diff --git a/.gitignore b/.gitignore index acf4f59..6a770b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ -# Windows thumbnail cache files +# Windows image file caches Thumbs.db ehthumbs.db -ehthumbs_vista.db # Folder config file Desktop.ini @@ -9,15 +8,38 @@ Desktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ -# Windows Installer files -*.cab -*.msi -*.msm -*.msp - # Windows shortcuts *.lnk -# ========================= -# Operating System Files -# ========================= +# build files +*.o +*.d + +#binaries +*.so + +#libs +*.a + +#files created by build +*.apk +*.ap_ +*.class +*.keystore +projects/Android/build/* +assets/oculussig* +Projects/Android/.externalNativeBuild/ndkBuild/debug/arm64-v8a/android_gradle_build.json +*.json +Projects/Android/.externalNativeBuild/ndkBuild/debug/arm64-v8a/ndkBuild_build_command.txt +Projects/Android/.externalNativeBuild/ndkBuild/debug/arm64-v8a/ndkBuild_build_output.txt +Projects/Android/.externalNativeBuild/ndkBuild/release/arm64-v8a/ndkBuild_build_command.txt +Projects/Android/.externalNativeBuild/ndkBuild/release/armeabi-v7a/ndkBuild_build_output.txt +*.bin +Projects/Android/.gradle/4.4/fileHashes/fileHashes.lock +*.ser +Projects/Android/.idea/codeStyles/Project.xml +*.xml +Projects/Android/.externalNativeBuild/ndkBuild/debug/armeabi-v7a/ndkBuild_build_command.txt +Projects/Android/.externalNativeBuild/ndkBuild/release/armeabi-v7a/ndkBuild_build_command.txt +Projects/Android/.externalNativeBuild/ndkBuild/debug/armeabi-v7a/ndkBuild_build_output.txt +Projects/Android/.externalNativeBuild/ndkBuild/release/arm64-v8a/ndkBuild_build_output.txt diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..da81cd3 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,125 @@ +#GNU GENERAL PUBLIC LICENSE +#Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 Lesser 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 an idea of what it does. +Copyright (C) yyyy name of author + +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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 Lesser General Public License instead of this License. diff --git a/Projects/Android/Android.iml b/Projects/Android/Android.iml new file mode 100644 index 0000000..5fb34c6 --- /dev/null +++ b/Projects/Android/Android.iml @@ -0,0 +1,161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Projects/Android/build.bat b/Projects/Android/build.bat new file mode 100644 index 0000000..facf79f --- /dev/null +++ b/Projects/Android/build.bat @@ -0,0 +1,29 @@ +@rem Only edit the master copy of this file in SDK_ROOT/bin/scripts/build/perproject + +@setlocal enableextensions enabledelayedexpansion + +@if not exist "build.gradle" @echo Build script must be executed from project directory. & goto :Abort + +@set P=.. + +:TryAgain + +@rem @echo P = %P% + +@if exist "%P%\bin\scripts\build\build.py.bat" goto :Found + +@if exist "%P%\bin\scripts\build" @echo "Could not find build.py.bat" & goto :Abort + +@set P=%P%\.. + +@goto :TryAgain + +:Found + +@set P=%P%\bin\scripts\build +@call %P%\build.py.bat %1 %2 %3 %4 %5 +@goto :End + +:Abort + +:End diff --git a/Projects/Android/build.gradle b/Projects/Android/build.gradle new file mode 100644 index 0000000..35670b2 --- /dev/null +++ b/Projects/Android/build.gradle @@ -0,0 +1,48 @@ +apply plugin: 'com.android.application' +apply from: "${rootProject.projectDir}/VrApp.gradle" + +android { + // This is the name of the generated apk file, which will have + // -debug.apk or -release.apk appended to it. + // The filename doesn't effect the Android installation process. + // Use only letters to remain compatible with the package name. + project.archivesBaseName = "lambda1vr" + + defaultConfig { + // Gradle replaces the manifest package with this value, which must + // be unique on a system. If you don't change it, a new app + // will replace an older one. + applicationId "com.drbeef." + project.archivesBaseName + + // override app plugin abiFilters for both 32 and 64-bit support + externalNativeBuild { + ndk { + abiFilters 'armeabi-v7a' + } + ndkBuild { + abiFilters 'armeabi-v7a' + } + } + } + + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + java.srcDirs = ['../../java'] + res.srcDirs = ['../../res'] + assets.srcDirs = ['../../assets'] + } + } +} + +dependencies { +} + +repositories { + google() +} +buildscript { + repositories { + google() + } +} \ No newline at end of file diff --git a/Projects/Android/build.py b/Projects/Android/build.py new file mode 100644 index 0000000..36335c3 --- /dev/null +++ b/Projects/Android/build.py @@ -0,0 +1,29 @@ +#!/usr/bin/python + +# This first bit of code is common bootstrapping code +# to determine the SDK root, and to set up the import +# path for additional python code. + +#begin bootstrap +import os +import sys + +def init(): + root = os.path.realpath( os.path.dirname(os.path.realpath(__file__) ) ) + os.chdir(root) # make sure we are always executing from the project directory + while( os.path.isdir( os.path.join(root, 'bin/scripts/build') ) == False ): + root = os.path.realpath( os.path.join(root, '..') ) + if( len(root) <= 5 ): # Should catch both Posix and Windows root directories (e.g. '/' and 'C:\') + print('Unable to find SDK root. Exiting.') + sys.exit(1) + root = os.path.abspath(root) + os.environ['OCULUS_SDK_PATH'] = root + sys.path.append( root + "/bin/scripts/build" ) + +init() +import ovrbuild +ovrbuild.init() +#end bootstrap + + +ovrbuild.build() diff --git a/Projects/Android/gradle/wrapper/gradle-wrapper.jar b/Projects/Android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..7a3265e Binary files /dev/null and b/Projects/Android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/Projects/Android/gradle/wrapper/gradle-wrapper.properties b/Projects/Android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..8a1cc64 --- /dev/null +++ b/Projects/Android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Thu Sep 27 22:37:56 BST 2018 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip diff --git a/Projects/Android/gradlew b/Projects/Android/gradlew new file mode 100644 index 0000000..cccdd3d --- /dev/null +++ b/Projects/Android/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/Projects/Android/gradlew.bat b/Projects/Android/gradlew.bat new file mode 100644 index 0000000..f955316 --- /dev/null +++ b/Projects/Android/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/Projects/Android/jni/Android.mk b/Projects/Android/jni/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/Projects/Android/jni/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/Projects/Android/jni/Application.mk b/Projects/Android/jni/Application.mk new file mode 100644 index 0000000..423d6a5 --- /dev/null +++ b/Projects/Android/jni/Application.mk @@ -0,0 +1,36 @@ +# MAKEFILE_LIST specifies the current used Makefiles, of which this is the last +# one. I use that to obtain the Application.mk dir then import the root +# Application.mk. +ROOT_DIR := $(dir $(lastword $(MAKEFILE_LIST)))../../../../.. +NDK_MODULE_PATH := $(ROOT_DIR) + +XASH_SDL ?= 0 +APP_PLATFORM := android-19 + +APP_CFLAGS += -Wl,--no-undefined + +# if non-zero, works only if single ABI selected +XASH_THREAD_NUM ?= 0 + + +# CFLAGS_OPT := -O3 -fomit-frame-pointer -ggdb -funsafe-math-optimizations -ftree-vectorize -fgraphite-identity -floop-interchange -funsafe-loop-optimizations -finline-limit=256 -pipe +# CFLAGS_OPT_ARM := -mthumb -mfpu=neon -mcpu=cortex-a9 -pipe -mvectorize-with-neon-quad -DVECTORIZE_SINCOS -fPIC -DHAVE_EFFICIENT_UNALIGNED_ACCESS +# CFLAGS_HARDFP := -D_NDK_MATH_NO_SOFTFP=1 -mhard-float -mfloat-abi=hard -DLOAD_HARDFP -DSOFTFP_LINK +APPLICATIONMK_PATH = $(call my-dir) + +GL4ES_PATH := $(APPLICATIONMK_PATH)/src/gl4es/include + +XASH3D_PATH := $(APPLICATIONMK_PATH)/src/Xash3D/xash3d + +HLSDK_PATH := $(APPLICATIONMK_PATH)/src/HLSDK/halflife/ + +# XASH3D_CONFIG := $(APPLICATIONMK_PATH)/xash3d_config.mk + +# ndk-r14 introduced failure for missing dependencies. If 'false', the clean +# step will error as we currently remove prebuilt artifacts on clean. +APP_ALLOW_MISSING_DEPS=true + +APP_MODULES := gl4es xash menu client server +APP_STL := c++_shared + + diff --git a/Projects/Android/jni/src/Android.mk b/Projects/Android/jni/src/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/Projects/Android/jni/src/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/Projects/Android/jni/src/Lambda1VR/L1VR_SurfaceView.c b/Projects/Android/jni/src/Lambda1VR/L1VR_SurfaceView.c new file mode 100644 index 0000000..05a8fb4 --- /dev/null +++ b/Projects/Android/jni/src/Lambda1VR/L1VR_SurfaceView.c @@ -0,0 +1,2645 @@ +/************************************************************************************ + +Filename : Lambda1VR.c based on VrCubeWorld_SurfaceView.c +Content : This sample uses a plain Android SurfaceView and handles all + Activity and Surface life cycle events in native code. This sample + does not use the application framework and also does not use LibOVR. + This sample only uses the VrApi. +Created : March, 2015 +Authors : J.M.P. van Waveren / Simon Brown + +Copyright : Copyright 2015 Oculus VR, LLC. All Rights reserved. + +*************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include // for prctl( PR_SET_NAME ) +#include +#include // for native window JNI +#include + +#include "argtable3.h" + +#include +#include +#include +#include + +//GL4ES +//#include <../src/gl/loader.h> + +//#include +#include +#include +#include +#include +#include +//#include +#include +#include + +#if !defined( EGL_OPENGL_ES3_BIT_KHR ) +#define EGL_OPENGL_ES3_BIT_KHR 0x0040 +#endif + +#define PITCH 0 +#define YAW 1 +#define ROLL 2 + + + +// EXT_texture_border_clamp +#ifndef GL_CLAMP_TO_BORDER +#define GL_CLAMP_TO_BORDER 0x812D +#endif + +#ifndef GL_TEXTURE_BORDER_COLOR +#define GL_TEXTURE_BORDER_COLOR 0x1004 +#endif + + +// Must use EGLSyncKHR because the VrApi still supports OpenGL ES 2.0 +#define EGL_SYNC + +#if defined EGL_SYNC +// EGL_KHR_reusable_sync +PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR; +PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR; +PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR; +PFNEGLSIGNALSYNCKHRPROC eglSignalSyncKHR; +PFNEGLGETSYNCATTRIBKHRPROC eglGetSyncAttribKHR; +#endif + +#include "VrApi.h" +#include "VrApi_Helpers.h" +#include "VrApi_SystemUtils.h" +#include "VrApi_Input.h" +#include "../gl4es/src/gl/loader.h" + +#ifndef NDEBUG +#define DEBUG 1 +#endif + +#define LOG_TAG "Lambda1VR" + +#define ALOGE(...) __android_log_print( ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__ ) +#if DEBUG +#define ALOGV(...) __android_log_print( ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__ ) +#else +#define ALOGV(...) +#endif + +int CPU_LEVEL = 2; +int GPU_LEVEL = 3; +int NUM_MULTI_SAMPLES = 1; + +float SS_MULTIPLIER = 1.0f; + +float worldPosition[3]; +float hmdPosition[3]; +float playerHeight; +float positionDeltaThisFrame[3]; + +static float radians(float deg) { + return (deg * M_PI) / 180.0; +} + +static float degrees(float rad) { + return (rad * 180.0) / M_PI; +} + + +/* global arg_xxx structs */ +struct arg_dbl *ss; +struct arg_int *cpu; +struct arg_int *gpu; +struct arg_dbl *msaa; +struct arg_end *end; + +char **argv; +int argc=0; + +cvar_t cl_righthanded; + +/* +================================================================================ + +System Clock Time + +================================================================================ +*/ + +static double GetTimeInSeconds() +{ + struct timespec now; + clock_gettime( CLOCK_MONOTONIC, &now ); + return ( now.tv_sec * 1e9 + now.tv_nsec ) * 0.000000001; +} + +/* +================================================================================ + +LAMBDA1VR Stuff + +================================================================================ +*/ + +//All the functionality we link to in the DarkPlaces Quake implementation + +static bool xash_initialised = false; + +typedef void (*pfnChangeGame)( const char *progname ); +extern int Host_Main( int argc, const char **argv, const char *progname, int bChangeGame, pfnChangeGame func ); + + +//Timing stuff for joypad control +static long oldtime=0; +long delta=0; + +int curtime; +int Sys_Milliseconds (void) +{ + struct timeval tp; + struct timezone tzp; + static int secbase; + + gettimeofday(&tp, &tzp); + + if (!secbase) + { + secbase = tp.tv_sec; + return tp.tv_usec/1000; + } + + curtime = (tp.tv_sec - secbase)*1000 + tp.tv_usec/1000; + + return curtime; +} + +int runStatus = -1; +void QC_exit(int exitCode) +{ + runStatus = exitCode; +} + +vec3_t hmdorientation; +float gunangles[3]; +float weaponOffset[3]; + +float horizFOV; +float vertFOV; + +int bigScreen = 0; +ovrMatrix4f modelScreen; +ovrMatrix4f rotation; + +void BigScreenMode(int mode) +{ + if (mode == 1)// && key_consoleactive == 0) // bit of a hack, but only way rotation set when menu first invoked + { + rotation = ovrMatrix4f_CreateRotation( 0.0f, radians(hmdorientation[YAW]), 0.0f ); + } + + if (bigScreen != 2) + { + bigScreen = mode; + } +} + +extern int stereoMode; +qboolean demoplayback = false; + +static void UnEscapeQuotes( char *arg ) +{ + char *last = NULL; + while( *arg ) { + if( *arg == '"' && *last == '\\' ) { + char *c_curr = arg; + char *c_last = last; + while( *c_curr ) { + *c_last = *c_curr; + c_last = c_curr; + c_curr++; + } + *c_last = '\0'; + } + last = arg; + arg++; + } +} + +static int ParseCommandLine(char *cmdline, char **argv) +{ + char *bufp; + char *lastp = NULL; + int argc, last_argc; + argc = last_argc = 0; + for ( bufp = cmdline; *bufp; ) { + while ( isspace(*bufp) ) { + ++bufp; + } + if ( *bufp == '"' ) { + ++bufp; + if ( *bufp ) { + if ( argv ) { + argv[argc] = bufp; + } + ++argc; + } + while ( *bufp && ( *bufp != '"' || *lastp == '\\' ) ) { + lastp = bufp; + ++bufp; + } + } else { + if ( *bufp ) { + if ( argv ) { + argv[argc] = bufp; + } + ++argc; + } + while ( *bufp && ! isspace(*bufp) ) { + ++bufp; + } + } + if ( *bufp ) { + if ( argv ) { + *bufp = '\0'; + } + ++bufp; + } + if( argv && last_argc != argc ) { + UnEscapeQuotes( argv[last_argc] ); + } + last_argc = argc; + } + if ( argv ) { + argv[argc] = NULL; + } + return(argc); +} + +/* +================================================================================ + +OpenGL-ES Utility Functions + +================================================================================ +*/ + +typedef struct +{ + bool multi_view; // GL_OVR_multiview, GL_OVR_multiview2 + bool EXT_texture_border_clamp; // GL_EXT_texture_border_clamp, GL_OES_texture_border_clamp +} OpenGLExtensions_t; + +OpenGLExtensions_t glExtensions; + +static void EglInitExtensions() +{ +#if defined EGL_SYNC + eglCreateSyncKHR = (PFNEGLCREATESYNCKHRPROC) eglGetProcAddress( "eglCreateSyncKHR" ); + eglDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC) eglGetProcAddress( "eglDestroySyncKHR" ); + eglClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC) eglGetProcAddress( "eglClientWaitSyncKHR" ); + eglSignalSyncKHR = (PFNEGLSIGNALSYNCKHRPROC) eglGetProcAddress( "eglSignalSyncKHR" ); + eglGetSyncAttribKHR = (PFNEGLGETSYNCATTRIBKHRPROC) eglGetProcAddress( "eglGetSyncAttribKHR" ); +#endif + + const char * allExtensions = (const char *)glGetString( GL_EXTENSIONS ); + if ( allExtensions != NULL ) + { + glExtensions.multi_view = strstr( allExtensions, "GL_OVR_multiview2" ) && + strstr( allExtensions, "GL_OVR_multiview_multisampled_render_to_texture" ); + + glExtensions.EXT_texture_border_clamp = false;//strstr( allExtensions, "GL_EXT_texture_border_clamp" ) || + //strstr( allExtensions, "GL_OES_texture_border_clamp" ); + } +} + +static const char * EglErrorString( const EGLint error ) +{ + switch ( error ) + { + case EGL_SUCCESS: return "EGL_SUCCESS"; + case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED"; + case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS"; + case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC"; + case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE"; + case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT"; + case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG"; + case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE"; + case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY"; + case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE"; + case EGL_BAD_MATCH: return "EGL_BAD_MATCH"; + case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER"; + case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP"; + case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW"; + case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST"; + default: return "unknown"; + } +} + +static const char * GlFrameBufferStatusString( GLenum status ) +{ + switch ( status ) + { + case GL_FRAMEBUFFER_UNDEFINED: return "GL_FRAMEBUFFER_UNDEFINED"; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; + case GL_FRAMEBUFFER_UNSUPPORTED: return "GL_FRAMEBUFFER_UNSUPPORTED"; + case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: return "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"; + default: return "unknown"; + } +} + +#define CHECK_GL_ERRORS +#ifdef CHECK_GL_ERRORS + +static const char * GlErrorString( GLenum error ) +{ + switch ( error ) + { + case GL_NO_ERROR: return "GL_NO_ERROR"; + case GL_INVALID_ENUM: return "GL_INVALID_ENUM"; + case GL_INVALID_VALUE: return "GL_INVALID_VALUE"; + case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION"; + case GL_INVALID_FRAMEBUFFER_OPERATION: return "GL_INVALID_FRAMEBUFFER_OPERATION"; + case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY"; + default: return "unknown"; + } +} + +static void GLCheckErrors( int line ) +{ + for ( int i = 0; i < 10; i++ ) + { + const GLenum error = glGetError(); + if ( error == GL_NO_ERROR ) + { + break; + } + ALOGE( "GL error on line %d: %s", line, GlErrorString( error ) ); + } +} + +#define GL( func ) func; GLCheckErrors( __LINE__ ); + +#else // CHECK_GL_ERRORS + +#define GL( func ) func; + +#endif // CHECK_GL_ERRORS + +/* +================================================================================ + +ovrEgl + +================================================================================ +*/ + +typedef struct +{ + EGLint MajorVersion; + EGLint MinorVersion; + EGLDisplay Display; + EGLConfig Config; + EGLSurface TinySurface; + EGLSurface MainSurface; + EGLContext Context; +} ovrEgl; + +static void ovrEgl_Clear( ovrEgl * egl ) +{ + egl->MajorVersion = 0; + egl->MinorVersion = 0; + egl->Display = 0; + egl->Config = 0; + egl->TinySurface = EGL_NO_SURFACE; + egl->MainSurface = EGL_NO_SURFACE; + egl->Context = EGL_NO_CONTEXT; +} + +static void ovrEgl_CreateContext( ovrEgl * egl, const ovrEgl * shareEgl ) +{ + if ( egl->Display != 0 ) + { + return; + } + + egl->Display = eglGetDisplay( EGL_DEFAULT_DISPLAY ); + ALOGV( " eglInitialize( Display, &MajorVersion, &MinorVersion )" ); + eglInitialize( egl->Display, &egl->MajorVersion, &egl->MinorVersion ); + // Do NOT use eglChooseConfig, because the Android EGL code pushes in multisample + // flags in eglChooseConfig if the user has selected the "force 4x MSAA" option in + // settings, and that is completely wasted for our warp target. + const int MAX_CONFIGS = 1024; + EGLConfig configs[MAX_CONFIGS]; + EGLint numConfigs = 0; + if ( eglGetConfigs( egl->Display, configs, MAX_CONFIGS, &numConfigs ) == EGL_FALSE ) + { + ALOGE( " eglGetConfigs() failed: %s", EglErrorString( eglGetError() ) ); + return; + } + const EGLint configAttribs[] = + { + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, // need alpha for the multi-pass timewarp compositor + EGL_DEPTH_SIZE, 0, + EGL_STENCIL_SIZE, 0, + EGL_SAMPLES, 0, + EGL_NONE + }; + egl->Config = 0; + for ( int i = 0; i < numConfigs; i++ ) + { + EGLint value = 0; + + eglGetConfigAttrib( egl->Display, configs[i], EGL_RENDERABLE_TYPE, &value ); + if ( ( value & EGL_OPENGL_ES3_BIT_KHR ) != EGL_OPENGL_ES3_BIT_KHR ) + { + continue; + } + + // The pbuffer config also needs to be compatible with normal window rendering + // so it can share textures with the window context. + eglGetConfigAttrib( egl->Display, configs[i], EGL_SURFACE_TYPE, &value ); + if ( ( value & ( EGL_WINDOW_BIT | EGL_PBUFFER_BIT ) ) != ( EGL_WINDOW_BIT | EGL_PBUFFER_BIT ) ) + { + continue; + } + + int j = 0; + for ( ; configAttribs[j] != EGL_NONE; j += 2 ) + { + eglGetConfigAttrib( egl->Display, configs[i], configAttribs[j], &value ); + if ( value != configAttribs[j + 1] ) + { + break; + } + } + if ( configAttribs[j] == EGL_NONE ) + { + egl->Config = configs[i]; + break; + } + } + if ( egl->Config == 0 ) + { + ALOGE( " eglChooseConfig() failed: %s", EglErrorString( eglGetError() ) ); + return; + } + EGLint contextAttribs[] = + { + EGL_CONTEXT_CLIENT_VERSION, 3, + EGL_NONE + }; + ALOGV( " Context = eglCreateContext( Display, Config, EGL_NO_CONTEXT, contextAttribs )" ); + egl->Context = eglCreateContext( egl->Display, egl->Config, ( shareEgl != NULL ) ? shareEgl->Context : EGL_NO_CONTEXT, contextAttribs ); + if ( egl->Context == EGL_NO_CONTEXT ) + { + ALOGE( " eglCreateContext() failed: %s", EglErrorString( eglGetError() ) ); + return; + } + const EGLint surfaceAttribs[] = + { + EGL_WIDTH, 16, + EGL_HEIGHT, 16, + EGL_NONE + }; + ALOGV( " TinySurface = eglCreatePbufferSurface( Display, Config, surfaceAttribs )" ); + egl->TinySurface = eglCreatePbufferSurface( egl->Display, egl->Config, surfaceAttribs ); + if ( egl->TinySurface == EGL_NO_SURFACE ) + { + ALOGE( " eglCreatePbufferSurface() failed: %s", EglErrorString( eglGetError() ) ); + eglDestroyContext( egl->Display, egl->Context ); + egl->Context = EGL_NO_CONTEXT; + return; + } + ALOGV( " eglMakeCurrent( Display, TinySurface, TinySurface, Context )" ); + if ( eglMakeCurrent( egl->Display, egl->TinySurface, egl->TinySurface, egl->Context ) == EGL_FALSE ) + { + ALOGE( " eglMakeCurrent() failed: %s", EglErrorString( eglGetError() ) ); + eglDestroySurface( egl->Display, egl->TinySurface ); + eglDestroyContext( egl->Display, egl->Context ); + egl->Context = EGL_NO_CONTEXT; + return; + } +} + +static void ovrEgl_DestroyContext( ovrEgl * egl ) +{ + if ( egl->Display != 0 ) + { + ALOGE( " eglMakeCurrent( Display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT )" ); + if ( eglMakeCurrent( egl->Display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT ) == EGL_FALSE ) + { + ALOGE( " eglMakeCurrent() failed: %s", EglErrorString( eglGetError() ) ); + } + } + if ( egl->Context != EGL_NO_CONTEXT ) + { + ALOGE( " eglDestroyContext( Display, Context )" ); + if ( eglDestroyContext( egl->Display, egl->Context ) == EGL_FALSE ) + { + ALOGE( " eglDestroyContext() failed: %s", EglErrorString( eglGetError() ) ); + } + egl->Context = EGL_NO_CONTEXT; + } + if ( egl->TinySurface != EGL_NO_SURFACE ) + { + ALOGE( " eglDestroySurface( Display, TinySurface )" ); + if ( eglDestroySurface( egl->Display, egl->TinySurface ) == EGL_FALSE ) + { + ALOGE( " eglDestroySurface() failed: %s", EglErrorString( eglGetError() ) ); + } + egl->TinySurface = EGL_NO_SURFACE; + } + if ( egl->Display != 0 ) + { + ALOGE( " eglTerminate( Display )" ); + if ( eglTerminate( egl->Display ) == EGL_FALSE ) + { + ALOGE( " eglTerminate() failed: %s", EglErrorString( eglGetError() ) ); + } + egl->Display = 0; + } +} + +/* +================================================================================ + +ovrFramebuffer + +================================================================================ +*/ + +typedef struct +{ + int Width; + int Height; + int Multisamples; + int TextureSwapChainLength; + int TextureSwapChainIndex; + ovrTextureSwapChain * ColorTextureSwapChain; + GLuint * DepthBuffers; + GLuint * FrameBuffers; +} ovrFramebuffer; + +static void ovrFramebuffer_Clear( ovrFramebuffer * frameBuffer ) +{ + frameBuffer->Width = 0; + frameBuffer->Height = 0; + frameBuffer->Multisamples = 0; + frameBuffer->TextureSwapChainLength = 0; + frameBuffer->TextureSwapChainIndex = 0; + frameBuffer->ColorTextureSwapChain = NULL; + frameBuffer->DepthBuffers = NULL; + frameBuffer->FrameBuffers = NULL; +} + +static bool ovrFramebuffer_Create( ovrFramebuffer * frameBuffer, const GLenum colorFormat, const int width, const int height, const int multisamples ) +{ + LOAD_GLES2(glBindTexture); + LOAD_GLES2(glTexParameteri); + LOAD_GLES2(glGenRenderbuffers); + LOAD_GLES2(glBindRenderbuffer); + LOAD_GLES2(glRenderbufferStorage); + LOAD_GLES2(glGenFramebuffers); + LOAD_GLES2(glBindFramebuffer); + LOAD_GLES2(glFramebufferRenderbuffer); + LOAD_GLES2(glFramebufferTexture2D); + LOAD_GLES2(glCheckFramebufferStatus); + + frameBuffer->Width = width * SS_MULTIPLIER; + frameBuffer->Height = height * SS_MULTIPLIER; + frameBuffer->Multisamples = multisamples; + + frameBuffer->ColorTextureSwapChain = vrapi_CreateTextureSwapChain3( VRAPI_TEXTURE_TYPE_2D, colorFormat, frameBuffer->Width, frameBuffer->Height, 1, 3 ); + frameBuffer->TextureSwapChainLength = vrapi_GetTextureSwapChainLength( frameBuffer->ColorTextureSwapChain ); + frameBuffer->DepthBuffers = (GLuint *)malloc( frameBuffer->TextureSwapChainLength * sizeof( GLuint ) ); + frameBuffer->FrameBuffers = (GLuint *)malloc( frameBuffer->TextureSwapChainLength * sizeof( GLuint ) ); + + for ( int i = 0; i < frameBuffer->TextureSwapChainLength; i++ ) + { + // Create the color buffer texture. + const GLuint colorTexture = vrapi_GetTextureSwapChainHandle( frameBuffer->ColorTextureSwapChain, i ); + GLenum colorTextureTarget = GL_TEXTURE_2D; + GL( gles_glBindTexture( colorTextureTarget, colorTexture ) ); + // Just clamp to edge. However, this requires manually clearing the border + // around the layer to clear the edge texels. + GL( gles_glTexParameteri( colorTextureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ) ); + GL( gles_glTexParameteri( colorTextureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ) ); + + GL( gles_glTexParameteri( colorTextureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR ) ); + GL( gles_glTexParameteri( colorTextureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR ) ); + GL( gles_glBindTexture( colorTextureTarget, 0 ) ); + + { + { + // Create depth buffer. + GL( gles_glGenRenderbuffers( 1, &frameBuffer->DepthBuffers[i] ) ); + GL( gles_glBindRenderbuffer( GL_RENDERBUFFER, frameBuffer->DepthBuffers[i] ) ); + GL( gles_glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, frameBuffer->Width, frameBuffer->Height ) ); + GL( gles_glBindRenderbuffer( GL_RENDERBUFFER, 0 ) ); + + // Create the frame buffer. + GL( gles_glGenFramebuffers( 1, &frameBuffer->FrameBuffers[i] ) ); + GL( gles_glBindFramebuffer( GL_DRAW_FRAMEBUFFER, frameBuffer->FrameBuffers[i] ) ); + GL( gles_glFramebufferRenderbuffer( GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, frameBuffer->DepthBuffers[i] ) ); + GL( gles_glFramebufferTexture2D( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0 ) ); + GL( GLenum renderFramebufferStatus = gles_glCheckFramebufferStatus( GL_DRAW_FRAMEBUFFER ) ); + GL( gles_glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ) ); + if ( renderFramebufferStatus != GL_FRAMEBUFFER_COMPLETE ) + { + ALOGE( "Incomplete frame buffer object: %s", GlFrameBufferStatusString( renderFramebufferStatus ) ); + return false; + } + } + } + } + + return true; +} + +static void ovrFramebuffer_Destroy( ovrFramebuffer * frameBuffer ) +{ + LOAD_GLES2(glDeleteFramebuffers); + LOAD_GLES2(glDeleteRenderbuffers); + + GL( gles_glDeleteFramebuffers( frameBuffer->TextureSwapChainLength, frameBuffer->FrameBuffers ) ); + GL( gles_glDeleteRenderbuffers( frameBuffer->TextureSwapChainLength, frameBuffer->DepthBuffers ) ); + + vrapi_DestroyTextureSwapChain( frameBuffer->ColorTextureSwapChain ); + + free( frameBuffer->DepthBuffers ); + free( frameBuffer->FrameBuffers ); + + ovrFramebuffer_Clear( frameBuffer ); +} + +static void ovrFramebuffer_SetCurrent( ovrFramebuffer * frameBuffer ) +{ + LOAD_GLES2(glBindFramebuffer); + GL( gles_glBindFramebuffer( GL_DRAW_FRAMEBUFFER, frameBuffer->FrameBuffers[frameBuffer->TextureSwapChainIndex] ) ); +} + +static void ovrFramebuffer_SetNone() +{ + LOAD_GLES2(glBindFramebuffer); + GL( gles_glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ) ); +} + +static void ovrFramebuffer_Resolve( ovrFramebuffer * frameBuffer ) +{ + LOAD_GLES2(glFlush); + + // Discard the depth buffer, so the tiler won't need to write it back out to memory. + const GLenum depthAttachment[1] = { GL_DEPTH_ATTACHMENT }; + glInvalidateFramebuffer( GL_DRAW_FRAMEBUFFER, 1, depthAttachment ); + + // Flush this frame worth of commands. + glFlush(); +} + +static void ovrFramebuffer_Advance( ovrFramebuffer * frameBuffer ) +{ + // Advance to the next texture from the set. + frameBuffer->TextureSwapChainIndex = ( frameBuffer->TextureSwapChainIndex + 1 ) % frameBuffer->TextureSwapChainLength; +} + + +static void ovrFramebuffer_ClearEdgeTexels( ovrFramebuffer * frameBuffer ) +{ + LOAD_GLES2(glEnable); + LOAD_GLES2(glDisable); + LOAD_GLES2(glViewport); + LOAD_GLES2(glScissor); + LOAD_GLES2(glClearColor); + LOAD_GLES2(glClear); + + GL( gles_glEnable( GL_SCISSOR_TEST ) ); + GL( gles_glViewport( 0, 0, frameBuffer->Width, frameBuffer->Height ) ); + + // Explicitly clear the border texels to black because OpenGL-ES does not support GL_CLAMP_TO_BORDER. + // Clear to fully opaque black. + GL( gles_glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ) ); + + // bottom + GL( gles_glScissor( 0, 0, frameBuffer->Width, 1 ) ); + GL( gles_glClear( GL_COLOR_BUFFER_BIT ) ); + // top + GL( gles_glScissor( 0, frameBuffer->Height - 1, frameBuffer->Width, 1 ) ); + GL( gles_glClear( GL_COLOR_BUFFER_BIT ) ); + // left + GL( gles_glScissor( 0, 0, 1, frameBuffer->Height ) ); + GL( gles_glClear( GL_COLOR_BUFFER_BIT ) ); + // right + GL( gles_glScissor( frameBuffer->Width - 1, 0, 1, frameBuffer->Height ) ); + GL( gles_glClear( GL_COLOR_BUFFER_BIT ) ); + + GL( gles_glScissor( 0, 0, 0, 0 ) ); + GL( gles_glDisable( GL_SCISSOR_TEST ) ); +} + + +/* +================================================================================ + +ovrRenderer + +================================================================================ +*/ + + +typedef struct +{ + ovrFramebuffer FrameBuffer[VRAPI_FRAME_LAYER_EYE_MAX]; + ovrFramebuffer L1VRFrameBuffer; + ovrMatrix4f ProjectionMatrix; + int NumBuffers; +} ovrRenderer; + +static void ovrRenderer_Clear( ovrRenderer * renderer ) +{ + for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ ) + { + ovrFramebuffer_Clear( &renderer->FrameBuffer[eye] ); + } + ovrFramebuffer_Clear( &renderer->L1VRFrameBuffer ); + renderer->ProjectionMatrix = ovrMatrix4f_CreateIdentity(); + renderer->NumBuffers = VRAPI_FRAME_LAYER_EYE_MAX; +} + + +static const char VERTEX_SHADER[] = + "uniform mat4 u_MVPMatrix;" + "attribute vec4 a_Position;" + "attribute vec2 a_texCoord;" + "varying vec2 v_texCoord;" + "void main() {" + " gl_Position = u_MVPMatrix * a_Position;" + " v_texCoord = a_texCoord;" + "}"; + + +static const char FRAGMENT_SHADER[] = + "precision mediump float;" + "varying vec2 v_texCoord;" + "uniform sampler2D s_texture;" + "uniform sampler2D s_texture1;" + "void main() {" + " gl_FragColor = texture2D( s_texture, v_texCoord ) * texture2D( s_texture1, v_texCoord );" + "}"; + +int loadShader(int type, const char * shaderCode){ + LOAD_GLES2(glCreateShader); + LOAD_GLES2(glShaderSource); + LOAD_GLES2(glCompileShader); + + int shader = gles_glCreateShader(type); + GL( gles_glShaderSource(shader, 1, &shaderCode, 0)); + GL( gles_glCompileShader(shader)); + return shader; +} + +int BuildScreenVignetteTexture( ) +{ + LOAD_GLES2(glGenTextures); + LOAD_GLES2(glBindTexture); + LOAD_GLES2(glTexImage2D); + LOAD_GLES2(glTexParameteri); + + static const int scale = 8; + static const int width = 10 * scale; + static const int height = 8 * scale; + unsigned char buffer[width * height]; + memset( buffer, 255, sizeof( buffer ) ); + for ( int i = 0; i < width; i++ ) + { + buffer[i] = 0; + buffer[width*height - 1 - i] = 0; + } + for ( int i = 0; i < height; i++ ) + { + buffer[i * width] = 0; + buffer[i * width + width - 1] = 0; + } + GLuint texId = 0; + gles_glGenTextures( 1, &texId ); + gles_glBindTexture( GL_TEXTURE_2D, texId ); + gles_glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, buffer ); + gles_glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + gles_glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + gles_glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + gles_glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + gles_glBindTexture( GL_TEXTURE_2D, 0 ); + + return texId; +} + +static short indices[6] = {0, 1, 2, 0, 2, 3}; + +static float uvs[8] = { + 0.0f, 1.0f, + 0.0f, 0.0f, + 1.0f, 0.0f, + 1.0f, 1.0f +}; + +static float SCREEN_COORDS[12] = { + -2.0f, 1.75f, 0.0f, + -2.0f, -1.75f, 0.0f, + 2.0f, -1.75f, 0.0f, + 2.0f, 1.75f, 0.0f +}; + +int vignetteTexture = 0; + +int sp_Image = 0; +int positionParam = 0; +int texCoordParam = 0; +int samplerParam = 0; +int vignetteParam = 0; +int modelViewProjectionParam = 0; + +static void ovrRenderer_Create( ovrRenderer * renderer, const ovrJava * java ) +{ + LOAD_GLES2(glCreateProgram); + LOAD_GLES2(glAttachShader); + LOAD_GLES2(glLinkProgram); + LOAD_GLES2(glGetAttribLocation); + LOAD_GLES2(glGetUniformLocation); + + renderer->NumBuffers = VRAPI_FRAME_LAYER_EYE_MAX; + + // Create the shaders, images + int vertexShader = loadShader(GL_VERTEX_SHADER, VERTEX_SHADER); + int fragmentShader = loadShader(GL_FRAGMENT_SHADER, FRAGMENT_SHADER); + + + sp_Image = gles_glCreateProgram(); // create empty OpenGL ES Program + GL( gles_glAttachShader(sp_Image, vertexShader)); // add the vertex shader to program + GL( gles_glAttachShader(sp_Image, fragmentShader)); // add the fragment shader to program + GL( gles_glLinkProgram(sp_Image)); // creates OpenGL ES program executable + positionParam = GL( gles_glGetAttribLocation(sp_Image, "a_Position")); + texCoordParam = GL( gles_glGetAttribLocation(sp_Image, "a_texCoord")); + modelViewProjectionParam = GL( gles_glGetUniformLocation(sp_Image, "u_MVPMatrix")); + samplerParam = GL( gles_glGetUniformLocation(sp_Image, "s_texture")); + vignetteParam = GL( gles_glGetUniformLocation(sp_Image, "s_texture1")); + + vignetteTexture = BuildScreenVignetteTexture(); + + modelScreen = ovrMatrix4f_CreateIdentity(); + rotation = ovrMatrix4f_CreateIdentity(); + ovrMatrix4f translation = ovrMatrix4f_CreateTranslation( 0, 0, -3.0f ); + modelScreen = ovrMatrix4f_Multiply( &modelScreen, &translation ); + + horizFOV = vrapi_GetSystemPropertyInt( java, VRAPI_SYS_PROP_SUGGESTED_EYE_FOV_DEGREES_X); + vertFOV = vrapi_GetSystemPropertyInt( java, VRAPI_SYS_PROP_SUGGESTED_EYE_FOV_DEGREES_Y); + + // Create the render Textures. + for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ ) + { + ovrFramebuffer_Create( &renderer->FrameBuffer[eye], + GL_RGBA8, + vrapi_GetSystemPropertyInt( java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_WIDTH ), + vrapi_GetSystemPropertyInt( java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_HEIGHT ), + NUM_MULTI_SAMPLES ); + } + + ovrFramebuffer_Create( &renderer->L1VRFrameBuffer, + GL_RGBA8, + vrapi_GetSystemPropertyInt( java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_WIDTH ), + vrapi_GetSystemPropertyInt( java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_HEIGHT ), + NUM_MULTI_SAMPLES ); + + // Setup the projection matrix. + renderer->ProjectionMatrix = ovrMatrix4f_CreateProjectionFov( + vrapi_GetSystemPropertyFloat( java, VRAPI_SYS_PROP_SUGGESTED_EYE_FOV_DEGREES_X ), + vrapi_GetSystemPropertyFloat( java, VRAPI_SYS_PROP_SUGGESTED_EYE_FOV_DEGREES_Y ), + 0.0f, 0.0f, 1.0f, 0.0f ); + +} + +static void ovrRenderer_Destroy( ovrRenderer * renderer ) +{ + for ( int eye = 0; eye < renderer->NumBuffers; eye++ ) + { + ovrFramebuffer_Destroy( &renderer->FrameBuffer[eye] ); + } + ovrFramebuffer_Destroy( &renderer->L1VRFrameBuffer ); + renderer->ProjectionMatrix = ovrMatrix4f_CreateIdentity(); +} + +void QuatToYawPitchRoll(ovrQuatf q, vec3_t out) { + float sqw = q.w*q.w; + float sqx = q.x*q.x; + float sqy = q.y*q.y; + float sqz = q.z*q.z; + float unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor + float test = q.x*q.y + q.z*q.w; + if( test > 0.49999*unit ) { // singularity at north pole + out[YAW] = 2 * atan2f(q.x,q.w) / ((float)M_PI / 180.0f); + out[ROLL] = -(float)M_PI/2 / ((float)M_PI / 180.0f) ; + out[PITCH] = 0; + } + else if( test < -0.49999*unit ) { // singularity at south pole + out[YAW] = -2 * atan2f(q.x,q.w) / ((float)M_PI / 180.0f); + out[ROLL] = (float)M_PI/2 / ((float)M_PI / 180.0f); + out[PITCH] = 0; + } + else { + //out[YAW] = atan2(2*q.y*q.w-2*q.x*q.z , sqx - sqy - sqz + sqw) / (M_PI / 180.0f); + out[YAW] = atan2f(2*q.y*q.w-2*q.x*q.z , 1 - 2*sqy - 2*sqz) / ((float)M_PI / 180.0f); + out[ROLL] = -asinf(2*test/unit) / ((float)M_PI / 180.0f); + //out[PITCH] = -atan2(2*q.x*q.w-2*q.y*q.z , -sqx + sqy - sqz + sqw) / (M_PI / 180.0f); + out[PITCH] = -atan2f(2*q.x*q.w-2*q.y*q.z , 1 - 2*sqx - 2*sqz) / ((float)M_PI / 180.0f); + + } +} + +static void adjustYaw(float adjustment, float* out) +{ + *out -= adjustment; + if (*out > 180.0f) + *out -= 360.0f; + if (*out < -180.0f) + *out += 360.0f; +} + +void setWorldPosition( float x, float y, float z ) +{ + positionDeltaThisFrame[0] = (worldPosition[0] - x); + positionDeltaThisFrame[1] = (worldPosition[1] - y); + positionDeltaThisFrame[2] = (worldPosition[2] - z); + + worldPosition[0] = x; + worldPosition[1] = y; + worldPosition[2] = z; +} + +void setHMDPosition( float x, float y, float z ) +{ + hmdPosition[0] = x; + hmdPosition[1] = y; + if (bigScreen) + { + playerHeight = y; + } + hmdPosition[2] = z; +} + +void Host_BeginFrame(); +void Host_Frame(int eye); +void Host_EndFrame(); + +static ovrLayerProjection2 ovrRenderer_RenderFrame( ovrRenderer * renderer, const ovrJava * java, + const ovrTracking2 * tracking, ovrMobile * ovr ) +{ + LOAD_GLES2(glEnable); + LOAD_GLES2(glDepthMask); + LOAD_GLES2(glDepthFunc); + LOAD_GLES2(glViewport); + LOAD_GLES2(glScissor); + LOAD_GLES2(glClearColor); + LOAD_GLES2(glClear); + LOAD_GLES2(glDisable); + LOAD_GLES2(glUseProgram); + LOAD_GLES2(glVertexAttribPointer); + LOAD_GLES2(glUniformMatrix4fv); + LOAD_GLES2(glActiveTexture); + LOAD_GLES2(glGetIntegerv); + LOAD_GLES2(glBindTexture); + LOAD_GLES2(glUniform1i); + LOAD_GLES2(glDrawElements); + + ovrTracking2 updatedTracking = *tracking; + + //Get orientation + // We extract Yaw, Pitch, Roll instead of directly using the orientation + // to allow "additional" yaw manipulation with mouse/controller. + const ovrQuatf quatHmd = tracking->HeadPose.Pose.Orientation; + const ovrVector3f positionHmd = tracking->HeadPose.Pose.Position; + QuatToYawPitchRoll(quatHmd, hmdorientation); + setHMDPosition(positionHmd.x, positionHmd.y, positionHmd.z); + + //TODO: fix + if (true) { //cl_trackingmode.flags == 0) { + //Use hmd position for world position + setWorldPosition(positionHmd.x, positionHmd.y, positionHmd.z); + } + + ALOGV(" HMD-Yaw: %f", hmdorientation[YAW]); + ALOGV(" HMD-Position: %f, %f, %f", positionHmd.x, positionHmd.y, positionHmd.z); + + //Set move information - if showing menu, don't pass head orientation through +// QC_MoveEvent(hmdorientation[YAW], hmdorientation[PITCH], hmdorientation[ROLL]); + + //Set everything up + Host_BeginFrame(); + + ovrMatrix4f eyeViewMatrixTransposed[2]; + eyeViewMatrixTransposed[0] = ovrMatrix4f_Transpose( &updatedTracking.Eye[0].ViewMatrix ); + eyeViewMatrixTransposed[1] = ovrMatrix4f_Transpose( &updatedTracking.Eye[1].ViewMatrix ); + + ovrMatrix4f projectionMatrixTransposed[2]; + projectionMatrixTransposed[0] = ovrMatrix4f_Transpose( &updatedTracking.Eye[0].ProjectionMatrix ); + projectionMatrixTransposed[1] = ovrMatrix4f_Transpose( &updatedTracking.Eye[1].ProjectionMatrix ); + + + ovrLayerProjection2 layer = vrapi_DefaultLayerProjection2(); + layer.HeadPose = updatedTracking.HeadPose; + for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ ) + { + ovrFramebuffer * frameBuffer = &renderer->FrameBuffer[renderer->NumBuffers == 1 ? 0 : eye]; + layer.Textures[eye].ColorSwapChain = frameBuffer->ColorTextureSwapChain; + layer.Textures[eye].SwapChainIndex = frameBuffer->TextureSwapChainIndex; + + ovrMatrix4f projectionMatrix; + if (bigScreen) { + projectionMatrix = ovrMatrix4f_CreateProjectionFov(horizFOV, vertFOV, + 0.0f, 0.0f, 0.1f, + 0.0f); + } else{ + projectionMatrix = ovrMatrix4f_CreateProjectionFov(horizFOV, vertFOV+4.0f, + 0.0f, 0.0f, 0.1f, + 0.0f); + } +// layer.Textures[eye].TexCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromProjection( +// &projectionMatrix); + + //Gear VR + layer.Textures[eye].TexCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromProjection( &updatedTracking.Eye[eye].ProjectionMatrix ); + + layer.Textures[eye].TextureRect.x = 0; + layer.Textures[eye].TextureRect.y = 0; + layer.Textures[eye].TextureRect.width = 1.0f; + layer.Textures[eye].TextureRect.height = 1.0f; + } + layer.Header.Flags |= VRAPI_FRAME_LAYER_FLAG_CHROMATIC_ABERRATION_CORRECTION; + + // Render the eye images. + for ( int eye = 0; eye < renderer->NumBuffers; eye++ ) + { + bool screen = false; + ovrFramebuffer * frameBuffer = &renderer->FrameBuffer[eye]; + if (screen)//bigScreen != 0 || demoplayback) + frameBuffer = &renderer->L1VRFrameBuffer; + + ovrFramebuffer_SetCurrent( frameBuffer ); + + { + GL( glEnable( GL_SCISSOR_TEST ) ); + GL( glDepthMask( GL_TRUE ) ); + GL( glEnable( GL_DEPTH_TEST ) ); + GL( glDepthFunc( GL_LEQUAL ) ); + + //Weusing the size of the render target + GL( glViewport( 0, 0, frameBuffer->Width, frameBuffer->Height ) ); + GL( glScissor( 0, 0, frameBuffer->Width, frameBuffer->Height ) ); + + GL( glClearColor( 0.3f, 0.0f, 0.0f, 1.0f ) ); + GL( glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ); + GL( glDisable(GL_SCISSOR_TEST)); + + //Now do the drawing for this eye + Host_Frame(eye); + } + + //Clear edge to prevent smearing + ovrFramebuffer_ClearEdgeTexels( frameBuffer ); + + if (screen)//bigScreen != 0 || demoplayback)// || key_consoleactive) + { + frameBuffer = &renderer->FrameBuffer[eye]; + ovrFramebuffer_SetCurrent( frameBuffer ); + + // Apply the projection and view transformation + ovrMatrix4f modelView = ovrMatrix4f_Multiply( &updatedTracking.Eye[0].ViewMatrix, &rotation ); + modelView = ovrMatrix4f_Multiply( &modelView, &modelScreen ); + ovrMatrix4f modelViewProjection = ovrMatrix4f_Multiply( &renderer->ProjectionMatrix, &modelView ); + + GLint originalTex0 = 0; + GLint originalTex1 = 0; + GL( gles_glEnable( GL_SCISSOR_TEST ) ); + GL( gles_glDepthMask( GL_TRUE ) ); + GL( gles_glEnable( GL_DEPTH_TEST ) ); + GL( gles_glDepthFunc( GL_LEQUAL ) ); + GL( gles_glViewport( 0, 0, frameBuffer->Width, frameBuffer->Height ) ); + GL( gles_glScissor( 0, 0, frameBuffer->Width, frameBuffer->Height ) ); + GL( gles_glClearColor( 0.01f, 0.0f, 0.0f, 1.0f ) ); + GL( gles_glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ); + GL( gles_glDisable(GL_SCISSOR_TEST)); + + GL( gles_glUseProgram(sp_Image)); + + // Set the position of the screen + GL( gles_glVertexAttribPointer(positionParam, 3, GL_FLOAT, GL_FALSE, 0, SCREEN_COORDS)); + + // Prepare the texture coordinates + GL( gles_glVertexAttribPointer(texCoordParam, 2, GL_FLOAT, GL_FALSE, 0, uvs) ); + + // Apply the projection and view transformation + modelView = ovrMatrix4f_Multiply( &modelView, &modelScreen ); + + GL( gles_glUniformMatrix4fv(modelViewProjectionParam, 1, GL_TRUE, (const GLfloat *)modelViewProjection.M[0]) ); + + GL( gles_glActiveTexture(GL_TEXTURE0) ); + + GLuint colorTexture = vrapi_GetTextureSwapChainHandle( + renderer->L1VRFrameBuffer.ColorTextureSwapChain, + renderer->L1VRFrameBuffer.TextureSwapChainIndex); + gles_glGetIntegerv(GL_TEXTURE_BINDING_2D, &originalTex0); + GL( gles_glBindTexture( GL_TEXTURE_2D, colorTexture ) ); + + // Set the sampler texture unit to our fbo's color texture + GL( gles_glUniform1i(samplerParam, 0) ); + + //Bind vignette texture to texture 1 + GL( gles_glActiveTexture( GL_TEXTURE1 ) ); + gles_glGetIntegerv(GL_TEXTURE_BINDING_2D, &originalTex1); + GL( gles_glBindTexture( GL_TEXTURE_2D, vignetteTexture) ); + GL( gles_glUniform1i(vignetteParam, 1) ); + + // Draw the triangles + GL( gles_glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices) ); + + + //Restore previously active textures + GL( gles_glBindTexture(GL_TEXTURE_2D, originalTex1) ); + GL( gles_glActiveTexture(GL_TEXTURE0) ); + GL( gles_glBindTexture(GL_TEXTURE_2D, originalTex0) ); + + + //Clear edge to prevent smearing + ovrFramebuffer_ClearEdgeTexels( frameBuffer ); + } + + ovrFramebuffer_Resolve( frameBuffer ); + ovrFramebuffer_Advance( frameBuffer ); + } + + Host_EndFrame(); + + ovrFramebuffer_SetNone(); + + return layer; +} + +/* +================================================================================ + +ovrRenderThread + +================================================================================ +*/ + + +/* +================================================================================ + +ovrApp + +================================================================================ +*/ + +typedef struct +{ + ovrJava Java; + ovrEgl Egl; + ANativeWindow * NativeWindow; + bool Resumed; + ovrMobile * Ovr; + long long FrameIndex; + double DisplayTime; + int SwapInterval; + int CpuLevel; + int GpuLevel; + int MainThreadTid; + int RenderThreadTid; + ovrRenderer Renderer; +} ovrApp; + +static void ovrApp_Clear( ovrApp * app ) +{ + app->Java.Vm = NULL; + app->Java.Env = NULL; + app->Java.ActivityObject = NULL; + app->NativeWindow = NULL; + app->Resumed = false; + app->Ovr = NULL; + app->FrameIndex = 1; + app->DisplayTime = 0; + app->SwapInterval = 1; + app->CpuLevel = 2; + app->GpuLevel = 2; + app->MainThreadTid = 0; + app->RenderThreadTid = 0; + + ovrEgl_Clear( &app->Egl ); + + ovrRenderer_Clear( &app->Renderer ); +} + +static void ovrApp_PushBlackFinal( ovrApp * app ) +{ + int frameFlags = 0; + frameFlags |= VRAPI_FRAME_FLAG_FLUSH | VRAPI_FRAME_FLAG_FINAL; + + ovrLayerProjection2 layer = vrapi_DefaultLayerBlackProjection2(); + layer.Header.Flags |= VRAPI_FRAME_LAYER_FLAG_INHIBIT_SRGB_FRAMEBUFFER; + + const ovrLayerHeader2 * layers[] = + { + &layer.Header + }; + + ovrSubmitFrameDescription2 frameDesc = {}; + frameDesc.Flags = frameFlags; + frameDesc.SwapInterval = 1; + frameDesc.FrameIndex = app->FrameIndex; + frameDesc.DisplayTime = app->DisplayTime; + frameDesc.LayerCount = 1; + frameDesc.Layers = layers; + + vrapi_SubmitFrame2( app->Ovr, &frameDesc ); +} + +static void ovrApp_HandleVrModeChanges( ovrApp * app ) +{ + if ( app->Resumed != false && app->NativeWindow != NULL ) + { + if ( app->Ovr == NULL ) + { + ovrModeParms parms = vrapi_DefaultModeParms( &app->Java ); + // Must reset the FLAG_FULLSCREEN window flag when using a SurfaceView + parms.Flags |= VRAPI_MODE_FLAG_RESET_WINDOW_FULLSCREEN; + + parms.Flags |= VRAPI_MODE_FLAG_NATIVE_WINDOW; + parms.Display = (size_t)app->Egl.Display; + parms.WindowSurface = (size_t)app->NativeWindow; + parms.ShareContext = (size_t)app->Egl.Context; + + ALOGV( " eglGetCurrentSurface( EGL_DRAW ) = %p", eglGetCurrentSurface( EGL_DRAW ) ); + + ALOGV( " vrapi_EnterVrMode()" ); + + app->Ovr = vrapi_EnterVrMode( &parms ); + + ALOGV( " eglGetCurrentSurface( EGL_DRAW ) = %p", eglGetCurrentSurface( EGL_DRAW ) ); + + // If entering VR mode failed then the ANativeWindow was not valid. + if ( app->Ovr == NULL ) + { + ALOGE( "Invalid ANativeWindow!" ); + app->NativeWindow = NULL; + } + + // Set performance parameters once we have entered VR mode and have a valid ovrMobile. + if ( app->Ovr != NULL ) + { + vrapi_SetClockLevels( app->Ovr, app->CpuLevel, app->GpuLevel ); + + ALOGV( " vrapi_SetClockLevels( %d, %d )", app->CpuLevel, app->GpuLevel ); + + vrapi_SetPerfThread( app->Ovr, VRAPI_PERF_THREAD_TYPE_MAIN, app->MainThreadTid ); + + ALOGV( " vrapi_SetPerfThread( MAIN, %d )", app->MainThreadTid ); + + vrapi_SetPerfThread( app->Ovr, VRAPI_PERF_THREAD_TYPE_RENDERER, app->RenderThreadTid ); + + ALOGV( " vrapi_SetPerfThread( RENDERER, %d )", app->RenderThreadTid ); + } + } + } + else + { + if ( app->Ovr != NULL ) + { + ALOGV( " eglGetCurrentSurface( EGL_DRAW ) = %p", eglGetCurrentSurface( EGL_DRAW ) ); + + ALOGV( " vrapi_LeaveVrMode()" ); + + vrapi_LeaveVrMode( app->Ovr ); + app->Ovr = NULL; + + ALOGV( " eglGetCurrentSurface( EGL_DRAW ) = %p", eglGetCurrentSurface( EGL_DRAW ) ); + } + } +} + +static void handleTrackedControllerButton(ovrInputStateTrackedRemote * trackedRemoteState, ovrInputStateTrackedRemote * prevTrackedRemoteState, uint32_t button, int key) +{ + if ((trackedRemoteState->Buttons & button) != (prevTrackedRemoteState->Buttons & button)) + { + Key_Event(key, (trackedRemoteState->Buttons & button) > 0 ? 1 : 0); + } +} +/* +static void rotateAboutOrigin(float v1, float v2, float rotation, vec2_t out) +{ + vec3_t temp; + temp[0] = v1; + temp[1] = v2; + + vec3_t v; + matrix4x4_t matrix; + Matrix4x4_CreateFromQuakeEntity(&matrix, 0.0f, 0.0f, 0.0f, 0.0f, rotation, 0.0f, 1.0f); + Matrix4x4_Transform(&matrix, temp, v); + + out[0] = v[0]; + out[1] = v[1]; +} + + +static void rotateAboutOrigin2(vec3_t in, float pitch, float yaw, vec3_t out) +{ + vec3_t v; + matrix4x4_t matrix; + Matrix4x4_CreateFromQuakeEntity(&matrix, 0.0f, 0.0f, 0.0f, pitch, yaw, 0.0f, 1.0f); + Matrix4x4_Transform(&matrix, in, v); + Vector2Copy(out, v); +} +*/ +ovrInputStateTrackedRemote leftTrackedRemoteState_old; +ovrInputStateTrackedRemote leftTrackedRemoteState_new; +ovrTracking leftRemoteTracking; +ovrInputStateTrackedRemote rightTrackedRemoteState_old; +ovrInputStateTrackedRemote rightTrackedRemoteState_new; +ovrTracking rightRemoteTracking; + +//Text Input stuff +bool textInput = false; +int shift = 0; +int left_grid = 0; +char left_lower[3][10] = {"bcfihgdae", "klorqpmjn", "tuwzyxvs "}; +char left_shift[3][10] = {"BCFIHGDAE", "KLORQPMJN", "TUWZYXVS "}; +int right_grid = 0; +char right_lower[2][10] = {"236987415", "+-)]&[(?0"}; +char right_shift[2][10] = {"\"*:|._~/#", "%^}>,<{\\@"}; + +char left_grid_map[2][3][3][8] = { + { + { + "a b c", "j k l", "s t u" + }, + { + "d e f", "m n o", "v w" + }, + { + "g h i", "p q r", "x y z" + }, + }, + { + { + "A B C", "J K L", "S T U" + }, + { + "D E F", "M N O", "V W" + }, + { + "G H I", "P Q R", "X Y Z" + }, + + } +}; + + +char right_grid_map[2][3][2][8] = { + { + { + "1 2 3", "? + -" + }, + { + "4 5 6", "( 0 )" + }, + { + "7 8 9", "[ & ]" + }, + }, + { + { + "/ \" *", "\\ % ^" + }, + { + "~ # :", "{ @ }" + }, + { + "_ . |", "< , >" + }, + } +}; + + +static int getCharacter(float x, float y) +{ + int c = 8; + if (x < -0.3f || x > 0.3f || y < -0.3f || y > 0.3f) + { + if (x == 0.0f) + { + if (y > 0.0f) + { + c = 0; + } + else + { + c = 4; + } + } + else + { + float angle = atanf(y / x) / ((float)M_PI / 180.0f); + if (x > 0.0f) + { + c = (int)(((90.0f - angle) + 22.5f) / 45.0f); + } + else + { + c = (int)(((90.0f - angle) + 22.5f) / 45.0f) + 4; + if (c == 8) + c = 0; + } + } + } + + return c; +} + +extern int IN_TouchEvent( touchEventType type, int fingerID, float x, float y, float dx, float dy ); + +float initialTouchX, initialTouchY; + +static void ovrApp_HandleInput( ovrApp * app ) +{ + float remote_movementSideways = 0.0f; + float remote_movementForward = 0.0f; + float positional_movementSideways = 0.0f; + float positional_movementForward = 0.0f; + float controllerAngles[3]; + + //The amount of yaw changed by controller + //TODO: fixme + float yawOffset = 0.0f;//cl.viewangles[YAW] - hmdorientation[YAW]; + + float trackepadMaxX,trackepadMaxY; + + for ( int i = 0; ; i++ ) { + ovrInputCapabilityHeader cap; + ovrResult result = vrapi_EnumerateInputDevices(app->Ovr, i, &cap); + if (result < 0) { + break; + } + + if (cap.Type == ovrControllerType_TrackedRemote) { + ovrTracking remoteTracking; + ovrInputStateTrackedRemote trackedRemoteState; + trackedRemoteState.Header.ControllerType = ovrControllerType_TrackedRemote; + result = vrapi_GetCurrentInputState(app->Ovr, i, &trackedRemoteState.Header); + + if (result == ovrSuccess) { + ovrInputTrackedRemoteCapabilities remoteCapabilities; + remoteCapabilities.Header = cap; + result = vrapi_GetInputDeviceCapabilities(app->Ovr, &remoteCapabilities.Header); + + result = vrapi_GetInputTrackingState(app->Ovr, i, app->DisplayTime, + &remoteTracking); + + trackepadMaxX = remoteCapabilities.TrackpadMaxX; + trackepadMaxY = remoteCapabilities.TrackpadMaxY; + + if (remoteCapabilities.ControllerCapabilities & ovrControllerCaps_RightHand) { + rightTrackedRemoteState_new = trackedRemoteState; + rightRemoteTracking = remoteTracking; + } else{ + leftTrackedRemoteState_new = trackedRemoteState; + leftRemoteTracking = remoteTracking; + } + } + } + } + + ovrInputStateTrackedRemote *dominantTrackedRemoteState = cl_righthanded.flags ? &rightTrackedRemoteState_new : &leftTrackedRemoteState_new; + ovrInputStateTrackedRemote *dominantTrackedRemoteStateOld = cl_righthanded.flags ? &rightTrackedRemoteState_old : &leftTrackedRemoteState_old; + ovrTracking *dominantRemoteTracking = cl_righthanded.flags ? &rightRemoteTracking : &leftRemoteTracking; + ovrInputStateTrackedRemote *offHandTrackedRemoteState = !cl_righthanded.flags ? &rightTrackedRemoteState_new : &leftTrackedRemoteState_new; + ovrInputStateTrackedRemote *offHandTrackedRemoteStateOld = !cl_righthanded.flags ? &rightTrackedRemoteState_old : &leftTrackedRemoteState_old; + ovrTracking *offHandRemoteTracking = !cl_righthanded.flags ? &rightRemoteTracking : &leftRemoteTracking; + +/* if (textInput) + { + //Toggle text input + if ((leftTrackedRemoteState_new.Buttons & ovrButton_Y) && + (leftTrackedRemoteState_new.Buttons & ovrButton_Y) != + (leftTrackedRemoteState_old.Buttons & ovrButton_Y)) { + textInput = !textInput; +// SCR_CenterPrint("Text Input: Disabled"); + } + + int left_char_index = getCharacter(leftTrackedRemoteState_new.Joystick.x, leftTrackedRemoteState_new.Joystick.y); + int right_char_index = getCharacter(rightTrackedRemoteState_new.Joystick.x, rightTrackedRemoteState_new.Joystick.y); + + //Toggle Shift + if ((leftTrackedRemoteState_new.Buttons & ovrButton_X) && + (leftTrackedRemoteState_new.Buttons & ovrButton_X) != + (leftTrackedRemoteState_old.Buttons & ovrButton_X)) { + shift = 1 - shift; + } + + //Cycle Left Grid + if ((leftTrackedRemoteState_new.Buttons & ovrButton_GripTrigger) && + (leftTrackedRemoteState_new.Buttons & ovrButton_GripTrigger) != + (leftTrackedRemoteState_old.Buttons & ovrButton_GripTrigger)) { + left_grid = (++left_grid) % 3; + } + + //Cycle Right Grid + if ((rightTrackedRemoteState_new.Buttons & ovrButton_GripTrigger) && + (rightTrackedRemoteState_new.Buttons & ovrButton_GripTrigger) != + (rightTrackedRemoteState_old.Buttons & ovrButton_GripTrigger)) { + right_grid = (++right_grid) % 2; + } + + char left_char; + char right_char; + if (shift) + { + left_char = left_shift[left_grid][left_char_index]; + right_char = right_shift[right_grid][right_char_index]; + } else{ + left_char = left_lower[left_grid][left_char_index]; + right_char = right_lower[right_grid][right_char_index]; + } + + //Enter + if ((rightTrackedRemoteState_new.Buttons & ovrButton_A) != + (rightTrackedRemoteState_old.Buttons & ovrButton_A)) { + //QC_KeyEvent((rightTrackedRemoteState_new.Buttons & ovrButton_A) > 0 ? 1 : 0, K_ENTER, 0); + } + + //Delete + if ((rightTrackedRemoteState_new.Buttons & ovrButton_B) != + (rightTrackedRemoteState_old.Buttons & ovrButton_B)) { + //QC_KeyEvent((rightTrackedRemoteState_new.Buttons & ovrButton_B) > 0 ? 1 : 0, K_BACKSPACE, 0); + } + + //Use Left Character + if ((leftTrackedRemoteState_new.Buttons & ovrButton_Trigger) != + (leftTrackedRemoteState_old.Buttons & ovrButton_Trigger)) { + if (left_char == ' ') + { + Key_Event(); + QC_KeyEvent((leftTrackedRemoteState_new.Buttons & ovrButton_Trigger) > 0 ? 1 : 0, + 0, left_char); + + } else + { + QC_KeyEvent((leftTrackedRemoteState_new.Buttons & ovrButton_Trigger) > 0 ? 1 : 0, + left_char, left_char); + + } + } + + //Use Right Character + if ((rightTrackedRemoteState_new.Buttons & ovrButton_Trigger) != + (rightTrackedRemoteState_old.Buttons & ovrButton_Trigger)) { + QC_KeyEvent((rightTrackedRemoteState_new.Buttons & ovrButton_Trigger) > 0 ? 1 : 0, + right_char, right_char); + } + + //Menu button + handleTrackedControllerButton(&leftTrackedRemoteState_new, &leftTrackedRemoteState_old, + ovrButton_Enter, K_ESCAPE); + + + if (textInput) { + //Draw grid maps to screen + char buffer[256]; + + //Give the user an idea of what the buttons are + dpsnprintf(buffer, 256, + " %s %s\n %s %s\n %s %s\n\nText Input: %c %c", + left_grid_map[shift][0][left_grid], right_grid_map[shift][0][right_grid], + left_grid_map[shift][1][left_grid], right_grid_map[shift][1][right_grid], + left_grid_map[shift][2][left_grid], right_grid_map[shift][2][right_grid], + left_char, right_char); + SCR_CenterPrint(buffer); + } + + //Save state + leftTrackedRemoteState_old = leftTrackedRemoteState_new; + rightTrackedRemoteState_old = rightTrackedRemoteState_new; + + } else */ + { + //Hacky menu control + { + const ovrQuatf quatRemote = rightRemoteTracking.HeadPose.Pose.Orientation; + float remoteAngles[3]; + QuatToYawPitchRoll(quatRemote, remoteAngles); + bool touchingTrackpad = (rightTrackedRemoteState_new.TrackpadStatus != 0); + if (touchingTrackpad && + remoteAngles[YAW] > -30.0f && remoteAngles[YAW] < 30.0f && + remoteAngles[PITCH] > -30.0f && remoteAngles[PITCH] < 30.0f) { + + int newRemoteTrigState = (rightTrackedRemoteState_new.Buttons & ovrButton_A) != 0; + int prevRemoteTrigState = (rightTrackedRemoteState_old.Buttons & ovrButton_A) != 0; + + touchEventType t = event_motion; + + float touchX = (remoteAngles[YAW] + 30.0f) / 60.0f; + float touchY = (remoteAngles[PITCH] + 30.0f) / 60.0f; + if (newRemoteTrigState != prevRemoteTrigState) + { + t = newRemoteTrigState ? event_down : event_up; + if (newRemoteTrigState) + { + initialTouchX = touchX; + initialTouchY = touchY; + } + } + + IN_TouchEvent(t, 0, touchX, touchY, initialTouchX - touchX, initialTouchY - touchY); + } + } + + //dominant hand stuff first + { + + weaponOffset[0] = dominantRemoteTracking->HeadPose.Pose.Position.x - hmdPosition[0]; + weaponOffset[1] = dominantRemoteTracking->HeadPose.Pose.Position.y - hmdPosition[1]; + weaponOffset[2] = dominantRemoteTracking->HeadPose.Pose.Position.z - hmdPosition[2]; + + if (false) {//cl_trackingmode.flags == 1) { + //Use controller position for world position + setWorldPosition(dominantRemoteTracking->HeadPose.Pose.Position.x, + dominantRemoteTracking->HeadPose.Pose.Position.y, + dominantRemoteTracking->HeadPose.Pose.Position.z); + } + + ///Weapon location relative to view +/* vec2_t v; + rotateAboutOrigin(weaponOffset[0], weaponOffset[2], -yawOffset, v); + weaponOffset[0] = v[0]; + weaponOffset[2] = v[1]; +*/ + //Set gun angles + const ovrQuatf quatRemote = dominantRemoteTracking->HeadPose.Pose.Orientation; + QuatToYawPitchRoll(quatRemote, gunangles); + + //TODO: THIS NEEDS WORK!! - can't get it working and it is doing my head in!! + /* // Adjust right (+ve), adjust Back (+ve), up (+ve) + vec3_t adjustment; + //VectorSet(adjustment, cl_weapon_offset_lr.value, cl_weapon_offset_ud.value, cl_weapon_offset_fb.value); + VectorSet(adjustment, 0.0f, 0.2f, 0.2f); + rotateAboutOrigin2(adjustment, gunangles[PITCH], gunangles[YAW]-yawOffset, adjustment); + VectorAdd(adjustment, weaponOffset, weaponOffset);*/ + + //Adjust gun pitch for user preference +// gunangles[PITCH] += cl_weaponpitchadjust.value; + gunangles[YAW] += yawOffset; + + //Change laser sight on joystick click + if ((dominantTrackedRemoteState->Buttons & ovrButton_Joystick) && + (dominantTrackedRemoteState->Buttons & ovrButton_Joystick) != + (dominantTrackedRemoteStateOld->Buttons & ovrButton_Joystick)) { +// Cvar_SetValueQuick(&r_lasersight, (r_lasersight.flags + 1) % 3); + } + } + + //off-hand stuff + float controllerYawHeading; + float hmdYawHeading; + { + QuatToYawPitchRoll(offHandRemoteTracking->HeadPose.Pose.Orientation, + controllerAngles); + + controllerYawHeading = controllerAngles[YAW] - gunangles[YAW] + yawOffset; + hmdYawHeading = hmdorientation[YAW] - gunangles[YAW] + yawOffset; + +#ifndef NDEBUG + //Change heading mode on click of off=hand joystick + if ((offHandTrackedRemoteState->Buttons & ovrButton_Joystick) && bigScreen == 0 && + (offHandTrackedRemoteState->Buttons & ovrButton_Joystick) != + (offHandTrackedRemoteStateOld->Buttons & ovrButton_Joystick)) { +// Cvar_SetValueQuick(&cl_walkdirection, 1 - cl_walkdirection.flags); +// if (cl_walkdirection.flags == 1) { +// SCR_CenterPrint("Heading Mode: Direction of HMD"); +// } else { +// SCR_CenterPrint("Heading Mode: Direction of off-hand controller"); +// } + } +#endif + } + + //Right-hand specific stuff + { + ALOGE(" Right-Controller-Position: %f, %f, %f", + rightRemoteTracking.HeadPose.Pose.Position.x, + rightRemoteTracking.HeadPose.Pose.Position.y, + rightRemoteTracking.HeadPose.Pose.Position.z); + + //This section corrects for the fact that the controller actually controls direction of movement, but we want to move relative to the direction the + //player is facing for positional tracking + //TODO: fixme! + float multiplier = 1.0f;/*arbitrary value that works ->*/ + //2200.0f / cl_forwardspeed.value; + +/* vec2_t v; + rotateAboutOrigin(-positionDeltaThisFrame[0] * multiplier, + positionDeltaThisFrame[2] * multiplier, -hmdorientation[YAW], v); + positional_movementSideways = v[0]; + positional_movementForward = v[1]; +*/ + + long t = Sys_Milliseconds(); + delta = t - oldtime; + oldtime = t; + if (delta > 1000) + delta = 1000; +// QC_MotionEvent(delta, rightTrackedRemoteState_new.Joystick.x, +// rightTrackedRemoteState_new.Joystick.y); + + if (bigScreen != 0) { + + int rightJoyState = (rightTrackedRemoteState_new.Joystick.x > 0.7f ? 1 : 0); + if (rightJoyState != (rightTrackedRemoteState_old.Joystick.x > 0.7f ? 1 : 0)) { + Key_Event('d', rightJoyState); + //QC_KeyEvent(rightJoyState, 'd', 0); + } + rightJoyState = (rightTrackedRemoteState_new.Joystick.x < -0.7f ? 1 : 0); + if (rightJoyState != (rightTrackedRemoteState_old.Joystick.x < -0.7f ? 1 : 0)) { + Key_Event('a', rightJoyState); + //QC_KeyEvent(rightJoyState, 'a', 0); + } + rightJoyState = (rightTrackedRemoteState_new.Joystick.y < -0.7f ? 1 : 0); + if (rightJoyState != (rightTrackedRemoteState_old.Joystick.y < -0.7f ? 1 : 0)) { + Key_Event(K_DOWNARROW, rightJoyState); + //QC_KeyEvent(rightJoyState, K_DOWNARROW, 0); + } + rightJoyState = (rightTrackedRemoteState_new.Joystick.y > 0.7f ? 1 : 0); + if (rightJoyState != (rightTrackedRemoteState_old.Joystick.y > 0.7f ? 1 : 0)) { + Key_Event(K_UPARROW, rightJoyState); + //QC_KeyEvent(rightJoyState, K_UPARROW, 0); + } + + //Click an option + handleTrackedControllerButton(&rightTrackedRemoteState_new, + &rightTrackedRemoteState_old, ovrButton_A, K_ENTER); + + //Back button + handleTrackedControllerButton(&rightTrackedRemoteState_new, + &rightTrackedRemoteState_old, ovrButton_B, K_ESCAPE); + } else { + //Jump + handleTrackedControllerButton(&rightTrackedRemoteState_new, + &rightTrackedRemoteState_old, ovrButton_A, K_SPACE); + } + + if (cl_righthanded.flags) { + //Fire + handleTrackedControllerButton(&rightTrackedRemoteState_new, + &rightTrackedRemoteState_old, + ovrButton_Trigger, K_MOUSE1); + } else { + //Run + handleTrackedControllerButton(&rightTrackedRemoteState_new, + &rightTrackedRemoteState_old, + ovrButton_Trigger, K_SHIFT); + } + + //Next Weapon + handleTrackedControllerButton(&rightTrackedRemoteState_new, + &rightTrackedRemoteState_old, ovrButton_GripTrigger, '/'); + + //Adjust weapon aim pitch + if ((rightTrackedRemoteState_new.Buttons & ovrButton_B) && + (rightTrackedRemoteState_new.Buttons & ovrButton_B) != + (rightTrackedRemoteState_old.Buttons & ovrButton_B)) { +// float newPitchAdjust = cl_weaponpitchadjust.value + 1.0f; +// if (newPitchAdjust > 23.0f) { +// newPitchAdjust = -7.0f; +// } + +// Cvar_SetValueQuick(&cl_weaponpitchadjust, newPitchAdjust); +// ALOGV("Pitch Adjust: %f", newPitchAdjust); + } + + rightTrackedRemoteState_old = rightTrackedRemoteState_new; + + } + + //Left-hand specific stuff + { + ALOGE(" Left-Controller-Position: %f, %f, %f", + leftRemoteTracking.HeadPose.Pose.Position.x, + leftRemoteTracking.HeadPose.Pose.Position.y, + leftRemoteTracking.HeadPose.Pose.Position.z); + + //Menu button + handleTrackedControllerButton(&leftTrackedRemoteState_new, &leftTrackedRemoteState_old, + ovrButton_Enter, K_ESCAPE); + + if (bigScreen != 0) { + int leftJoyState = (leftTrackedRemoteState_new.Joystick.x > 0.7f ? 1 : 0); + if (leftJoyState != (leftTrackedRemoteState_old.Joystick.x > 0.7f ? 1 : 0)) { + Key_Event('d', leftJoyState); + //QC_KeyEvent(leftJoyState, 'd', 0); + } + leftJoyState = (leftTrackedRemoteState_new.Joystick.x < -0.7f ? 1 : 0); + if (leftJoyState != (leftTrackedRemoteState_old.Joystick.x < -0.7f ? 1 : 0)) { + Key_Event('a', leftJoyState); + //QC_KeyEvent(leftJoyState, 'a', 0); + } + leftJoyState = (leftTrackedRemoteState_new.Joystick.y < -0.7f ? 1 : 0); + if (leftJoyState != (leftTrackedRemoteState_old.Joystick.y < -0.7f ? 1 : 0)) { + Key_Event(K_DOWNARROW, leftJoyState); + // QC_KeyEvent(leftJoyState, K_DOWNARROW, 0); + } + leftJoyState = (leftTrackedRemoteState_new.Joystick.y > 0.7f ? 1 : 0); + if (leftJoyState != (leftTrackedRemoteState_old.Joystick.y > 0.7f ? 1 : 0)) { + Key_Event(K_UPARROW, leftJoyState); +// QC_KeyEvent(leftJoyState, K_UPARROW, 0); + } + } + + + //Adjust to be off-hand controller oriented + vec2_t v; +/* rotateAboutOrigin(leftTrackedRemoteState_new.Joystick.x, + leftTrackedRemoteState_new.Joystick.y, + //cl_walkdirection.flags == 1 ? hmdYawHeading : + controllerYawHeading, + v); +*/ remote_movementSideways = v[0]; + remote_movementForward = v[1]; + + if (cl_righthanded.flags) { + //Run + handleTrackedControllerButton(&leftTrackedRemoteState_new, + &leftTrackedRemoteState_old, + ovrButton_Trigger, K_SHIFT); + } else { + //Fire + handleTrackedControllerButton(&leftTrackedRemoteState_new, + &leftTrackedRemoteState_old, + ovrButton_Trigger, K_MOUSE1); + } + + //Prev Weapon + handleTrackedControllerButton(&leftTrackedRemoteState_new, &leftTrackedRemoteState_old, + ovrButton_GripTrigger, '#'); + +#ifndef NDEBUG + //Give all weapons and all ammo and god mode + if ((leftTrackedRemoteState_new.Buttons & ovrButton_X) && + (leftTrackedRemoteState_new.Buttons & ovrButton_X) != + (leftTrackedRemoteState_old.Buttons & ovrButton_X)) { +// Cbuf_InsertText("God\n"); +// Cbuf_InsertText("Impulse 9\n"); + } +#endif + + //Toggle text input + if ((leftTrackedRemoteState_new.Buttons & ovrButton_Y) && + (leftTrackedRemoteState_new.Buttons & ovrButton_Y) != + (leftTrackedRemoteState_old.Buttons & ovrButton_Y)) { + textInput = !textInput; + } + + + leftTrackedRemoteState_old = leftTrackedRemoteState_new; + } + +// QC_Analog(true, remote_movementSideways + positional_movementSideways, +// remote_movementForward + positional_movementForward); + + + //if (bullettime.flags) + { + float speed = powf(sqrtf(powf(leftTrackedRemoteState_new.Joystick.x, 2) + powf(leftTrackedRemoteState_new.Joystick.y, 2)), 1.1f); + float movement = sqrtf(powf(positionDeltaThisFrame[0] * 30.0f, 2) + powf(positionDeltaThisFrame[1] * 30.0f, 2) + powf(positionDeltaThisFrame[2] * 30.0f, 2)); +// speed = bound(0.12f, (speed > movement) ? speed : movement, 1.0f); +// Cvar_SetValueQuick(&slowmo, speed); + } + } +} + +/* +================================================================================ + +ovrMessageQueue + +================================================================================ +*/ + +typedef enum +{ + MQ_WAIT_NONE, // don't wait + MQ_WAIT_RECEIVED, // wait until the consumer thread has received the message + MQ_WAIT_PROCESSED // wait until the consumer thread has processed the message +} ovrMQWait; + +#define MAX_MESSAGE_PARMS 8 +#define MAX_MESSAGES 1024 + +typedef struct +{ + int Id; + ovrMQWait Wait; + long long Parms[MAX_MESSAGE_PARMS]; +} ovrMessage; + +static void ovrMessage_Init( ovrMessage * message, const int id, const int wait ) +{ + message->Id = id; + message->Wait = wait; + memset( message->Parms, 0, sizeof( message->Parms ) ); +} + +static void ovrMessage_SetPointerParm( ovrMessage * message, int index, void * ptr ) { *(void **)&message->Parms[index] = ptr; } +static void * ovrMessage_GetPointerParm( ovrMessage * message, int index ) { return *(void **)&message->Parms[index]; } +static void ovrMessage_SetIntegerParm( ovrMessage * message, int index, int value ) { message->Parms[index] = value; } +static int ovrMessage_GetIntegerParm( ovrMessage * message, int index ) { return (int)message->Parms[index]; } +static void ovrMessage_SetFloatParm( ovrMessage * message, int index, float value ) { *(float *)&message->Parms[index] = value; } +static float ovrMessage_GetFloatParm( ovrMessage * message, int index ) { return *(float *)&message->Parms[index]; } + +// Cyclic queue with messages. +typedef struct +{ + ovrMessage Messages[MAX_MESSAGES]; + volatile int Head; // dequeue at the head + volatile int Tail; // enqueue at the tail + ovrMQWait Wait; + volatile bool EnabledFlag; + volatile bool PostedFlag; + volatile bool ReceivedFlag; + volatile bool ProcessedFlag; + pthread_mutex_t Mutex; + pthread_cond_t PostedCondition; + pthread_cond_t ReceivedCondition; + pthread_cond_t ProcessedCondition; +} ovrMessageQueue; + +static void ovrMessageQueue_Create( ovrMessageQueue * messageQueue ) +{ + messageQueue->Head = 0; + messageQueue->Tail = 0; + messageQueue->Wait = MQ_WAIT_NONE; + messageQueue->EnabledFlag = false; + messageQueue->PostedFlag = false; + messageQueue->ReceivedFlag = false; + messageQueue->ProcessedFlag = false; + + pthread_mutexattr_t attr; + pthread_mutexattr_init( &attr ); + pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_ERRORCHECK ); + pthread_mutex_init( &messageQueue->Mutex, &attr ); + pthread_mutexattr_destroy( &attr ); + pthread_cond_init( &messageQueue->PostedCondition, NULL ); + pthread_cond_init( &messageQueue->ReceivedCondition, NULL ); + pthread_cond_init( &messageQueue->ProcessedCondition, NULL ); +} + +static void ovrMessageQueue_Destroy( ovrMessageQueue * messageQueue ) +{ + pthread_mutex_destroy( &messageQueue->Mutex ); + pthread_cond_destroy( &messageQueue->PostedCondition ); + pthread_cond_destroy( &messageQueue->ReceivedCondition ); + pthread_cond_destroy( &messageQueue->ProcessedCondition ); +} + +static void ovrMessageQueue_Enable( ovrMessageQueue * messageQueue, const bool set ) +{ + messageQueue->EnabledFlag = set; +} + +static void ovrMessageQueue_PostMessage( ovrMessageQueue * messageQueue, const ovrMessage * message ) +{ + if ( !messageQueue->EnabledFlag ) + { + return; + } + while ( messageQueue->Tail - messageQueue->Head >= MAX_MESSAGES ) + { + usleep( 1000 ); + } + pthread_mutex_lock( &messageQueue->Mutex ); + messageQueue->Messages[messageQueue->Tail & ( MAX_MESSAGES - 1 )] = *message; + messageQueue->Tail++; + messageQueue->PostedFlag = true; + pthread_cond_broadcast( &messageQueue->PostedCondition ); + if ( message->Wait == MQ_WAIT_RECEIVED ) + { + while ( !messageQueue->ReceivedFlag ) + { + pthread_cond_wait( &messageQueue->ReceivedCondition, &messageQueue->Mutex ); + } + messageQueue->ReceivedFlag = false; + } + else if ( message->Wait == MQ_WAIT_PROCESSED ) + { + while ( !messageQueue->ProcessedFlag ) + { + pthread_cond_wait( &messageQueue->ProcessedCondition, &messageQueue->Mutex ); + } + messageQueue->ProcessedFlag = false; + } + pthread_mutex_unlock( &messageQueue->Mutex ); +} + +static void ovrMessageQueue_SleepUntilMessage( ovrMessageQueue * messageQueue ) +{ + if ( messageQueue->Wait == MQ_WAIT_PROCESSED ) + { + messageQueue->ProcessedFlag = true; + pthread_cond_broadcast( &messageQueue->ProcessedCondition ); + messageQueue->Wait = MQ_WAIT_NONE; + } + pthread_mutex_lock( &messageQueue->Mutex ); + if ( messageQueue->Tail > messageQueue->Head ) + { + pthread_mutex_unlock( &messageQueue->Mutex ); + return; + } + while ( !messageQueue->PostedFlag ) + { + pthread_cond_wait( &messageQueue->PostedCondition, &messageQueue->Mutex ); + } + messageQueue->PostedFlag = false; + pthread_mutex_unlock( &messageQueue->Mutex ); +} + +static bool ovrMessageQueue_GetNextMessage( ovrMessageQueue * messageQueue, ovrMessage * message, bool waitForMessages ) +{ + if ( messageQueue->Wait == MQ_WAIT_PROCESSED ) + { + messageQueue->ProcessedFlag = true; + pthread_cond_broadcast( &messageQueue->ProcessedCondition ); + messageQueue->Wait = MQ_WAIT_NONE; + } + if ( waitForMessages ) + { + ovrMessageQueue_SleepUntilMessage( messageQueue ); + } + pthread_mutex_lock( &messageQueue->Mutex ); + if ( messageQueue->Tail <= messageQueue->Head ) + { + pthread_mutex_unlock( &messageQueue->Mutex ); + return false; + } + *message = messageQueue->Messages[messageQueue->Head & ( MAX_MESSAGES - 1 )]; + messageQueue->Head++; + pthread_mutex_unlock( &messageQueue->Mutex ); + if ( message->Wait == MQ_WAIT_RECEIVED ) + { + messageQueue->ReceivedFlag = true; + pthread_cond_broadcast( &messageQueue->ReceivedCondition ); + } + else if ( message->Wait == MQ_WAIT_PROCESSED ) + { + messageQueue->Wait = MQ_WAIT_PROCESSED; + } + return true; +} + +/* +================================================================================ + +ovrAppThread + +================================================================================ +*/ + +enum +{ + MESSAGE_ON_CREATE, + MESSAGE_ON_START, + MESSAGE_ON_RESUME, + MESSAGE_ON_PAUSE, + MESSAGE_ON_STOP, + MESSAGE_ON_DESTROY, + MESSAGE_ON_SURFACE_CREATED, + MESSAGE_ON_SURFACE_DESTROYED +}; + +typedef struct +{ + JavaVM * JavaVm; + jobject ActivityObject; + pthread_t Thread; + ovrMessageQueue MessageQueue; + ANativeWindow * NativeWindow; +} ovrAppThread; + +long shutdownCountdown; + +int m_width; +int m_height; +void Android_GetScreenRes(int *width, int *height) +{ + *width=m_width; + *height=m_height; +} + +void Android_MessageBox(const char *title, const char *text) +{ + ALOGE("%s %s", title, text); +} + +void * AppThreadFunction( void * parm ) +{ + ovrAppThread * appThread = (ovrAppThread *)parm; + + ovrJava java; + java.Vm = appThread->JavaVm; + (*java.Vm)->AttachCurrentThread( java.Vm, &java.Env, NULL ); + java.ActivityObject = appThread->ActivityObject; + + // Note that AttachCurrentThread will reset the thread name. + prctl( PR_SET_NAME, (long)"OVR::Main", 0, 0, 0 ); + + const ovrInitParms initParms = vrapi_DefaultInitParms( &java ); + int32_t initResult = vrapi_Initialize( &initParms ); + if ( initResult != VRAPI_INITIALIZE_SUCCESS ) + { + // If intialization failed, vrapi_* function calls will not be available. + exit( 0 ); + } + + ovrApp appState; + ovrApp_Clear( &appState ); + appState.Java = java; + + // This app will handle android gamepad events itself. + vrapi_SetPropertyInt( &appState.Java, VRAPI_EAT_NATIVE_GAMEPAD_EVENTS, 0 ); + + m_width=vrapi_GetSystemPropertyInt( &java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_WIDTH ) * SS_MULTIPLIER; + m_height=vrapi_GetSystemPropertyInt( &java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_HEIGHT ) * SS_MULTIPLIER; + + + ovrEgl_CreateContext( &appState.Egl, NULL ); + + EglInitExtensions(); + + appState.CpuLevel = CPU_LEVEL; + appState.GpuLevel = GPU_LEVEL; + appState.MainThreadTid = gettid(); + + ovrRenderer_Create( &appState.Renderer, &java ); + + //Always use this folder + chdir("/sdcard/xash"); + + //Initialise gl4es + Com_LoadLibrary("gl4es", 0); + + const double startTime = GetTimeInSeconds(); + + for ( bool destroyed = false; destroyed == false; ) + { + for ( ; ; ) + { + ovrMessage message; + const bool waitForMessages = ( appState.Ovr == NULL && destroyed == false ); + if ( !ovrMessageQueue_GetNextMessage( &appThread->MessageQueue, &message, waitForMessages ) ) + { + break; + } + + switch ( message.Id ) + { + case MESSAGE_ON_CREATE: + { + break; + } + case MESSAGE_ON_START: + { + if (!xash_initialised) + { + char *arg = (char*)ovrMessage_GetPointerParm( &message, 0 ); + + ALOGV( " Initialising Xash3D Engine" ); + + if (arg) + { +// QC_SetResolution(vrapi_GetSystemPropertyInt( &java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_WIDTH ) * SS_MULTIPLIER, +// vrapi_GetSystemPropertyInt( &java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_HEIGHT ) * SS_MULTIPLIER); + + Host_Main(argc, argv, "valve", false, NULL); + //main(argc, argv); + } + else + { + int argc = 1; char *argv[] = { "xash3d" }; + + Host_Main(argc, argv, "valve", false, NULL); + + //QC_SetResolution(vrapi_GetSystemPropertyInt( &java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_WIDTH ) * SS_MULTIPLIER, + // vrapi_GetSystemPropertyInt( &java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_HEIGHT ) * SS_MULTIPLIER); + + //main(argc, argv); + } + + xash_initialised = true; + + //Ensure game starts with credits active + //MR_ToggleMenu(2); + } + break; + } + case MESSAGE_ON_RESUME: + { + //If we get here, then user has opted not to quit + //jni_resumeAudio(); + appState.Resumed = true; + break; + } + case MESSAGE_ON_PAUSE: + { + //jni_pauseAudio(); + appState.Resumed = false; + break; + } + case MESSAGE_ON_STOP: + { + break; + } + case MESSAGE_ON_DESTROY: + { + appState.NativeWindow = NULL; + destroyed = true; + break; + } + case MESSAGE_ON_SURFACE_CREATED: { appState.NativeWindow = (ANativeWindow *)ovrMessage_GetPointerParm( &message, 0 ); break; } + case MESSAGE_ON_SURFACE_DESTROYED: { appState.NativeWindow = NULL; break; } + } + + ovrApp_HandleVrModeChanges( &appState ); + } + + if ( appState.Ovr == NULL ) + { + continue; + } + + // This is the only place the frame index is incremented, right before + // calling vrapi_GetPredictedDisplayTime(). + appState.FrameIndex++; + + // Create the scene if not yet created. + // The scene is created here to be able to show a loading icon. + if (!xash_initialised || runStatus != -1) + { + // Show a loading icon. + int frameFlags = 0; + frameFlags |= VRAPI_FRAME_FLAG_FLUSH; + + ovrLayerProjection2 blackLayer = vrapi_DefaultLayerBlackProjection2(); + blackLayer.Header.Flags |= VRAPI_FRAME_LAYER_FLAG_INHIBIT_SRGB_FRAMEBUFFER; + + ovrLayerLoadingIcon2 iconLayer = vrapi_DefaultLayerLoadingIcon2(); + iconLayer.Header.Flags |= VRAPI_FRAME_LAYER_FLAG_INHIBIT_SRGB_FRAMEBUFFER; + + const ovrLayerHeader2 * layers[] = + { + &blackLayer.Header, + &iconLayer.Header, + }; + + ovrSubmitFrameDescription2 frameDesc = {}; + frameDesc.Flags = frameFlags; + frameDesc.SwapInterval = 1; + frameDesc.FrameIndex = appState.FrameIndex; + frameDesc.DisplayTime = appState.DisplayTime; + frameDesc.LayerCount = 2; + frameDesc.Layers = layers; + + vrapi_SubmitFrame2( appState.Ovr, &frameDesc ); + } + + if (runStatus == -1) { +#ifndef NDEBUG + if (appState.FrameIndex > 10800) + { + //Trigger shutdown after a couple of minutes in debug mode + runStatus = 0; + } +#endif + // Get the HMD pose, predicted for the middle of the time period during which + // the new eye images will be displayed. The number of frames predicted ahead + // depends on the pipeline depth of the engine and the synthesis rate. + // The better the prediction, the less black will be pulled in at the edges. + const double predictedDisplayTime = vrapi_GetPredictedDisplayTime(appState.Ovr, + appState.FrameIndex); + const ovrTracking2 tracking = vrapi_GetPredictedTracking2(appState.Ovr, + predictedDisplayTime); + + appState.DisplayTime = predictedDisplayTime; + + ovrApp_HandleInput(&appState); + + + // Render eye images and setup the primary layer using ovrTracking2. + const ovrLayerProjection2 worldLayer = ovrRenderer_RenderFrame(&appState.Renderer, + &appState.Java, + &tracking, appState.Ovr); + + const ovrLayerHeader2 *layers[] = + { + &worldLayer.Header + }; + + ovrSubmitFrameDescription2 frameDesc = {}; + frameDesc.Flags = 0; + frameDesc.SwapInterval = appState.SwapInterval; + frameDesc.FrameIndex = appState.FrameIndex; + frameDesc.DisplayTime = appState.DisplayTime; + frameDesc.LayerCount = 1; + frameDesc.Layers = layers; + + // Hand over the eye images to the time warp. + vrapi_SubmitFrame2(appState.Ovr, &frameDesc); + } + else + { + //We are now shutting down + if (runStatus == 0) + { + //Give us half a second (36 frames) + shutdownCountdown = 36; + runStatus++; + } else if (runStatus == 1) + { + if (--shutdownCountdown == 0) { + runStatus++; + } + } else if (runStatus == 2) + { + Host_Shutdown(); + runStatus++; + } else if (runStatus == 3) + { + ovrRenderer_Destroy( &appState.Renderer ); + ovrEgl_DestroyContext( &appState.Egl ); + (*java.Vm)->DetachCurrentThread( java.Vm ); + vrapi_Shutdown(); + exit( 0 ); + } + } + } + + return NULL; +} + +static void ovrAppThread_Create( ovrAppThread * appThread, JNIEnv * env, jobject activityObject ) +{ + (*env)->GetJavaVM( env, &appThread->JavaVm ); + appThread->ActivityObject = (*env)->NewGlobalRef( env, activityObject ); + appThread->Thread = 0; + appThread->NativeWindow = NULL; + ovrMessageQueue_Create( &appThread->MessageQueue ); + + const int createErr = pthread_create( &appThread->Thread, NULL, AppThreadFunction, appThread ); + if ( createErr != 0 ) + { + ALOGE( "pthread_create returned %i", createErr ); + } +} + +static void ovrAppThread_Destroy( ovrAppThread * appThread, JNIEnv * env ) +{ + pthread_join( appThread->Thread, NULL ); + (*env)->DeleteGlobalRef( env, appThread->ActivityObject ); + ovrMessageQueue_Destroy( &appThread->MessageQueue ); +} + +/* +================================================================================ + +Activity lifecycle + +================================================================================ +*/ + +int JNI_OnLoad(JavaVM* vm, void* reserved) +{ + JNIEnv *env; + if((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) + { + ALOGE("Failed JNI_OnLoad"); + return -1; + } + + return JNI_VERSION_1_4; +} + +JNIEXPORT jlong JNICALL Java_com_drbeef_lambda1vr_GLES3JNILib_onCreate( JNIEnv * env, jclass activityClass, jobject activity, + jstring commandLineParams) +{ + ALOGV( " GLES3JNILib::onCreate()" ); + + /* the global arg_xxx structs are initialised within the argtable */ + void *argtable[] = { + ss = arg_dbl0("s", "supersampling", "", "super sampling value (e.g. 1.0)"), + cpu = arg_int0("c", "cpu", "", "CPU perf index 1-3 (default: 2)"), + gpu = arg_int0("g", "gpu", "", "GPU perf index 1-3 (default: 3)"), + msaa = arg_dbl0("m", "msaa", "", "msaa value 1-4 (default 1)"), // Don't think this actually works + end = arg_end(20) + }; + + jboolean iscopy; + const char *arg = (*env)->GetStringUTFChars(env, commandLineParams, &iscopy); + + char *cmdLine = NULL; + if (arg && strlen(arg)) + { + cmdLine = strdup(arg); + } + + (*env)->ReleaseStringUTFChars(env, commandLineParams, arg); + + ALOGV("Command line %s", cmdLine); + argv = malloc(sizeof(char*) * 255); + argc = ParseCommandLine(strdup(cmdLine), argv); + + /* verify the argtable[] entries were allocated sucessfully */ + if (arg_nullcheck(argtable) == 0) { + /* Parse the command line as defined by argtable[] */ + arg_parse(argc, argv, argtable); + + if (ss->count > 0 && ss->dval[0] > 0.0) + { + SS_MULTIPLIER = ss->dval[0]; + } + + if (cpu->count > 0 && cpu->ival[0] > 0 && cpu->ival[0] < 10) + { + CPU_LEVEL = cpu->ival[0]; + } + + if (gpu->count > 0 && gpu->ival[0] > 0 && gpu->ival[0] < 10) + { + GPU_LEVEL = gpu->ival[0]; + } + + if (msaa->count > 0 && msaa->dval[0] > 0 && msaa->dval[0] < 5) + { + NUM_MULTI_SAMPLES = msaa->dval[0]; + } + } + + + ovrAppThread * appThread = (ovrAppThread *) malloc( sizeof( ovrAppThread ) ); + ovrAppThread_Create( appThread, env, activity ); + + ovrMessageQueue_Enable( &appThread->MessageQueue, true ); + ovrMessage message; + ovrMessage_Init( &message, MESSAGE_ON_CREATE, MQ_WAIT_PROCESSED ); + ovrMessageQueue_PostMessage( &appThread->MessageQueue, &message ); + + return (jlong)((size_t)appThread); +} + + +JNIEXPORT void JNICALL Java_com_drbeef_lambda1vr_GLES3JNILib_onStart( JNIEnv * env, jobject obj, jlong handle) +{ + ALOGV( " GLES3JNILib::onStart()" ); + + ovrAppThread * appThread = (ovrAppThread *)((size_t)handle); + ovrMessage message; + ovrMessage_Init( &message, MESSAGE_ON_START, MQ_WAIT_PROCESSED ); + ovrMessageQueue_PostMessage( &appThread->MessageQueue, &message ); +} + +JNIEXPORT void JNICALL Java_com_drbeef_lambda1vr_GLES3JNILib_onResume( JNIEnv * env, jobject obj, jlong handle ) +{ + ALOGV( " GLES3JNILib::onResume()" ); + ovrAppThread * appThread = (ovrAppThread *)((size_t)handle); + ovrMessage message; + ovrMessage_Init( &message, MESSAGE_ON_RESUME, MQ_WAIT_PROCESSED ); + ovrMessageQueue_PostMessage( &appThread->MessageQueue, &message ); +} + +JNIEXPORT void JNICALL Java_com_drbeef_lambda1vr_GLES3JNILib_onPause( JNIEnv * env, jobject obj, jlong handle ) +{ + ALOGV( " GLES3JNILib::onPause()" ); + ovrAppThread * appThread = (ovrAppThread *)((size_t)handle); + ovrMessage message; + ovrMessage_Init( &message, MESSAGE_ON_PAUSE, MQ_WAIT_PROCESSED ); + ovrMessageQueue_PostMessage( &appThread->MessageQueue, &message ); +} + +JNIEXPORT void JNICALL Java_com_drbeef_lambda1vr_GLES3JNILib_onStop( JNIEnv * env, jobject obj, jlong handle ) +{ + ALOGV( " GLES3JNILib::onStop()" ); + ovrAppThread * appThread = (ovrAppThread *)((size_t)handle); + ovrMessage message; + ovrMessage_Init( &message, MESSAGE_ON_STOP, MQ_WAIT_PROCESSED ); + ovrMessageQueue_PostMessage( &appThread->MessageQueue, &message ); +} + +JNIEXPORT void JNICALL Java_com_drbeef_lambda1vr_GLES3JNILib_onDestroy( JNIEnv * env, jobject obj, jlong handle ) +{ + ALOGV( " GLES3JNILib::onDestroy()" ); + ovrAppThread * appThread = (ovrAppThread *)((size_t)handle); + ovrMessage message; + ovrMessage_Init( &message, MESSAGE_ON_DESTROY, MQ_WAIT_PROCESSED ); + ovrMessageQueue_PostMessage( &appThread->MessageQueue, &message ); + ovrMessageQueue_Enable( &appThread->MessageQueue, false ); + + ovrAppThread_Destroy( appThread, env ); + free( appThread ); +} + +/* +================================================================================ + +Surface lifecycle + +================================================================================ +*/ + +JNIEXPORT void JNICALL Java_com_drbeef_lambda1vr_GLES3JNILib_onSurfaceCreated( JNIEnv * env, jobject obj, jlong handle, jobject surface ) +{ + ALOGV( " GLES3JNILib::onSurfaceCreated()" ); + ovrAppThread * appThread = (ovrAppThread *)((size_t)handle); + + ANativeWindow * newNativeWindow = ANativeWindow_fromSurface( env, surface ); + if ( ANativeWindow_getWidth( newNativeWindow ) < ANativeWindow_getHeight( newNativeWindow ) ) + { + // An app that is relaunched after pressing the home button gets an initial surface with + // the wrong orientation even though android:screenOrientation="landscape" is set in the + // manifest. The choreographer callback will also never be called for this surface because + // the surface is immediately replaced with a new surface with the correct orientation. + ALOGE( " Surface not in landscape mode!" ); + } + + ALOGV( " NativeWindow = ANativeWindow_fromSurface( env, surface )" ); + appThread->NativeWindow = newNativeWindow; + ovrMessage message; + ovrMessage_Init( &message, MESSAGE_ON_SURFACE_CREATED, MQ_WAIT_PROCESSED ); + ovrMessage_SetPointerParm( &message, 0, appThread->NativeWindow ); + ovrMessageQueue_PostMessage( &appThread->MessageQueue, &message ); +} + +JNIEXPORT void JNICALL Java_com_drbeef_lambda1vr_GLES3JNILib_onSurfaceChanged( JNIEnv * env, jobject obj, jlong handle, jobject surface ) +{ + ALOGV( " GLES3JNILib::onSurfaceChanged()" ); + ovrAppThread * appThread = (ovrAppThread *)((size_t)handle); + + ANativeWindow * newNativeWindow = ANativeWindow_fromSurface( env, surface ); + if ( ANativeWindow_getWidth( newNativeWindow ) < ANativeWindow_getHeight( newNativeWindow ) ) + { + // An app that is relaunched after pressing the home button gets an initial surface with + // the wrong orientation even though android:screenOrientation="landscape" is set in the + // manifest. The choreographer callback will also never be called for this surface because + // the surface is immediately replaced with a new surface with the correct orientation. + ALOGE( " Surface not in landscape mode!" ); + } + + if ( newNativeWindow != appThread->NativeWindow ) + { + if ( appThread->NativeWindow != NULL ) + { + ovrMessage message; + ovrMessage_Init( &message, MESSAGE_ON_SURFACE_DESTROYED, MQ_WAIT_PROCESSED ); + ovrMessageQueue_PostMessage( &appThread->MessageQueue, &message ); + ALOGV( " ANativeWindow_release( NativeWindow )" ); + ANativeWindow_release( appThread->NativeWindow ); + appThread->NativeWindow = NULL; + } + if ( newNativeWindow != NULL ) + { + ALOGV( " NativeWindow = ANativeWindow_fromSurface( env, surface )" ); + appThread->NativeWindow = newNativeWindow; + ovrMessage message; + ovrMessage_Init( &message, MESSAGE_ON_SURFACE_CREATED, MQ_WAIT_PROCESSED ); + ovrMessage_SetPointerParm( &message, 0, appThread->NativeWindow ); + ovrMessageQueue_PostMessage( &appThread->MessageQueue, &message ); + } + } + else if ( newNativeWindow != NULL ) + { + ANativeWindow_release( newNativeWindow ); + } +} + +JNIEXPORT void JNICALL Java_com_drbeef_lambda1vr_GLES3JNILib_onSurfaceDestroyed( JNIEnv * env, jobject obj, jlong handle ) +{ + ALOGV( " GLES3JNILib::onSurfaceDestroyed()" ); + ovrAppThread * appThread = (ovrAppThread *)((size_t)handle); + ovrMessage message; + ovrMessage_Init( &message, MESSAGE_ON_SURFACE_DESTROYED, MQ_WAIT_PROCESSED ); + ovrMessageQueue_PostMessage( &appThread->MessageQueue, &message ); + ALOGV( " ANativeWindow_release( NativeWindow )" ); + ANativeWindow_release( appThread->NativeWindow ); + appThread->NativeWindow = NULL; +} diff --git a/Projects/Android/jni/src/Lambda1VR/argtable3.c b/Projects/Android/jni/src/Lambda1VR/argtable3.c new file mode 100644 index 0000000..d031bd2 --- /dev/null +++ b/Projects/Android/jni/src/Lambda1VR/argtable3.c @@ -0,0 +1,5019 @@ +/******************************************************************************* + * This file is part of the argtable3 library. + * + * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of STEWART HEITMANN nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 STEWART HEITMANN 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. + ******************************************************************************/ + +#include "argtable3.h" + +// On Windows isspace crashes app in case of using Unicode character set and string to be above ASCII +// so you have to use _istspace instead of space +#ifdef UNICODE +#include + #define ISSPACE _istspace +#else + #define ISSPACE isspace +#endif + +/******************************************************************************* + * This file is part of the argtable3 library. + * + * Copyright (C) 2013 Tom G. Huang + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of STEWART HEITMANN nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 STEWART HEITMANN 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. + ******************************************************************************/ + +#ifndef ARG_UTILS_H +#define ARG_UTILS_H + +#define ARG_ENABLE_TRACE 0 +#define ARG_ENABLE_LOG 1 + +#ifdef __cplusplus +extern "C" { +#endif + +enum +{ + EMINCOUNT = 1, + EMAXCOUNT, + EBADINT, + // The same name define EOVERFLOW in errno.h on windows platform +#ifdef __STDC_WANT_SECURE_LIB__ + EOVERFLOW_, +#else + EOVERFLOW, +#endif + EBADDOUBLE, + EBADDATE, + EREGNOMATCH +}; + + +#if defined(_MSC_VER) +#define ARG_TRACE(x) \ + __pragma(warning(push)) \ + __pragma(warning(disable:4127)) \ + do { if (ARG_ENABLE_TRACE) dbg_printf x; } while (0) \ + __pragma(warning(pop)) + +#define ARG_LOG(x) \ + __pragma(warning(push)) \ + __pragma(warning(disable:4127)) \ + do { if (ARG_ENABLE_LOG) dbg_printf x; } while (0) \ + __pragma(warning(pop)) +#else +#define ARG_TRACE(x) \ + do { if (ARG_ENABLE_TRACE) dbg_printf x; } while (0) + +#define ARG_LOG(x) \ + do { if (ARG_ENABLE_LOG) dbg_printf x; } while (0) +#endif + +extern void dbg_printf(const char *fmt, ...); + +#ifdef __cplusplus +} +#endif + +#endif + +/******************************************************************************* + * This file is part of the argtable3 library. + * + * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of STEWART HEITMANN nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 STEWART HEITMANN 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. + ******************************************************************************/ + +#include +#include + + +void dbg_printf(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); +} + +/* $Id: getopt.h,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $ */ +/* $OpenBSD: getopt.h,v 1.1 2002/12/03 20:24:29 millert Exp $ */ +/* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#ifndef _GETOPT_H_ +#define _GETOPT_H_ + +#if 0 +#include +#endif + +/* + * GNU-like getopt_long() and 4.4BSD getsubopt()/optreset extensions + */ +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +struct option { + /* name of long option */ + const char *name; + /* + * one of no_argument, required_argument, and optional_argument: + * whether option takes an argument + */ + int has_arg; + /* if not NULL, set *flag to val when option found */ + int *flag; + /* if flag not NULL, value to set *flag to; else return value */ + int val; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int getopt_long(int, char * const *, const char *, + const struct option *, int *); +int getopt_long_only(int, char * const *, const char *, + const struct option *, int *); +#ifndef _GETOPT_DEFINED +#define _GETOPT_DEFINED +int getopt(int, char * const *, const char *); +int getsubopt(char **, char * const *, char **); + +extern char *optarg; /* getopt(3) external variables */ +extern int opterr; +extern int optind; +extern int optopt; +extern int optreset; +extern char *suboptarg; /* getsubopt(3) external variable */ +#endif /* _GETOPT_DEFINED */ + +#ifdef __cplusplus +} +#endif +#endif /* !_GETOPT_H_ */ +/* $Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $ */ +/* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */ +/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ + +/* + * Copyright (c) 2002 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ + +#ifndef lint +static const char rcsid[]="$Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $"; +#endif /* lint */ +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#if 0 +#include +#endif +#include +#include +#include + + +#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */ + +#ifdef REPLACE_GETOPT +int opterr = 1; /* if error message should be printed */ +int optind = 1; /* index into parent argv vector */ +int optopt = '?'; /* character checked for validity */ +int optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ +#endif + +#define PRINT_ERROR ((opterr) && (*options != ':')) + +#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ +#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ +#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ + +/* return values */ +#define BADCH (int)'?' +#define BADARG ((*options == ':') ? (int)':' : (int)'?') +#define INORDER (int)1 + +#define EMSG "" + +static int getopt_internal(int, char * const *, const char *, + const struct option *, int *, int); +static int parse_long_options(char * const *, const char *, + const struct option *, int *, int); +static int gcd(int, int); +static void permute_args(int, int, int, char * const *); + +static char *place = EMSG; /* option letter processing */ + +/* XXX: set optreset to 1 rather than these two */ +static int nonopt_start = -1; /* first non option argument (for permute) */ +static int nonopt_end = -1; /* first option after non options (for permute) */ + +/* Error messages */ +static const char recargchar[] = "option requires an argument -- %c"; +static const char recargstring[] = "option requires an argument -- %s"; +static const char ambig[] = "ambiguous option -- %.*s"; +static const char noarg[] = "option doesn't take an argument -- %.*s"; +static const char illoptchar[] = "unknown option -- %c"; +static const char illoptstring[] = "unknown option -- %s"; + + + +#ifdef _WIN32 + +/* Windows needs warnx(). We change the definition though: + * 1. (another) global is defined, opterrmsg, which holds the error message + * 2. errors are always printed out on stderr w/o the program name + * Note that opterrmsg always gets set no matter what opterr is set to. The + * error message will not be printed if opterr is 0 as usual. + */ + +#include +#include + +#define MAX_OPTER_MSG_SIZE 128 + +extern char opterrmsg[MAX_OPTER_MSG_SIZE]; +char opterrmsg[MAX_OPTER_MSG_SIZE]; /* buffer for the last error message */ + +static void warnx(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + /* + Make sure opterrmsg is always zero-terminated despite the _vsnprintf() + implementation specifics and manually suppress the warning. + */ + memset(opterrmsg, 0, sizeof opterrmsg); + if (fmt != NULL) +#ifdef __STDC_WANT_SECURE_LIB__ + _vsnprintf_s(opterrmsg, MAX_OPTER_MSG_SIZE, sizeof(opterrmsg) - 1, fmt, ap); +#else + _vsnprintf(opterrmsg, sizeof(opterrmsg) - 1, fmt, ap); +#endif + va_end(ap); + +#pragma warning(suppress: 6053) + fprintf(stderr, "%s\n", opterrmsg); +} + +#else +#include +#endif /*_WIN32*/ + + +/* + * Compute the greatest common divisor of a and b. + */ +static int +gcd(int a, int b) +{ + int c; + + c = a % b; + while (c != 0) { + a = b; + b = c; + c = a % b; + } + + return (b); +} + +/* + * Exchange the block from nonopt_start to nonopt_end with the block + * from nonopt_end to opt_end (keeping the same order of arguments + * in each block). + */ +static void +permute_args(int panonopt_start, int panonopt_end, int opt_end, + char * const *nargv) +{ + int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; + char *swap; + + /* + * compute lengths of blocks and number and size of cycles + */ + nnonopts = panonopt_end - panonopt_start; + nopts = opt_end - panonopt_end; + ncycle = gcd(nnonopts, nopts); + cyclelen = (opt_end - panonopt_start) / ncycle; + + for (i = 0; i < ncycle; i++) { + cstart = panonopt_end+i; + pos = cstart; + for (j = 0; j < cyclelen; j++) { + if (pos >= panonopt_end) + pos -= nnonopts; + else + pos += nopts; + swap = nargv[pos]; + /* LINTED const cast */ + ((char **) nargv)[pos] = nargv[cstart]; + /* LINTED const cast */ + ((char **)nargv)[cstart] = swap; + } + } +} + +/* + * parse_long_options -- + * Parse long options in argc/argv argument vector. + * Returns -1 if short_too is set and the option does not match long_options. + */ +static int +parse_long_options(char * const *nargv, const char *options, + const struct option *long_options, int *idx, int short_too) +{ + char *current_argv, *has_equal; + size_t current_argv_len; + int i, match; + + current_argv = place; + match = -1; + + optind++; + + if ((has_equal = strchr(current_argv, '=')) != NULL) { + /* argument found (--option=arg) */ + current_argv_len = has_equal - current_argv; + has_equal++; + } else + current_argv_len = strlen(current_argv); + + for (i = 0; long_options[i].name; i++) { + /* find matching long option */ + if (strncmp(current_argv, long_options[i].name, + current_argv_len)) + continue; + + if (strlen(long_options[i].name) == current_argv_len) { + /* exact match */ + match = i; + break; + } + /* + * If this is a known short option, don't allow + * a partial match of a single character. + */ + if (short_too && current_argv_len == 1) + continue; + + if (match == -1) /* partial match */ + match = i; + else { + /* ambiguous abbreviation */ + if (PRINT_ERROR) + warnx(ambig, (int)current_argv_len, + current_argv); + optopt = 0; + return (BADCH); + } + } + if (match != -1) { /* option found */ + if (long_options[match].has_arg == no_argument + && has_equal) { + if (PRINT_ERROR) + warnx(noarg, (int)current_argv_len, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + return (BADARG); + } + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + optarg = has_equal; + else if (long_options[match].has_arg == + required_argument) { + /* + * optional argument doesn't use next nargv + */ + optarg = nargv[optind++]; + } + } + if ((long_options[match].has_arg == required_argument) + && (optarg == NULL)) { + /* + * Missing argument; leading ':' indicates no error + * should be generated. + */ + if (PRINT_ERROR) + warnx(recargstring, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + --optind; + return (BADARG); + } + } else { /* unknown option */ + if (short_too) { + --optind; + return (-1); + } + if (PRINT_ERROR) + warnx(illoptstring, current_argv); + optopt = 0; + return (BADCH); + } + if (idx) + *idx = match; + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + return (0); + } else + return (long_options[match].val); +} + +/* + * getopt_internal -- + * Parse argc/argv argument vector. Called by user level routines. + */ +static int +getopt_internal(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx, int flags) +{ + char *oli; /* option letter list index */ + int optchar, short_too; + static int posixly_correct = -1; +#ifdef __STDC_WANT_SECURE_LIB__ + char* buffer = NULL; + size_t buffer_size = 0; + errno_t err = 0; +#endif + + if (options == NULL) + return (-1); + + /* + * Disable GNU extensions if POSIXLY_CORRECT is set or options + * string begins with a '+'. + */ + +#ifdef __STDC_WANT_SECURE_LIB__ + if (posixly_correct == -1) { + err = _dupenv_s(&buffer, &buffer_size, "POSIXLY_CORRECT") == 0; + posixly_correct = buffer != NULL; + if(buffer != NULL && err == 0) { + free(buffer); + } + } +#else + if (posixly_correct == -1) + posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); +#endif + if (posixly_correct || *options == '+') + flags &= ~FLAG_PERMUTE; + else if (*options == '-') + flags |= FLAG_ALLARGS; + if (*options == '+' || *options == '-') + options++; + + /* + * XXX Some GNU programs (like cvs) set optind to 0 instead of + * XXX using optreset. Work around this braindamage. + */ + if (optind == 0) + optind = optreset = 1; + + optarg = NULL; + if (optreset) + nonopt_start = nonopt_end = -1; +start: + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc) { /* end of argument vector */ + place = EMSG; + if (nonopt_end != -1) { + /* do permutation, if we have to */ + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + else if (nonopt_start != -1) { + /* + * If we skipped non-options, set optind + * to the first of them. + */ + optind = nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + if (*(place = nargv[optind]) != '-' || + (place[1] == '\0' && strchr(options, '-') == NULL)) { + place = EMSG; /* found non-option */ + if (flags & FLAG_ALLARGS) { + /* + * GNU extension: + * return non-option as argument to option 1 + */ + optarg = nargv[optind++]; + return (INORDER); + } + if (!(flags & FLAG_PERMUTE)) { + /* + * If no permutation wanted, stop parsing + * at first non-option. + */ + return (-1); + } + /* do permutation */ + if (nonopt_start == -1) + nonopt_start = optind; + else if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + nonopt_start = optind - + (nonopt_end - nonopt_start); + nonopt_end = -1; + } + optind++; + /* process next argument */ + goto start; + } + if (nonopt_start != -1 && nonopt_end == -1) + nonopt_end = optind; + + /* + * If we have "-" do nothing, if "--" we are done. + */ + if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { + optind++; + place = EMSG; + /* + * We found an option (--), so if we skipped + * non-options, we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + } + + /* + * Check long options if: + * 1) we were passed some + * 2) the arg is not just "-" + * 3) either the arg starts with -- we are getopt_long_only() + */ + if (long_options != NULL && place != nargv[optind] && + (*place == '-' || (flags & FLAG_LONGONLY))) { + short_too = 0; + if (*place == '-') + place++; /* --foo long option */ + else if (*place != ':' && strchr(options, *place) != NULL) + short_too = 1; /* could be short option too */ + + optchar = parse_long_options(nargv, options, long_options, + idx, short_too); + if (optchar != -1) { + place = EMSG; + return (optchar); + } + } + + if ((optchar = (int)*place++) == (int)':' || + (optchar == (int)'-' && *place != '\0') || + (oli = strchr(options, optchar)) == NULL) { + /* + * If the user specified "-" and '-' isn't listed in + * options, return -1 (non-option) as per POSIX. + * Otherwise, it is an unknown option character (or ':'). + */ + if (optchar == (int)'-' && *place == '\0') + return (-1); + if (!*place) + ++optind; + if (PRINT_ERROR) + warnx(illoptchar, optchar); + optopt = optchar; + return (BADCH); + } + if (long_options != NULL && optchar == 'W' && oli[1] == ';') { + /* -W long-option */ + if (*place) /* no space */ + /* NOTHING */; + else if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else /* white space */ + place = nargv[optind]; + optchar = parse_long_options(nargv, options, long_options, + idx, 0); + place = EMSG; + return (optchar); + } + if (*++oli != ':') { /* doesn't take argument */ + if (!*place) + ++optind; + } else { /* takes (optional) argument */ + optarg = NULL; + if (*place) /* no white space */ + optarg = place; + else if (oli[1] != ':') { /* arg not optional */ + if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else + optarg = nargv[optind]; + } + place = EMSG; + ++optind; + } + /* dump back option letter */ + return (optchar); +} + +#ifdef REPLACE_GETOPT +/* + * getopt -- + * Parse argc/argv argument vector. + * + * [eventually this will replace the BSD getopt] + */ +int +getopt(int nargc, char * const *nargv, const char *options) +{ + + /* + * We don't pass FLAG_PERMUTE to getopt_internal() since + * the BSD getopt(3) (unlike GNU) has never done this. + * + * Furthermore, since many privileged programs call getopt() + * before dropping privileges it makes sense to keep things + * as simple (and bug-free) as possible. + */ + return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); +} +#endif /* REPLACE_GETOPT */ + +/* + * getopt_long -- + * Parse argc/argv argument vector. + */ +int +getopt_long(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE)); +} + +/* + * getopt_long_only -- + * Parse argc/argv argument vector. + */ +int +getopt_long_only(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE|FLAG_LONGONLY)); +} +/******************************************************************************* + * This file is part of the argtable3 library. + * + * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of STEWART HEITMANN nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 STEWART HEITMANN 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. + ******************************************************************************/ + +#include +#include + +#include "argtable3.h" + + +char * arg_strptime(const char *buf, const char *fmt, struct tm *tm); + + +static void arg_date_resetfn(struct arg_date *parent) +{ + ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); + parent->count = 0; +} + + +static int arg_date_scanfn(struct arg_date *parent, const char *argval) +{ + int errorcode = 0; + + if (parent->count == parent->hdr.maxcount) + { + errorcode = EMAXCOUNT; + } + else if (!argval) + { + /* no argument value was given, leave parent->tmval[] unaltered but still count it */ + parent->count++; + } + else + { + const char *pend; + struct tm tm = parent->tmval[parent->count]; + + /* parse the given argument value, store result in parent->tmval[] */ + pend = arg_strptime(argval, parent->format, &tm); + if (pend && pend[0] == '\0') + parent->tmval[parent->count++] = tm; + else + errorcode = EBADDATE; + } + + ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode)); + return errorcode; +} + + +static int arg_date_checkfn(struct arg_date *parent) +{ + int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0; + + ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode)); + return errorcode; +} + + +static void arg_date_errorfn( + struct arg_date *parent, + FILE *fp, + int errorcode, + const char *argval, + const char *progname) +{ + const char *shortopts = parent->hdr.shortopts; + const char *longopts = parent->hdr.longopts; + const char *datatype = parent->hdr.datatype; + + /* make argval NULL safe */ + argval = argval ? argval : ""; + + fprintf(fp, "%s: ", progname); + switch(errorcode) + { + case EMINCOUNT: + fputs("missing option ", fp); + arg_print_option(fp, shortopts, longopts, datatype, "\n"); + break; + + case EMAXCOUNT: + fputs("excess option ", fp); + arg_print_option(fp, shortopts, longopts, argval, "\n"); + break; + + case EBADDATE: + { + struct tm tm; + char buff[200]; + + fprintf(fp, "illegal timestamp format \"%s\"\n", argval); + memset(&tm, 0, sizeof(tm)); + arg_strptime("1999-12-31 23:59:59", "%F %H:%M:%S", &tm); + strftime(buff, sizeof(buff), parent->format, &tm); + printf("correct format is \"%s\"\n", buff); + break; + } + } +} + + +struct arg_date * arg_date0( + const char * shortopts, + const char * longopts, + const char * format, + const char *datatype, + const char *glossary) +{ + return arg_daten(shortopts, longopts, format, datatype, 0, 1, glossary); +} + + +struct arg_date * arg_date1( + const char * shortopts, + const char * longopts, + const char * format, + const char *datatype, + const char *glossary) +{ + return arg_daten(shortopts, longopts, format, datatype, 1, 1, glossary); +} + + +struct arg_date * arg_daten( + const char * shortopts, + const char * longopts, + const char * format, + const char *datatype, + int mincount, + int maxcount, + const char *glossary) +{ + size_t nbytes; + struct arg_date *result; + + /* foolproof things by ensuring maxcount is not less than mincount */ + maxcount = (maxcount < mincount) ? mincount : maxcount; + + /* default time format is the national date format for the locale */ + if (!format) + format = "%x"; + + nbytes = sizeof(struct arg_date) /* storage for struct arg_date */ + + maxcount * sizeof(struct tm); /* storage for tmval[maxcount] array */ + + /* allocate storage for the arg_date struct + tmval[] array. */ + /* we use calloc because we want the tmval[] array zero filled. */ + result = (struct arg_date *)calloc(1, nbytes); + if (result) + { + /* init the arg_hdr struct */ + result->hdr.flag = ARG_HASVALUE; + result->hdr.shortopts = shortopts; + result->hdr.longopts = longopts; + result->hdr.datatype = datatype ? datatype : format; + result->hdr.glossary = glossary; + result->hdr.mincount = mincount; + result->hdr.maxcount = maxcount; + result->hdr.parent = result; + result->hdr.resetfn = (arg_resetfn *)arg_date_resetfn; + result->hdr.scanfn = (arg_scanfn *)arg_date_scanfn; + result->hdr.checkfn = (arg_checkfn *)arg_date_checkfn; + result->hdr.errorfn = (arg_errorfn *)arg_date_errorfn; + + /* store the tmval[maxcount] array immediately after the arg_date struct */ + result->tmval = (struct tm *)(result + 1); + + /* init the remaining arg_date member variables */ + result->count = 0; + result->format = format; + } + + ARG_TRACE(("arg_daten() returns %p\n", result)); + return result; +} + + +/*- + * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code was contributed to The NetBSD Foundation by Klaus Klein. + * Heavily optimised by David Laight + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include +#include +#include + +/* + * We do not implement alternate representations. However, we always + * check whether a given modifier is allowed for a certain conversion. + */ +#define ALT_E 0x01 +#define ALT_O 0x02 +#define LEGAL_ALT(x) { if (alt_format & ~(x)) return (0); } +#define TM_YEAR_BASE (1900) + +static int conv_num(const char * *, int *, int, int); + +static const char *day[7] = { + "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", + "Friday", "Saturday" +}; + +static const char *abday[7] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; + +static const char *mon[12] = { + "January", "February", "March", "April", "May", "June", "July", + "August", "September", "October", "November", "December" +}; + +static const char *abmon[12] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +static const char *am_pm[2] = { + "AM", "PM" +}; + + +static int arg_strcasecmp(const char *s1, const char *s2) +{ + const unsigned char *us1 = (const unsigned char *)s1; + const unsigned char *us2 = (const unsigned char *)s2; + while (tolower(*us1) == tolower(*us2++)) + if (*us1++ == '\0') + return 0; + + return tolower(*us1) - tolower(*--us2); +} + + +static int arg_strncasecmp(const char *s1, const char *s2, size_t n) +{ + if (n != 0) + { + const unsigned char *us1 = (const unsigned char *)s1; + const unsigned char *us2 = (const unsigned char *)s2; + do + { + if (tolower(*us1) != tolower(*us2++)) + return tolower(*us1) - tolower(*--us2); + + if (*us1++ == '\0') + break; + } while (--n != 0); + } + + return 0; +} + + +char * arg_strptime(const char *buf, const char *fmt, struct tm *tm) +{ + char c; + const char *bp; + size_t len = 0; + int alt_format, i, split_year = 0; + + bp = buf; + + while ((c = *fmt) != '\0') { + /* Clear `alternate' modifier prior to new conversion. */ + alt_format = 0; + + /* Eat up white-space. */ + if (ISSPACE(c)) { + while (ISSPACE(*bp)) + bp++; + + fmt++; + continue; + } + + if ((c = *fmt++) != '%') + goto literal; + + +again: + switch (c = *fmt++) + { + case '%': /* "%%" is converted to "%". */ +literal: + if (c != *bp++) + return (0); + break; + + /* + * "Alternative" modifiers. Just set the appropriate flag + * and start over again. + */ + case 'E': /* "%E?" alternative conversion modifier. */ + LEGAL_ALT(0); + alt_format |= ALT_E; + goto again; + + case 'O': /* "%O?" alternative conversion modifier. */ + LEGAL_ALT(0); + alt_format |= ALT_O; + goto again; + + /* + * "Complex" conversion rules, implemented through recursion. + */ + case 'c': /* Date and time, using the locale's format. */ + LEGAL_ALT(ALT_E); + bp = arg_strptime(bp, "%x %X", tm); + if (!bp) + return (0); + break; + + case 'D': /* The date as "%m/%d/%y". */ + LEGAL_ALT(0); + bp = arg_strptime(bp, "%m/%d/%y", tm); + if (!bp) + return (0); + break; + + case 'R': /* The time as "%H:%M". */ + LEGAL_ALT(0); + bp = arg_strptime(bp, "%H:%M", tm); + if (!bp) + return (0); + break; + + case 'r': /* The time in 12-hour clock representation. */ + LEGAL_ALT(0); + bp = arg_strptime(bp, "%I:%M:%S %p", tm); + if (!bp) + return (0); + break; + + case 'T': /* The time as "%H:%M:%S". */ + LEGAL_ALT(0); + bp = arg_strptime(bp, "%H:%M:%S", tm); + if (!bp) + return (0); + break; + + case 'X': /* The time, using the locale's format. */ + LEGAL_ALT(ALT_E); + bp = arg_strptime(bp, "%H:%M:%S", tm); + if (!bp) + return (0); + break; + + case 'x': /* The date, using the locale's format. */ + LEGAL_ALT(ALT_E); + bp = arg_strptime(bp, "%m/%d/%y", tm); + if (!bp) + return (0); + break; + + /* + * "Elementary" conversion rules. + */ + case 'A': /* The day of week, using the locale's form. */ + case 'a': + LEGAL_ALT(0); + for (i = 0; i < 7; i++) { + /* Full name. */ + len = strlen(day[i]); + if (arg_strncasecmp(day[i], bp, len) == 0) + break; + + /* Abbreviated name. */ + len = strlen(abday[i]); + if (arg_strncasecmp(abday[i], bp, len) == 0) + break; + } + + /* Nothing matched. */ + if (i == 7) + return (0); + + tm->tm_wday = i; + bp += len; + break; + + case 'B': /* The month, using the locale's form. */ + case 'b': + case 'h': + LEGAL_ALT(0); + for (i = 0; i < 12; i++) { + /* Full name. */ + len = strlen(mon[i]); + if (arg_strncasecmp(mon[i], bp, len) == 0) + break; + + /* Abbreviated name. */ + len = strlen(abmon[i]); + if (arg_strncasecmp(abmon[i], bp, len) == 0) + break; + } + + /* Nothing matched. */ + if (i == 12) + return (0); + + tm->tm_mon = i; + bp += len; + break; + + case 'C': /* The century number. */ + LEGAL_ALT(ALT_E); + if (!(conv_num(&bp, &i, 0, 99))) + return (0); + + if (split_year) { + tm->tm_year = (tm->tm_year % 100) + (i * 100); + } else { + tm->tm_year = i * 100; + split_year = 1; + } + break; + + case 'd': /* The day of month. */ + case 'e': + LEGAL_ALT(ALT_O); + if (!(conv_num(&bp, &tm->tm_mday, 1, 31))) + return (0); + break; + + case 'k': /* The hour (24-hour clock representation). */ + LEGAL_ALT(0); + /* FALLTHROUGH */ + case 'H': + LEGAL_ALT(ALT_O); + if (!(conv_num(&bp, &tm->tm_hour, 0, 23))) + return (0); + break; + + case 'l': /* The hour (12-hour clock representation). */ + LEGAL_ALT(0); + /* FALLTHROUGH */ + case 'I': + LEGAL_ALT(ALT_O); + if (!(conv_num(&bp, &tm->tm_hour, 1, 12))) + return (0); + if (tm->tm_hour == 12) + tm->tm_hour = 0; + break; + + case 'j': /* The day of year. */ + LEGAL_ALT(0); + if (!(conv_num(&bp, &i, 1, 366))) + return (0); + tm->tm_yday = i - 1; + break; + + case 'M': /* The minute. */ + LEGAL_ALT(ALT_O); + if (!(conv_num(&bp, &tm->tm_min, 0, 59))) + return (0); + break; + + case 'm': /* The month. */ + LEGAL_ALT(ALT_O); + if (!(conv_num(&bp, &i, 1, 12))) + return (0); + tm->tm_mon = i - 1; + break; + + case 'p': /* The locale's equivalent of AM/PM. */ + LEGAL_ALT(0); + /* AM? */ + if (arg_strcasecmp(am_pm[0], bp) == 0) { + if (tm->tm_hour > 11) + return (0); + + bp += strlen(am_pm[0]); + break; + } + /* PM? */ + else if (arg_strcasecmp(am_pm[1], bp) == 0) { + if (tm->tm_hour > 11) + return (0); + + tm->tm_hour += 12; + bp += strlen(am_pm[1]); + break; + } + + /* Nothing matched. */ + return (0); + + case 'S': /* The seconds. */ + LEGAL_ALT(ALT_O); + if (!(conv_num(&bp, &tm->tm_sec, 0, 61))) + return (0); + break; + + case 'U': /* The week of year, beginning on sunday. */ + case 'W': /* The week of year, beginning on monday. */ + LEGAL_ALT(ALT_O); + /* + * XXX This is bogus, as we can not assume any valid + * information present in the tm structure at this + * point to calculate a real value, so just check the + * range for now. + */ + if (!(conv_num(&bp, &i, 0, 53))) + return (0); + break; + + case 'w': /* The day of week, beginning on sunday. */ + LEGAL_ALT(ALT_O); + if (!(conv_num(&bp, &tm->tm_wday, 0, 6))) + return (0); + break; + + case 'Y': /* The year. */ + LEGAL_ALT(ALT_E); + if (!(conv_num(&bp, &i, 0, 9999))) + return (0); + + tm->tm_year = i - TM_YEAR_BASE; + break; + + case 'y': /* The year within 100 years of the epoch. */ + LEGAL_ALT(ALT_E | ALT_O); + if (!(conv_num(&bp, &i, 0, 99))) + return (0); + + if (split_year) { + tm->tm_year = ((tm->tm_year / 100) * 100) + i; + break; + } + split_year = 1; + if (i <= 68) + tm->tm_year = i + 2000 - TM_YEAR_BASE; + else + tm->tm_year = i + 1900 - TM_YEAR_BASE; + break; + + /* + * Miscellaneous conversions. + */ + case 'n': /* Any kind of white-space. */ + case 't': + LEGAL_ALT(0); + while (ISSPACE(*bp)) + bp++; + break; + + + default: /* Unknown/unsupported conversion. */ + return (0); + } + + + } + + /* LINTED functional specification */ + return ((char *)bp); +} + + +static int conv_num(const char * *buf, int *dest, int llim, int ulim) +{ + int result = 0; + + /* The limit also determines the number of valid digits. */ + int rulim = ulim; + + if (**buf < '0' || **buf > '9') + return (0); + + do { + result *= 10; + result += *(*buf)++ - '0'; + rulim /= 10; + } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9'); + + if (result < llim || result > ulim) + return (0); + + *dest = result; + return (1); +} +/******************************************************************************* + * This file is part of the argtable3 library. + * + * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of STEWART HEITMANN nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 STEWART HEITMANN 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. + ******************************************************************************/ + +#include + +#include "argtable3.h" + + +static void arg_dbl_resetfn(struct arg_dbl *parent) +{ + ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); + parent->count = 0; +} + + +static int arg_dbl_scanfn(struct arg_dbl *parent, const char *argval) +{ + int errorcode = 0; + + if (parent->count == parent->hdr.maxcount) + { + /* maximum number of arguments exceeded */ + errorcode = EMAXCOUNT; + } + else if (!argval) + { + /* a valid argument with no argument value was given. */ + /* This happens when an optional argument value was invoked. */ + /* leave parent argument value unaltered but still count the argument. */ + parent->count++; + } + else + { + double val; + char *end; + + /* extract double from argval into val */ + val = strtod(argval, &end); + + /* if success then store result in parent->dval[] array otherwise return error*/ + if (*end == 0) + parent->dval[parent->count++] = val; + else + errorcode = EBADDOUBLE; + } + + ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode)); + return errorcode; +} + + +static int arg_dbl_checkfn(struct arg_dbl *parent) +{ + int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0; + + ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode)); + return errorcode; +} + + +static void arg_dbl_errorfn( + struct arg_dbl *parent, + FILE *fp, + int errorcode, + const char *argval, + const char *progname) +{ + const char *shortopts = parent->hdr.shortopts; + const char *longopts = parent->hdr.longopts; + const char *datatype = parent->hdr.datatype; + + /* make argval NULL safe */ + argval = argval ? argval : ""; + + fprintf(fp, "%s: ", progname); + switch(errorcode) + { + case EMINCOUNT: + fputs("missing option ", fp); + arg_print_option(fp, shortopts, longopts, datatype, "\n"); + break; + + case EMAXCOUNT: + fputs("excess option ", fp); + arg_print_option(fp, shortopts, longopts, argval, "\n"); + break; + + case EBADDOUBLE: + fprintf(fp, "invalid argument \"%s\" to option ", argval); + arg_print_option(fp, shortopts, longopts, datatype, "\n"); + break; + } +} + + +struct arg_dbl * arg_dbl0( + const char * shortopts, + const char * longopts, + const char *datatype, + const char *glossary) +{ + return arg_dbln(shortopts, longopts, datatype, 0, 1, glossary); +} + + +struct arg_dbl * arg_dbl1( + const char * shortopts, + const char * longopts, + const char *datatype, + const char *glossary) +{ + return arg_dbln(shortopts, longopts, datatype, 1, 1, glossary); +} + + +struct arg_dbl * arg_dbln( + const char * shortopts, + const char * longopts, + const char *datatype, + int mincount, + int maxcount, + const char *glossary) +{ + size_t nbytes; + struct arg_dbl *result; + + /* foolproof things by ensuring maxcount is not less than mincount */ + maxcount = (maxcount < mincount) ? mincount : maxcount; + + nbytes = sizeof(struct arg_dbl) /* storage for struct arg_dbl */ + + (maxcount + 1) * sizeof(double); /* storage for dval[maxcount] array plus one extra for padding to memory boundary */ + + result = (struct arg_dbl *)malloc(nbytes); + if (result) + { + size_t addr; + size_t rem; + + /* init the arg_hdr struct */ + result->hdr.flag = ARG_HASVALUE; + result->hdr.shortopts = shortopts; + result->hdr.longopts = longopts; + result->hdr.datatype = datatype ? datatype : ""; + result->hdr.glossary = glossary; + result->hdr.mincount = mincount; + result->hdr.maxcount = maxcount; + result->hdr.parent = result; + result->hdr.resetfn = (arg_resetfn *)arg_dbl_resetfn; + result->hdr.scanfn = (arg_scanfn *)arg_dbl_scanfn; + result->hdr.checkfn = (arg_checkfn *)arg_dbl_checkfn; + result->hdr.errorfn = (arg_errorfn *)arg_dbl_errorfn; + + /* Store the dval[maxcount] array on the first double boundary that + * immediately follows the arg_dbl struct. We do the memory alignment + * purely for SPARC and Motorola systems. They require floats and + * doubles to be aligned on natural boundaries. + */ + addr = (size_t)(result + 1); + rem = addr % sizeof(double); + result->dval = (double *)(addr + sizeof(double) - rem); + ARG_TRACE(("addr=%p, dval=%p, sizeof(double)=%d rem=%d\n", addr, result->dval, (int)sizeof(double), (int)rem)); + + result->count = 0; + } + + ARG_TRACE(("arg_dbln() returns %p\n", result)); + return result; +} +/******************************************************************************* + * This file is part of the argtable3 library. + * + * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of STEWART HEITMANN nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 STEWART HEITMANN 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. + ******************************************************************************/ + +#include + +#include "argtable3.h" + + +static void arg_end_resetfn(struct arg_end *parent) +{ + ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); + parent->count = 0; +} + +static void arg_end_errorfn( + void *parent, + FILE *fp, + int error, + const char *argval, + const char *progname) +{ + /* suppress unreferenced formal parameter warning */ + (void)parent; + + progname = progname ? progname : ""; + argval = argval ? argval : ""; + + fprintf(fp, "%s: ", progname); + switch(error) + { + case ARG_ELIMIT: + fputs("too many errors to display", fp); + break; + case ARG_EMALLOC: + fputs("insufficent memory", fp); + break; + case ARG_ENOMATCH: + fprintf(fp, "unexpected argument \"%s\"", argval); + break; + case ARG_EMISSARG: + fprintf(fp, "option \"%s\" requires an argument", argval); + break; + case ARG_ELONGOPT: + fprintf(fp, "invalid option \"%s\"", argval); + break; + default: + fprintf(fp, "invalid option \"-%c\"", error); + break; + } + + fputc('\n', fp); +} + + +struct arg_end * arg_end(int maxcount) +{ + size_t nbytes; + struct arg_end *result; + + nbytes = sizeof(struct arg_end) + + maxcount * sizeof(int) /* storage for int error[maxcount] array*/ + + maxcount * sizeof(void *) /* storage for void* parent[maxcount] array */ + + maxcount * sizeof(char *); /* storage for char* argval[maxcount] array */ + + result = (struct arg_end *)malloc(nbytes); + if (result) + { + /* init the arg_hdr struct */ + result->hdr.flag = ARG_TERMINATOR; + result->hdr.shortopts = NULL; + result->hdr.longopts = NULL; + result->hdr.datatype = NULL; + result->hdr.glossary = NULL; + result->hdr.mincount = 1; + result->hdr.maxcount = maxcount; + result->hdr.parent = result; + result->hdr.resetfn = (arg_resetfn *)arg_end_resetfn; + result->hdr.scanfn = NULL; + result->hdr.checkfn = NULL; + result->hdr.errorfn = (arg_errorfn *)arg_end_errorfn; + + /* store error[maxcount] array immediately after struct arg_end */ + result->error = (int *)(result + 1); + + /* store parent[maxcount] array immediately after error[] array */ + result->parent = (void * *)(result->error + maxcount ); + + /* store argval[maxcount] array immediately after parent[] array */ + result->argval = (const char * *)(result->parent + maxcount ); + } + + ARG_TRACE(("arg_end(%d) returns %p\n", maxcount, result)); + return result; +} + + +void arg_print_errors(FILE * fp, struct arg_end * end, const char * progname) +{ + int i; + ARG_TRACE(("arg_errors()\n")); + for (i = 0; i < end->count; i++) + { + struct arg_hdr *errorparent = (struct arg_hdr *)(end->parent[i]); + if (errorparent->errorfn) + errorparent->errorfn(end->parent[i], + fp, + end->error[i], + end->argval[i], + progname); + } +} +/******************************************************************************* + * This file is part of the argtable3 library. + * + * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of STEWART HEITMANN nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 STEWART HEITMANN 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. + ******************************************************************************/ + +#include +#include + +#include "argtable3.h" + +#ifdef WIN32 +# define FILESEPARATOR1 '\\' +# define FILESEPARATOR2 '/' +#else +# define FILESEPARATOR1 '/' +# define FILESEPARATOR2 '/' +#endif + + +static void arg_file_resetfn(struct arg_file *parent) +{ + ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); + parent->count = 0; +} + + +/* Returns ptr to the base filename within *filename */ +static const char * arg_basename(const char *filename) +{ + const char *result = NULL, *result1, *result2; + + /* Find the last occurrence of eother file separator character. */ + /* Two alternative file separator chars are supported as legal */ + /* file separators but not both together in the same filename. */ + result1 = (filename ? strrchr(filename, FILESEPARATOR1) : NULL); + result2 = (filename ? strrchr(filename, FILESEPARATOR2) : NULL); + + if (result2) + result = result2 + 1; /* using FILESEPARATOR2 (the alternative file separator) */ + + if (result1) + result = result1 + 1; /* using FILESEPARATOR1 (the preferred file separator) */ + + if (!result) + result = filename; /* neither file separator was found so basename is the whole filename */ + + /* special cases of "." and ".." are not considered basenames */ + if (result && ( strcmp(".", result) == 0 || strcmp("..", result) == 0 )) + result = filename + strlen(filename); + + return result; +} + + +/* Returns ptr to the file extension within *basename */ +static const char * arg_extension(const char *basename) +{ + /* find the last occurrence of '.' in basename */ + const char *result = (basename ? strrchr(basename, '.') : NULL); + + /* if no '.' was found then return pointer to end of basename */ + if (basename && !result) + result = basename + strlen(basename); + + /* special case: basenames with a single leading dot (eg ".foo") are not considered as true extensions */ + if (basename && result == basename) + result = basename + strlen(basename); + + /* special case: empty extensions (eg "foo.","foo..") are not considered as true extensions */ + if (basename && result && result[1] == '\0') + result = basename + strlen(basename); + + return result; +} + + +static int arg_file_scanfn(struct arg_file *parent, const char *argval) +{ + int errorcode = 0; + + if (parent->count == parent->hdr.maxcount) + { + /* maximum number of arguments exceeded */ + errorcode = EMAXCOUNT; + } + else if (!argval) + { + /* a valid argument with no argument value was given. */ + /* This happens when an optional argument value was invoked. */ + /* leave parent arguiment value unaltered but still count the argument. */ + parent->count++; + } + else + { + parent->filename[parent->count] = argval; + parent->basename[parent->count] = arg_basename(argval); + parent->extension[parent->count] = + arg_extension(parent->basename[parent->count]); /* only seek extensions within the basename (not the file path)*/ + parent->count++; + } + + ARG_TRACE(("%s4:scanfn(%p) returns %d\n", __FILE__, parent, errorcode)); + return errorcode; +} + + +static int arg_file_checkfn(struct arg_file *parent) +{ + int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0; + + ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode)); + return errorcode; +} + + +static void arg_file_errorfn( + struct arg_file *parent, + FILE *fp, + int errorcode, + const char *argval, + const char *progname) +{ + const char *shortopts = parent->hdr.shortopts; + const char *longopts = parent->hdr.longopts; + const char *datatype = parent->hdr.datatype; + + /* make argval NULL safe */ + argval = argval ? argval : ""; + + fprintf(fp, "%s: ", progname); + switch(errorcode) + { + case EMINCOUNT: + fputs("missing option ", fp); + arg_print_option(fp, shortopts, longopts, datatype, "\n"); + break; + + case EMAXCOUNT: + fputs("excess option ", fp); + arg_print_option(fp, shortopts, longopts, argval, "\n"); + break; + + default: + fprintf(fp, "unknown error at \"%s\"\n", argval); + } +} + + +struct arg_file * arg_file0( + const char * shortopts, + const char * longopts, + const char *datatype, + const char *glossary) +{ + return arg_filen(shortopts, longopts, datatype, 0, 1, glossary); +} + + +struct arg_file * arg_file1( + const char * shortopts, + const char * longopts, + const char *datatype, + const char *glossary) +{ + return arg_filen(shortopts, longopts, datatype, 1, 1, glossary); +} + + +struct arg_file * arg_filen( + const char * shortopts, + const char * longopts, + const char *datatype, + int mincount, + int maxcount, + const char *glossary) +{ + size_t nbytes; + struct arg_file *result; + + /* foolproof things by ensuring maxcount is not less than mincount */ + maxcount = (maxcount < mincount) ? mincount : maxcount; + + nbytes = sizeof(struct arg_file) /* storage for struct arg_file */ + + sizeof(char *) * maxcount /* storage for filename[maxcount] array */ + + sizeof(char *) * maxcount /* storage for basename[maxcount] array */ + + sizeof(char *) * maxcount; /* storage for extension[maxcount] array */ + + result = (struct arg_file *)malloc(nbytes); + if (result) + { + int i; + + /* init the arg_hdr struct */ + result->hdr.flag = ARG_HASVALUE; + result->hdr.shortopts = shortopts; + result->hdr.longopts = longopts; + result->hdr.glossary = glossary; + result->hdr.datatype = datatype ? datatype : ""; + result->hdr.mincount = mincount; + result->hdr.maxcount = maxcount; + result->hdr.parent = result; + result->hdr.resetfn = (arg_resetfn *)arg_file_resetfn; + result->hdr.scanfn = (arg_scanfn *)arg_file_scanfn; + result->hdr.checkfn = (arg_checkfn *)arg_file_checkfn; + result->hdr.errorfn = (arg_errorfn *)arg_file_errorfn; + + /* store the filename,basename,extension arrays immediately after the arg_file struct */ + result->filename = (const char * *)(result + 1); + result->basename = result->filename + maxcount; + result->extension = result->basename + maxcount; + result->count = 0; + + /* foolproof the string pointers by initialising them with empty strings */ + for (i = 0; i < maxcount; i++) + { + result->filename[i] = ""; + result->basename[i] = ""; + result->extension[i] = ""; + } + } + + ARG_TRACE(("arg_filen() returns %p\n", result)); + return result; +} +/******************************************************************************* + * This file is part of the argtable3 library. + * + * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of STEWART HEITMANN nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 STEWART HEITMANN 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. + ******************************************************************************/ + +#include +#include +#include + +#include "argtable3.h" + + +static void arg_int_resetfn(struct arg_int *parent) +{ + ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); + parent->count = 0; +} + + +/* strtol0x() is like strtol() except that the numeric string is */ +/* expected to be prefixed by "0X" where X is a user supplied char. */ +/* The string may optionally be prefixed by white space and + or - */ +/* as in +0X123 or -0X123. */ +/* Once the prefix has been scanned, the remainder of the numeric */ +/* string is converted using strtol() with the given base. */ +/* eg: to parse hex str="-0X12324", specify X='X' and base=16. */ +/* eg: to parse oct str="+0o12324", specify X='O' and base=8. */ +/* eg: to parse bin str="-0B01010", specify X='B' and base=2. */ +/* Failure of conversion is indicated by result where *endptr==str. */ +static long int strtol0X(const char * str, + const char * *endptr, + char X, + int base) +{ + long int val; /* stores result */ + int s = 1; /* sign is +1 or -1 */ + const char *ptr = str; /* ptr to current position in str */ + + /* skip leading whitespace */ + while (ISSPACE(*ptr)) + ptr++; + /* printf("1) %s\n",ptr); */ + + /* scan optional sign character */ + switch (*ptr) + { + case '+': + ptr++; + s = 1; + break; + case '-': + ptr++; + s = -1; + break; + default: + s = 1; + break; + } + /* printf("2) %s\n",ptr); */ + + /* '0X' prefix */ + if ((*ptr++) != '0') + { + /* printf("failed to detect '0'\n"); */ + *endptr = str; + return 0; + } + /* printf("3) %s\n",ptr); */ + if (toupper(*ptr++) != toupper(X)) + { + /* printf("failed to detect '%c'\n",X); */ + *endptr = str; + return 0; + } + /* printf("4) %s\n",ptr); */ + + /* attempt conversion on remainder of string using strtol() */ + val = strtol(ptr, (char * *)endptr, base); + if (*endptr == ptr) + { + /* conversion failed */ + *endptr = str; + return 0; + } + + /* success */ + return s * val; +} + + +/* Returns 1 if str matches suffix (case insensitive). */ +/* Str may contain trailing whitespace, but nothing else. */ +static int detectsuffix(const char *str, const char *suffix) +{ + /* scan pairwise through strings until mismatch detected */ + while( toupper(*str) == toupper(*suffix) ) + { + /* printf("'%c' '%c'\n", *str, *suffix); */ + + /* return 1 (success) if match persists until the string terminator */ + if (*str == '\0') + return 1; + + /* next chars */ + str++; + suffix++; + } + /* printf("'%c' '%c' mismatch\n", *str, *suffix); */ + + /* return 0 (fail) if the matching did not consume the entire suffix */ + if (*suffix != 0) + return 0; /* failed to consume entire suffix */ + + /* skip any remaining whitespace in str */ + while (ISSPACE(*str)) + str++; + + /* return 1 (success) if we have reached end of str else return 0 (fail) */ + return (*str == '\0') ? 1 : 0; +} + + +static int arg_int_scanfn(struct arg_int *parent, const char *argval) +{ + int errorcode = 0; + + if (parent->count == parent->hdr.maxcount) + { + /* maximum number of arguments exceeded */ + errorcode = EMAXCOUNT; + } + else if (!argval) + { + /* a valid argument with no argument value was given. */ + /* This happens when an optional argument value was invoked. */ + /* leave parent arguiment value unaltered but still count the argument. */ + parent->count++; + } + else + { + long int val; + const char *end; + + /* attempt to extract hex integer (eg: +0x123) from argval into val conversion */ + val = strtol0X(argval, &end, 'X', 16); + if (end == argval) + { + /* hex failed, attempt octal conversion (eg +0o123) */ + val = strtol0X(argval, &end, 'O', 8); + if (end == argval) + { + /* octal failed, attempt binary conversion (eg +0B101) */ + val = strtol0X(argval, &end, 'B', 2); + if (end == argval) + { + /* binary failed, attempt decimal conversion with no prefix (eg 1234) */ + val = strtol(argval, (char * *)&end, 10); + if (end == argval) + { + /* all supported number formats failed */ + return EBADINT; + } + } + } + } + + /* Safety check for integer overflow. WARNING: this check */ + /* achieves nothing on machines where size(int)==size(long). */ + if ( val > INT_MAX || val < INT_MIN ) +#ifdef __STDC_WANT_SECURE_LIB__ + errorcode = EOVERFLOW_; +#else + errorcode = EOVERFLOW; +#endif + + /* Detect any suffixes (KB,MB,GB) and multiply argument value appropriately. */ + /* We need to be mindful of integer overflows when using such big numbers. */ + if (detectsuffix(end, "KB")) /* kilobytes */ + { + if ( val > (INT_MAX / 1024) || val < (INT_MIN / 1024) ) +#ifdef __STDC_WANT_SECURE_LIB__ + errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */ +#else + errorcode = EOVERFLOW; /* Overflow would occur if we proceed */ +#endif + else + val *= 1024; /* 1KB = 1024 */ + } + else if (detectsuffix(end, "MB")) /* megabytes */ + { + if ( val > (INT_MAX / 1048576) || val < (INT_MIN / 1048576) ) +#ifdef __STDC_WANT_SECURE_LIB__ + errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */ +#else + errorcode = EOVERFLOW; /* Overflow would occur if we proceed */ +#endif + else + val *= 1048576; /* 1MB = 1024*1024 */ + } + else if (detectsuffix(end, "GB")) /* gigabytes */ + { + if ( val > (INT_MAX / 1073741824) || val < (INT_MIN / 1073741824) ) +#ifdef __STDC_WANT_SECURE_LIB__ + errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */ +#else + errorcode = EOVERFLOW; /* Overflow would occur if we proceed */ +#endif + else + val *= 1073741824; /* 1GB = 1024*1024*1024 */ + } + else if (!detectsuffix(end, "")) + errorcode = EBADINT; /* invalid suffix detected */ + + /* if success then store result in parent->ival[] array */ + if (errorcode == 0) + parent->ival[parent->count++] = val; + } + + /* printf("%s:scanfn(%p,%p) returns %d\n",__FILE__,parent,argval,errorcode); */ + return errorcode; +} + + +static int arg_int_checkfn(struct arg_int *parent) +{ + int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0; + /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/ + return errorcode; +} + + +static void arg_int_errorfn( + struct arg_int *parent, + FILE *fp, + int errorcode, + const char *argval, + const char *progname) +{ + const char *shortopts = parent->hdr.shortopts; + const char *longopts = parent->hdr.longopts; + const char *datatype = parent->hdr.datatype; + + /* make argval NULL safe */ + argval = argval ? argval : ""; + + fprintf(fp, "%s: ", progname); + switch(errorcode) + { + case EMINCOUNT: + fputs("missing option ", fp); + arg_print_option(fp, shortopts, longopts, datatype, "\n"); + break; + + case EMAXCOUNT: + fputs("excess option ", fp); + arg_print_option(fp, shortopts, longopts, argval, "\n"); + break; + + case EBADINT: + fprintf(fp, "invalid argument \"%s\" to option ", argval); + arg_print_option(fp, shortopts, longopts, datatype, "\n"); + break; + +#ifdef __STDC_WANT_SECURE_LIB__ + case EOVERFLOW_: +#else + case EOVERFLOW: +#endif + fputs("integer overflow at option ", fp); + arg_print_option(fp, shortopts, longopts, datatype, " "); + fprintf(fp, "(%s is too large)\n", argval); + break; + } +} + + +struct arg_int * arg_int0( + const char *shortopts, + const char *longopts, + const char *datatype, + const char *glossary) +{ + return arg_intn(shortopts, longopts, datatype, 0, 1, glossary); +} + + +struct arg_int * arg_int1( + const char *shortopts, + const char *longopts, + const char *datatype, + const char *glossary) +{ + return arg_intn(shortopts, longopts, datatype, 1, 1, glossary); +} + + +struct arg_int * arg_intn( + const char *shortopts, + const char *longopts, + const char *datatype, + int mincount, + int maxcount, + const char *glossary) +{ + size_t nbytes; + struct arg_int *result; + + /* foolproof things by ensuring maxcount is not less than mincount */ + maxcount = (maxcount < mincount) ? mincount : maxcount; + + nbytes = sizeof(struct arg_int) /* storage for struct arg_int */ + + maxcount * sizeof(int); /* storage for ival[maxcount] array */ + + result = (struct arg_int *)malloc(nbytes); + if (result) + { + /* init the arg_hdr struct */ + result->hdr.flag = ARG_HASVALUE; + result->hdr.shortopts = shortopts; + result->hdr.longopts = longopts; + result->hdr.datatype = datatype ? datatype : ""; + result->hdr.glossary = glossary; + result->hdr.mincount = mincount; + result->hdr.maxcount = maxcount; + result->hdr.parent = result; + result->hdr.resetfn = (arg_resetfn *)arg_int_resetfn; + result->hdr.scanfn = (arg_scanfn *)arg_int_scanfn; + result->hdr.checkfn = (arg_checkfn *)arg_int_checkfn; + result->hdr.errorfn = (arg_errorfn *)arg_int_errorfn; + + /* store the ival[maxcount] array immediately after the arg_int struct */ + result->ival = (int *)(result + 1); + result->count = 0; + } + + ARG_TRACE(("arg_intn() returns %p\n", result)); + return result; +} +/******************************************************************************* + * This file is part of the argtable3 library. + * + * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of STEWART HEITMANN nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 STEWART HEITMANN 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. + ******************************************************************************/ + +#include + +#include "argtable3.h" + + +static void arg_lit_resetfn(struct arg_lit *parent) +{ + ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); + parent->count = 0; +} + + +static int arg_lit_scanfn(struct arg_lit *parent, const char *argval) +{ + int errorcode = 0; + if (parent->count < parent->hdr.maxcount ) + parent->count++; + else + errorcode = EMAXCOUNT; + + ARG_TRACE(("%s:scanfn(%p,%s) returns %d\n", __FILE__, parent, argval, + errorcode)); + return errorcode; +} + + +static int arg_lit_checkfn(struct arg_lit *parent) +{ + int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0; + ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode)); + return errorcode; +} + + +static void arg_lit_errorfn( + struct arg_lit *parent, + FILE *fp, + int errorcode, + const char *argval, + const char *progname) +{ + const char *shortopts = parent->hdr.shortopts; + const char *longopts = parent->hdr.longopts; + const char *datatype = parent->hdr.datatype; + + switch(errorcode) + { + case EMINCOUNT: + fprintf(fp, "%s: missing option ", progname); + arg_print_option(fp, shortopts, longopts, datatype, "\n"); + fprintf(fp, "\n"); + break; + + case EMAXCOUNT: + fprintf(fp, "%s: extraneous option ", progname); + arg_print_option(fp, shortopts, longopts, datatype, "\n"); + break; + } + + ARG_TRACE(("%s:errorfn(%p, %p, %d, %s, %s)\n", __FILE__, parent, fp, + errorcode, argval, progname)); +} + + +struct arg_lit * arg_lit0( + const char * shortopts, + const char * longopts, + const char * glossary) +{ + return arg_litn(shortopts, longopts, 0, 1, glossary); +} + + +struct arg_lit * arg_lit1( + const char *shortopts, + const char *longopts, + const char *glossary) +{ + return arg_litn(shortopts, longopts, 1, 1, glossary); +} + + +struct arg_lit * arg_litn( + const char *shortopts, + const char *longopts, + int mincount, + int maxcount, + const char *glossary) +{ + struct arg_lit *result; + + /* foolproof things by ensuring maxcount is not less than mincount */ + maxcount = (maxcount < mincount) ? mincount : maxcount; + + result = (struct arg_lit *)malloc(sizeof(struct arg_lit)); + if (result) + { + /* init the arg_hdr struct */ + result->hdr.flag = 0; + result->hdr.shortopts = shortopts; + result->hdr.longopts = longopts; + result->hdr.datatype = NULL; + result->hdr.glossary = glossary; + result->hdr.mincount = mincount; + result->hdr.maxcount = maxcount; + result->hdr.parent = result; + result->hdr.resetfn = (arg_resetfn *)arg_lit_resetfn; + result->hdr.scanfn = (arg_scanfn *)arg_lit_scanfn; + result->hdr.checkfn = (arg_checkfn *)arg_lit_checkfn; + result->hdr.errorfn = (arg_errorfn *)arg_lit_errorfn; + + /* init local variables */ + result->count = 0; + } + + ARG_TRACE(("arg_litn() returns %p\n", result)); + return result; +} +/******************************************************************************* + * This file is part of the argtable3 library. + * + * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of STEWART HEITMANN nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 STEWART HEITMANN 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. + ******************************************************************************/ + +#include + +#include "argtable3.h" + +struct arg_rem *arg_rem(const char *datatype, const char *glossary) +{ + struct arg_rem *result = (struct arg_rem *)malloc(sizeof(struct arg_rem)); + if (result) + { + result->hdr.flag = 0; + result->hdr.shortopts = NULL; + result->hdr.longopts = NULL; + result->hdr.datatype = datatype; + result->hdr.glossary = glossary; + result->hdr.mincount = 1; + result->hdr.maxcount = 1; + result->hdr.parent = result; + result->hdr.resetfn = NULL; + result->hdr.scanfn = NULL; + result->hdr.checkfn = NULL; + result->hdr.errorfn = NULL; + } + + ARG_TRACE(("arg_rem() returns %p\n", result)); + return result; +} + +/******************************************************************************* + * This file is part of the argtable3 library. + * + * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of STEWART HEITMANN nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 STEWART HEITMANN 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. + ******************************************************************************/ + +#include +#include + +#include "argtable3.h" + + +#ifndef _TREX_H_ +#define _TREX_H_ +/*************************************************************** + T-Rex a tiny regular expression library + + Copyright (C) 2003-2006 Alberto Demichelis + + This software is provided 'as-is', without any express + or implied warranty. In no event will the authors be held + liable for any damages arising from the use of this software. + + Permission is granted to anyone to use this software for + any purpose, including commercial applications, and to alter + it and redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; + you must not claim that you wrote the original software. + If you use this software in a product, an acknowledgment + in the product documentation would be appreciated but + is not required. + + 2. Altered source versions must be plainly marked as such, + and must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any + source distribution. + +****************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _UNICODE +#define TRexChar unsigned short +#define MAX_CHAR 0xFFFF +#define _TREXC(c) L##c +#define trex_strlen wcslen +#define trex_printf wprintf +#else +#define TRexChar char +#define MAX_CHAR 0xFF +#define _TREXC(c) (c) +#define trex_strlen strlen +#define trex_printf printf +#endif + +#ifndef TREX_API +#define TREX_API extern +#endif + +#define TRex_True 1 +#define TRex_False 0 + +#define TREX_ICASE ARG_REX_ICASE + +typedef unsigned int TRexBool; +typedef struct TRex TRex; + +typedef struct { + const TRexChar *begin; + int len; +} TRexMatch; + +TREX_API TRex *trex_compile(const TRexChar *pattern, const TRexChar **error, int flags); +TREX_API void trex_free(TRex *exp); +TREX_API TRexBool trex_match(TRex* exp, const TRexChar* text); +TREX_API TRexBool trex_search(TRex* exp, const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end); +TREX_API TRexBool trex_searchrange(TRex* exp, const TRexChar* text_begin, const TRexChar* text_end, const TRexChar** out_begin, const TRexChar** out_end); +TREX_API int trex_getsubexpcount(TRex* exp); +TREX_API TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp); + +#ifdef __cplusplus +} +#endif + +#endif + + + +struct privhdr +{ + const char *pattern; + int flags; +}; + + +static void arg_rex_resetfn(struct arg_rex *parent) +{ + ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); + parent->count = 0; +} + +static int arg_rex_scanfn(struct arg_rex *parent, const char *argval) +{ + int errorcode = 0; + const TRexChar *error = NULL; + TRex *rex = NULL; + TRexBool is_match = TRex_False; + + if (parent->count == parent->hdr.maxcount ) + { + /* maximum number of arguments exceeded */ + errorcode = EMAXCOUNT; + } + else if (!argval) + { + /* a valid argument with no argument value was given. */ + /* This happens when an optional argument value was invoked. */ + /* leave parent argument value unaltered but still count the argument. */ + parent->count++; + } + else + { + struct privhdr *priv = (struct privhdr *)parent->hdr.priv; + + /* test the current argument value for a match with the regular expression */ + /* if a match is detected, record the argument value in the arg_rex struct */ + + rex = trex_compile(priv->pattern, &error, priv->flags); + is_match = trex_match(rex, argval); + if (!is_match) + errorcode = EREGNOMATCH; + else + parent->sval[parent->count++] = argval; + + trex_free(rex); + } + + ARG_TRACE(("%s:scanfn(%p) returns %d\n",__FILE__,parent,errorcode)); + return errorcode; +} + +static int arg_rex_checkfn(struct arg_rex *parent) +{ + int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0; + //struct privhdr *priv = (struct privhdr*)parent->hdr.priv; + + /* free the regex "program" we constructed in resetfn */ + //regfree(&(priv->regex)); + + /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/ + return errorcode; +} + +static void arg_rex_errorfn(struct arg_rex *parent, + FILE *fp, + int errorcode, + const char *argval, + const char *progname) +{ + const char *shortopts = parent->hdr.shortopts; + const char *longopts = parent->hdr.longopts; + const char *datatype = parent->hdr.datatype; + + /* make argval NULL safe */ + argval = argval ? argval : ""; + + fprintf(fp, "%s: ", progname); + switch(errorcode) + { + case EMINCOUNT: + fputs("missing option ", fp); + arg_print_option(fp, shortopts, longopts, datatype, "\n"); + break; + + case EMAXCOUNT: + fputs("excess option ", fp); + arg_print_option(fp, shortopts, longopts, argval, "\n"); + break; + + case EREGNOMATCH: + fputs("illegal value ", fp); + arg_print_option(fp, shortopts, longopts, argval, "\n"); + break; + + default: + { + //char errbuff[256]; + //regerror(errorcode, NULL, errbuff, sizeof(errbuff)); + //printf("%s\n", errbuff); + } + break; + } +} + + +struct arg_rex * arg_rex0(const char * shortopts, + const char * longopts, + const char * pattern, + const char *datatype, + int flags, + const char *glossary) +{ + return arg_rexn(shortopts, + longopts, + pattern, + datatype, + 0, + 1, + flags, + glossary); +} + +struct arg_rex * arg_rex1(const char * shortopts, + const char * longopts, + const char * pattern, + const char *datatype, + int flags, + const char *glossary) +{ + return arg_rexn(shortopts, + longopts, + pattern, + datatype, + 1, + 1, + flags, + glossary); +} + + +struct arg_rex * arg_rexn(const char * shortopts, + const char * longopts, + const char * pattern, + const char *datatype, + int mincount, + int maxcount, + int flags, + const char *glossary) +{ + size_t nbytes; + struct arg_rex *result; + struct privhdr *priv; + int i; + const TRexChar *error = NULL; + TRex *rex = NULL; + + if (!pattern) + { + printf( + "argtable: ERROR - illegal regular expression pattern \"(NULL)\"\n"); + printf("argtable: Bad argument table.\n"); + return NULL; + } + + /* foolproof things by ensuring maxcount is not less than mincount */ + maxcount = (maxcount < mincount) ? mincount : maxcount; + + nbytes = sizeof(struct arg_rex) /* storage for struct arg_rex */ + + sizeof(struct privhdr) /* storage for private arg_rex data */ + + maxcount * sizeof(char *); /* storage for sval[maxcount] array */ + + result = (struct arg_rex *)malloc(nbytes); + if (result == NULL) + return result; + + /* init the arg_hdr struct */ + result->hdr.flag = ARG_HASVALUE; + result->hdr.shortopts = shortopts; + result->hdr.longopts = longopts; + result->hdr.datatype = datatype ? datatype : pattern; + result->hdr.glossary = glossary; + result->hdr.mincount = mincount; + result->hdr.maxcount = maxcount; + result->hdr.parent = result; + result->hdr.resetfn = (arg_resetfn *)arg_rex_resetfn; + result->hdr.scanfn = (arg_scanfn *)arg_rex_scanfn; + result->hdr.checkfn = (arg_checkfn *)arg_rex_checkfn; + result->hdr.errorfn = (arg_errorfn *)arg_rex_errorfn; + + /* store the arg_rex_priv struct immediately after the arg_rex struct */ + result->hdr.priv = result + 1; + priv = (struct privhdr *)(result->hdr.priv); + priv->pattern = pattern; + priv->flags = flags; + + /* store the sval[maxcount] array immediately after the arg_rex_priv struct */ + result->sval = (const char * *)(priv + 1); + result->count = 0; + + /* foolproof the string pointers by initializing them to reference empty strings */ + for (i = 0; i < maxcount; i++) + result->sval[i] = ""; + + /* here we construct and destroy a regex representation of the regular + * expression for no other reason than to force any regex errors to be + * trapped now rather than later. If we don't, then errors may go undetected + * until an argument is actually parsed. + */ + + rex = trex_compile(priv->pattern, &error, priv->flags); + if (rex == NULL) + { + ARG_LOG(("argtable: %s \"%s\"\n", error ? error : _TREXC("undefined"), priv->pattern)); + ARG_LOG(("argtable: Bad argument table.\n")); + } + + trex_free(rex); + + ARG_TRACE(("arg_rexn() returns %p\n", result)); + return result; +} + + + +/* see copyright notice in trex.h */ +#include +#include +#include +#include + +#ifdef _UINCODE +#define scisprint iswprint +#define scstrlen wcslen +#define scprintf wprintf +#define _SC(x) L(x) +#else +#define scisprint isprint +#define scstrlen strlen +#define scprintf printf +#define _SC(x) (x) +#endif + +#ifdef _DEBUG +#include + +static const TRexChar *g_nnames[] = +{ + _SC("NONE"),_SC("OP_GREEDY"), _SC("OP_OR"), + _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"), _SC("OP_CLASS"), + _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"), + _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB") +}; + +#endif +#define OP_GREEDY (MAX_CHAR+1) // * + ? {n} +#define OP_OR (MAX_CHAR+2) +#define OP_EXPR (MAX_CHAR+3) //parentesis () +#define OP_NOCAPEXPR (MAX_CHAR+4) //parentesis (?:) +#define OP_DOT (MAX_CHAR+5) +#define OP_CLASS (MAX_CHAR+6) +#define OP_CCLASS (MAX_CHAR+7) +#define OP_NCLASS (MAX_CHAR+8) //negates class the [^ +#define OP_RANGE (MAX_CHAR+9) +#define OP_CHAR (MAX_CHAR+10) +#define OP_EOL (MAX_CHAR+11) +#define OP_BOL (MAX_CHAR+12) +#define OP_WB (MAX_CHAR+13) + +#define TREX_SYMBOL_ANY_CHAR ('.') +#define TREX_SYMBOL_GREEDY_ONE_OR_MORE ('+') +#define TREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*') +#define TREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?') +#define TREX_SYMBOL_BRANCH ('|') +#define TREX_SYMBOL_END_OF_STRING ('$') +#define TREX_SYMBOL_BEGINNING_OF_STRING ('^') +#define TREX_SYMBOL_ESCAPE_CHAR ('\\') + + +typedef int TRexNodeType; + +typedef struct tagTRexNode{ + TRexNodeType type; + int left; + int right; + int next; +}TRexNode; + +struct TRex{ + const TRexChar *_eol; + const TRexChar *_bol; + const TRexChar *_p; + int _first; + int _op; + TRexNode *_nodes; + int _nallocated; + int _nsize; + int _nsubexpr; + TRexMatch *_matches; + int _currsubexp; + void *_jmpbuf; + const TRexChar **_error; + int _flags; +}; + +static int trex_list(TRex *exp); + +static int trex_newnode(TRex *exp, TRexNodeType type) +{ + TRexNode n; + int newid; + n.type = type; + n.next = n.right = n.left = -1; + if(type == OP_EXPR) + n.right = exp->_nsubexpr++; + if(exp->_nallocated < (exp->_nsize + 1)) { + exp->_nallocated *= 2; + exp->_nodes = (TRexNode *)realloc(exp->_nodes, exp->_nallocated * sizeof(TRexNode)); + } + exp->_nodes[exp->_nsize++] = n; + newid = exp->_nsize - 1; + return (int)newid; +} + +static void trex_error(TRex *exp,const TRexChar *error) +{ + if(exp->_error) *exp->_error = error; + longjmp(*((jmp_buf*)exp->_jmpbuf),-1); +} + +static void trex_expect(TRex *exp, int n){ + if((*exp->_p) != n) + trex_error(exp, _SC("expected paren")); + exp->_p++; +} + +static TRexChar trex_escapechar(TRex *exp) +{ + if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR){ + exp->_p++; + switch(*exp->_p) { + case 'v': exp->_p++; return '\v'; + case 'n': exp->_p++; return '\n'; + case 't': exp->_p++; return '\t'; + case 'r': exp->_p++; return '\r'; + case 'f': exp->_p++; return '\f'; + default: return (*exp->_p++); + } + } else if(!scisprint(*exp->_p)) trex_error(exp,_SC("letter expected")); + return (*exp->_p++); +} + +static int trex_charclass(TRex *exp,int classid) +{ + int n = trex_newnode(exp,OP_CCLASS); + exp->_nodes[n].left = classid; + return n; +} + +static int trex_charnode(TRex *exp,TRexBool isclass) +{ + TRexChar t; + if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR) { + exp->_p++; + switch(*exp->_p) { + case 'n': exp->_p++; return trex_newnode(exp,'\n'); + case 't': exp->_p++; return trex_newnode(exp,'\t'); + case 'r': exp->_p++; return trex_newnode(exp,'\r'); + case 'f': exp->_p++; return trex_newnode(exp,'\f'); + case 'v': exp->_p++; return trex_newnode(exp,'\v'); + case 'a': case 'A': case 'w': case 'W': case 's': case 'S': + case 'd': case 'D': case 'x': case 'X': case 'c': case 'C': + case 'p': case 'P': case 'l': case 'u': + { + t = *exp->_p; exp->_p++; + return trex_charclass(exp,t); + } + case 'b': + case 'B': + if(!isclass) { + int node = trex_newnode(exp,OP_WB); + exp->_nodes[node].left = *exp->_p; + exp->_p++; + return node; + } //else default + default: + t = *exp->_p; exp->_p++; + return trex_newnode(exp,t); + } + } + else if(!scisprint(*exp->_p)) { + + trex_error(exp,_SC("letter expected")); + } + t = *exp->_p; exp->_p++; + return trex_newnode(exp,t); +} +static int trex_class(TRex *exp) +{ + int ret = -1; + int first = -1,chain; + if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING){ + ret = trex_newnode(exp,OP_NCLASS); + exp->_p++; + }else ret = trex_newnode(exp,OP_CLASS); + + if(*exp->_p == ']') trex_error(exp,_SC("empty class")); + chain = ret; + while(*exp->_p != ']' && exp->_p != exp->_eol) { + if(*exp->_p == '-' && first != -1){ + int r,t; + if(*exp->_p++ == ']') trex_error(exp,_SC("unfinished range")); + r = trex_newnode(exp,OP_RANGE); + if(first>*exp->_p) trex_error(exp,_SC("invalid range")); + if(exp->_nodes[first].type == OP_CCLASS) trex_error(exp,_SC("cannot use character classes in ranges")); + exp->_nodes[r].left = exp->_nodes[first].type; + t = trex_escapechar(exp); + exp->_nodes[r].right = t; + exp->_nodes[chain].next = r; + chain = r; + first = -1; + } + else{ + if(first!=-1){ + int c = first; + exp->_nodes[chain].next = c; + chain = c; + first = trex_charnode(exp,TRex_True); + } + else{ + first = trex_charnode(exp,TRex_True); + } + } + } + if(first!=-1){ + int c = first; + exp->_nodes[chain].next = c; + chain = c; + first = -1; + } + /* hack? */ + exp->_nodes[ret].left = exp->_nodes[ret].next; + exp->_nodes[ret].next = -1; + return ret; +} + +static int trex_parsenumber(TRex *exp) +{ + int ret = *exp->_p-'0'; + int positions = 10; + exp->_p++; + while(isdigit(*exp->_p)) { + ret = ret*10+(*exp->_p++-'0'); + if(positions==1000000000) trex_error(exp,_SC("overflow in numeric constant")); + positions *= 10; + }; + return ret; +} + +static int trex_element(TRex *exp) +{ + int ret = -1; + switch(*exp->_p) + { + case '(': { + int expr,newn; + exp->_p++; + + + if(*exp->_p =='?') { + exp->_p++; + trex_expect(exp,':'); + expr = trex_newnode(exp,OP_NOCAPEXPR); + } + else + expr = trex_newnode(exp,OP_EXPR); + newn = trex_list(exp); + exp->_nodes[expr].left = newn; + ret = expr; + trex_expect(exp,')'); + } + break; + case '[': + exp->_p++; + ret = trex_class(exp); + trex_expect(exp,']'); + break; + case TREX_SYMBOL_END_OF_STRING: exp->_p++; ret = trex_newnode(exp,OP_EOL);break; + case TREX_SYMBOL_ANY_CHAR: exp->_p++; ret = trex_newnode(exp,OP_DOT);break; + default: + ret = trex_charnode(exp,TRex_False); + break; + } + + { + TRexBool isgreedy = TRex_False; + unsigned short p0 = 0, p1 = 0; + switch(*exp->_p){ + case TREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break; + case TREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break; + case TREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; isgreedy = TRex_True; break; + case '{': + exp->_p++; + if(!isdigit(*exp->_p)) trex_error(exp,_SC("number expected")); + p0 = (unsigned short)trex_parsenumber(exp); + /*******************************/ + switch(*exp->_p) { + case '}': + p1 = p0; exp->_p++; + break; + case ',': + exp->_p++; + p1 = 0xFFFF; + if(isdigit(*exp->_p)){ + p1 = (unsigned short)trex_parsenumber(exp); + } + trex_expect(exp,'}'); + break; + default: + trex_error(exp,_SC(", or } expected")); + } + /*******************************/ + isgreedy = TRex_True; + break; + + } + if(isgreedy) { + int nnode = trex_newnode(exp,OP_GREEDY); + exp->_nodes[nnode].left = ret; + exp->_nodes[nnode].right = ((p0)<<16)|p1; + ret = nnode; + } + } + if((*exp->_p != TREX_SYMBOL_BRANCH) && (*exp->_p != ')') && (*exp->_p != TREX_SYMBOL_GREEDY_ZERO_OR_MORE) && (*exp->_p != TREX_SYMBOL_GREEDY_ONE_OR_MORE) && (*exp->_p != '\0')) { + int nnode = trex_element(exp); + exp->_nodes[ret].next = nnode; + } + + return ret; +} + +static int trex_list(TRex *exp) +{ + int ret=-1,e; + if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING) { + exp->_p++; + ret = trex_newnode(exp,OP_BOL); + } + e = trex_element(exp); + if(ret != -1) { + exp->_nodes[ret].next = e; + } + else ret = e; + + if(*exp->_p == TREX_SYMBOL_BRANCH) { + int temp,tright; + exp->_p++; + temp = trex_newnode(exp,OP_OR); + exp->_nodes[temp].left = ret; + tright = trex_list(exp); + exp->_nodes[temp].right = tright; + ret = temp; + } + return ret; +} + +static TRexBool trex_matchcclass(int cclass,TRexChar c) +{ + switch(cclass) { + case 'a': return isalpha(c)?TRex_True:TRex_False; + case 'A': return !isalpha(c)?TRex_True:TRex_False; + case 'w': return (isalnum(c) || c == '_')?TRex_True:TRex_False; + case 'W': return (!isalnum(c) && c != '_')?TRex_True:TRex_False; + case 's': return ISSPACE(c)?TRex_True:TRex_False; + case 'S': return !ISSPACE(c)?TRex_True:TRex_False; + case 'd': return isdigit(c)?TRex_True:TRex_False; + case 'D': return !isdigit(c)?TRex_True:TRex_False; + case 'x': return isxdigit(c)?TRex_True:TRex_False; + case 'X': return !isxdigit(c)?TRex_True:TRex_False; + case 'c': return iscntrl(c)?TRex_True:TRex_False; + case 'C': return !iscntrl(c)?TRex_True:TRex_False; + case 'p': return ispunct(c)?TRex_True:TRex_False; + case 'P': return !ispunct(c)?TRex_True:TRex_False; + case 'l': return islower(c)?TRex_True:TRex_False; + case 'u': return isupper(c)?TRex_True:TRex_False; + } + return TRex_False; /*cannot happen*/ +} + +static TRexBool trex_matchclass(TRex* exp,TRexNode *node,TRexChar c) +{ + do { + switch(node->type) { + case OP_RANGE: + if (exp->_flags & TREX_ICASE) + { + if(c >= toupper(node->left) && c <= toupper(node->right)) return TRex_True; + if(c >= tolower(node->left) && c <= tolower(node->right)) return TRex_True; + } + else + { + if(c >= node->left && c <= node->right) return TRex_True; + } + break; + case OP_CCLASS: + if(trex_matchcclass(node->left,c)) return TRex_True; + break; + default: + if (exp->_flags & TREX_ICASE) + { + if (c == tolower(node->type) || c == toupper(node->type)) return TRex_True; + } + else + { + if(c == node->type)return TRex_True; + } + + } + } while((node->next != -1) && (node = &exp->_nodes[node->next])); + return TRex_False; +} + +static const TRexChar *trex_matchnode(TRex* exp,TRexNode *node,const TRexChar *str,TRexNode *next) +{ + + TRexNodeType type = node->type; + switch(type) { + case OP_GREEDY: { + //TRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL; + TRexNode *greedystop = NULL; + int p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0; + const TRexChar *s=str, *good = str; + + if(node->next != -1) { + greedystop = &exp->_nodes[node->next]; + } + else { + greedystop = next; + } + + while((nmaches == 0xFFFF || nmaches < p1)) { + + const TRexChar *stop; + if(!(s = trex_matchnode(exp,&exp->_nodes[node->left],s,greedystop))) + break; + nmaches++; + good=s; + if(greedystop) { + //checks that 0 matches satisfy the expression(if so skips) + //if not would always stop(for instance if is a '?') + if(greedystop->type != OP_GREEDY || + (greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0)) + { + TRexNode *gnext = NULL; + if(greedystop->next != -1) { + gnext = &exp->_nodes[greedystop->next]; + }else if(next && next->next != -1){ + gnext = &exp->_nodes[next->next]; + } + stop = trex_matchnode(exp,greedystop,s,gnext); + if(stop) { + //if satisfied stop it + if(p0 == p1 && p0 == nmaches) break; + else if(nmaches >= p0 && p1 == 0xFFFF) break; + else if(nmaches >= p0 && nmaches <= p1) break; + } + } + } + + if(s >= exp->_eol) + break; + } + if(p0 == p1 && p0 == nmaches) return good; + else if(nmaches >= p0 && p1 == 0xFFFF) return good; + else if(nmaches >= p0 && nmaches <= p1) return good; + return NULL; + } + case OP_OR: { + const TRexChar *asd = str; + TRexNode *temp=&exp->_nodes[node->left]; + while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) { + if(temp->next != -1) + temp = &exp->_nodes[temp->next]; + else + return asd; + } + asd = str; + temp = &exp->_nodes[node->right]; + while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) { + if(temp->next != -1) + temp = &exp->_nodes[temp->next]; + else + return asd; + } + return NULL; + break; + } + case OP_EXPR: + case OP_NOCAPEXPR:{ + TRexNode *n = &exp->_nodes[node->left]; + const TRexChar *cur = str; + int capture = -1; + if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) { + capture = exp->_currsubexp; + exp->_matches[capture].begin = cur; + exp->_currsubexp++; + } + + do { + TRexNode *subnext = NULL; + if(n->next != -1) { + subnext = &exp->_nodes[n->next]; + }else { + subnext = next; + } + if(!(cur = trex_matchnode(exp,n,cur,subnext))) { + if(capture != -1){ + exp->_matches[capture].begin = 0; + exp->_matches[capture].len = 0; + } + return NULL; + } + } while((n->next != -1) && (n = &exp->_nodes[n->next])); + + if(capture != -1) + exp->_matches[capture].len = (int)(cur - exp->_matches[capture].begin); + return cur; + } + case OP_WB: + if((str == exp->_bol && !ISSPACE(*str)) + || ((str == exp->_eol && !ISSPACE(*(str-1)))) + || ((!ISSPACE(*str) && ISSPACE(*(str+1)))) + || ((ISSPACE(*str) && !ISSPACE(*(str+1)))) ) { + return (node->left == 'b')?str:NULL; + } + return (node->left == 'b')?NULL:str; + case OP_BOL: + if(str == exp->_bol) return str; + return NULL; + case OP_EOL: + if(str == exp->_eol) return str; + return NULL; + case OP_DOT: + str++; + return str; + case OP_NCLASS: + case OP_CLASS: + if(trex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?TRex_True:TRex_False):(type == OP_NCLASS?TRex_True:TRex_False)) { + str++; + return str; + } + return NULL; + case OP_CCLASS: + if(trex_matchcclass(node->left,*str)) { + str++; + return str; + } + return NULL; + default: /* char */ + if (exp->_flags & TREX_ICASE) + { + if(*str != tolower(node->type) && *str != toupper(node->type)) return NULL; + } + else + { + if (*str != node->type) return NULL; + } + str++; + return str; + } + return NULL; +} + +/* public api */ +TRex *trex_compile(const TRexChar *pattern,const TRexChar **error,int flags) +{ + TRex *exp = (TRex *)malloc(sizeof(TRex)); + exp->_eol = exp->_bol = NULL; + exp->_p = pattern; + exp->_nallocated = (int)scstrlen(pattern) * sizeof(TRexChar); + exp->_nodes = (TRexNode *)malloc(exp->_nallocated * sizeof(TRexNode)); + exp->_nsize = 0; + exp->_matches = 0; + exp->_nsubexpr = 0; + exp->_first = trex_newnode(exp,OP_EXPR); + exp->_error = error; + exp->_jmpbuf = malloc(sizeof(jmp_buf)); + exp->_flags = flags; + if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) { + int res = trex_list(exp); + exp->_nodes[exp->_first].left = res; + if(*exp->_p!='\0') + trex_error(exp,_SC("unexpected character")); +#ifdef _DEBUG + { + int nsize,i; + TRexNode *t; + nsize = exp->_nsize; + t = &exp->_nodes[0]; + scprintf(_SC("\n")); + for(i = 0;i < nsize; i++) { + if(exp->_nodes[i].type>MAX_CHAR) + scprintf(_SC("[%02d] %10s "),i,g_nnames[exp->_nodes[i].type-MAX_CHAR]); + else + scprintf(_SC("[%02d] %10c "),i,exp->_nodes[i].type); + scprintf(_SC("left %02d right %02d next %02d\n"),exp->_nodes[i].left,exp->_nodes[i].right,exp->_nodes[i].next); + } + scprintf(_SC("\n")); + } +#endif + exp->_matches = (TRexMatch *) malloc(exp->_nsubexpr * sizeof(TRexMatch)); + memset(exp->_matches,0,exp->_nsubexpr * sizeof(TRexMatch)); + } + else{ + trex_free(exp); + return NULL; + } + return exp; +} + +void trex_free(TRex *exp) +{ + if(exp) { + if(exp->_nodes) free(exp->_nodes); + if(exp->_jmpbuf) free(exp->_jmpbuf); + if(exp->_matches) free(exp->_matches); + free(exp); + } +} + +TRexBool trex_match(TRex* exp,const TRexChar* text) +{ + const TRexChar* res = NULL; + exp->_bol = text; + exp->_eol = text + scstrlen(text); + exp->_currsubexp = 0; + res = trex_matchnode(exp,exp->_nodes,text,NULL); + if(res == NULL || res != exp->_eol) + return TRex_False; + return TRex_True; +} + +TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end) +{ + const TRexChar *cur = NULL; + int node = exp->_first; + if(text_begin >= text_end) return TRex_False; + exp->_bol = text_begin; + exp->_eol = text_end; + do { + cur = text_begin; + while(node != -1) { + exp->_currsubexp = 0; + cur = trex_matchnode(exp,&exp->_nodes[node],cur,NULL); + if(!cur) + break; + node = exp->_nodes[node].next; + } + text_begin++; + } while(cur == NULL && text_begin != text_end); + + if(cur == NULL) + return TRex_False; + + --text_begin; + + if(out_begin) *out_begin = text_begin; + if(out_end) *out_end = cur; + return TRex_True; +} + +TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end) +{ + return trex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end); +} + +int trex_getsubexpcount(TRex* exp) +{ + return exp->_nsubexpr; +} + +TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp) +{ + if( n<0 || n >= exp->_nsubexpr) return TRex_False; + *subexp = exp->_matches[n]; + return TRex_True; +} +/******************************************************************************* + * This file is part of the argtable3 library. + * + * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of STEWART HEITMANN nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 STEWART HEITMANN 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. + ******************************************************************************/ + +#include + +#include "argtable3.h" + + +static void arg_str_resetfn(struct arg_str *parent) +{ + ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); + parent->count = 0; +} + + +static int arg_str_scanfn(struct arg_str *parent, const char *argval) +{ + int errorcode = 0; + + if (parent->count == parent->hdr.maxcount) + { + /* maximum number of arguments exceeded */ + errorcode = EMAXCOUNT; + } + else if (!argval) + { + /* a valid argument with no argument value was given. */ + /* This happens when an optional argument value was invoked. */ + /* leave parent arguiment value unaltered but still count the argument. */ + parent->count++; + } + else + { + parent->sval[parent->count++] = argval; + } + + ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode)); + return errorcode; +} + + +static int arg_str_checkfn(struct arg_str *parent) +{ + int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0; + + ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode)); + return errorcode; +} + + +static void arg_str_errorfn( + struct arg_str *parent, + FILE *fp, + int errorcode, + const char *argval, + const char *progname) +{ + const char *shortopts = parent->hdr.shortopts; + const char *longopts = parent->hdr.longopts; + const char *datatype = parent->hdr.datatype; + + /* make argval NULL safe */ + argval = argval ? argval : ""; + + fprintf(fp, "%s: ", progname); + switch(errorcode) + { + case EMINCOUNT: + fputs("missing option ", fp); + arg_print_option(fp, shortopts, longopts, datatype, "\n"); + break; + + case EMAXCOUNT: + fputs("excess option ", fp); + arg_print_option(fp, shortopts, longopts, argval, "\n"); + break; + } +} + + +struct arg_str * arg_str0( + const char *shortopts, + const char *longopts, + const char *datatype, + const char *glossary) +{ + return arg_strn(shortopts, longopts, datatype, 0, 1, glossary); +} + + +struct arg_str * arg_str1( + const char *shortopts, + const char *longopts, + const char *datatype, + const char *glossary) +{ + return arg_strn(shortopts, longopts, datatype, 1, 1, glossary); +} + + +struct arg_str * arg_strn( + const char *shortopts, + const char *longopts, + const char *datatype, + int mincount, + int maxcount, + const char *glossary) +{ + size_t nbytes; + struct arg_str *result; + + /* should not allow this stupid error */ + /* we should return an error code warning this logic error */ + /* foolproof things by ensuring maxcount is not less than mincount */ + maxcount = (maxcount < mincount) ? mincount : maxcount; + + nbytes = sizeof(struct arg_str) /* storage for struct arg_str */ + + maxcount * sizeof(char *); /* storage for sval[maxcount] array */ + + result = (struct arg_str *)malloc(nbytes); + if (result) + { + int i; + + /* init the arg_hdr struct */ + result->hdr.flag = ARG_HASVALUE; + result->hdr.shortopts = shortopts; + result->hdr.longopts = longopts; + result->hdr.datatype = datatype ? datatype : ""; + result->hdr.glossary = glossary; + result->hdr.mincount = mincount; + result->hdr.maxcount = maxcount; + result->hdr.parent = result; + result->hdr.resetfn = (arg_resetfn *)arg_str_resetfn; + result->hdr.scanfn = (arg_scanfn *)arg_str_scanfn; + result->hdr.checkfn = (arg_checkfn *)arg_str_checkfn; + result->hdr.errorfn = (arg_errorfn *)arg_str_errorfn; + + /* store the sval[maxcount] array immediately after the arg_str struct */ + result->sval = (const char * *)(result + 1); + result->count = 0; + + /* foolproof the string pointers by initialising them to reference empty strings */ + for (i = 0; i < maxcount; i++) + result->sval[i] = ""; + } + + ARG_TRACE(("arg_strn() returns %p\n", result)); + return result; +} +/******************************************************************************* + * This file is part of the argtable3 library. + * + * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of STEWART HEITMANN nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 STEWART HEITMANN 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. + ******************************************************************************/ + +#include +#include +#include +#include + +#include "argtable3.h" + +static +void arg_register_error(struct arg_end *end, + void *parent, + int error, + const char *argval) +{ + /* printf("arg_register_error(%p,%p,%d,%s)\n",end,parent,error,argval); */ + if (end->count < end->hdr.maxcount) + { + end->error[end->count] = error; + end->parent[end->count] = parent; + end->argval[end->count] = argval; + end->count++; + } + else + { + end->error[end->hdr.maxcount - 1] = ARG_ELIMIT; + end->parent[end->hdr.maxcount - 1] = end; + end->argval[end->hdr.maxcount - 1] = NULL; + } +} + + +/* + * Return index of first table entry with a matching short option + * or -1 if no match was found. + */ +static +int find_shortoption(struct arg_hdr * *table, char shortopt) +{ + int tabindex; + for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) + { + if (table[tabindex]->shortopts && + strchr(table[tabindex]->shortopts, shortopt)) + return tabindex; + } + return -1; +} + + +struct longoptions +{ + int getoptval; + int noptions; + struct option *options; +}; + +#if 0 +static +void dump_longoptions(struct longoptions * longoptions) +{ + int i; + printf("getoptval = %d\n", longoptions->getoptval); + printf("noptions = %d\n", longoptions->noptions); + for (i = 0; i < longoptions->noptions; i++) + { + printf("options[%d].name = \"%s\"\n", + i, + longoptions->options[i].name); + printf("options[%d].has_arg = %d\n", i, longoptions->options[i].has_arg); + printf("options[%d].flag = %p\n", i, longoptions->options[i].flag); + printf("options[%d].val = %d\n", i, longoptions->options[i].val); + } +} +#endif + +static +struct longoptions * alloc_longoptions(struct arg_hdr * *table) +{ + struct longoptions *result; + size_t nbytes; + int noptions = 1; + size_t longoptlen = 0; + int tabindex; + + /* + * Determine the total number of option structs required + * by counting the number of comma separated long options + * in all table entries and return the count in noptions. + * note: noptions starts at 1 not 0 because we getoptlong + * requires a NULL option entry to terminate the option array. + * While we are at it, count the number of chars required + * to store private copies of all the longoption strings + * and return that count in logoptlen. + */ + tabindex = 0; + do + { + const char *longopts = table[tabindex]->longopts; + longoptlen += (longopts ? strlen(longopts) : 0) + 1; + while (longopts) + { + noptions++; + longopts = strchr(longopts + 1, ','); + } + } while(!(table[tabindex++]->flag & ARG_TERMINATOR)); + /*printf("%d long options consuming %d chars in total\n",noptions,longoptlen);*/ + + + /* allocate storage for return data structure as: */ + /* (struct longoptions) + (struct options)[noptions] + char[longoptlen] */ + nbytes = sizeof(struct longoptions) + + sizeof(struct option) * noptions + + longoptlen; + result = (struct longoptions *)malloc(nbytes); + if (result) + { + int option_index = 0; + char *store; + + result->getoptval = 0; + result->noptions = noptions; + result->options = (struct option *)(result + 1); + store = (char *)(result->options + noptions); + + for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) + { + const char *longopts = table[tabindex]->longopts; + + while(longopts && *longopts) + { + char *storestart = store; + + /* copy progressive longopt strings into the store */ + while (*longopts != 0 && *longopts != ',') + *store++ = *longopts++; + *store++ = 0; + if (*longopts == ',') + longopts++; + /*fprintf(stderr,"storestart=\"%s\"\n",storestart);*/ + + result->options[option_index].name = storestart; + result->options[option_index].flag = &(result->getoptval); + result->options[option_index].val = tabindex; + if (table[tabindex]->flag & ARG_HASOPTVALUE) + result->options[option_index].has_arg = 2; + else if (table[tabindex]->flag & ARG_HASVALUE) + result->options[option_index].has_arg = 1; + else + result->options[option_index].has_arg = 0; + + option_index++; + } + } + /* terminate the options array with a zero-filled entry */ + result->options[option_index].name = 0; + result->options[option_index].has_arg = 0; + result->options[option_index].flag = 0; + result->options[option_index].val = 0; + } + + /*dump_longoptions(result);*/ + return result; +} + +static +char * alloc_shortoptions(struct arg_hdr * *table) +{ + char *result; + size_t len = 2; + int tabindex; + + /* determine the total number of option chars required */ + for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) + { + struct arg_hdr *hdr = table[tabindex]; + len += 3 * (hdr->shortopts ? strlen(hdr->shortopts) : 0); + } + + result = malloc(len); + if (result) + { + char *res = result; + + /* add a leading ':' so getopt return codes distinguish */ + /* unrecognised option and options missing argument values */ + *res++ = ':'; + + for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) + { + struct arg_hdr *hdr = table[tabindex]; + const char *shortopts = hdr->shortopts; + while(shortopts && *shortopts) + { + *res++ = *shortopts++; + if (hdr->flag & ARG_HASVALUE) + *res++ = ':'; + if (hdr->flag & ARG_HASOPTVALUE) + *res++ = ':'; + } + } + /* null terminate the string */ + *res = 0; + } + + /*printf("alloc_shortoptions() returns \"%s\"\n",(result?result:"NULL"));*/ + return result; +} + + +/* return index of the table terminator entry */ +static +int arg_endindex(struct arg_hdr * *table) +{ + int tabindex = 0; + while (!(table[tabindex]->flag & ARG_TERMINATOR)) + tabindex++; + return tabindex; +} + + +static +void arg_parse_tagged(int argc, + char * *argv, + struct arg_hdr * *table, + struct arg_end *endtable) +{ + struct longoptions *longoptions; + char *shortoptions; + int copt; + + /*printf("arg_parse_tagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/ + + /* allocate short and long option arrays for the given opttable[]. */ + /* if the allocs fail then put an error msg in the last table entry. */ + longoptions = alloc_longoptions(table); + shortoptions = alloc_shortoptions(table); + if (!longoptions || !shortoptions) + { + /* one or both memory allocs failed */ + arg_register_error(endtable, endtable, ARG_EMALLOC, NULL); + /* free anything that was allocated (this is null safe) */ + free(shortoptions); + free(longoptions); + return; + } + + /*dump_longoptions(longoptions);*/ + + /* reset getopts internal option-index to zero, and disable error reporting */ + optind = 0; + opterr = 0; + + /* fetch and process args using getopt_long */ + while( (copt = + getopt_long(argc, argv, shortoptions, longoptions->options, + NULL)) != -1) + { + /* + printf("optarg='%s'\n",optarg); + printf("optind=%d\n",optind); + printf("copt=%c\n",(char)copt); + printf("optopt=%c (%d)\n",optopt, (int)(optopt)); + */ + switch(copt) + { + case 0: + { + int tabindex = longoptions->getoptval; + void *parent = table[tabindex]->parent; + /*printf("long option detected from argtable[%d]\n", tabindex);*/ + if (optarg && optarg[0] == 0 && + (table[tabindex]->flag & ARG_HASVALUE)) + { + /* printf(": long option %s requires an argument\n",argv[optind-1]); */ + arg_register_error(endtable, endtable, ARG_EMISSARG, + argv[optind - 1]); + /* continue to scan the (empty) argument value to enforce argument count checking */ + } + if (table[tabindex]->scanfn) + { + int errorcode = table[tabindex]->scanfn(parent, optarg); + if (errorcode != 0) + arg_register_error(endtable, parent, errorcode, optarg); + } + } + break; + + case '?': + /* + * getopt_long() found an unrecognised short option. + * if it was a short option its value is in optopt + * if it was a long option then optopt=0 + */ + switch (optopt) + { + case 0: + /*printf("?0 unrecognised long option %s\n",argv[optind-1]);*/ + arg_register_error(endtable, endtable, ARG_ELONGOPT, + argv[optind - 1]); + break; + default: + /*printf("?* unrecognised short option '%c'\n",optopt);*/ + arg_register_error(endtable, endtable, optopt, NULL); + break; + } + break; + + case ':': + /* + * getopt_long() found an option with its argument missing. + */ + /*printf(": option %s requires an argument\n",argv[optind-1]); */ + arg_register_error(endtable, endtable, ARG_EMISSARG, + argv[optind - 1]); + break; + + default: + { + /* getopt_long() found a valid short option */ + int tabindex = find_shortoption(table, (char)copt); + /*printf("short option detected from argtable[%d]\n", tabindex);*/ + if (tabindex == -1) + { + /* should never get here - but handle it just in case */ + /*printf("unrecognised short option %d\n",copt);*/ + arg_register_error(endtable, endtable, copt, NULL); + } + else + { + if (table[tabindex]->scanfn) + { + void *parent = table[tabindex]->parent; + int errorcode = table[tabindex]->scanfn(parent, optarg); + if (errorcode != 0) + arg_register_error(endtable, parent, errorcode, optarg); + } + } + break; + } + } + } + + free(shortoptions); + free(longoptions); +} + + +static +void arg_parse_untagged(int argc, + char * *argv, + struct arg_hdr * *table, + struct arg_end *endtable) +{ + int tabindex = 0; + int errorlast = 0; + const char *optarglast = NULL; + void *parentlast = NULL; + + /*printf("arg_parse_untagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/ + while (!(table[tabindex]->flag & ARG_TERMINATOR)) + { + void *parent; + int errorcode; + + /* if we have exhausted our argv[optind] entries then we have finished */ + if (optind >= argc) + { + /*printf("arg_parse_untagged(): argv[] exhausted\n");*/ + return; + } + + /* skip table entries with non-null long or short options (they are not untagged entries) */ + if (table[tabindex]->longopts || table[tabindex]->shortopts) + { + /*printf("arg_parse_untagged(): skipping argtable[%d] (tagged argument)\n",tabindex);*/ + tabindex++; + continue; + } + + /* skip table entries with NULL scanfn */ + if (!(table[tabindex]->scanfn)) + { + /*printf("arg_parse_untagged(): skipping argtable[%d] (NULL scanfn)\n",tabindex);*/ + tabindex++; + continue; + } + + /* attempt to scan the current argv[optind] with the current */ + /* table[tabindex] entry. If it succeeds then keep it, otherwise */ + /* try again with the next table[] entry. */ + parent = table[tabindex]->parent; + errorcode = table[tabindex]->scanfn(parent, argv[optind]); + if (errorcode == 0) + { + /* success, move onto next argv[optind] but stay with same table[tabindex] */ + /*printf("arg_parse_untagged(): argtable[%d] successfully matched\n",tabindex);*/ + optind++; + + /* clear the last tentative error */ + errorlast = 0; + } + else + { + /* failure, try same argv[optind] with next table[tabindex] entry */ + /*printf("arg_parse_untagged(): argtable[%d] failed match\n",tabindex);*/ + tabindex++; + + /* remember this as a tentative error we may wish to reinstate later */ + errorlast = errorcode; + optarglast = argv[optind]; + parentlast = parent; + } + + } + + /* if a tenative error still remains at this point then register it as a proper error */ + if (errorlast) + { + arg_register_error(endtable, parentlast, errorlast, optarglast); + optind++; + } + + /* only get here when not all argv[] entries were consumed */ + /* register an error for each unused argv[] entry */ + while (optind < argc) + { + /*printf("arg_parse_untagged(): argv[%d]=\"%s\" not consumed\n",optind,argv[optind]);*/ + arg_register_error(endtable, endtable, ARG_ENOMATCH, argv[optind++]); + } + + return; +} + + +static +void arg_parse_check(struct arg_hdr * *table, struct arg_end *endtable) +{ + int tabindex = 0; + /* printf("arg_parse_check()\n"); */ + do + { + if (table[tabindex]->checkfn) + { + void *parent = table[tabindex]->parent; + int errorcode = table[tabindex]->checkfn(parent); + if (errorcode != 0) + arg_register_error(endtable, parent, errorcode, NULL); + } + } while(!(table[tabindex++]->flag & ARG_TERMINATOR)); +} + + +static +void arg_reset(void * *argtable) +{ + struct arg_hdr * *table = (struct arg_hdr * *)argtable; + int tabindex = 0; + /*printf("arg_reset(%p)\n",argtable);*/ + do + { + if (table[tabindex]->resetfn) + table[tabindex]->resetfn(table[tabindex]->parent); + } while(!(table[tabindex++]->flag & ARG_TERMINATOR)); +} + + +int arg_parse(int argc, char * *argv, void * *argtable) +{ + struct arg_hdr * *table = (struct arg_hdr * *)argtable; + struct arg_end *endtable; + int endindex; + char * *argvcopy = NULL; + + /*printf("arg_parse(%d,%p,%p)\n",argc,argv,argtable);*/ + + /* reset any argtable data from previous invocations */ + arg_reset(argtable); + + /* locate the first end-of-table marker within the array */ + endindex = arg_endindex(table); + endtable = (struct arg_end *)table[endindex]; + + /* Special case of argc==0. This can occur on Texas Instruments DSP. */ + /* Failure to trap this case results in an unwanted NULL result from */ + /* the malloc for argvcopy (next code block). */ + if (argc == 0) + { + /* We must still perform post-parse checks despite the absence of command line arguments */ + arg_parse_check(table, endtable); + + /* Now we are finished */ + return endtable->count; + } + + argvcopy = (char **)malloc(sizeof(char *) * (argc + 1)); + if (argvcopy) + { + int i; + + /* + Fill in the local copy of argv[]. We need a local copy + because getopt rearranges argv[] which adversely affects + susbsequent parsing attempts. + */ + for (i = 0; i < argc; i++) + argvcopy[i] = argv[i]; + + argvcopy[argc] = NULL; + + /* parse the command line (local copy) for tagged options */ + arg_parse_tagged(argc, argvcopy, table, endtable); + + /* parse the command line (local copy) for untagged options */ + arg_parse_untagged(argc, argvcopy, table, endtable); + + /* if no errors so far then perform post-parse checks otherwise dont bother */ + if (endtable->count == 0) + arg_parse_check(table, endtable); + + /* release the local copt of argv[] */ + free(argvcopy); + } + else + { + /* memory alloc failed */ + arg_register_error(endtable, endtable, ARG_EMALLOC, NULL); + } + + return endtable->count; +} + + +/* + * Concatenate contents of src[] string onto *pdest[] string. + * The *pdest pointer is altered to point to the end of the + * target string and *pndest is decremented by the same number + * of chars. + * Does not append more than *pndest chars into *pdest[] + * so as to prevent buffer overruns. + * Its something like strncat() but more efficient for repeated + * calls on the same destination string. + * Example of use: + * char dest[30] = "good" + * size_t ndest = sizeof(dest); + * char *pdest = dest; + * arg_char(&pdest,"bye ",&ndest); + * arg_char(&pdest,"cruel ",&ndest); + * arg_char(&pdest,"world!",&ndest); + * Results in: + * dest[] == "goodbye cruel world!" + * ndest == 10 + */ +static +void arg_cat(char * *pdest, const char *src, size_t *pndest) +{ + char *dest = *pdest; + char *end = dest + *pndest; + + /*locate null terminator of dest string */ + while(dest < end && *dest != 0) + dest++; + + /* concat src string to dest string */ + while(dest < end && *src != 0) + *dest++ = *src++; + + /* null terminate dest string */ + *dest = 0; + + /* update *pdest and *pndest */ + *pndest = end - dest; + *pdest = dest; +} + + +static +void arg_cat_option(char *dest, + size_t ndest, + const char *shortopts, + const char *longopts, + const char *datatype, + int optvalue) +{ + if (shortopts) + { + char option[3]; + + /* note: option array[] is initialiazed dynamically here to satisfy */ + /* a deficiency in the watcom compiler wrt static array initializers. */ + option[0] = '-'; + option[1] = shortopts[0]; + option[2] = 0; + + arg_cat(&dest, option, &ndest); + if (datatype) + { + arg_cat(&dest, " ", &ndest); + if (optvalue) + { + arg_cat(&dest, "[", &ndest); + arg_cat(&dest, datatype, &ndest); + arg_cat(&dest, "]", &ndest); + } + else + arg_cat(&dest, datatype, &ndest); + } + } + else if (longopts) + { + size_t ncspn; + + /* add "--" tag prefix */ + arg_cat(&dest, "--", &ndest); + + /* add comma separated option tag */ + ncspn = strcspn(longopts, ","); +#ifdef __STDC_WANT_SECURE_LIB__ + strncat_s(dest, ndest, longopts, (ncspn < ndest) ? ncspn : ndest); +#else + strncat(dest, longopts, (ncspn < ndest) ? ncspn : ndest); +#endif + + if (datatype) + { + arg_cat(&dest, "=", &ndest); + if (optvalue) + { + arg_cat(&dest, "[", &ndest); + arg_cat(&dest, datatype, &ndest); + arg_cat(&dest, "]", &ndest); + } + else + arg_cat(&dest, datatype, &ndest); + } + } + else if (datatype) + { + if (optvalue) + { + arg_cat(&dest, "[", &ndest); + arg_cat(&dest, datatype, &ndest); + arg_cat(&dest, "]", &ndest); + } + else + arg_cat(&dest, datatype, &ndest); + } +} + +static +void arg_cat_optionv(char *dest, + size_t ndest, + const char *shortopts, + const char *longopts, + const char *datatype, + int optvalue, + const char *separator) +{ + separator = separator ? separator : ""; + + if (shortopts) + { + const char *c = shortopts; + while(*c) + { + /* "-a|-b|-c" */ + char shortopt[3]; + + /* note: shortopt array[] is initialiazed dynamically here to satisfy */ + /* a deficiency in the watcom compiler wrt static array initializers. */ + shortopt[0] = '-'; + shortopt[1] = *c; + shortopt[2] = 0; + + arg_cat(&dest, shortopt, &ndest); + if (*++c) + arg_cat(&dest, separator, &ndest); + } + } + + /* put separator between long opts and short opts */ + if (shortopts && longopts) + arg_cat(&dest, separator, &ndest); + + if (longopts) + { + const char *c = longopts; + while(*c) + { + size_t ncspn; + + /* add "--" tag prefix */ + arg_cat(&dest, "--", &ndest); + + /* add comma separated option tag */ + ncspn = strcspn(c, ","); +#ifdef __STDC_WANT_SECURE_LIB__ + strncat_s(dest, ndest, c, (ncspn < ndest) ? ncspn : ndest); +#else + strncat(dest, c, (ncspn < ndest) ? ncspn : ndest); +#endif + c += ncspn; + + /* add given separator in place of comma */ + if (*c == ',') + { + arg_cat(&dest, separator, &ndest); + c++; + } + } + } + + if (datatype) + { + if (longopts) + arg_cat(&dest, "=", &ndest); + else if (shortopts) + arg_cat(&dest, " ", &ndest); + + if (optvalue) + { + arg_cat(&dest, "[", &ndest); + arg_cat(&dest, datatype, &ndest); + arg_cat(&dest, "]", &ndest); + } + else + arg_cat(&dest, datatype, &ndest); + } +} + + +/* this function should be deprecated because it doesnt consider optional argument values (ARG_HASOPTVALUE) */ +void arg_print_option(FILE *fp, + const char *shortopts, + const char *longopts, + const char *datatype, + const char *suffix) +{ + char syntax[200] = ""; + suffix = suffix ? suffix : ""; + + /* there is no way of passing the proper optvalue for optional argument values here, so we must ignore it */ + arg_cat_optionv(syntax, + sizeof(syntax), + shortopts, + longopts, + datatype, + 0, + "|"); + + fputs(syntax, fp); + fputs(suffix, fp); +} + + +/* + * Print a GNU style [OPTION] string in which all short options that + * do not take argument values are presented in abbreviated form, as + * in: -xvfsd, or -xvf[sd], or [-xvsfd] + */ +static +void arg_print_gnuswitch(FILE *fp, struct arg_hdr * *table) +{ + int tabindex; + char *format1 = " -%c"; + char *format2 = " [-%c"; + char *suffix = ""; + + /* print all mandatory switches that are without argument values */ + for(tabindex = 0; + table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR); + tabindex++) + { + /* skip optional options */ + if (table[tabindex]->mincount < 1) + continue; + + /* skip non-short options */ + if (table[tabindex]->shortopts == NULL) + continue; + + /* skip options that take argument values */ + if (table[tabindex]->flag & ARG_HASVALUE) + continue; + + /* print the short option (only the first short option char, ignore multiple choices)*/ + fprintf(fp, format1, table[tabindex]->shortopts[0]); + format1 = "%c"; + format2 = "[%c"; + } + + /* print all optional switches that are without argument values */ + for(tabindex = 0; + table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR); + tabindex++) + { + /* skip mandatory args */ + if (table[tabindex]->mincount > 0) + continue; + + /* skip args without short options */ + if (table[tabindex]->shortopts == NULL) + continue; + + /* skip args with values */ + if (table[tabindex]->flag & ARG_HASVALUE) + continue; + + /* print first short option */ + fprintf(fp, format2, table[tabindex]->shortopts[0]); + format2 = "%c"; + suffix = "]"; + } + + fprintf(fp, "%s", suffix); +} + + +void arg_print_syntax(FILE *fp, void * *argtable, const char *suffix) +{ + struct arg_hdr * *table = (struct arg_hdr * *)argtable; + int i, tabindex; + + /* print GNU style [OPTION] string */ + arg_print_gnuswitch(fp, table); + + /* print remaining options in abbreviated style */ + for(tabindex = 0; + table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR); + tabindex++) + { + char syntax[200] = ""; + const char *shortopts, *longopts, *datatype; + + /* skip short options without arg values (they were printed by arg_print_gnu_switch) */ + if (table[tabindex]->shortopts && + !(table[tabindex]->flag & ARG_HASVALUE)) + continue; + + shortopts = table[tabindex]->shortopts; + longopts = table[tabindex]->longopts; + datatype = table[tabindex]->datatype; + arg_cat_option(syntax, + sizeof(syntax), + shortopts, + longopts, + datatype, + table[tabindex]->flag & ARG_HASOPTVALUE); + + if (strlen(syntax) > 0) + { + /* print mandatory instances of this option */ + for (i = 0; i < table[tabindex]->mincount; i++) + fprintf(fp, " %s", syntax); + + /* print optional instances enclosed in "[..]" */ + switch ( table[tabindex]->maxcount - table[tabindex]->mincount ) + { + case 0: + break; + case 1: + fprintf(fp, " [%s]", syntax); + break; + case 2: + fprintf(fp, " [%s] [%s]", syntax, syntax); + break; + default: + fprintf(fp, " [%s]...", syntax); + break; + } + } + } + + if (suffix) + fprintf(fp, "%s", suffix); +} + + +void arg_print_syntaxv(FILE *fp, void * *argtable, const char *suffix) +{ + struct arg_hdr * *table = (struct arg_hdr * *)argtable; + int i, tabindex; + + /* print remaining options in abbreviated style */ + for(tabindex = 0; + table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR); + tabindex++) + { + char syntax[200] = ""; + const char *shortopts, *longopts, *datatype; + + shortopts = table[tabindex]->shortopts; + longopts = table[tabindex]->longopts; + datatype = table[tabindex]->datatype; + arg_cat_optionv(syntax, + sizeof(syntax), + shortopts, + longopts, + datatype, + table[tabindex]->flag & ARG_HASOPTVALUE, + "|"); + + /* print mandatory options */ + for (i = 0; i < table[tabindex]->mincount; i++) + fprintf(fp, " %s", syntax); + + /* print optional args enclosed in "[..]" */ + switch ( table[tabindex]->maxcount - table[tabindex]->mincount ) + { + case 0: + break; + case 1: + fprintf(fp, " [%s]", syntax); + break; + case 2: + fprintf(fp, " [%s] [%s]", syntax, syntax); + break; + default: + fprintf(fp, " [%s]...", syntax); + break; + } + } + + if (suffix) + fprintf(fp, "%s", suffix); +} + + +void arg_print_glossary(FILE *fp, void * *argtable, const char *format) +{ + struct arg_hdr * *table = (struct arg_hdr * *)argtable; + int tabindex; + + format = format ? format : " %-20s %s\n"; + for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) + { + if (table[tabindex]->glossary) + { + char syntax[200] = ""; + const char *shortopts = table[tabindex]->shortopts; + const char *longopts = table[tabindex]->longopts; + const char *datatype = table[tabindex]->datatype; + const char *glossary = table[tabindex]->glossary; + arg_cat_optionv(syntax, + sizeof(syntax), + shortopts, + longopts, + datatype, + table[tabindex]->flag & ARG_HASOPTVALUE, + ", "); + fprintf(fp, format, syntax, glossary); + } + } +} + + +/** + * Print a piece of text formatted, which means in a column with a + * left and a right margin. The lines are wrapped at whitspaces next + * to right margin. The function does not indent the first line, but + * only the following ones. + * + * Example: + * arg_print_formatted( fp, 0, 5, "Some text that doesn't fit." ) + * will result in the following output: + * + * Some + * text + * that + * doesn' + * t fit. + * + * Too long lines will be wrapped in the middle of a word. + * + * arg_print_formatted( fp, 2, 7, "Some text that doesn't fit." ) + * will result in the following output: + * + * Some + * text + * that + * doesn' + * t fit. + * + * As you see, the first line is not indented. This enables output of + * lines, which start in a line where output already happened. + * + * Author: Uli Fouquet + */ +static +void arg_print_formatted( FILE *fp, + const unsigned lmargin, + const unsigned rmargin, + const char *text ) +{ + const unsigned textlen = (unsigned)strlen( text ); + unsigned line_start = 0; + unsigned line_end = textlen + 1; + const unsigned colwidth = (rmargin - lmargin) + 1; + + /* Someone doesn't like us... */ + if ( line_end < line_start ) + { fprintf( fp, "%s\n", text ); } + + while (line_end - 1 > line_start ) + { + /* Eat leading whitespaces. This is essential because while + wrapping lines, there will often be a whitespace at beginning + of line */ + while ( ISSPACE(*(text + line_start)) ) + { line_start++; } + + if ((line_end - line_start) > colwidth ) + { line_end = line_start + colwidth; } + + /* Find last whitespace, that fits into line */ + while ( ( line_end > line_start ) + && ( line_end - line_start > colwidth ) + && !ISSPACE(*(text + line_end))) + { line_end--; } + + /* Do not print trailing whitespace. If this text + has got only one line, line_end now points to the + last char due to initialization. */ + line_end--; + + /* Output line of text */ + while ( line_start < line_end ) + { + fputc(*(text + line_start), fp ); + line_start++; + } + fputc( '\n', fp ); + + /* Initialize another line */ + if ( line_end + 1 < textlen ) + { + unsigned i; + + for (i = 0; i < lmargin; i++ ) + { fputc( ' ', fp ); } + + line_end = textlen; + } + + /* If we have to print another line, get also the last char. */ + line_end++; + + } /* lines of text */ +} + +/** + * Prints the glossary in strict GNU format. + * Differences to arg_print_glossary() are: + * - wraps lines after 80 chars + * - indents lines without shortops + * - does not accept formatstrings + * + * Contributed by Uli Fouquet + */ +void arg_print_glossary_gnu(FILE *fp, void * *argtable ) +{ + struct arg_hdr * *table = (struct arg_hdr * *)argtable; + int tabindex; + + for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) + { + if (table[tabindex]->glossary) + { + char syntax[200] = ""; + const char *shortopts = table[tabindex]->shortopts; + const char *longopts = table[tabindex]->longopts; + const char *datatype = table[tabindex]->datatype; + const char *glossary = table[tabindex]->glossary; + + if ( !shortopts && longopts ) + { + /* Indent trailing line by 4 spaces... */ + memset( syntax, ' ', 4 ); + *(syntax + 4) = '\0'; + } + + arg_cat_optionv(syntax, + sizeof(syntax), + shortopts, + longopts, + datatype, + table[tabindex]->flag & ARG_HASOPTVALUE, + ", "); + + /* If syntax fits not into column, print glossary in new line... */ + if ( strlen(syntax) > 25 ) + { + fprintf( fp, " %-25s %s\n", syntax, "" ); + *syntax = '\0'; + } + + fprintf( fp, " %-25s ", syntax ); + arg_print_formatted( fp, 28, 79, glossary ); + } + } /* for each table entry */ + + fputc( '\n', fp ); +} + + +/** + * Checks the argtable[] array for NULL entries and returns 1 + * if any are found, zero otherwise. + */ +int arg_nullcheck(void * *argtable) +{ + struct arg_hdr * *table = (struct arg_hdr * *)argtable; + int tabindex; + /*printf("arg_nullcheck(%p)\n",argtable);*/ + + if (!table) + return 1; + + tabindex = 0; + do + { + /*printf("argtable[%d]=%p\n",tabindex,argtable[tabindex]);*/ + if (!table[tabindex]) + return 1; + } while(!(table[tabindex++]->flag & ARG_TERMINATOR)); + + return 0; +} + + +/* + * arg_free() is deprecated in favour of arg_freetable() due to a flaw in its design. + * The flaw results in memory leak in the (very rare) case that an intermediate + * entry in the argtable array failed its memory allocation while others following + * that entry were still allocated ok. Those subsequent allocations will not be + * deallocated by arg_free(). + * Despite the unlikeliness of the problem occurring, and the even unlikelier event + * that it has any deliterious effect, it is fixed regardless by replacing arg_free() + * with the newer arg_freetable() function. + * We still keep arg_free() for backwards compatibility. + */ +void arg_free(void * *argtable) +{ + struct arg_hdr * *table = (struct arg_hdr * *)argtable; + int tabindex = 0; + int flag; + /*printf("arg_free(%p)\n",argtable);*/ + do + { + /* + if we encounter a NULL entry then somewhat incorrectly we presume + we have come to the end of the array. It isnt strictly true because + an intermediate entry could be NULL with other non-NULL entries to follow. + The subsequent argtable entries would then not be freed as they should. + */ + if (table[tabindex] == NULL) + break; + + flag = table[tabindex]->flag; + free(table[tabindex]); + table[tabindex++] = NULL; + + } while(!(flag & ARG_TERMINATOR)); +} + +/* frees each non-NULL element of argtable[], where n is the size of the number of entries in the array */ +void arg_freetable(void * *argtable, size_t n) +{ + struct arg_hdr * *table = (struct arg_hdr * *)argtable; + size_t tabindex = 0; + /*printf("arg_freetable(%p)\n",argtable);*/ + for (tabindex = 0; tabindex < n; tabindex++) + { + if (table[tabindex] == NULL) + continue; + + free(table[tabindex]); + table[tabindex] = NULL; + }; +} + diff --git a/Projects/Android/jni/src/Lambda1VR/argtable3.h b/Projects/Android/jni/src/Lambda1VR/argtable3.h new file mode 100644 index 0000000..1107de2 --- /dev/null +++ b/Projects/Android/jni/src/Lambda1VR/argtable3.h @@ -0,0 +1,305 @@ +/******************************************************************************* + * This file is part of the argtable3 library. + * + * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of STEWART HEITMANN nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 STEWART HEITMANN 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. + ******************************************************************************/ + +#ifndef ARGTABLE3 +#define ARGTABLE3 + +#include /* FILE */ +#include /* struct tm */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define ARG_REX_ICASE 1 + +/* bit masks for arg_hdr.flag */ +enum +{ + ARG_TERMINATOR=0x1, + ARG_HASVALUE=0x2, + ARG_HASOPTVALUE=0x4 +}; + +typedef void (arg_resetfn)(void *parent); +typedef int (arg_scanfn)(void *parent, const char *argval); +typedef int (arg_checkfn)(void *parent); +typedef void (arg_errorfn)(void *parent, FILE *fp, int error, const char *argval, const char *progname); + + +/* +* The arg_hdr struct defines properties that are common to all arg_xxx structs. +* The argtable library requires each arg_xxx struct to have an arg_hdr +* struct as its first data member. +* The argtable library functions then use this data to identify the +* properties of the command line option, such as its option tags, +* datatype string, and glossary strings, and so on. +* Moreover, the arg_hdr struct contains pointers to custom functions that +* are provided by each arg_xxx struct which perform the tasks of parsing +* that particular arg_xxx arguments, performing post-parse checks, and +* reporting errors. +* These functions are private to the individual arg_xxx source code +* and are the pointer to them are initiliased by that arg_xxx struct's +* constructor function. The user could alter them after construction +* if desired, but the original intention is for them to be set by the +* constructor and left unaltered. +*/ +struct arg_hdr +{ + char flag; /* Modifier flags: ARG_TERMINATOR, ARG_HASVALUE. */ + const char *shortopts; /* String defining the short options */ + const char *longopts; /* String defiing the long options */ + const char *datatype; /* Description of the argument data type */ + const char *glossary; /* Description of the option as shown by arg_print_glossary function */ + int mincount; /* Minimum number of occurences of this option accepted */ + int maxcount; /* Maximum number of occurences if this option accepted */ + void *parent; /* Pointer to parent arg_xxx struct */ + arg_resetfn *resetfn; /* Pointer to parent arg_xxx reset function */ + arg_scanfn *scanfn; /* Pointer to parent arg_xxx scan function */ + arg_checkfn *checkfn; /* Pointer to parent arg_xxx check function */ + arg_errorfn *errorfn; /* Pointer to parent arg_xxx error function */ + void *priv; /* Pointer to private header data for use by arg_xxx functions */ +}; + +struct arg_rem +{ + struct arg_hdr hdr; /* The mandatory argtable header struct */ +}; + +struct arg_lit +{ + struct arg_hdr hdr; /* The mandatory argtable header struct */ + int count; /* Number of matching command line args */ +}; + +struct arg_int +{ + struct arg_hdr hdr; /* The mandatory argtable header struct */ + int count; /* Number of matching command line args */ + int *ival; /* Array of parsed argument values */ +}; + +struct arg_dbl +{ + struct arg_hdr hdr; /* The mandatory argtable header struct */ + int count; /* Number of matching command line args */ + double *dval; /* Array of parsed argument values */ +}; + +struct arg_str +{ + struct arg_hdr hdr; /* The mandatory argtable header struct */ + int count; /* Number of matching command line args */ + const char **sval; /* Array of parsed argument values */ +}; + +struct arg_rex +{ + struct arg_hdr hdr; /* The mandatory argtable header struct */ + int count; /* Number of matching command line args */ + const char **sval; /* Array of parsed argument values */ +}; + +struct arg_file +{ + struct arg_hdr hdr; /* The mandatory argtable header struct */ + int count; /* Number of matching command line args*/ + const char **filename; /* Array of parsed filenames (eg: /home/foo.bar) */ + const char **basename; /* Array of parsed basenames (eg: foo.bar) */ + const char **extension; /* Array of parsed extensions (eg: .bar) */ +}; + +struct arg_date +{ + struct arg_hdr hdr; /* The mandatory argtable header struct */ + const char *format; /* strptime format string used to parse the date */ + int count; /* Number of matching command line args */ + struct tm *tmval; /* Array of parsed time values */ +}; + +enum {ARG_ELIMIT=1, ARG_EMALLOC, ARG_ENOMATCH, ARG_ELONGOPT, ARG_EMISSARG}; +struct arg_end +{ + struct arg_hdr hdr; /* The mandatory argtable header struct */ + int count; /* Number of errors encountered */ + int *error; /* Array of error codes */ + void **parent; /* Array of pointers to offending arg_xxx struct */ + const char **argval; /* Array of pointers to offending argv[] string */ +}; + + +/**** arg_xxx constructor functions *********************************/ + +struct arg_rem* arg_rem(const char* datatype, const char* glossary); + +struct arg_lit* arg_lit0(const char* shortopts, + const char* longopts, + const char* glossary); +struct arg_lit* arg_lit1(const char* shortopts, + const char* longopts, + const char *glossary); +struct arg_lit* arg_litn(const char* shortopts, + const char* longopts, + int mincount, + int maxcount, + const char *glossary); + +struct arg_key* arg_key0(const char* keyword, + int flags, + const char* glossary); +struct arg_key* arg_key1(const char* keyword, + int flags, + const char* glossary); +struct arg_key* arg_keyn(const char* keyword, + int flags, + int mincount, + int maxcount, + const char* glossary); + +struct arg_int* arg_int0(const char* shortopts, + const char* longopts, + const char* datatype, + const char* glossary); +struct arg_int* arg_int1(const char* shortopts, + const char* longopts, + const char* datatype, + const char *glossary); +struct arg_int* arg_intn(const char* shortopts, + const char* longopts, + const char *datatype, + int mincount, + int maxcount, + const char *glossary); + +struct arg_dbl* arg_dbl0(const char* shortopts, + const char* longopts, + const char* datatype, + const char* glossary); +struct arg_dbl* arg_dbl1(const char* shortopts, + const char* longopts, + const char* datatype, + const char *glossary); +struct arg_dbl* arg_dbln(const char* shortopts, + const char* longopts, + const char *datatype, + int mincount, + int maxcount, + const char *glossary); + +struct arg_str* arg_str0(const char* shortopts, + const char* longopts, + const char* datatype, + const char* glossary); +struct arg_str* arg_str1(const char* shortopts, + const char* longopts, + const char* datatype, + const char *glossary); +struct arg_str* arg_strn(const char* shortopts, + const char* longopts, + const char* datatype, + int mincount, + int maxcount, + const char *glossary); + +struct arg_rex* arg_rex0(const char* shortopts, + const char* longopts, + const char* pattern, + const char* datatype, + int flags, + const char* glossary); +struct arg_rex* arg_rex1(const char* shortopts, + const char* longopts, + const char* pattern, + const char* datatype, + int flags, + const char *glossary); +struct arg_rex* arg_rexn(const char* shortopts, + const char* longopts, + const char* pattern, + const char* datatype, + int mincount, + int maxcount, + int flags, + const char *glossary); + +struct arg_file* arg_file0(const char* shortopts, + const char* longopts, + const char* datatype, + const char* glossary); +struct arg_file* arg_file1(const char* shortopts, + const char* longopts, + const char* datatype, + const char *glossary); +struct arg_file* arg_filen(const char* shortopts, + const char* longopts, + const char* datatype, + int mincount, + int maxcount, + const char *glossary); + +struct arg_date* arg_date0(const char* shortopts, + const char* longopts, + const char* format, + const char* datatype, + const char* glossary); +struct arg_date* arg_date1(const char* shortopts, + const char* longopts, + const char* format, + const char* datatype, + const char *glossary); +struct arg_date* arg_daten(const char* shortopts, + const char* longopts, + const char* format, + const char* datatype, + int mincount, + int maxcount, + const char *glossary); + +struct arg_end* arg_end(int maxerrors); + + +/**** other functions *******************************************/ +int arg_nullcheck(void **argtable); +int arg_parse(int argc, char **argv, void **argtable); +void arg_print_option(FILE *fp, const char *shortopts, const char *longopts, const char *datatype, const char *suffix); +void arg_print_syntax(FILE *fp, void **argtable, const char *suffix); +void arg_print_syntaxv(FILE *fp, void **argtable, const char *suffix); +void arg_print_glossary(FILE *fp, void **argtable, const char *format); +void arg_print_glossary_gnu(FILE *fp, void **argtable); +void arg_print_errors(FILE* fp, struct arg_end* end, const char* progname); +void arg_freetable(void **argtable, size_t n); + +/**** deprecated functions, for back-compatibility only ********/ +void arg_free(void **argtable); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Projects/Android/jni/src/Xash3D/Android.mk b/Projects/Android/jni/src/Xash3D/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/Projects/Android/jni/src/Xash3D/xash3d/.clang-format b/Projects/Android/jni/src/Xash3D/xash3d/.clang-format new file mode 100644 index 0000000..09b29d4 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/.clang-format @@ -0,0 +1,33 @@ +#BasedOnStyle: WebKit +IndentWidth: 4 +TabWidth: 4 +UseTab: ForIndentation + +BreakBeforeBraces: Allman + +AlignAfterOpenBracket: true +AlignConsecutiveAssignments: true +AlignOperands: true + +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false + +NamespaceIndentation: Inner + +SpaceAfterCStyleCast: false +SpaceBeforeParens: true +SpaceInEmptyParentheses: true +SpacesInAngles: true +SpacesInParentheses: true +SpacesBeforeTrailingComments: 1 + +IndentCaseLabels: false +IndentWrappedFunctionNames: true + +PointerAlignment: Right + +ColumnLimit: 0 +BinPackArguments: false \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/.gitignore b/Projects/Android/jni/src/Xash3D/xash3d/.gitignore new file mode 100644 index 0000000..bde4a5a --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/.gitignore @@ -0,0 +1,315 @@ +# Binaries +*.o +*.so +*.a +*.framework + +# Other +*.save +# Qt Creator for some reason creates *.user.$version files, so exclude it too +*.user* +*~ + +### Xcode ### +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.xcuserstate + + +### OSX ### +.DS_Store +.AppleDouble +.LSOverride + + +# Thumbnails +._* + +# Files that might appear on external disk +.Spotlight-V100 +.Trashes + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + + +### CMake ### +CMakeCache.txt +CMakeFiles +Makefile +cmake_install.cmake +install_manifest.txt +# makedepend +Makefile.dep +*.bak +ALL_BUILD.* +INSTALL.* +ZERO_CHECK.* + +# Visual Studio +*.obj +*.dll +*.exp +*.lib +*.suo +*.sdf +Debug/ +Release/ +ipch/ +*.opensdf +# Use CMake for generating projects +*.vcxproj.filters +*.vcxproj +*.sln + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# PVS Studio for Linux output +*.cl.cfg + +# Kate +*.kate-swp +*.swp + +# QtCreator +build-* + +# Android +*.apk + +# Visual Studio CMake support +CMakeSettings.json + +# rpmbuild +RPMS/ diff --git a/Projects/Android/jni/src/Xash3D/xash3d/.gitmodules b/Projects/Android/jni/src/Xash3D/xash3d/.gitmodules new file mode 100644 index 0000000..41b36cd --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/.gitmodules @@ -0,0 +1,6 @@ +[submodule "hlsdk"] + path = hlsdk + url = https://github.com/SDLash3D/halflife +[submodule "mainui"] + path = mainui + url = https://github.com/FWGS/mainui_cpp diff --git a/Projects/Android/jni/src/Xash3D/xash3d/.travis.yml b/Projects/Android/jni/src/Xash3D/xash3d/.travis.yml new file mode 100644 index 0000000..4a046d3 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/.travis.yml @@ -0,0 +1,47 @@ +language: c +cache: ccache +compiler: gcc +sudo: false +addons: + apt: + packages: + - cmake + - mingw-w64-i686-dev + - binutils-mingw-w64-i686 + - gcc-mingw-w64-i686 + - g++-mingw-w64-i686 + - p7zip-full + - gcc-multilib + - g++-multilib + - libx11-dev:i386 + - libxext-dev:i386 + - x11-utils + - libgl1-mesa-dev + - libasound-dev + - zlib1g:i386 + - libstdc++6:i386 +git: + depth: 50 + submodules: true +jdk: + - oraclejdk8 +os: + - linux + - osx + +before_script: + - sh scripts/travis_${TRAVIS_OS_NAME}_deps.sh + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export ANDROID_HOME=$PWD/android-sdk-linux; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export PATH=${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:$PWD/android-ndk; fi + - sh scripts/travis_common_deps.sh +script: + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sh scripts/build_android_engine.sh; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sh scripts/build_mingw_engine.sh; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sh scripts/build_portable_linux_engine.sh; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sh scripts/build_osx_engine.sh; fi +after_script: + - cd ${TRAVIS_BUILD_DIR} + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ccache --show-stats > ccache_stats.log; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sh scripts/travis-deploy.sh travis xash3d-mingw.7z xash3d-linux.7z xash3d-generic.apk android-debug-symbols.txz ccache_stats.log; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sh scripts/travis-upload.sh xash3d-mingw.7z xash3d-linux.7z xash3d-generic.apk; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sh scripts/travis-deploy.sh z_apple xash3d-osx.tar.bz2; fi diff --git a/Projects/Android/jni/src/Xash3D/xash3d/Android.mk b/Projects/Android/jni/src/Xash3D/xash3d/Android.mk new file mode 100644 index 0000000..d8b752f --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/Android.mk @@ -0,0 +1,5 @@ +#include $(call all-subdir-makefiles) + +include $(XASH3D_PATH)/engine/Android.mk +include $(XASH3D_PATH)/mainui/Android.mk +include $(XASH3D_PATH)/vgui_support/Android.mk diff --git a/Projects/Android/jni/src/Xash3D/xash3d/CMakeLists.txt b/Projects/Android/jni/src/Xash3D/xash3d/CMakeLists.txt new file mode 100644 index 0000000..d437f3d --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/CMakeLists.txt @@ -0,0 +1,150 @@ +# +# Copyright (c) 2015 Pavlo Lavrenenko +# +# 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, and to permit persons to whom the Software is +# 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 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 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 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +cmake_minimum_required(VERSION 2.8.0) + +# Install custom module path +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") + +include(VSForceXPToolchain) # Force XP toolchain for Visual Studio + +project(XASH3D) + +include(FWGSLib) +include(CMakeDependentOption) +include(CPack) + +#-------------- +# USER DEFINES \ +################\ + +set (XASH3D_VERSION 0.19.2) + +option(XASH_DEDICATED "Enable dedicated build. Servers must choose this." OFF) # Servers must choose this + +# Enable 64-bit build of Xash3D FWGS Engine. +option(XASH_64BIT "Enable experimental 64-bit build. Note that you must also provide 64-bit game binaries" OFF) + +# Windows only. Enable it by default for Windows. +option(XASH_IPX "Enable IPX support for networking. Windows only. Deprecated." OFF) +cmake_dependent_option(XASH_NONSTANDARD_LOAD "Enable own DLL loader in Windows." ON "WIN32" OFF) + +# POSIX only. Disable it by default for Windows +cmake_dependent_option(XASH_USE_SELECT "Enable reading console commands from stdin." ON "NOT WIN32" OFF) +cmake_dependent_option(XASH_LIBDL "Enable libdl use. POSIX only." ON "NOT WIN32" OFF) + +# Disable for Windows and 64Bit +cmake_dependent_option(XASH_DLL_LOADER "Enable DLL loading on x86 Linux/*nix." OFF "NOT WIN32 AND NOT XASH_64BIT" OFF) + +option(XASH_GLES "Enable if Xash3D is running over GL to GLES translator." OFF) +option(XASH_NANOGL "Use NanoGL(GLES1). Implicitly enables XASH_GLES." OFF) +option(XASH_WES "Use gl-wes-v2(GLES2). Implicitly enables XASH_GLES." OFF) +fwgs_string_option(XASH_NANOGL_SRC "NanoGL source path" "nanogl") +fwgs_string_option(XASH_WES_SRC "gl-wes-v2 source path" "gl-wes-v2") +option(XASH_SAILFISH "Build for Sailfish OS. Implicitly enables XASH_WES, XASH_GLES." OFF) +option(XASH_STATIC "Static build. Implicitly enables XASH_SINGLE_BINARY." OFF) +option(XASH_NO_ASYNC_NS_RESOLVE "Disable asynchronous domain name resolving." OFF) + +option(XASH_VECTORIZE_SINCOS "Try to use vectorized versions of sin(), cos() and sincos()" ON) + +# Desktop or dedicated version options +if(XASH_DEDICATED) + option(XASH_SDL "Enable SDL." OFF) # Dedicated servers still can use SDL + option(XASH_SINGLE_BINARY "Don't build game launcher and build engine as executable" ON) + set(XASH_VGUI OFF) # But these dedicated can't use at all, so hardcode it as disabled + set(XASH_MAINUI OFF) # But these dedicated can't use at all, so hardcode it as disabled +else() + option(XASH_SDL "Enable SDL." ON) + option(XASH_SINGLE_BINARY "Don't build game launcher and build engine as executable" OFF) + cmake_dependent_option(XASH_VGUI "Enable VGUI support." ON "NOT XASH_64BIT" OFF) + option(XASH_MAINUI "Build mainui library" ON) # Totally not recommended to disable +endif() + +# Misc +option(XASH_USE_STB_SPRINTF "Use stb_sprintf implementation for sprintf" ON) +option(XASH_NO_INSTALL_RUNSCRIPT "Don't install xash3d.sh" OFF) +option(XASH_NO_INSTALL_VGUI_BIN "Don't bundle proprietary VGUI" OFF) +if(WIN32) # Autodownload for lazy developers using Windows + option(XASH_DOWNLOAD_DEPENDENCIES "Download dependencies automatically, if supported" ON) +else() + option(XASH_DOWNLOAD_DEPENDENCIES "Download dependencies automatically, if supported" OFF) +endif() + +# Installing +if(WIN32) + fwgs_string_option(LIB_INSTALL_DIR "Libraries install directory" ${CMAKE_BINARY_DIR}) + fwgs_string_option(LIB_INSTALL_SUBDIR "Libraries install subdirectory" "") + fwgs_string_option(BIN_INSTALL_DIR "Executables install directory" ${CMAKE_BINARY_DIR}) +else() + fwgs_string_option(LIB_INSTALL_DIR "Libraries install directory" "lib") + fwgs_string_option(LIB_INSTALL_SUBDIR "Libraries install subdirectory" "xash3d") + fwgs_string_option(BIN_INSTALL_DIR "Executables install directory" "bin") +endif() + + +if(NOT XASH_64BIT AND CMAKE_SIZEOF_VOID_P EQUAL 8) + message(FATAL_ERROR "You're building 64 bit Xash3D! Note that there is almost no games compiled for 64-bit. Please, set CMake to build for 32 system. If you still want 64bit build, pass -DXASH_64BIT=1 to CMake") +endif() +if(NOT XASH_LIBDL AND NOT XASH_DLL_LOADER AND NOT XASH_NONSTANDARD_LOAD) + message(FATAL_ERROR "You must enable XASH_LIBDL, XASH_DLL_LOADER or both. Otherwise engine is useless.") +endif() + +if(XASH_64BIT) + message(STATUS "Building for 64 Bit") +else() + message(STATUS "Building for 32 Bit") +endif() + + +# Dependencies +if(XASH_STATIC) + set(XASH_SINGLE_BINARY ON) +endif() + +if(XASH_SAILFISH) + set(XASH_WES ON) +endif() + +if(XASH_NANOGL OR XASH_WES) + set(XASH_GLES ON) +endif() + +fwgs_conditional_subproject(XASH_MAINUI mainui) +fwgs_conditional_subproject("NOT XASH_64BIT AND XASH_VGUI" vgui_support) +fwgs_conditional_subproject("NOT XASH_64BIT AND XASH_DLL_LOADER" loader) +fwgs_conditional_subproject("NOT XASH_SINGLE_BINARY" game_launch) +add_subdirectory(engine) + +if(NOT (WIN32 OR XASH_NO_INSTALL_RUNSCRIPT)) + install(FILES "scripts/xash3d.sh" + DESTINATION "${BIN_INSTALL_DIR}" + RENAME "xash3d" + PERMISSIONS OWNER_READ OWNER_EXECUTE OWNER_WRITE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) +endif() + +if(WIN32) + if(XASH_SINGLE_BINARY) + set_property(DIRECTORY . PROPERTY VS_STARTUP_PROJECT xash) # Engine project + else() + set_property(DIRECTORY . PROPERTY VS_STARTUP_PROJECT xash3d) # Game_launch project + endif() +endif() diff --git a/Projects/Android/jni/src/Xash3D/xash3d/CONTRIBUTING.md b/Projects/Android/jni/src/Xash3D/xash3d/CONTRIBUTING.md new file mode 100644 index 0000000..b6dd026 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/CONTRIBUTING.md @@ -0,0 +1,57 @@ +# Contributing to Xash3D SDL + +Third-party patches for Xash3D SDL are great idea. +But if you want your patch to be accepted, we can give you few guidelines. + +## If you are reporting bugs + +1. Check you are using latest version. You can build latest Xash3D for yourself, look to README.md. +2. Check open issues is your bug is already reported and closed issues if it reported and fixed. Don't send bug if it's already reported. +3. Now you can write bugreport. +4. Write down steps to reproduce bug. +5. Write down OS and architecture you are using. +6. Re-run engine with `-dev 5 -log` arguments, reproduce bug and post engine.log which can be found in your working directory. +7. Attach screenshot if it will help clarify the sitation. +8. Wait for answer. + +## If you are contributing code + +### Which branch? + +* We recommend using `master` branch. But you still can use any of our branches, if they are up-to-date. + +### Third-party libraries + +* Philosophy of any Xash Project by Uncle Mike: don't be bloated. We follow it too. +* There is allowed only these libraries, which is used in Linux GoldSrc version or if there is a REAL reason to use library. + +### Portability level + +* Xash3D have it's own crt library. It's recommended to use it. It most cases it's just a wrappers around standart C library. +* If your feature need platform-specific code, try to implement to every supported OS and every supported compiler. +* You must put it under appopriate macro. It's a rule: Xash3D SDL must compile everywhere. + +| OS | Macro | +| -- | ----- | +| Linux | `defined(__linux__)` | +| FreeBSD | `defined(__FreeBSD__)` | +| NetBSD | `defined(__NetBSD__)` | +| OpenBSD | `defined(__OpenBSD__)` | +| OS X/iOS | `defined(__APPLE__)` and TargetConditionals macros | +| Windows | `defined(_WIN32)` | +| Android | `defined(__ANDROID__)` | +| Emscripten | `defined(__EMSCRIPTEN__)` | + +### Licensing + +* Look COPYING file in repository, if you are unsure. + +### Code style + +* This project uses Quake's C code style convention. +* In short: + * Use spaces in parenthesis. Even in empty. + * Use tabs, not spaces, for indentation. + * Any brace must have it's own line. + * Short blocks, if statements and loops on single line is allowed. +* You can use clang-format here. Config is located in `.clang-format` file in repository's root . diff --git a/Projects/Android/jni/src/Xash3D/xash3d/COPYING b/Projects/Android/jni/src/Xash3D/xash3d/COPYING new file mode 100644 index 0000000..e587591 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/COPYING @@ -0,0 +1,621 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. 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 +them 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 prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. 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. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey 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; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If 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 convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + 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. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +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. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/README.md b/Projects/Android/jni/src/Xash3D/xash3d/README.md new file mode 100644 index 0000000..05a21aa --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/README.md @@ -0,0 +1,25 @@ +# Xash3D FWGS Engine [![Build Status](https://travis-ci.org/FWGS/xash3d.svg)](https://travis-ci.org/FWGS/xash3d) [![Windows Build Status](https://ci.appveyor.com/api/projects/status/github/FWGS/xash3d?svg=true)](https://ci.appveyor.com/project/a1batross/xash3d) + +Latest version of the engine is available at: +https://github.com/FWGS/xash3d + +Orignal project: [Xash3D on ModDB](http://www.moddb.com/engines/xash3d-engine) + +Xash3D Engine is a custom Gold Source engine rewritten from scratch. Xash3D +is compatible with many of the Gold Source games and mods and should be +able to run almost any existing singleplayer Half-Life mod without a hitch. +The multiplayer part is not yet completed, multiplayer mods should work just +fine, but bear in mind that some features may not work at all or work not +exactly the way they do in Gold Source Engine. + +Xash3D FWGS is a fork of Xash3D Engine, which aims on crossplatform and compability +with original Xash3D and Gold Source. + +- [Building and running Xash3D FWGS](https://github.com/FWGS/xash3d/wiki/Building-and-running) +- [Installing and setting up the server on Debian/Ubuntu Linux](https://github.com/FWGS/xash3d/wiki/How-to-set-up-a-Xash3D-Dedicated-Server-on-Debian-Ubuntu-Linux) + +# License + +The library is licensed under GPLv3 license, see [COPYING](https://github.com/FWGS/xash3d/blob/master/COPYING) for details. +CMakeLists.txt files are licensed under MIT license, you will find it's text +in every CMakeLists.txt header. diff --git a/Projects/Android/jni/src/Xash3D/xash3d/appveyor.yml b/Projects/Android/jni/src/Xash3D/xash3d/appveyor.yml new file mode 100644 index 0000000..068e68d --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/appveyor.yml @@ -0,0 +1,36 @@ +version: 1.0.{build} + +branches: + only: + - master + - 0.20.x + +environment: + matrix: + - os: Visual Studio 2013 + GENERATOR_NAME: "Visual Studio 12 2013" + - os: Visual Studio 2015 + GENERATOR_NAME: "Visual Studio 14 2015" +# TODO: Uncomment when AppVeyor will provide XP toolchain for VS2017 +# - os: Visual Studio 2017 +# GENERATOR_NAME: "Visual Studio 15 2017" + +clone_folder: c:\projects\xash\xash3d + +build: + project: INSTALL.vcxproj + verbosity: normal + +configuration: + - Debug + - Release + +before_build: + - git submodule update --init --recursive + - cmake -G "%GENERATOR_NAME%" + +after_build: + # Create archive + - 7z a -t7z xash3d-win.7z -m0=lzma2 -mx=9 -mfb=64 -md=32m -ms=on c:\projects\xash\xash3d\%CONFIGURATION% + - appveyor PushArtifact xash3d-win.7z + - curl --upload-file xash3d-win.7z https://transfer.sh/xash3d-win.7z diff --git a/Projects/Android/jni/src/Xash3D/xash3d/cmake/FWGSLib.cmake b/Projects/Android/jni/src/Xash3D/xash3d/cmake/FWGSLib.cmake new file mode 100644 index 0000000..aca09b4 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/cmake/FWGSLib.cmake @@ -0,0 +1,457 @@ +# +# Copyright (c) 2018 a1batross +# +# 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, and to permit persons to whom the Software is +# 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 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 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 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +option(FWGSLIB_DEBUG "Print debug messages for FWGSLib" OFF) +option(XASH_FORCE_PIE "Force enable -fpie/-fPIC" OFF) # may be required by some systems, although not recommended for i386 + +# /* +# ================ +# fwgs_debug +# ================ +# */ +macro(fwgs_debug) + if(FWGSLIB_DEBUG) + message(${ARGV}) + endif() +endmacro() + +# /* +# ================ +# fwgs_install +# +# Common installation function for FWGS projects +# When using VS it tries to simulate VS behaviour for default installing +# Otherwise *nix-style +# ================ +# */ +macro(fwgs_install tgt) + if(NOT MSVC) + install(TARGETS ${tgt} DESTINATION ${LIB_INSTALL_DIR}/${LIB_INSTALL_SUBDIR} + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE) # chmod 755 + else() + install(TARGETS ${tgt} + CONFIGURATIONS Debug + RUNTIME DESTINATION ${LIB_INSTALL_DIR}/Debug/ + LIBRARY DESTINATION ${LIB_INSTALL_DIR}/Debug/) + install(FILES $ + CONFIGURATIONS Debug + DESTINATION ${LIB_INSTALL_DIR}/Debug/ ) + install(TARGETS ${tgt} + CONFIGURATIONS Release + RUNTIME DESTINATION ${LIB_INSTALL_DIR}/Release/ + LIBRARY DESTINATION ${LIB_INSTALL_DIR}/Release/) + endif() +endmacro() + +# /* +# ================ +# fwgs_conditional_subproject +# +# Default properties for target +# ================ +# */ +macro(fwgs_conditional_subproject cond subproject) + set(TEMP 1) + foreach(d ${cond}) + string(REGEX REPLACE " +" ";" expr "${d}") + if(${expr}) + else() + set(TEMP 0) + endif() + endforeach() + if(TEMP) + add_subdirectory(${subproject}) + endif() +endmacro() + +# /* +# ================ +# fwgs_set_default_properties +# +# Default properties for target +# ================ +# */ +macro(fwgs_set_default_properties tgt) + if( XASH_FORCE_PIE OR (APPLE AND CMAKE_OSX_ARCHITECTURES) OR NOT (ARCH STREQUAL "i386")) + message(STATUS "Enabled PIE for ${tgt}") + set_target_properties(${tgt} PROPERTIES + POSITION_INDEPENDENT_CODE 1) + else() + message(STATUS "Disabled PIE for ${tgt}") + endif() + if(WIN32) + set_target_properties(${tgt} PROPERTIES + PREFIX "") + endif() +endmacro() + +# /* +# =============== +# fwgs_string_option +# +# like option(), but for string +# =============== +# */ +macro(fwgs_string_option name description value) + set(${name} ${value} CACHE STRING ${description}) +endmacro() + +# /* +# ================ +# cond_list_append +# +# Append to list by condition check +# ================ +# */ +macro(cond_list_append arg1 arg2 arg3) + set(TEMP 1) + foreach(d ${arg1}) + string(REGEX REPLACE " +" ";" expr "${d}") + if(${expr}) + else() + set(TEMP 0) + endif() + endforeach() + + if(TEMP) + list(APPEND ${arg2} ${${arg3}}) + endif() +endmacro(cond_list_append) + +macro(fwgs_unpack_file file path) + message(STATUS "Unpacking ${file} to ${CMAKE_BINARY_DIR}/${path}") + execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/${path}) + execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf ${file} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/${path}) +endmacro() + +# HACKHACK: as you can see, other compilers and OSes +# can easily link to vgui library, no matter how it was placed +# On Linux just target_link_libraries will give you a wrong +# binary, which have ABSOLUTE PATH to vgui.so! +# Stupid Linux linkers just check for a path and this may give +# a TWO SAME libraries in memory, which obviously goes to crash engine + +# EXAMPLE(without hack): +# $ LD_LIBRARY_PATH=$(pwd) ldd libvgui_support.so +# /home/user/projects/hlsdk/linux/vgui.so => /home/user/projects/hlsdk/linux/vgui.so (addr) +# With hack: +# $ LD_LIBRARY_PATH=$(pwd) ldd libvgui_support.so +# vgui.so => $(pwd)/vgui.so + +macro(target_link_vgui_hack arg1) + if(WIN32) + target_link_libraries(${arg1} ${VGUI_LIBRARY} ) + elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + target_link_libraries(${arg1} ${VGUI_LIBRARY} ) + elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + add_custom_command(TARGET ${arg1} PRE_LINK COMMAND + ${CMAKE_COMMAND} -E copy ${VGUI_LIBRARY} $) + target_link_libraries(${arg1} -L. -L${arg1}/ -l:vgui.so) + endif() +endmacro() + +# /* +# ================ +# fwgs_link_package +# +# Downloads(if enabled), finds and links library +# ================ +# */ +macro(fwgs_library_dependency tgt pkgname) + if(XASH_DOWNLOAD_DEPENDENCIES AND ${ARGC} GREATER 2) + set(FORCE_DOWNLOAD FALSE) + set(FORCE_UNPACK FALSE) + + # Disabled, due to bugs + # find_package(${pkgname}) # First try to find it in system! + if(NOT ${${pkgname}_FOUND}) # Not found anything, download it + set(FORCE_DOWNLOAD TRUE) + set(FORCE_UNPACK TRUE) + else() + # I see what you did there, CMake Cache! + if(NOT EXISTS ${${pkgname}_LIBRARY}) + # Check if we unpacked + if(NOT EXISTS ${CMAKE_BINARY_DIR}/${pkgname}) + set(FORCE_UNPACK TRUE) + + # Check if we need re-download + if(NOT EXISTS "${CMAKE_BINARY_DIR}/${ARGV3}") + set(FORCE_DOWNLOAD TRUE) + endif() + endif() + endif() + endif() + + if(FORCE_DOWNLOAD) + # Download + message(STATUS "Downloading ${pkgname} dependency for ${tgt} from ${ARGV2} to ${ARGV3}") + file(DOWNLOAD "${ARGV2}" "${CMAKE_BINARY_DIR}/${ARGV3}") + set(FORCE_UNPACK TRUE) # Update directory contents + endif() + + if(FORCE_UNPACK) + fwgs_unpack_file("${CMAKE_BINARY_DIR}/${ARGV3}" "${pkgname}") + endif() + + if(FORCE_DOWNLOAD OR FORCE_UNPACK) + set(${ARGV4} ${CMAKE_BINARY_DIR}/${pkgname}/${ARGV5}) # Pass subdirectory, like VGUI/vgui-dev-master or SDL2/SDL2-2.0.x + find_package(${pkgname} REQUIRED) # Now try it hard + endif() + else() + find_package(${pkgname} REQUIRED) # Find in system + endif() + + include_directories(${${pkgname}_INCLUDE_DIR}) + if(${pkgname} STREQUAL VGUI) #HACKHACK: VGUI link + target_link_vgui_hack(${tgt}) + else() + target_link_libraries(${tgt} ${${pkgname}_LIBRARY}) + endif() +endmacro() + +# /* +# ================ +# fwgs_add_compile_options +# +# add_compile_options, but better with language specification +# ================ +# */ +macro(fwgs_add_compile_options lang) + set(FLAGS ${ARGV}) + list(REMOVE_AT FLAGS 0) # Get rid of language + + string(REPLACE ";" " " FLAGS_STR "${FLAGS}") + + if(${lang} STREQUAL "C") + fwgs_debug(STATUS "Adding ${FLAGS_STR} for both C/CXX") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS_STR}") + set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} ${FLAGS_STR}") + elseif(${lang} STREQUAL "CONLY") + fwgs_debug(STATUS "Adding ${FLAGS_STR} for C ONLY") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS_STR}") + elseif(${lang} STREQUAL "CXX") + fwgs_debug(STATUS "Adding ${FLAGS_STR} for CXX") + set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} ${FLAGS_STR}") + endif() +endmacro() + +# /* +# ================ +# fwgs_fix_default_msvc_settings +# +# Tweaks CMake's default compiler/linker settings to suit Google Test's needs. +# +# This must be a macro(), as inside a function string() can only +# update variables in the function scope. +# ================ +# */ +macro(fwgs_fix_default_msvc_settings) + if (MSVC) + # For MSVC, CMake sets certain flags to defaults we want to override. + # This replacement code is taken from sample in the CMake Wiki at + # http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace. + foreach (flag_var + CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) + # When Google Test is built as a shared library, it should also use + # shared runtime libraries. Otherwise, it may end up with multiple + # copies of runtime library data in different modules, resulting in + # hard-to-find crashes. When it is built as a static library, it is + # preferable to use CRT as static libraries, as we don't have to rely + # on CRT DLLs being available. CMake always defaults to using shared + # CRT libraries, so we override that default here. + string(REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") + endforeach() + endif() +endmacro() + +# /* +# ============== +# xash_link_sdl2 +# +# Download and link SDL2, if supported +# ============== +# */ +macro(xash_link_sdl2 tgt) + if(WIN32) + set(SDL2_VER "2.0.7") + set(SDL2_DEVELPKG "VC.zip") + set(SDL2_SUBDIR "SDL2-${SDL2_VER}") + set(SDL2_ARCHIVE "SDL2.zip") + if(MINGW) + if(XASH_64BIT) + set(SDL2_SUBDIR "SDL2-${SDL2_VER}/x86_64-w64-mingw32") + else() + set(SDL2_SUBDIR "SDL2-${SDL2_VER}/i686-w64-mingw32") + endif() + set(SDL2_DEVELPKG "mingw.tar.gz") + set(SDL2_ARCHIVE "SDL2.tar.gz") + endif() + + set(SDL2_DOWNLOAD_URL "http://libsdl.org/release/SDL2-devel-${SDL2_VER}-${SDL2_DEVELPKG}") + + fwgs_library_dependency(${tgt} SDL2 ${SDL2_DOWNLOAD_URL} ${SDL2_ARCHIVE} SDL2_PATH ${SDL2_SUBDIR}) + else() + # SDL2 doesn't provide dev packages for nonWin32 targets + fwgs_library_dependency(${tgt} SDL2) + endif() +endmacro() + +# Code below is taken from https://github.com/axr/solar-cmake/blob/master/TargetArch.cmake +# Modified by a1batross + +set(archdetect_c_code " +#if defined(__arm__) || defined(__TARGET_ARCH_ARM) + #if defined(__ARM_ARCH_7__) \\ + || defined(__ARM_ARCH_7A__) \\ + || defined(__ARM_ARCH_7R__) \\ + || defined(__ARM_ARCH_7M__) \\ + || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 7) + #error cmake_ARCH armv7 + #elif defined(__ARM_ARCH_6__) \\ + || defined(__ARM_ARCH_6J__) \\ + || defined(__ARM_ARCH_6T2__) \\ + || defined(__ARM_ARCH_6Z__) \\ + || defined(__ARM_ARCH_6K__) \\ + || defined(__ARM_ARCH_6ZK__) \\ + || defined(__ARM_ARCH_6M__) \\ + || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 6) + #error cmake_ARCH armv6 + #elif defined(__ARM_ARCH_5TEJ__) \\ + || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 5) + #error cmake_ARCH armv5 + #else + #error cmake_ARCH arm + #endif +#elif defined(__i386) || defined(__i386__) || defined(_M_IX86) + #error cmake_ARCH i386 +#elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64) + #error cmake_ARCH x86_64 +#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64) + #error cmake_ARCH ia64 +#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \\ + || defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \\ + || defined(_M_MPPC) || defined(_M_PPC) + #if defined(__ppc64__) || defined(__powerpc64__) || defined(__64BIT__) + #error cmake_ARCH ppc64 + #else + #error cmake_ARCH ppc + #endif +#endif + +#error cmake_ARCH unknown +") + +# Set ppc_support to TRUE before including this file or ppc and ppc64 +# will be treated as invalid architectures since they are no longer supported by Apple + +function(target_architecture output_var) + if(APPLE AND CMAKE_OSX_ARCHITECTURES) + # On OS X we use CMAKE_OSX_ARCHITECTURES *if* it was set + # First let's normalize the order of the values + + # Note that it's not possible to compile PowerPC applications if you are using + # the OS X SDK version 10.6 or later - you'll need 10.4/10.5 for that, so we + # disable it by default + # See this page for more information: + # http://stackoverflow.com/questions/5333490/how-can-we-restore-ppc-ppc64-as-well-as-full-10-4-10-5-sdk-support-to-xcode-4 + + # Architecture defaults to i386 or ppc on OS X 10.5 and earlier, depending on the CPU type detected at runtime. + # On OS X 10.6+ the default is x86_64 if the CPU supports it, i386 otherwise. + + foreach(osx_arch ${CMAKE_OSX_ARCHITECTURES}) + if("${osx_arch}" STREQUAL "ppc" AND ppc_support) + set(osx_arch_ppc TRUE) + elseif("${osx_arch}" STREQUAL "i386") + set(osx_arch_i386 TRUE) + elseif("${osx_arch}" STREQUAL "x86_64") + set(osx_arch_x86_64 TRUE) + elseif("${osx_arch}" STREQUAL "ppc64" AND ppc_support) + set(osx_arch_ppc64 TRUE) + else() + message(FATAL_ERROR "Invalid OS X arch name: ${osx_arch}") + endif() + endforeach() + + # Now add all the architectures in our normalized order + if(osx_arch_ppc) + list(APPEND ARCH ppc) + endif() + + if(osx_arch_i386) + list(APPEND ARCH i386) + endif() + + if(osx_arch_x86_64) + list(APPEND ARCH x86_64) + endif() + + if(osx_arch_ppc64) + list(APPEND ARCH ppc64) + endif() + else() + file(WRITE "${CMAKE_BINARY_DIR}/arch.c" "${archdetect_c_code}") + + enable_language(C) + + # Detect the architecture in a rather creative way... + # This compiles a small C program which is a series of ifdefs that selects a + # particular #error preprocessor directive whose message string contains the + # target architecture. The program will always fail to compile (both because + # file is not a valid C program, and obviously because of the presence of the + # #error preprocessor directives... but by exploiting the preprocessor in this + # way, we can detect the correct target architecture even when cross-compiling, + # since the program itself never needs to be run (only the compiler/preprocessor) + try_run( + run_result_unused + compile_result_unused + "${CMAKE_BINARY_DIR}" + "${CMAKE_BINARY_DIR}/arch.c" + COMPILE_OUTPUT_VARIABLE ARCH + CMAKE_FLAGS CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES} + ) + + # Parse the architecture name from the compiler output + string(REGEX MATCH "cmake_ARCH ([a-zA-Z0-9_]+)" ARCH "${ARCH}") + + # Get rid of the value marker leaving just the architecture name + string(REPLACE "cmake_ARCH " "" ARCH "${ARCH}") + + # If we are compiling with an unknown architecture this variable should + # already be set to "unknown" but in the case that it's empty (i.e. due + # to a typo in the code), then set it to unknown + if (NOT ARCH) + set(ARCH unknown) + endif() + endif() + + message(STATUS "Target architecture: ${ARCH}") + set(${output_var} "${ARCH}" PARENT_SCOPE) +endfunction() + +# Set ARCH global variable +target_architecture(ARCH) diff --git a/Projects/Android/jni/src/Xash3D/xash3d/cmake/FindSDL2.cmake b/Projects/Android/jni/src/Xash3D/xash3d/cmake/FindSDL2.cmake new file mode 100644 index 0000000..b90e065 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/cmake/FindSDL2.cmake @@ -0,0 +1,181 @@ +# This module defines +# SDL2_LIBRARY, the name of the library to link against +# SDL2_FOUND, if false, do not try to link to SDL2 +# SDL2_INCLUDE_DIR, where to find SDL.h +# +# This module responds to the the flag: +# SDL2_BUILDING_LIBRARY +# If this is defined, then no SDL2main will be linked in because +# only applications need main(). +# Otherwise, it is assumed you are building an application and this +# module will attempt to locate and set the the proper link flags +# as part of the returned SDL2_LIBRARY variable. +# +# Don't forget to include SDLmain.h and SDLmain.m your project for the +# OS X framework based version. (Other versions link to -lSDL2main which +# this module will try to find on your behalf.) Also for OS X, this +# module will automatically add the -framework Cocoa on your behalf. +# +# +# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration +# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library +# (SDL2.dll, libsdl2.so, SDL2.framework, etc). +# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again. +# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value +# as appropriate. These values are used to generate the final SDL2_LIBRARY +# variable, but when these values are unset, SDL2_LIBRARY does not get created. +# +# +# $SDL2DIR is an environment variable that would +# correspond to the ./configure --prefix=$SDL2DIR +# used in building SDL2. +# l.e.galup 9-20-02 +# +# Modified by Eric Wing. +# Added code to assist with automated building by using environmental variables +# and providing a more controlled/consistent search behavior. +# Added new modifications to recognize OS X frameworks and +# additional Unix paths (FreeBSD, etc). +# Also corrected the header search path to follow "proper" SDL guidelines. +# Added a search for SDL2main which is needed by some platforms. +# Added a search for threads which is needed by some platforms. +# Added needed compile switches for MinGW. +# +# On OSX, this will prefer the Framework version (if found) over others. +# People will have to manually change the cache values of +# SDL2_LIBRARY to override this selection or set the CMake environment +# CMAKE_INCLUDE_PATH to modify the search paths. +# +# Note that the header path has changed from SDL2/SDL.h to just SDL.h +# This needed to change because "proper" SDL convention +# is #include "SDL.h", not . This is done for portability +# reasons because not all systems place things in SDL2/ (see FreeBSD). + +#============================================================================= +# Copyright 2003-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +message(STATUS " ${SDL2_PATH}") + +if(WIN32 AND (NOT SDL2_PATH AND NOT XASH_DOWNLOAD_DEPENDENCIES)) + message(FATAL_ERROR "To find SDL2 correctly, you need to pass SDL2_PATH variable to CMake") +endif() + +set(SDL2_SEARCH_PATHS + ${SDL2_PATH} + ${CMAKE_LIBRARY_PATH} + + # OSX paths + ~/Library/Frameworks + /Library/Frameworks + + # *nix + /usr/local + /usr +) + +find_path(SDL2_INCLUDE_DIR SDL.h + PATH_SUFFIXES include/SDL2 include + PATHS ${SDL2_SEARCH_PATHS} +) + +find_library(SDL2_LIBRARY_TEMP + NAMES SDL2 SDL2.dll + PATH_SUFFIXES + lib + lib/i386-linux-gnu + lib/x86 + PATHS ${SDL2_SEARCH_PATHS} +) + +# Call sdl2-config if SDL2_LIBRARY still not found +if(NOT SDL2_LIBRARY_TEMP AND NOT WIN32) + execute_process(COMMAND sdl2-config --libs + RESULT_VARIABLE SDL2_CONFIG_RETVAL + OUTPUT_VARIABLE SDL2_LIBRARY_TEMP + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(SDL2_CONFIG_RETVAL) + message(SEND_ERROR "sdl2-config --libs returned code ${SDL2_CONFIG_RETVAL}. Check that sdl2-config is working.") + endif() +endif() + +if(SDL2_BUILDING_EXECUTABLE) + if(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") + # Non-OS X framework versions expect you to also dynamically link to + # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms + # seem to provide SDL2main for compatibility even though they don't + # necessarily need it. + find_library(SDL2MAIN_LIBRARY + NAMES SDL2main libSDL2main.a + PATH_SUFFIXES + lib + lib/i386-linux-gnu + lib/x86 + PATHS ${SDL2_SEARCH_PATHS} + ) + endif() +endif() + +# SDL2 may require threads on your system. +# The Apple build may not need an explicit flag because one of the +# frameworks may already provide it. +# But for non-OSX systems, I will use the CMake Threads package. +if(NOT APPLE) + find_package(Threads) +endif() + +# MinGW needs an additional library, mwindows +# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows +# (Actually on second look, I think it only needs one of the m* libraries.) +if(MINGW) + set(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW") +endif() + +if(SDL2_LIBRARY_TEMP) + # For SDL2main + if(SDL2_BUILDING_EXECUTABLE AND SDL2MAIN_LIBRARY) + set(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP}) + endif() + + # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa. + # CMake doesn't display the -framework Cocoa string in the UI even + # though it actually is there if I modify a pre-used variable. + # I think it has something to do with the CACHE STRING. + # So I use a temporary variable until the end so I can set the + # "real" variable in one-shot. + if(APPLE) + set(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa") + endif() + + # For threads, as mentioned Apple doesn't need this. + # In fact, there seems to be a problem if I used the Threads package + # and try using this line, so I'm just skipping it entirely for OS X. + if(NOT APPLE) + set(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT}) + endif() + + # For MinGW library + if(MINGW) + set(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP}) + endif() + + # Set the final string here so the GUI reflects the final state. + set(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found") + # Set the temp variable to INTERNAL so it is not seen in the CMake GUI + set(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "") +endif() + +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args(SDL2 REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR) + +message(STATUS " ${SDL2_LIBRARY}") diff --git a/Projects/Android/jni/src/Xash3D/xash3d/cmake/FindVGUI.cmake b/Projects/Android/jni/src/Xash3D/xash3d/cmake/FindVGUI.cmake new file mode 100644 index 0000000..9f96c02 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/cmake/FindVGUI.cmake @@ -0,0 +1,92 @@ +# +# Copyright (c) 2017 Flying With Gauss +# +# 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, and to permit persons to whom the Software is +# 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 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 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 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +include(FindPackageHandleStandardArgs) + +if(NOT HL_SDK_DIR AND NOT XASH_DOWNLOAD_DEPENDENCIES) + message( FATAL_ERROR "Pass a HL_SDK_DIR variable to CMake to be able use VGUI" ) +endif() + +set(VGUI_SEARCH_PATHS ${HL_SDK_DIR}) + +find_path(VGUI_INCLUDE_DIR + VGUI.h + HINTS $ENV{VGUIDIR} + PATH_SUFFIXES + utils/vgui/include/ # HLSDK + include/ # vgui-dev + PATHS ${VGUI_SEARCH_PATHS} +) + +message(STATUS " ${VGUI_SEARCH_PATHS}") + +if(APPLE) + set(LIBNAMES vgui.dylib) +else() + set(LIBNAMES vgui vgui.so) +endif() + +find_library(VGUI_LIBRARY + NAMES ${LIBNAMES} + HINTS $ENV{VGUIDIR} + PATH_SUFFIXES + games/lib/xash3d # libvgui debian package + lib/xash3d # Maybe installed in system? + xash3d/ # Maybe installed in system? [2] + utils/vgui/lib/win32_vc6 # Win32 VC6 + linux/ # Linux + linux/release # OSX + lib/win32_vc6 # vgui-dev Win32 VC6 + lib/ # vgui-dev Linux & OSX + PATHS ${VGUI_SEARCH_PATHS} +) + +# HACKHACK: as you can see, other compilers and OSes +# can easily link to vgui library, no matter how it was placed +# On Linux just target_link_libraries will give you a wrong +# binary, which have ABSOLUTE PATH to vgui.so! +# Stupid Linux linkers just check for a path and this may give +# a TWO SAME libraries in memory, which obviously goes to crash engine + +# EXAMPLE(without hack): +# $ LD_LIBRARY_PATH=$(pwd) ldd libvgui_support.so +# /home/user/projects/hlsdk/linux/vgui.so => /home/user/projects/hlsdk/linux/vgui.so (addr) +# With hack: +# $ LD_LIBRARY_PATH=$(pwd) ldd libvgui_support.so +# vgui.so => $(pwd)/vgui.so + +macro(target_link_vgui_hack arg1) + if(WIN32) + target_link_libraries(${arg1} ${VGUI_LIBRARY} ) + elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + target_link_libraries(${arg1} ${VGUI_LIBRARY} ) + elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + add_custom_command(TARGET ${arg1} PRE_LINK COMMAND + ${CMAKE_COMMAND} -E copy ${VGUI_LIBRARY} $) + target_link_libraries(${arg1} -L. -L${arg1}/ -l:vgui.so) + endif() +endmacro() + +find_package_handle_standard_args(VGUI REQUIRED_VARS VGUI_LIBRARY VGUI_INCLUDE_DIR) + +message(STATUS " ${VGUI_LIBRARY}") + diff --git a/Projects/Android/jni/src/Xash3D/xash3d/cmake/VSForceXPToolchain.cmake b/Projects/Android/jni/src/Xash3D/xash3d/cmake/VSForceXPToolchain.cmake new file mode 100644 index 0000000..e78fb0a --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/cmake/VSForceXPToolchain.cmake @@ -0,0 +1,29 @@ +if(WIN32) + # Windows XP compatible platform toolset. Must be set before project(), + # otherwise change of CMAKE_*_TOOLSET will take no effect. + # We get VS version from the generator name because neither MSVC* nor other + # variables that describe the compiler aren't available before project(). + if ("${CMAKE_GENERATOR}" MATCHES "Visual Studio ([0-9]+)") + if(${CMAKE_MATCH_1} LESS 11) + # Nothing. Older VS does support XP by default. + elseif(${CMAKE_MATCH_1} EQUAL 11) + # Visual Studio 11 2012 + set(CMAKE_GENERATOR_TOOLSET "v110_xp" CACHE STRING "CMAKE_GENERATOR_TOOLSET" FORCE) + set(CMAK_VS_PLATFORM_TOOLSET "v110_xp" CACHE STRING "CMAKE_VS_PLATFORM_TOOLSET" FORCE) + elseif (${CMAKE_MATCH_1} EQUAL 12) + # Visual Studio 12 2013 + set(CMAKE_GENERATOR_TOOLSET "v120_xp" CACHE STRING "CMAKE_GENERATOR_TOOLSET" FORCE) + set(CMAKE_VS_PLATFORM_TOOLSET "v120_xp" CACHE STRING "CMAKE_VS_PLATFORM_TOOLSET" FORCE) + elseif (${CMAKE_MATCH_1} EQUAL 14) + # Visual Studio 14 2015 + set(CMAKE_GENERATOR_TOOLSET "v140_xp" CACHE STRING "CMAKE_GENERATOR_TOOLSET" FORCE) + set(CMAKE_VS_PLATFORM_TOOLSET "v140_xp" CACHE STRING "CMAKE_VS_PLATFORM_TOOLSET" FORCE) + elseif (${CMAKE_MATCH_1} EQUAL 15) + # Visual Studio 15 2017 + set(CMAKE_GENERATOR_TOOLSET "v141_xp" CACHE STRING "CMAKE_GENERATOR_TOOLSET" FORCE) + set(CMAKE_VS_PLATFORM_TOOLSET "v141_xp" CACHE STRING "CMAKE_VS_PLATFORM_TOOLSET" FORCE) + else() + message(WARNING "WARNING: You maybe building without Windows XP compability. See which toolchain version Visual Studio provides, and say cmake to use it: cmake -G \"Visual Studio XX\" -T \"vXXX_xp\"") + endif() + endif() +endif() diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/backends.h b/Projects/Android/jni/src/Xash3D/xash3d/common/backends.h new file mode 100644 index 0000000..bd0d776 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/backends.h @@ -0,0 +1,47 @@ +/* +backends.h - backend macro definations +Copyright (C) 2016 Mittorn + +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 3 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. +*/ + + +#ifndef BACKENDS_H +#define BACKENDS_H + +// video backends (XASH_VIDEO) +#define VIDEO_NULL 0 +#define VIDEO_SDL 1 +#define VIDEO_ANDROID 2 + +// audio backends (XASH_SOUND) +#define SOUND_NULL 0 +#define SOUND_SDL 1 +#define SOUND_OPENSLES 2 + +// crash handler (XASH_CRASHHANDLER) +#define CRASHHANDLER_NULL 0 +#define CRASHHANDLER_UCONTEXT 1 +#define CRASHHANDLER_DBGHELP 2 +#define CRASHHANDLER_WIN32 3 + +// input (XASH_INPUT) +#define INPUT_NULL 0 +#define INPUT_SDL 1 +#define INPUT_ANDROID 2 + +// timer (XASH_TIMER) +#define TIMER_NULL 0 // not used +#define TIMER_SDL 1 +#define TIMER_LINUX 2 +#define TIMER_WIN32 3 + +#endif /* BACKENDS_H */ diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/beamdef.h b/Projects/Android/jni/src/Xash3D/xash3d/common/beamdef.h new file mode 100644 index 0000000..542e2e5 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/beamdef.h @@ -0,0 +1,59 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef BEAMDEF_H +#define BEAMDEF_H + +#define FBEAM_STARTENTITY 0x00000001 +#define FBEAM_ENDENTITY 0x00000002 +#define FBEAM_FADEIN 0x00000004 +#define FBEAM_FADEOUT 0x00000008 +#define FBEAM_SINENOISE 0x00000010 +#define FBEAM_SOLID 0x00000020 +#define FBEAM_SHADEIN 0x00000040 +#define FBEAM_SHADEOUT 0x00000080 +#define FBEAM_STARTVISIBLE 0x10000000 // Has this client actually seen this beam's start entity yet? +#define FBEAM_ENDVISIBLE 0x20000000 // Has this client actually seen this beam's end entity yet? +#define FBEAM_ISACTIVE 0x40000000 +#define FBEAM_FOREVER 0x80000000 + +struct beam_s +{ + BEAM *next; + int type; + int flags; + vec3_t source; + vec3_t target; + vec3_t delta; + float t; // 0 .. 1 over lifetime of beam + float freq; + float die; + float width; + float amplitude; + float r, g, b; + float brightness; + float speed; + float frameRate; + float frame; + int segments; + int startEntity; + int endEntity; + int modelIndex; + int frameCount; + struct model_s *pFollowModel; + struct particle_s *particles; +}; + +#endif//BEAMDEF_H diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/bspfile.h b/Projects/Android/jni/src/Xash3D/xash3d/common/bspfile.h new file mode 100644 index 0000000..955925b --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/bspfile.h @@ -0,0 +1,247 @@ +/* +bspfile.h - BSP format included q1, hl1 support +Copyright (C) 2010 Uncle Mike + +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 3 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. +*/ + +#ifndef BSPFILE_H +#define BSPFILE_H + +/* +============================================================================== + +BRUSH MODELS + +.bsp contain level static geometry with including PVS and lightning info +============================================================================== +*/ + +// header +#define Q1BSP_VERSION 29 // quake1 regular version (beta is 28) +#define HLBSP_VERSION 30 // half-life regular version +#define XTBSP_VERSION 31 // extended lightmaps and expanded clipnodes limit + +#define IDEXTRAHEADER (('H'<<24)+('S'<<16)+('A'<<8)+'X') // little-endian "XASH" +#define EXTRA_VERSION 2 // because version 1 was occupied by old versions of XashXT + +#define DELUXEMAP_VERSION 1 +#define IDDELUXEMAPHEADER (('T'<<24)+('I'<<16)+('L'<<8)+'Q') // little-endian "QLIT" + +// worldcraft predefined angles +#define ANGLE_UP -1 +#define ANGLE_DOWN -2 + +// bmodel limits +#define MAX_MAP_HULLS 4 // MAX_HULLS + +#define SURF_NOCULL BIT( 0 ) // two-sided polygon (e.g. 'water4b') +#define SURF_PLANEBACK BIT( 1 ) // plane should be negated +#define SURF_DRAWSKY BIT( 2 ) // sky surface +#define SURF_WATERCSG BIT( 3 ) // culled by csg (was SURF_DRAWSPRITE) +#define SURF_DRAWTURB BIT( 4 ) // warp surface +#define SURF_DRAWTILED BIT( 5 ) // face without lighmap +#define SURF_CONVEYOR BIT( 6 ) // scrolled texture (was SURF_DRAWBACKGROUND) +#define SURF_UNDERWATER BIT( 7 ) // caustics +#define SURF_TRANSPARENT BIT( 8 ) // it's a transparent texture (was SURF_DONTWARP) + +#define SURF_REFLECT BIT( 31 ) // reflect surface (mirror) + +// lightstyle management +#define LM_STYLES 4 // MAXLIGHTMAPS +#define LS_NORMAL 0x00 +#define LS_UNUSED 0xFE +#define LS_NONE 0xFF + +#define MAX_MAP_MODELS 1024 // can be increased up to 2048 if needed +#define MAX_MAP_BRUSHES 32768 // unsigned short limit +#define MAX_MAP_ENTITIES 8192 // can be increased up to 32768 if needed +#define MAX_MAP_ENTSTRING 0x80000 // 512 kB should be enough +#define MAX_MAP_PLANES 65536 // can be increased without problems +#define MAX_MAP_NODES 32767 // because negative shorts are leafs +#define MAX_MAP_CLIPNODES 32767 // because negative shorts are contents +#define MAX_MAP_LEAFS 32767 // signed short limit +#define MAX_MAP_VERTS 65535 // unsigned short limit +#define MAX_MAP_FACES 65535 // unsigned short limit +#define MAX_MAP_MARKSURFACES 65535 // unsigned short limit +#define MAX_MAP_TEXINFO MAX_MAP_FACES // in theory each face may have personal texinfo +#define MAX_MAP_EDGES 0x100000 // can be increased but not needed +#define MAX_MAP_SURFEDGES 0x200000 // can be increased but not needed +#define MAX_MAP_TEXTURES 2048 // can be increased but not needed +#define MAX_MAP_MIPTEX 0x2000000 // 32 Mb internal textures data +#define MAX_MAP_LIGHTING 0x2000000 // 32 Mb lightmap raw data (can contain deluxemaps) +#define MAX_MAP_VISIBILITY 0x800000 // 8 Mb visdata + +// quake lump ordering +#define LUMP_ENTITIES 0 +#define LUMP_PLANES 1 +#define LUMP_TEXTURES 2 // internal textures +#define LUMP_VERTEXES 3 +#define LUMP_VISIBILITY 4 +#define LUMP_NODES 5 +#define LUMP_TEXINFO 6 +#define LUMP_FACES 7 +#define LUMP_LIGHTING 8 +#define LUMP_CLIPNODES 9 +#define LUMP_LEAFS 10 +#define LUMP_MARKSURFACES 11 +#define LUMP_EDGES 12 +#define LUMP_SURFEDGES 13 +#define LUMP_MODELS 14 // internal submodels +#define HEADER_LUMPS 15 + +// version 31 +#define LUMP_CLIPNODES2 15 // hull0 goes into LUMP_NODES, hull1 goes into LUMP_CLIPNODES, +#define LUMP_CLIPNODES3 16 // hull2 goes into LUMP_CLIPNODES2, hull3 goes into LUMP_CLIPNODES3 + +#define HEADER_LUMPS_31 17 + +#define LUMP_FACES_EXTRADATA 0 // extension of dface_t +#define LUMP_VERTS_EXTRADATA 1 // extension of dvertex_t +#define LUMP_CUBEMAPS 2 // cubemap description + +#define EXTRA_LUMPS 8 // g-cont. just for future expansions + +// texture flags +#define TEX_SPECIAL BIT( 0 ) // sky or slime, no lightmap or 256 subdivision + +// ambient sound types +enum +{ + AMBIENT_WATER = 0, // waterfall + AMBIENT_SKY, // wind + AMBIENT_SLIME, // never used in quake + AMBIENT_LAVA, // never used in quake + NUM_AMBIENTS, // automatic ambient sounds +}; + +// +// BSP File Structures +// + +typedef struct +{ + int fileofs; + int filelen; +} dlump_t; + +typedef struct +{ + int version; + dlump_t lumps[HEADER_LUMPS_31]; +} dheader31_t; + +typedef struct +{ + int id; // must be little endian XASH + int version; + dlump_t lumps[EXTRA_LUMPS]; +} dextrahdr_t; + +typedef struct +{ + int version; + dlump_t lumps[HEADER_LUMPS]; +} dheader_t; + +typedef struct +{ + vec3_t mins; + vec3_t maxs; + vec3_t origin; // for sounds or lights + int headnode[MAX_MAP_HULLS]; + int visleafs; // not including the solid leaf 0 + int firstface; + int numfaces; +} dmodel_t; + +typedef struct +{ + int nummiptex; + int dataofs[4]; // [nummiptex] +} dmiptexlump_t; + +typedef struct +{ + vec3_t point; +} dvertex_t; + +typedef struct +{ + vec3_t normal; + float dist; + int type; // PLANE_X - PLANE_ANYZ ? +} dplane_t; + +typedef struct +{ + int planenum; + short children[2]; // negative numbers are -(leafs + 1), not nodes + short mins[3]; // for sphere culling + short maxs[3]; + word firstface; + word numfaces; // counting both sides +} dnode_t; + +// leaf 0 is the generic CONTENTS_SOLID leaf, used for all solid areas +// all other leafs need visibility info +typedef struct +{ + int contents; + int visofs; // -1 = no visibility info + + short mins[3]; // for frustum culling + short maxs[3]; + word firstmarksurface; + word nummarksurfaces; + + // automatic ambient sounds + byte ambient_level[NUM_AMBIENTS]; // ambient sound level (0 - 255) +} dleaf_t; + +typedef struct +{ + int planenum; + short children[2]; // negative numbers are contents +} dclipnode_t; + +typedef struct +{ + float vecs[2][4]; // texmatrix [s/t][xyz offset] + int miptex; + int flags; +} dtexinfo_t; + +typedef word dmarkface_t; // leaf marksurfaces indexes +typedef int dsurfedge_t; // map surfedges + +// NOTE: that edge 0 is never used, because negative edge nums +// are used for counterclockwise use of the edge in a face +typedef struct +{ + word v[2]; // vertex numbers +} dedge_t; + +typedef struct +{ + word planenum; + short side; + + int firstedge; // we must support > 64k edges + short numedges; + short texinfo; + + // lighting info + byte styles[LM_STYLES]; + int lightofs; // start of [numstyles*surfsize] samples +} dface_t; + +#endif//BSPFILE_H diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/cl_entity.h b/Projects/Android/jni/src/Xash3D/xash3d/common/cl_entity.h new file mode 100644 index 0000000..02f84e3 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/cl_entity.h @@ -0,0 +1,105 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef CL_ENTITY_H +#define CL_ENTITY_H + +typedef struct efrag_s +{ + struct mleaf_s *leaf; + struct efrag_s *leafnext; + struct cl_entity_s *entity; + struct efrag_s *entnext; +} efrag_t; + +typedef struct +{ + byte mouthopen; // 0 = mouth closed, 255 = mouth agape + byte sndcount; // counter for running average + int sndavg; // running average +} mouth_t; + +typedef struct +{ + float prevanimtime; + float sequencetime; + byte prevseqblending[2]; + vec3_t prevorigin; + vec3_t prevangles; + + int prevsequence; + float prevframe; + + byte prevcontroller[4]; + byte prevblending[2]; +} latchedvars_t; + +typedef struct +{ + // Time stamp for this movement + float animtime; + + vec3_t origin; + vec3_t angles; +} position_history_t; + +typedef struct cl_entity_s cl_entity_t; + +#define HISTORY_MAX 64 // Must be power of 2 +#define HISTORY_MASK ( HISTORY_MAX - 1 ) + +#include "entity_state.h" +#include "event_args.h" + +struct cl_entity_s +{ + int index; // Index into cl_entities ( should match actual slot, but not necessarily ) + qboolean player; // True if this entity is a "player" + + entity_state_t baseline; // The original state from which to delta during an uncompressed message + entity_state_t prevstate; // The state information from the penultimate message received from the server + entity_state_t curstate; // The state information from the last message received from server + + int current_position; // Last received history update index + position_history_t ph[HISTORY_MAX]; // History of position and angle updates for this player + + mouth_t mouth; // For synchronizing mouth movements. + + latchedvars_t latched; // Variables used by studio model rendering routines + + // Information based on interplocation, extrapolation, prediction, or just copied from last msg received. + // + float lastmove; + + // Actual render position and angles + vec3_t origin; + vec3_t angles; + + // Attachment points + vec3_t attachment[4]; + + // Other entity local information + int trivial_accept; + + struct model_s *model; // cl.model_precache[ curstate.modelindes ]; all visible entities have a model + struct efrag_s *efrag; // linked list of efrags + struct mnode_s *topnode; // for bmodels, first world node that splits bmodel, or NULL if not split + + float syncbase; // for client-side animations -- used by obsolete alias animation system, remove? + int visframe; // last frame this entity was found in an active leaf + colorVec cvFloorColor; +}; + +#endif//CL_ENTITY_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/com_model.h b/Projects/Android/jni/src/Xash3D/xash3d/common/com_model.h new file mode 100644 index 0000000..731fb55 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/com_model.h @@ -0,0 +1,412 @@ +/* +com_model.h - cient model structures +Copyright (C) 2010 Uncle Mike + +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 3 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. +*/ + +#ifndef COM_MODEL_H +#define COM_MODEL_H + +#include "bspfile.h" // we need some declarations from it + +/* +============================================================================== + + ENGINE MODEL FORMAT +============================================================================== +*/ +#define STUDIO_RENDER 1 +#define STUDIO_EVENTS 2 + +#define ZISCALE ((float)0x8000) + +#define MIPLEVELS 4 +#define VERTEXSIZE 7 +#define MAXLIGHTMAPS 4 +#define NUM_AMBIENTS 4 // automatic ambient sounds + +// model types +typedef enum +{ + mod_bad = -1, + mod_brush, + mod_sprite, + mod_alias, + mod_studio +} modtype_t; + +typedef struct mplane_s +{ + vec3_t normal; + float dist; + byte type; // for fast side tests + byte signbits; // signx + (signy<<1) + (signz<<1) + byte pad[2]; +} mplane_t; + +typedef struct +{ + vec3_t position; +} mvertex_t; + +typedef struct +{ + unsigned short v[2]; + unsigned int cachededgeoffset; +} medge_t; + +typedef struct texture_s +{ + char name[16]; + unsigned int width, height; + int gl_texturenum; + struct msurface_s *texturechain; // for gl_texsort drawing + int anim_total; // total tenths in sequence ( 0 = no) + int anim_min, anim_max; // time for this frame min <=time< max + struct texture_s *anim_next; // in the animation sequence + struct texture_s *alternate_anims; // bmodels in frame 1 use these + unsigned short fb_texturenum; // auto-luma texturenum + unsigned short dt_texturenum; // detail-texture binding + unsigned int unused[2]; // reserved + unsigned short unused1; + unsigned short nm_texturenum; +} texture_t; + +typedef struct +{ + float vecs[2][4]; // [s/t] unit vectors in world space. + // [i][3] is the s/t offset relative to the origin. + // s or t = dot( 3Dpoint, vecs[i] ) + vecs[i][3] + float mipadjust; // mipmap limits for very small surfaces + texture_t *texture; + int flags; // sky or slime, no lightmap or 256 subdivision +} mtexinfo_t; + +// 73 bytes per VBO vertex +// FIXME: align to 32 bytes +typedef struct glvert_s +{ + vec3_t vertex; // position + vec3_t normal; // normal + vec2_t stcoord; // ST texture coords + vec2_t lmcoord; // ST lightmap coords + vec2_t sccoord; // ST scissor coords (decals only) - for normalmap coords migration + vec3_t tangent; // tangent + vec3_t binormal; // binormal + byte color[4]; // colors per vertex +} glvert_t; + +typedef struct glpoly_s +{ + struct glpoly_s *next; + struct glpoly_s *chain; + int numverts; + int flags; // for SURF_UNDERWATER + float verts[4][VERTEXSIZE]; // variable sized (xyz s1t1 s2t2) +} glpoly_t; + +typedef struct mnode_s +{ +// common with leaf + int contents; // 0, to differentiate from leafs + int visframe; // node needs to be traversed if current + + float minmaxs[6]; // for bounding box culling + struct mnode_s *parent; + +// node specific + mplane_t *plane; + struct mnode_s *children[2]; + + unsigned short firstsurface; + unsigned short numsurfaces; +} mnode_t; + +typedef struct msurface_s msurface_t; +typedef struct decal_s decal_t; + +// JAY: Compress this as much as possible +struct decal_s +{ + decal_t *pnext; // linked list for each surface + msurface_t *psurface; // Surface id for persistence / unlinking + float dx; // local texture coordinates + float dy; // + float scale; // Pixel scale + short texture; // Decal texture + byte flags; // Decal flags FDECAL_* + short entityIndex; // Entity this is attached to +// Xash3D added + vec3_t position; // location of the decal center in world space. + vec3_t saxis; // direction of the s axis in world space + struct msurfmesh_s *mesh; // decal mesh in local space + int reserved[4]; // for future expansions +}; + +typedef struct mleaf_s +{ +// common with node + int contents; + int visframe; // node needs to be traversed if current + + float minmaxs[6]; // for bounding box culling + + struct mnode_s *parent; +// leaf specific + byte *compressed_vis; + struct efrag_s *efrags; + + msurface_t **firstmarksurface; + int nummarksurfaces; + byte *compressed_pas; + byte ambient_sound_level[NUM_AMBIENTS]; + +} mleaf_t; + +struct msurface_s +{ + int visframe; // should be drawn when node is crossed + + mplane_t *plane; // pointer to shared plane + int flags; // see SURF_ #defines + + int firstedge; // look up in model->surfedges[], negative numbers + int numedges; // are backwards edges + + short texturemins[2]; + short extents[2]; + + int light_s, light_t; // gl lightmap coordinates + + glpoly_t *polys; // multiple if warped + struct msurface_s *texturechain; + + mtexinfo_t *texinfo; + + // lighting info + int dlightframe; // last frame the surface was checked by an animated light + int dlightbits; // dynamically generated. Indicates if the surface illumination + // is modified by an animated light. + + int lightmaptexturenum; + byte styles[MAXLIGHTMAPS]; + int cached_light[MAXLIGHTMAPS]; // values currently used in lightmap + struct msurface_s *lightmapchain; // for new dlights rendering (was cached_dlight) + + color24 *samples; // note: this is the actual lightmap data for this surface + decal_t *pdecals; +}; + +typedef struct msurfmesh_s +{ + unsigned short numVerts; + unsigned short numElems; // ~ 20 000 vertex per one surface. Should be enough + unsigned int startVert; // user-variable. may be used for construct world single-VBO + unsigned int startElem; // user-variable. may be used for construct world single-VBO + + glvert_t *verts; // vertexes array + unsigned short *elems; // indices + + struct msurface_s *surf; // pointer to parent surface. Just for consistency + struct msurfmesh_s *next; // temporary chain of subdivided surfaces +} msurfmesh_t; + +// surface extradata stored in cache.data for all brushmodels +typedef struct mextrasurf_s +{ + vec3_t mins, maxs; + vec3_t origin; // surface origin + msurfmesh_t *mesh; // VBO\VA ready surface mesh. Not used by engine but can be used by mod-makers + + int dlight_s, dlight_t; // gl lightmap coordinates for dynamic lightmaps + + int mirrortexturenum; // gl texnum + float mirrormatrix[4][4]; + struct mextrasurf_s *mirrorchain; // for gl_texsort drawing + struct mextrasurf_s *detailchain; // for detail textures drawing + color24 *deluxemap; // note: this is the actual deluxemap data for this surface + + int reserved[32]; // just for future expansions or mod-makers +} mextrasurf_t; + +typedef struct hull_s +{ + dclipnode_t *clipnodes; + mplane_t *planes; + int firstclipnode; + int lastclipnode; + vec3_t clip_mins; + vec3_t clip_maxs; +} hull_t; + +#ifndef CACHE_USER +#define CACHE_USER +typedef struct cache_user_s +{ + void *data; // extradata +} cache_user_t; +#endif + +typedef struct model_s +{ + char name[64]; // model name + qboolean needload; // bmodels and sprites don't cache normally + + // shared modelinfo + modtype_t type; // model type + int numframes; // sprite's framecount + byte *mempool; // private mempool (was synctype) + int flags; // hl compatibility + +// +// volume occupied by the model +// + vec3_t mins, maxs; // bounding box at angles '0 0 0' + float radius; + + // brush model + int firstmodelsurface; + int nummodelsurfaces; + + int numsubmodels; + dmodel_t *submodels; // or studio animations + + int numplanes; + mplane_t *planes; + + int numleafs; // number of visible leafs, not counting 0 + mleaf_t *leafs; + + int numvertexes; + mvertex_t *vertexes; + + int numedges; + medge_t *edges; + + int numnodes; + mnode_t *nodes; + + int numtexinfo; + mtexinfo_t *texinfo; + + int numsurfaces; + msurface_t *surfaces; + + int numsurfedges; + int *surfedges; + + int numclipnodes; + dclipnode_t *clipnodes; + + int nummarksurfaces; + msurface_t **marksurfaces; + + hull_t hulls[MAX_MAP_HULLS]; + + int numtextures; + texture_t **textures; + + byte *visdata; + + color24 *lightdata; + char *entities; +// +// additional model data +// + cache_user_t cache; // only access through Mod_Extradata +} model_t; + +typedef struct alight_s +{ + int ambientlight; // clip at 128 + int shadelight; // clip at 192 - ambientlight + vec3_t color; + float *plightvec; +} alight_t; + +typedef struct auxvert_s +{ + float fv[3]; // viewspace x, y +} auxvert_t; + +#define MAX_SCOREBOARDNAME 32 +#define MAX_INFO_STRING 256 + +#include "custom.h" + +typedef struct player_info_s +{ + int userid; // User id on server + char userinfo[MAX_INFO_STRING]; // User info string + char name[MAX_SCOREBOARDNAME]; // Name (extracted from userinfo) + int spectator; // Spectator or not, unused + + int ping; + int packet_loss; + + // skin information + char model[64]; + int topcolor; + int bottomcolor; + + // last frame rendered + int renderframe; + + // Gait frame estimation + int gaitsequence; + float gaitframe; + float gaityaw; + vec3_t prevgaitorigin; + + customization_t customdata; +} player_info_t; + +// +// sprite representation in memory +// +typedef enum { SPR_SINGLE = 0, SPR_GROUP, SPR_ANGLED } spriteframetype_t; + +typedef struct mspriteframe_s +{ + int width; + int height; + float up, down, left, right; + int gl_texturenum; +} mspriteframe_t; + +typedef struct +{ + int numframes; + float *intervals; + mspriteframe_t *frames[1]; +} mspritegroup_t; + +typedef struct +{ + spriteframetype_t type; + mspriteframe_t *frameptr; +} mspriteframedesc_t; + +typedef struct +{ + short type; + short texFormat; + int maxwidth; + int maxheight; + int numframes; + int radius; + int facecull; + int synctype; + mspriteframedesc_t frames[1]; +} msprite_t; + +#endif//COM_MODEL_H diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/con_nprint.h b/Projects/Android/jni/src/Xash3D/xash3d/common/con_nprint.h new file mode 100644 index 0000000..5d87c76 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/con_nprint.h @@ -0,0 +1,25 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef CON_NPRINT_H +#define CON_NPRINT_H + +typedef struct con_nprint_s +{ + int index; // Row # + float time_to_live; // # of seconds before it dissappears + float color[3]; // RGB colors ( 0.0 -> 1.0 scale ) +} con_nprint_t; + +#endif//CON_NPRINT_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/const.h b/Projects/Android/jni/src/Xash3D/xash3d/common/const.h new file mode 100644 index 0000000..a684cbf --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/const.h @@ -0,0 +1,783 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef CONST_H +#define CONST_H +// +// Constants shared by the engine and dlls +// This header file included by engine files and DLL files. +// Most came from server.h + +// edict->flags +#define FL_FLY (1U << 0) // Changes the SV_Movestep() behavior to not need to be on ground +#define FL_SWIM (1U << 1) // Changes the SV_Movestep() behavior to not need to be on ground (but stay in water) +#define FL_CONVEYOR (1U << 2) +#define FL_CLIENT (1U << 3) +#define FL_INWATER (1U << 4) +#define FL_MONSTER (1U << 5) +#define FL_GODMODE (1U << 6) +#define FL_NOTARGET (1U << 7) +#define FL_SKIPLOCALHOST (1U << 8) // Don't send entity to local host, it's predicting this entity itself +#define FL_ONGROUND (1U << 9) // At rest / on the ground +#define FL_PARTIALGROUND (1U << 10) // not all corners are valid +#define FL_WATERJUMP (1U << 11) // player jumping out of water +#define FL_FROZEN (1U << 12) // Player is frozen for 3rd person camera +#define FL_FAKECLIENT (1U << 13) // JAC: fake client, simulated server side; don't send network messages to them +#define FL_DUCKING (1U << 14) // Player flag -- Player is fully crouched +#define FL_FLOAT (1U << 15) // Apply floating force to this entity when in water +#define FL_GRAPHED (1U << 16) // worldgraph has this ent listed as something that blocks a connection + +// UNDONE: Do we need these? +#define FL_IMMUNE_WATER (1U << 17) +#define FL_IMMUNE_SLIME (1U << 18) +#define FL_IMMUNE_LAVA (1U << 19) + +#define FL_PROXY (1U << 20) // This is a spectator proxy +#define FL_ALWAYSTHINK (1U << 21) // Brush model flag -- call think every frame regardless of nextthink - ltime (for constantly changing velocity/path) +#define FL_BASEVELOCITY (1U << 22) // Base velocity has been applied this frame (used to convert base velocity into momentum) +#define FL_MONSTERCLIP (1U << 23) // Only collide in with monsters who have FL_MONSTERCLIP set +#define FL_ONTRAIN (1U << 24) // Player is _controlling_ a train, so movement commands should be ignored on client during prediction. +#define FL_WORLDBRUSH (1U << 25) // Not moveable/removeable brush entity (really part of the world, but represented as an entity for transparency or something) +#define FL_SPECTATOR (1U << 26) // This client is a spectator, don't run touch functions, etc. +#define FL_CUSTOMENTITY (1U << 29) // This is a custom entity +#define FL_KILLME (1U << 30) // This entity is marked for death -- This allows the engine to kill ents at the appropriate time +#define FL_DORMANT (1U << 31) // Entity is dormant, no updates to client + +// Goes into globalvars_t.trace_flags +#define FTRACE_SIMPLEBOX (1U << 0) // Traceline with a simple box +#define FTRACE_IGNORE_GLASS (1U << 1) // traceline will be ignored entities with rendermode != kRenderNormal + +// walkmove modes +#define WALKMOVE_NORMAL 0 // normal walkmove +#define WALKMOVE_WORLDONLY 1 // doesn't hit ANY entities, no matter what the solid type +#define WALKMOVE_CHECKONLY 2 // move, but don't touch triggers + +// edict->movetype values +#define MOVETYPE_NONE 0 // never moves +//#define MOVETYPE_ANGLENOCLIP 1 +//#define MOVETYPE_ANGLECLIP 2 +#define MOVETYPE_WALK 3 // Player only - moving on the ground +#define MOVETYPE_STEP 4 // gravity, special edge handling -- monsters use this +#define MOVETYPE_FLY 5 // No gravity, but still collides with stuff +#define MOVETYPE_TOSS 6 // gravity/collisions +#define MOVETYPE_PUSH 7 // no clip to world, push and crush +#define MOVETYPE_NOCLIP 8 // No gravity, no collisions, still do velocity/avelocity +#define MOVETYPE_FLYMISSILE 9 // extra size to monsters +#define MOVETYPE_BOUNCE 10 // Just like Toss, but reflect velocity when contacting surfaces +#define MOVETYPE_BOUNCEMISSILE 11 // bounce w/o gravity +#define MOVETYPE_FOLLOW 12 // track movement of aiment +#define MOVETYPE_PUSHSTEP 13 // BSP model that needs physics/world collisions (uses nearest hull for world collision) +#define MOVETYPE_COMPOUND 14 // glue two entities together (simple movewith) + +// edict->solid values +// NOTE: Some movetypes will cause collisions independent of SOLID_NOT/SOLID_TRIGGER when the entity moves +// SOLID only effects OTHER entities colliding with this one when they move - UGH! +#define SOLID_NOT 0 // no interaction with other objects +#define SOLID_TRIGGER 1 // touch on edge, but not blocking +#define SOLID_BBOX 2 // touch on edge, block +#define SOLID_SLIDEBOX 3 // touch on edge, but not an onground +#define SOLID_BSP 4 // bsp clip, touch on edge, block +#define SOLID_CUSTOM 5 // call external callbacks for tracing + +// edict->deadflag values +#define DEAD_NO 0 // alive +#define DEAD_DYING 1 // playing death animation or still falling off of a ledge waiting to hit ground +#define DEAD_DEAD 2 // dead. lying still. +#define DEAD_RESPAWNABLE 3 +#define DEAD_DISCARDBODY 4 + +#define DAMAGE_NO 0 +#define DAMAGE_YES 1 +#define DAMAGE_AIM 2 + +// entity effects +#define EF_BRIGHTFIELD 1 // swirling cloud of particles +#define EF_MUZZLEFLASH 2 // single frame ELIGHT on entity attachment 0 +#define EF_BRIGHTLIGHT 4 // DLIGHT centered at entity origin +#define EF_DIMLIGHT 8 // player flashlight +#define EF_INVLIGHT 16 // get lighting from ceiling +#define EF_NOINTERP 32 // don't interpolate the next frame +#define EF_LIGHT 64 // rocket flare glow sprite +#define EF_NODRAW 128 // don't draw entity + +// From HLSDK 2.4 +#define EF_NIGHTVISION 256 // player nightvision +#define EF_SNIPERLASER 512 // sniper laser effect +#define EF_FIBERCAMERA 1024 // fiber camera + +#define EF_NOREFLECT (1U << 24) // Entity won't reflecting in mirrors +#define EF_REFLECTONLY (1U << 25) // Entity will be drawing only in mirrors +#define EF_NOWATERCSG (1U << 26) // Do not remove sides for func_water entity +#define EF_FULLBRIGHT (1U << 27) // Just get fullbright +#define EF_NOSHADOW (1U << 28) // ignore shadow for this entity +#define EF_MERGE_VISIBILITY (1U << 29) // this entity allowed to merge vis (e.g. env_sky or portal camera) +#define EF_REQUEST_PHS (1U << 30) // This entity requested phs bitvector instead of pvsbitvector in AddToFullPack calls +// g-cont. one reserved bit here for me + +// entity flags +#define EFLAG_SLERP 1 // do studio interpolation of this entity + +// +// temp entity events +// +#define TE_BEAMPOINTS 0 // beam effect between two points +// coord coord coord (start position) +// coord coord coord (end position) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_BEAMENTPOINT 1 // beam effect between point and entity +// short (start entity) +// coord coord coord (end position) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_GUNSHOT 2 // particle effect plus ricochet sound +// coord coord coord (position) + +#define TE_EXPLOSION 3 // additive sprite, 2 dynamic lights, flickering particles, explosion sound, move vertically 8 pps +// coord coord coord (position) +// short (sprite index) +// byte (scale in 0.1's) +// byte (framerate) +// byte (flags) +// +// The Explosion effect has some flags to control performance/aesthetic features: +#define TE_EXPLFLAG_NONE 0 // all flags clear makes default Half-Life explosion +#define TE_EXPLFLAG_NOADDITIVE 1 // sprite will be drawn opaque (ensure that the sprite you send is a non-additive sprite) +#define TE_EXPLFLAG_NODLIGHTS 2 // do not render dynamic lights +#define TE_EXPLFLAG_NOSOUND 4 // do not play client explosion sound +#define TE_EXPLFLAG_NOPARTICLES 8 // do not draw particles +#define TE_EXPLFLAG_DRAWALPHA 16 // sprite will be drawn alpha +#define TE_EXPLFLAG_ROTATE 32 // rotate the sprite randomly + +#define TE_TAREXPLOSION 4 // Quake1 "tarbaby" explosion with sound +// coord coord coord (position) + +#define TE_SMOKE 5 // alphablend sprite, move vertically 30 pps +// coord coord coord (position) +// short (sprite index) +// byte (scale in 0.1's) +// byte (framerate) + +#define TE_TRACER 6 // tracer effect from point to point +// coord, coord, coord (start) +// coord, coord, coord (end) + +#define TE_LIGHTNING 7 // TE_BEAMPOINTS with simplified parameters +// coord, coord, coord (start) +// coord, coord, coord (end) +// byte (life in 0.1's) +// byte (width in 0.1's) +// byte (amplitude in 0.01's) +// short (sprite model index) + +#define TE_BEAMENTS 8 +// short (start entity) +// short (end entity) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_SPARKS 9 // 8 random tracers with gravity, ricochet sprite +// coord coord coord (position) + +#define TE_LAVASPLASH 10 // Quake1 lava splash +// coord coord coord (position) + +#define TE_TELEPORT 11 // Quake1 teleport splash +// coord coord coord (position) + +#define TE_EXPLOSION2 12 // Quake1 colormaped (base palette) particle explosion with sound +// coord coord coord (position) +// byte (starting color) +// byte (num colors) + +#define TE_BSPDECAL 13 // Decal from the .BSP file +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// short (texture index of precached decal texture name) +// short (entity index) +// [optional - only included if previous short is non-zero (not the world)] short (index of model of above entity) + +#define TE_IMPLOSION 14 // tracers moving toward a point +// coord, coord, coord (position) +// byte (radius) +// byte (count) +// byte (life in 0.1's) + +#define TE_SPRITETRAIL 15 // line of moving glow sprites with gravity, fadeout, and collisions +// coord, coord, coord (start) +// coord, coord, coord (end) +// short (sprite index) +// byte (count) +// byte (life in 0.1's) +// byte (scale in 0.1's) +// byte (velocity along vector in 10's) +// byte (randomness of velocity in 10's) + +#define TE_BEAM 16 // obsolete + +#define TE_SPRITE 17 // additive sprite, plays 1 cycle +// coord, coord, coord (position) +// short (sprite index) +// byte (scale in 0.1's) +// byte (brightness) + +#define TE_BEAMSPRITE 18 // A beam with a sprite at the end +// coord, coord, coord (start position) +// coord, coord, coord (end position) +// short (beam sprite index) +// short (end sprite index) + +#define TE_BEAMTORUS 19 // screen aligned beam ring, expands to max radius over lifetime +// coord coord coord (center position) +// coord coord coord (axis and radius) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_BEAMDISK 20 // disk that expands to max radius over lifetime +// coord coord coord (center position) +// coord coord coord (axis and radius) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_BEAMCYLINDER 21 // cylinder that expands to max radius over lifetime +// coord coord coord (center position) +// coord coord coord (axis and radius) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_BEAMFOLLOW 22 // create a line of decaying beam segments until entity stops moving +// short (entity:attachment to follow) +// short (sprite index) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte,byte,byte (color) +// byte (brightness) + +#define TE_GLOWSPRITE 23 +// coord, coord, coord (pos) short (model index) byte (scale / 10) + +#define TE_BEAMRING 24 // connect a beam ring to two entities +// short (start entity) +// short (end entity) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_STREAK_SPLASH 25 // oriented shower of tracers +// coord coord coord (start position) +// coord coord coord (direction vector) +// byte (color) +// short (count) +// short (base speed) +// short (random velocity) + +#define TE_BEAMHOSE 26 // obsolete + +#define TE_DLIGHT 27 // dynamic light, effect world, minor entity effect +// coord, coord, coord (pos) +// byte (radius in 10's) +// byte byte byte (color) +// byte (life in 10's) +// byte (decay rate in 10's) + +#define TE_ELIGHT 28 // point entity light, no world effect +// short (entity:attachment to follow) +// coord coord coord (initial position) +// coord (radius) +// byte byte byte (color) +// byte (life in 0.1's) +// coord (decay rate) + +#define TE_TEXTMESSAGE 29 +// short 1.2.13 x (-1 = center) +// short 1.2.13 y (-1 = center) +// byte Effect 0 = fade in/fade out +// 1 is flickery credits +// 2 is write out (training room) +// 4 bytes r,g,b,a color1 (text color) +// 4 bytes r,g,b,a color2 (effect color) +// ushort 8.8 fadein time +// ushort 8.8 fadeout time +// ushort 8.8 hold time +// optional ushort 8.8 fxtime (time the highlight lags behing the leading text in effect 2) +// string text message (512 chars max sz string) +#define TE_LINE 30 +// coord, coord, coord startpos +// coord, coord, coord endpos +// short life in 0.1 s +// 3 bytes r, g, b + +#define TE_BOX 31 +// coord, coord, coord boxmins +// coord, coord, coord boxmaxs +// short life in 0.1 s +// 3 bytes r, g, b + +#define TE_KILLBEAM 99 // kill all beams attached to entity +// short (entity) + +#define TE_LARGEFUNNEL 100 +// coord coord coord (funnel position) +// short (sprite index) +// short (flags) + +#define TE_BLOODSTREAM 101 // particle spray +// coord coord coord (start position) +// coord coord coord (spray vector) +// byte (color) +// byte (speed) + +#define TE_SHOWLINE 102 // line of particles every 5 units, dies in 30 seconds +// coord coord coord (start position) +// coord coord coord (end position) + +#define TE_BLOOD 103 // particle spray +// coord coord coord (start position) +// coord coord coord (spray vector) +// byte (color) +// byte (speed) + +#define TE_DECAL 104 // Decal applied to a brush entity (not the world) +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// byte (texture index of precached decal texture name) +// short (entity index) + +#define TE_FIZZ 105 // create alpha sprites inside of entity, float upwards +// short (entity) +// short (sprite index) +// byte (density) + +#define TE_MODEL 106 // create a moving model that bounces and makes a sound when it hits +// coord, coord, coord (position) +// coord, coord, coord (velocity) +// angle (initial yaw) +// short (model index) +// byte (bounce sound type) +// byte (life in 0.1's) + +#define TE_EXPLODEMODEL 107 // spherical shower of models, picks from set +// coord, coord, coord (origin) +// coord (velocity) +// short (model index) +// short (count) +// byte (life in 0.1's) + +#define TE_BREAKMODEL 108 // box of models or sprites +// coord, coord, coord (position) +// coord, coord, coord (size) +// coord, coord, coord (velocity) +// byte (random velocity in 10's) +// short (sprite or model index) +// byte (count) +// byte (life in 0.1 secs) +// byte (flags) + +#define TE_GUNSHOTDECAL 109 // decal and ricochet sound +// coord, coord, coord (position) +// short (entity index???) +// byte (decal???) + +#define TE_SPRITE_SPRAY 110 // spay of alpha sprites +// coord, coord, coord (position) +// coord, coord, coord (velocity) +// short (sprite index) +// byte (count) +// byte (speed) +// byte (noise) + +#define TE_ARMOR_RICOCHET 111 // quick spark sprite, client ricochet sound. +// coord, coord, coord (position) +// byte (scale in 0.1's) + +#define TE_PLAYERDECAL 112 // ??? +// byte (playerindex) +// coord, coord, coord (position) +// short (entity???) +// byte (decal number???) +// [optional] short (model index???) + +#define TE_BUBBLES 113 // create alpha sprites inside of box, float upwards +// coord, coord, coord (min start position) +// coord, coord, coord (max start position) +// coord (float height) +// short (model index) +// byte (count) +// coord (speed) + +#define TE_BUBBLETRAIL 114 // create alpha sprites along a line, float upwards +// coord, coord, coord (min start position) +// coord, coord, coord (max start position) +// coord (float height) +// short (model index) +// byte (count) +// coord (speed) + +#define TE_BLOODSPRITE 115 // spray of opaque sprite1's that fall, single sprite2 for 1..2 secs (this is a high-priority tent) +// coord, coord, coord (position) +// short (sprite1 index) +// short (sprite2 index) +// byte (color) +// byte (scale) + +#define TE_WORLDDECAL 116 // Decal applied to the world brush +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// byte (texture index of precached decal texture name) + +#define TE_WORLDDECALHIGH 117 // Decal (with texture index > 256) applied to world brush +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// byte (texture index of precached decal texture name - 256) + +#define TE_DECALHIGH 118 // Same as TE_DECAL, but the texture index was greater than 256 +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// byte (texture index of precached decal texture name - 256) +// short (entity index) + +#define TE_PROJECTILE 119 // Makes a projectile (like a nail) (this is a high-priority tent) +// coord, coord, coord (position) +// coord, coord, coord (velocity) +// short (modelindex) +// byte (life) +// byte (owner) projectile won't collide with owner (if owner == 0, projectile will hit any client). + +#define TE_SPRAY 120 // Throws a shower of sprites or models +// coord, coord, coord (position) +// coord, coord, coord (direction) +// short (modelindex) +// byte (count) +// byte (speed) +// byte (noise) +// byte (rendermode) + +#define TE_PLAYERSPRITES 121 // sprites emit from a player's bounding box (ONLY use for players!) +// byte (playernum) +// short (sprite modelindex) +// byte (count) +// byte (variance) (0 = no variance in size) (10 = 10% variance in size) + +#define TE_PARTICLEBURST 122 // very similar to lavasplash. +// coord (origin) +// short (radius) +// byte (particle color) +// byte (duration * 10) (will be randomized a bit) + +#define TE_FIREFIELD 123 // makes a field of fire. +// coord (origin) +// short (radius) (fire is made in a square around origin. -radius, -radius to radius, radius) +// short (modelindex) +// byte (count) +// byte (flags) +// byte (duration (in seconds) * 10) (will be randomized a bit) +// +// to keep network traffic low, this message has associated flags that fit into a byte: +#define TEFIRE_FLAG_ALLFLOAT 1 // all sprites will drift upwards as they animate +#define TEFIRE_FLAG_SOMEFLOAT 2 // some of the sprites will drift upwards. (50% chance) +#define TEFIRE_FLAG_LOOP 4 // if set, sprite plays at 15 fps, otherwise plays at whatever rate stretches the animation over the sprite's duration. +#define TEFIRE_FLAG_ALPHA 8 // if set, sprite is rendered alpha blended at 50% else, opaque +#define TEFIRE_FLAG_PLANAR 16 // if set, all fire sprites have same initial Z instead of randomly filling a cube. + +// From HLSDK 2.4 +#define TEFIRE_FLAG_ADDITIVE 32 // if set, sprite is rendered non-opaque with additive + +#define TE_PLAYERATTACHMENT 124 // attaches a TENT to a player (this is a high-priority tent) +// byte (entity index of player) +// coord (vertical offset) ( attachment origin.z = player origin.z + vertical offset ) +// short (model index) +// short (life * 10 ); + +#define TE_KILLPLAYERATTACHMENTS 125 // will expire all TENTS attached to a player. +// byte (entity index of player) + +#define TE_MULTIGUNSHOT 126 // much more compact shotgun message +// This message is used to make a client approximate a 'spray' of gunfire. +// Any weapon that fires more than one bullet per frame and fires in a bit of a spread is +// a good candidate for MULTIGUNSHOT use. (shotguns) +// +// NOTE: This effect makes the client do traces for each bullet, these client traces ignore +// entities that have studio models.Traces are 4096 long. +// +// coord (origin) +// coord (origin) +// coord (origin) +// coord (direction) +// coord (direction) +// coord (direction) +// coord (x noise * 100) +// coord (y noise * 100) +// byte (count) +// byte (bullethole decal texture index) + +#define TE_USERTRACER 127 // larger message than the standard tracer, but allows some customization. +// coord (origin) +// coord (origin) +// coord (origin) +// coord (velocity) +// coord (velocity) +// coord (velocity) +// byte ( life * 10 ) +// byte ( color ) this is an index into an array of color vectors in the engine. (0 - ) +// byte ( length * 10 ) + +#define MSG_BROADCAST 0 // unreliable to all +#define MSG_ONE 1 // reliable to one (msg_entity) +#define MSG_ALL 2 // reliable to all +#define MSG_INIT 3 // write to the init string +#define MSG_PVS 4 // Ents in PVS of org +#define MSG_PAS 5 // Ents in PAS of org +#define MSG_PVS_R 6 // Reliable to PVS +#define MSG_PAS_R 7 // Reliable to PAS +#define MSG_ONE_UNRELIABLE 8 // Send to one client, but don't put in reliable stream, put in unreliable datagram ( could be dropped ) +#define MSG_SPEC 9 // Sends to all spectator proxies + +// contents of a spot in the world +#define CONTENTS_EMPTY -1 +#define CONTENTS_SOLID -2 +#define CONTENTS_WATER -3 +#define CONTENTS_SLIME -4 +#define CONTENTS_LAVA -5 +#define CONTENTS_SKY -6 +// These additional contents constants are defined in bspfile.h +#define CONTENTS_ORIGIN -7 // removed at csg time +#define CONTENTS_CLIP -8 // changed to contents_solid +#define CONTENTS_CURRENT_0 -9 +#define CONTENTS_CURRENT_90 -10 +#define CONTENTS_CURRENT_180 -11 +#define CONTENTS_CURRENT_270 -12 +#define CONTENTS_CURRENT_UP -13 +#define CONTENTS_CURRENT_DOWN -14 +#define CONTENTS_TRANSLUCENT -15 + +#define CONTENTS_LADDER -16 + +#define CONTENT_FLYFIELD -17 +#define CONTENT_GRAVITY_FLYFIELD -18 +#define CONTENT_FOG -19 + +#define CONTENT_EMPTY -1 +#define CONTENT_SOLID -2 +#define CONTENT_WATER -3 +#define CONTENT_SLIME -4 +#define CONTENT_LAVA -5 +#define CONTENT_SKY -6 + +// channels +#define CHAN_AUTO 0 +#define CHAN_WEAPON 1 +#define CHAN_VOICE 2 +#define CHAN_ITEM 3 +#define CHAN_BODY 4 +#define CHAN_STREAM 5 // allocate stream channel from the static or dynamic area +#define CHAN_STATIC 6 // allocate channel from the static area +#define CHAN_NETWORKVOICE_BASE 7 // voice data coming across the network +#define CHAN_NETWORKVOICE_END 500 // network voice data reserves slots (CHAN_NETWORKVOICE_BASE through CHAN_NETWORKVOICE_END). + +// From HLSDK 2.4 +#define CHAN_BOT 501 // channel used for bot chatter + +// attenuation values +#define ATTN_NONE 0 +#define ATTN_NORM (float)0.8 +#define ATTN_IDLE (float)2 +#define ATTN_STATIC (float)1.25 + +// pitch values +#define PITCH_NORM 100 // non-pitch shifted +#define PITCH_LOW 95 // other values are possible - 0-255, where 255 is very high +#define PITCH_HIGH 120 + +// volume values +#define VOL_NORM 1.0 + +// plats +#define PLAT_LOW_TRIGGER 1 + +// Trains +#define SF_TRAIN_WAIT_RETRIGGER 1 +#define SF_TRAIN_START_ON 4 // Train is initially moving +#define SF_TRAIN_PASSABLE 8 // Train is not solid -- used to make water trains + +// buttons +#define IN_ATTACK (1U << 0) +#define IN_JUMP (1U << 1) +#define IN_DUCK (1U << 2) +#define IN_FORWARD (1U << 3) +#define IN_BACK (1U << 4) +#define IN_USE (1U << 5) +#define IN_CANCEL (1U << 6) +#define IN_LEFT (1U << 7) +#define IN_RIGHT (1U << 8) +#define IN_MOVELEFT (1U << 9) +#define IN_MOVERIGHT (1U << 10) +#define IN_ATTACK2 (1U << 11) +#define IN_RUN (1U << 12) +#define IN_RELOAD (1U << 13) +#define IN_ALT1 (1U << 14) +#define IN_SCORE (1U << 15) // Used by client.dll for when scoreboard is held down + +// Break Model Defines +#define BREAK_TYPEMASK 0x4F +#define BREAK_GLASS 0x01 +#define BREAK_METAL 0x02 +#define BREAK_FLESH 0x04 +#define BREAK_WOOD 0x08 +#define BREAK_SMOKE 0x10 +#define BREAK_TRANS 0x20 +#define BREAK_CONCRETE 0x40 +#define BREAK_2 0x80 + +// Colliding temp entity sounds +#define BOUNCE_GLASS BREAK_GLASS +#define BOUNCE_METAL BREAK_METAL +#define BOUNCE_FLESH BREAK_FLESH +#define BOUNCE_WOOD BREAK_WOOD +#define BOUNCE_SHRAP 0x10 +#define BOUNCE_SHELL 0x20 +#define BOUNCE_CONCRETE BREAK_CONCRETE +#define BOUNCE_SHOTSHELL 0x80 + +// Temp entity bounce sound types +#define TE_BOUNCE_NULL 0 +#define TE_BOUNCE_SHELL 1 +#define TE_BOUNCE_SHOTSHELL 2 + +// Rendering constants +enum +{ + kRenderNormal, // src + kRenderTransColor, // c*a+dest*(1-a) + kRenderTransTexture, // src*a+dest*(1-a) + kRenderGlow, // src*a+dest -- No Z buffer checks + kRenderTransAlpha, // src*srca+dest*(1-srca) + kRenderTransAdd, // src*a+dest + kRenderWorldGlow // Same as kRenderGlow but not fixed size in screen space +}; + +enum +{ + kRenderFxNone = 0, + kRenderFxPulseSlow, + kRenderFxPulseFast, + kRenderFxPulseSlowWide, + kRenderFxPulseFastWide, + kRenderFxFadeSlow, + kRenderFxFadeFast, + kRenderFxSolidSlow, + kRenderFxSolidFast, + kRenderFxStrobeSlow, + kRenderFxStrobeFast, + kRenderFxStrobeFaster, + kRenderFxFlickerSlow, + kRenderFxFlickerFast, + kRenderFxNoDissipation, + kRenderFxDistort, // Distort/scale/translate flicker + kRenderFxHologram, // kRenderFxDistort + distance fade + kRenderFxDeadPlayer, // kRenderAmt is the player index + kRenderFxExplode, // Scale up really big! + kRenderFxGlowShell, // Glowing Shell + kRenderFxClampMinScale, // Keep this sprite from getting very small (SPRITES only!) + kRenderFxLightMultiplier //CTM !!!CZERO added to tell the studiorender that the value in iuser2 is a lightmultiplier +}; + +#include "xash3d_types.h" + +typedef int func_t; +typedef int string_t; + +typedef unsigned short word; + + +typedef struct +{ + byte r, g, b; +} color24; + +typedef struct +{ + unsigned r, g, b, a; +} colorVec; + +typedef struct link_s +{ + struct link_s *prev, *next; +} link_t; + +typedef struct edict_s edict_t; + +typedef struct +{ + vec3_t normal; + float dist; +} plane_t; + +typedef struct +{ + qboolean allsolid; // if true, plane is not valid + qboolean startsolid; // if true, the initial point was in a solid area + qboolean inopen, inwater; + float fraction; // time completed, 1.0 = didn't hit anything + vec3_t endpos; // final position + plane_t plane; // surface normal at impact + edict_t *ent; // entity the surface is on + int hitgroup; // 0 == generic, non zero is specific body part +} trace_t; + +#endif//CONST_H diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/cvardef.h b/Projects/Android/jni/src/Xash3D/xash3d/common/cvardef.h new file mode 100644 index 0000000..d092082 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/cvardef.h @@ -0,0 +1,38 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef CVARDEF_H +#define CVARDEF_H + +#define FCVAR_ARCHIVE (1<<0) // set to cause it to be saved to vars.rc +#define FCVAR_USERINFO (1<<1) // changes the client's info string +#define FCVAR_SERVER (1<<2) // notifies players when changed +#define FCVAR_EXTDLL (1<<3) // defined by external DLL +#define FCVAR_CLIENTDLL (1<<4) // defined by the client dll +#define FCVAR_PROTECTED (1<<5) // It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value +#define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server. +#define FCVAR_PRINTABLEONLY (1<<7) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ). +#define FCVAR_UNLOGGED (1<<8) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log +#define FCVAR_NOEXTRAWHITESPACE (1<<9) // strip trailing/leading white space from this cvar + +typedef struct cvar_s +{ + char *name; + char *string; + int flags; + float value; + struct cvar_s *next; +} cvar_t; + +#endif//CVARDEF_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/defaults.h b/Projects/Android/jni/src/Xash3D/xash3d/common/defaults.h new file mode 100644 index 0000000..57f37e2 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/defaults.h @@ -0,0 +1,165 @@ +/* +defaults.h - set up default configuration +Copyright (C) 2016 Mittorn + +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 3 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. +*/ + +#ifndef DEFAULTS_H +#define DEFAULTS_H + +#include "backends.h" + +/* +=================================================================== + +SETUP BACKENDS DEFINITIONS + +=================================================================== +*/ +#ifndef XASH_DEDICATED + + #ifdef XASH_SDL + + // by default, use SDL subsystems + #ifndef XASH_VIDEO + #define XASH_VIDEO VIDEO_SDL + #endif // XASH_VIDEO + + #ifndef XASH_TIMER + #define XASH_TIMER TIMER_SDL + #endif + + #ifndef XASH_INPUT + #define XASH_INPUT INPUT_SDL + #endif + + #ifndef XASH_SOUND + #define XASH_SOUND SOUND_SDL + #endif + + #endif //XASH_SDL + + #if defined __ANDROID__ && !defined XASH_SDL + + #ifndef XASH_VIDEO + #define XASH_VIDEO VIDEO_ANDROID + #endif + + #ifndef XASH_TIMER + #define XASH_TIMER TIMER_LINUX + #endif + + #ifndef XASH_INPUT + #define XASH_INPUT INPUT_ANDROID + #endif + + #ifndef XASH_SOUND + #define XASH_SOUND SOUND_OPENSLES + #endif + #endif // android case + +#endif // XASH_DEDICATED + +// select crashhandler based on defines +#ifndef XASH_CRASHHANDLER + #ifdef _WIN32 + #ifdef DBGHELP + #define XASH_CRASHHANDLER CRASHHANDLER_DBGHELP + #endif + #elif defined CRASHHANDLER + #define XASH_CRASHHANDLER CRASHHANDLER_UCONTEXT + #else + #define XASH_CRASHHANDLER CRASHHANDLER_NULL + #endif +#endif + +// no timer - no xash +#ifndef XASH_TIMER + #ifdef _WIN32 + #define XASH_TIMER TIMER_WIN32 + #else + #define XASH_TIMER TIMER_LINUX + #endif +#endif + +// +// fallback to NULL +// +#ifndef XASH_VIDEO + #define XASH_VIDEO VIDEO_NULL +#endif + +#ifndef XASH_SOUND + #define XASH_SOUND SOUND_NULL +#endif + +#ifndef XASH_INPUT + #define XASH_INPUT INPUT_NULL +#endif + +/* +========================================================================= + +Default build-depended cvar and constant values + +========================================================================= +*/ + +#if defined __ANDROID__ || TARGET_OS_IPHONE || defined __SAILFISH__ + #define DEFAULT_TOUCH_ENABLE "1" + #define DEFAULT_M_IGNORE "1" +#else + #define DEFAULT_TOUCH_ENABLE "0" + #define DEFAULT_M_IGNORE "0" +#endif + +#if defined __ANDROID__ || TARGET_OS_IPHONE || defined __SAILFISH__ || defined __EMSCRIPTEN__ +// this means that libraries are provided with engine, but not in game data +// You need add library loading code to library.c when adding new platform +#define XASH_INTERNAL_GAMELIBS +#endif + +#if defined XASH_GL4ES || XASH_NANOGL || defined XASH_WES || defined XASH_REGAL +#ifndef XASH_GLES +#define XASH_GLES +#endif // XASH_GLES +#ifndef XASH_GL_STATIC +#define XASH_GL_STATIC +#endif // XASH_GL_STATIC +#endif // XASH_GL4ES || XASH_NANOGL || XASH_WES || XASH_REGAL + +#define DEFAULT_PRIMARY_MASTER "ms.xash.su:27010" +#define DEFAULT_SECONDARY_MASTER "ms2.xash.su:27010" +// Set ForceSimulating to 1 by default for dedicated, because AMXModX timers require this +// TODO: enable simulating for any server? +#ifdef XASH_DEDICATED + #define DEFAULT_SV_FORCESIMULATING "1" +#else + #define DEFAULT_SV_FORCESIMULATING "0" +#endif + +// allow override for developer/debug builds +#ifndef DEFAULT_DEV + #define DEFAULT_DEV 0 +#endif + +#ifndef DEFAULT_FULLSCREEN +#define DEFAULT_FULLSCREEN 1 +#endif + +#if TARGET_OS_IPHONE + #define DEFAULT_CON_MAXFRAC "0.5" +#else + #define DEFAULT_CON_MAXFRAC "1" +#endif + +#endif // DEFAULTS_H diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/demo_api.h b/Projects/Android/jni/src/Xash3D/xash3d/common/demo_api.h new file mode 100644 index 0000000..fa89bbe --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/demo_api.h @@ -0,0 +1,27 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef DEMO_API_H +#define DEMO_API_H + +typedef struct demo_api_s +{ + int (*IsRecording)( void ); + int (*IsPlayingback)( void ); + int (*IsTimeDemo)( void ); + void (*WriteBuffer)( int size, unsigned char *buffer ); +} demo_api_t; + +#endif//DEMO_API_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/dlight.h b/Projects/Android/jni/src/Xash3D/xash3d/common/dlight.h new file mode 100644 index 0000000..b139d58 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/dlight.h @@ -0,0 +1,31 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef DLIGHT_H +#define DLIGHT_H + +typedef struct dlight_s +{ + vec3_t origin; + float radius; + color24 color; + float die; // stop lighting after this time + float decay; // drop this each second + float minlight; // don't add when contributing less + int key; + qboolean dark; // subtracts light instead of adding +} dlight_t; + +#endif//DLIGHT_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/engine_features.h b/Projects/Android/jni/src/Xash3D/xash3d/common/engine_features.h new file mode 100644 index 0000000..13b0f90 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/engine_features.h @@ -0,0 +1,30 @@ +/* +engine_features.h - engine features that can be enabled by mod-maker request +Copyright (C) 2012 Uncle Mike + +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 3 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. +*/ + +#ifndef FEATURES_H +#define FEATURES_H + +// list of engine features that can be enabled through callback SV_CheckFeatures +#define ENGINE_WRITE_LARGE_COORD (1<<0) // replace standard message WRITE_COORD with big message for support more than 8192 units in world +#define ENGINE_BUILD_SURFMESHES (1<<1) // bulid surface meshes that goes into mextrasurf->mesh. For mod makers and custom renderers +#define ENGINE_LOAD_DELUXEDATA (1<<2) // loading deluxemap for map (if present) +#define ENGINE_TRANSFORM_TRACE_AABB (1<<3) // transform trace bbox into local space of rotating bmodels +#define ENGINE_LARGE_LIGHTMAPS (1<<4) // change lightmap sizes from 128x128 to 256x256 +#define ENGINE_COMPENSATE_QUAKE_BUG (1<<5) // compensate stupid quake bug (inverse pitch) for mods where this bug is fixed +#define ENGINE_DISABLE_HDTEXTURES (1<<6) // disable support of HD-textures in case custom renderer have separate way to load them +#define ENGINE_COMPUTE_STUDIO_LERP (1<<7) // enable MOVETYPE_STEP lerping back in engine +#define ENGINE_THREADED_MAIN_LOOP (1<<8) // simulate dedictated thread for main engine loop (prefomance) + +#endif//FEATURES_H diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/entity_state.h b/Projects/Android/jni/src/Xash3D/xash3d/common/entity_state.h new file mode 100644 index 0000000..ef5448f --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/entity_state.h @@ -0,0 +1,186 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef ENTITY_STATE_H +#define ENTITY_STATE_H + +// For entityType below +#define ENTITY_NORMAL (1<<0) +#define ENTITY_BEAM (1<<1) + +// Entity state is used for the baseline and for delta compression of a packet of +// entities that is sent to a client. +typedef struct entity_state_s entity_state_t; + +struct entity_state_s +{ +// Fields which are filled in by routines outside of delta compression + int entityType; + // Index into cl_entities array for this entity. + int number; + float msg_time; + + // Message number last time the player/entity state was updated. + int messagenum; + +// Fields which can be transitted and reconstructed over the network stream + vec3_t origin; + vec3_t angles; + + int modelindex; + int sequence; + float frame; + int colormap; + short skin; + short solid; + int effects; + float scale; + byte eflags; + + // Render information + int rendermode; + int renderamt; + color24 rendercolor; + int renderfx; + + int movetype; + float animtime; + float framerate; + int body; + byte controller[4]; + byte blending[4]; + vec3_t velocity; + + // Send bbox down to client for use during prediction. + vec3_t mins; + vec3_t maxs; + + int aiment; + // If owned by a player, the index of that player ( for projectiles ). + int owner; + + // Friction, for prediction. + float friction; + // Gravity multiplier + float gravity; + +// PLAYER SPECIFIC + int team; + int playerclass; + int health; + qboolean spectator; + int weaponmodel; + int gaitsequence; + // If standing on conveyor, e.g. + vec3_t basevelocity; + // Use the crouched hull, or the regular player hull. + int usehull; + // Latched buttons last time state updated. + int oldbuttons; + // -1 = in air, else pmove entity number + int onground; + int iStepLeft; + // How fast we are falling + float flFallVelocity; + + float fov; + int weaponanim; + + // Parametric movement overrides + vec3_t startpos; + vec3_t endpos; + float impacttime; + float starttime; + + // For mods + int iuser1; + int iuser2; + int iuser3; + int iuser4; + float fuser1; + float fuser2; + float fuser3; + float fuser4; + vec3_t vuser1; + vec3_t vuser2; + vec3_t vuser3; + vec3_t vuser4; +}; + +#include "pm_info.h" + +typedef struct clientdata_s +{ + vec3_t origin; + vec3_t velocity; + + int viewmodel; + vec3_t punchangle; + int flags; + int waterlevel; + int watertype; + vec3_t view_ofs; + float health; + + int bInDuck; + int weapons; // remove? + + int flTimeStepSound; + int flDuckTime; + int flSwimTime; + int waterjumptime; + + float maxspeed; + + float fov; + int weaponanim; + + int m_iId; + int ammo_shells; + int ammo_nails; + int ammo_cells; + int ammo_rockets; + float m_flNextAttack; + + int tfstate; + int pushmsec; + int deadflag; + char physinfo[MAX_PHYSINFO_STRING]; + + // For mods + int iuser1; + int iuser2; + int iuser3; + int iuser4; + float fuser1; + float fuser2; + float fuser3; + float fuser4; + vec3_t vuser1; + vec3_t vuser2; + vec3_t vuser3; + vec3_t vuser4; + +} clientdata_t; + +#include "weaponinfo.h" + +typedef struct local_state_s +{ + entity_state_t playerstate; + clientdata_t client; + weapon_data_t weapondata[64]; +} local_state_t; + +#endif//ENTITY_STATE_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/entity_types.h b/Projects/Android/jni/src/Xash3D/xash3d/common/entity_types.h new file mode 100644 index 0000000..25a8fce --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/entity_types.h @@ -0,0 +1,25 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef ENTITY_TYPES_H +#define ENTITY_TYPES_H + +#define ET_NORMAL 0 +#define ET_PLAYER 1 +#define ET_TEMPENTITY 2 +#define ET_BEAM 3 +#define ET_FRAGMENTED 4 // BMODEL or SPRITE that was split across BSP nodes + +#endif//ENTITY_TYPES_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/event_api.h b/Projects/Android/jni/src/Xash3D/xash3d/common/event_api.h new file mode 100644 index 0000000..15e73b9 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/event_api.h @@ -0,0 +1,54 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef EVENT_API_H +#define EVENT_API_H + +#define EVENT_API_VERSION 1 + +typedef struct event_api_s +{ + int version; + void ( *EV_PlaySound )( int ent, float *origin, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch ); + void ( *EV_StopSound )( int ent, int channel, const char *sample ); + int ( *EV_FindModelIndex )( const char *pmodel ); + int ( *EV_IsLocal )( int playernum ); + int ( *EV_LocalPlayerDucking )( void ); + void ( *EV_LocalPlayerViewheight )( float * ); + void ( *EV_LocalPlayerBounds )( int hull, float *mins, float *maxs ); + int ( *EV_IndexFromTrace)( struct pmtrace_s *pTrace ); + struct physent_s *( *EV_GetPhysent )( int idx ); + void ( *EV_SetUpPlayerPrediction )( int dopred, int bIncludeLocalClient ); + void ( *EV_PushPMStates )( void ); + void ( *EV_PopPMStates )( void ); + void ( *EV_SetSolidPlayers )( int playernum ); + void ( *EV_SetTraceHull )( int hull ); + void ( *EV_PlayerTrace )( float *start, float *end, int traceFlags, int ignore_pe, struct pmtrace_s *tr ); + void ( *EV_WeaponAnimation )( int sequence, int body ); + unsigned short ( *EV_PrecacheEvent )( int type, const char* psz ); + void ( *EV_PlaybackEvent )( int flags, const struct edict_s *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ); + const char *( *EV_TraceTexture )( int ground, float *vstart, float *vend ); + void ( *EV_StopAllSounds )( int entnum, int entchannel ); + void ( *EV_KillEvents )( int entnum, const char *eventname ); + + // Xash3D extension + unsigned short (*EV_IndexForEvent)( const char *name ); + const char *(*EV_EventForIndex)( unsigned short index ); + void ( *EV_PlayerTraceExt )( float *start, float *end, int traceFlags, int (*pfnIgnore)( struct physent_s *pe ), struct pmtrace_s *tr ); + const char *(*EV_SoundForIndex)( int index ); + struct msurface_s *( *EV_TraceSurface )( int ground, float *vstart, float *vend ); +} event_api_t; + +#endif//EVENT_API_H diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/event_args.h b/Projects/Android/jni/src/Xash3D/xash3d/common/event_args.h new file mode 100644 index 0000000..d85906c --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/event_args.h @@ -0,0 +1,47 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef EVENT_ARGS_H +#define EVENT_ARGS_H + +// Event was invoked with stated origin +#define FEVENT_ORIGIN ( 1<<0 ) + +// Event was invoked with stated angles +#define FEVENT_ANGLES ( 1<<1 ) + +typedef struct event_args_s +{ + int flags; + + // Transmitted + int entindex; + + float origin[3]; + float angles[3]; + float velocity[3]; + + int ducking; + + float fparam1; + float fparam2; + + int iparam1; + int iparam2; + + int bparam1; + int bparam2; +} event_args_t; + +#endif//EVENT_ARGS_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/event_flags.h b/Projects/Android/jni/src/Xash3D/xash3d/common/event_flags.h new file mode 100644 index 0000000..3c1d8fb --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/event_flags.h @@ -0,0 +1,45 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef EVENT_FLAGS_H +#define EVENT_FLAGS_H + +// Skip local host for event send. +#define FEV_NOTHOST (1<<0) + +// Send the event reliably. You must specify the origin and angles and use +// PLAYBACK_EVENT_FULL for this to work correctly on the server for anything +// that depends on the event origin/angles. I.e., the origin/angles are not +// taken from the invoking edict for reliable events. +#define FEV_RELIABLE (1<<1) + +// Don't restrict to PAS/PVS, send this event to _everybody_ on the server ( useful for stopping CHAN_STATIC +// sounds started by client event when client is not in PVS anymore ( hwguy in TFC e.g. ). +#define FEV_GLOBAL (1<<2) + +// If this client already has one of these events in its queue, just update the event instead of sending it as a duplicate +// +#define FEV_UPDATE (1<<3) + +// Only send to entity specified as the invoker +#define FEV_HOSTONLY (1<<4) + +// Only send if the event was created on the server. +#define FEV_SERVER (1<<5) + +// Only issue event client side ( from shared code ) +#define FEV_CLIENT (1<<6) + +#endif//EVENT_FLAGS_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/gameinfo.h b/Projects/Android/jni/src/Xash3D/xash3d/common/gameinfo.h new file mode 100644 index 0000000..511b371 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/gameinfo.h @@ -0,0 +1,49 @@ +/* +gameinfo.h - current game info +Copyright (C) 2010 Uncle Mike + +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 3 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. +*/ + +#ifndef GAMEINFO_H +#define GAMEINFO_H + +#define GFL_NOMODELS (1<<0) + +/* +======================================================================== + +GAMEINFO stuff + +internal shared gameinfo structure (readonly for engine parts) +======================================================================== +*/ +typedef struct +{ + // filesystem info + char gamefolder[64]; // used for change game '-game x' + char startmap[64]; // map to start singleplayer game + char trainmap[64]; // map to start hazard course (if specified) + char title[64]; // Game Main Title + char version[14]; // game version (optional) + short flags; // game flags + + // about mod info + char game_url[256]; // link to a developer's site + char update_url[256]; // link to updates page + char type[64]; // single, toolkit, multiplayer etc + char date[64]; + char size[64]; // displayed mod size + + int gamemode; +} GAMEINFO; + +#endif//GAMEINFO_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/hltv.h b/Projects/Android/jni/src/Xash3D/xash3d/common/hltv.h new file mode 100644 index 0000000..ea33d7d --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/hltv.h @@ -0,0 +1,64 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef HLTV_H +#define HLTV_H + +#define TYPE_CLIENT 0 // client is a normal HL client (default) +#define TYPE_PROXY 1 // client is another proxy +#define TYPE_COMMENTATOR 3 // client is a commentator +#define TYPE_DEMO 4 // client is a demo file + +// sub commands of svc_hltv: +#define HLTV_ACTIVE 0 // tells client that he's an spectator and will get director commands +#define HLTV_STATUS 1 // send status infos about proxy +#define HLTV_LISTEN 2 // tell client to listen to a multicast stream + +// sub commands of svc_director: +#define DRC_CMD_NONE 0 // NULL director command +#define DRC_CMD_START 1 // start director mode +#define DRC_CMD_EVENT 2 // informs about director command +#define DRC_CMD_MODE 3 // switches camera modes +#define DRC_CMD_CAMERA 4 // sets camera registers +#define DRC_CMD_TIMESCALE 5 // sets time scale +#define DRC_CMD_MESSAGE 6 // send HUD centerprint +#define DRC_CMD_SOUND 7 // plays a particular sound +#define DRC_CMD_STATUS 8 // status info about broadcast +#define DRC_CMD_BANNER 9 // banner file name for HLTV gui +#define DRC_CMD_STUFFTEXT 10 // like the normal svc_stufftext but as director command +#define DRC_CMD_CHASE 11 // chase a certain player +#define DRC_CMD_INEYE 12 // view player through own eyes +#define DRC_CMD_MAP 13 // show overview map +#define DRC_CMD_CAMPATH 14 // define camera waypoint +#define DRC_CMD_WAYPOINTS 15 // start moving camera, inetranl message + +#define DRC_CMD_LAST 15 + +// HLTV_EVENT event flags +#define DRC_FLAG_PRIO_MASK 0x0F // priorities between 0 and 15 (15 most important) +#define DRC_FLAG_SIDE (1<<4) // +#define DRC_FLAG_DRAMATIC (1<<5) // is a dramatic scene +#define DRC_FLAG_SLOWMOTION (1<<6) // would look good in SloMo +#define DRC_FLAG_FACEPLAYER (1<<7) // player is doning something (reload/defuse bomb etc) +#define DRC_FLAG_INTRO (1<<8) // is a introduction scene +#define DRC_FLAG_FINAL (1<<9) // is a final scene +#define DRC_FLAG_NO_RANDOM (1<<10) // don't randomize event data + +// DRC_CMD_WAYPOINT flags +#define DRC_FLAG_STARTPATH 1 // end with speed 0.0 +#define DRC_FLAG_SLOWSTART 2 // start with speed 0.0 +#define DRC_FLAG_SLOWEND 4 //end with speed 0.0 + +#endif//HLTV_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/ivoicetweak.h b/Projects/Android/jni/src/Xash3D/xash3d/common/ivoicetweak.h new file mode 100644 index 0000000..541a63f --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/ivoicetweak.h @@ -0,0 +1,40 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef IVOICETWEAK_H +#define IVOICETWEAK_H + +// These provide access to the voice controls. +typedef enum +{ + MicrophoneVolume = 0, // values 0-1. + OtherSpeakerScale // values 0-1. Scales how loud other players are. +} VoiceTweakControl; + +typedef struct IVoiceTweak_s +{ + // These turn voice tweak mode on and off. While in voice tweak mode, the user's voice is echoed back + // without sending to the server. + int (*StartVoiceTweakMode)( void ); // Returns 0 on error. + void (*EndVoiceTweakMode)( void ); + + // Get/set control values. + void (*SetControlFloat)( VoiceTweakControl iControl, float value ); + float (*GetControlFloat)( VoiceTweakControl iControl ); + + int (*GetSpeakingVolume)( void ); +} IVoiceTweak; + +#endif//IVOICETWEAK_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/kbutton.h b/Projects/Android/jni/src/Xash3D/xash3d/common/kbutton.h new file mode 100644 index 0000000..23cd8ac --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/kbutton.h @@ -0,0 +1,18 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( KBUTTONH ) +#define KBUTTONH +#pragma once + +typedef struct kbutton_s +{ + int down[2]; // key nums holding it down + int state; // low bit is down state +} kbutton_t; + +#endif // !KBUTTONH \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/lightstyle.h b/Projects/Android/jni/src/Xash3D/xash3d/common/lightstyle.h new file mode 100644 index 0000000..9631ca7 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/lightstyle.h @@ -0,0 +1,29 @@ +/* +lightstyle.h - lighstyle description +Copyright (C) 2011 Uncle Mike + +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 3 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. +*/ + +#ifndef LIGHTSTYLE_H +#define LIGHTSTYLE_H + +typedef struct +{ + char pattern[256]; + float map[256]; + int length; + float value; + qboolean interp; // allow to interpolate this lightstyle + float time; // local time warranties that new style begins from the start, not mid or end of the sequence +} lightstyle_t; + +#endif//LIGHTSTYLE_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/mathlib.h b/Projects/Android/jni/src/Xash3D/xash3d/common/mathlib.h new file mode 100644 index 0000000..fadb97f --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/mathlib.h @@ -0,0 +1,95 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// mathlib.h + +#include + +typedef float vec_t; +typedef vec_t vec2_t[2]; +typedef vec_t vec3_t[3]; +typedef vec_t vec4_t[4]; // x,y,z,w + +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +struct mplane_s; + +extern vec3_t vec3_origin; +extern int nanmask; + +#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask) + +#ifndef VECTOR_H + #define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]) +#endif + +#define VectorSubtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];(c)[2]=(a)[2]-(b)[2];} +#define VectorAdd(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];(c)[2]=(a)[2]+(b)[2];} +#define VectorCopy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];(b)[2]=(a)[2];} +#define VectorClear(a) {(a)[0]=0.0;(a)[1]=0.0;(a)[2]=0.0;} + +void VectorMA (const vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc); + +vec_t _DotProduct (vec3_t v1, vec3_t v2); +void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out); +void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out); +void _VectorCopy (vec3_t in, vec3_t out); + +int VectorCompare (const vec3_t v1, const vec3_t v2); +float Length (const vec3_t v); +void CrossProduct (const vec3_t v1, const vec3_t v2, vec3_t cross); +float VectorNormalize (vec3_t v); // returns vector length +void VectorInverse (vec3_t v); +void VectorScale (const vec3_t in, vec_t scale, vec3_t out); + +void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]); +void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]); + +void AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); +void AngleVectorsTranspose (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); +#define AngleIVectors AngleVectorsTranspose + +void AngleMatrix (const vec3_t angles, float (*matrix)[4] ); +void AngleIMatrix (const vec3_t angles, float (*matrix)[4] ); +void VectorTransform (const vec3_t in1, float in2[3][4], vec3_t out); + +void NormalizeAngles( vec3_t angles ); +void InterpolateAngles( vec3_t start, vec3_t end, vec3_t output, float frac ); +float AngleBetweenVectors( const vec3_t v1, const vec3_t v2 ); + +void VectorMatrix( vec3_t forward, vec3_t right, vec3_t up); +void VectorAngles( const vec3_t forward, vec3_t angles ); + +int InvertMatrix( const float * m, float *out ); + +int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct mplane_s *plane); +float anglemod(float a); + +#define BOX_ON_PLANE_SIDE(emins, emaxs, p) \ + (((p)->type < 3)? \ + ( \ + ((p)->dist <= (emins)[(p)->type])? \ + 1 \ + : \ + ( \ + ((p)->dist >= (emaxs)[(p)->type])?\ + 2 \ + : \ + 3 \ + ) \ + ) \ + : \ + BoxOnPlaneSide( (emins), (emaxs), (p))) diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/net_api.h b/Projects/Android/jni/src/Xash3D/xash3d/common/net_api.h new file mode 100644 index 0000000..956b16e --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/net_api.h @@ -0,0 +1,98 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef NET_API_H +#define NET_API_H + +#include "netadr.h" + +#define NETAPI_REQUEST_SERVERLIST ( 0 ) // Doesn't need a remote address +#define NETAPI_REQUEST_PING ( 1 ) +#define NETAPI_REQUEST_RULES ( 2 ) +#define NETAPI_REQUEST_PLAYERS ( 3 ) +#define NETAPI_REQUEST_DETAILS ( 4 ) + +// Set this flag for things like broadcast requests, etc. where the engine should not +// kill the request hook after receiving the first response +#define FNETAPI_MULTIPLE_RESPONSE ( 1<<0 ) + +struct net_response_s; +typedef void (*net_api_response_func_t) ( struct net_response_s *response ); + +#define NET_SUCCESS ( 0 ) +#define NET_ERROR_TIMEOUT ( 1<<0 ) +#define NET_ERROR_PROTO_UNSUPPORTED ( 1<<1 ) +#define NET_ERROR_UNDEFINED ( 1<<2 ) + +typedef struct net_adrlist_s +{ + struct net_adrlist_s *next; + netadr_t remote_address; +} net_adrlist_t; + +typedef struct net_response_s +{ + // NET_SUCCESS or an error code + int error; + // Context ID + int context; + // Type + int type; + // Server that is responding to the request + netadr_t remote_address; + // Response RTT ping time + double ping; + // Key/Value pair string ( separated by backlash \ characters ) + // WARNING: You must copy this buffer in the callback function, because it is freed + // by the engine right after the call!!!! + // ALSO: For NETAPI_REQUEST_SERVERLIST requests, this will be a pointer to a linked list of net_adrlist_t's + void *response; +} net_response_t; + +typedef struct net_status_s +{ + // Connected to remote server? 1 == yes, 0 otherwise + int connected; + // Client's IP address + netadr_t local_address; + // Address of remote server + netadr_t remote_address; + // Packet Loss ( as a percentage ) + int packet_loss; + // Latency, in seconds ( multiply by 1000.0 to get milliseconds ) + double latency; + // Connection time, in seconds + double connection_time; + // Rate setting ( for incoming data ) + double rate; +} net_status_t; + +typedef struct net_api_s +{ + // APIs + void (*InitNetworking)( void ); + void (*Status )( struct net_status_s *status ); + void (*SendRequest)( int context, int request, int flags, double timeout, struct netadr_s *remote_address, net_api_response_func_t response ); + void (*CancelRequest)( int context ); + void (*CancelAllRequests)( void ); + char *(*AdrToString)( struct netadr_s *a ); + int ( *CompareAdr)( struct netadr_s *a, struct netadr_s *b ); + int ( *StringToAdr)( char *s, struct netadr_s *a ); + const char *(*ValueForKey)( const char *s, const char *key ); + void (*RemoveKey)( char *s, const char *key ); + void (*SetValueForKey)( char *s, const char *key, const char *value, int maxsize ); +} net_api_t; + +#endif//NET_APIH diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/netadr.h b/Projects/Android/jni/src/Xash3D/xash3d/common/netadr.h new file mode 100644 index 0000000..dfeea8b --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/netadr.h @@ -0,0 +1,37 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef NETADR_H +#define NETADR_H + +typedef enum +{ + NA_UNUSED, + NA_LOOPBACK, + NA_BROADCAST, + NA_IP, + NA_IPX, + NA_BROADCAST_IPX +} netadrtype_t; + +typedef struct netadr_s +{ + netadrtype_t type; + unsigned char ip[4]; + unsigned char ipx[10]; + unsigned short port; +} netadr_t; + +#endif//NETADR_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/particledef.h b/Projects/Android/jni/src/Xash3D/xash3d/common/particledef.h new file mode 100644 index 0000000..7f01593 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/particledef.h @@ -0,0 +1,54 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef PARTICLEDEF_H +#define PARTICLEDEF_H + +typedef enum +{ + pt_static, + pt_grav, + pt_slowgrav, + pt_fire, + pt_explode, + pt_explode2, + pt_blob, + pt_blob2, + pt_vox_slowgrav, + pt_vox_grav, + pt_clientcustom, // Must have callback function specified + pt_tracer // Always have callback +} ptype_t; + +struct particle_s +{ + vec3_t org; + short color; + short packedColor; + struct particle_s *next; + vec3_t vel; + float ramp; + float die; + ptype_t type; + void (*deathfunc)( struct particle_s *particle ); + + // for pt_clientcusttom, we'll call this function each frame + void (*callback)( struct particle_s *particle, float frametime ); + + // For deathfunc, etc. + unsigned char context; +}; + +#endif//PARTICLEDEF_H diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/pmtrace.h b/Projects/Android/jni/src/Xash3D/xash3d/common/pmtrace.h new file mode 100644 index 0000000..6394de5 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/pmtrace.h @@ -0,0 +1,41 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef PM_TRACE_H +#define PM_TRACE_H + +typedef struct +{ + vec3_t normal; + float dist; +} pmplane_t; + +typedef struct pmtrace_s pmtrace_t; + +struct pmtrace_s +{ + qboolean allsolid; // if true, plane is not valid + qboolean startsolid; // if true, the initial point was in a solid area + qboolean inopen, inwater; // End point is in empty space or in water + float fraction; // time completed, 1.0 = didn't hit anything + vec3_t endpos; // final position + pmplane_t plane; // surface normal at impact + int ent; // entity at impact + vec3_t deltavelocity; // Change in player's velocity caused by impact. + // Only run on server. + int hitgroup; +}; + +#endif//PM_TRACE_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/port.h b/Projects/Android/jni/src/Xash3D/xash3d/common/port.h new file mode 100644 index 0000000..8cc74ed --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/port.h @@ -0,0 +1,187 @@ +/* +port.h -- Portability Layer for Windows types +Copyright (C) 2015 Alibek Omarov + +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 3 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. +*/ + +#pragma once +#ifndef PORT_H +#define PORT_H + +#if defined(__LP64__) || defined(__LLP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + #define XASH_64BIT +#endif + +#ifdef XASH_64BIT +#define ARCH_SUFFIX "64" +#else +#define ARCH_SUFFIX +#endif + +#if defined(__ANDROID__) || TARGET_OS_IOS || defined(__SAILFISH__) +#define XASH_MOBILE_PLATFORM +#endif + +#ifdef _WIN32 +#define PATH_SPLITTER "\\" +#else +#define PATH_SPLITTER "/" +#endif + +#if !defined(_WIN32) + #include + #include + #include + #include + + #if defined(__APPLE__) + #include + #define OS_LIB_EXT "dylib" + #define OPEN_COMMAND "open" + #include "TargetConditionals.h" + #else + #define OS_LIB_EXT "so" + #define OPEN_COMMAND "xdg-open" + #endif + + + #ifdef __EMSCRIPTEN__ + #include + #endif + + #if defined(__ANDROID__) + #if defined(LOAD_HARDFP) + #define POSTFIX "_hardfp" + #else + #define POSTFIX + #endif + + // don't change these names + #define MENUDLL "libmenu" POSTFIX "." OS_LIB_EXT + #define CLIENTDLL "libclient" POSTFIX "." OS_LIB_EXT + #define SERVERDLL "libserver" POSTFIX "." OS_LIB_EXT + #define GAMEPATH "/sdcard/xash" + #elif defined(__SAILFISH__) + #define POSTFIX + // don't change these names + #define MENUDLL "libmenu" POSTFIX "." OS_LIB_EXT + #define CLIENTDLL "libclient" POSTFIX "." OS_LIB_EXT + #define SERVERDLL "libserver" POSTFIX "." OS_LIB_EXT + #define GAMEPATH "/home/nemo/xash" + #define LIBPATH "/usr/lib/xash3d/" + #define SHAREPATH "/usr/share/xash3d/" + #else + #define MENUDLL "libxashmenu" ARCH_SUFFIX "." OS_LIB_EXT + #define CLIENTDLL "client" ARCH_SUFFIX "." OS_LIB_EXT + #endif + + #define VGUI_SUPPORT_DLL "libvgui_support." OS_LIB_EXT + + // Windows-specific + #define __cdecl + #define _inline static inline + #define O_BINARY 0 // O_BINARY is Windows extension + #define O_TEXT 0 // O_TEXT is Windows extension + + // Windows functions to Linux equivalent + #define _mkdir( x ) mkdir( x, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH ) + #define LoadLibrary( x ) dlopen( x, RTLD_NOW ) + #define GetProcAddress( x, y ) dlsym( x, y ) + #define SetCurrentDirectory( x ) (!chdir( x )) + #define FreeLibrary( x ) dlclose( x ) + //#define MAKEWORD( a, b ) ((short int)(((unsigned char)(a))|(((short int)((unsigned char)(b)))<<8))) + #define max( a, b ) (((a) > (b)) ? (a) : (b)) + #define min( a, b ) (((a) < (b)) ? (a) : (b)) + #define tell( a ) lseek(a, 0, SEEK_CUR) + + typedef unsigned char BYTE; + typedef short int WORD; + typedef unsigned int DWORD; + typedef int LONG; + typedef unsigned int ULONG; + typedef int WPARAM; + typedef unsigned int LPARAM; + + typedef void* HANDLE; + typedef void* HMODULE; + typedef void* HINSTANCE; + + typedef char* LPSTR; + + typedef struct tagPOINT + { + int x, y; + } POINT; +#else // WIN32 + #ifdef __MINGW32__ + #define _inline static inline + #endif + + #define strcasecmp _stricmp + #define strncasecmp _strnicmp + #define open _open + #define read _read + + // shut-up compiler warnings + #pragma warning(disable : 4244) // MIPS + #pragma warning(disable : 4018) // signed/unsigned mismatch + #pragma warning(disable : 4305) // truncation from const double to float + #pragma warning(disable : 4115) // named type definition in parentheses + #pragma warning(disable : 4100) // unreferenced formal parameter + #pragma warning(disable : 4127) // conditional expression is constant + #pragma warning(disable : 4057) // differs in indirection to slightly different base types + #pragma warning(disable : 4201) // nonstandard extension used + #pragma warning(disable : 4706) // assignment within conditional expression + #pragma warning(disable : 4054) // type cast' : from function pointer + #pragma warning(disable : 4310) // cast truncates constant value + + #define HSPRITE WINAPI_HSPRITE + #include + #undef HSPRITE + + #define OS_LIB_EXT "dll" + #define MENUDLL "menu"ARCH_SUFFIX"." OS_LIB_EXT + #define CLIENTDLL "client"ARCH_SUFFIX"." OS_LIB_EXT + #define VGUI_SUPPORT_DLL "../vgui_support." OS_LIB_EXT + #include + +#if defined(_MSC_VER) && (_MSC_VER < 1700) +#include +static __inline int round(float f) +{ + return (int)(f + 0.5); + +} +static __inline float cbrt(float f) +{ + return pow(f,1.0/3.0); + +} + +#endif + + +#ifdef XASH_64BIT +// windows NameForFunction not implemented yet +#define XASH_ALLOW_SAVERESTORE_OFFSETS +#endif +#endif //WIN32 + +#ifndef INT_MAX +#define INT_MAX 2147483647 +#endif + +#ifndef USHRT_MAX +#define USHRT_MAX 65535 +#endif + +#endif // PORT_H diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/qfont.h b/Projects/Android/jni/src/Xash3D/xash3d/common/qfont.h new file mode 100644 index 0000000..0640857 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/qfont.h @@ -0,0 +1,38 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef QFONT_H +#define QFONT_H + +// Font stuff + +#define NUM_GLYPHS 256 + +typedef struct +{ + short startoffset; + short charwidth; +} charinfo; + +typedef struct qfont_s +{ + int width, height; + int rowcount; + int rowheight; + charinfo fontinfo[NUM_GLYPHS]; + byte data[4]; +} qfont_t; + +#endif//QFONT_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/r_efx.h b/Projects/Android/jni/src/Xash3D/xash3d/common/r_efx.h new file mode 100644 index 0000000..7353df9 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/r_efx.h @@ -0,0 +1,195 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef R_EFX_H +#define R_EFX_H + +// particle_t +#if !defined( PARTICLEDEFH ) +#include "particledef.h" +#endif + +// BEAM +#if !defined( BEAMDEFH ) +#include "beamdef.h" +#endif + +// dlight_t +#if !defined ( DLIGHTH ) +#include "dlight.h" +#endif + +// cl_entity_t +#if !defined( CL_ENTITYH ) +#include "cl_entity.h" +#endif + +/* +// FOR REFERENCE, These are the built-in tracer colors. Note, color 4 is the one +// that uses the tracerred/tracergreen/tracerblue and traceralpha cvar settings +color24 gTracerColors[] = +{ + { 255, 255, 255 }, // White + { 255, 0, 0 }, // Red + { 0, 255, 0 }, // Green + { 0, 0, 255 }, // Blue + { 0, 0, 0 }, // Tracer default, filled in from cvars, etc. + { 255, 167, 17 }, // Yellow-orange sparks + { 255, 130, 90 }, // Yellowish streaks (garg) + { 55, 60, 144 }, // Blue egon streak + { 255, 130, 90 }, // More Yellowish streaks (garg) + { 255, 140, 90 }, // More Yellowish streaks (garg) + { 200, 130, 90 }, // More red streaks (garg) + { 255, 120, 70 }, // Darker red streaks (garg) +}; +*/ + +// Temporary entity array +#define TENTPRIORITY_LOW 0 +#define TENTPRIORITY_HIGH 1 + +// TEMPENTITY flags +#define FTENT_NONE 0x00000000 +#define FTENT_SINEWAVE 0x00000001 +#define FTENT_GRAVITY 0x00000002 +#define FTENT_ROTATE 0x00000004 +#define FTENT_SLOWGRAVITY 0x00000008 +#define FTENT_SMOKETRAIL 0x00000010 +#define FTENT_COLLIDEWORLD 0x00000020 +#define FTENT_FLICKER 0x00000040 +#define FTENT_FADEOUT 0x00000080 +#define FTENT_SPRANIMATE 0x00000100 +#define FTENT_HITSOUND 0x00000200 +#define FTENT_SPIRAL 0x00000400 +#define FTENT_SPRCYCLE 0x00000800 +#define FTENT_COLLIDEALL 0x00001000 // will collide with world and slideboxes +#define FTENT_PERSIST 0x00002000 // tent is not removed when unable to draw +#define FTENT_COLLIDEKILL 0x00004000 // tent is removed upon collision with anything +#define FTENT_PLYRATTACHMENT 0x00008000 // tent is attached to a player (owner) +#define FTENT_SPRANIMATELOOP 0x00010000 // animating sprite doesn't die when last frame is displayed +#define FTENT_SPARKSHOWER 0x00020000 +#define FTENT_NOMODEL 0x00040000 // Doesn't have a model, never try to draw ( it just triggers other things ) +#define FTENT_CLIENTCUSTOM 0x00080000 // Must specify callback. Callback function is responsible for killing tempent and updating fields ( unless other flags specify how to do things ) +#define FTENT_SCALE 0x00100000 // An experiment + +typedef struct tempent_s TEMPENTITY; +struct tempent_s +{ + int flags; + float die; + float frameMax; + float x; + float y; + float z; + float fadeSpeed; + float bounceFactor; + int hitSound; + void (*hitcallback)( struct tempent_s *ent, struct pmtrace_s *ptr ); + void (*callback)( struct tempent_s *ent, float frametime, float currenttime ); + TEMPENTITY *next; + int priority; + short clientIndex; // if attached, this is the index of the client to stick to + // if COLLIDEALL, this is the index of the client to ignore + // TENTS with FTENT_PLYRATTACHMENT MUST set the clientindex! + + vec3_t tentOffset; // if attached, client origin + tentOffset = tent origin. + cl_entity_t entity; + + // baseline.origin - velocity + // baseline.renderamt - starting fadeout intensity + // baseline.angles - angle velocity +}; + +typedef struct efx_api_s efx_api_t; + +struct efx_api_s +{ + particle_t *(*R_AllocParticle)( void (*callback)( struct particle_s *particle, float frametime )); + void (*R_BlobExplosion)( float *org ); + void (*R_Blood)( float *org, float *dir, int pcolor, int speed ); + void (*R_BloodSprite)( float *org, int colorindex, int modelIndex, int modelIndex2, float size ); + void (*R_BloodStream)( float *org, float *dir, int pcolor, int speed ); + void (*R_BreakModel)( float *pos, float *size, float *dir, float random, float life, int count, int modelIndex, char flags ); + void (*R_Bubbles)( float *mins, float *maxs, float height, int modelIndex, int count, float speed ); + void (*R_BubbleTrail)( float *start, float *end, float height, int modelIndex, int count, float speed ); + void (*R_BulletImpactParticles)( float *pos ); + void (*R_EntityParticles)( struct cl_entity_s *ent ); + void (*R_Explosion)( float *pos, int model, float scale, float framerate, int flags ); + void (*R_FizzEffect)( struct cl_entity_s *pent, int modelIndex, int density ); + void (*R_FireField)( float *org, int radius, int modelIndex, int count, int flags, float life ); + void (*R_FlickerParticles)( float *org ); + void (*R_FunnelSprite)( float *org, int modelIndex, int reverse ); + void (*R_Implosion)( float *end, float radius, int count, float life ); + void (*R_LargeFunnel)( float *org, int reverse ); + void (*R_LavaSplash)( float *org ); + void (*R_MultiGunshot)( float *org, float *dir, float *noise, int count, int decalCount, int *decalIndices ); + void (*R_MuzzleFlash)( float *pos1, int type ); + void (*R_ParticleBox)( float *mins, float *maxs, unsigned char r, unsigned char g, unsigned char b, float life ); + void (*R_ParticleBurst)( float *pos, int size, int color, float life ); + void (*R_ParticleExplosion)( float *org ); + void (*R_ParticleExplosion2)( float *org, int colorStart, int colorLength ); + void (*R_ParticleLine)( float *start, float *end, unsigned char r, unsigned char g, unsigned char b, float life ); + void (*R_PlayerSprites)( int client, int modelIndex, int count, int size ); + void (*R_Projectile)( float *origin, float *velocity, int modelIndex, int life, int owner, void (*hitcallback)( struct tempent_s *ent, struct pmtrace_s *ptr ) ); + void (*R_RicochetSound)( float *pos ); + void (*R_RicochetSprite)( float *pos, struct model_s *pmodel, float duration, float scale ); + void (*R_RocketFlare)( float *pos ); + void (*R_RocketTrail)( float *start, float *end, int type ); + void (*R_RunParticleEffect)( float *org, float *dir, int color, int count ); + void (*R_ShowLine)( float *start, float *end ); + void (*R_SparkEffect)( float *pos, int count, int velocityMin, int velocityMax ); + void (*R_SparkShower)( float *pos ); + void (*R_SparkStreaks)( float *pos, int count, int velocityMin, int velocityMax ); + void (*R_Spray)( float *pos, float *dir, int modelIndex, int count, int speed, int spread, int rendermode ); + void (*R_Sprite_Explode)( TEMPENTITY *pTemp, float scale, int flags ); + void (*R_Sprite_Smoke)( TEMPENTITY *pTemp, float scale ); + void (*R_Sprite_Spray)( float *pos, float *dir, int modelIndex, int count, int speed, int iRand ); + void (*R_Sprite_Trail)( int type, float *start, float *end, int modelIndex, int count, float life, float size, float amplitude, int renderamt, float speed ); + void (*R_Sprite_WallPuff)( TEMPENTITY *pTemp, float scale ); + void (*R_StreakSplash)( float *pos, float *dir, int color, int count, float speed, int velocityMin, int velocityMax ); + void (*R_TracerEffect)( float *start, float *end ); + void (*R_UserTracerParticle)( float *org, float *vel, float life, int colorIndex, float length, unsigned char deathcontext, void (*deathfunc)( struct particle_s *particle )); + particle_t *(*R_TracerParticles)( float *org, float *vel, float life ); + void (*R_TeleportSplash)( float *org ); + void (*R_TempSphereModel)( float *pos, float speed, float life, int count, int modelIndex ); + TEMPENTITY *(*R_TempModel)( float *pos, float *dir, float *angles, float life, int modelIndex, int soundtype ); + TEMPENTITY *(*R_DefaultSprite)( float *pos, int spriteIndex, float framerate ); + TEMPENTITY *(*R_TempSprite)( float *pos, float *dir, float scale, int modelIndex, int rendermode, int renderfx, float a, float life, int flags ); + int (*Draw_DecalIndex)( int id ); + int (*Draw_DecalIndexFromName)( char *name ); + void (*R_DecalShoot)( int textureIndex, int entity, int modelIndex, float *position, int flags ); + void (*R_AttachTentToPlayer)( int client, int modelIndex, float zoffset, float life ); + void (*R_KillAttachedTents)( int client ); + BEAM *(*R_BeamCirclePoints)( int type, float *start, float *end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *(*R_BeamEntPoint)( int startEnt, float *end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *(*R_BeamEnts)( int startEnt, int endEnt, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *(*R_BeamFollow)( int startEnt, int modelIndex, float life, float width, float r, float g, float b, float brightness ); + void (*R_BeamKill)( int deadEntity ); + BEAM *(*R_BeamLightning)( float *start, float *end, int modelIndex, float life, float width, float amplitude, float brightness, float speed ); + BEAM *(*R_BeamPoints)( float *start, float *end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *(*R_BeamRing)( int startEnt, int endEnt, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + dlight_t *(*CL_AllocDlight)( int key ); + dlight_t *(*CL_AllocElight)( int key ); + TEMPENTITY *(*CL_TempEntAlloc)( float *org, struct model_s *model ); + TEMPENTITY *(*CL_TempEntAllocNoModel)( float *org ); + TEMPENTITY *(*CL_TempEntAllocHigh)( float *org, struct model_s *model ); + TEMPENTITY *(*CL_TentEntAllocCustom)( float *origin, struct model_s *model, int high, void (*callback)( struct tempent_s *ent, float frametime, float currenttime )); + void (*R_GetPackedColor)( short *packed, short color ); + short (*R_LookupColor)( unsigned char r, unsigned char g, unsigned char b ); + void (*R_DecalRemoveAll)( int textureIndex ); // textureIndex points to the decal index in the array, not the actual texture index. + void (*R_FireCustomDecal)( int textureIndex, int entity, int modelIndex, float *position, int flags, float scale ); +}; + +#endif//R_EFX_H diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/r_studioint.h b/Projects/Android/jni/src/Xash3D/xash3d/common/r_studioint.h new file mode 100644 index 0000000..00384a1 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/r_studioint.h @@ -0,0 +1,154 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + + +#ifndef R_STUDIOINT_H +#define R_STUDIOINT_H + +#define STUDIO_INTERFACE_VERSION 1 + +typedef struct engine_studio_api_s +{ + // Allocate number*size bytes and zero it + void *( *Mem_Calloc )( int number, size_t size ); + // Check to see if pointer is in the cache + void *( *Cache_Check )( struct cache_user_s *c ); + // Load file into cache ( can be swapped out on demand ) + void ( *LoadCacheFile )( char *path, struct cache_user_s *cu ); + // Retrieve model pointer for the named model + struct model_s *( *Mod_ForName )( const char *name, int crash_if_missing ); + // Retrieve pointer to studio model data block from a model + void *( *Mod_Extradata )( struct model_s *mod ); + // Retrieve indexed model from client side model precache list + struct model_s *( *GetModelByIndex )( int index ); + // Get entity that is set for rendering + struct cl_entity_s * ( *GetCurrentEntity )( void ); + // Get referenced player_info_t + struct player_info_s *( *PlayerInfo )( int index ); + // Get most recently received player state data from network system + struct entity_state_s *( *GetPlayerState )( int index ); + // Get viewentity + struct cl_entity_s * ( *GetViewEntity )( void ); + // Get current frame count, and last two timestampes on client + void ( *GetTimes )( int *framecount, double *current, double *old ); + // Get a pointer to a cvar by name + struct cvar_s *( *GetCvar )( const char *name ); + // Get current render origin and view vectors ( up, right and vpn ) + void ( *GetViewInfo )( float *origin, float *upv, float *rightv, float *vpnv ); + // Get sprite model used for applying chrome effect + struct model_s *( *GetChromeSprite )( void ); + // Get model counters so we can incement instrumentation + void ( *GetModelCounters )( int **s, int **a ); + // Get software scaling coefficients + void ( *GetAliasScale )( float *x, float *y ); + + // Get bone, light, alias, and rotation matrices + float ****( *StudioGetBoneTransform )( void ); + float ****( *StudioGetLightTransform )( void ); + float ***( *StudioGetAliasTransform )( void ); + float ***( *StudioGetRotationMatrix )( void ); + + // Set up body part, and get submodel pointers + void ( *StudioSetupModel )( int bodypart, void **ppbodypart, void **ppsubmodel ); + // Check if entity's bbox is in the view frustum + int ( *StudioCheckBBox )( void ); + // Apply lighting effects to model + void ( *StudioDynamicLight )( struct cl_entity_s *ent, struct alight_s *plight ); + void ( *StudioEntityLight )( struct alight_s *plight ); + void ( *StudioSetupLighting )( struct alight_s *plighting ); + + // Draw mesh vertices + void ( *StudioDrawPoints )( void ); + + // Draw hulls around bones + void ( *StudioDrawHulls )( void ); + // Draw bbox around studio models + void ( *StudioDrawAbsBBox )( void ); + // Draws bones + void ( *StudioDrawBones )( void ); + // Loads in appropriate texture for model + void ( *StudioSetupSkin )( void *ptexturehdr, int index ); + // Sets up for remapped colors + void ( *StudioSetRemapColors )( int top, int bottom ); + // Set's player model and returns model pointer + struct model_s *( *SetupPlayerModel )( int index ); + // Fires any events embedded in animation + void ( *StudioClientEvents )( void ); + // Retrieve/set forced render effects flags + int ( *GetForceFaceFlags )( void ); + void ( *SetForceFaceFlags )( int flags ); + // Tell engine the value of the studio model header + void ( *StudioSetHeader )( void *header ); + // Tell engine which model_t * is being renderered + void ( *SetRenderModel )( struct model_s *model ); + + // Final state setup and restore for rendering + void ( *SetupRenderer )( int rendermode ); + void ( *RestoreRenderer )( void ); + + // Set render origin for applying chrome effect + void ( *SetChromeOrigin )( void ); + + // True if using D3D/OpenGL + int ( *IsHardware )( void ); + + // Only called by hardware interface + void ( *GL_StudioDrawShadow )( void ); + void ( *GL_SetRenderMode )( int mode ); + + void ( *StudioSetRenderamt )( int iRenderamt ); + void ( *StudioSetCullState )( int iCull ); + void ( *StudioRenderShadow )( int iSprite, float *p1, float *p2, float *p3, float *p4 ); +} engine_studio_api_t; + +typedef struct server_studio_api_s +{ + // Allocate number*size bytes and zero it + void *( *Mem_Calloc )( int number, size_t size ); + // Check to see if pointer is in the cache + void *( *Cache_Check )( struct cache_user_s *c ); + // Load file into cache ( can be swapped out on demand ) + void ( *LoadCacheFile )( char *path, struct cache_user_s *cu ); + // Retrieve pointer to studio model data block from a model + void *( *Mod_Extradata )( struct model_s *mod ); +} server_studio_api_t; + +// client blending +typedef struct r_studio_interface_s +{ + int version; + int ( *StudioDrawModel )( int flags ); + int ( *StudioDrawPlayer )( int flags, struct entity_state_s *pplayer ); +} r_studio_interface_t; + +// server blending +#define SV_BLENDING_INTERFACE_VERSION 1 + +typedef struct sv_blending_interface_s +{ + int version; + + void ( *SV_StudioSetupBones )( struct model_s *pModel, + float frame, + int sequence, + const vec3_t angles, + const vec3_t origin, + const byte *pcontroller, + const byte *pblending, + int iBone, + const edict_t *pEdict ); +} sv_blending_interface_t; + +#endif//R_STUDIOINT_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/ref_params.h b/Projects/Android/jni/src/Xash3D/xash3d/common/ref_params.h new file mode 100644 index 0000000..2642358 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/ref_params.h @@ -0,0 +1,90 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef REF_PARAMS_H +#define REF_PARAMS_H + +typedef struct ref_params_s +{ + // output + vec3_t vieworg; + vec3_t viewangles; + + vec3_t forward; + vec3_t right; + vec3_t up; + + // Client frametime; + float frametime; + // Client time + float time; + + // Misc + int intermission; + int paused; + int spectator; + int onground; + int waterlevel; + + vec3_t simvel; + vec3_t simorg; + + vec3_t viewheight; + float idealpitch; + + vec3_t cl_viewangles; + int health; + vec3_t crosshairangle; + float viewsize; + + vec3_t punchangle; + int maxclients; + int viewentity; + int playernum; + int max_entities; + int demoplayback; + int hardware; + int smoothing; + + // Last issued usercmd + struct usercmd_s *cmd; + + // Movevars + struct movevars_s *movevars; + + int viewport[4]; // the viewport coordinates x, y, width, height + int nextView; // the renderer calls ClientDLL_CalcRefdef() and Renderview + // so long in cycles until this value is 0 (multiple views) + int onlyClientDraw; // if !=0 nothing is drawn by the engine except clientDraw functions +// Xash3D extension + float fov_x, fov_y; // actual fov can be overriden on nextView +} ref_params_t; + +// same as ref_params but for overview mode +typedef struct ref_overview_s +{ + vec3_t origin; + qboolean rotated; + + float xLeft; + float xRight; + float xTop; + float xBottom; + float zFar; + float zNear; + float flZoom; +} ref_overview_t; + +#endif//REF_PARAMS_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/render_api.h b/Projects/Android/jni/src/Xash3D/xash3d/common/render_api.h new file mode 100644 index 0000000..7404415 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/render_api.h @@ -0,0 +1,262 @@ +/* +render_api.h - Xash3D extension for client interface +Copyright (C) 2011 Uncle Mike + +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 3 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. +*/ + +#ifndef RENDER_API_H +#define RENDER_API_H + +#include "lightstyle.h" +#include "dlight.h" + +// changes for version 28 +// replace decal_t from software declaration to hardware (matched to normal HL) +// mextrasurf_t->increased limit of reserved fields (up from 7 to 32) +// replace R_StoreEfrags with him extended version +// formed group for BSP decal manipulating +// move misc functions at end of the interface +// added new export for clearing studio decals + +#define CL_RENDER_INTERFACE_VERSION 35 +#define MAX_STUDIO_DECALS 4096 // + unused space of BSP decals + +#define SURF_INFO( surf, mod ) ((mextrasurf_t *)mod->cache.data + (surf - mod->surfaces)) +#define INFO_SURF( surf, mod ) (mod->surfaces + (surf - (mextrasurf_t *)mod->cache.data)) + +// render info parms +#define PARM_TEX_WIDTH 1 // all parms with prefix 'TEX_' receive arg as texnum +#define PARM_TEX_HEIGHT 2 // otherwise it's not used +#define PARM_TEX_SRC_WIDTH 3 +#define PARM_TEX_SRC_HEIGHT 4 +#define PARM_TEX_SKYBOX 5 // second arg as skybox ordering num +#define PARM_TEX_SKYTEXNUM 6 // skytexturenum for quake sky +#define PARM_TEX_LIGHTMAP 7 // second arg as number 0 - 128 +#define PARM_TEX_TARGET 8 +#define PARM_TEX_TEXNUM 9 +#define PARM_TEX_FLAGS 10 +#define PARM_TEX_TYPE 11 +#define PARM_TEX_CACHEFRAME 12 // compare with worldmodel->needload +#define PARM_TEX_GLFORMAT 13 // get a texture GL-format +#define PARM_TEX_ENCODE 14 // custom encoding for DXT image +// reserved +#define PARM_WORLD_VERSION 16 // return the version of bsp +#define PARM_SKY_SPHERE 17 // sky is quake sphere ? +#define PARM_MAP_HAS_MIRRORS 18 // current map has mirorrs +#define PARM_MAP_HAS_DELUXE 19 // map has deluxedata +#define PARM_MAX_ENTITIES 20 +#define PARM_WIDESCREEN 21 +#define PARM_FULLSCREEN 22 +#define PARM_SCREEN_WIDTH 23 +#define PARM_SCREEN_HEIGHT 24 +#define PARM_CLIENT_INGAME 25 +#define PARM_FEATURES 26 // same as movevars->features +#define PARM_ACTIVE_TMU 27 // for debug +#define PARM_CACHEFRAME 28 +#define PARM_MAX_IMAGE_UNITS 29 +#define PARM_CLIENT_ACTIVE 30 +#define PARM_REBUILD_GAMMA 31 // if true lightmaps rebuilding for gamma change + +enum +{ + // skybox ordering + SKYBOX_RIGHT = 0, + SKYBOX_BACK, + SKYBOX_LEFT, + SKYBOX_FORWARD, + SKYBOX_UP, + SKYBOX_DOWN, +}; + +typedef enum +{ + TEX_INVALID = 0, // free slot + TEX_SYSTEM, // generated by engine + TEX_NOMIP, // hud pics, menu etc + TEX_BRUSH, // a map texture + TEX_SPRITE, // sprite frames + TEX_STUDIO, // studio skins + TEX_LIGHTMAP, // lightmap textures + TEX_DECAL, // decals + TEX_VGUI, // vgui fonts or images + TEX_CUBEMAP, // cubemap textures (sky) + TEX_DETAIL, // detail textures + TEX_REMAP, // local copy of remap texture + TEX_SCREENCOPY, // keep screen copy e.g. for mirror + TEX_CUSTOM, // user created texture + TEX_DEPTHMAP // shadowmap texture +} texType_t; + +typedef enum +{ + TF_NEAREST = (1<<0), // disable texfilter + TF_KEEP_RGBDATA = (1<<1), // some images keep source + TF_NOFLIP_TGA = (1<<2), // Steam background completely ignore tga attribute 0x20 + TF_KEEP_8BIT = (1<<3), // keep original 8-bit image (if present) + TF_NOPICMIP = (1<<4), // ignore r_picmip resample rules + TF_UNCOMPRESSED = (1<<5), // don't compress texture in video memory + TF_CUBEMAP = (1<<6), // it's cubemap texture + TF_DEPTHMAP = (1<<7), // custom texture filter used + TF_INTENSITY = (1<<8), // monochrome intensity image + TF_LUMINANCE = (1<<9), // force image to grayscale + TF_SKYSIDE = (1<<10), // this is a part of skybox + TF_CLAMP = (1<<11), // clamp texcoords to [0..1] range + TF_NOMIPMAP = (1<<12), // don't build mips for this image + TF_HAS_LUMA = (1<<13), // sets by GL_UploadTexture + TF_MAKELUMA = (1<<14), // create luma from quake texture (only q1 textures contain luma-pixels) + TF_NORMALMAP = (1<<15), // is a normalmap + TF_HAS_ALPHA = (1<<16), // image has alpha (used only for GL_CreateTexture) + TF_FORCE_COLOR = (1<<17), // force upload monochrome textures as RGB (detail textures) + TF_TEXTURE_1D = (1<<18), // this is GL_TEXTURE_1D + TF_BORDER = (1<<19), // zero clamp for projected textures + TF_TEXTURE_3D = (1<<20), // this is GL_TEXTURE_3D + TF_STATIC = (1<<21), // a marker for purge mechanism (not used by engine) + TF_TEXTURE_RECTANGLE= (1<<22), // this is GL_TEXTURE_RECTANGLE + TF_ALPHA_BORDER = (1<<23), // clamp to (0,0,0,255) (probably no difference) + + TF_ALPHACONTRAST = (1<<25), // special texture flags for internal usage + TF_FLOAT = (1<<26), // float textures + TF_NOCOMPARE = (1<<27), // disable comparing for depth textures + TF_FLOATDATA = (1<<28), +} texFlags_t; + +typedef struct beam_s BEAM; +typedef struct particle_s particle_t; + +// 12 bytes here +typedef struct modelstate_s +{ + short sequence; + short frame; // 10 bits multiple by 4, should be enough + byte blending[2]; + byte controller[4]; + byte body; + byte skin; +} modelstate_t; + +typedef struct decallist_s +{ + vec3_t position; + char name[64]; + short entityIndex; + byte depth; + byte flags; + float scale; + + // this is the surface plane that we hit so that + // we can move certain decals across + // transitions if they hit similar geometry + vec3_t impactPlaneNormal; + + modelstate_t studio_state; // studio decals only +} decallist_t; + +typedef struct render_api_s +{ + // Get renderer info (doesn't changes engine state at all) + int (*RenderGetParm)( int parm, int arg ); // generic + void (*GetDetailScaleForTexture)( int texture, float *xScale, float *yScale ); + void (*GetExtraParmsForTexture)( int texture, byte *red, byte *green, byte *blue, byte *alpha ); + lightstyle_t* (*GetLightStyle)( int number ); + dlight_t* (*GetDynamicLight)( int number ); + dlight_t* (*GetEntityLight)( int number ); + byte (*TextureToTexGamma)( byte color ); // software gamma support + void (*GetBeamChains)( BEAM ***active_beams, BEAM ***free_beams, particle_t ***free_trails ); + + // Set renderer info (tell engine about changes) + void (*R_SetCurrentEntity)( struct cl_entity_s *ent ); // tell engine about both currententity and currentmodel + void (*R_SetCurrentModel)( struct model_s *mod ); // change currentmodel but leave currententity unchanged + void (*GL_SetWorldviewProjectionMatrix)( const float *glmatrix ); // update viewprojection matrix (tracers uses it) + void (*R_StoreEfrags)( struct efrag_s **ppefrag, int framecount );// store efrags for static entities + + // Texture tools + int (*GL_FindTexture)( const char *name ); + const char* (*GL_TextureName)( unsigned int texnum ); + const byte* (*GL_TextureData)( unsigned int texnum ); // may be NULL + int (*GL_LoadTexture)( const char *name, const byte *buf, size_t size, int flags ); + int (*GL_CreateTexture)( const char *name, int width, int height, const void *buffer, int flags ); + void (*GL_SetTextureType)( unsigned int texnum, unsigned int type ); + void (*GL_TextureCacheFrame)( unsigned int texnum ); + void (*GL_FreeTexture)( unsigned int texnum ); + + // Decals manipulating (draw & remove) + void (*DrawSingleDecal)( struct decal_s *pDecal, struct msurface_s *fa ); + float *(*R_DecalSetupVerts)( struct decal_s *pDecal, struct msurface_s *surf, int texture, int *outCount ); + void (*R_EntityRemoveDecals)( struct model_s *mod ); // remove all the decals from specified entity (BSP only) + + // AVIkit support + void *(*AVI_LoadVideo)( const char *filename, int ignore_hwgamma ); + int (*AVI_GetVideoInfo)( void *Avi, long *xres, long *yres, float *duration ); + int (*AVI_GetVideoFrameNumber)( void *Avi, float time ); + byte *(*AVI_GetVideoFrame)( void *Avi, long frame ); + void (*AVI_UploadRawFrame)( int texture, int cols, int rows, int width, int height, const byte *data ); + void (*AVI_FreeVideo)( void *Avi ); + int (*AVI_IsActive)( void *Avi ); + + // glState related calls (must use this instead of normal gl-calls to prevent de-synchornize local states between engine and the client) + void (*GL_Bind)( int tmu, unsigned int texnum ); + void (*GL_SelectTexture)( int tmu ); + void (*GL_LoadTextureMatrix)( const float *glmatrix ); + void (*GL_TexMatrixIdentity)( void ); + void (*GL_CleanUpTextureUnits)( int last ); // pass 0 for clear all the texture units + void (*GL_TexGen)( unsigned int coord, unsigned int mode ); + void (*GL_TextureTarget)( unsigned int target ); // change texture unit mode without bind texture + void (*GL_TexCoordArrayMode)( unsigned int texmode ); + void (*GL_Reserved0)( void ); // for potential interface expansion without broken compatibility + void (*GL_Reserved1)( void ); + void (*GL_Reserved2)( void ); + void (*GL_Reserved3)( void ); + + // Misc renderer functions + void (*GL_DrawParticles)( const float *vieworg, const float *fwd, const float *rt, const float *up, unsigned int clipFlags ); + void (*EnvShot)( const float *vieworg, const char *name, qboolean skyshot, int shotsize ); // creates a cubemap or skybox into gfx\env folder + int (*COM_CompareFileTime)( const char *filename1, const char *filename2, int *iCompare ); + void (*Host_Error)( const char *error, ... ); // cause Host Error + int (*SPR_LoadExt)( const char *szPicName, unsigned int texFlags ); // extended version of SPR_Load + void (*TessPolygon)( struct msurface_s *surf, struct model_s *mod, float tessSize ); + struct mstudiotex_s *( *StudioGetTexture )( struct cl_entity_s *e ); + const struct ref_overview_s *( *GetOverviewParms )( void ); + void (*S_FadeMusicVolume)( float fadePercent ); // fade background track (0-100 percents) + void (*SetRandomSeed)( long lSeed ); // set custom seed for RANDOM_FLOAT\RANDOM_LONG for predictable random + // static allocations + void *(*pfnMemAlloc)( size_t cb, const char *filename, const int fileline ); + void (*pfnMemFree)( void *mem, const char *filename, const int fileline ); + // find in files + char **(*pfnGetFilesList)( const char *pattern, int *numFiles, int gamedironly ); + // ONLY ADD NEW FUNCTIONS TO THE END OF THIS STRUCT. INTERFACE VERSION IS FROZEN AT 35 +} render_api_t; + +// render callbacks +typedef struct render_interface_s +{ + int version; + // passed through R_RenderFrame (0 - use engine renderer, 1 - use custom client renderer) + int (*GL_RenderFrame)( const struct ref_params_s *pparams, qboolean drawWorld ); + // build all the lightmaps on new level or when gamma is changed + void (*GL_BuildLightmaps)( void ); + // setup map bounds for ortho-projection when we in dev_overview mode + void (*GL_OrthoBounds)( const float *mins, const float *maxs ); + // handle decals which hit mod_studio or mod_sprite + void (*R_StudioDecalShoot)( int decalTexture, struct cl_entity_s *ent, const float *start, const float *pos, int flags, modelstate_t *state ); + // prepare studio decals for save + int (*R_CreateStudioDecalList)( decallist_t *pList, int count, qboolean changelevel ); + // clear decals by engine request (e.g. for demo recording or vid_restart) + void (*R_ClearStudioDecals)( void ); + // grab r_speeds message + qboolean (*R_SpeedsMessage)( char *out, size_t size ); + // replace with built-in R_DrawCubemapView for make skyshots or envshots + qboolean (*R_DrawCubemapView)( const float *origin, const float *angles, int size ); + // alloc or destroy studiomodel custom data + void (*Mod_ProcessUserData)( struct model_s *mod, qboolean create, const byte *buffer ); +} render_interface_t; + +#endif//RENDER_API_H diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/screenfade.h b/Projects/Android/jni/src/Xash3D/xash3d/common/screenfade.h new file mode 100644 index 0000000..730f729 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/screenfade.h @@ -0,0 +1,29 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef SCREENFADE_H +#define SCREENFADE_H + +typedef struct screenfade_s +{ + float fadeSpeed; // How fast to fade (tics / second) (+ fade in, - fade out) + float fadeEnd; // When the fading hits maximum + float fadeTotalEnd; // Total End Time of the fade (used for FFADE_OUT) + float fadeReset; // When to reset to not fading (for fadeout and hold) + byte fader, fadeg, fadeb, fadealpha; // Fade color + int fadeFlags; // Fading flags +} screenfade_t; + +#endif//SCREENFADE_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/studio_event.h b/Projects/Android/jni/src/Xash3D/xash3d/common/studio_event.h new file mode 100644 index 0000000..29ea1f9 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/studio_event.h @@ -0,0 +1,27 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef STUDIO_EVENT_H +#define STUDIO_EVENT_H + +typedef struct mstudioevent_s +{ + int frame; + int event; + int type; + char options[64]; +} mstudioevent_t; + +#endif//STUDIO_EVENT_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/triangleapi.h b/Projects/Android/jni/src/Xash3D/xash3d/common/triangleapi.h new file mode 100644 index 0000000..f83c7ff --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/triangleapi.h @@ -0,0 +1,62 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef TRIANGLEAPI_H +#define TRIANGLEAPI_H + +typedef enum +{ + TRI_FRONT = 0, + TRI_NONE = 1, +} TRICULLSTYLE; + +#define TRI_API_VERSION 1 + +#define TRI_TRIANGLES 0 +#define TRI_TRIANGLE_FAN 1 +#define TRI_QUADS 2 +#define TRI_POLYGON 3 +#define TRI_LINES 4 +#define TRI_TRIANGLE_STRIP 5 +#define TRI_QUAD_STRIP 6 +#define TRI_POINTS 7 // Xash3D added + +typedef struct triangleapi_s +{ + int version; + + void (*RenderMode)( int mode ); + void (*Begin)( int primitiveCode ); + void (*End)( void ); + + void (*Color4f)( float r, float g, float b, float a ); + void (*Color4ub)( unsigned char r, unsigned char g, unsigned char b, unsigned char a ); + void (*TexCoord2f)( float u, float v ); + void (*Vertex3fv)( float *worldPnt ); + void (*Vertex3f)( float x, float y, float z ); + void (*Brightness)( float brightness ); + void (*CullFace)( TRICULLSTYLE style ); + int (*SpriteTexture)( struct model_s *pSpriteModel, int frame ); + int (*WorldToScreen)( float *world, float *screen ); // Returns 1 if it's z clipped + void (*Fog)( float flFogColor[3], float flStart, float flEnd, int bOn ); //Works just like GL_FOG, flFogColor is r/g/b. + void (*ScreenToWorld)( float *screen, float *world ); + void (*GetMatrix)( const int pname, float *matrix ); + int (*BoxInPVS)( float *mins, float *maxs ); + void (*LightAtPoint)( float *pos, float *value ); + void (*Color4fRendermode)( float r, float g, float b, float a, int rendermode ); + void (*FogParams)( float flDensity, int iFogSkybox ); +} triangleapi_t; + +#endif//TRIANGLEAPI_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/usercmd.h b/Projects/Android/jni/src/Xash3D/xash3d/common/usercmd.h new file mode 100644 index 0000000..96e3c91 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/usercmd.h @@ -0,0 +1,39 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef USERCMD_H +#define USERCMD_H + +typedef struct usercmd_s +{ + short lerp_msec; // Interpolation time on client + byte msec; // Duration in ms of command + vec3_t viewangles; // Command view angles + + // intended velocities + float forwardmove; // Forward velocity + float sidemove; // Sideways velocity + float upmove; // Upward velocity + byte lightlevel; // Light level at spot where we are standing. + unsigned short buttons; // Attack and move buttons + byte impulse; // Impulse command issued + byte weaponselect; // Current weapon id + + // Experimental player impact stuff. + int impact_index; + vec3_t impact_position; +} usercmd_t; + +#endif//USERCMD_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/wadfile.h b/Projects/Android/jni/src/Xash3D/xash3d/common/wadfile.h new file mode 100644 index 0000000..ae85648 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/wadfile.h @@ -0,0 +1,96 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef WADFILE_H +#define WADFILE_H + +/* +======================================================================== +.WAD archive format (WhereAllData - WAD) + +List of compressed files, that can be identify only by TYPE_* + + +header: dwadinfo_t[dwadinfo_t] +file_1: byte[dwadinfo_t[num]->disksize] +file_2: byte[dwadinfo_t[num]->disksize] +file_3: byte[dwadinfo_t[num]->disksize] +... +file_n: byte[dwadinfo_t[num]->disksize] +infotable dlumpinfo_t[dwadinfo_t->numlumps] +======================================================================== +*/ + +#define IDWAD3HEADER (('3'<<24)+('D'<<16)+('A'<<8)+'W') + +// dlumpinfo_t->attribs +#define ATTR_NONE 0 // allow to read-write +#define ATTR_READONLY BIT( 0 ) // don't overwrite this lump in anyway +#define ATTR_COMPRESSED BIT( 1 ) // not used for now, just reserved +#define ATTR_HIDDEN BIT( 2 ) // not used for now, just reserved +#define ATTR_SYSTEM BIT( 3 ) // not used for now, just reserved + +// dlumpinfo_t->type +#define TYP_ANY -1 // any type can be accepted +#define TYP_NONE 0 // unknown lump type +#define TYP_LABEL 1 // legacy from Doom1. Empty lump - label (like P_START, P_END etc) +#define TYP_PALETTE 64 // quake or half-life palette (768 bytes) +#define TYP_DDSTEX 65 // contain DDS texture +#define TYP_GFXPIC 66 // menu or hud image (not contain mip-levels) +#define TYP_MIPTEX 67 // quake1 and half-life in-game textures with four miplevels +#define TYP_RAWDATA 68 // never was used but may contain any data +#define TYP_COLORMAP2 69 // old stuff. build palette from LBM file (not used) +#define TYP_QFONT 70 // half-life font (qfont_t) + +// dlumpinfo_t->img_type +#define IMG_DIFFUSE 0 // same as default pad1 always equal 0 +#define IMG_ALPHAMASK 1 // alpha-channel that stored separate as luminance texture +#define IMG_NORMALMAP 2 // indexed normalmap +#define IMG_GLOSSMAP 3 // luminance or color specularity map +#define IMG_GLOSSPOWER 4 // gloss power map (each value is a specular pow) +#define IMG_HEIGHTMAP 5 // heightmap (for parallax occlusion mapping or source of normalmap) +#define IMG_LUMA 6 // luma or glow texture with self-illuminated parts +#define IMG_DECAL_ALPHA 7 // it's a decal texture (last color in palette is base color, and other colors his graduations) +#define IMG_DECAL_COLOR 8 // decal without alpha-channel uses base, like 127 127 127 as transparent color + +/* +======================================================================== + +.LMP image format (Half-Life gfx.wad lumps) + +======================================================================== +*/ +typedef struct lmp_s +{ + unsigned int width; + unsigned int height; +} lmp_t; + +/* +======================================================================== + +.MIP image format (half-Life textures) + +======================================================================== +*/ +typedef struct mip_s +{ + char name[16]; + unsigned int width; + unsigned int height; + unsigned int offsets[4]; // four mip maps stored +} mip_t; + +#endif//WADFILE_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/weaponinfo.h b/Projects/Android/jni/src/Xash3D/xash3d/common/weaponinfo.h new file mode 100644 index 0000000..ae78c64 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/weaponinfo.h @@ -0,0 +1,50 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef WEAPONINFO_H +#define WEAPONINFO_H + +// Info about weapons player might have in his/her possession +typedef struct weapon_data_s +{ + int m_iId; + int m_iClip; + + float m_flNextPrimaryAttack; + float m_flNextSecondaryAttack; + float m_flTimeWeaponIdle; + + int m_fInReload; + int m_fInSpecialReload; + float m_flNextReload; + float m_flPumpTime; + float m_fReloadTime; + + float m_fAimedDamage; + float m_fNextAimBonus; + int m_fInZoom; + int m_iWeaponState; + + int iuser1; + int iuser2; + int iuser3; + int iuser4; + float fuser1; + float fuser2; + float fuser3; + float fuser4; +} weapon_data_t; + +#endif//WEAPONINFO_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/wrect.h b/Projects/Android/jni/src/Xash3D/xash3d/common/wrect.h new file mode 100644 index 0000000..48d6182 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/wrect.h @@ -0,0 +1,29 @@ +/* +wrect.h - rectangle definition +Copyright (C) 2010 Uncle Mike + +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 3 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. +*/ + +#ifndef WRECT_H +#define WRECT_H + +typedef struct wrect_s +{ + int left, right, top, bottom; +} wrect_t; + +typedef struct rectf_s +{ + float x, y, w, h; +} rectf_t; + +#endif //WRECT_H \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/xash3d_types.h b/Projects/Android/jni/src/Xash3D/xash3d/common/xash3d_types.h new file mode 100644 index 0000000..1896622 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/xash3d_types.h @@ -0,0 +1,33 @@ +// basic typedefs +#ifndef XASH_TYPES_H +#define XASH_TYPES_H +typedef unsigned char byte; +typedef int sound_t; +typedef float vec_t; +typedef vec_t vec2_t[2]; +typedef vec_t vec3_t[3]; +typedef vec_t vec4_t[4]; +typedef vec_t quat_t[4]; +typedef byte rgba_t[4]; // unsigned byte colorpack +typedef byte rgb_t[3]; // unsigned byte colorpack +typedef vec_t matrix3x4[3][4]; +typedef vec_t matrix4x4[4][4]; + +#undef true +#undef false + +#ifndef __cplusplus +typedef enum { false, true } qboolean; +#else +typedef int qboolean; +#endif + +#if _MSC_VER == 1200 +typedef __int64 integer64; //msvc6 +#elif defined (XASH_SDL) +typedef Uint64 integer64; +#else +typedef unsigned long long integer64; +#endif +typedef integer64 longtime_t; +#endif // XASH_TYPES_H diff --git a/Projects/Android/jni/src/Xash3D/xash3d/contrib/mittorn/Makefile.dllloader b/Projects/Android/jni/src/Xash3D/xash3d/contrib/mittorn/Makefile.dllloader new file mode 100644 index 0000000..21756a3 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/contrib/mittorn/Makefile.dllloader @@ -0,0 +1,37 @@ +CC = gcc -m32 +CXX = g++ -m32 +CFLAGS ?= -mstackrealign -mpreferred-stack-boundary=12 -ggdb -O0 -fPIC +TOPDIR = $(PWD)/.. +INCLUDES = -I. -I$(PWD) +DEFINES = +#DEFINES = -DNOEXEC + +ifneq ($(NOSDL),1) + DEFINES += -DSDL +endif + +%.o : %.c + $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< -o $@ + +SRCS = $(wildcard *.c) +OBJS = $(SRCS:.c=.o) + +libloader.so : $(OBJS) + $(CC) $(LDFLAGS) -o libloader.so -shared $(OBJS) -lm + + +libloader.a: $(OBJS) + $(AR) rcs libloader.a $(OBJS) + +.PHONY: depend clean + +clean : + $(RM) $(OBJS) libloader.so + +depend: Makefile.dep + +Makefile.dep: $(SRCS) + rm -f ./Makefile.dep + $(CC) $(CFLAGS) $(filter-out -I/usr/include/SDL2,$(INCLUDES)) $(filter-out -DXASH_SDL,$(DEFINES)) -MM $^>>./Makefile.dep + +include Makefile.dep diff --git a/Projects/Android/jni/src/Xash3D/xash3d/contrib/mittorn/Makefile.emscripten b/Projects/Android/jni/src/Xash3D/xash3d/contrib/mittorn/Makefile.emscripten new file mode 100644 index 0000000..b39fba1 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/contrib/mittorn/Makefile.emscripten @@ -0,0 +1,170 @@ +############################################# +# Makefile.emscripten - Xash3D Emscripten port +# Copyright (C) 2017 mittorn + +# 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 3 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. +############################################## + + +CC = ~/emscripten/emcc --llvm-lto 3 -s INLINING_LIMIT=10 -s USE_SDL=2 +CXX = ~/emscripten/em++ --llvm-lto 3 -s INLINING_LIMIT=10 -s USE_SDL=2 +# async mode - produces very large scripts. Unuseful with shared libraries +ASYNC ?= 0 + +OUTPUT_DIR ?= xash-em + +XASH_COMMIT := $(firstword $(shell git rev-parse --short=6 HEAD) unknown) + +ifeq ($(XASH_COMMIT),unknown) +$(warning You seems to build xash3d without git) +$(warning Please use git if you are going to publish your build) +endif + +# emscripten port only works with gl-wes-v2 (WebGL is GLES2) +WES = 1 + +ifeq ($(EMSCRIPTEN_SIMD),1) + SIMD_SUF=-simd + CC += -s SIMD=1 + CXX += -s SIMD=1 +endif +CFLAGS =-Os -g0 -Wall -Wextra -Wsign-compare -Wno-unknown-pragmas -Wno-missing-field-initializers -Wno-unused-parameter +obj/common/launcher.o : override CFLAGS = -O0 -g0 +LDFLAGS = +LIBS = -lm +LBITS := $(shell getconf LONG_BIT) +ifneq ($(64BIT),1) + ifeq ($(LBITS),64) + LDFLAGS += -m32 + CFLAGS += -m32 + endif +endif +TOPDIR = $(PWD)/.. +INCLUDES := +XASH_SINGLE_BINARY ?= 1 +INSTALL_DIR ?= ./install/ +ifeq ($(NANOGL),1) +INCLUDES += -Inanogl -Inanogl/GL +endif +ifeq ($(WES),1) +INCLUDES += -Inanogl -Inanogl/GL -Igl-wes-v2/src +endif +INCLUDES += -Icommon -I../common -I. -I../pm_shared -Iclient -Iserver -Iclient/vgui -Icommon/sdl + +DEFINES = -DDEFAULT_DEV=5 -DXASH_SDL_DISABLE_RESIZE -DDEFAULT_MODE_WIDTH=640 -DDEFAULT_MODE_HEIGHT=480 -DDEFAULT_FULLSCREEN=0 -DWES_WEBGL -DXASH_ALLOW_SAVERESTORE_OFFSETS -DUSE_STB_SPRINTF=0 -DNO_SJLJ + +# Specify commit hash in version string +DEFINES += -DXASH_BUILD_COMMIT=\"$(XASH_COMMIT)\" + +ifeq ($(ASYNC),1) +DEFINES += -DEMSCRIPTEN_ASYNC +CXX += -s ASYNCIFY=1 +else +DEFINES += -DNO_SJLJ +endif +ifneq ($(64BIT),1) +DEFINES += -DXASH_FASTSTR +endif +ifeq ($(XASH_DEDICATED),1) + DEFINES += -DXASH_DEDICATED +else + DEFINES += -DXASH_SDL + LIBS += -pthread +endif + +ifeq ($(NANOGL),1) +DEFINES += -DXASH_NANOGL -DXASH -D__MULTITEXTURE_SUPPORT__ -DEGL_LIB=\"libEGL.so\" +endif +ifeq ($(WES),1) +DEFINES += -DXASH_WES -D__MULTITEXTURE_SUPPORT__ -DEGL_LIB=\"libEGL.so\" +endif +# Some libc implementations cannot use libdl, so disable it by default +ifeq ($(XASH_STATIC),1) + + ifneq ($(XASH_STATIC_LIBDL),1) + DEFINES += -DNO_LIBDL + endif + + XASH_SINGLE_BINARY := 1 +endif + +ifeq ($(XASH_DLL_LOADER),1) + DEFINES += -DDLL_LOADER + ifeq ($(XASH_SINGLE_BINARY),1) + LIBS += libloader.a -pthread -lm + else + LIBS += libloader.so + endif +endif + +ifeq ($(XASH_SINGLE_BINARY),1) + DEFINES += -DSINGLE_BINARY +endif + +ifeq ($(XASH_VGUI),1) + DEFINES += -DXASH_VGUI +endif + + +SRCS_CPP = +SRCS_C = + +#ifeq ($(XASH_VGUI),1) +# SRCS_CPP += $(wildcard client/vgui/*.cpp) +#endif + +ifeq ($(NANOGL),1) +SRCS_CPP += $(wildcard nanogl/*.cpp) +endif +ifeq ($(WES),1) +SRCS += $(wildcard gl-wes-v2/src/*.c) +endif +OBJS_CPP = $(patsubst %.cpp,obj/%.o,$(SRCS_CPP)) +SRCS += $(wildcard server/*.c) $(wildcard client/vgui/*.c) $(wildcard common/*.c) $(wildcard common/imagelib/*.c) $(wildcard common/soundlib/*.c) $(wildcard common/soundlib/libmpg/*.c) +ifneq ($(XASH_DEDICATED),1) +SRCS += $(wildcard client/*.c) +SRCS += $(wildcard platform/sdl/*.c) +endif +OBJS = $(patsubst %.c,obj/%.o,$(SRCS)) + +$(OUTPUT_DIR)/xash$(SIMD_SUF).html: $(OBJS) $(OBJS_CPP) platform/emscripten/shell.html + EMCC_FORCE_STDLIBS=1 $(CXX) -O3 --js-opts 1 -s INLINING_LIMIT=10 -s ELIMINATE_DUPLICATE_FUNCTIONS=1 -s AGGRESSIVE_VARIABLE_ELIMINATION=1 -s LEGACY_GL_CREATE_RESOURCE_ON_BIND=1 -s UNALIGNED_ACCESS_FUNCTION_LIST=\"platform/emscripten/unaligned.txt\" --shell-file platform/emscripten/shell.html -s NO_EXIT_RUNTIME=0 -s LZ4=1 -s -g0 -o "$@" -s MAIN_MODULE=1 -s TOTAL_MEMORY=150994944 -fvisibility=hidden $(LDFLAGS) $(OBJS) $(OBJS_CPP) $(LIBS) + + + +DIRS := obj obj/server obj/client/vgui obj/common/sdl obj/common/imagelib obj/common/soundlib/libmpg obj/platform/sdl obj/nanogl obj/gl-wes-v2/src $(OUTPUT_DIR) + + +$(OBJS): | $(DIRS) + +$(DIRS) : + mkdir -p $(DIRS) +obj/%.o : %.c + $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c "$<" -o "$@" -Wno-unused-result -fvisibility=hidden + +obj/%.o : %.cpp + $(CXX) $(CFLAGS) $(INCLUDES) $(DEFINES) -c "$<" -o "$@" + + +default: $(BINARIES) + +.PHONY: depend clean list install + +clean: + $(RM) $(OBJS) $(OBJS_CPP) $(BINARIES) + +list: + @echo Sources: + @echo $(SRCS) + @echo C++ Sources: + @echo $(SRCS_CPP) + @echo Objects: + @echo $(OBJS) $(OBJS_CPP) diff --git a/Projects/Android/jni/src/Xash3D/xash3d/contrib/mittorn/Makefile.linux b/Projects/Android/jni/src/Xash3D/xash3d/contrib/mittorn/Makefile.linux new file mode 100644 index 0000000..851e730 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/contrib/mittorn/Makefile.linux @@ -0,0 +1,223 @@ +############################################# +# Makefile.linux - linux makefile +# Copyright (C) 2017 mittorn + +# 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 3 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. +############################################## + +# Default options - optimized to debug on local machine +CC ?= gcc +CXX ?= g++ +CFLAGS ?= -DDEBUG_RESOLVE -g -O2 -march=native -fno-omit-frame-pointer -ggdb -funsigned-char -Wall -Wextra -Wsign-compare -Wno-unknown-pragmas -Wno-missing-field-initializers -Wno-unused-parameter -Wno-unused-but-set-variable +LDFLAGS = +LBITS := $(shell getconf LONG_BIT) +DEPS := + +XASH_COMMIT := $(firstword $(shell git rev-parse --short=6 HEAD) unknown) + +ifeq ($(XASH_COMMIT),unknown) +$(warning You seems to build xash3d without git) +$(warning Please use git if you are going to publish your build) +endif + +# Pass 64BIT=1 to make arguments to allow amd64 builds +ifneq ($(64BIT),1) + ifeq ($(LBITS),64) + LDFLAGS += -m32 + CFLAGS += -m32 + endif +endif + +TOPDIR = $(PWD)/.. +INCLUDES := +XASH_SINGLE_BINARY ?= 1 +INSTALL_DIR ?= ./install/ +ifeq ($(NANOGL),1) +INCLUDES += -Inanogl -Inanogl/GL +endif +INCLUDES += -I/usr/include/SDL2 -Icommon -I../common -I. -I../pm_shared -Iclient -Iserver -Iclient/vgui -Icommon/sdl + +############################# +# Preprocessor defines: +############################# +# USE_SELECT - allow asynchronous stdin console input +# COLORIZE_CONSOLE - enable ANSI console colors +# DEBUGNAN - report NaN errors in server physics +# XASH_FORCEINLINE - make crtlib functions inlined +# GDB_BREAK - add TRAP's on errors when GDB detected +############################# +DEFINES = -DUSE_SELECT -DCOLORIZE_CONSOLE -DDEBUGNAN -DXASH_FORCEINLINE -DGDB_BREAK + +# Specify commit hash in version string +ifneq ($(XASH_RELEASE),1) +DEFINES += -DXASH_BUILD_COMMIT=\"$(XASH_COMMIT)\" +else +DEFINES += -DXASH_RELEASE +endif + +# Enable optimized crt functions for 32-bit systems +ifneq ($(64BIT),1) +DEFINES += -DXASH_FASTSTR +endif + + +# Only SDL backend exists on linux +ifeq ($(XASH_DEDICATED),1) + DEFINES += -DXASH_DEDICATED +# Enable debug messages in resolve thread + DEFINES += -DDEBUG_RESOLVE +else + DEFINES += -DXASH_SDL + LIBS += -lSDL2 +endif + +############################################# +# GL/GLES translators. +# You need clone it to engine folder to use +# Only one translator should be enabled +############################################# +ifeq ($(NANOGL),1) +DEFINES += -DXASH_NANOGL -D__MULTITEXTURE_SUPPORT__ -DEGL_LIB=\"libEGL.so\" +endif + +ifeq ($(WES),1) +DEFINES += -DXASH_WES -D__MULTITEXTURE_SUPPORT__ -DEGL_LIB=\"libEGL.so\" +endif + +ifeq ($(REGAL),1) +DEFINES += -DXASH_REGAL -D__MULTITEXTURE_SUPPORT__ -DEGL_LIB=\"regal/lib/linux-32/libRegal.so\" +LIBS += regal/lib/linux-32/libRegal.so +endif + +# Some libc implementations cannot use libdl, so disable it by default +ifeq ($(XASH_STATIC),1) + + ifneq ($(XASH_STATIC_LIBDL),1) + DEFINES += -DNO_LIBDL + endif + + XASH_SINGLE_BINARY := 1 +endif + +ifneq ($(XASH_STATIC),1) + LIBS += -ldl +endif + +ifeq ($(XASH_STATIC_LIBDL),1) + LIBS += -ldl +endif + +LIBS += -lm -pthread + + +ifeq ($(XASH_SINGLE_BINARY),1) + DEFINES += -DSINGLE_BINARY +endif + +# Collect files +SRCS_CPP = +SRCS = $(wildcard server/*.c) $(wildcard client/vgui/*.c) $(wildcard common/*.c) $(wildcard common/imagelib/*.c) $(wildcard common/soundlib/*.c) $(wildcard common/soundlib/libmpg/*.c) +ifneq ($(XASH_DEDICATED),1) + SRCS += $(wildcard client/*.c) + SRCS += $(wildcard platform/sdl/*.c) + ifeq ($(WES),1) + SRCS += $(wildcard gl-wes-v2/src/*.c) + endif + ifeq ($(NANOGL),1) + SRCS_CPP += $(wildcard nanogl/*.cpp) + endif +endif +OBJS = $(patsubst %.c,obj/%.o,$(SRCS)) +OBJS_CPP = $(patsubst %.cpp,obj/%.o,$(SRCS_CPP)) + +################################# +# Windows DLL loader +# Should be enabled only on i386 builds +################################# +LOADER := +ifeq ($(XASH_DLL_LOADER),1) + DEFINES += -DDLL_LOADER + ifeq ($(XASH_SINGLE_BINARY),1) + LOADER = libloader.a + else + LOADER = libloader.so + endif + DEPS += $(LOADER) + LIBS += $(LOADER) +endif + +# Rules for binaries +ifeq ($(XASH_SINGLE_BINARY),0) + BINARIES = libxash.so +libxash.so : $(OBJS) $(OBJS_CPP) $(DEPS) + $(CC) -fvisibility=hidden -o libxash.so $(LDFLAGS) -shared $(OBJS) $(OBJS_CPP) $(LIBS) + +else +BINARIES = xash +xash: $(OBJS) $(OBJS_CPP) $(DEPS) +ifeq ($(XASH_STATIC),1) + $(CC) -o xash -static $(LDFLAGS) $(OBJS) $(OBJS_CPP) $(LIBS) +else + $(CC) -o xash -fvisibility=hidden $(LDFLAGS) $(OBJS) $(OBJS_CPP) $(LIBS) +endif + +endif + +ifeq ($(XASH_DLL_LOADER),1) +$(LOADER): + $(MAKE) -f ../loader/Makefile.dllloader -C ../loader $(LOADER) + cp ../loader/$(LOADER) . +endif + +# Create dirs for object files +DIRS := obj obj/server obj/client/vgui obj/common/sdl obj/common/imagelib obj/common/soundlib/libmpg obj/platform/sdl obj/nanogl +$(OBJS): | $(DIRS) + +$(DIRS) : + mkdir -p $(DIRS) + +# Object rules +obj/%.o : %.c + $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c "$<" -o "$@" -Wno-unused-result -fvisibility=hidden + +obj/%.o : %.cpp + $(CXX) $(CFLAGS) $(INCLUDES) $(DEFINES) -c "$<" -o "$@" + + +default: $(BINARIES) + +.PHONY: depend clean list install + +clean: + $(RM) $(OBJS) $(OBJS_CPP) $(BINARIES) ../loader/*.o ../loader/*.a ../loader/*.so $(LOADER) + +list: + @echo Sources: + @echo $(SRCS) + @echo C++ Sources: + @echo $(SRCS_CPP) + @echo Objects: + @echo $(OBJS) $(OBJS_CPP) + @echo Dirs: + @echo $(DIRS) + @echo Dependencies: + @echo $(DEPS) + +# Simple install rule +install: $(BINARIES) + mkdir -p $(INSTALL_DIR) + +ifeq ($(XASH_SINGLE_BINARY),1) + cp xash $(INSTALL_DIR)/xash_bin +else + cp libxash.so $(INSTALL_DIR)/ + cp libloader.so $(INSTALL_DIR)/ +endif diff --git a/Projects/Android/jni/src/Xash3D/xash3d/contrib/mittorn/Makefile.mingw b/Projects/Android/jni/src/Xash3D/xash3d/contrib/mittorn/Makefile.mingw new file mode 100644 index 0000000..80ec93d --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/contrib/mittorn/Makefile.mingw @@ -0,0 +1,135 @@ +############################################# +# Makefile.mingw - mingw makefile +# Copyright (C) 2017 mittorn + +# 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 3 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. +############################################## + +CC ?= gcc +CXX ?= g++ + +# Workaround wrong default mingw32-make configuration ($(CC) does not exist) +ifeq ($(CC),cc) + CC = gcc +endif + +# Optimized build +CFLAGS = -DDEBUG_RESOLVE -DVECTORIZE_SINCOS -O2 -fno-omit-frame-pointer -ggdb -funsafe-loop-optimizations -funsafe-math-optimizations -msse2 -msse3 -ftree-vectorize -mstackrealign -mpreferred-stack-boundary=4 -finline-limit=512 -march=i686 +LDFLAGS = + +XASH_COMMIT := $(firstword $(shell git rev-parse --short=6 HEAD) unknown) + +ifeq ($(XASH_COMMIT),unknown) +$(warning You seems to build xash3d without git) +$(warning Please use git if you are going to publish your build) +endif + +# detect 64bit mingw +MACHINE := $(shell $(CC) -dumpmachine) +ifneq ($(64BIT),1) + ifeq ($(MACHINE),x86_64-w64-mingw32) + LDFLAGS += -m32 -L$(SDL_DIR)/i686-w64-mingw32/lib + CFLAGS += -m32 -I$(SDL_DIR)/i686-w64-mingw32/include/SDL2 + endif +else + LDFLAGS += -L$(SDL_DIR)/x86_64-w64-mingw32/lib + CFLAGS += -I$(SDL_DIR)/x86_64-w64-mingw32/include/SDL2 +endif + +# You should download SDL2 mingw +# development libraries to use non-dedicated mode +SDL_DIR ?= ../SDL2 + +LIBS = -lm +TOPDIR = $(PWD)/.. +INCLUDES = -I$(SDL_DIR)/include -Icommon -I../common -Iserver -Iclient -Iclient/vgui -I. -I../pm_shared +DEFINES = + +# win32 dependencies configuration +ifeq ($(XASH_DEDICATED),1) + DEFINES += -DXASH_DEDICATED + LIBS += -luser32 -lkernel32 -lgdi32 -ldbghelp -lpsapi +else + DEFINES += -DXASH_SDL + LIBS += -lSDL2 -L$(SDL_DIR)/lib/x86 -L$(SDL_DIR)/lib/x64 -luser32 -lkernel32 -lgdi32 -ldbghelp -lpsapi +endif + +# nanogl core profile support (broken, unuseful) +ifeq ($(NANOGL),1) +INCLUDES += -I../nanogl -I../nanogl/GL +DEFINES += -DXASH_GLES -DXASH_NANOGL -DUSE_CORE_PROFILE +LIBS += -lstdc++ +endif +############################# +# Preprocessor defines: +############################# +# USE_SELECT - allow asynchronous stdin console input +# COLORIZE_CONSOLE - enable ANSI console colors +# DEBUGNAN - report NaN errors in server physics +# XASH_FORCEINLINE - make crtlib functions inlined +# SINGLE_BINARY - tells to build xash_bin.exe instead of xash_sdl.dll +# XASH_W32CON - enable graphical win32 console +# DBGHELP - enable crashhandler with dbghelp library +############################# +DEFINES += -DSINGLE_BINARY -DXASH_FORCEINLINE -DXASH_W32CON -DDBGHELP + +ifneq ($(XASH_RELEASE),1) +# Specify commit hash in version string +DEFINES += -DXASH_BUILD_COMMIT=\"$(XASH_COMMIT)\" +else +DEFINES += -DXASH_RELEASE +endif + +# Enable optimized crt functions for 32-bit systems +ifneq ($(64BIT),1) +DEFINES += -DXASH_FASTSTR +endif + +# Object rules +%.o : %.c + $(CC) -pipe $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< -o $@ + +%.o : %.cpp + $(CXX) -pipe $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< -o $@ + + +# Collect files +SRCS_CPP = + +ifeq ($(NANOGL),1) + SRCS_CPP += $(wildcard ../nanogl/*.cpp) +endif + +OBJS_CPP = $(SRCS_CPP:.cpp=.o) +SRCS = $(wildcard server/*.c) $(wildcard client/vgui/*.c) $(wildcard common/*.c) $(wildcard common/imagelib/*.c) $(wildcard common/soundlib/*.c) $(wildcard common/soundlib/libmpg/*.c) $(wildcard platform/win32/*.c) +OBJS = $(SRCS:.c=.o) + + +ifneq ($(XASH_DEDICATED),1) + SRCS += $(wildcard client/*.c) + SRCS += $(wildcard platform/sdl/*.c) +endif + +# Binary rules +xash_bin.exe: $(OBJS) $(OBJS_CPP) + $(CC) -o xash_bin.exe $(LDFLAGS) $(OBJS) $(OBJS_CPP) $(LIBS) + +.PHONY: depend clean list +clean: + -$(RM) $(OBJS) $(OBJS_CPP) xash_bin.exe + -cmd /c del $(subst /,\,$(OBJS) $(OBJS_CPP) xash_bin.exe) +list: + @echo Sources: + @echo $(SRCS) + @echo C++ Sources: + @echo $(SRCS_CPP) + @echo Objects: + @echo $(OBJS) $(OBJS_CPP) diff --git a/Projects/Android/jni/src/Xash3D/xash3d/contrib/mittorn/README.md b/Projects/Android/jni/src/Xash3D/xash3d/contrib/mittorn/README.md new file mode 100644 index 0000000..289e3b1 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/contrib/mittorn/README.md @@ -0,0 +1,269 @@ +**Table of Contents** *generated with [DocToc](http://doctoc.herokuapp.com/)* + +- [Building](#building) + - [Manual build (without CMake)](#manual-build-without-cmake) + - [Building Engine](#building-engine) + - [Building launch binary](#building-launch-binary) + - [Building on Windows](#building-on-windows) + - [Visual Studio 2013 (recommended for Windows)](#visual-studio-2013-recommended-for-windows) + - [Visual Studio 6](#visual-studio-6) + - [MinGW](#mingw) + - [Building Game mods](#building-game-mods) + - [Linux](#linux) + - [microndk](#microndk) + - [Makefile.linux](#makefile-linux) + - [Windows](#windows) +- [Running](#running) + - [Manual running](#manual-running) + - [Running with GDB](#running-with-gdb) + - [Using DLL Loader](#using-dll-loader) + - [Running MinGW builds](#running-mingw-builds) + - [Running MinGW builds under GDB](#running-mingw-builds-under-gdb) + +# Building + +## Manual build (without CMake) + +### Building engine + +Clone Xash3D repository using git: + + git clone https://github.com/FWGS/xash3d + +Move to the Xash3D folder: + + cd xash3d/engine + + make -f Makefile.linux XASH_VGUI=1 + +or same for dedicated + + make -f Makefile.linux XASH_DEDICATED=1 + +To enable dll support on linux, build loader library: + + cd ../loader + make -f Makefile.linux libloader.so libloader.a + cp libloader.so libloader.a ../engine/ + +And built engine with XASH_DLL_LOADER=1: + + cd ../engine + make -f Makefile.linux XASH_VGUI=1 XASH_SDL=1 XASH_DLL_LOADER=1 + +or same for dedicated server + + cd ../engine + make -f Makefile.linux XASH_DEDICATED=1 XASH_DLL_LOADER=1 + +### Building engine in separate library + +Some old distros does not support hidden symbol visibility +This results in crash when loading server library + +Building launch binary + + cd (xash3d)/game_launch + gcc xash.c -o xash -ldl -lrt -lm + +Building engine library: + + make -f Makefile.linux XASH_SINGLE_BINARY=0 + +## Building on Windows + +### Visual Studio 2013 (recommended for Windows) + +Download latest prebuilt SDL2 from + +https://www.libsdl.org/release/SDL2-devel-2.0.4-VC.zip + +Unzip and rename `SDL2-2.0.4` folder to `SDL2` and put it next to xash3d project folder. + + ..\xash3d\ + ..\SDL2\ + +Open `xash.sln` with Visual Studio 2013 and make a build. After building, copy contents of `Debug` or +`Release` folder to directory you choose. Copy `valve` folder and `vgui.dll` from your Half Life game +installation folder and `SDL2.dll` form `\SDL2\lib\x86\` to it. +Move `vgui_support.dll` into `valve` folder. + + ..\valve\ + ..\valve\vgui_support.dll + ..\menu.dll + ..\SDL2.dll + ..\vgui.dll + ..\xash.dll + ..\xash.exe + +Now you good to go, just run `xash.exe`. + +### Visual Studio 6 + +This is legacy configuration, but msvc6 seems to generate more stable and more effective code + +Setup your msvc6 enviroment, unpack SDL2-2.0.4 to xash3d folder and do: + + cd (xash3d)\engine + ..\msvc6\build.bat + cd (xash3d)\game_launch + ..\msvc6\build_launch.bat + +### MinGW + +The most effective configuration, but maybe unstable. +Setup your MinGW environment and run: + + cd (xash3d)\engine\ + CC=gcc mingw32-make -f Makefile.mingw + + engine will be built to single exe binary + +## Building game mods + +### Linux + +#### microndk + +All mods that ported to android may be build to linux using Android.mk with microndk: + +[https://github.com/SDLash3D/microndk] + +Clone microndk repo somewhere, change xash3d_config to preffered configuration (change arch to x86 +for example) + +Go to dlls folder if you are building server or cl_dlls if you are building client and do: + + make -f /path/to/microndk/microndk.mk -j4 + +Do: + + make -f /path/to/microndk/microndk.mk -j4 clean + +every time when you build client after building server + +#### Makefile.linux + +### Windows + +On windows common way is using Visual Studio as many mods does not correctly work with mingw. + +Just open project and build it. + +Other is using mingw and microndk, but it was not tested yet. + +hlsdk-xash3d based mods may work fine with mingw. + +You may use microndk to build it. Build process is very similar to linux one. + +After setting up MinGW enviroment, do:
+`mingw32-make -f \path\to\microndk\Microndk.mk` + +to build 64-bit library, use:
+`mingw32-make -f \path\to\microndk\Microndk.mk 64BIT=1` + +Edit xash3d_config.mk to set optimal CFLAGS if you are running server + +# Running + +Copy **valve** folder from Half-Life: + + cp -r $HOME/.steam/steam/steamapps/common/Half-Life/valve $HOME/Games/Xash3D + +**NOTE**: If you build with CMake, you can now use `make install`. It will install binaries where +they must be located. So just run `xash3d` from command line in directory where is gamedata is located. +For additional info look to the CMakeLists.txt in repo root and xash3d.sh script. + +After a successful build, copy the next files to some other directory where you want to run Xash3D: + + cp engine/libxash.so game_launch/xash3d mainui/libxashmenu.so $HOME/Games/Xash3D + +If you built it with XASH_VGUI, also copy vgui.so: + + cp ../hlsdk/linux/vgui.so vgui_support/libvgui_support.so $HOME/Games/Xash3D + +Copy script: + + cp ../xash3d.sh $HOME/Games/Xash3D + +Run: + + cd $HOME/Games/Xash3D + ./xash3d.sh + +## Manual running + +Put xash3d binaries and vgui(optionally) to you game data directory and run: + + LD_LIBRARY_PATH=. ./xash -dev 5 + +## Running under GDB + + LD_LIBRARY_PATH=. gdb --args ./xash -dev 5 + +## Using DLL Loader + +Put vgui_support.dll from windows build to your game data folder and run: + + LD_LIBRARY_PATH=. ./xash -dev 5 -vguilib vgui.dll -clientlib valve/cl_dlls/client.dll -dll dlls/hl.dll + +## Running MinGW builds + +Put exe file to your game data directory + + cd (game)\ + xash_bin -dev 5 + +### Running MinGW builds under GDB + + gdb --args ./xash_bin.exe -dev 5 + +# Useful GDB commands + +Start or restart process: + + (gdb) r + +Show backtrace: + + (gdb) bt + +Full backtrace: + + (gdb) bt full + +Continue execution: + + (gdb) c + +Recover from segmentation fault: + +Skipping function: + + (gdb) handle SIGSEGV nopass + (gdb) ret + (gdb) c + +Restart frame for beginning: + + (gdb) handle SIGSEGV nopass + (gdb) jump *Host_AbortCurrentFrame +Anti-Crash script (useful for scripting servers): +``` +cd /path/to/rootdir +file xash +set args xash -dev 5 -nowcon +handle SIGSEGV nopass +catch signal SIGSEGV +set $crashes=0 +commands +print $crashes++ +if $crashes > 500 +set $crashes=0 +run +else +jump *Host_AbortCurrentFrame +end +end +run +``` diff --git a/Projects/Android/jni/src/Xash3D/xash3d/contrib/mittorn/setup.bat b/Projects/Android/jni/src/Xash3D/xash3d/contrib/mittorn/setup.bat new file mode 100644 index 0000000..2a08414 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/contrib/mittorn/setup.bat @@ -0,0 +1 @@ +copy /y %~dp0\Makefile.mingw %~dp0\..\..\engine\ \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/contrib/mittorn/setup.sh b/Projects/Android/jni/src/Xash3D/xash3d/contrib/mittorn/setup.sh new file mode 100644 index 0000000..1b3e884 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/contrib/mittorn/setup.sh @@ -0,0 +1,6 @@ +#!/bin/sh +SCRIPTDIR=$(dirname "$0") +TOPDIR=$SCRIPTDIR/../../ +cp $SCRIPTDIR/Makefile.dllloader $TOPDIR/loader/ +cp $SCRIPTDIR/Makefile.emscripten $TOPDIR/engine/ +cp $SCRIPTDIR/Makefile.linux $TOPDIR/engine/ \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/engine/Android.mk b/Projects/Android/jni/src/Xash3D/xash3d/engine/Android.mk new file mode 100644 index 0000000..71f2379 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/engine/Android.mk @@ -0,0 +1,179 @@ +#Xash Engine Android port +#Copyright (c) nicknekit + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := xash + +APP_PLATFORM := android-19 + +include $(XASH3D_CONFIG) + +LOCAL_CFLAGS += -D__MULTITEXTURE_SUPPORT__ -DXASH_GLES -DXASH_GL4ES -DUSE_EVDEV -DXASH_DYNAMIC_DLADDR -DCRASHHANDLER -DXASH_OPENSL -DXASH_SKIPCRTLIB -DXASH_FORCEINLINE -DXASH_FASTSTR + +XASH_COMMIT := $(firstword $(shell cd $(LOCAL_PATH)&&git rev-parse --short=6 HEAD) unknown) + +LOCAL_CFLAGS += -DXASH_BUILD_COMMIT=\"$(XASH_COMMIT)\" + +LOCAL_CONLYFLAGS += -std=c99 + +LOCAL_C_INCLUDES := \ + $(GL4ES_PATH)/src/GL \ + $(GL4ES_PATH)/include \ + $(LOCAL_PATH)/. \ + $(LOCAL_PATH)/common \ + $(LOCAL_PATH)/client \ + $(LOCAL_PATH)/client/vgui \ + $(LOCAL_PATH)/server \ + $(LOCAL_PATH)/common/imagelib \ + $(LOCAL_PATH)/platform/android \ + $(LOCAL_PATH)/common/soundlib \ + $(LOCAL_PATH)/common/soundlib/libmpg \ + $(LOCAL_PATH)/../common \ + $(LOCAL_PATH)/../pm_shared \ + $(LOCAL_PATH)/../ \ + $(LOCAL_PATH)/../utils/vgui/include \ + $(HLSDK_PATH)/cl_dll/ + +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES) + +LOCAL_SRC_FILES := \ + $(LOCAL_PATH)/../../../Lambda1VR/L1VR_SurfaceView.c \ + $(LOCAL_PATH)/../../../Lambda1VR/argtable3.c \ + client/cl_cmds.c \ + client/cl_demo.c \ + client/cl_events.c \ + client/cl_frame.c \ + client/cl_game.c \ + client/cl_main.c \ + client/cl_menu.c \ + client/cl_mobile.c \ + client/cl_parse.c \ + client/cl_pmove.c \ + client/cl_remap.c \ + client/cl_scrn.c \ + client/cl_tent.c \ + client/cl_video.c \ + client/cl_view.c \ + client/cl_netgraph.c \ + client/gl_backend.c \ + client/gl_beams.c \ + client/gl_cull.c \ + client/gl_decals.c \ + client/gl_draw.c \ + client/gl_image.c \ + client/gl_mirror.c \ + client/gl_refrag.c \ + client/gl_rlight.c \ + client/gl_rmain.c \ + client/gl_rmath.c \ + client/gl_rmisc.c \ + client/gl_rpart.c \ + client/gl_rsurf.c \ + client/gl_rstrobe.c \ + client/gl_sprite.c \ + client/gl_studio.c \ + client/vid_common.c \ + client/gl_warp.c \ + client/joyinput.c \ + platform/android/snd_opensles.c \ + client/input.c \ + client/keys.c \ + client/input_evdevkey.c \ + client/console.c \ + client/touch.c \ + client/gamma.c \ + client/s_dsp.c \ + client/s_load.c \ + client/s_main.c \ + client/s_mix.c \ + client/s_mouth.c \ + client/s_stream.c \ + client/s_utils.c \ + client/s_vox.c \ + common/avikit.c \ + common/build.c \ + common/base_cmd.c \ + common/cfgscript.c \ + common/cmd.c \ + common/common.c \ + common/con_utils.c \ + common/crclib.c \ + common/crtlib.c \ + common/cvar.c \ + common/filesystem.c \ + common/host.c \ + common/hpak.c \ + common/infostring.c \ + common/identification.c \ + common/library.c \ + common/masterlist.c \ + common/mathlib.c \ + common/matrixlib.c \ + common/mod_studio.c \ + common/model.c \ + common/net_buffer.c \ + common/net_chan.c \ + common/net_encode.c \ + common/net_huff.c \ + common/network.c \ + common/pm_surface.c \ + common/pm_trace.c \ + common/random.c \ + common/sys_con.c \ + common/system.c \ + common/titles.c \ + common/world.c \ + common/zone.c \ + common/crashhandler.c \ + server/sv_client.c \ + server/sv_cmds.c \ + server/sv_custom.c \ + server/sv_frame.c \ + server/sv_filter.c \ + server/sv_game.c \ + server/sv_init.c \ + server/sv_main.c \ + server/sv_log.c \ + server/sv_move.c \ + server/sv_phys.c \ + server/sv_pmove.c \ + server/sv_save.c \ + server/sv_world.c \ + client/vgui/vgui_draw.c \ + common/imagelib/img_bmp.c \ + common/imagelib/img_main.c \ + common/imagelib/img_quant.c \ + common/imagelib/img_tga.c \ + common/imagelib/img_utils.c \ + common/imagelib/img_wad.c \ + common/imagelib/img_dds.c \ + common/soundlib/snd_main.c \ + common/soundlib/snd_mp3.c \ + common/soundlib/snd_utils.c \ + common/soundlib/snd_wav.c \ + common/soundlib/libmpg/dct36.c \ + common/soundlib/libmpg/dct64.c \ + common/soundlib/libmpg/format.c \ + common/soundlib/libmpg/frame.c \ + common/soundlib/libmpg/index.c \ + common/soundlib/libmpg/layer3.c \ + common/soundlib/libmpg/libmpg.c \ + common/soundlib/libmpg/mpg123.c \ + common/soundlib/libmpg/parse.c \ + common/soundlib/libmpg/reader.c \ + common/soundlib/libmpg/synth.c \ + common/soundlib/libmpg/tabinit.c \ + common/Sequence.c \ + platform/android/vid_android.c \ + platform/android/android_nosdl.c + +#LOCAL_STATIC_LIBRARIES := GL +LOCAL_LDLIBS := -ldl -llog -landroid -lGLESv3 -lEGL # include default libraries +LOCAL_SHARED_LIBRARIES := vrapi gl4es + +include $(BUILD_SHARED_LIBRARY) + +$(call import-module,VrApi/Projects/AndroidPrebuilt/jni) \ No newline at end of file diff --git a/Projects/Android/jni/src/Xash3D/xash3d/engine/CMakeLists.txt b/Projects/Android/jni/src/Xash3D/xash3d/engine/CMakeLists.txt new file mode 100644 index 0000000..c3ad8f9 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/engine/CMakeLists.txt @@ -0,0 +1,222 @@ +# +# Copyright (c) 2016 Alibek Omarov +# +# 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, and to permit persons to whom the Software is +# 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 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 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 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +cmake_minimum_required(VERSION 2.8.0) +project(XASH_ENGINE C) + +set(XASH_ENGINE xash) # Lib name + +fwgs_fix_default_msvc_settings() +file(GLOB_RECURSE XASH_ENGINE_SOURCES common/*.c server/*.c ) # Minimal sources +file(GLOB_RECURSE XASH_ENGINE_WIN32_SOURCES platform/win32/*.c) # Win32 only sources +file(GLOB_RECURSE XASH_ENGINE_SDL_SOURCES platform/sdl/*.c) # SDL version sources +file(GLOB_RECURSE XASH_ENGINE_ANDROID_SOURCES platform/android/*.c) # Android sources +file(GLOB_RECURSE XASH_ENGINE_CLIENT_SOURCES client/*.c) # Client sources + +cond_list_append(WIN32 XASH_ENGINE_SOURCES XASH_ENGINE_WIN32_SOURCES) +cond_list_append(XASH_SDL XASH_ENGINE_SOURCES XASH_ENGINE_SDL_SOURCES) +cond_list_append(ANDROID XASH_ENGINE_SOURCES XASH_ENGINE_ANDROID_SOURCES) +cond_list_append("NOT XASH_DEDICATED" XASH_ENGINE_SOURCES XASH_ENGINE_CLIENT_SOURCES) + + +include_directories( + . + common/ + common/imagelib/ + common/soundlib/ + client/ + client/vgui/ + server/ + ../common + ../pm_shared +) + +if(XASH_NANOGL) + file(GLOB_RECURSE XASH_ENGINE_GLESWRAP_SOURCES ${XASH_NANOGL_SRC}/*.cpp) # NanoGL version + if(NOT XASH_ENGINE_GLESWRAP_SOURCES) + message(FATAL_ERROR "Clone both nanogl sources to engine folder!") + endif() + list(APPEND XASH_ENGINE_SOURCES ${XASH_ENGINE_GLESWRAP_SOURCES}) + + include_directories(${XASH_NANOGL_SRC}/ ${XASH_NANOGL_SRC}/GL/) + add_definitions(-DXASH_NANOGL -D__MULTITEXTURE_SUPPORT__) +elseif(XASH_WES) + file(GLOB XASH_ENGINE_GLESWRAP_SOURCES ${XASH_WES_SRC}/src/*.c) # wesgl version + if(NOT XASH_ENGINE_GLESWRAP_SOURCES) + message(FATAL_ERROR "Clone both gl-wes-v2 and nanogl sources to engine folder!") + endif() + list(APPEND XASH_ENGINE_SOURCES ${XASH_ENGINE_GLESWRAP_SOURCES}) + + include_directories(${XASH_NANOGL_SRC}/ ${XASH_NANOGL_SRC}/GL/ ${XASH_WES_SRC}/src/) + add_definitions(-DXASH_WES) +endif() + +add_definitions(-DXASH_FORCEINLINE) + +# Important, as HLSDK and engine shares some symbol names! +if(NOT WIN32) # Windows by default have hidden visibility and better linker + fwgs_add_compile_options(C -fvisibility=hidden) +endif() + +# ----- Conditions ----- + +if(XASH_VECTORIZE_SINCOS) # I know what I am doing and I want to build version that requires SSE + add_definitions(-DVECTORIZE_SINCOS) +endif() + +if(XASH_SINGLE_BINARY) # Set executable or library + add_definitions(-DSINGLE_BINARY) + add_executable(${XASH_ENGINE} ${XASH_ENGINE_SOURCES}) +else() + add_library(${XASH_ENGINE} SHARED ${XASH_ENGINE_SOURCES}) +endif() + +if(MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE) +endif() + +if(WIN32 AND NOT XASH_64BIT) + add_definitions( -DDBGHELP -DXASH_W32CON) # dbghelp crashhandler + if(MINGW) + target_link_libraries(${XASH_ENGINE} -luser32 -lkernel32 -lgdi32 -ldbghelp -lpsapi) + endif() +else() + if(XASH_USE_SELECT) + add_definitions(-DUSE_SELECT) + endif() + add_definitions(-DCOLORIZE_CONSOLE) +endif() + +if(LINUX) + add_definitions(-DGDB_BREAK) +endif() + +if(NOT XASH_64BIT AND NOT MSVC) + add_definitions(-DXASH_FASTSTR) +endif() + +if(XASH_IPX) + add_definitions(-DXASH_IPX) +endif() + +if(XASH_NONSTANDARD_LOAD) + add_definitions(-DXASH_NONSTANDARD_LOAD) +endif() + +if(XASH_DEDICATED) + add_definitions(-DXASH_DEDICATED) + if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND NOT XASH_SDL) + target_link_libraries(${XASH_ENGINE} -lrt) + endif() +endif() + +if(XASH_SDL) + set(SDL2_BUILDING_EXECUTABLE ${XASH_SINGLE_BINARY}) # link sdl2main, if needed + xash_link_sdl2(${XASH_ENGINE}) + add_definitions(-DXASH_SDL) + if(MSVC) + string(REGEX REPLACE "lib$" "dll" SDL2_DLL "${SDL2_LIBRARY}") + install(FILES ${SDL2_DLL} + CONFIGURATIONS Debug + DESTINATION ${LIB_INSTALL_DIR}/Debug/) + install(FILES ${SDL2_DLL} + CONFIGURATIONS Release + DESTINATION ${LIB_INSTALL_DIR}/Release/) + endif() +endif() + +if(XASH_GLES) + add_definitions(-DXASH_GLES -DXASH_GL_STATIC) +endif() + +if(XASH_SAILFISH) + add_definitions(-D__SAILFISH__) +endif() + +if(XASH_DLL_LOADER) + add_definitions(-DDLL_LOADER) + + include_directories(../loader) + + # See target_link_vgui_hack + + # Not needed anymore, loader is static always + # add_custom_command(TARGET ${XASH_ENGINE} PRE_LINK COMMAND + # ${CMAKE_COMMAND} -E copy $ $) + + target_link_libraries(${XASH_ENGINE} loader) +endif() + +if(XASH_LIBDL) + target_link_libraries(${XASH_ENGINE} ${CMAKE_DL_LIBS}) +else() + add_definitions(-DNO_LIBDL) +endif() + +if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + add_definitions(-D_DEBUG) +endif() + +if(XASH_RELEASE) + add_definitions(-DXASH_RELEASE) +else() + execute_process(COMMAND "git" "rev-parse" "--short" "HEAD" + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + OUTPUT_VARIABLE SHORT_HASH + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(SHORT_HASH) + message(STATUS "git hash: ${SHORT_HASH}") + add_definitions(-DXASH_BUILD_COMMIT="${SHORT_HASH}") + else() + message(STATUS "git hash: not set") + endif() +endif() + +if(XASH_NO_ASYNC_NS_RESOLVE) + add_definitions(-DXASH_NO_ASYNC_NS_RESOLVE) +endif() + +if(XASH_USE_STB_SPRINTF) + add_definitions(-DXASH_USE_STB_SPRINTF) +endif() + +fwgs_set_default_properties(${XASH_ENGINE}) + +if(NOT WIN32) + target_link_libraries(${XASH_ENGINE} -lm -lpthread) + # For single binary builds we change name to game_launch's executable name + if(XASH_SINGLE_BINARY) + set_target_properties(${XASH_ENGINE} PROPERTIES + OUTPUT_NAME "xash3d") + endif() +else() + # For Win32 we have split DLL names + if(XASH_DEDICATED) + set_target_properties(${XASH_ENGINE} PROPERTIES + OUTPUT_NAME "xash_dedicated") + else() + set_target_properties(${XASH_ENGINE} PROPERTIES + OUTPUT_NAME "xash_sdl") + endif() +endif() + +fwgs_install(${XASH_ENGINE}) diff --git a/Projects/Android/jni/src/Xash3D/xash3d/engine/Sequence.h b/Projects/Android/jni/src/Xash3D/xash3d/engine/Sequence.h new file mode 100644 index 0000000..dd1cbc4 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/engine/Sequence.h @@ -0,0 +1,205 @@ +//--------------------------------------------------------------------------- +// +// S c r i p t e d S e q u e n c e s +// +//--------------------------------------------------------------------------- +#ifndef _INCLUDE_SEQUENCE_H_ +#define _INCLUDE_SEQUENCE_H_ + + +#ifndef _DEF_BYTE_ +//typedef unsigned char byte; +#endif + +#ifndef CDLL_INT_H +//--------------------------------------------------------------------------- +// client_textmessage_t +//--------------------------------------------------------------------------- +typedef struct client_textmessage_s +{ + int effect; + byte r1, g1, b1, a1; // 2 colors for effects + byte r2, g2, b2, a2; + float x; + float y; + float fadein; + float fadeout; + float holdtime; + float fxtime; + char *pName; + char *pMessage; +} client_textmessage_t; +#endif + + +//--------------------------------------------------------------------------- +// sequenceCommandEnum_e +// +// Enumerated sequence command types. +//--------------------------------------------------------------------------- +enum sequenceCommandEnum_ +{ + SEQUENCE_COMMAND_ERROR = -1, + SEQUENCE_COMMAND_PAUSE = 0, + SEQUENCE_COMMAND_FIRETARGETS, + SEQUENCE_COMMAND_KILLTARGETS, + SEQUENCE_COMMAND_TEXT, + SEQUENCE_COMMAND_SOUND, + SEQUENCE_COMMAND_GOSUB, + SEQUENCE_COMMAND_SENTENCE, + SEQUENCE_COMMAND_REPEAT, + SEQUENCE_COMMAND_SETDEFAULTS, + SEQUENCE_COMMAND_MODIFIER, + SEQUENCE_COMMAND_POSTMODIFIER, + SEQUENCE_COMMAND_NOOP, + + SEQUENCE_MODIFIER_EFFECT, + SEQUENCE_MODIFIER_POSITION, + SEQUENCE_MODIFIER_COLOR, + SEQUENCE_MODIFIER_COLOR2, + SEQUENCE_MODIFIER_FADEIN, + SEQUENCE_MODIFIER_FADEOUT, + SEQUENCE_MODIFIER_HOLDTIME, + SEQUENCE_MODIFIER_FXTIME, + SEQUENCE_MODIFIER_SPEAKER, + SEQUENCE_MODIFIER_LISTENER, + SEQUENCE_MODIFIER_TEXTCHANNEL, +}; +typedef enum sequenceCommandEnum_ sequenceCommandEnum_e; + +//-------------------------------------------------------------------------- +// sequenceDefaultBits_e +// +// Enumerated list of possible modifiers for a command. This enumeration +// is used in a bitarray controlling what modifiers are specified for a command. +//--------------------------------------------------------------------------- +enum sequenceModifierBits +{ + SEQUENCE_MODIFIER_EFFECT_BIT = (1 << 1), + SEQUENCE_MODIFIER_POSITION_BIT = (1 << 2), + SEQUENCE_MODIFIER_COLOR_BIT = (1 << 3), + SEQUENCE_MODIFIER_COLOR2_BIT = (1 << 4), + SEQUENCE_MODIFIER_FADEIN_BIT = (1 << 5), + SEQUENCE_MODIFIER_FADEOUT_BIT = (1 << 6), + SEQUENCE_MODIFIER_HOLDTIME_BIT = (1 << 7), + SEQUENCE_MODIFIER_FXTIME_BIT = (1 << 8), + SEQUENCE_MODIFIER_SPEAKER_BIT = (1 << 9), + SEQUENCE_MODIFIER_LISTENER_BIT = (1 << 10), + SEQUENCE_MODIFIER_TEXTCHANNEL_BIT = (1 << 11), +}; +typedef enum sequenceModifierBits sequenceModifierBits_e ; + + +//--------------------------------------------------------------------------- +// sequenceCommandType_e +// +// Typeerated sequence command types. +//--------------------------------------------------------------------------- +enum sequenceCommandType_ +{ + SEQUENCE_TYPE_COMMAND, + SEQUENCE_TYPE_MODIFIER, +}; +typedef enum sequenceCommandType_ sequenceCommandType_e; + + +//--------------------------------------------------------------------------- +// sequenceCommandMapping_s +// +// A mapping of a command enumerated-value to its name. +//--------------------------------------------------------------------------- +typedef struct sequenceCommandMapping_ sequenceCommandMapping_s; +struct sequenceCommandMapping_ +{ + sequenceCommandEnum_e commandEnum; + const char* commandName; + sequenceCommandType_e commandType; +}; + + +//--------------------------------------------------------------------------- +// sequenceCommandLine_s +// +// Structure representing a single command (usually 1 line) from a +// .SEQ file entry. +//--------------------------------------------------------------------------- +typedef struct sequenceCommandLine_ sequenceCommandLine_s; +struct sequenceCommandLine_ +{ + int commandType; // Specifies the type of command + client_textmessage_t clientMessage; // Text HUD message struct + char* speakerName; // Targetname of speaking entity + char* listenerName; // Targetname of entity being spoken to + char* soundFileName; // Name of sound file to play + char* sentenceName; // Name of sentences.txt to play + char* fireTargetNames; // List of targetnames to fire + char* killTargetNames; // List of targetnames to remove + float delay; // Seconds 'till next command + int repeatCount; // If nonzero, reset execution pointer to top of block (N times, -1 = infinite) + int textChannel; // Display channel on which text message is sent + int modifierBitField; // Bit field to specify what clientmessage fields are valid + sequenceCommandLine_s* nextCommandLine; // Next command (linked list) +}; + + +//--------------------------------------------------------------------------- +// sequenceEntry_s +// +// Structure representing a single command (usually 1 line) from a +// .SEQ file entry. +//--------------------------------------------------------------------------- +typedef struct sequenceEntry_ sequenceEntry_s; +struct sequenceEntry_ +{ + char* fileName; // Name of sequence file without .SEQ extension + char* entryName; // Name of entry label in file + sequenceCommandLine_s* firstCommand; // Linked list of commands in entry + sequenceEntry_s* nextEntry; // Next loaded entry + qboolean isGlobal; // Is entry retained over level transitions? +}; + + + +//--------------------------------------------------------------------------- +// sentenceEntry_s +// Structure representing a single sentence of a group from a .SEQ +// file entry. Sentences are identical to entries in sentences.txt, but +// can be unique per level and are loaded/unloaded with the level. +//--------------------------------------------------------------------------- +typedef struct sentenceEntry_ sentenceEntry_s; +struct sentenceEntry_ +{ + char* data; // sentence data (ie "We have hostiles" ) + sentenceEntry_s* nextEntry; // Next loaded entry + qboolean isGlobal; // Is entry retained over level transitions? + unsigned int index; // this entry's position in the file. +}; + +//-------------------------------------------------------------------------- +// sentenceGroupEntry_s +// Structure representing a group of sentences found in a .SEQ file. +// A sentence group is defined by all sentences with the same name, ignoring +// the number at the end of the sentence name. Groups enable a sentence +// to be picked at random across a group. +//-------------------------------------------------------------------------- +typedef struct sentenceGroupEntry_ sentenceGroupEntry_s; +struct sentenceGroupEntry_ +{ + char* groupName; // name of the group (ie CT_ALERT ) + unsigned int numSentences; // number of sentences in group + sentenceEntry_s* firstSentence; // head of linked list of sentences in group + sentenceGroupEntry_s* nextEntry; // next loaded group +}; + +//--------------------------------------------------------------------------- +// Function declarations +//--------------------------------------------------------------------------- +sequenceEntry_s* Sequence_Get( const char* fileName, const char* entryName ); +void Sequence_ParseFile( const char* fileName, qboolean isGlobal ); +void Sequence_OnLevelLoad( const char* mapName ); +sentenceEntry_s* Sequence_PickSentence( const char *groupName, int pickMethod, int *picked ); +void Sequence_Init( void ); +void Sequence_PurgeEntries( qboolean purgeGlobals ); +sentenceEntry_s *Sequence_GetSentenceByIndex( unsigned int index ); + +#endif // _INCLUDE_SEQUENCE_H_ diff --git a/Projects/Android/jni/src/Xash3D/xash3d/engine/anorms.h b/Projects/Android/jni/src/Xash3D/xash3d/engine/anorms.h new file mode 100644 index 0000000..d147aea --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/engine/anorms.h @@ -0,0 +1,177 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +{-0.525731, 0.000000, 0.850651}, +{-0.442863, 0.238856, 0.864188}, +{-0.295242, 0.000000, 0.955423}, +{-0.309017, 0.500000, 0.809017}, +{-0.162460, 0.262866, 0.951056}, +{0.000000, 0.000000, 1.000000}, +{0.000000, 0.850651, 0.525731}, +{-0.147621, 0.716567, 0.681718}, +{0.147621, 0.716567, 0.681718}, +{0.000000, 0.525731, 0.850651}, +{0.309017, 0.500000, 0.809017}, +{0.525731, 0.000000, 0.850651}, +{0.295242, 0.000000, 0.955423}, +{0.442863, 0.238856, 0.864188}, +{0.162460, 0.262866, 0.951056}, +{-0.681718, 0.147621, 0.716567}, +{-0.809017, 0.309017, 0.500000}, +{-0.587785, 0.425325, 0.688191}, +{-0.850651, 0.525731, 0.000000}, +{-0.864188, 0.442863, 0.238856}, +{-0.716567, 0.681718, 0.147621}, +{-0.688191, 0.587785, 0.425325}, +{-0.500000, 0.809017, 0.309017}, +{-0.238856, 0.864188, 0.442863}, +{-0.425325, 0.688191, 0.587785}, +{-0.716567, 0.681718, -0.147621}, +{-0.500000, 0.809017, -0.309017}, +{-0.525731, 0.850651, 0.000000}, +{0.000000, 0.850651, -0.525731}, +{-0.238856, 0.864188, -0.442863}, +{0.000000, 0.955423, -0.295242}, +{-0.262866, 0.951056, -0.162460}, +{0.000000, 1.000000, 0.000000}, +{0.000000, 0.955423, 0.295242}, +{-0.262866, 0.951056, 0.162460}, +{0.238856, 0.864188, 0.442863}, +{0.262866, 0.951056, 0.162460}, +{0.500000, 0.809017, 0.309017}, +{0.238856, 0.864188, -0.442863}, +{0.262866, 0.951056, -0.162460}, +{0.500000, 0.809017, -0.309017}, +{0.850651, 0.525731, 0.000000}, +{0.716567, 0.681718, 0.147621}, +{0.716567, 0.681718, -0.147621}, +{0.525731, 0.850651, 0.000000}, +{0.425325, 0.688191, 0.587785}, +{0.864188, 0.442863, 0.238856}, +{0.688191, 0.587785, 0.425325}, +{0.809017, 0.309017, 0.500000}, +{0.681718, 0.147621, 0.716567}, +{0.587785, 0.425325, 0.688191}, +{0.955423, 0.295242, 0.000000}, +{1.000000, 0.000000, 0.000000}, +{0.951056, 0.162460, 0.262866}, +{0.850651, -0.525731, 0.000000}, +{0.955423, -0.295242, 0.000000}, +{0.864188, -0.442863, 0.238856}, +{0.951056, -0.162460, 0.262866}, +{0.809017, -0.309017, 0.500000}, +{0.681718, -0.147621, 0.716567}, +{0.850651, 0.000000, 0.525731}, +{0.864188, 0.442863, -0.238856}, +{0.809017, 0.309017, -0.500000}, +{0.951056, 0.162460, -0.262866}, +{0.525731, 0.000000, -0.850651}, +{0.681718, 0.147621, -0.716567}, +{0.681718, -0.147621, -0.716567}, +{0.850651, 0.000000, -0.525731}, +{0.809017, -0.309017, -0.500000}, +{0.864188, -0.442863, -0.238856}, +{0.951056, -0.162460, -0.262866}, +{0.147621, 0.716567, -0.681718}, +{0.309017, 0.500000, -0.809017}, +{0.425325, 0.688191, -0.587785}, +{0.442863, 0.238856, -0.864188}, +{0.587785, 0.425325, -0.688191}, +{0.688191, 0.587785, -0.425325}, +{-0.147621, 0.716567, -0.681718}, +{-0.309017, 0.500000, -0.809017}, +{0.000000, 0.525731, -0.850651}, +{-0.525731, 0.000000, -0.850651}, +{-0.442863, 0.238856, -0.864188}, +{-0.295242, 0.000000, -0.955423}, +{-0.162460, 0.262866, -0.951056}, +{0.000000, 0.000000, -1.000000}, +{0.295242, 0.000000, -0.955423}, +{0.162460, 0.262866, -0.951056}, +{-0.442863, -0.238856, -0.864188}, +{-0.309017, -0.500000, -0.809017}, +{-0.162460, -0.262866, -0.951056}, +{0.000000, -0.850651, -0.525731}, +{-0.147621, -0.716567, -0.681718}, +{0.147621, -0.716567, -0.681718}, +{0.000000, -0.525731, -0.850651}, +{0.309017, -0.500000, -0.809017}, +{0.442863, -0.238856, -0.864188}, +{0.162460, -0.262866, -0.951056}, +{0.238856, -0.864188, -0.442863}, +{0.500000, -0.809017, -0.309017}, +{0.425325, -0.688191, -0.587785}, +{0.716567, -0.681718, -0.147621}, +{0.688191, -0.587785, -0.425325}, +{0.587785, -0.425325, -0.688191}, +{0.000000, -0.955423, -0.295242}, +{0.000000, -1.000000, 0.000000}, +{0.262866, -0.951056, -0.162460}, +{0.000000, -0.850651, 0.525731}, +{0.000000, -0.955423, 0.295242}, +{0.238856, -0.864188, 0.442863}, +{0.262866, -0.951056, 0.162460}, +{0.500000, -0.809017, 0.309017}, +{0.716567, -0.681718, 0.147621}, +{0.525731, -0.850651, 0.000000}, +{-0.238856, -0.864188, -0.442863}, +{-0.500000, -0.809017, -0.309017}, +{-0.262866, -0.951056, -0.162460}, +{-0.850651, -0.525731, 0.000000}, +{-0.716567, -0.681718, -0.147621}, +{-0.716567, -0.681718, 0.147621}, +{-0.525731, -0.850651, 0.000000}, +{-0.500000, -0.809017, 0.309017}, +{-0.238856, -0.864188, 0.442863}, +{-0.262866, -0.951056, 0.162460}, +{-0.864188, -0.442863, 0.238856}, +{-0.809017, -0.309017, 0.500000}, +{-0.688191, -0.587785, 0.425325}, +{-0.681718, -0.147621, 0.716567}, +{-0.442863, -0.238856, 0.864188}, +{-0.587785, -0.425325, 0.688191}, +{-0.309017, -0.500000, 0.809017}, +{-0.147621, -0.716567, 0.681718}, +{-0.425325, -0.688191, 0.587785}, +{-0.162460, -0.262866, 0.951056}, +{0.442863, -0.238856, 0.864188}, +{0.162460, -0.262866, 0.951056}, +{0.309017, -0.500000, 0.809017}, +{0.147621, -0.716567, 0.681718}, +{0.000000, -0.525731, 0.850651}, +{0.425325, -0.688191, 0.587785}, +{0.587785, -0.425325, 0.688191}, +{0.688191, -0.587785, 0.425325}, +{-0.955423, 0.295242, 0.000000}, +{-0.951056, 0.162460, 0.262866}, +{-1.000000, 0.000000, 0.000000}, +{-0.850651, 0.000000, 0.525731}, +{-0.955423, -0.295242, 0.000000}, +{-0.951056, -0.162460, 0.262866}, +{-0.864188, 0.442863, -0.238856}, +{-0.951056, 0.162460, -0.262866}, +{-0.809017, 0.309017, -0.500000}, +{-0.864188, -0.442863, -0.238856}, +{-0.951056, -0.162460, -0.262866}, +{-0.809017, -0.309017, -0.500000}, +{-0.681718, 0.147621, -0.716567}, +{-0.681718, -0.147621, -0.716567}, +{-0.850651, 0.000000, -0.525731}, +{-0.688191, 0.587785, -0.425325}, +{-0.587785, 0.425325, -0.688191}, +{-0.425325, 0.688191, -0.587785}, +{-0.425325, -0.688191, -0.587785}, +{-0.587785, -0.425325, -0.688191}, +{-0.688191, -0.587785, -0.425325}, diff --git a/Projects/Android/jni/src/Xash3D/xash3d/engine/cdll_exp.h b/Projects/Android/jni/src/Xash3D/xash3d/engine/cdll_exp.h new file mode 100644 index 0000000..796ca33 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/engine/cdll_exp.h @@ -0,0 +1,77 @@ +/* +cdll_exp.h - exports for client +Copyright (C) 2013 Uncle Mike + +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 3 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. +*/ +#ifndef CDLL_EXP_H +#define CDLL_EXP_H + +struct tempent_s; +struct engine_studio_api_s; +struct r_studio_interface_s; + +// NOTE: ordering is important! +typedef struct cldll_func_s +{ + int (*pfnInitialize)( cl_enginefunc_t *pEnginefuncs, int iVersion ); + void (*pfnInit)( void ); + int (*pfnVidInit)( void ); + int (*pfnRedraw)( float flTime, int intermission ); + int (*pfnUpdateClientData)( client_data_t *cdata, float flTime ); + void (*pfnReset)( void ); + void (*pfnPlayerMove)( struct playermove_s *ppmove, int server ); + void (*pfnPlayerMoveInit)( struct playermove_s *ppmove ); + char (*pfnPlayerMoveTexture)( char *name ); + void (*IN_ActivateMouse)( void ); + void (*IN_DeactivateMouse)( void ); + void (*IN_MouseEvent)( int mstate ); + void (*IN_ClearStates)( void ); + void (*IN_Accumulate)( void ); + void (*CL_CreateMove)( float frametime, struct usercmd_s *cmd, int active ); + int (*CL_IsThirdPerson)( void ); + void (*CL_CameraOffset)( float *ofs ); + void *(*KB_Find)( const char *name ); + void (*CAM_Think)( void ); // camera stuff + void (*pfnCalcRefdef)( ref_params_t *pparams ); + int (*pfnAddEntity)( int type, cl_entity_t *ent, const char *modelname ); + void (*pfnCreateEntities)( void ); + void (*pfnDrawNormalTriangles)( void ); + void (*pfnDrawTransparentTriangles)( void ); + void (*pfnStudioEvent)( const struct mstudioevent_s *event, const cl_entity_t *entity ); + void (*pfnPostRunCmd)( struct local_state_s *from, struct local_state_s *to, usercmd_t *cmd, int runfuncs, double time, unsigned int random_seed ); + void (*pfnShutdown)( void ); + void (*pfnTxferLocalOverrides)( entity_state_t *state, const clientdata_t *client ); + void (*pfnProcessPlayerState)( entity_state_t *dst, const entity_state_t *src ); + void (*pfnTxferPredictionData)( entity_state_t *ps, const entity_state_t *pps, clientdata_t *pcd, const clientdata_t *ppcd, weapon_data_t *wd, const weapon_data_t *pwd ); + void (*pfnDemo_ReadBuffer)( int size, byte *buffer ); + int (*pfnConnectionlessPacket)( const struct netadr_s *net_from, const char *args, char *buffer, int *size ); + int (*pfnGetHullBounds)( int hullnumber, float *mins, float *maxs ); + void (*pfnFrame)( double time ); + int (*pfnKey_Event)( int eventcode, int keynum, const char *pszCurrentBinding ); + void (*pfnTempEntUpdate)( double frametime, double client_time, double cl_gravity, struct tempent_s **ppTempEntFree, struct tempent_s **ppTempEntActive, int ( *Callback_AddVisibleEntity )( cl_entity_t *pEntity ), void ( *Callback_TempEntPlaySound )( struct tempent_s *pTemp, float damp )); + cl_entity_t *(*pfnGetUserEntity)( int index ); + void (*pfnVoiceStatus)( int entindex, qboolean bTalking ); + void (*pfnDirectorMessage)( int iSize, void *pbuf ); + int (*pfnGetStudioModelInterface)( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio ); + void (*pfnChatInputPosition)( int *x, int *y ); + int (*pfnGetPlayerTeam)( int playerIndex ); + void *(*pfnGetClientFactory)( void ); + // Xash3D extension + int (*pfnGetRenderInterface)( int version, render_api_t *renderfuncs, render_interface_t *callback ); + void (*pfnClipMoveToEntity)( struct physent_s *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, struct pmtrace_s *tr ); + // More extenstions for the extensions god! (SDL Xash port) + int (*pfnTouchEvent)( int type, int fingerID, float x, float y, float dx, float dy ); + void (*pfnMoveEvent)( float forwardmove, float sidemove ); + void (*pfnLookEvent)( float relyaw, float relpitch ); +} cldll_func_t; + +#endif//CDLL_EXP_H diff --git a/Projects/Android/jni/src/Xash3D/xash3d/engine/cdll_int.h b/Projects/Android/jni/src/Xash3D/xash3d/engine/cdll_int.h new file mode 100644 index 0000000..c7b04fc --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/engine/cdll_int.h @@ -0,0 +1,312 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// cdll_int.h +// +// 4-23-98 +// JOHN: client dll interface declarations +// + +#ifndef CDLL_INT_H +#define CDLL_INT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "const.h" +#include + +#define MAX_ALIAS_NAME 32 + +typedef struct cmdalias_s +{ + struct cmdalias_s *next; + char name[MAX_ALIAS_NAME]; + char *value; +} cmdalias_t; + +// this file is included by both the engine and the client-dll, +// so make sure engine declarations aren't done twice + +typedef int HSPRITE; // handle to a graphic +typedef int (*pfnUserMsgHook)( const char *pszName, int iSize, void *pbuf ); + +#include "wrect.h" + +#define SCRINFO_SCREENFLASH 1 +#define SCRINFO_STRETCHED 2 + +typedef struct SCREENINFO_s +{ + int iSize; + int iWidth; + int iHeight; + int iFlags; + int iCharHeight; + short charWidths[256]; +} SCREENINFO; + +typedef struct client_data_s +{ + // fields that cannot be modified (ie. have no effect if changed) + vec3_t origin; + + // fields that can be changed by the cldll + vec3_t viewangles; + int iWeaponBits; + float fov; // field of view +} client_data_t; + +typedef struct client_sprite_s +{ + char szName[64]; + char szSprite[64]; + int hspr; + int iRes; + wrect_t rc; +} client_sprite_t; + +typedef struct client_textmessage_s +{ + int effect; + byte r1, g1, b1, a1; // 2 colors for effects + byte r2, g2, b2, a2; + float x; + float y; + float fadein; + float fadeout; + float holdtime; + float fxtime; + const char *pName; + const char *pMessage; +} client_textmessage_t; + +typedef struct hud_player_info_s +{ + char *name; + short ping; + byte thisplayer; // TRUE if this is the calling player + + // stuff that's unused at the moment, but should be done + byte spectator; + byte packetloss; + char *model; + short topcolor; + short bottomcolor; + + uint64_t m_nSteamID; +} hud_player_info_t; + +struct screenfade_s; +struct tagPOINT; + +typedef struct cl_enginefuncs_s +{ + // sprite handlers + HSPRITE (*pfnSPR_Load)( const char *szPicName ); + int (*pfnSPR_Frames)( HSPRITE hPic ); + int (*pfnSPR_Height)( HSPRITE hPic, int frame ); + int (*pfnSPR_Width)( HSPRITE hPic, int frame ); + void (*pfnSPR_Set)( HSPRITE hPic, int r, int g, int b ); + void (*pfnSPR_Draw)( int frame, int x, int y, const wrect_t *prc ); + void (*pfnSPR_DrawHoles)( int frame, int x, int y, const wrect_t *prc ); + void (*pfnSPR_DrawAdditive)( int frame, int x, int y, const wrect_t *prc ); + void (*pfnSPR_EnableScissor)( int x, int y, int width, int height ); + void (*pfnSPR_DisableScissor)( void ); + client_sprite_t *(*pfnSPR_GetList)( char *psz, int *piCount ); + + // screen handlers + void (*pfnFillRGBA)( int x, int y, int width, int height, int r, int g, int b, int a ); + int (*pfnGetScreenInfo)( SCREENINFO *pscrinfo ); + void (*pfnSetCrosshair)( HSPRITE hspr, wrect_t rc, int r, int g, int b ); + + // cvar handlers + struct cvar_s *(*pfnRegisterVariable)( char *szName, char *szValue, int flags ); + float (*pfnGetCvarFloat)( char *szName ); + char* (*pfnGetCvarString)( char *szName ); + + // command handlers + int (*pfnAddCommand)( char *cmd_name, void (*function)(void) ); + int (*pfnHookUserMsg)( char *szMsgName, pfnUserMsgHook pfn ); + int (*pfnServerCmd)( char *szCmdString ); + int (*pfnClientCmd)( char *szCmdString ); + + void (*pfnGetPlayerInfo)( int ent_num, hud_player_info_t *pinfo ); + + // sound handlers + void (*pfnPlaySoundByName)( char *szSound, float volume ); + void (*pfnPlaySoundByIndex)( int iSound, float volume ); + + // vector helpers + void (*pfnAngleVectors)( const float *vecAngles, float *forward, float *right, float *up ); + + // text message system + client_textmessage_t *(*pfnTextMessageGet)( const char *pName ); + int (*pfnDrawCharacter)( int x, int y, int number, int r, int g, int b ); + int (*pfnDrawConsoleString)( int x, int y, char *string ); + void (*pfnDrawSetTextColor)( float r, float g, float b ); + void (*pfnDrawConsoleStringLen)( const char *string, int *length, int *height ); + + void (*pfnConsolePrint)( const char *string ); + void (*pfnCenterPrint)( const char *string ); + + // Added for user input processing + int (*GetWindowCenterX)( void ); + int (*GetWindowCenterY)( void ); + void (*GetViewAngles)( float * ); + void (*SetViewAngles)( float * ); + int (*GetMaxClients)( void ); + void (*Cvar_SetValue)( char *cvar, float value ); + + int (*Cmd_Argc)( void ); + char *(*Cmd_Argv)( int arg ); + void (*Con_Printf)( char *fmt, ... ); + void (*Con_DPrintf)( char *fmt, ... ); + void (*Con_NPrintf)( int pos, char *fmt, ... ); + void (*Con_NXPrintf)( struct con_nprint_s *info, char *fmt, ... ); + + const char* (*PhysInfo_ValueForKey)( const char *key ); + const char* (*ServerInfo_ValueForKey)( const char *key ); + float (*GetClientMaxspeed)( void ); + int (*CheckParm)( char *parm, char **ppnext ); + + void (*Key_Event)( int key, int down ); + void (*GetMousePosition)( int *mx, int *my ); + int (*IsNoClipping)( void ); + + struct cl_entity_s *(*GetLocalPlayer)( void ); + struct cl_entity_s *(*GetViewModel)( void ); + struct cl_entity_s *(*GetEntityByIndex)( int idx ); + + float (*GetClientTime)( void ); + void (*V_CalcShake)( void ); + void (*V_ApplyShake)( float *origin, float *angles, float factor ); + + int (*PM_PointContents)( float *point, int *truecontents ); + int (*PM_WaterEntity)( float *p ); + struct pmtrace_s *(*PM_TraceLine)( float *start, float *end, int flags, int usehull, int ignore_pe ); + + struct model_s *(*CL_LoadModel)( const char *modelname, int *index ); + int (*CL_CreateVisibleEntity)( int type, struct cl_entity_s *ent ); + + const struct model_s* (*GetSpritePointer)( HSPRITE hSprite ); + void (*pfnPlaySoundByNameAtLocation)( char *szSound, float volume, float *origin ); + + unsigned short (*pfnPrecacheEvent)( int type, const char* psz ); + void (*pfnPlaybackEvent)( int flags, const struct edict_s *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ); + void (*pfnWeaponAnim)( int iAnim, int body ); + float (*pfnRandomFloat)( float flLow, float flHigh ); + int (*pfnRandomLong)( int lLow, int lHigh ); + void (*pfnHookEvent)( char *name, void ( *pfnEvent )( struct event_args_s *args )); + int (*Con_IsVisible) (); + const char *(*pfnGetGameDirectory)( void ); + struct cvar_s *(*pfnGetCvarPointer)( const char *szName ); + const char *(*Key_LookupBinding)( const char *pBinding ); + const char *(*pfnGetLevelName)( void ); + void (*pfnGetScreenFade)( struct screenfade_s *fade ); + void (*pfnSetScreenFade)( struct screenfade_s *fade ); + void* (*VGui_GetPanel)( ); + void (*VGui_ViewportPaintBackground)( int extents[4] ); + + byte* (*COM_LoadFile)( char *path, int usehunk, int *pLength ); + char* (*COM_ParseFile)( char *data, char *token ); + void (*COM_FreeFile)( void *buffer ); + + struct triangleapi_s *pTriAPI; + struct efx_api_s *pEfxAPI; + struct event_api_s *pEventAPI; + struct demo_api_s *pDemoAPI; + struct net_api_s *pNetAPI; + struct IVoiceTweak_s *pVoiceTweak; + + // returns 1 if the client is a spectator only (connected to a proxy), 0 otherwise or 2 if in dev_overview mode + int (*IsSpectateOnly)( void ); + struct model_s *(*LoadMapSprite)( const char *filename ); + + // file search functions + void (*COM_AddAppDirectoryToSearchPath)( const char *pszBaseDir, const char *appName ); + int (*COM_ExpandFilename)( const char *fileName, char *nameOutBuffer, int nameOutBufferSize ); + + // User info + // playerNum is in the range (1, MaxClients) + // returns NULL if player doesn't exit + // returns "" if no value is set + const char *( *PlayerInfo_ValueForKey )( int playerNum, const char *key ); + void (*PlayerInfo_SetValueForKey )( const char *key, const char *value ); + + // Gets a unique ID for the specified player. This is the same even if you see the player on a different server. + // iPlayer is an entity index, so client 0 would use iPlayer=1. + // Returns false if there is no player on the server in the specified slot. + qboolean (*GetPlayerUniqueID)(int iPlayer, char playerID[16]); + + // TrackerID access + int (*GetTrackerIDForPlayer)(int playerSlot); + int (*GetPlayerForTrackerID)(int trackerID); + + // Same as pfnServerCmd, but the message goes in the unreliable stream so it can't clog the net stream + // (but it might not get there). + int ( *pfnServerCmdUnreliable )( char *szCmdString ); + + void (*pfnGetMousePos)( struct tagPOINT *ppt ); + void (*pfnSetMousePos)( int x, int y ); + void (*pfnSetMouseEnable)( qboolean fEnable ); + + // undocumented interface starts here + struct cvar_s* (*pfnGetFirstCvarPtr)( void ); + void* (*pfnGetFirstCmdFunctionHandle)( void ); + void* (*pfnGetNextCmdFunctionHandle)( void *cmdhandle ); + const char* (*pfnGetCmdFunctionName)( void *cmdhandle ); + float (*pfnGetClientOldTime)( void ); + float (*pfnGetGravity)( void ); + struct model_s* (*pfnGetModelByIndex)( int index ); + void (*pfnSetFilterMode)( int mode ); // same as gl_texsort in original Quake + void (*pfnSetFilterColor)( float red, float green, float blue ); + void (*pfnSetFilterBrightness)( float brightness ); + void *(*pfnSequenceGet)( const char *fileName, const char *entryName ); + void (*pfnSPR_DrawGeneric)( int frame, int x, int y, const wrect_t *prc, int blendsrc, int blenddst, int width, int height ); + void *(*pfnSequencePickSentence)( const char *groupName, int pickMethod, int *entryPicked ); + int (*pfnDrawString)( int x, int y, const char *str, int r, int g, int b ); + int (*pfnDrawStringReverse)( int x, int y, const char *str, int r, int g, int b ); + const char *(*LocalPlayerInfo_ValueForKey)( const char* key ); + int (*pfnVGUI2DrawCharacter)( int x, int y, int ch, unsigned int font ); + int (*pfnVGUI2DrawCharacterAdditive)( int x, int y, int ch, int r, int g, int b, unsigned int font ); + unsigned int (*pfnGetApproxWavePlayLen)( char *filename ); + void* (*GetCareerGameUI)( void ); // g-cont. !!!! potential crash-point! + void (*Cvar_Set)( char *name, char *value ); + int (*pfnIsPlayingCareerMatch)( void ); + void (*pfnPlaySoundVoiceByName)( char *szSound, float volume, int pitch ); + void (*pfnPrimeMusicStream)( char *filename, int looping ); + double (*pfnSys_FloatTime)( void ); + + // decay funcs + void (*pfnProcessTutorMessageDecayBuffer)( int *buffer, int buflen ); + void (*pfnConstructTutorMessageDecayBuffer)( int *buffer, int buflen ); + void (*pfnResetTutorMessageDecayData)( void ); + + void (*pfnPlaySoundByNameAtPitch)( char *szSound, float volume, int pitch ); + void (*pfnFillRGBABlend)( int x, int y, int width, int height, int r, int g, int b, int a ); + int (*pfnGetAppID)( void ); + cmdalias_t *(*pfnGetAliases)( void ); + void (*pfnVguiWrap2_GetMouseDelta)( int *x, int *y ); +} cl_enginefunc_t; + +#define CLDLL_INTERFACE_VERSION 7 + +#ifdef __cplusplus +} +#endif + +#endif//CDLL_INT_H diff --git a/Projects/Android/jni/src/Xash3D/xash3d/engine/client/anorm_dots.h b/Projects/Android/jni/src/Xash3D/xash3d/engine/client/anorm_dots.h new file mode 100644 index 0000000..475ea3d --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/engine/client/anorm_dots.h @@ -0,0 +1,35 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +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. + +*/ +{1.23,1.30,1.47,1.35,1.56,1.71,1.37,1.38,1.59,1.60,1.79,1.97,1.88,1.92,1.79,1.02,0.93,1.07,0.82,0.87,0.88,0.94,0.96,1.14,1.11,0.82,0.83,0.89,0.89,0.86,0.94,0.91,1.00,1.21,0.98,1.48,1.30,1.57,0.96,1.07,1.14,1.60,1.61,1.40,1.37,1.72,1.78,1.79,1.93,1.99,1.90,1.68,1.71,1.86,1.60,1.68,1.78,1.86,1.93,1.99,1.97,1.44,1.22,1.49,0.93,0.99,0.99,1.23,1.22,1.44,1.49,0.89,0.89,0.97,0.91,0.98,1.19,0.82,0.76,0.82,0.71,0.72,0.73,0.76,0.79,0.86,0.83,0.72,0.76,0.76,0.89,0.82,0.89,0.82,0.89,0.91,0.83,0.96,1.14,0.97,1.40,1.19,0.98,0.94,1.00,1.07,1.37,1.21,1.48,1.30,1.57,1.61,1.37,0.86,0.83,0.91,0.82,0.82,0.88,0.89,0.96,1.14,0.98,0.87,0.93,0.94,1.02,1.30,1.07,1.35,1.38,1.11,1.56,1.92,1.79,1.79,1.59,1.60,1.72,1.90,1.79,0.80,0.85,0.79,0.93,0.80,0.85,0.77,0.74,0.72,0.77,0.74,0.72,0.70,0.70,0.71,0.76,0.73,0.79,0.79,0.73,0.76,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.26,1.26,1.48,1.23,1.50,1.71,1.14,1.19,1.38,1.46,1.64,1.94,1.87,1.84,1.71,1.02,0.92,1.00,0.79,0.85,0.84,0.91,0.90,0.98,0.99,0.77,0.77,0.83,0.82,0.79,0.86,0.84,0.92,0.99,0.91,1.24,1.03,1.33,0.88,0.94,0.97,1.41,1.39,1.18,1.11,1.51,1.61,1.59,1.80,1.91,1.76,1.54,1.65,1.76,1.70,1.70,1.85,1.85,1.97,1.99,1.93,1.28,1.09,1.39,0.92,0.97,0.99,1.18,1.26,1.52,1.48,0.83,0.85,0.90,0.88,0.93,1.00,0.77,0.73,0.78,0.72,0.71,0.74,0.75,0.79,0.86,0.81,0.75,0.81,0.79,0.96,0.88,0.94,0.86,0.93,0.92,0.85,1.08,1.33,1.05,1.55,1.31,1.01,1.05,1.27,1.31,1.60,1.47,1.70,1.54,1.76,1.76,1.57,0.93,0.90,0.99,0.88,0.88,0.95,0.97,1.11,1.39,1.20,0.92,0.97,1.01,1.10,1.39,1.22,1.51,1.58,1.32,1.64,1.97,1.85,1.91,1.77,1.74,1.88,1.99,1.91,0.79,0.86,0.80,0.94,0.84,0.88,0.74,0.74,0.71,0.82,0.77,0.76,0.70,0.73,0.72,0.73,0.70,0.74,0.85,0.77,0.82,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.34,1.27,1.53,1.17,1.46,1.71,0.98,1.05,1.20,1.34,1.48,1.86,1.82,1.71,1.62,1.09,0.94,0.99,0.79,0.85,0.82,0.90,0.87,0.93,0.96,0.76,0.74,0.79,0.76,0.74,0.79,0.78,0.85,0.92,0.85,1.00,0.93,1.06,0.81,0.86,0.89,1.16,1.12,0.97,0.95,1.28,1.38,1.35,1.60,1.77,1.57,1.33,1.50,1.58,1.69,1.63,1.82,1.74,1.91,1.92,1.80,1.04,0.97,1.21,0.90,0.93,0.97,1.05,1.21,1.48,1.37,0.77,0.80,0.84,0.85,0.88,0.92,0.73,0.71,0.74,0.74,0.71,0.75,0.73,0.79,0.84,0.78,0.79,0.86,0.81,1.05,0.94,0.99,0.90,0.95,0.92,0.86,1.24,1.44,1.14,1.59,1.34,1.02,1.27,1.50,1.49,1.80,1.69,1.86,1.72,1.87,1.80,1.69,1.00,0.98,1.23,0.95,0.96,1.09,1.16,1.37,1.63,1.46,0.99,1.10,1.25,1.24,1.51,1.41,1.67,1.77,1.55,1.72,1.95,1.89,1.98,1.91,1.86,1.97,1.99,1.94,0.81,0.89,0.85,0.98,0.90,0.94,0.75,0.78,0.73,0.89,0.83,0.82,0.72,0.77,0.76,0.72,0.70,0.71,0.91,0.83,0.89,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.46,1.34,1.60,1.16,1.46,1.71,0.94,0.99,1.05,1.26,1.33,1.74,1.76,1.57,1.54,1.23,0.98,1.05,0.83,0.89,0.84,0.92,0.87,0.91,0.96,0.78,0.74,0.79,0.72,0.72,0.75,0.76,0.80,0.88,0.83,0.94,0.87,0.95,0.76,0.80,0.82,0.97,0.96,0.89,0.88,1.08,1.11,1.10,1.37,1.59,1.37,1.07,1.27,1.34,1.57,1.45,1.69,1.55,1.77,1.79,1.60,0.93,0.90,0.99,0.86,0.87,0.93,0.96,1.07,1.35,1.18,0.73,0.76,0.77,0.81,0.82,0.85,0.70,0.71,0.72,0.78,0.73,0.77,0.73,0.79,0.82,0.76,0.83,0.90,0.84,1.18,0.98,1.03,0.92,0.95,0.90,0.86,1.32,1.45,1.15,1.53,1.27,0.99,1.42,1.65,1.58,1.93,1.83,1.94,1.81,1.88,1.74,1.70,1.19,1.17,1.44,1.11,1.15,1.36,1.41,1.61,1.81,1.67,1.22,1.34,1.50,1.42,1.65,1.61,1.82,1.91,1.75,1.80,1.89,1.89,1.98,1.99,1.94,1.98,1.92,1.87,0.86,0.95,0.92,1.14,0.98,1.03,0.79,0.84,0.77,0.97,0.90,0.89,0.76,0.82,0.82,0.74,0.72,0.71,0.98,0.89,0.97,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.60,1.44,1.68,1.22,1.49,1.71,0.93,0.99,0.99,1.23,1.22,1.60,1.68,1.44,1.49,1.40,1.14,1.19,0.89,0.96,0.89,0.97,0.89,0.91,0.98,0.82,0.76,0.82,0.71,0.72,0.73,0.76,0.79,0.86,0.83,0.91,0.83,0.89,0.72,0.76,0.76,0.89,0.89,0.82,0.82,0.98,0.96,0.97,1.14,1.40,1.19,0.94,1.00,1.07,1.37,1.21,1.48,1.30,1.57,1.61,1.37,0.86,0.83,0.91,0.82,0.82,0.88,0.89,0.96,1.14,0.98,0.70,0.72,0.73,0.77,0.76,0.79,0.70,0.72,0.71,0.82,0.77,0.80,0.74,0.79,0.80,0.74,0.87,0.93,0.85,1.23,1.02,1.02,0.93,0.93,0.87,0.85,1.30,1.35,1.07,1.38,1.11,0.94,1.47,1.71,1.56,1.97,1.88,1.92,1.79,1.79,1.59,1.60,1.30,1.35,1.56,1.37,1.38,1.59,1.60,1.79,1.92,1.79,1.48,1.57,1.72,1.61,1.78,1.79,1.93,1.99,1.90,1.86,1.78,1.86,1.93,1.99,1.97,1.90,1.79,1.72,0.94,1.07,1.00,1.37,1.21,1.30,0.86,0.91,0.83,1.14,0.98,0.96,0.82,0.88,0.89,0.79,0.76,0.73,1.07,0.94,1.11,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.74,1.57,1.76,1.33,1.54,1.71,0.94,1.05,0.99,1.26,1.16,1.46,1.60,1.34,1.46,1.59,1.37,1.37,0.97,1.11,0.96,1.10,0.95,0.94,1.08,0.89,0.82,0.88,0.72,0.76,0.75,0.80,0.80,0.88,0.87,0.91,0.83,0.87,0.72,0.76,0.74,0.83,0.84,0.78,0.79,0.96,0.89,0.92,0.98,1.23,1.05,0.86,0.92,0.95,1.11,0.98,1.22,1.03,1.34,1.42,1.14,0.79,0.77,0.84,0.78,0.76,0.82,0.82,0.89,0.97,0.90,0.70,0.71,0.71,0.73,0.72,0.74,0.73,0.76,0.72,0.86,0.81,0.82,0.76,0.79,0.77,0.73,0.90,0.95,0.86,1.18,1.03,0.98,0.92,0.90,0.83,0.84,1.19,1.17,0.98,1.15,0.97,0.89,1.42,1.65,1.44,1.93,1.83,1.81,1.67,1.61,1.36,1.41,1.32,1.45,1.58,1.57,1.53,1.74,1.70,1.88,1.94,1.81,1.69,1.77,1.87,1.79,1.89,1.92,1.98,1.99,1.98,1.89,1.65,1.80,1.82,1.91,1.94,1.75,1.61,1.50,1.07,1.34,1.27,1.60,1.45,1.55,0.93,0.99,0.90,1.35,1.18,1.07,0.87,0.93,0.96,0.85,0.82,0.77,1.15,0.99,1.27,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.86,1.71,1.82,1.48,1.62,1.71,0.98,1.20,1.05,1.34,1.17,1.34,1.53,1.27,1.46,1.77,1.60,1.57,1.16,1.38,1.12,1.35,1.06,1.00,1.28,0.97,0.89,0.95,0.76,0.81,0.79,0.86,0.85,0.92,0.93,0.93,0.85,0.87,0.74,0.78,0.74,0.79,0.82,0.76,0.79,0.96,0.85,0.90,0.94,1.09,0.99,0.81,0.85,0.89,0.95,0.90,0.99,0.94,1.10,1.24,0.98,0.75,0.73,0.78,0.74,0.72,0.77,0.76,0.82,0.89,0.83,0.73,0.71,0.71,0.71,0.70,0.72,0.77,0.80,0.74,0.90,0.85,0.84,0.78,0.79,0.75,0.73,0.92,0.95,0.86,1.05,0.99,0.94,0.90,0.86,0.79,0.81,1.00,0.98,0.91,0.96,0.89,0.83,1.27,1.50,1.23,1.80,1.69,1.63,1.46,1.37,1.09,1.16,1.24,1.44,1.49,1.69,1.59,1.80,1.69,1.87,1.86,1.72,1.82,1.91,1.94,1.92,1.95,1.99,1.98,1.91,1.97,1.89,1.51,1.72,1.67,1.77,1.86,1.55,1.41,1.25,1.33,1.58,1.50,1.80,1.63,1.74,1.04,1.21,0.97,1.48,1.37,1.21,0.93,0.97,1.05,0.92,0.88,0.84,1.14,1.02,1.34,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.94,1.84,1.87,1.64,1.71,1.71,1.14,1.38,1.19,1.46,1.23,1.26,1.48,1.26,1.50,1.91,1.80,1.76,1.41,1.61,1.39,1.59,1.33,1.24,1.51,1.18,0.97,1.11,0.82,0.88,0.86,0.94,0.92,0.99,1.03,0.98,0.91,0.90,0.79,0.84,0.77,0.79,0.84,0.77,0.83,0.99,0.85,0.91,0.92,1.02,1.00,0.79,0.80,0.86,0.88,0.84,0.92,0.88,0.97,1.10,0.94,0.74,0.71,0.74,0.72,0.70,0.73,0.72,0.76,0.82,0.77,0.77,0.73,0.74,0.71,0.70,0.73,0.83,0.85,0.78,0.92,0.88,0.86,0.81,0.79,0.74,0.75,0.92,0.93,0.85,0.96,0.94,0.88,0.86,0.81,0.75,0.79,0.93,0.90,0.85,0.88,0.82,0.77,1.05,1.27,0.99,1.60,1.47,1.39,1.20,1.11,0.95,0.97,1.08,1.33,1.31,1.70,1.55,1.76,1.57,1.76,1.70,1.54,1.85,1.97,1.91,1.99,1.97,1.99,1.91,1.77,1.88,1.85,1.39,1.64,1.51,1.58,1.74,1.32,1.22,1.01,1.54,1.76,1.65,1.93,1.70,1.85,1.28,1.39,1.09,1.52,1.48,1.26,0.97,0.99,1.18,1.00,0.93,0.90,1.05,1.01,1.31,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.97,1.92,1.88,1.79,1.79,1.71,1.37,1.59,1.38,1.60,1.35,1.23,1.47,1.30,1.56,1.99,1.93,1.90,1.60,1.78,1.61,1.79,1.57,1.48,1.72,1.40,1.14,1.37,0.89,0.96,0.94,1.07,1.00,1.21,1.30,1.14,0.98,0.96,0.86,0.91,0.83,0.82,0.88,0.82,0.89,1.11,0.87,0.94,0.93,1.02,1.07,0.80,0.79,0.85,0.82,0.80,0.87,0.85,0.93,1.02,0.93,0.77,0.72,0.74,0.71,0.70,0.70,0.71,0.72,0.77,0.74,0.82,0.76,0.79,0.72,0.73,0.76,0.89,0.89,0.82,0.93,0.91,0.86,0.83,0.79,0.73,0.76,0.91,0.89,0.83,0.89,0.89,0.82,0.82,0.76,0.72,0.76,0.86,0.83,0.79,0.82,0.76,0.73,0.94,1.00,0.91,1.37,1.21,1.14,0.98,0.96,0.88,0.89,0.96,1.14,1.07,1.60,1.40,1.61,1.37,1.57,1.48,1.30,1.78,1.93,1.79,1.99,1.92,1.90,1.79,1.59,1.72,1.79,1.30,1.56,1.35,1.38,1.60,1.11,1.07,0.94,1.68,1.86,1.71,1.97,1.68,1.86,1.44,1.49,1.22,1.44,1.49,1.22,0.99,0.99,1.23,1.19,0.98,0.97,0.97,0.98,1.19,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.94,1.97,1.87,1.91,1.85,1.71,1.60,1.77,1.58,1.74,1.51,1.26,1.48,1.39,1.64,1.99,1.97,1.99,1.70,1.85,1.76,1.91,1.76,1.70,1.88,1.55,1.33,1.57,0.96,1.08,1.05,1.31,1.27,1.47,1.54,1.39,1.20,1.11,0.93,0.99,0.90,0.88,0.95,0.88,0.97,1.32,0.92,1.01,0.97,1.10,1.22,0.84,0.80,0.88,0.79,0.79,0.85,0.86,0.92,1.02,0.94,0.82,0.76,0.77,0.72,0.73,0.70,0.72,0.71,0.74,0.74,0.88,0.81,0.85,0.75,0.77,0.82,0.94,0.93,0.86,0.92,0.92,0.86,0.85,0.79,0.74,0.79,0.88,0.85,0.81,0.82,0.83,0.77,0.78,0.73,0.71,0.75,0.79,0.77,0.74,0.77,0.73,0.70,0.86,0.92,0.84,1.14,0.99,0.98,0.91,0.90,0.84,0.83,0.88,0.97,0.94,1.41,1.18,1.39,1.11,1.33,1.24,1.03,1.61,1.80,1.59,1.91,1.84,1.76,1.64,1.38,1.51,1.71,1.26,1.50,1.23,1.19,1.46,0.99,1.00,0.91,1.70,1.85,1.65,1.93,1.54,1.76,1.52,1.48,1.26,1.28,1.39,1.09,0.99,0.97,1.18,1.31,1.01,1.05,0.90,0.93,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.86,1.95,1.82,1.98,1.89,1.71,1.80,1.91,1.77,1.86,1.67,1.34,1.53,1.51,1.72,1.92,1.91,1.99,1.69,1.82,1.80,1.94,1.87,1.86,1.97,1.59,1.44,1.69,1.05,1.24,1.27,1.49,1.50,1.69,1.72,1.63,1.46,1.37,1.00,1.23,0.98,0.95,1.09,0.96,1.16,1.55,0.99,1.25,1.10,1.24,1.41,0.90,0.85,0.94,0.79,0.81,0.85,0.89,0.94,1.09,0.98,0.89,0.82,0.83,0.74,0.77,0.72,0.76,0.73,0.75,0.78,0.94,0.86,0.91,0.79,0.83,0.89,0.99,0.95,0.90,0.90,0.92,0.84,0.86,0.79,0.75,0.81,0.85,0.80,0.78,0.76,0.77,0.73,0.74,0.71,0.71,0.73,0.74,0.74,0.71,0.76,0.72,0.70,0.79,0.85,0.78,0.98,0.92,0.93,0.85,0.87,0.82,0.79,0.81,0.89,0.86,1.16,0.97,1.12,0.95,1.06,1.00,0.93,1.38,1.60,1.35,1.77,1.71,1.57,1.48,1.20,1.28,1.62,1.27,1.46,1.17,1.05,1.34,0.96,0.99,0.90,1.63,1.74,1.50,1.80,1.33,1.58,1.48,1.37,1.21,1.04,1.21,0.97,0.97,0.93,1.05,1.34,1.02,1.14,0.84,0.88,0.92,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.74,1.89,1.76,1.98,1.89,1.71,1.93,1.99,1.91,1.94,1.82,1.46,1.60,1.65,1.80,1.79,1.77,1.92,1.57,1.69,1.74,1.87,1.88,1.94,1.98,1.53,1.45,1.70,1.18,1.32,1.42,1.58,1.65,1.83,1.81,1.81,1.67,1.61,1.19,1.44,1.17,1.11,1.36,1.15,1.41,1.75,1.22,1.50,1.34,1.42,1.61,0.98,0.92,1.03,0.83,0.86,0.89,0.95,0.98,1.23,1.14,0.97,0.89,0.90,0.78,0.82,0.76,0.82,0.77,0.79,0.84,0.98,0.90,0.98,0.83,0.89,0.97,1.03,0.95,0.92,0.86,0.90,0.82,0.86,0.79,0.77,0.84,0.81,0.76,0.76,0.72,0.73,0.70,0.72,0.71,0.73,0.73,0.72,0.74,0.71,0.78,0.74,0.72,0.75,0.80,0.76,0.94,0.88,0.91,0.83,0.87,0.84,0.79,0.76,0.82,0.80,0.97,0.89,0.96,0.88,0.95,0.94,0.87,1.11,1.37,1.10,1.59,1.57,1.37,1.33,1.05,1.08,1.54,1.34,1.46,1.16,0.99,1.26,0.96,1.05,0.92,1.45,1.55,1.27,1.60,1.07,1.34,1.35,1.18,1.07,0.93,0.99,0.90,0.93,0.87,0.96,1.27,0.99,1.15,0.77,0.82,0.85,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.60,1.78,1.68,1.93,1.86,1.71,1.97,1.99,1.99,1.97,1.93,1.60,1.68,1.78,1.86,1.61,1.57,1.79,1.37,1.48,1.59,1.72,1.79,1.92,1.90,1.38,1.35,1.60,1.23,1.30,1.47,1.56,1.71,1.88,1.79,1.92,1.79,1.79,1.30,1.56,1.35,1.37,1.59,1.38,1.60,1.90,1.48,1.72,1.57,1.61,1.79,1.21,1.00,1.30,0.89,0.94,0.96,1.07,1.14,1.40,1.37,1.14,0.96,0.98,0.82,0.88,0.82,0.89,0.83,0.86,0.91,1.02,0.93,1.07,0.87,0.94,1.11,1.02,0.93,0.93,0.82,0.87,0.80,0.85,0.79,0.80,0.85,0.77,0.72,0.74,0.71,0.70,0.70,0.71,0.72,0.77,0.74,0.72,0.76,0.73,0.82,0.79,0.76,0.73,0.79,0.76,0.93,0.86,0.91,0.83,0.89,0.89,0.82,0.72,0.76,0.76,0.89,0.82,0.89,0.82,0.89,0.91,0.83,0.96,1.14,0.97,1.40,1.44,1.19,1.22,0.99,0.98,1.49,1.44,1.49,1.22,0.99,1.23,0.98,1.19,0.97,1.21,1.30,1.00,1.37,0.94,1.07,1.14,0.98,0.96,0.86,0.91,0.83,0.88,0.82,0.89,1.11,0.94,1.07,0.73,0.76,0.79,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.46,1.65,1.60,1.82,1.80,1.71,1.93,1.91,1.99,1.94,1.98,1.74,1.76,1.89,1.89,1.42,1.34,1.61,1.11,1.22,1.36,1.50,1.61,1.81,1.75,1.15,1.17,1.41,1.18,1.19,1.42,1.44,1.65,1.83,1.67,1.94,1.81,1.88,1.32,1.58,1.45,1.57,1.74,1.53,1.70,1.98,1.69,1.87,1.77,1.79,1.92,1.45,1.27,1.55,0.97,1.07,1.11,1.34,1.37,1.59,1.60,1.35,1.07,1.18,0.86,0.93,0.87,0.96,0.90,0.93,0.99,1.03,0.95,1.15,0.90,0.99,1.27,0.98,0.90,0.92,0.78,0.83,0.77,0.84,0.79,0.82,0.86,0.73,0.71,0.73,0.72,0.70,0.73,0.72,0.76,0.81,0.76,0.76,0.82,0.77,0.89,0.85,0.82,0.75,0.80,0.80,0.94,0.88,0.94,0.87,0.95,0.96,0.88,0.72,0.74,0.76,0.83,0.78,0.84,0.79,0.87,0.91,0.83,0.89,0.98,0.92,1.23,1.34,1.05,1.16,0.99,0.96,1.46,1.57,1.54,1.33,1.05,1.26,1.08,1.37,1.10,0.98,1.03,0.92,1.14,0.86,0.95,0.97,0.90,0.89,0.79,0.84,0.77,0.82,0.76,0.82,0.97,0.89,0.98,0.71,0.72,0.74,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.34,1.51,1.53,1.67,1.72,1.71,1.80,1.77,1.91,1.86,1.98,1.86,1.82,1.95,1.89,1.24,1.10,1.41,0.95,0.99,1.09,1.25,1.37,1.63,1.55,0.96,0.98,1.16,1.05,1.00,1.27,1.23,1.50,1.69,1.46,1.86,1.72,1.87,1.24,1.49,1.44,1.69,1.80,1.59,1.69,1.97,1.82,1.94,1.91,1.92,1.99,1.63,1.50,1.74,1.16,1.33,1.38,1.58,1.60,1.77,1.80,1.48,1.21,1.37,0.90,0.97,0.93,1.05,0.97,1.04,1.21,0.99,0.95,1.14,0.92,1.02,1.34,0.94,0.86,0.90,0.74,0.79,0.75,0.81,0.79,0.84,0.86,0.71,0.71,0.73,0.76,0.73,0.77,0.74,0.80,0.85,0.78,0.81,0.89,0.84,0.97,0.92,0.88,0.79,0.85,0.86,0.98,0.92,1.00,0.93,1.06,1.12,0.95,0.74,0.74,0.78,0.79,0.76,0.82,0.79,0.87,0.93,0.85,0.85,0.94,0.90,1.09,1.27,0.99,1.17,1.05,0.96,1.46,1.71,1.62,1.48,1.20,1.34,1.28,1.57,1.35,0.90,0.94,0.85,0.98,0.81,0.89,0.89,0.83,0.82,0.75,0.78,0.73,0.77,0.72,0.76,0.89,0.83,0.91,0.71,0.70,0.72,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.26,1.39,1.48,1.51,1.64,1.71,1.60,1.58,1.77,1.74,1.91,1.94,1.87,1.97,1.85,1.10,0.97,1.22,0.88,0.92,0.95,1.01,1.11,1.39,1.32,0.88,0.90,0.97,0.96,0.93,1.05,0.99,1.27,1.47,1.20,1.70,1.54,1.76,1.08,1.31,1.33,1.70,1.76,1.55,1.57,1.88,1.85,1.91,1.97,1.99,1.99,1.70,1.65,1.85,1.41,1.54,1.61,1.76,1.80,1.91,1.93,1.52,1.26,1.48,0.92,0.99,0.97,1.18,1.09,1.28,1.39,0.94,0.93,1.05,0.92,1.01,1.31,0.88,0.81,0.86,0.72,0.75,0.74,0.79,0.79,0.86,0.85,0.71,0.73,0.75,0.82,0.77,0.83,0.78,0.85,0.88,0.81,0.88,0.97,0.90,1.18,1.00,0.93,0.86,0.92,0.94,1.14,0.99,1.24,1.03,1.33,1.39,1.11,0.79,0.77,0.84,0.79,0.77,0.84,0.83,0.90,0.98,0.91,0.85,0.92,0.91,1.02,1.26,1.00,1.23,1.19,0.99,1.50,1.84,1.71,1.64,1.38,1.46,1.51,1.76,1.59,0.84,0.88,0.80,0.94,0.79,0.86,0.82,0.77,0.76,0.74,0.74,0.71,0.73,0.70,0.72,0.82,0.77,0.85,0.74,0.70,0.73,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00} diff --git a/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_cmds.c b/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_cmds.c new file mode 100644 index 0000000..d9ff993 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_cmds.c @@ -0,0 +1,522 @@ +/* +cl_cmds.c - client console commnds +Copyright (C) 2007 Uncle Mike + +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 3 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. +*/ + +#ifndef XASH_DEDICATED +#include "common.h" +#include "client.h" +#include "gl_local.h" + +/* +==================== +CL_PlayVideo_f + +movie +==================== +*/ +void CL_PlayVideo_f( void ) +{ + string path; + + if( Cmd_Argc() != 2 && Cmd_Argc() != 3 ) + { + Msg( "movie [full]\n" ); + return; + } + + if( cls.state == ca_active ) + { + Msg( "Can't play movie while connected to a server.\nPlease disconnect first.\n" ); + return; + } + + switch( Cmd_Argc( )) + { + case 2: // simple user version + Q_snprintf( path, sizeof( path ), "media/%s.avi", Cmd_Argv( 1 )); + SCR_PlayCinematic( path ); + break; + case 3: // sequenced cinematics used this + SCR_PlayCinematic( Cmd_Argv( 1 )); + break; + } +} + +/* +=============== +CL_PlayCDTrack_f + +Emulate audio-cd system +=============== +*/ +void CL_PlayCDTrack_f( void ) +{ + const char *command; + static int track = 0; + static qboolean paused = false; + static qboolean looped = false; + static qboolean enabled = true; + + if( Cmd_Argc() < 2 ) return; + command = Cmd_Argv( 1 ); + + if( !enabled && Q_stricmp( command, "on" )) return; // CD-player is disabled + + if( !Q_stricmp( command, "play" )) + { + track = bound( 1, Q_atoi( Cmd_Argv( 2 )), MAX_CDTRACKS ); + S_StartBackgroundTrack( clgame.cdtracks[track-1], NULL, 0 ); + paused = false; + looped = false; + } + else if( !Q_stricmp( command, "loop" )) + { + track = bound( 1, Q_atoi( Cmd_Argv( 2 )), MAX_CDTRACKS ); + S_StartBackgroundTrack( clgame.cdtracks[track-1], clgame.cdtracks[track-1], 0 ); + paused = false; + looped = true; + } + else if( !Q_stricmp( command, "pause" )) + { + S_StreamSetPause( true ); + paused = true; + } + else if( !Q_stricmp( command, "resume" )) + { + S_StreamSetPause( false ); + paused = false; + } + else if( !Q_stricmp( command, "stop" )) + { + S_StopBackgroundTrack(); + paused = false; + looped = false; + track = 0; + } + else if( !Q_stricmp( command, "on" )) + { + enabled = true; + } + else if( !Q_stricmp( command, "off" )) + { + enabled = false; + } + else if( !Q_stricmp( command, "info" )) + { + int i, maxTrack; + + for( maxTrack = i = 0; i < MAX_CDTRACKS; i++ ) + if( Q_strlen( clgame.cdtracks[i] )) maxTrack++; + + Msg( "%u tracks\n", maxTrack ); + if( track ) + { + if( paused ) Msg( "Paused %s track %u\n", looped ? "looping" : "playing", track ); + else Msg( "Currently %s track %u\n", looped ? "looping" : "playing", track ); + } + Msg( "Volume is %f\n", Cvar_VariableValue( "MP3Volume" )); + return; + } + else Msg( "cd: unknown command %s\n", command ); +} + +/* +=============== +CL_PlayCDTrack_f + +Handle "mp3" console command +=============== +*/ +void CL_MP3Command_f ( void ) +{ + char *pszCommand, *pszTrack; + + if ( Cmd_Argc() < 2 ) + return; + + pszCommand = Cmd_Argv (1); + pszTrack = Cmd_Argv (2); + + if (Q_stricmp(pszCommand, "play") == 0) + { + S_StartBackgroundTrack( pszTrack, NULL, 0 ); + return; + } + else if (Q_stricmp(pszCommand, "playfile") == 0) + { + S_StartBackgroundTrack( pszTrack, NULL, 0 ); + return; + } + else if (Q_stricmp(pszCommand, "loop") == 0) + { + S_StartBackgroundTrack( pszTrack, pszTrack, 0 ); + return; + } + else if (Q_stricmp(pszCommand, "loopfile") == 0) + { + S_StartBackgroundTrack( pszTrack, pszTrack, 0 ); + return; + } + else if (Q_stricmp(pszCommand, "stop") == 0) + { + S_StopBackgroundTrack(); + return; + } +} + + +/* +================== +CL_ScreenshotGetName +================== +*/ +void CL_ScreenshotGetName( int lastnum, char *filename ) +{ + if( lastnum < 0 || lastnum > 9999 ) + { + // bound + Q_sprintf( filename, "scrshots/%s/!error.bmp", clgame.mapname ); + return; + } + + Q_sprintf( filename, "scrshots/%s_shot%04d.bmp", clgame.mapname, lastnum ); +} + +/* +================== +CL_SnapshotGetName +================== +*/ +qboolean CL_SnapshotGetName( int lastnum, char *filename ) +{ + if( lastnum < 0 || lastnum > 9999 ) + { + MsgDev( D_ERROR, "unable to write snapshot\n" ); + FS_AllowDirectPaths( false ); + return false; + } + + Q_sprintf( filename, "%s_%04d.bmp", clgame.mapname, lastnum ); + + return true; +} + +/* +============================================================================== + + SCREEN SHOTS + +============================================================================== +*/ +/* +================== +CL_ScreenShot_f + +normal screenshot +================== +*/ +void CL_ScreenShot_f( void ) +{ + int i; + string checkname; + + if( gl_overview->integer == 1 ) + { + // special case for write overview image and script file + Q_snprintf( cls.shotname, sizeof( cls.shotname ), "overviews/%s.bmp", clgame.mapname ); + cls.scrshot_action = scrshot_mapshot; // build new frame for mapshot + } + else + { + // scan for a free filename + for( i = 0; i < 9999; i++ ) + { + CL_ScreenshotGetName( i, checkname ); + if( !FS_FileExists( checkname, false )) + break; + } + + Q_strncpy( cls.shotname, checkname, sizeof( cls.shotname )); + cls.scrshot_action = scrshot_normal; // build new frame for screenshot + } + + cls.envshot_vieworg = NULL; // no custom view + cls.envshot_viewsize = 0; +} + +/* +================== +CL_SnapShot_f + +save screenshots into root dir +================== +*/ +void CL_SnapShot_f( void ) +{ + int i; + string checkname; + + if( gl_overview->integer == 1 ) + { + // special case for write overview image and script file + Q_snprintf( cls.shotname, sizeof( cls.shotname ), "overviews/%s.bmp", clgame.mapname ); + cls.scrshot_action = scrshot_mapshot; // build new frame for mapshot + } + else + { + FS_AllowDirectPaths( true ); + + // scan for a free filename + for( i = 0; i < 9999; i++ ) + { + if( !CL_SnapshotGetName( i, checkname )) + return; // no namespace + + if( !FS_FileExists( checkname, false )) + break; + } + + FS_AllowDirectPaths( false ); + Q_strncpy( cls.shotname, checkname, sizeof( cls.shotname )); + cls.scrshot_action = scrshot_snapshot; // build new frame for screenshot + } + + cls.envshot_vieworg = NULL; // no custom view + cls.envshot_viewsize = 0; +} + +/* +================== +CL_EnvShot_f + +cubemap view +================== +*/ +void CL_EnvShot_f( void ) +{ + if( Cmd_Argc() < 2 ) + { + Msg( "Usage: envshot \n" ); + return; + } + + Q_sprintf( cls.shotname, "gfx/env/%s", Cmd_Argv( 1 )); + cls.scrshot_action = scrshot_envshot; // build new frame for envshot + cls.envshot_vieworg = NULL; // no custom view + cls.envshot_viewsize = 0; +} + +/* +================== +CL_SkyShot_f + +skybox view +================== +*/ +void CL_SkyShot_f( void ) +{ + if( Cmd_Argc() < 2 ) + { + Msg( "Usage: skyshot \n" ); + return; + } + + Q_sprintf( cls.shotname, "gfx/env/%s", Cmd_Argv( 1 )); + cls.scrshot_action = scrshot_skyshot; // build new frame for skyshot + cls.envshot_vieworg = NULL; // no custom view + cls.envshot_viewsize = 0; +} + +/* +================== +CL_LevelShot_f + +splash logo while map is loading +================== +*/ +void CL_LevelShot_f( void ) +{ + size_t ft1, ft2; + string filename; + + if( cls.scrshot_request != scrshot_plaque ) return; + cls.scrshot_request = scrshot_inactive; + + // check for existence + if( cls.demoplayback && ( cls.demonum != -1 )) + { + Q_sprintf( cls.shotname, "levelshots/%s_%s.bmp", cls.demoname, glState.wideScreen ? "16x9" : "4x3" ); + Q_snprintf( filename, sizeof( filename ), "demos/%s.dem", cls.demoname ); + + // make sure that levelshot is newer than demo + ft1 = FS_FileTime( filename, false ); + ft2 = FS_FileTime( cls.shotname, true ); + } + else if( cl.worldmodel->name ) + { + Q_sprintf( cls.shotname, "levelshots/%s_%s.bmp", clgame.mapname, glState.wideScreen ? "16x9" : "4x3" ); + + // make sure that levelshot is newer than bsp + ft1 = FS_FileTime( cl.worldmodel->name, false ); + ft2 = FS_FileTime( cls.shotname, true ); + } + else ft1 = ft2 = 0; + + // missing levelshot or level newer than levelshot + if( ft2 == (size_t)-1 || ft1 > ft2 ) + cls.scrshot_action = scrshot_plaque; // build new frame for levelshot + else cls.scrshot_action = scrshot_inactive; // disable - not needs +} + +/* +================== +CL_SaveShot_f + +mini-pic in loadgame menu +================== +*/ +void CL_SaveShot_f( void ) +{ + if( Cmd_Argc() < 2 ) + { + Msg( "Usage: saveshot \n" ); + return; + } + + Q_sprintf( cls.shotname, "save/%s.bmp", Cmd_Argv( 1 )); + cls.scrshot_action = scrshot_savegame; // build new frame for saveshot +} + +/* +================== +CL_DemoShot_f + +mini-pic in playdemo menu +================== +*/ +void CL_DemoShot_f( void ) +{ + if( Cmd_Argc() < 2 ) + { + Msg( "Usage: demoshot \n" ); + return; + } + + Q_sprintf( cls.shotname, "demos/%s.bmp", Cmd_Argv( 1 )); + cls.scrshot_action = scrshot_demoshot; // build new frame for demoshot +} + +/* +============== +CL_DeleteDemo_f + +============== +*/ +void CL_DeleteDemo_f( void ) +{ + if( Cmd_Argc() != 2 ) + { + Msg( "Usage: killdemo \n" ); + return; + } + + if( cls.demorecording && !Q_stricmp( cls.demoname, Cmd_Argv( 1 ))) + { + Msg( "Can't delete %s - recording\n", Cmd_Argv( 1 )); + return; + } + + // delete save and saveshot + FS_Delete( va( "demos/%s.dem", Cmd_Argv( 1 ))); + FS_Delete( va( "demos/%s.bmp", Cmd_Argv( 1 ))); +} + +/* +================= +CL_SetSky_f + +Set a specified skybox (only for local clients) +================= +*/ +void CL_SetSky_f( void ) +{ + if( Cmd_Argc() < 2 ) + { + Msg( "Usage: skyname \n" ); + return; + } + + R_SetupSky( Cmd_Argv( 1 )); +} + +/* +================ +SCR_TimeRefresh_f + +timerefresh [noflip] +================ +*/ +void SCR_TimeRefresh_f( void ) +{ + int i; + double start, stop; + double time; + + if( cls.state != ca_active ) + return; + + start = Sys_DoubleTime(); + + if( Cmd_Argc() == 2 ) + { + // run without page flipping + R_BeginFrame( false ); + for( i = 0; i < 128; i++ ) + { + cl.refdef.viewangles[1] = i / 128.0 * 360.0f; + R_RenderFrame( &cl.refdef, true ); + } + R_EndFrame(); + } + else + { + for( i = 0; i < 128; i++ ) + { + cl.refdef.viewangles[1] = i / 128.0 * 360.0f; + + R_BeginFrame( true ); + R_RenderFrame( &cl.refdef, true ); + R_EndFrame(); + } + } + + stop = Sys_DoubleTime (); + time = (stop - start); + Msg( "%f seconds (%f fps)\n", time, 128 / time ); +} + +/* +============= +SCR_Viewpos_f + +viewpos (level-designer helper) +============= +*/ +void SCR_Viewpos_f( void ) +{ + Msg( "org ( %g %g %g )\n", cl.refdef.vieworg[0], cl.refdef.vieworg[1], cl.refdef.vieworg[2] ); + Msg( "ang ( %g %g %g )\n", cl.refdef.viewangles[0], cl.refdef.viewangles[1], cl.refdef.viewangles[2] ); +} + +#endif //XASH_DEDICATED diff --git a/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_demo.c b/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_demo.c new file mode 100644 index 0000000..5f50a10 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_demo.c @@ -0,0 +1,1249 @@ +/* +cl_demo.c - demo record & playback +Copyright (C) 2007 Uncle Mike + +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 3 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. +*/ + +#ifndef XASH_DEDICATED + +#include "common.h" +#include "client.h" +#include "net_encode.h" + +#define dem_unknown 0 // unknown command +#define dem_norewind 1 // startup message +#define dem_read 2 // it's a normal network packet +#define dem_jumptime 3 // move the demostart time value forward by this amount +#define dem_userdata 4 // userdata from the client.dll +#define dem_usercmd 5 // read usercmd_t +#define dem_stop 6 // end of time +#define dem_lastcmd dem_stop + +#define DEMO_STARTUP 0 // this lump contains startup info needed to spawn into the server +#define DEMO_NORMAL 1 // this lump contains playback info of messages, etc., needed during playback. + +#define IDEMOHEADER (('M'<<24)+('E'<<16)+('D'<<8)+'I') // little-endian "IDEM" +#define DEMO_PROTOCOL 1 + +const char *demo_cmd[dem_lastcmd+1] = +{ + "dem_unknown", + "dem_norewind", + "dem_read", + "dem_jumptime", + "dem_userdata", + "dem_usercmd", + "dem_stop", +}; + +typedef struct +{ + int id; // should be IDEM + int dem_protocol; // should be DEMO_PROTOCOL + int net_protocol; // should be PROTOCOL_VERSION + char mapname[64]; // name of map + char gamedir[64]; // name of game directory (FS_Gamedir()) + int directory_offset; // offset of Entry Directory. +} demoheader_t; + +typedef struct +{ + int entrytype; // DEMO_STARTUP or DEMO_NORMAL + float playback_time; // time of track + int playback_frames; // # of frames in track + int offset; // file offset of track data + int length; // length of track +} demoentry_t; + +typedef struct +{ + demoentry_t *entries; // track entry info + int numentries; // number of tracks +} demodirectory_t; + +// private demo states +struct +{ + demoheader_t header; + demoentry_t *entry; + demodirectory_t directory; + int framecount; + float starttime; + float realstarttime; + int entryIndex; +} demo; + +/* +==================== +CL_StartupDemoHeader + +spooling demo header in case +we record a demo on this level +==================== +*/ +void CL_StartupDemoHeader( void ) +{ + if( cls.demoheader ) + { + FS_Close( cls.demoheader ); + } + + // Note: this is replacing tmpfile() + cls.demoheader = FS_Open( "demoheader.tmp", "w+b", true ); + + if( !cls.demoheader ) + { + MsgDev( D_ERROR, "couldn't open temporary header file.\n" ); + return; + } + + MsgDev( D_INFO, "Spooling demo header.\n" ); +} + +/* +==================== +CL_CloseDemoHeader + +close demoheader file on engine shutdown +==================== +*/ +void CL_CloseDemoHeader( void ) +{ + if( !cls.demoheader ) + return; + + FS_Close( cls.demoheader ); +} + +/* +==================== +CL_GetDemoRecordClock + +write time while demo is recording +==================== +*/ +float CL_GetDemoRecordClock( void ) +{ + return cl.mtime[0]; +} + +/* +==================== +CL_GetDemoPlaybackClock + +overwrite host.realtime +==================== +*/ +float CL_GetDemoPlaybackClock( void ) +{ + return host.realtime + host.frametime; +} + +/* +==================== +CL_WriteDemoCmdHeader + +Writes the demo command header and time-delta +==================== +*/ +void CL_WriteDemoCmdHeader( byte cmd, file_t *file ) +{ + float dt; + + ASSERT( cmd >= 1 && cmd <= dem_lastcmd ); + if( !file ) return; + + // command + FS_Write( file, &cmd, sizeof( byte )); + + // time offset + dt = (float)(CL_GetDemoRecordClock() - demo.starttime); + FS_Write( file, &dt, sizeof( float )); +} + +/* +==================== +CL_WriteDemoJumpTime + +Update level time on a next level +==================== +*/ +void CL_WriteDemoJumpTime( void ) +{ + if( cls.demowaiting || !cls.demofile ) + return; + + demo.starttime = CL_GetDemoRecordClock(); // setup the demo starttime + + // demo playback should read this as an incoming message. + // write the client's realtime value out so we can synchronize the reads. + CL_WriteDemoCmdHeader( dem_jumptime, cls.demofile ); +} + +/* +==================== +CL_WriteDemoUserCmd + +Writes the current user cmd +==================== +*/ +void CL_WriteDemoUserCmd( int cmdnumber ) +{ + sizebuf_t buf; + word bytes; + byte data[1024]; + + if( !cls.demorecording || !cls.demofile ) + return; + + CL_WriteDemoCmdHeader( dem_usercmd, cls.demofile ); + + FS_Write( cls.demofile, &cls.netchan.outgoing_sequence, sizeof( int )); + FS_Write( cls.demofile, &cmdnumber, sizeof( int )); + + // write usercmd_t + BF_Init( &buf, "UserCmd", data, sizeof( data )); + CL_WriteUsercmd( &buf, -1, cmdnumber ); // always no delta + + bytes = BF_GetNumBytesWritten( &buf ); + + FS_Write( cls.demofile, &bytes, sizeof( word )); + FS_Write( cls.demofile, data, bytes ); +} + +/* +==================== +CL_WriteDemoSequence + +Save state of cls.netchan sequences +so that we can play the demo correctly. +==================== +*/ +void CL_WriteDemoSequence( file_t *file ) +{ + ASSERT( file ); + + FS_Write( file, &cls.netchan.incoming_sequence, sizeof( int )); + FS_Write( file, &cls.netchan.incoming_acknowledged, sizeof( int )); + FS_Write( file, &cls.netchan.incoming_reliable_acknowledged, sizeof( int )); + FS_Write( file, &cls.netchan.incoming_reliable_sequence, sizeof( int )); + FS_Write( file, &cls.netchan.outgoing_sequence, sizeof( int )); + FS_Write( file, &cls.netchan.reliable_sequence, sizeof( int )); + FS_Write( file, &cls.netchan.last_reliable_sequence, sizeof( int )); +} + +/* +==================== +CL_WriteDemoMessage + +Dumps the current net message, prefixed by the length +==================== +*/ +void CL_WriteDemoMessage( qboolean startup, int start, sizebuf_t *msg ) +{ + file_t *file = startup ? cls.demoheader : cls.demofile; + int swlen; + byte c; + + if( !file ) return; + + // past the start but not recording a demo. + if( !startup && !cls.demorecording ) + return; + + swlen = BF_GetNumBytesWritten( msg ) - start; + if( swlen <= 0 ) return; + + if( !startup ) + { + cls.demotime += host.frametime; + demo.framecount++; + } + + // demo playback should read this as an incoming message. + c = (cls.state != ca_active) ? dem_norewind : dem_read; + + CL_WriteDemoCmdHeader( c, file ); + CL_WriteDemoSequence( file ); + + // write the length out. + FS_Write( file, &swlen, sizeof( int )); + + // output the buffer. Skip the network packet stuff. + FS_Write( file, BF_GetData( msg ) + start, swlen ); +} + +/* +==================== +CL_WriteDemoUserMessage + +Dumps the user message (demoaction) +==================== +*/ +void CL_WriteDemoUserMessage( const byte *buffer, size_t size ) +{ + if( !cls.demorecording || cls.demowaiting ) + return; + + if( !cls.demofile || !buffer || size <= 0 ) + return; + + CL_WriteDemoCmdHeader( dem_userdata, cls.demofile ); + + // write the length out. + FS_Write( cls.demofile, &size, sizeof( int )); + + // output the buffer. + FS_Write( cls.demofile, buffer, size ); +} + +/* +==================== +CL_WriteDemoHeader + +Write demo header +==================== +*/ +void CL_WriteDemoHeader( const char *name ) +{ + fs_offset_t copysize; + fs_offset_t savepos; + fs_offset_t curpos; + + MsgDev( D_INFO, "recording to %s.\n", name ); + cls.demofile = FS_Open( name, "wb", false ); + cls.demotime = 0.0; + + if( !cls.demofile ) + { + MsgDev( D_ERROR, "couldn't open %s.\n", name ); + return; + } + + cls.demorecording = true; + cls.demowaiting = true; // don't start saving messages until a non-delta compressed message is received + + Q_memset( &demo.header, 0, sizeof( demo.header )); + + demo.header.id = IDEMOHEADER; + demo.header.dem_protocol = DEMO_PROTOCOL; + demo.header.net_protocol = PROTOCOL_VERSION; + Q_strncpy( demo.header.mapname, clgame.mapname, sizeof( demo.header.mapname )); + Q_strncpy( demo.header.gamedir, FS_Gamedir(), sizeof( demo.header.gamedir )); + + // write header + FS_Write( cls.demofile, &demo.header, sizeof( demo.header )); + + demo.directory.numentries = 2; + demo.directory.entries = Mem_Alloc( cls.mempool, sizeof( demoentry_t ) * demo.directory.numentries ); + + // DIRECTORY ENTRY # 0 + demo.entry = &demo.directory.entries[0]; // only one here. + demo.entry->entrytype = DEMO_STARTUP; + demo.entry->playback_time = 0.0f; // startup takes 0 time. + demo.entry->offset = FS_Tell( cls.demofile ); // position for this chunk. + + // finish off the startup info. + CL_WriteDemoCmdHeader( dem_stop, cls.demoheader ); + + // now copy the stuff we cached from the server. + copysize = savepos = FS_Tell( cls.demoheader ); + + FS_Seek( cls.demoheader, 0, SEEK_SET ); + + FS_FileCopy( cls.demofile, cls.demoheader, copysize ); + + // jump back to end, in case we record another demo for this session. + FS_Seek( cls.demoheader, savepos, SEEK_SET ); + + demo.starttime = CL_GetDemoRecordClock(); // setup the demo starttime + demo.realstarttime = demo.starttime; + demo.framecount = 0; + + // now move on to entry # 1, the first data chunk. + curpos = FS_Tell( cls.demofile ); + demo.entry->length = curpos - demo.entry->offset; + + // now we are writing the first real lump. + demo.entry = &demo.directory.entries[1]; // first real data lump + demo.entry->entrytype = DEMO_NORMAL; + demo.entry->playback_time = 0.0f; // startup takes 0 time. + + demo.entry->offset = FS_Tell( cls.demofile ); + + // demo playback should read this as an incoming message. + // write the client's realtime value out so we can synchronize the reads. + CL_WriteDemoCmdHeader( dem_jumptime, cls.demofile ); + + if( clgame.hInstance ) clgame.dllFuncs.pfnReset(); + + Cbuf_InsertText( "fullupdate\n" ); + Cbuf_Execute(); +} + +/* +================= +CL_StopRecord + +finish recording demo +================= +*/ +void CL_StopRecord( void ) +{ + int i, curpos; + float stoptime; + + if( !cls.demorecording ) return; + + // demo playback should read this as an incoming message. + CL_WriteDemoCmdHeader( dem_stop, cls.demofile ); + + stoptime = CL_GetDemoRecordClock(); + + // close down the hud for now. + // g-cont. is this need??? + if( clgame.hInstance ) clgame.dllFuncs.pfnReset(); + + curpos = FS_Tell( cls.demofile ); + demo.entry->length = curpos - demo.entry->offset; + demo.entry->playback_time = stoptime - demo.realstarttime; + demo.entry->playback_frames = demo.framecount; + + // Now write out the directory and free it and touch up the demo header. + FS_Write( cls.demofile, &demo.directory.numentries, sizeof( int )); + + for( i = 0; i < demo.directory.numentries; i++ ) + { + FS_Write( cls.demofile, &demo.directory.entries[i], sizeof( demoentry_t )); + } + + Mem_Free( demo.directory.entries ); + demo.directory.numentries = 0; + + demo.header.directory_offset = curpos; + FS_Seek( cls.demofile, 0, SEEK_SET ); + FS_Write( cls.demofile, &demo.header, sizeof( demo.header )); + + FS_Close( cls.demofile ); + cls.demofile = NULL; + cls.demorecording = false; + cls.demoname[0] = '\0'; + menu.globals->demoname[0] = '\0'; + + Msg( "Completed demo\n" ); + MsgDev( D_INFO, "Recording time %.2f\n", cls.demotime ); + cls.demotime = 0.0; +} + +/* +================= +CL_DrawDemoRecording +================= +*/ +void CL_DrawDemoRecording( void ) +{ + char string[64]; + rgba_t color = { 255, 255, 255, 255 }; + fs_offset_t pos; + int len; + + if(!( host.developer && cls.demorecording )) + return; + + pos = FS_Tell( cls.demofile ); + Q_snprintf( string, sizeof( string ), "RECORDING %s: %ik", cls.demoname, (int)(pos / 1024) ); + + Con_DrawStringLen( string, &len, NULL ); + Con_DrawString(( scr_width->integer - len) >> 1, scr_height->integer >> 2, string, color ); +} + +/* +======================================================================= + +CLIENT SIDE DEMO PLAYBACK + +======================================================================= +*/ +/* +================= +CL_ReadDemoCmdHeader + +read the demo command +================= +*/ +void CL_ReadDemoCmdHeader( byte *cmd, float *dt ) +{ + // read the command + FS_Read( cls.demofile, cmd, sizeof( byte )); + ASSERT( *cmd >= 1 && *cmd <= dem_lastcmd ); + + // read the timestamp + FS_Read( cls.demofile, dt, sizeof( float )); +} + +/* +================= +CL_ReadDemoUserCmd + +read the demo usercmd for predicting +and smooth movement during playback the demo +================= +*/ +void CL_ReadDemoUserCmd( qboolean discard ) +{ + byte data[1024]; + int cmdnumber; + int outgoing_sequence; + runcmd_t *pcmd; + word bytes; + + FS_Read( cls.demofile, &outgoing_sequence, sizeof( int )); + FS_Read( cls.demofile, &cmdnumber, sizeof( int )); + FS_Read( cls.demofile, &bytes, sizeof( short )); + FS_Read( cls.demofile, data, bytes ); + + if( !discard ) + { + usercmd_t nullcmd; + sizebuf_t buf; + + Q_memset( &nullcmd, 0, sizeof( nullcmd )); + BF_Init( &buf, "UserCmd", data, sizeof( data )); + + pcmd = &cl.commands[cmdnumber & CL_UPDATE_MASK]; + pcmd->processedfuncs = false; + pcmd->senttime = 0.0f; + pcmd->receivedtime = 0.1f; + pcmd->frame_lerp = 0.1f; + pcmd->heldback = false; + pcmd->sendsize = 1; + + // always delta'ing from null + cl.refdef.cmd = &pcmd->cmd; + + MSG_ReadDeltaUsercmd( &buf, &nullcmd, cl.refdef.cmd ); + + // NOTE: we need to have the current outgoing sequence correct + // so we can do prediction correctly during playback + cls.netchan.outgoing_sequence = outgoing_sequence; + } +} + +/* +================= +CL_ReadDemoSequence + +read netchan sequences +================= +*/ +void CL_ReadDemoSequence( qboolean discard ) +{ + int incoming_sequence; + int incoming_acknowledged; + int incoming_reliable_acknowledged; + int incoming_reliable_sequence; + int outgoing_sequence; + int reliable_sequence; + int last_reliable_sequence; + + FS_Read( cls.demofile, &incoming_sequence, sizeof( int )); + FS_Read( cls.demofile, &incoming_acknowledged, sizeof( int )); + FS_Read( cls.demofile, &incoming_reliable_acknowledged, sizeof( int )); + FS_Read( cls.demofile, &incoming_reliable_sequence, sizeof( int )); + FS_Read( cls.demofile, &outgoing_sequence, sizeof( int )); + FS_Read( cls.demofile, &reliable_sequence, sizeof( int )); + FS_Read( cls.demofile, &last_reliable_sequence, sizeof( int )); + + if( discard ) return; + + cls.netchan.incoming_sequence = incoming_sequence; + cls.netchan.incoming_acknowledged = incoming_acknowledged; + cls.netchan.incoming_reliable_acknowledged = incoming_reliable_acknowledged; + cls.netchan.incoming_reliable_sequence = incoming_reliable_sequence; + cls.netchan.outgoing_sequence = outgoing_sequence; + cls.netchan.reliable_sequence = reliable_sequence; + cls.netchan.last_reliable_sequence = last_reliable_sequence; +} + +/* +================= +CL_DemoCompleted +================= +*/ +void CL_DemoCompleted( void ) +{ + if( cls.demonum != -1 ) + cls.changedemo = true; + + CL_StopPlayback(); + + if( !CL_NextDemo() && host.developer <= 2 ) + UI_SetActiveMenu( true ); +} + +/* +================= +CL_DemoMoveToNextSection + +returns true on success, false on failure +g-cont. probably captain obvious mode is ON +================= +*/ +qboolean CL_DemoMoveToNextSection( void ) +{ + if( ++demo.entryIndex >= demo.directory.numentries ) + { + // done + CL_DemoCompleted(); + return false; + } + + // switch to next section, we got a dem_stop + demo.entry = &demo.directory.entries[demo.entryIndex]; + + // ready to continue reading, reset clock. + FS_Seek( cls.demofile, demo.entry->offset, SEEK_SET ); + + // time is now relative to this chunk's clock. + demo.starttime = CL_GetDemoPlaybackClock(); + demo.framecount = 0; + + return true; +} + +qboolean CL_ReadRawNetworkData( byte *buffer, size_t *length ) +{ + int msglen = 0; + + ASSERT( buffer != NULL ); + ASSERT( length != NULL ); + + *length = 0; // assume we fail + FS_Read( cls.demofile, &msglen, sizeof( int )); + + if( msglen < 0 ) + { + MsgDev( D_ERROR, "Demo message length < 0\n" ); + CL_DemoCompleted(); + return false; + } + + if( msglen < 8 ) + { + MsgDev( D_NOTE, "read runt demo message\n" ); + } + + if( msglen > NET_MAX_PAYLOAD ) + { + MsgDev( D_ERROR, "Demo message %i > %i\n", msglen, NET_MAX_PAYLOAD ); + CL_DemoCompleted(); + return false; + } + + if( msglen > 0 ) + { + if( FS_Read( cls.demofile, buffer, msglen ) != msglen ) + { + MsgDev( D_ERROR, "Error reading demo message data\n" ); + CL_DemoCompleted(); + return false; + } + } + + *length = msglen; + + if( cls.state != ca_active ) + Cbuf_Execute(); + + return true; +} + +/* +================= +CL_DemoReadMessage + +reads demo data and write it to client +================= +*/ +qboolean CL_DemoReadMessage( byte *buffer, size_t *length ) +{ + float f = 0.0f; + int curpos = 0; + float fElapsedTime = 0.0f; + qboolean swallowmessages = true; + byte *userbuf = NULL; + size_t size; + byte cmd; + + if( !cls.demofile ) + { + MsgDev( D_ERROR, "tried to read a demo message with no demo file\n" ); + CL_DemoCompleted(); + return false; + } + + // HACKHACK: changedemo issues + if( !cls.netchan.remote_address.type ) + cls.netchan.remote_address.type = NA_LOOPBACK; + + if(( !cl.background && ( cl.refdef.paused || cls.key_dest != key_game )) || cls.key_dest == key_console ) + { + demo.starttime += host.frametime; + return false; // paused + } + + do + { + qboolean bSkipMessage = false; + + if( !cls.demofile ) break; + curpos = FS_Tell( cls.demofile ); + + CL_ReadDemoCmdHeader( &cmd, &f ); + + fElapsedTime = CL_GetDemoPlaybackClock() - demo.starttime; + bSkipMessage = (f >= fElapsedTime) ? true : false; + + if( cls.changelevel ) + demo.framecount = 1; + + // HACKHACK: changelevel issues + if( demo.framecount <= 10 && ( fElapsedTime - f ) > host.frametime ) + demo.starttime = CL_GetDemoPlaybackClock(); + + // not ready for a message yet, put it back on the file. + if( cmd != dem_norewind && cmd != dem_stop && bSkipMessage ) + { + // never skip first message + if( demo.framecount != 0 ) + { + FS_Seek( cls.demofile, curpos, SEEK_SET ); + return false; // not time yet. + } + } + + // COMMAND HANDLERS + switch( cmd ) + { + case dem_jumptime: + demo.starttime = CL_GetDemoPlaybackClock(); + break; + case dem_stop: + CL_DemoMoveToNextSection(); + break; + case dem_userdata: + FS_Read( cls.demofile, &size, sizeof( int )); + userbuf = Mem_Alloc( cls.mempool, size ); + FS_Read( cls.demofile, userbuf, size ); + + if( clgame.hInstance ) + clgame.dllFuncs.pfnDemo_ReadBuffer( size, userbuf ); + Mem_Free( userbuf ); + userbuf = NULL; + break; + case dem_usercmd: + CL_ReadDemoUserCmd( false ); + break; + default: + swallowmessages = false; + break; + } + } while( swallowmessages ); + + if( !cls.demofile ) + return false; + + // if not on "LOADING" section, check a few things + if( demo.entryIndex ) + { + // We are now on the second frame of a new section, + // if so, reset start time (unless in a timedemo) + if( demo.framecount == 1 ) + { + // cheat by moving the relative start time forward. + demo.starttime = CL_GetDemoPlaybackClock(); + } + } + + demo.framecount++; + CL_ReadDemoSequence( false ); + + return CL_ReadRawNetworkData( buffer, length ); +} + +/* +============== +CL_StopPlayback + +Called when a demo file runs out, or the user starts a game +============== +*/ +void CL_StopPlayback( void ) +{ + if( !cls.demoplayback ) return; + + // release demofile + FS_Close( cls.demofile ); + cls.demoplayback = false; + demo.framecount = 0; + cls.demofile = NULL; + + cls.olddemonum = max( -1, cls.demonum - 1 ); + Mem_Free( demo.directory.entries ); + demo.directory.numentries = 0; + demo.directory.entries = NULL; + demo.entry = NULL; + + cls.demoname[0] = '\0'; // clear demoname too + menu.globals->demoname[0] = '\0'; + + S_StopAllSounds(); + S_StopBackgroundTrack(); + + if( !cls.changedemo ) + { + // let game known about demo state + Cvar_FullSet( "cl_background", "0", CVAR_READ_ONLY ); + cls.state = ca_disconnected; + Q_memset( &cls.serveradr, 0, sizeof( cls.serveradr ) ); + cl.background = 0; + cls.demonum = -1; + } +} + +/* +================== +CL_GetComment +================== +*/ +qboolean CL_GetComment( const char *demoname, char *comment ) +{ + file_t *demfile; + demoheader_t demohdr; + demodirectory_t directory; + demoentry_t entry; + float playtime = 0.0f; + int i; + + if( !comment ) return false; + + demfile = FS_Open( demoname, "rb", false ); + if( !demfile ) + { + Q_strncpy( comment, "", MAX_STRING ); + return false; + } + + // read in the m_DemoHeader + FS_Read( demfile, &demohdr, sizeof( demoheader_t )); + + if( demohdr.id != IDEMOHEADER ) + { + FS_Close( demfile ); + Q_strncpy( comment, "", MAX_STRING ); + return false; + } + + if( demohdr.net_protocol != PROTOCOL_VERSION || demohdr.dem_protocol != DEMO_PROTOCOL ) + { + FS_Close( demfile ); + Q_strncpy( comment, "", MAX_STRING ); + return false; + } + + // now read in the directory structure. + FS_Seek( demfile, demohdr.directory_offset, SEEK_SET ); + FS_Read( demfile, &directory.numentries, sizeof( int )); + + if( directory.numentries < 1 || directory.numentries > 1024 ) + { + FS_Close( demfile ); + Q_strncpy( comment, "", MAX_STRING ); + return false; + } + + for( i = 0; i < directory.numentries; i++ ) + { + FS_Read( demfile, &entry, sizeof( demoentry_t )); + playtime += entry.playback_time; + } + + // split comment to sections + Q_strncpy( comment, demohdr.mapname, CS_SIZE ); + Q_strncpy( comment + CS_SIZE, "", CS_SIZE ); // TODO: write titles or somewhat + Q_strncpy( comment + CS_SIZE * 2, va( "%g sec", playtime ), CS_TIME ); + + // all done + FS_Close( demfile ); + + return true; +} + +/* +================== +CL_NextDemo + +Called when a demo or cinematic finishes +If the "nextdemo" cvar is set, that command will be issued +================== +*/ +qboolean CL_NextDemo( void ) +{ + string str; + + if( cls.demonum == -1 ) + return false; // don't play demos + S_StopAllSounds(); + + if( !cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS ) + { + cls.demonum = 0; + if( !cls.demos[cls.demonum][0] ) + { + MsgDev( D_INFO, "no demos listed with startdemos\n" ); + cls.demonum = -1; + return false; + } + } + + Q_snprintf( str, MAX_STRING, "playdemo %s\n", cls.demos[cls.demonum] ); + + Cbuf_InsertText( str ); + cls.demonum++; + + return true; +} + +/* +================== +CL_DemoGetName +================== +*/ +void CL_DemoGetName( int lastnum, char *filename ) +{ + if( !filename ) + return; + + if( lastnum < 0 || lastnum > 9999 ) + { + // bound + Q_strcpy( filename, "demo9999" ); + return; + } + + + Q_sprintf( filename, "demo%04d", lastnum ); +} + +/* +==================== +CL_Record_f + +record +Begins recording a demo from the current position +==================== +*/ +void CL_Record_f( void ) +{ + const char *name; + string demoname, demopath, demoshot; + int n; + + if( Cmd_Argc() == 1 ) + { + name = "new"; + } + else if( Cmd_Argc() == 2 ) + { + name = Cmd_Argv( 1 ); + } + else + { + Msg( "Usage: record \n" ); + return; + } + + if( cls.demorecording ) + { + Msg( "Already recording.\n"); + return; + } + + if( cls.demoplayback ) + { + Msg( "Can't record during demo playback.\n"); + return; + } + + if( !cls.demoheader || cls.state != ca_active ) + { + Msg( "You must be in a level to record.\n"); + return; + } + + if( !Q_stricmp( name, "new" )) + { + // scan for a free filename + for( n = 0; n < 10000; n++ ) + { + CL_DemoGetName( n, demoname ); + if( !FS_FileExists( va( "demos/%s.dem", demoname ), true )) + break; + } + + if( n == 10000 ) + { + Msg( "^3ERROR: no free slots for demo recording\n" ); + return; + } + } + else Q_strncpy( demoname, name, sizeof( demoname )); + + // open the demo file + Q_sprintf( demopath, "demos/%s.dem", demoname ); + Q_sprintf( demoshot, "demos/%s.bmp", demoname ); + + // make sure what old demo is removed + if( FS_FileExists( demopath, false )) FS_Delete( demopath ); + if( FS_FileExists( demoshot, false )) FS_Delete( demoshot ); + + // write demoshot for preview + Cbuf_AddText( va( "demoshot \"%s\"\n", demoname )); + Q_strncpy( cls.demoname, demoname, sizeof( cls.demoname )); + Q_strncpy( menu.globals->demoname, demoname, sizeof( menu.globals->demoname )); + + CL_WriteDemoHeader( demopath ); +} + +/* +==================== +CL_PlayDemo_f + +playdemo +==================== +*/ +void CL_PlayDemo_f( void ) +{ + string filename; + string demoname; + int i; + + if( Cmd_Argc() != 2 ) + { + Msg( "Usage: playdemo \n" ); + return; + } + + if( cls.demoplayback ) + { + CL_StopPlayback(); + } + + if( cls.demorecording ) + { + Msg( "Can't playback during demo record.\n"); + return; + } + + Q_strncpy( demoname, Cmd_Argv( 1 ), sizeof( demoname ) - 1 ); + Q_snprintf( filename, sizeof( filename ), "demos/%s.dem", demoname ); + + if( !FS_FileExists( filename, true )) + { + MsgDev( D_ERROR, "couldn't open %s\n", filename ); + cls.demonum = -1; // stop demo loop + return; + } + + cls.demofile = FS_Open( filename, "rb", true ); + Q_strncpy( cls.demoname, demoname, sizeof( cls.demoname )); + Q_strncpy( menu.globals->demoname, demoname, sizeof( menu.globals->demoname )); + + // read in the m_DemoHeader + FS_Read( cls.demofile, &demo.header, sizeof( demoheader_t )); + + if( demo.header.id != IDEMOHEADER ) + { + MsgDev( D_ERROR, "%s is not a demo file\n", filename ); + FS_Close( cls.demofile ); + cls.demofile = NULL; + cls.demonum = -1; // stop demo loop + return; + } + + if( demo.header.net_protocol != PROTOCOL_VERSION || demo.header.dem_protocol != DEMO_PROTOCOL ) + { + MsgDev( D_ERROR, "demo protocol outdated\n" + "Demo file protocols Network(%i), Demo(%i)\n" + "Server protocol is at Network(%i), Demo(%i)\n", + demo.header.net_protocol, + demo.header.dem_protocol, + PROTOCOL_VERSION, + DEMO_PROTOCOL + ); + + FS_Close( cls.demofile ); + cls.demofile = NULL; + cls.demonum = -1; // stop demo loop + return; + } + + // now read in the directory structure. + FS_Seek( cls.demofile, demo.header.directory_offset, SEEK_SET ); + FS_Read( cls.demofile, &demo.directory.numentries, sizeof( int )); + + if( demo.directory.numentries < 1 || demo.directory.numentries > 1024 ) + { + MsgDev( D_ERROR, "demo had bogus # of directory entries: %i\n", demo.directory.numentries ); + FS_Close( cls.demofile ); + cls.demofile = NULL; + cls.demonum = -1; // stop demo loop + cls.changedemo = false; + return; + } + + if( cls.changedemo ) + { + S_StopAllSounds(); + SCR_BeginLoadingPlaque( false ); + + CL_ClearState (); + CL_InitEdicts (); // re-arrange edicts + } + else + { + // NOTE: at this point demo is still valid + CL_Disconnect(); + Host_ShutdownServer(); + + Con_Close(); + UI_SetActiveMenu( false ); + } + + // allocate demo entries + demo.directory.entries = Mem_Alloc( cls.mempool, sizeof( demoentry_t ) * demo.directory.numentries ); + + for( i = 0; i < demo.directory.numentries; i++ ) + { + FS_Read( cls.demofile, &demo.directory.entries[i], sizeof( demoentry_t )); + } + + demo.entryIndex = 0; + demo.entry = &demo.directory.entries[demo.entryIndex]; + + FS_Seek( cls.demofile, demo.entry->offset, SEEK_SET ); + + cls.demoplayback = true; + cls.state = ca_connected; + cl.background = (cls.demonum != -1) ? true : false; + + demo.starttime = CL_GetDemoPlaybackClock(); // for determining whether to read another message + + Netchan_Setup( NS_CLIENT, &cls.netchan, net_from, net_qport->integer ); + + demo.framecount = 0; + cls.lastoutgoingcommand = -1; + cls.nextcmdtime = host.realtime; + + // g-cont. is this need? + Q_strncpy( cls.servername, demoname, sizeof( cls.servername )); + + // begin a playback demo +} + +/* +================== +CL_StartDemos_f +================== +*/ +void CL_StartDemos_f( void ) +{ + int i, c; + + if( cls.key_dest != key_menu ) + { + MsgDev( D_INFO, "startdemos is not valid from the console\n" ); + return; + } + + c = Cmd_Argc() - 1; + if( c > MAX_DEMOS ) + { + MsgDev( D_WARN, "Host_StartDemos: max %i demos in demoloop\n", MAX_DEMOS ); + c = MAX_DEMOS; + } + + MsgDev( D_INFO, "%i demo%s in loop\n", c, (c > 1) ? "s" : "" ); + + for( i = 1; i < c + 1; i++ ) + Q_strncpy( cls.demos[i-1], Cmd_Argv( i ), sizeof( cls.demos[0] )); + + if( !SV_Active() && !cls.demoplayback ) + { + // run demos loop in background mode + Cvar_SetFloat( "v_dark", 1.0f ); + cls.demonum = 0; + CL_NextDemo (); + } + else cls.demonum = -1; +} + +/* +================== +CL_Demos_f + +Return to looping demos +================== +*/ +void CL_Demos_f( void ) +{ + if( cls.key_dest != key_menu ) + { + MsgDev( D_INFO, "demos is not valid from the console\n" ); + return; + } + + cls.demonum = cls.olddemonum; + + if( cls.demonum == -1 ) + cls.demonum = 0; + + if( !SV_Active() && !cls.demoplayback ) + { + // run demos loop in background mode + cls.changedemo = true; + CL_NextDemo (); + } +} + + +/* +==================== +CL_Stop_f + +stop any client activity +==================== +*/ +void CL_Stop_f( void ) +{ + // stop all + CL_StopRecord(); + CL_StopPlayback(); + SCR_StopCinematic(); + + // stop background track that was runned from the console + if( !SV_Active( )) + { + S_StopBackgroundTrack(); + } +} +#endif // XASH_DEDICATED diff --git a/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_events.c b/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_events.c new file mode 100644 index 0000000..b4cdef0 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_events.c @@ -0,0 +1,513 @@ +/* +cl_events.c - client-side event system implementation +Copyright (C) 2011 Uncle Mike + +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 3 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. +*/ + +#ifndef XASH_DEDICATED + +#include "common.h" +#include "client.h" +#include "event_flags.h" +#include "net_encode.h" + +/* +=============== +CL_ResetEvent + +=============== +*/ +void CL_ResetEvent( event_info_t *ei ) +{ + Q_memset( ei, 0, sizeof( *ei )); +} + +/* +============= +CL_SetEventIndex + +============= +*/ +void CL_SetEventIndex( const char *szEvName, int ev_index ) +{ + cl_user_event_t *ev; + int i; + + if( !szEvName || !*szEvName ) + return; // ignore blank names + + // search event by name to link with + for( i = 0; i < MAX_EVENTS; i++ ) + { + ev = clgame.events[i]; + if( !ev ) break; + + if( !Q_stricmp( ev->name, szEvName )) + { + ev->index = ev_index; + return; + } + } +} + +/* +============= +CL_EventIndex + +============= +*/ +word GAME_EXPORT CL_EventIndex( const char *name ) +{ + int i; + + if( !name || !name[0] ) + return 0; + + for( i = 1; i < MAX_EVENTS && cl.event_precache[i][0]; i++ ) + { + if( !Q_stricmp( cl.event_precache[i], name )) + return i; + } + return 0; +} + +/* +============= +CL_EventIndex + +============= +*/ +const char *GAME_EXPORT CL_IndexEvent( word index ) +{ + if( index >= MAX_EVENTS ) + return 0; + + return cl.event_precache[index]; +} + +/* +============= +CL_RegisterEvent + +============= +*/ +void CL_RegisterEvent( int lastnum, const char *szEvName, pfnEventHook func ) +{ + cl_user_event_t *ev; + + if( lastnum == MAX_EVENTS ) + { + MsgDev( D_ERROR, "CL_RegisterEvent: MAX_EVENTS hit!\n" ); + return; + } + + // clear existing or allocate new one + if( !clgame.events[lastnum] ) + clgame.events[lastnum] = Mem_Alloc( cls.mempool, sizeof( cl_user_event_t )); + else Q_memset( clgame.events[lastnum], 0, sizeof( cl_user_event_t )); + + ev = clgame.events[lastnum]; + + // NOTE: ev->index will be set later + Q_strncpy( ev->name, szEvName, CS_SIZE ); + ev->func = func; +} + +/* +============= +CL_FireEvent + +============= +*/ +qboolean CL_FireEvent( event_info_t *ei ) +{ + cl_user_event_t *ev; + const char *name; + int i, idx; + + if( !ei || !ei->index ) + return false; + + if( cl_trace_events->integer ) + { + MsgDev( D_INFO, "^3EVENT %s AT %.2f %.2f %.2f\n" // event name + " %.2f %.2f\n" // float params + " %i %i\n" // int params + " %s %s\n", // bool params + cl.event_precache[ bound( 1, ei->index, MAX_EVENTS )], ei->args.origin[0], ei->args.origin[1], ei->args.origin[2], + ei->args.fparam1, ei->args.fparam2, + ei->args.iparam1, ei->args.iparam2, + ei->args.bparam1 ? "TRUE" : "FALSE", ei->args.bparam2 ? "TRUE" : "FALSE" ); + + } + + // get the func pointer + for( i = 0; i < MAX_EVENTS; i++ ) + { + ev = clgame.events[i]; + + if( !ev ) + { + idx = bound( 1, ei->index, MAX_EVENTS ); + MsgDev( D_ERROR, "CL_FireEvent: %s not precached\n", cl.event_precache[idx] ); + break; + } + + if( ev->index == ei->index ) + { + if( ev->func ) + { + ev->func( &ei->args ); + return true; + } + + name = cl.event_precache[ei->index]; + MsgDev( D_ERROR, "CL_FireEvent: %s not hooked\n", name ); + break; + } + } + + return false; +} + +/* +============= +CL_FireEvents + +called right before draw frame +============= +*/ +void CL_FireEvents( void ) +{ + int i; + event_state_t *es; + event_info_t *ei; + qboolean success; + + es = &cl.events; + + for( i = 0; i < MAX_EVENT_QUEUE; i++ ) + { + ei = &es->ei[i]; + + if( ei->index == 0 ) + continue; + + // delayed event! + if( ei->fire_time && ( ei->fire_time > cl.time )) + continue; + + success = CL_FireEvent( ei ); + + // zero out the remaining fields + CL_ResetEvent( ei ); + } +} + +/* +============= +CL_FindEvent + +find first empty event +============= +*/ +event_info_t *CL_FindEmptyEvent( void ) +{ + int i; + event_state_t *es; + event_info_t *ei; + + es = &cl.events; + + // look for first slot where index is != 0 + for( i = 0; i < MAX_EVENT_QUEUE; i++ ) + { + ei = &es->ei[i]; + if( ei->index != 0 ) + continue; + return ei; + } + + // no slots available + return NULL; +} + +/* +============= +CL_FindEvent + +replace only unreliable events +============= +*/ +event_info_t *CL_FindUnreliableEvent( void ) +{ + event_state_t *es; + event_info_t *ei; + int i; + + es = &cl.events; + + for ( i = 0; i < MAX_EVENT_QUEUE; i++ ) + { + ei = &es->ei[i]; + if( ei->index != 0 ) + { + // it's reliable, so skip it + if( ei->flags & FEV_RELIABLE ) + continue; + } + return ei; + } + + // this should never happen + return NULL; +} + +/* +============= +CL_QueueEvent + +============= +*/ +void CL_QueueEvent( int flags, int index, float delay, event_args_t *args ) +{ + qboolean unreliable = (flags & FEV_RELIABLE) ? false : true; + event_info_t *ei; + + // find a normal slot + ei = CL_FindEmptyEvent(); + + if( !ei && unreliable ) + return; + + // okay, so find any old unreliable slot + if( !ei ) + { + ei = CL_FindUnreliableEvent(); + if( !ei ) return; + } + + ei->index = index; + ei->fire_time = delay ? (cl.time + delay) : 0.0f; + ei->flags = flags; + ei->args = *args; +} + +/* +============= +CL_ParseReliableEvent + +============= +*/ +void CL_ParseReliableEvent( sizebuf_t *msg ) +{ + int event_index; + event_args_t nullargs, args; + float delay = 0.0f; + cl_entity_t *pEnt; + + Q_memset( &nullargs, 0, sizeof( nullargs )); + + event_index = BF_ReadUBitLong( msg, MAX_EVENT_BITS ); + + if( BF_ReadOneBit( msg )) + delay = (float)BF_ReadWord( msg ) * (1.0f / 100.0f); + + // reliable events not use delta-compression just null-compression + MSG_ReadDeltaEvent( msg, &nullargs, &args ); + + if(( pEnt = CL_GetEntityByIndex( args.entindex )) != NULL ) + { + if( VectorIsNull( args.origin )) + VectorCopy( pEnt->curstate.origin, args.origin ); + if( VectorIsNull( args.angles )) + VectorCopy( pEnt->curstate.angles, args.angles ); + if( VectorIsNull( args.velocity )) + VectorCopy( pEnt->curstate.velocity, args.velocity ); + } + + CL_QueueEvent( FEV_RELIABLE|FEV_SERVER, event_index, delay, &args ); +} + + +/* +============= +CL_ParseEvent + +============= +*/ +void CL_ParseEvent( sizebuf_t *msg ) +{ + int event_index; + int i, num_events; + int packet_ent; + event_args_t nullargs, args; + qboolean has_update; + entity_state_t *state; + cl_entity_t *pEnt; + float delay; + + Q_memset( &nullargs, 0, sizeof( nullargs )); + + num_events = BF_ReadUBitLong( msg, 5 ); + + // parse events queue + for( i = 0 ; i < num_events; i++ ) + { + event_index = BF_ReadUBitLong( msg, MAX_EVENT_BITS ); + Q_memset( &args, 0, sizeof( args )); + has_update = false; + + if( BF_ReadOneBit( msg )) + { + packet_ent = BF_ReadUBitLong( msg, MAX_ENTITY_BITS ); + + if( BF_ReadOneBit( msg )) + { + MSG_ReadDeltaEvent( msg, &nullargs, &args ); + has_update = true; + } + } + else packet_ent = -1; + + if( packet_ent != -1 ) + state = &cls.packet_entities[(cl.frame.first_entity+packet_ent)%cls.num_client_entities]; + else state = NULL; + + // it's a client. Override some params + if( args.entindex >= 1 && args.entindex <= cl.maxclients ) + { + if(( args.entindex - 1 ) == cl.playernum ) + { + if( state && !CL_IsPredicted( )) + { + // restore viewangles from angles + args.angles[PITCH] = -state->angles[PITCH] * 3; + args.angles[YAW] = state->angles[YAW]; + args.angles[ROLL] = 0; // no roll + } + else + { + // get the predicted angles + VectorCopy( cl.refdef.cl_viewangles, args.angles ); + } + + VectorCopy( cl.frame.client.origin, args.origin ); + VectorCopy( cl.frame.client.velocity, args.velocity ); + } + else if( state ) + { + // restore viewangles from angles + args.angles[PITCH] = -state->angles[PITCH] * 3; + args.angles[YAW] = state->angles[YAW]; + args.angles[ROLL] = 0; // no roll + + // if we restore origin and velocity everytime, why don't do it here also? + if( VectorIsNull( args.origin )) + VectorCopy( state->origin, args.origin ); + if( VectorIsNull( args.velocity )) + VectorCopy( state->velocity, args.velocity ); + } + } + else if( state ) + { + if( VectorIsNull( args.origin )) + VectorCopy( state->origin, args.origin ); + if( VectorIsNull( args.angles )) + VectorCopy( state->angles, args.angles ); + if( VectorIsNull( args.velocity )) + VectorCopy( state->velocity, args.velocity ); + } + else if(( pEnt = CL_GetEntityByIndex( args.entindex )) != NULL ) + { + if( VectorIsNull( args.origin )) + VectorCopy( pEnt->curstate.origin, args.origin ); + if( VectorIsNull( args.angles )) + VectorCopy( pEnt->curstate.angles, args.angles ); + if( VectorIsNull( args.velocity )) + VectorCopy( pEnt->curstate.velocity, args.velocity ); + } + + if( BF_ReadOneBit( msg )) + delay = (float)BF_ReadWord( msg ) * (1.0f / 100.0f); + else delay = 0.0f; + + // g-cont. should we need find the event with same index? + CL_QueueEvent( 0, event_index, delay, &args ); + } +} + +/* +============= +CL_PlaybackEvent + +============= +*/ +void GAME_EXPORT CL_PlaybackEvent( int flags, const edict_t *pInvoker, word eventindex, float delay, float *origin, + float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ) +{ + event_args_t args; + int invokerIndex = 0; + + // first check event for out of bounds + if( eventindex < 1 || eventindex > MAX_EVENTS ) + { + MsgDev( D_ERROR, "CL_PlaybackEvent: invalid eventindex %i\n", eventindex ); + return; + } + + + if( flags & FEV_SERVER ) + { + MsgDev( D_WARN, "CL_PlaybackEvent: event with FEV_SERVER flag!\n" ); + return; + } + + // check event for precached + if( !CL_EventIndex( cl.event_precache[eventindex] )) + { + MsgDev( D_ERROR, "CL_PlaybackEvent: event %i was not precached\n", eventindex ); + return; + } + + flags |= FEV_CLIENT; // it's a client event + flags &= ~(FEV_NOTHOST|FEV_HOSTONLY|FEV_GLOBAL); + + if( delay < 0.0f ) delay = 0.0f; // fixup negative delays + invokerIndex = cl.playernum + 1; // only local client can issue client events + + args.flags = 0; + args.entindex = invokerIndex; + + if( !angles || VectorIsNull( angles )) + VectorCopy( cl.refdef.cl_viewangles, args.angles ); + else + VectorCopy( angles, args.angles ); + + if( !origin || VectorIsNull( origin )) + VectorCopy( cl.predicted.origin, args.origin ); + else + VectorCopy( origin, args.origin ); + + VectorCopy( cl.predicted.velocity, args.velocity ); + args.ducking = cl.predicted.usehull == 1; + + args.fparam1 = fparam1; + args.fparam2 = fparam2; + args.iparam1 = iparam1; + args.iparam2 = iparam2; + args.bparam1 = bparam1; + args.bparam2 = bparam2; + + CL_QueueEvent( flags, eventindex, delay, &args ); +} +#endif // XASH_DEDICATED diff --git a/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_frame.c b/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_frame.c new file mode 100644 index 0000000..98eebcd --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_frame.c @@ -0,0 +1,1377 @@ +/* +cl_frame.c - client world snapshot +Copyright (C) 2008 Uncle Mike + +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 3 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. +*/ + +#ifndef XASH_DEDICATED + +#include "common.h" +#include "client.h" +#include "net_encode.h" +#include "entity_types.h" +#include "gl_local.h" +#include "pm_local.h" +#include "cl_tent.h" +#include "studio.h" +#include "sound.h" +#include "dlight.h" +#include "input.h" + +#define MAX_FORWARD 6 + +qboolean CL_IsPlayerIndex( int idx ) +{ + if( idx > 0 && idx <= cl.maxclients ) + return true; + return false; +} + +qboolean CL_IsPredicted( void ) +{ + if( !cl_predict->integer || !cl.frame.valid || cl.background || Host_IsLocalClient() ) + return false; + + if(( cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged ) >= ( CL_UPDATE_BACKUP - 1 )) + return false; + + return true; +} + +int CL_PushMoveFilter( physent_t *pe ) +{ + if( !pe || pe->solid != SOLID_BSP || pe->movetype != MOVETYPE_PUSH ) + return 1; + + // optimization. Ignore world to avoid + // unneeded transformations + if( pe->info == 0 ) + return 1; + + return 0; +} + +void CL_ResetPositions( cl_entity_t *ent ) +{ + // disabled to prevent FindInterpolationUpdates use wrong stored data + // re-enable when ent->ph[ent->current_position] will be actual + //position_history_t store = ent->ph[ent->current_position]; + + ent->current_position = 0; + //ent->current_position = 1; + + Q_memset( ent->ph, 0, sizeof( ent->ph ) ); + //ent->ph[1] = ent->ph[0] = store; +} + +/* +========================================================================= + +FRAME PARSING + +========================================================================= +*/ +/* +================== +CL_UpdatePositions + +Store another position into interpolation circular buffer +================== +*/ +void CL_UpdatePositions( cl_entity_t *ent ) +{ + position_history_t *ph; + + ent->current_position = (ent->current_position + 1) & HISTORY_MASK; + + ph = &ent->ph[ent->current_position]; + + VectorCopy( ent->curstate.origin, ph->origin ); + VectorCopy( ent->curstate.angles, ph->angles ); + ph->animtime = ent->curstate.msg_time; +} + +/* +================== +CL_FindInterpolationUpdates + +find two timestamps +================== +*/ +qboolean CL_FindInterpolationUpdates( cl_entity_t *ent, float targettime, position_history_t **ph0, position_history_t **ph1 ) +{ + qboolean extrapolate = true; + int i, i0, i1, imod; + float at; + + // Debug on grenade + // qboolean debug = !Q_strcmp( ent->model->name, "models/w_grenade.mdl" ); + // qboolean debug = ent->index == cl.playernum; + + i0 = ( ent->current_position ) & HISTORY_MASK; + i1 = ( ent->current_position - 1 ) & HISTORY_MASK; + imod = ent->current_position; + + for ( i = 1 ; i < HISTORY_MAX - 1 ; i++ ) + { + at = ent->ph[ ( imod - i ) & HISTORY_MASK ].animtime; + + if( at == 0.0 ) + break; + + if( at < targettime ) + { + i0 = ( ( imod - i ) + 1 ) & HISTORY_MASK; + i1 = ( imod - i ) & HISTORY_MASK; + extrapolate = false; + break; + } + } + + if( ph0 != NULL ) *ph0 = &ent->ph[i0]; + if( ph1 != NULL ) *ph1 = &ent->ph[i1]; + + return extrapolate; +} + +/* +================== +CL_EntityTeleported + +Check is entity teleported +================== +*/ +_inline qboolean CL_EntityTeleported( cl_entity_t *e ) +{ + return fabs(e->curstate.origin[0] - e->prevstate.origin[0]) > 128.0f || + fabs(e->curstate.origin[1] - e->prevstate.origin[1]) > 128.0f || + fabs(e->curstate.origin[2] - e->prevstate.origin[2]) > 128.0f; +} + +/* +================== +CL_PureOrigin + +non-local players interpolation +================== +*/ +void CL_PureOrigin( cl_entity_t *ent, float t, vec3_t outorigin, vec3_t outangles ) +{ + position_history_t *ph0, *ph1; + float t1, t0; + float frac; + vec3_t delta; + vec3_t pos, angles; + + CL_FindInterpolationUpdates( ent, t, &ph0, &ph1 ); + + if( !ph0 || !ph1 ) + return; + + t0 = ph0->animtime; + t1 = ph1->animtime; + + if( t0 != 0 ) + { + VectorSubtract( ph0->origin, ph1->origin, delta ); + + if ( t0 != t1 ) + frac = bound( 0.0, ( t - t1 ) / ( t0 - t1 ), 1.2f ); // players are allowed to extrapolate + else + frac = 1.0f; + + VectorMA( ph1->origin, frac, delta, pos ); + InterpolateAngles( ph0->angles, ph1->angles, angles, frac ); + + VectorCopy( pos, outorigin ); + VectorCopy( angles, outangles ); + } + else + { + VectorCopy( ph1->origin, outorigin ); + VectorCopy( ph1->angles, outangles ); + } +} + +/* +==================== +CL_ComputePlayerOrigin + +non-local players interpolation +==================== +*/ +void CL_ComputePlayerOrigin( cl_entity_t *e ) +{ + float t; + + if( e->index == cl.playernum + 1 ) + { + VectorCopy( cl.predicted.origin, e->origin ); + VectorCopy( e->curstate.angles, e->angles ); + return; + } + else + { + VectorCopy( e->curstate.origin, e->origin ); + VectorCopy( e->curstate.angles, e->angles ); + } + + // enitty was moved too far + if( CL_EntityTeleported( e ) ) + { + VectorCopy( e->curstate.origin, e->origin ); + VectorCopy( e->curstate.angles, e->angles ); + + CL_ResetPositions( e ); + return; + } + + t = cl.time - cl_interp->value; + CL_PureOrigin( e, t, e->origin, e->angles ); +} + +/* +==================== +CL_InterpolateModel + +non-players interpolation +==================== +*/ +qboolean CL_InterpolateModel( cl_entity_t *e ) +{ + position_history_t *ph0 = NULL, *ph1 = NULL; + vec3_t origin, angles, delta; + float t, t1, t2, frac; + qboolean extrapolate; + + VectorCopy( e->curstate.origin, e->origin ); + VectorCopy( e->curstate.angles, e->angles ); + + // disable interpolating in singleplayer + if( cls.timedemo || NET_IsLocalAddress( cls.netchan.remote_address ) ) + return true; + + // disable interpolating non-moving entities + if( e->curstate.movetype == MOVETYPE_NONE ) + return true; + + // don't inerpolate modelless entities or bmodels + if( !e->model ) + return true; + + if( ( e->model->type == mod_brush || e->model->name[0] == '*' ) && !r_bmodelinterp->integer ) + return true; + + // skip entity on which we ride + if( cl.predicted.moving && cl.predicted.onground == e->index ) + return true; + + // recovering from delta error or cl_nodelta enabled + if( cl.delta_sequence < 1 ) + return true; + + t = cl.time - cl_interp->value; + + extrapolate = CL_FindInterpolationUpdates( e, t, &ph0, &ph1 ); + + t1 = ph1->animtime; + t2 = ph0->animtime; + + if( t < t1 ) + return false; + + if( extrapolate ) + { + if( e->model->type == mod_brush ) + return true; //keep curstate + + //Msg("%s %f %f %f %f\n", e->model->name, e->curstate.animtime, cl.time - e->curstate.msg_time, t1, t2 ); + + if( e->curstate.animtime == 0 ) + return false; // hide new non-interpolated entity + } + + if( t1 == 0 || ( VectorIsNull( ph1->origin ) && !VectorIsNull( ph0->origin ) ) ) + { + VectorCopy( ph0->origin, e->origin ); + VectorCopy( ph0->angles, e->angles ); + return false; + } + + if( t2 == t1 ) + { + VectorCopy( ph0->origin, e->origin ); + VectorCopy( ph0->angles, e->angles ); + return true; + } + + VectorSubtract( ph0->origin, ph1->origin, delta ); + + frac = ( t - t1 ) / ( t2 - t1 ); + + if( frac < 0 ) + return false; + + if( frac > 1.0f ) + frac = 1.0f ; + + VectorMA( ph1->origin, frac, delta, origin ); + + InterpolateAngles( ph0->angles, ph1->angles, angles, frac ); + + VectorCopy( origin, e->origin ); + VectorCopy( angles, e->angles ); + + return true; +} + +/* +============= +CL_IsParametricEntity + +parametric rockets code(see UTIL_ParametricRocket) +============= +*/ +_inline qboolean CL_IsParametricEntity( cl_entity_t *ent ) +{ + return ent->curstate.starttime != 0.0f && ent->curstate.impacttime != 0.0f; +} + +/* +============= +CL_ParametricMove + +parametric rockets code(see UTIL_ParametricRocket) +============= +*/ +void CL_ParametricMove( cl_entity_t *ent ) +{ + float lerp = ( cl.time - ent->curstate.starttime ) / ( ent->curstate.impacttime - ent->curstate.starttime ); + vec3_t dir; + + lerp = bound( 0.0f, lerp, 1.0f ); + + // first we need to calc actual origin + VectorLerp( ent->curstate.startpos, lerp, ent->curstate.endpos, ent->curstate.origin ); + VectorSubtract( ent->curstate.endpos, ent->curstate.startpos, dir ); + VectorAngles( dir, ent->curstate.angles ); // re-aim projectile +} + +/* +================== +CL_EntityCustomLerp + +================== +*/ +qboolean CL_EntityCustomLerp( cl_entity_t *e ) +{ + switch( e->curstate.movetype ) + { + case MOVETYPE_NONE: + case MOVETYPE_STEP: + case MOVETYPE_WALK: + case MOVETYPE_FLY: + case MOVETYPE_COMPOUND: + return false; + } + + return true; +} + + +/* +=============== +CL_UpdateEntityFields + +Try to interpolate entity. If can't, return zero and skip entity this frame +=============== +*/ +qboolean CL_UpdateEntityFields( cl_entity_t *ent ) +{ + ent->model = Mod_Handle( ent->curstate.modelindex ); + // ent->curstate.msg_time = cl.time; + + if( CL_IsParametricEntity( ent ) ) + { + CL_ParametricMove( ent ); + VectorCopy( ent->curstate.origin, ent->origin ); + VectorCopy( ent->curstate.angles, ent->angles ); + } + else if( ent->player ) + { + if( ent->curstate.modelindex && !ent->model ) + ent->model = Mod_ForName("models/player.mdl", false ); + + CL_ComputePlayerOrigin( ent ); //!!! Custom interpolation for players + } + else if( CL_EntityCustomLerp( ent ) ) + { + if( !CL_InterpolateModel( ent ) && ent->curstate.entityType != ENTITY_BEAM && + ent->model && ent->model->type != mod_brush ) + return false; // failed to interpolate entity, skip this frame + } + // this originally was allowed for only cstrike and czero + else if( ent->curstate.movetype == MOVETYPE_STEP && + !NET_IsLocalAddress( cls.netchan.remote_address ) ) + { + if( !CL_InterpolateModel( ent ) ) + return false; // failed to interpolate entity, skip this frame + } + else + { + // no interpolation right now + VectorCopy( ent->curstate.origin, ent->origin ); + VectorCopy( ent->curstate.angles, ent->angles ); + } + + if( ent->player && RP_LOCALCLIENT( ent )) // stupid Half-Life bug + ent->angles[PITCH] = -ent->angles[PITCH] / 3.0f; + + // make me lerp + if( ent->model && ent->model->type == mod_brush && ent->curstate.animtime != 0.0f) + { + float f = 0.0f; + + // don't do it if the goalstarttime hasn't updated in a while. + // NOTE: Because we need to interpolate multiplayer characters, the interpolation time limit + // was increased to 1.0 s., which is 2x the max lag we are accounting for. + if(( cl.time < ent->curstate.animtime + 1.0f ) && ( ent->curstate.animtime != ent->latched.prevanimtime )) + f = ( cl.time - ent->curstate.animtime ) / ( ent->curstate.animtime - ent->latched.prevanimtime ); + + f = f - 1.0f; + + ent->origin[0] += ( ent->origin[0] - ent->latched.prevorigin[0] ) * f; + ent->origin[1] += ( ent->origin[1] - ent->latched.prevorigin[1] ) * f; + ent->origin[2] += ( ent->origin[2] - ent->latched.prevorigin[2] ) * f; + + InterpolateAngles( ent->angles, ent->latched.prevangles, ent->angles, f ); + + } + else if( ent->curstate.eflags & EFLAG_SLERP ) + { + float f = 0.0f; + + // don't do it if the goalstarttime hasn't updated in a while. + // NOTE: Because we need to interpolate multiplayer characters, the interpolation time limit + // was increased to 1.0 s., which is 2x the max lag we are accounting for. + if(( cl.time < ent->curstate.animtime + 1.0f ) && ( ent->curstate.animtime != ent->latched.prevanimtime )) + f = ( cl.time - ent->curstate.animtime ) / ( ent->curstate.animtime - ent->latched.prevanimtime ); + + f = f - 1.0f; + + if( ent->curstate.movetype == MOVETYPE_FLY ) + { + ent->origin[0] += ( ent->curstate.origin[0] - ent->latched.prevorigin[0] ) * f; + ent->origin[1] += ( ent->curstate.origin[1] - ent->latched.prevorigin[1] ) * f; + ent->origin[2] += ( ent->curstate.origin[2] - ent->latched.prevorigin[2] ) * f; + + InterpolateAngles( ent->angles, ent->latched.prevangles, ent->angles, f ); + } + else if( ent->curstate.movetype == MOVETYPE_STEP ) + { + vec3_t vecSrc, vecEnd; + pmtrace_t trace; + cl_entity_t *m_pGround = NULL; + + if( ent->model ) + { + CL_SetTraceHull( 0 ); // g-cont. player hull for better detect moving platforms + VectorSet( vecSrc, ent->origin[0], ent->origin[1], ent->origin[2] + ent->model->maxs[2] ); + VectorSet( vecEnd, vecSrc[0], vecSrc[1], vecSrc[2] - ent->model->mins[2] - 8.0f ); + CL_PlayerTraceExt( vecSrc, vecEnd, PM_STUDIO_IGNORE, CL_PushMoveFilter, &trace ); + m_pGround = CL_GetEntityByIndex( pfnIndexFromTrace( &trace )); + } + + if( m_pGround && m_pGround->curstate.movetype == MOVETYPE_PUSH ) + { + qboolean applyVel, applyAvel; + + applyVel = !VectorCompare( m_pGround->curstate.origin, m_pGround->prevstate.origin ); + applyAvel = !VectorCompare( m_pGround->curstate.angles, m_pGround->prevstate.angles ); + + if( applyVel || applyAvel ) + { + ent->origin[0] += ( m_pGround->curstate.origin[0] - m_pGround->prevstate.origin[0] ) * -1.0f; + ent->origin[1] += ( m_pGround->curstate.origin[1] - m_pGround->prevstate.origin[1] ) * -1.0f; +// ent->origin[2] += ( m_pGround->curstate.origin[2] - m_pGround->prevstate.origin[2] ) * -1.0f; + ent->latched.prevorigin[2] = ent->origin[2]; + } + + if( applyAvel ) + { + InterpolateAngles( m_pGround->curstate.angles, m_pGround->prevstate.angles, ent->angles, -1.0f ); + } + } + + // moved code from StudioSetupTransform here + if( host.features & ENGINE_COMPUTE_STUDIO_LERP ) + { + ent->origin[0] += ( ent->curstate.origin[0] - ent->latched.prevorigin[0] ) * f; + ent->origin[1] += ( ent->curstate.origin[1] - ent->latched.prevorigin[1] ) * f; + ent->origin[2] += ( ent->curstate.origin[2] - ent->latched.prevorigin[2] ) * f; + + InterpolateAngles( ent->angles, ent->latched.prevangles, ent->angles, f ); + } + } + } + + return true; +} + +qboolean CL_AddVisibleEntity( cl_entity_t *ent, int entityType ) +{ + if( !ent || !ent->model ) + return false; + + if( entityType == ET_TEMPENTITY ) + { + // copy actual origin and angles back to let StudioModelRenderer + // get actual value directly from curstate + VectorCopy( ent->origin, ent->curstate.origin ); + VectorCopy( ent->angles, ent->curstate.angles ); + } + + if( CL_IsInMenu( ) && ( ( !ui_renderworld->integer && !cl.background ) || ent->player )) + { + // menu entities ignores client filter + if( !R_AddEntity( ent, entityType )) + return false; + } + else + { + // check for adding this entity + if( !clgame.dllFuncs.pfnAddEntity( entityType, ent, ent->model->name )) + return false; + + // don't add himself on firstperson + if( RP_LOCALCLIENT( ent ) && !cl.thirdperson && cls.key_dest != key_menu && cl.refdef.viewentity == ( cl.playernum + 1 )) + { + if( gl_allow_mirrors->integer && world.has_mirrors ) + { + if( !R_AddEntity( ent, entityType )) + return false; + } + // otherwise just pass to player effects like flashlight, particles etc + } + else if( entityType == ET_BEAM ) + { + CL_AddCustomBeam( ent ); + return true; + } + else if( !R_AddEntity( ent, entityType )) + { + return false; + } + } + + // set actual entity type + ent->curstate.entityType = entityType; + + // apply effects + if( ent->curstate.effects & EF_BRIGHTFIELD ) + CL_EntityParticles( ent ); + + // add in muzzleflash effect + if( ent->curstate.effects & EF_MUZZLEFLASH ) + { + dlight_t *dl; + + if( ent == &clgame.viewent ) + ent->curstate.effects &= ~EF_MUZZLEFLASH; + + dl = CL_AllocElight( 0 ); + + VectorCopy( ent->attachment[0], dl->origin ); + dl->die = cl.time + 0.05f; + dl->color.r = 255; + dl->color.g = 180; + dl->color.b = 64; + dl->radius = 100; + } + + // add light effect + if( ent->curstate.effects & EF_LIGHT ) + { + dlight_t *dl = CL_AllocDlight( ent->curstate.number ); + VectorCopy( ent->origin, dl->origin ); + dl->die = cl.time; // die at next frame + dl->color.r = 100; + dl->color.g = 100; + dl->color.b = 100; + dl->radius = 200; + CL_RocketFlare( ent->origin ); + } + + // add dimlight + if( ent->curstate.effects & EF_DIMLIGHT ) + { + if( entityType == ET_PLAYER ) + { + CL_UpdateFlashlight( ent ); + } + else + { + dlight_t *dl = CL_AllocDlight( ent->curstate.number ); + VectorCopy( ent->origin, dl->origin ); + dl->die = cl.time; // die at next frame + dl->color.r = 255; + dl->color.g = 255; + dl->color.b = 255; + dl->radius = Com_RandomLong( 200, 230 ); + } + } + + if( ent->curstate.effects & EF_BRIGHTLIGHT ) + { + dlight_t *dl = CL_AllocDlight( 0 ); + VectorSet( dl->origin, ent->origin[0], ent->origin[1], ent->origin[2] + 16.0f ); + dl->die = cl.time + 0.001f; // die at next frame + dl->color.r = 255; + dl->color.g = 255; + dl->color.b = 255; + + if( entityType == ET_PLAYER ) + dl->radius = 430; + else dl->radius = Com_RandomLong( 400, 430 ); + } + + if( ent->model->type == mod_studio ) + { + if( ent->model->flags & STUDIO_ROTATE ) + ent->angles[1] = anglemod( 100.0f * cl.time ); + + if( ent->model->flags & STUDIO_GIB ) + CL_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 2 ); + else if( ent->model->flags & STUDIO_ZOMGIB ) + CL_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 4 ); + else if( ent->model->flags & STUDIO_TRACER ) + CL_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 3 ); + else if( ent->model->flags & STUDIO_TRACER2 ) + CL_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 5 ); + else if( ent->model->flags & STUDIO_ROCKET ) + { + dlight_t *dl = CL_AllocDlight( ent->curstate.number ); + VectorCopy( ent->origin, dl->origin ); + dl->color.r = 255; + dl->color.g = 255; + dl->color.b = 255; + + // HACKHACK: get radius from head entity + if( ent->curstate.rendermode != kRenderNormal ) + dl->radius = max( 0, ent->curstate.renderamt - 55 ); + else dl->radius = 200; + dl->die = cl.time + 0.01f; + + CL_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 0 ); + } + else if( ent->model->flags & STUDIO_GRENADE ) + CL_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 1 ); + else if( ent->model->flags & STUDIO_TRACER3 ) + CL_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 6 ); + } + + return true; +} + +/* +================== +CL_WeaponAnim + +Set new weapon animation +================== +*/ +void GAME_EXPORT CL_WeaponAnim( int iAnim, int body ) +{ + cl_entity_t *view = &clgame.viewent; + cl.weaponstarttime = 0; + cl.weaponseq = iAnim; + + // anim is changed. update latchedvars + if( iAnim != view->curstate.sequence ) + { + int i; + + // save current blends to right lerping from last sequence + for( i = 0; i < 2; i++ ) + view->latched.prevseqblending[i] = view->curstate.blending[i]; + view->latched.prevsequence = view->curstate.sequence; // save old sequence + + // save animtime + view->latched.prevanimtime = view->curstate.animtime; + view->latched.sequencetime = 0.0f; + } + + view->curstate.animtime = cl.time; // start immediately + view->curstate.framerate = 1.0f; + view->curstate.sequence = iAnim; + view->latched.prevframe = 0.0f; + view->curstate.scale = 1.0f; + view->curstate.frame = 0.0f; + view->curstate.body = body; + +#if 0 // g-cont. for GlowShell testing + view->curstate.renderfx = kRenderFxGlowShell; + view->curstate.rendercolor.r = 255; + view->curstate.rendercolor.g = 128; + view->curstate.rendercolor.b = 0; + view->curstate.renderamt = 100; +#endif +} + +/* +================== +CL_UpdateStudioVars + +Update studio latched vars so interpolation work properly +================== +*/ +void CL_UpdateStudioVars( cl_entity_t *ent, entity_state_t *newstate, qboolean noInterp ) +{ + int i; + + if( newstate->effects & EF_NOINTERP || noInterp ) + { + ent->latched.sequencetime = 0.0f; // no lerping between sequences + ent->latched.prevsequence = newstate->sequence; // keep an actual + ent->latched.prevanimtime = newstate->animtime; + + VectorCopy( newstate->origin, ent->latched.prevorigin ); + VectorCopy( newstate->angles, ent->latched.prevangles ); + + // copy controllers + for( i = 0; i < 4; i++ ) + ent->latched.prevcontroller[i] = newstate->controller[i]; + + // copy blends + for( i = 0; i < 2; i++ ) + ent->latched.prevblending[i] = newstate->blending[i]; + return; + } + + // sequence has changed, hold the previous sequence info + if( newstate->sequence != ent->curstate.sequence ) + { + if( ent->index > 0 && ent->index <= cl.maxclients ) + ent->latched.sequencetime = ent->curstate.animtime + 0.01f; + else ent->latched.sequencetime = ent->curstate.animtime + 0.1f; + + // save current blends to right lerping from last sequence + for( i = 0; i < 2; i++ ) + ent->latched.prevseqblending[i] = ent->curstate.blending[i]; + ent->latched.prevsequence = ent->curstate.sequence; // save old sequence + } + + if( newstate->animtime != ent->curstate.animtime ) + { + // client got new packet, shuffle animtimes + ent->latched.prevanimtime = ent->curstate.animtime; + VectorCopy( ent->curstate.origin, ent->latched.prevorigin ); + VectorCopy( ent->curstate.angles, ent->latched.prevangles ); + + for( i = 0; i < 4; i++ ) + ent->latched.prevcontroller[i] = newstate->controller[i]; + } + + // copy controllers + for( i = 0; i < 4; i++ ) + { + if( ent->curstate.controller[i] != newstate->controller[i] ) + ent->latched.prevcontroller[i] = ent->curstate.controller[i]; + } + + // copy blends + for( i = 0; i < 2; i++ ) + ent->latched.prevblending[i] = ent->curstate.blending[i]; +} + +/* +================== +CL_UpdateBmodelVars + +Using studio latched vars for interpolate bmodels +================== +*/ +void CL_UpdateBmodelVars( cl_entity_t *ent, entity_state_t *newstate, qboolean noInterp ) +{ + if( newstate->effects & EF_NOINTERP || noInterp ) + { + ent->latched.prevanimtime = newstate->animtime; + VectorCopy( newstate->origin, ent->latched.prevorigin ); + VectorCopy( newstate->angles, ent->latched.prevangles ); + return; + } + + if( newstate->animtime != ent->curstate.animtime ) + { + // client got new packet, shuffle animtimes + ent->latched.prevanimtime = ent->curstate.animtime; + VectorCopy( newstate->origin, ent->latched.prevorigin ); + VectorCopy( newstate->angles, ent->latched.prevangles ); + } + + // NOTE: store prevorigin for interpolate monsters on moving platforms + if( !VectorCompare( newstate->origin, ent->curstate.origin )) + VectorCopy( ent->curstate.origin, ent->latched.prevorigin ); + if( !VectorCompare( newstate->angles, ent->curstate.angles )) + VectorCopy( ent->curstate.angles, ent->latched.prevangles ); +} + +void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t *old, qboolean unchanged ) +{ + cl_entity_t *ent; + entity_state_t *state; + qboolean newent = (old) ? false : true; + qboolean result = true; + if( ( newnum < 0 ) || ( newnum >= clgame.maxEntities ) ) + { + state = &cls.packet_entities[cls.next_client_entities % cls.num_client_entities]; + if( !unchanged ) + MSG_ReadDeltaEntity( msg, old, state, newnum, CL_IsPlayerIndex( newnum ), cl.mtime[0] ); + return; + } + ent = CL_EDICT_NUM( newnum ); + state = &cls.packet_entities[cls.next_client_entities % cls.num_client_entities]; + ent->index = newnum; + + if( newent ) old = &ent->baseline; + + if( unchanged ) *state = *old; + else result = MSG_ReadDeltaEntity( msg, old, state, newnum, CL_IsPlayerIndex( newnum ), cl.mtime[0] ); + + if( !result ) + { + if( newent ) + { + MsgDev( D_WARN, "Cl_DeltaEntity: tried to release new entity\n" ); + + // Perform remove, entity was created and removed between packets + + if( state->number == -1 ) + { + ent->curstate.messagenum = 0; + ent->baseline.number = 0; + MsgDev( D_NOTE, "Entity %i was removed from server\n", newnum ); + } + else MsgDev( D_NOTE, "Entity %i was removed from delta-message\n", newnum ); + return; + } + + CL_KillDeadBeams( ent ); // release dead beams +#if 0 + // this is for reference + if( state->number == -1 ) + Msg( "Entity %i was removed from server\n", newnum ); + else Msg( "Entity %i was removed from delta-message\n", newnum ); +#endif + if( state->number == -1 ) + { + ent->curstate.messagenum = 0; + ent->baseline.number = 0; + } + + // entity was delta removed + return; + } + + // entity is present in newframe + state->messagenum = cl.parsecount; + state->msg_time = cl.mtime[0]; + + cls.next_client_entities++; + frame->num_entities++; + + // set player state + ent->player = CL_IsPlayerIndex( ent->index ); + + if( state->effects & EF_NOINTERP || newent ) + { + // duplicate the current state so lerping doesn't hurt anything + ent->prevstate = *state; + if ( newent ) + CL_ResetPositions( ent ); + } + else + { + if( ent->player && ( ent->curstate.movetype != MOVETYPE_NONE ) && ( ent->prevstate.movetype == MOVETYPE_NONE ) ) + CL_ResetPositions( ent ); + + // shuffle the last state to previous + ent->prevstate = ent->curstate; + } + + // NOTE: always check modelindex for new state not current + if( Mod_GetType( state->modelindex ) == mod_studio ) + { + CL_UpdateStudioVars( ent, state, newent ); + } + else if( Mod_GetType( state->modelindex ) == mod_brush ) + { + CL_UpdateBmodelVars( ent, state, newent ); + } + + // set right current state + ent->curstate = *state; + + CL_UpdatePositions( ent ); +} + +/* +================= +CL_FlushEntityPacket + +Read and ignore whole entity packet. +================= +*/ +void CL_FlushEntityPacket( sizebuf_t *msg ) +{ + int newnum; + entity_state_t from, to; + Q_memset( &from, 0, sizeof( from )); + + cl.frames[cl.parsecountmod].valid = false; + cl.validsequence = 0; // can't render a frame + + // read it all, but ignore it + while( 1 ) + { + newnum = BF_ReadWord( msg ); + if( !newnum ) break; // done + + if( BF_CheckOverflow( msg )) + Host_Error( "CL_FlushEntityPacket: read overflow\n" ); + + MSG_ReadDeltaEntity( msg, &from, &to, newnum, CL_IsPlayerIndex( newnum ), cl.mtime[0] ); + } +} + +/* +================== +CL_ParsePacketEntities + +An svc_packetentities has just been parsed, deal with the +rest of the data stream. +================== +*/ +int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta ) +{ + frame_t *newframe, *oldframe; + int oldindex, newnum, oldnum; + int oldpacket; + cl_entity_t *player; + entity_state_t *oldent; + int i, count; + int playerbytes = 0, bufstart; + + // save first uncompressed packet as timestamp + if( cls.changelevel && !delta && cls.demorecording ) + CL_WriteDemoJumpTime(); + + // first, allocate packet for new frame + count = BF_ReadWord( msg ); + + newframe = &cl.frames[cl.parsecountmod]; + + // allocate parse entities + newframe->first_entity = cls.next_client_entities; + newframe->num_entities = 0; + newframe->valid = true; // assume valid + Q_memset( &newframe->graphdata, 0, sizeof( netbandwidthgraph_t )); + + if( delta ) + { + int subtracted; + + oldpacket = BF_ReadByte( msg ); + subtracted = ((( cls.netchan.incoming_sequence & 0xFF ) - oldpacket ) & 0xFF ); + + if( subtracted == 0 ) + { + MsgDev( D_NOTE, "CL_DeltaPacketEntities: update too old (flush)\n" ); + Con_NPrintf( 2, "^3Warning:^1 update too old\n^7\n" ); + CL_FlushEntityPacket( msg ); + return 0; // broken packet, so no players was been parsed + } + + + if( subtracted >= CL_UPDATE_MASK ) + { + MsgDev( D_NOTE, "CL_ParsePacketEntities: delta frame is too old: overflow (flush)\n"); + // we can't use this, it is too old + Con_NPrintf( 2, "^3Warning:^1 delta frame is too old: overflow^7\n" ); + CL_FlushEntityPacket( msg ); + return 0; // broken packet, so no players was been parsed + } + + oldframe = &cl.frames[oldpacket & CL_UPDATE_MASK]; + + if(( cls.next_client_entities - oldframe->first_entity ) > ( cls.num_client_entities - 128 )) + { + MsgDev( D_NOTE, "CL_ParsePacketEntities: delta frame is too old (flush)\n"); + Con_NPrintf( 2, "^3Warning:^1 delta frame is too old^7\n" ); + CL_FlushEntityPacket( msg ); + return 0; // broken packet, so no players was been parsed + } + } + else + { + // this is a full update that we can start delta compressing from now + oldframe = NULL; + oldpacket = -1; // delta too old or is initial message + cl.force_send_usercmd = true; // send reply + cls.demowaiting = false; // we can start recording now + } + + // mark current delta state + cl.validsequence = cls.netchan.incoming_sequence; + + oldent = NULL; + oldindex = 0; + + if( !oldframe ) + { + oldnum = MAX_ENTNUMBER; + } + else + { + if( oldindex >= oldframe->num_entities ) + { + oldnum = MAX_ENTNUMBER; + } + else + { + oldent = &cls.packet_entities[(oldframe->first_entity+oldindex) % cls.num_client_entities]; + oldnum = oldent->number; + } + } + + while( 1 ) + { + newnum = BF_ReadWord( msg ); + if( !newnum ) break; // end of packet entities + + if( BF_CheckOverflow( msg )) + Host_Error( "CL_ParsePacketEntities: read overflow\n" ); + + while( oldnum < newnum ) + { + // one or more entities from the old packet are unchanged + bufstart = BF_GetNumBytesRead( msg ); + CL_DeltaEntity( msg, newframe, oldnum, oldent, true ); + if( CL_IsPlayerIndex( oldnum ) ) + playerbytes += BF_GetNumBytesRead( msg ) - bufstart; + + oldindex++; + + if( oldindex >= oldframe->num_entities ) + { + oldnum = MAX_ENTNUMBER; + } + else + { + oldent = &cls.packet_entities[(oldframe->first_entity+oldindex) % cls.num_client_entities]; + oldnum = oldent->number; + } + } + + if( oldnum == newnum ) + { + // delta from previous state + bufstart = BF_GetNumBytesRead( msg ); + CL_DeltaEntity( msg, newframe, newnum, oldent, false ); + if( CL_IsPlayerIndex( newnum ) ) + playerbytes += BF_GetNumBytesRead( msg ) - bufstart; + oldindex++; + + if( oldindex >= oldframe->num_entities ) + { + oldnum = MAX_ENTNUMBER; + } + else + { + oldent = &cls.packet_entities[(oldframe->first_entity+oldindex) % cls.num_client_entities]; + oldnum = oldent->number; + } + continue; + } + + if( oldnum > newnum ) + { + // delta from baseline ? + bufstart = BF_GetNumBytesRead( msg ); + CL_DeltaEntity( msg, newframe, newnum, NULL, false ); + if( CL_IsPlayerIndex( newnum ) ) + playerbytes += BF_GetNumBytesRead( msg ) - bufstart; + continue; + } + } + + // any remaining entities in the old frame are copied over + while( oldnum != MAX_ENTNUMBER ) + { + // one or more entities from the old packet are unchanged + bufstart = BF_GetNumBytesRead( msg ); + CL_DeltaEntity( msg, newframe, oldnum, oldent, true ); + if( CL_IsPlayerIndex( newnum ) ) + playerbytes += BF_GetNumBytesRead( msg ) - bufstart; + + oldindex++; + + if( oldindex >= oldframe->num_entities ) + { + oldnum = MAX_ENTNUMBER; + } + else + { + oldent = &cls.packet_entities[(oldframe->first_entity+oldindex) % cls.num_client_entities]; + oldnum = oldent->number; + } + } + + if( newframe->num_entities != count ) + MsgDev( D_ERROR, "CL_Parse%sPacketEntities: (%i should be %i)\n", delta ? "Delta" : "", newframe->num_entities, count ); + + cl.frame = *newframe; + + if( !cl.frame.valid ) return 0; + + player = CL_GetLocalPlayer(); + + if( player != NULL ) + { + // update local player states + clgame.dllFuncs.pfnTxferLocalOverrides( &player->curstate, &newframe->client ); + } + + // update state for all players + for( i = 0; i < cl.maxclients; i++ ) + { + cl_entity_t *ent = CL_GetEntityByIndex( i + 1 ); + if( !ent ) continue; + clgame.dllFuncs.pfnProcessPlayerState( &newframe->playerstate[i], &ent->curstate ); + newframe->playerstate[i].number = ent->index; + } + + cl.frame = *newframe; + + if( cls.state != ca_active ) + { + // client entered the game + cls.state = ca_active; + cl.force_refdef = true; + cls.changelevel = false; // changelevel is done + cls.changedemo = false; // changedemo is done + + SCR_MakeLevelShot(); // make levelshot if needs + Cvar_SetFloat( "scr_loading", 0.0f ); // reset progress bar + Netchan_ReportFlow( &cls.netchan ); + + if(( cls.demoplayback || cls.disable_servercount != cl.servercount ) && cl.video_prepped ) + SCR_EndLoadingPlaque(); // get rid of loading plaque + } + else + { + CL_CheckPredictionError(); + } + + return playerbytes; +} + +/* +========================================================================== + +INTERPOLATE BETWEEN FRAMES TO GET RENDERING PARMS + +========================================================================== +*/ +/* +=============== +CL_SetIdealPitch +=============== +*/ +void CL_SetIdealPitch( void ) +{ + float angleval, sinval, cosval; + vec3_t top, bottom; + float z[MAX_FORWARD]; + int i, j; + float step, dir, steps; + pmtrace_t tr; + + if( !( cl.frame.client.flags & FL_ONGROUND )) + return; + + angleval = cl.frame.playerstate[cl.playernum].angles[YAW] * M_PI2 / 360.0f; + SinCos( angleval, &sinval, &cosval ); + + for( i = 0; i < MAX_FORWARD; i++ ) + { + top[0] = cl.predicted.origin[0] + cosval * (i + 3.0f) * 12.0f; + top[1] = cl.predicted.origin[1] + sinval * (i + 3.0f) * 12.0f; + top[2] = cl.predicted.origin[2] + cl.predicted.viewofs[2]; + + bottom[0] = top[0]; + bottom[1] = top[1]; + bottom[2] = top[2] - 160.0f; + + // skip any monsters (only world and brush models) + tr = CL_TraceLine( top, bottom, PM_STUDIO_IGNORE ); + if( tr.allsolid ) return; // looking at a wall, leave ideal the way is was + + if( tr.fraction == 1.0f ) + return; // near a dropoff + + z[i] = top[2] + tr.fraction * (bottom[2] - top[2]); + } + + dir = 0; + steps = 0; + + for( j = 1; j < i; j++ ) + { + step = z[j] - z[j-1]; + if( step > -ON_EPSILON && step < ON_EPSILON ) + continue; + + if( dir && ( step-dir > ON_EPSILON || step-dir < -ON_EPSILON )) + return; // mixed changes + + steps++; + dir = step; + } + + if( !dir ) + { + cl.refdef.idealpitch = 0.0f; + return; + } + + if( steps < 2 ) return; + cl.refdef.idealpitch = -dir * cl_idealpitchscale->value; +} + +/* +=============== +CL_AddPacketEntities + +=============== +*/ +void CL_AddPacketEntities( frame_t *frame ) +{ + cl_entity_t *ent, *clent; + int i, e, entityType; + + clent = CL_GetLocalPlayer(); + if( !clent ) return; + + for( i = 0; i < cl.frame.num_entities; i++ ) + { + e = cls.packet_entities[(cl.frame.first_entity + i) % cls.num_client_entities].number; + ent = CL_GetEntityByIndex( e ); + + if( !ent || ent == clgame.entities ) + continue; + + if( !CL_UpdateEntityFields( ent ) ) + continue; + + if( ent->player ) entityType = ET_PLAYER; + else if( ent->curstate.entityType == ENTITY_BEAM ) + entityType = ET_BEAM; + else entityType = ET_NORMAL; + + CL_AddVisibleEntity( ent, entityType ); + } +} + +/* +=============== +CL_AddEntities + +Emits all entities, particles, and lights to the refresh +=============== +*/ +void CL_AddEntities( void ) +{ + if( cls.state != ca_active ) + return; + + cl.num_custombeams = 0; + + CL_SetIdealPitch (); + clgame.dllFuncs.CAM_Think (); + + CL_AddPacketEntities( &cl.frame ); + clgame.dllFuncs.pfnCreateEntities(); + + CL_FireEvents(); // so tempents can be created immediately + CL_AddTempEnts(); + + // perfomance test + CL_TestLights(); +} + +// +// sound engine implementation +// +qboolean CL_GetEntitySpatialization( channel_t *ch ) +{ + cl_entity_t *ent; + qboolean valid_origin; + + if( ch->entnum == 0 ) + { + ch->staticsound = true; + return true; // static sound + } + + if(( ch->entnum - 1 ) == cl.playernum ) + { + VectorCopy( RI.vieworg, ch->origin ); + return true; + } + + valid_origin = VectorIsNull( ch->origin ) ? false : true; + ent = CL_GetEntityByIndex( ch->entnum ); + + // entity is not present on the client but has valid origin + if( !ent || !ent->index || ent->curstate.messagenum == 0 ) + return valid_origin; + + // a1ba: enabled this, as svc_sound does send it's own origin + // which is preferred, when entity isn't in PVS and curstate.origin does not update + // meanwhile, GS always trust svc_sound origin +#if 1 + // uncomment this if you want enable additional check by PVS + if( ent->curstate.messagenum != cl.parsecount ) + return valid_origin; +#endif + + // setup origin + VectorAverage( ent->curstate.mins, ent->curstate.maxs, ch->origin ); + VectorAdd( ch->origin, ent->curstate.origin, ch->origin ); + + // setup radius + if( ent->model != NULL && ent->model->radius ) ch->radius = ent->model->radius; + else ch->radius = RadiusFromBounds( ent->curstate.mins, ent->curstate.maxs ); + + return true; +} + +void CL_ExtraUpdate( void ) +{ + if( !cls.initialized ) + return; + if( !m_ignore->integer ) + clgame.dllFuncs.IN_Accumulate(); + S_ExtraUpdate(); +} +#endif // XASH_DEDICATED diff --git a/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_game.c b/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_game.c new file mode 100644 index 0000000..14a090b --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_game.c @@ -0,0 +1,4128 @@ +/* +cl_game.c - client dll interaction +Copyright (C) 2008 Uncle Mike + +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 3 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. +*/ + +#ifndef XASH_DEDICATED + +#include "common.h" +#include "client.h" +#include "const.h" +#include "triangleapi.h" +#include "r_efx.h" +#include "demo_api.h" +#include "ivoicetweak.h" +#include "pm_local.h" +#include "cl_tent.h" +#include "input.h" +#include "shake.h" +#include "sprite.h" +#include "gl_local.h" +#include "library.h" +#include "vgui_draw.h" +#include "sound.h" // SND_STOP_LOOPING + +#define MAX_LINELENGTH 80 +#define MAX_TEXTCHANNELS 8 // must be power of two (GoldSrc uses 4 channels) +#define TEXT_MSGNAME "TextMessage%i" + +char cl_textbuffer[MAX_TEXTCHANNELS][512]; +client_textmessage_t cl_textmessage[MAX_TEXTCHANNELS]; + +static struct crosshair_s +{ + // crosshair members + const model_t *pCrosshair; + wrect_t rcCrosshair; + rgba_t rgbaCrosshair; +} crosshair_state; + +extern rgba_t g_color_table[8]; + +static dllfunc_t cdll_exports[] = +{ +{ "Initialize", (void **)&clgame.dllFuncs.pfnInitialize }, +{ "HUD_VidInit", (void **)&clgame.dllFuncs.pfnVidInit }, +{ "HUD_Init", (void **)&clgame.dllFuncs.pfnInit }, +{ "HUD_Shutdown", (void **)&clgame.dllFuncs.pfnShutdown }, +{ "HUD_Redraw", (void **)&clgame.dllFuncs.pfnRedraw }, +{ "HUD_UpdateClientData", (void **)&clgame.dllFuncs.pfnUpdateClientData }, +{ "HUD_Reset", (void **)&clgame.dllFuncs.pfnReset }, +{ "HUD_PlayerMove", (void **)&clgame.dllFuncs.pfnPlayerMove }, +{ "HUD_PlayerMoveInit", (void **)&clgame.dllFuncs.pfnPlayerMoveInit }, +{ "HUD_PlayerMoveTexture", (void **)&clgame.dllFuncs.pfnPlayerMoveTexture }, +{ "HUD_ConnectionlessPacket", (void **)&clgame.dllFuncs.pfnConnectionlessPacket }, +{ "HUD_GetHullBounds", (void **)&clgame.dllFuncs.pfnGetHullBounds }, +{ "HUD_Frame", (void **)&clgame.dllFuncs.pfnFrame }, +{ "HUD_PostRunCmd", (void **)&clgame.dllFuncs.pfnPostRunCmd }, +{ "HUD_Key_Event", (void **)&clgame.dllFuncs.pfnKey_Event }, +{ "HUD_AddEntity", (void **)&clgame.dllFuncs.pfnAddEntity }, +{ "HUD_CreateEntities", (void **)&clgame.dllFuncs.pfnCreateEntities }, +{ "HUD_StudioEvent", (void **)&clgame.dllFuncs.pfnStudioEvent }, +{ "HUD_TxferLocalOverrides", (void **)&clgame.dllFuncs.pfnTxferLocalOverrides }, +{ "HUD_ProcessPlayerState", (void **)&clgame.dllFuncs.pfnProcessPlayerState }, +{ "HUD_TxferPredictionData", (void **)&clgame.dllFuncs.pfnTxferPredictionData }, +{ "HUD_TempEntUpdate", (void **)&clgame.dllFuncs.pfnTempEntUpdate }, +{ "HUD_DrawNormalTriangles", (void **)&clgame.dllFuncs.pfnDrawNormalTriangles }, +{ "HUD_DrawTransparentTriangles", (void **)&clgame.dllFuncs.pfnDrawTransparentTriangles }, +{ "HUD_GetUserEntity", (void **)&clgame.dllFuncs.pfnGetUserEntity }, +{ "Demo_ReadBuffer", (void **)&clgame.dllFuncs.pfnDemo_ReadBuffer }, +{ "CAM_Think", (void **)&clgame.dllFuncs.CAM_Think }, +{ "CL_IsThirdPerson", (void **)&clgame.dllFuncs.CL_IsThirdPerson }, +{ "CL_CameraOffset", (void **)&clgame.dllFuncs.CL_CameraOffset }, +{ "CL_CreateMove", (void **)&clgame.dllFuncs.CL_CreateMove }, +{ "IN_ActivateMouse", (void **)&clgame.dllFuncs.IN_ActivateMouse }, +{ "IN_DeactivateMouse", (void **)&clgame.dllFuncs.IN_DeactivateMouse }, +{ "IN_MouseEvent", (void **)&clgame.dllFuncs.IN_MouseEvent }, +{ "IN_Accumulate", (void **)&clgame.dllFuncs.IN_Accumulate }, +{ "IN_ClearStates", (void **)&clgame.dllFuncs.IN_ClearStates }, +{ "V_CalcRefdef", (void **)&clgame.dllFuncs.pfnCalcRefdef }, +{ "KB_Find", (void **)&clgame.dllFuncs.KB_Find }, +{ NULL, NULL } +}; + +// optional exports +static dllfunc_t cdll_new_exports[] = // allowed only in SDK 2.3 and higher +{ +{ "HUD_GetStudioModelInterface", (void **)&clgame.dllFuncs.pfnGetStudioModelInterface }, +{ "HUD_DirectorMessage", (void **)&clgame.dllFuncs.pfnDirectorMessage }, +{ "HUD_VoiceStatus", (void **)&clgame.dllFuncs.pfnVoiceStatus }, +{ "HUD_ChatInputPosition", (void **)&clgame.dllFuncs.pfnChatInputPosition }, +{ "HUD_GetRenderInterface", (void **)&clgame.dllFuncs.pfnGetRenderInterface }, // Xash3D ext +{ "HUD_GetPlayerTeam", (void **)&clgame.dllFuncs.pfnGetPlayerTeam }, +{ "HUD_ClipMoveToEntity", (void **)&clgame.dllFuncs.pfnClipMoveToEntity }, // Xash3D ext +{ "IN_ClientTouchEvent", (void **)&clgame.dllFuncs.pfnTouchEvent}, // Xash3D ext +{ "IN_ClientMoveEvent", (void **)&clgame.dllFuncs.pfnMoveEvent}, // Xash3D ext +{ "IN_ClientLookEvent", (void **)&clgame.dllFuncs.pfnLookEvent}, // Xash3D ext +{ NULL, NULL } +}; + +/* +==================== +CL_GetEntityByIndex + +Render callback for studio models +==================== +*/ +cl_entity_t *GAME_EXPORT CL_GetEntityByIndex( int index ) +{ + if( !clgame.entities ) // not in game yet + return NULL; + + if( index == 0 ) + return cl.world; + + if( index < 0 ) + return clgame.dllFuncs.pfnGetUserEntity( -index ); + + if( index >= clgame.maxEntities ) + return NULL; + + return CL_EDICT_NUM( index ); +} + +/* +==================== +CL_GetServerTime + +don't clamped time that come from server +==================== +*/ +float CL_GetServerTime( void ) +{ + return cl.mtime[0]; +} + +/* +==================== +CL_GetLerpFrac + +returns current lerp fraction +==================== +*/ +float CL_GetLerpFrac( void ) +{ + return cl.lerpFrac; +} + +/* +==================== +CL_IsThirdPerson + +returns true if thirdperson is enabled +==================== +*/ +qboolean CL_IsThirdPerson( void ) +{ + return cl.thirdperson; +} + +/* +==================== +CL_GetPlayerInfo + +get player info by render request +==================== +*/ +player_info_t *CL_GetPlayerInfo( int playerIndex ) +{ + if( playerIndex < 0 || playerIndex >= cl.maxclients ) + return NULL; + + return &cl.players[playerIndex]; +} + +/* +==================== +CL_CreatePlaylist + +Create a default valve playlist +==================== +*/ +void CL_CreatePlaylist( const char *filename ) +{ + file_t *f; + + f = FS_Open( filename, "w", false ); + if( !f ) return; + + // make standard cdaudio playlist + FS_Print( f, "blank\n" ); // #1 + FS_Print( f, "Half-Life01.mp3\n" ); // #2 + FS_Print( f, "Prospero01.mp3\n" ); // #3 + FS_Print( f, "Half-Life12.mp3\n" ); // #4 + FS_Print( f, "Half-Life07.mp3\n" ); // #5 + FS_Print( f, "Half-Life10.mp3\n" ); // #6 + FS_Print( f, "Suspense01.mp3\n" ); // #7 + FS_Print( f, "Suspense03.mp3\n" ); // #8 + FS_Print( f, "Half-Life09.mp3\n" ); // #9 + FS_Print( f, "Half-Life02.mp3\n" ); // #10 + FS_Print( f, "Half-Life13.mp3\n" ); // #11 + FS_Print( f, "Half-Life04.mp3\n" ); // #12 + FS_Print( f, "Half-Life15.mp3\n" ); // #13 + FS_Print( f, "Half-Life14.mp3\n" ); // #14 + FS_Print( f, "Half-Life16.mp3\n" ); // #15 + FS_Print( f, "Suspense02.mp3\n" ); // #16 + FS_Print( f, "Half-Life03.mp3\n" ); // #17 + FS_Print( f, "Half-Life08.mp3\n" ); // #18 + FS_Print( f, "Prospero02.mp3\n" ); // #19 + FS_Print( f, "Half-Life05.mp3\n" ); // #20 + FS_Print( f, "Prospero04.mp3\n" ); // #21 + FS_Print( f, "Half-Life11.mp3\n" ); // #22 + FS_Print( f, "Half-Life06.mp3\n" ); // #23 + FS_Print( f, "Prospero03.mp3\n" ); // #24 + FS_Print( f, "Half-Life17.mp3\n" ); // #25 + FS_Print( f, "Prospero05.mp3\n" ); // #26 + FS_Print( f, "Suspense05.mp3\n" ); // #27 + FS_Print( f, "Suspense07.mp3\n" ); // #28 + FS_Close( f ); +} + +/* +==================== +CL_InitCDAudio + +Initialize CD playlist +==================== +*/ +void CL_InitCDAudio( const char *filename ) +{ + char *afile, *pfile; + string token; + int c = 0; + + if( !FS_FileExists( filename, false )) + { + // create a default playlist + CL_CreatePlaylist( filename ); + } + + afile = (char *)FS_LoadFile( filename, NULL, false ); + if( !afile ) return; + + pfile = afile; + + // format: trackname\n [num] + while(( pfile = COM_ParseFile( pfile, token )) != NULL ) + { + if( !Q_stricmp( token, "blank" )) token[0] = '\0'; + Q_strncpy( clgame.cdtracks[c], token, sizeof( clgame.cdtracks[0] )); + + if( ++c > MAX_CDTRACKS - 1 ) + { + MsgDev( D_WARN, "CD_Init: too many tracks %i in %s (only %d allowed)\n", c, filename, MAX_CDTRACKS ); + break; + } + } + + Mem_Free( afile ); +} + +/* +==================== +CL_PointContents + +Return contents for point +==================== +*/ +int CL_PointContents( const vec3_t p ) +{ + int cont = CL_TruePointContents( p ); + + if( cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN ) + cont = CONTENTS_WATER; + return cont; +} + +/* +==================== +StudioEvent + +Event callback for studio models +==================== +*/ +void CL_StudioEvent( struct mstudioevent_s *event, cl_entity_t *pEdict ) +{ + clgame.dllFuncs.pfnStudioEvent( event, pEdict ); +} + +/* +============= +CL_AdjustXPos + +adjust text by x pos +============= +*/ +static int CL_AdjustXPos( float x, int width, int totalWidth ) +{ + int xPos; + float scale; + + scale = scr_width->value / (float)clgame.scrInfo.iWidth; + + if( x == -1 ) + { + xPos = ( clgame.scrInfo.iWidth - width ) * 0.5f; + } + else + { + if ( x < 0 ) + xPos = (1.0f + x) * clgame.scrInfo.iWidth - totalWidth; // Alight right + else // align left + xPos = x * clgame.scrInfo.iWidth; + } + + if( xPos + width > clgame.scrInfo.iWidth ) + xPos = clgame.scrInfo.iWidth - width; + else if( xPos < 0 ) + xPos = 0; + + return xPos * scale; +} + +/* +============= +CL_AdjustYPos + +adjust text by y pos +============= +*/ +static int CL_AdjustYPos( float y, int height ) +{ + int yPos; + float scale; + + scale = scr_height->value / (float)clgame.scrInfo.iHeight; + + if( y == -1 ) // centered? + { + yPos = ( clgame.scrInfo.iHeight - height ) * 0.5f; + } + else + { + // Alight bottom? + if( y < 0 ) + yPos = (1.0f + y) * clgame.scrInfo.iHeight - height; // Alight bottom + else // align top + yPos = y * clgame.scrInfo.iHeight; + } + + if( yPos + height > clgame.scrInfo.iHeight ) + yPos = clgame.scrInfo.iHeight - height; + else if( yPos < 0 ) + yPos = 0; + + return yPos * scale; +} + +/* +============= +CL_CenterPrint + +print centerscreen message +============= +*/ +void CL_CenterPrint( const char *text, float y ) +{ + byte *s; + int width = 0; + int length = 0; + float yscale = 1; + + clgame.centerPrint.lines = 1; + clgame.centerPrint.totalWidth = 0; + clgame.centerPrint.time = cl.mtime[0]; // allow pause for centerprint + Q_strncpy( clgame.centerPrint.message, text, sizeof( clgame.centerPrint.message )); + s = clgame.centerPrint.message; + + // count the number of lines for centering + while( *s ) + { + if( *s == '\n' ) + { + clgame.centerPrint.lines++; + if( width > clgame.centerPrint.totalWidth ) + clgame.centerPrint.totalWidth = width; + width = 0; + } + else width += clgame.scrInfo.charWidths[*s] * yscale; + s++; + length++; + } + + clgame.centerPrint.totalHeight = ( clgame.centerPrint.lines * clgame.scrInfo.iCharHeight ); + clgame.centerPrint.y = CL_AdjustYPos( y, clgame.centerPrint.totalHeight ); +} + +/* +==================== +SPR_AdjustSize + +draw hudsprite routine +==================== +*/ +void SPR_AdjustSize( float *x, float *y, float *w, float *h ) +{ + float xscale, yscale; + + ASSERT( x || y || w || h ); + + // scale for screen sizes + xscale = scr_width->value / (float)clgame.scrInfo.iWidth; + yscale = scr_height->value / (float)clgame.scrInfo.iHeight; + + if( x ) *x *= xscale; + if( y ) *y *= yscale; + + if( w ) *w *= xscale; + if( h ) *h *= yscale; +} + +/* +==================== +TextAdjustSize + +draw hudsprite routine +==================== +*/ +void TextAdjustSize( int *x, int *y, int *w, int *h ) +{ + float xscale, yscale; + + ASSERT( x || y || w || h ); + + if( !clgame.ds.adjust_size ) return; + + // scale for screen sizes + xscale = scr_width->value / (float)clgame.scrInfo.iWidth; + yscale = scr_height->value / (float)clgame.scrInfo.iHeight; + + if( x ) *x *= xscale; + if( y ) *y *= yscale; + if( w ) *w *= xscale; + if( h ) *h *= yscale; +} + +/* +==================== +PictAdjustSize + +draw hudsprite routine +==================== +*/ +void PicAdjustSize( float *x, float *y, float *w, float *h ) +{ + float xscale, yscale; + + if( !clgame.ds.adjust_size ) return; + if( !x && !y && !w && !h ) return; + + // scale for screen sizes + xscale = scr_width->value / (float)clgame.scrInfo.iWidth; + yscale = scr_height->value / (float)clgame.scrInfo.iHeight; + + if( x ) *x *= xscale; + if( y ) *y *= yscale; + if( w ) *w *= xscale; + if( h ) *h *= yscale; +} + +static qboolean SPR_Scissor( float *x, float *y, float *width, float *height, float *u0, float *v0, float *u1, float *v1 ) +{ + float dudx, dvdy; + + // clip sub rect to sprite + if(( width == 0 ) || ( height == 0 )) + return false; + + if( *x + *width <= clgame.ds.scissor_x ) + return false; + if( *x >= clgame.ds.scissor_x + clgame.ds.scissor_width ) + return false; + if( *y + *height <= clgame.ds.scissor_y ) + return false; + if( *y >= clgame.ds.scissor_y + clgame.ds.scissor_height ) + return false; + + dudx = (*u1 - *u0) / *width; + dvdy = (*v1 - *v0) / *height; + + if( *x < clgame.ds.scissor_x ) + { + *u0 += (clgame.ds.scissor_x - *x) * dudx; + *width -= clgame.ds.scissor_x - *x; + *x = clgame.ds.scissor_x; + } + + if( *x + *width > clgame.ds.scissor_x + clgame.ds.scissor_width ) + { + *u1 -= (*x + *width - (clgame.ds.scissor_x + clgame.ds.scissor_width)) * dudx; + *width = clgame.ds.scissor_x + clgame.ds.scissor_width - *x; + } + + if( *y < clgame.ds.scissor_y ) + { + *v0 += (clgame.ds.scissor_y - *y) * dvdy; + *height -= clgame.ds.scissor_y - *y; + *y = clgame.ds.scissor_y; + } + + if( *y + *height > clgame.ds.scissor_y + clgame.ds.scissor_height ) + { + *v1 -= (*y + *height - (clgame.ds.scissor_y + clgame.ds.scissor_height)) * dvdy; + *height = clgame.ds.scissor_y + clgame.ds.scissor_height - *y; + } + + return true; +} + +/* +==================== +SPR_DrawGeneric + +draw hudsprite routine +==================== +*/ +static void SPR_DrawGeneric( int frame, float x, float y, float width, float height, const wrect_t *prc ) +{ + float s1, s2, t1, t2; + int texnum; + + if( width == -1 && height == -1 ) + { + int w, h; + + // assume we get sizes from image + R_GetSpriteParms( &w, &h, NULL, frame, clgame.ds.pSprite ); + + width = w; + height = h; + } + + if( prc ) + { + wrect_t rc; + + rc = *prc; + + // Sigh! some stupid modmakers set wrong rectangles in hud.txt + if( rc.left <= 0 || rc.left >= width ) rc.left = 0; + if( rc.top <= 0 || rc.top >= height ) rc.top = 0; + if( rc.right <= 0 || rc.right > width ) rc.right = width; + if( rc.bottom <= 0 || rc.bottom > height ) rc.bottom = height; + + // calc user-defined rectangle + s1 = (float)rc.left / width; + t1 = (float)rc.top / height; + s2 = (float)rc.right / width; + t2 = (float)rc.bottom / height; + width = rc.right - rc.left; + height = rc.bottom - rc.top; + } + else + { + s1 = t1 = 0.0f; + s2 = t2 = 1.0f; + } + + // pass scissor test if supposed + if( clgame.ds.scissor_test && !SPR_Scissor( &x, &y, &width, &height, &s1, &t1, &s2, &t2 )) + return; + + // scale for screen sizes + SPR_AdjustSize( &x, &y, &width, &height ); + texnum = R_GetSpriteTexture( clgame.ds.pSprite, frame ); + pglColor4ubv( clgame.ds.spriteColor ); + R_DrawStretchPic( x, y, width, height, s1, t1, s2, t2, texnum ); +} + +/* +============= +CL_DrawCenterPrint + +called each frame +============= +*/ +void CL_DrawCenterPrint( void ) +{ + char *pText; + int i, j, x, y; + int width, lineLength; + byte *colorDefault, line[MAX_LINELENGTH]; + int charWidth, charHeight; + + if( !clgame.centerPrint.time ) + return; + + if(( cl.time - clgame.centerPrint.time ) >= scr_centertime->value ) + { + // time expired + clgame.centerPrint.time = 0.0f; + return; + } + + y = clgame.centerPrint.y; // start y + colorDefault = g_color_table[7]; + pText = clgame.centerPrint.message; + Con_DrawCharacterLen( 0, NULL, &charHeight ); + + for( i = 0; i < clgame.centerPrint.lines; i++ ) + { + lineLength = 0; + width = 0; + + while( *pText && *pText != '\n' && lineLength < MAX_LINELENGTH ) + { + byte c = *pText; + line[lineLength] = c; + Con_DrawCharacterLen( c, &charWidth, NULL ); + width += charWidth; + lineLength++; + pText++; + } + + if( lineLength == MAX_LINELENGTH ) + lineLength--; + + pText++; // Skip LineFeed + line[lineLength] = 0; + + x = CL_AdjustXPos( -1, width, clgame.centerPrint.totalWidth ); + + for( j = 0; j < lineLength; j++ ) + { + if( x >= 0 && y >= 0 && x <= clgame.scrInfo.iWidth ) + x += Con_DrawCharacter( x, y, line[j], colorDefault ); + } + y += charHeight; + } +} + +/* +============= +CL_DrawScreenFade + +fill screen with specfied color +can be modulated +============= +*/ +void CL_DrawScreenFade( void ) +{ + screenfade_t *sf = &clgame.fade; + int iFadeAlpha, testFlags; + + // keep pushing reset time out indefinitely + if( sf->fadeFlags & FFADE_STAYOUT ) + sf->fadeReset = cl.time + 0.1f; + + if( sf->fadeReset == 0.0f && sf->fadeEnd == 0.0f ) + return; // inactive + + // all done? + if(( cl.time > sf->fadeReset ) && ( cl.time > sf->fadeEnd )) + { + Q_memset( &clgame.fade, 0, sizeof( clgame.fade )); + return; + } + + testFlags = (sf->fadeFlags & ~FFADE_MODULATE); + + // fading... + if( testFlags == FFADE_STAYOUT ) + { + iFadeAlpha = sf->fadealpha; + } + else + { + iFadeAlpha = sf->fadeSpeed * ( sf->fadeEnd - cl.time ); + if( sf->fadeFlags & FFADE_OUT ) iFadeAlpha += sf->fadealpha; + iFadeAlpha = bound( 0, iFadeAlpha, sf->fadealpha ); + } + + pglColor4ub( sf->fader, sf->fadeg, sf->fadeb, iFadeAlpha ); + + if( sf->fadeFlags & FFADE_MODULATE ) + GL_SetRenderMode( kRenderTransAdd ); + else GL_SetRenderMode( kRenderTransTexture ); + R_DrawStretchPic( 0, 0, scr_width->integer, scr_height->integer, 0, 0, 1, 1, cls.fillImage ); + pglColor4ub( 255, 255, 255, 255 ); +} + +/* +==================== +CL_InitTitles + +parse all messages that declared in titles.txt +and hold them into permament memory pool +==================== +*/ +static void CL_InitTitles( const char *filename ) +{ + fs_offset_t fileSize; + byte *pMemFile; + int i; + + // initialize text messages (game_text) + for( i = 0; i < MAX_TEXTCHANNELS; i++ ) + { + cl_textmessage[i].pName = _copystring( clgame.mempool, va( TEXT_MSGNAME, i ), __FILE__, __LINE__ ); + cl_textmessage[i].pMessage = cl_textbuffer[i]; + } + + // clear out any old data that's sitting around. + if( clgame.titles ) Mem_Free( clgame.titles ); + + clgame.titles = NULL; + clgame.numTitles = 0; + + pMemFile = FS_LoadFile( filename, &fileSize, false ); + if( !pMemFile ) return; + + CL_TextMessageParse( pMemFile, (int)fileSize ); + Mem_Free( pMemFile ); +} + +/* +==================== +CL_ParseTextMessage + +Parse TE_TEXTMESSAGE +==================== +*/ +void CL_ParseTextMessage( sizebuf_t *msg ) +{ + static int msgindex = 0; + client_textmessage_t *text; + int channel; + + // read channel ( 0 - auto) + channel = BF_ReadByte( msg ); + + if( channel <= 0 || channel > ( MAX_TEXTCHANNELS - 1 )) + { + // invalid channel specified, use internal counter + if( channel != 0 ) MsgDev( D_ERROR, "HudText: invalid channel %i\n", channel ); + channel = msgindex; + msgindex = (msgindex + 1) & (MAX_TEXTCHANNELS - 1); + } + + // grab message channel + text = &cl_textmessage[channel]; + + text->x = (float)(BF_ReadShort( msg ) / 8192.0f); + text->y = (float)(BF_ReadShort( msg ) / 8192.0f); + text->effect = BF_ReadByte( msg ); + text->r1 = BF_ReadByte( msg ); + text->g1 = BF_ReadByte( msg ); + text->b1 = BF_ReadByte( msg ); + text->a1 = BF_ReadByte( msg ); + text->r2 = BF_ReadByte( msg ); + text->g2 = BF_ReadByte( msg ); + text->b2 = BF_ReadByte( msg ); + text->a2 = BF_ReadByte( msg ); + text->fadein = (float)(BF_ReadShort( msg ) / 256.0f ); + text->fadeout = (float)(BF_ReadShort( msg ) / 256.0f ); + text->holdtime = (float)(BF_ReadShort( msg ) / 256.0f ); + + if( text->effect == 2 ) + text->fxtime = (float)(BF_ReadShort( msg ) / 256.0f ); + else text->fxtime = 0.0f; + + // to prevent grab too long messages + Q_strncpy( (char *)text->pMessage, BF_ReadString( msg ), 512 ); + + // NOTE: a "HudText" message contain only 'string' with message name, so we + // don't needs to use MSG_ routines here, just directly write msgname into netbuffer + CL_DispatchUserMessage( "HudText", Q_strlen( text->pName ) + 1, (void *)text->pName ); +} + +/* +==================== +CL_GetLocalPlayer + +Render callback for studio models +==================== +*/ +cl_entity_t *GAME_EXPORT CL_GetLocalPlayer( void ) +{ + cl_entity_t *player; + + player = CL_EDICT_NUM( cl.playernum + 1 ); + //ASSERT( player != NULL ); + + return player; +} + +/* +==================== +CL_GetMaxlients + +Render callback for studio models +==================== +*/ +int GAME_EXPORT CL_GetMaxClients( void ) +{ + return cl.maxclients; +} + +/* +==================== +CL_SoundFromIndex + +return soundname from index +==================== +*/ +const char *GAME_EXPORT CL_SoundFromIndex( int index ) +{ + sfx_t *sfx = NULL; + int hSound; + + // make sure that we're within bounds + index = bound( 0, index, MAX_SOUNDS ); + hSound = cl.sound_index[index]; + + if( !hSound ) + { + MsgDev( D_ERROR, "CL_SoundFromIndex: invalid sound index %i\n", index ); + return NULL; + } + + sfx = S_GetSfxByHandle( hSound ); + if( !sfx ) + { + MsgDev( D_ERROR, "CL_SoundFromIndex: bad sfx for index %i\n", index ); + return NULL; + } + + return sfx->name; +} + +/* +========= +SPR_EnableScissor + +========= +*/ +static void GAME_EXPORT SPR_EnableScissor( int x, int y, int width, int height ) +{ + // check bounds + x = bound( 0, x, clgame.scrInfo.iWidth ); + y = bound( 0, y, clgame.scrInfo.iHeight ); + width = bound( 0, width, clgame.scrInfo.iWidth - x ); + height = bound( 0, height, clgame.scrInfo.iHeight - y ); + + clgame.ds.scissor_x = x; + clgame.ds.scissor_width = width; + clgame.ds.scissor_y = y; + clgame.ds.scissor_height = height; + clgame.ds.scissor_test = true; +} + +/* +========= +SPR_DisableScissor + +========= +*/ +static void GAME_EXPORT SPR_DisableScissor( void ) +{ + clgame.ds.scissor_x = 0; + clgame.ds.scissor_width = 0; + clgame.ds.scissor_y = 0; + clgame.ds.scissor_height = 0; + clgame.ds.scissor_test = false; +} + +/* +==================== +CL_DrawCrosshair + +Render crosshair +==================== +*/ +void CL_DrawCrosshair( void ) +{ + int x, y, width, height; + cl_entity_t *pPlayer; + + if( !crosshair_state.pCrosshair || cl.refdef.crosshairangle[2] || !cl_crosshair->integer ) + return; + + pPlayer = CL_GetLocalPlayer(); + + if( cl.frame.client.deadflag != DEAD_NO || cl.frame.client.flags & FL_FROZEN ) + return; + + // any camera on + if( cl.refdef.viewentity != pPlayer->index ) + return; + + // get crosshair dimension + width = crosshair_state.rcCrosshair.right - crosshair_state.rcCrosshair.left; + height = crosshair_state.rcCrosshair.bottom - crosshair_state.rcCrosshair.top; + + x = clgame.scrInfo.iWidth / 2; + y = clgame.scrInfo.iHeight / 2; + + // g-cont - cl.refdef.crosshairangle is the autoaim angle. + // if we're not using autoaim, just draw in the middle of the screen + if( !VectorIsNull( cl.refdef.crosshairangle )) + { + vec3_t angles; + vec3_t forward; + vec3_t point, screen; + + VectorAdd( cl.refdef.viewangles, cl.refdef.crosshairangle, angles ); + AngleVectors( angles, forward, NULL, NULL ); + VectorAdd( cl.refdef.vieworg, forward, point ); + R_WorldToScreen( point, screen ); + + x += 0.5f * screen[0] * scr_width->value + 0.5f; + y += 0.5f * screen[1] * scr_height->value + 0.5f; + } + + clgame.ds.pSprite = crosshair_state.pCrosshair; + + GL_SetRenderMode( kRenderTransTexture ); + *(int *)clgame.ds.spriteColor = *(int *)crosshair_state.rgbaCrosshair; + + SPR_EnableScissor( x - 0.5f * width, y - 0.5f * height, width, height ); + SPR_DrawGeneric( 0, x - 0.5f * width, y - 0.5f * height, -1, -1, &crosshair_state.rcCrosshair ); + SPR_DisableScissor(); +} + +/* +============= +CL_DrawLoading + +draw loading progress bar +============= +*/ +static void CL_DrawLoading( float percent ) +{ + int x, y, width, height, right; + float xscale, yscale, step, s2; + + R_GetTextureParms( &width, &height, cls.loadingBar ); + x = ( clgame.scrInfo.iWidth - width ) >> 1; + y = ( clgame.scrInfo.iHeight - height) >> 1; + + xscale = scr_width->value / (float)clgame.scrInfo.iWidth; + yscale = scr_height->value / (float)clgame.scrInfo.iHeight; + + x *= xscale; + y *= yscale; + width *= xscale; + height *= yscale; + + if( cl_allow_levelshots->integer ) + { + pglColor4ub( 128, 128, 128, 255 ); + GL_SetRenderMode( kRenderTransTexture ); + R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, cls.loadingBar ); + + step = (float)width / 100.0f; + right = (int)ceil( percent * step ); + s2 = (float)right / width; + width = right; + + pglColor4ub( 208, 152, 0, 255 ); + GL_SetRenderMode( kRenderTransTexture ); + R_DrawStretchPic( x, y, width, height, 0, 0, s2, 1, cls.loadingBar ); + pglColor4ub( 255, 255, 255, 255 ); + } + else + { + pglColor4ub( 255, 255, 255, 255 ); + GL_SetRenderMode( kRenderTransTexture ); + R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, cls.loadingBar ); + } +} + +/* +============= +CL_DrawPause + +draw pause sign +============= +*/ +static void CL_DrawPause( void ) +{ + int x, y, width, height; + float xscale, yscale; + + R_GetTextureParms( &width, &height, cls.pauseIcon ); + x = ( clgame.scrInfo.iWidth - width ) >> 1; + y = ( clgame.scrInfo.iHeight - height) >> 1; + + xscale = scr_width->value / (float)clgame.scrInfo.iWidth; + yscale = scr_height->value / (float)clgame.scrInfo.iHeight; + + x *= xscale; + y *= yscale; + width *= xscale; + height *= yscale; + + pglColor4ub( 255, 255, 255, 255 ); + GL_SetRenderMode( kRenderTransTexture ); + R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, cls.pauseIcon ); +} + +void CL_DrawHUD( int state ) +{ + if( state == CL_ACTIVE && !cl.video_prepped ) + state = CL_LOADING; + + if( state == CL_ACTIVE && cl.refdef.paused ) + state = CL_PAUSED; + + switch( state ) + { + case CL_ACTIVE: + CL_DrawScreenFade (); + CL_DrawCrosshair (); + CL_DrawCenterPrint (); + clgame.dllFuncs.pfnRedraw( cl.time, cl.refdef.intermission ); + break; + case CL_PAUSED: + CL_DrawScreenFade (); + CL_DrawCrosshair (); + CL_DrawCenterPrint (); + clgame.dllFuncs.pfnRedraw( cl.time, cl.refdef.intermission ); + CL_DrawPause(); + break; + case CL_LOADING: + CL_DrawLoading( scr_loading->value ); + break; + case CL_CHANGELEVEL: + if( cls.draw_changelevel ) + { + CL_DrawLoading( 100.0f ); + cls.draw_changelevel = false; + } + break; + } +} + +static void CL_ClearUserMessage( char *pszName, int svc_num ) +{ + int i; + + for( i = 0; i < MAX_USER_MESSAGES && clgame.msg[i].name[0]; i++ ) + if( ( clgame.msg[i].number == svc_num ) && Q_strcmp( clgame.msg[i].name, pszName ) ) + clgame.msg[i].number = 0; +} + +void CL_LinkUserMessage( char *pszName, const int svc_num, int iSize ) +{ + int i; + + if( !pszName || !*pszName ) + Host_Error( "CL_LinkUserMessage: bad message name\n" ); + + if( svc_num < svc_lastmsg ) + Host_Error( "CL_LinkUserMessage: tried to hook a system message \"%s\"\n", svc_strings[svc_num] ); + + // see if already hooked + for( i = 0; i < MAX_USER_MESSAGES && clgame.msg[i].name[0]; i++ ) + { + // NOTE: no check for DispatchFunc, check only name + if( !Q_strcmp( clgame.msg[i].name, pszName )) + { + clgame.msg[i].number = svc_num; + clgame.msg[i].size = iSize; + CL_ClearUserMessage( pszName, svc_num ); + return; + } + } + + if( i == MAX_USER_MESSAGES ) + { + Host_Error( "CL_LinkUserMessage: MAX_USER_MESSAGES hit!\n" ); + return; + } + + // register new message without DispatchFunc, so we should parse it properly + Q_strncpy( clgame.msg[i].name, pszName, sizeof( clgame.msg[i].name )); + clgame.msg[i].number = svc_num; + clgame.msg[i].size = iSize; + CL_ClearUserMessage( pszName, svc_num ); +} + +void CL_FreeEntity( cl_entity_t *pEdict ) +{ + ASSERT( pEdict ); + R_RemoveEfrags( pEdict ); + CL_KillDeadBeams( pEdict ); +} + +void CL_ClearWorld( void ) +{ + cl.world = clgame.entities; + cl.world->curstate.modelindex = 1; // world model + cl.world->curstate.solid = SOLID_BSP; + cl.world->curstate.movetype = MOVETYPE_PUSH; + cl.world->model = cl.worldmodel; + cl.world->index = 0; + + clgame.ds.cullMode = GL_FRONT; + clgame.numStatics = 0; +} + +void CL_InitEdicts( void ) +{ + ASSERT( clgame.entities == NULL ); + if( !clgame.mempool ) + return; // Host_Error without client + + CL_UPDATE_BACKUP = ( cl.maxclients == 1 ) ? SINGLEPLAYER_BACKUP : MULTIPLAYER_BACKUP; + cls.num_client_entities = CL_UPDATE_BACKUP * 64; + cls.packet_entities = Z_Realloc( cls.packet_entities, sizeof( entity_state_t ) * cls.num_client_entities ); + clgame.entities = Mem_Alloc( clgame.mempool, sizeof( cl_entity_t ) * clgame.maxEntities ); + clgame.static_entities = Mem_Alloc( clgame.mempool, sizeof( cl_entity_t ) * MAX_STATIC_ENTITIES ); + clgame.numStatics = 0; + + if(( clgame.maxRemapInfos - 1 ) != clgame.maxEntities ) + { + CL_ClearAllRemaps (); // purge old remap info + clgame.maxRemapInfos = clgame.maxEntities + 1; + clgame.remap_info = (remap_info_t **)Mem_Alloc( clgame.mempool, sizeof( remap_info_t* ) * clgame.maxRemapInfos ); + } +} + +void CL_FreeEdicts( void ) +{ + Z_Free( clgame.entities ); + clgame.entities = NULL; + + Z_Free( clgame.static_entities ); + clgame.static_entities = NULL; + + Z_Free( cls.packet_entities ); + cls.packet_entities = NULL; + + cls.num_client_entities = 0; + cls.next_client_entities = 0; + clgame.numStatics = 0; +} + +void CL_ClearEdicts( void ) +{ + if( clgame.entities != NULL ) + return; + + // in case we stopped with error + clgame.maxEntities = 2; + CL_InitEdicts(); +} + +/* +=============================================================================== + CGame Builtin Functions + +=============================================================================== +*/ +static qboolean CL_LoadHudSprite( const char *szSpriteName, model_t *m_pSprite, qboolean mapSprite, uint texFlags ) +{ + byte *buf; + fs_offset_t size; + qboolean loaded; + + ASSERT( m_pSprite != NULL ); + + buf = FS_LoadFile( szSpriteName, &size, false ); + if( !buf ) return false; + + Q_strncpy( m_pSprite->name, szSpriteName, sizeof( m_pSprite->name )); + m_pSprite->flags = 256; // it's hud sprite, make difference names to prevent free shared textures + + if( mapSprite ) Mod_LoadMapSprite( m_pSprite, buf, (size_t)size, &loaded ); + else Mod_LoadSpriteModel( m_pSprite, buf, &loaded, texFlags ); + + Mem_Free( buf ); + + if( !loaded ) + { + Mod_UnloadSpriteModel( m_pSprite ); + return false; + } + return true; +} + +/* +========= +pfnSPR_LoadExt + +========= +*/ +HSPRITE pfnSPR_LoadExt( const char *szPicName, uint texFlags ) +{ + char name[64]; + int i; + + if( !szPicName || !*szPicName ) + { + MsgDev( D_ERROR, "CL_LoadSprite: bad name!\n" ); + return 0; + } + + Q_strncpy( name, szPicName, sizeof( name )); + COM_FixSlashes( name ); + + // slot 0 isn't used + for( i = 1; i < MAX_IMAGES; i++ ) + { + if( !Q_stricmp( clgame.sprites[i].name, name )) + { + // prolonge registration + clgame.sprites[i].needload = clgame.load_sequence; + return i; + } + } + + // find a free model slot spot + for( i = 1; i < MAX_IMAGES; i++ ) + { + if( !clgame.sprites[i].name[0] ) + break; // this is a valid spot + } + + if( i >= MAX_IMAGES ) + { + MsgDev( D_ERROR, "SPR_Load: can't load %s, MAX_HSPRITES limit exceeded\n", szPicName ); + return 0; + } + + // load new model + if( CL_LoadHudSprite( name, &clgame.sprites[i], false, texFlags )) + { + if( i < MAX_IMAGES - 1 ) + { + clgame.sprites[i].needload = clgame.load_sequence; + } + return i; + } + return 0; +} + +/* +========= +pfnSPR_Load + +========= +*/ +HSPRITE GAME_EXPORT pfnSPR_Load( const char *szPicName ) +{ + int texFlags = TF_NOPICMIP; + if( cl_sprite_nearest->integer ) + texFlags |= TF_NEAREST; + + return pfnSPR_LoadExt( szPicName, texFlags ); +} + +/* +============= +CL_GetSpritePointer + +============= +*/ +const model_t *GAME_EXPORT CL_GetSpritePointer( HSPRITE hSprite ) +{ + if( hSprite <= 0 || hSprite > ( MAX_IMAGES - 1 )) + return NULL; // bad image + return &clgame.sprites[hSprite]; +} + +/* +========= +pfnSPR_Frames + +========= +*/ +static int GAME_EXPORT pfnSPR_Frames( HSPRITE hPic ) +{ + int numFrames; + + R_GetSpriteParms( NULL, NULL, &numFrames, 0, CL_GetSpritePointer( hPic )); + + return numFrames; +} + +/* +========= +pfnSPR_Height + +========= +*/ +static int GAME_EXPORT pfnSPR_Height( HSPRITE hPic, int frame ) +{ + int sprHeight; + + R_GetSpriteParms( NULL, &sprHeight, NULL, frame, CL_GetSpritePointer( hPic )); + + return sprHeight; +} + +/* +========= +pfnSPR_Width + +========= +*/ +static int GAME_EXPORT pfnSPR_Width( HSPRITE hPic, int frame ) +{ + int sprWidth; + + R_GetSpriteParms( &sprWidth, NULL, NULL, frame, CL_GetSpritePointer( hPic )); + + return sprWidth; +} + +/* +========= +pfnSPR_Set + +========= +*/ +static void GAME_EXPORT pfnSPR_Set( HSPRITE hPic, int r, int g, int b ) +{ + clgame.ds.pSprite = CL_GetSpritePointer( hPic ); + clgame.ds.spriteColor[0] = bound( 0, r, 255 ); + clgame.ds.spriteColor[1] = bound( 0, g, 255 ); + clgame.ds.spriteColor[2] = bound( 0, b, 255 ); + clgame.ds.spriteColor[3] = 255; + + // set default state + pglDisable( GL_BLEND ); + pglDisable( GL_ALPHA_TEST ); + pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); +} + +/* +========= +pfnSPR_Draw + +========= +*/ +static void GAME_EXPORT pfnSPR_Draw( int frame, int x, int y, const wrect_t *prc ) +{ + pglEnable( GL_ALPHA_TEST ); + SPR_DrawGeneric( frame, x, y, -1, -1, prc ); +} + +/* +========= +pfnSPR_DrawHoles + +========= +*/ +static void GAME_EXPORT pfnSPR_DrawHoles( int frame, int x, int y, const wrect_t *prc ) +{ + GL_SetRenderMode( kRenderTransAlpha ); + SPR_DrawGeneric( frame, x, y, -1, -1, prc ); +} + +/* +========= +pfnSPR_DrawAdditive + +========= +*/ +static void GAME_EXPORT pfnSPR_DrawAdditive( int frame, int x, int y, const wrect_t *prc ) +{ + GL_SetRenderMode( kRenderTransAdd ); + SPR_DrawGeneric( frame, x, y, -1, -1, prc ); +} + +/* +========= +pfnSPR_GetList + +for parsing half-life scripts - hud.txt etc +========= +*/ +static client_sprite_t *GAME_EXPORT pfnSPR_GetList( char *psz, int *piCount ) +{ + client_sprite_t *pList; + int index, numSprites = 0; + char *afile, *pfile; + string token; + byte *pool; + + if( piCount ) *piCount = 0; + + if( !clgame.itemspath[0] ) // typically it's sprites\*.txt + FS_ExtractFilePath( psz, clgame.itemspath ); + + afile = (char *)FS_LoadFile( psz, NULL, false ); + if( !afile ) return NULL; + + pfile = afile; + pfile = COM_ParseFile( pfile, token ); + numSprites = Q_atoi( token ); + + if( !cl.video_prepped ) pool = cls.mempool; // static memory + else pool = com_studiocache; // temporary + + // name, res, pic, x, y, w, h + // NOTE: we must use com_studiocache because it will be purge on next restart or change map + pList = Mem_Alloc( pool, sizeof( client_sprite_t ) * numSprites ); + + for( index = 0; index < numSprites; index++ ) + { + if(( pfile = COM_ParseFile( pfile, token )) == NULL ) + break; + + Q_strncpy( pList[index].szName, token, sizeof( pList[index].szName )); + + // read resolution + pfile = COM_ParseFile( pfile, token ); + pList[index].iRes = Q_atoi( token ); + + // read spritename + pfile = COM_ParseFile( pfile, token ); + Q_strncpy( pList[index].szSprite, token, sizeof( pList[index].szSprite )); + + // parse rectangle + pfile = COM_ParseFile( pfile, token ); + pList[index].rc.left = Q_atoi( token ); + + pfile = COM_ParseFile( pfile, token ); + pList[index].rc.top = Q_atoi( token ); + + pfile = COM_ParseFile( pfile, token ); + pList[index].rc.right = pList[index].rc.left + Q_atoi( token ); + + pfile = COM_ParseFile( pfile, token ); + pList[index].rc.bottom = pList[index].rc.top + Q_atoi( token ); + + if( piCount ) (*piCount)++; + } + + if( index < numSprites ) + MsgDev( D_WARN, "SPR_GetList: unexpected end of %s (%i should be %i)\n", psz, numSprites, index ); + + Mem_Free( afile ); + + return pList; +} + +/* +============= +pfnFillRGBA + +============= +*/ +void GAME_EXPORT CL_FillRGBA( int x, int y, int width, int height, int r, int g, int b, int a ) +{ + float x1 = x, y1 = y, w1 = width, h1 = height; + r = bound( 0, r, 255 ); + g = bound( 0, g, 255 ); + b = bound( 0, b, 255 ); + a = bound( 0, a, 255 ); + pglColor4ub( r, g, b, a ); + + SPR_AdjustSize( &x1, &y1, &w1, &h1 ); + + GL_SetRenderMode( kRenderTransAdd ); + R_DrawStretchPic( x1, y1, w1, h1, 0, 0, 1, 1, cls.fillImage ); + pglColor4ub( 255, 255, 255, 255 ); +} + +/* +============= +pfnGetScreenInfo + +get actual screen info +============= +*/ +int GAME_EXPORT pfnGetScreenInfo( SCREENINFO *pscrinfo ) +{ + // setup screen info + float scale_factor = hud_scale->value; + clgame.scrInfo.iSize = sizeof( clgame.scrInfo ); + + + if( scale_factor && scale_factor != 1.0f) + { + clgame.scrInfo.iWidth = scr_width->value / scale_factor; + clgame.scrInfo.iHeight = scr_height->value / scale_factor; + clgame.scrInfo.iFlags |= SCRINFO_STRETCHED; + } + else + { + clgame.scrInfo.iWidth = scr_width->integer; + clgame.scrInfo.iHeight = scr_height->integer; + clgame.scrInfo.iFlags &= ~SCRINFO_STRETCHED; + } + + if( !pscrinfo ) return 0; + + if( pscrinfo->iSize != clgame.scrInfo.iSize ) + clgame.scrInfo.iSize = pscrinfo->iSize; + + // copy screeninfo out + Q_memcpy( pscrinfo, &clgame.scrInfo, clgame.scrInfo.iSize ); + + return 1; +} + +/* +============= +pfnSetCrosshair + +setup crosshair +============= +*/ +static void GAME_EXPORT pfnSetCrosshair( HSPRITE hspr, wrect_t rc, int r, int g, int b ) +{ + crosshair_state.rgbaCrosshair[0] = (byte)r; + crosshair_state.rgbaCrosshair[1] = (byte)g; + crosshair_state.rgbaCrosshair[2] = (byte)b; + crosshair_state.rgbaCrosshair[3] = (byte)0xFF; + crosshair_state.pCrosshair = CL_GetSpritePointer( hspr ); + crosshair_state.rcCrosshair = rc; +} + +/* +============= +pfnHookUserMsg + +============= +*/ +static int GAME_EXPORT pfnHookUserMsg( const char *pszName, pfnUserMsgHook pfn ) +{ + int i; + + // ignore blank names or invalid callbacks + if( !pszName || !*pszName || !pfn ) + return 0; + + for( i = 0; i < MAX_USER_MESSAGES && clgame.msg[i].name[0]; i++ ) + { + // see if already hooked + if( !Q_strcmp( clgame.msg[i].name, pszName )) + return 1; + } + + if( i == MAX_USER_MESSAGES ) + { + Host_Error( "HookUserMsg: MAX_USER_MESSAGES hit!\n" ); + return 0; + } + + // hook new message + Q_strncpy( clgame.msg[i].name, pszName, sizeof( clgame.msg[i].name )); + clgame.msg[i].func = pfn; + + return 1; +} + +/* +============= +pfnServerCmd + +============= +*/ +static int GAME_EXPORT pfnServerCmd( const char *szCmdString ) +{ + string buf; + + if( !szCmdString || !szCmdString[0] ) + return 0; + + // just like the client typed "cmd xxxxx" at the console + Q_snprintf( buf, sizeof( buf ) - 1, "cmd %s\n", szCmdString ); + Cbuf_AddText( buf ); + + return 1; +} + +/* +============= +pfnClientCmd + +============= +*/ +static int GAME_EXPORT pfnClientCmd( const char *szCmdString ) +{ + if( !szCmdString || !szCmdString[0] ) + return 0; + + Cbuf_AddText( szCmdString ); + Cbuf_AddText( "\n" ); + return 1; +} + +/* +============= +pfnGetPlayerInfo + +============= +*/ +static void GAME_EXPORT pfnGetPlayerInfo( int ent_num, hud_player_info_t *pinfo ) +{ + player_info_t *player; + cl_entity_t *ent; + qboolean spec = false; + + ent = CL_GetEntityByIndex( ent_num ); + ent_num -= 1; // player list if offset by 1 from ents + + if( ent_num >= cl.maxclients || ent_num < 0 || !cl.players[ent_num].name[0] ) + { + Q_memset( pinfo, 0, sizeof( *pinfo )); + return; + } + + player = &cl.players[ent_num]; + pinfo->thisplayer = ( ent_num == cl.playernum ) ? true : false; + if( ent ) spec = ent->curstate.spectator; + + pinfo->name = player->name; + pinfo->model = player->model; + + pinfo->spectator = spec; + pinfo->ping = player->ping; + pinfo->packetloss = player->packet_loss; + pinfo->topcolor = Q_atoi( Info_ValueForKey( player->userinfo, "topcolor" )); + pinfo->bottomcolor = Q_atoi( Info_ValueForKey( player->userinfo, "bottomcolor" )); +} + +/* +============= +pfnPlaySoundByName + +============= +*/ +static void GAME_EXPORT pfnPlaySoundByName( const char *szSound, float volume ) +{ + int hSound = S_RegisterSound( szSound ); + S_StartSound( NULL, cl.refdef.viewentity, CHAN_ITEM, hSound, volume, ATTN_NORM, PITCH_NORM, SND_STOP_LOOPING ); +} + +/* +============= +pfnPlaySoundByIndex + +============= +*/ +static void GAME_EXPORT pfnPlaySoundByIndex( int iSound, float volume ) +{ + int hSound; + + // make sure what we in-bounds + iSound = bound( 0, iSound, MAX_SOUNDS ); + hSound = cl.sound_index[iSound]; + + if( !hSound ) + { + MsgDev( D_ERROR, "CL_PlaySoundByIndex: invalid sound handle %i\n", iSound ); + return; + } + S_StartSound( NULL, cl.refdef.viewentity, CHAN_ITEM, hSound, volume, ATTN_NORM, PITCH_NORM, SND_STOP_LOOPING ); +} + +/* +============= +pfnTextMessageGet + +returns specified message from titles.txt +============= +*/ +client_textmessage_t *GAME_EXPORT CL_TextMessageGet( const char *pName ) +{ + int i; + + // first check internal messages + for( i = 0; i < MAX_TEXTCHANNELS; i++ ) + { + if( !Q_strcmp( pName, va( TEXT_MSGNAME, i ))) + return cl_textmessage + i; + } + + // find desired message + for( i = 0; i < clgame.numTitles; i++ ) + { + if( !Q_stricmp( pName, clgame.titles[i].pName )) + return clgame.titles + i; + } + return NULL; // found nothing +} + +/* +============= +pfnDrawCharacter + +returns drawed chachter width (in real screen pixels) +============= +*/ +int GAME_EXPORT pfnDrawCharacter( int x, int y, int number, int r, int g, int b ) +{ + if( !cls.creditsFont.valid ) + return 0; + + number &= 255; + + if( hud_utf8->integer ) + number = Con_UtfProcessChar( number ); + + if( number < 32 ) return 0; + if( y < -clgame.scrInfo.iCharHeight ) + return 0; + + clgame.ds.adjust_size = true; + pfnPIC_Set( cls.creditsFont.hFontTexture, r, g, b, 255 ); + pfnPIC_DrawAdditive( x, y, -1, -1, &cls.creditsFont.fontRc[number] ); + clgame.ds.adjust_size = false; + + return clgame.scrInfo.charWidths[number]; +} + +/* +============= +pfnDrawConsoleString + +drawing string like a console string +============= +*/ +int GAME_EXPORT pfnDrawConsoleString( int x, int y, char *string ) +{ + int drawLen; + + if( !string || !*string ) return 0; // silent ignore + clgame.ds.adjust_size = true; + Con_SetFont( con_fontsize->integer ); + drawLen = Con_DrawString( x, y, string, clgame.ds.textColor ); + Vector4Copy( g_color_table[7], clgame.ds.textColor ); + clgame.ds.adjust_size = false; + Con_RestoreFont(); + + return (x + drawLen); // exclude color prexfixes +} + +/* +============= +pfnDrawSetTextColor + +set color for anything +============= +*/ +void GAME_EXPORT pfnDrawSetTextColor( float r, float g, float b ) +{ + // bound color and convert to byte + clgame.ds.textColor[0] = (byte)bound( 0, r * 255, 255 ); + clgame.ds.textColor[1] = (byte)bound( 0, g * 255, 255 ); + clgame.ds.textColor[2] = (byte)bound( 0, b * 255, 255 ); + clgame.ds.textColor[3] = (byte)0xFF; +} + +/* +============= +pfnDrawConsoleStringLen + +compute string length in screen pixels +============= +*/ +void GAME_EXPORT pfnDrawConsoleStringLen( const char *pText, int *length, int *height ) +{ + Con_SetFont( con_fontsize->integer ); + Con_DrawStringLen( pText, length, height ); + Con_RestoreFont(); +} + +/* +============= +pfnConsolePrint + +prints directly into console (can skip notify) +============= +*/ +static void GAME_EXPORT pfnConsolePrint( const char *string ) +{ + if( !string || !*string ) return; + if( *string != 1 ) Msg( "%s", string ); // show notify + else Con_NPrintf( 0, "%s", (char *)string + 1 ); // skip notify +} + +/* +============= +pfnCenterPrint + +holds and fade message at center of screen +like trigger_multiple message in q1 +============= +*/ +static void GAME_EXPORT pfnCenterPrint( const char *string ) +{ + if( !string || !*string ) return; // someone stupid joke + CL_CenterPrint( string, 0.25f ); +} + +/* +========= +GetWindowCenterX + +========= +*/ +static int GAME_EXPORT pfnGetWindowCenterX( void ) +{ + int x = 0; +#ifdef _WIN32 + if( m_ignore->integer ) + { + POINT pos; + GetCursorPos( &pos ); + return pos.x; + } +#endif + +#ifdef XASH_SDL + SDL_GetWindowPosition( host.hWnd, &x, NULL ); +#endif + + return host.window_center_x + x; +} + +/* +========= +GetWindowCenterY + +========= +*/ +static int GAME_EXPORT pfnGetWindowCenterY( void ) +{ + int y = 0; +#ifdef _WIN32 + if( m_ignore->integer ) + { + POINT pos; + GetCursorPos( &pos ); + return pos.y; + } +#endif + +#ifdef XASH_SDL + SDL_GetWindowPosition( host.hWnd, NULL, &y ); +#endif + + return host.window_center_y + y; +} + +/* +============= +pfnGetViewAngles + +return interpolated angles from previous frame +============= +*/ +static void GAME_EXPORT pfnGetViewAngles( float *angles ) +{ + if( angles ) VectorCopy( cl.refdef.cl_viewangles, angles ); +} + +/* +============= +pfnSetViewAngles + +return interpolated angles from previous frame +============= +*/ +static void GAME_EXPORT pfnSetViewAngles( float *angles ) +{ + if( angles ) VectorCopy( angles, cl.refdef.cl_viewangles ); +} + +/* +============= +pfnPhysInfo_ValueForKey + +============= +*/ +static const char* GAME_EXPORT pfnPhysInfo_ValueForKey( const char *key ) +{ + return Info_ValueForKey( cl.frame.client.physinfo, key ); +} + +/* +============= +pfnServerInfo_ValueForKey + +============= +*/ +static const char* GAME_EXPORT pfnServerInfo_ValueForKey( const char *key ) +{ + return Info_ValueForKey( cl.serverinfo, key ); +} + +/* +============= +pfnGetClientMaxspeed + +value that come from server +============= +*/ +static float GAME_EXPORT pfnGetClientMaxspeed( void ) +{ + return cl.frame.client.maxspeed; +} + +/* +============= +pfnCheckParm + +============= +*/ +static int GAME_EXPORT pfnCheckParm( char *parm, char **ppnext ) +{ + static char str[64]; + + if( Sys_GetParmFromCmdLine( parm, str )) + { + // get the pointer on cmdline param + if( ppnext ) *ppnext = str; + return 1; + } + return 0; +} + +/* +============= +pfnGetMousePosition + +============= +*/ +void GAME_EXPORT CL_GetMousePosition( int *mx, int *my ) +{ +#ifdef XASH_SDL + SDL_GetMouseState(mx, my); +#else + *mx = *my = 0; +#endif +} + +/* +============= +pfnIsNoClipping + +============= +*/ +int GAME_EXPORT pfnIsNoClipping( void ) +{ + cl_entity_t *pl = CL_GetLocalPlayer(); + + if( !pl ) return false; + + return pl->curstate.movetype == MOVETYPE_NOCLIP; +} + +/* +============= +pfnGetViewModel + +============= +*/ +static cl_entity_t* GAME_EXPORT pfnGetViewModel( void ) +{ + return &clgame.viewent; +} + +/* +============= +pfnGetClientTime + +============= +*/ +static float GAME_EXPORT pfnGetClientTime( void ) +{ + return cl.time; +} + +/* +============= +pfnCalcShake + +============= +*/ +static void GAME_EXPORT pfnCalcShake( void ) +{ + int i; + float fraction, freq; + float localAmp; + + if( clgame.shake.time == 0 ) + return; + + if(( cl.time > clgame.shake.time ) || clgame.shake.amplitude <= 0 || clgame.shake.frequency <= 0 ) + { + Q_memset( &clgame.shake, 0, sizeof( clgame.shake )); + return; + } + + if( cl.time > clgame.shake.next_shake ) + { + // higher frequency means we recalc the extents more often and perturb the display again + clgame.shake.next_shake = cl.time + ( 1.0f / clgame.shake.frequency ); + + // compute random shake extents (the shake will settle down from this) + for( i = 0; i < 3; i++ ) + clgame.shake.offset[i] = Com_RandomFloat( -clgame.shake.amplitude, clgame.shake.amplitude ); + clgame.shake.angle = Com_RandomFloat( -clgame.shake.amplitude * 0.25f, clgame.shake.amplitude * 0.25f ); + } + + // ramp down amplitude over duration (fraction goes from 1 to 0 linearly with slope 1/duration) + fraction = ( clgame.shake.time - cl.time ) / clgame.shake.duration; + + // ramp up frequency over duration + if( fraction ) + { + freq = ( clgame.shake.frequency / fraction ); + } + else + { + freq = 0; + } + + // square fraction to approach zero more quickly + fraction *= fraction; + + // Sine wave that slowly settles to zero + fraction = fraction * sin( cl.time * freq ); + + // add to view origin + VectorScale( clgame.shake.offset, fraction, clgame.shake.applied_offset ); + + // add to roll + clgame.shake.applied_angle = clgame.shake.angle * fraction; + + // drop amplitude a bit, less for higher frequency shakes + localAmp = clgame.shake.amplitude * ( host.frametime / ( clgame.shake.duration * clgame.shake.frequency )); + clgame.shake.amplitude -= localAmp; +} + +/* +============= +pfnApplyShake + +============= +*/ +static void GAME_EXPORT pfnApplyShake( float *origin, float *angles, float factor ) +{ + if( origin ) VectorMA( origin, factor, clgame.shake.applied_offset, origin ); + if( angles ) angles[ROLL] += clgame.shake.applied_angle * factor; +} + +/* +============= +pfnIsSpectateOnly + +============= +*/ +static int GAME_EXPORT pfnIsSpectateOnly( void ) +{ + cl_entity_t *pPlayer = CL_GetLocalPlayer(); + return pPlayer ? (pPlayer->curstate.spectator != 0) : 0; +} + +/* +============= +pfnPointContents + +============= +*/ +static int GAME_EXPORT pfnPointContents( const float *p, int *truecontents ) +{ + int cont, truecont; + + truecont = cont = CL_TruePointContents( p ); + if( truecontents ) *truecontents = truecont; + + if( cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN ) + cont = CONTENTS_WATER; + return cont; +} + +/* +============= +pfnTraceLine + +============= +*/ +static pmtrace_t *GAME_EXPORT pfnTraceLine( float *start, float *end, int flags, int usehull, int ignore_pe ) +{ + static pmtrace_t tr; + int old_usehull; + + old_usehull = clgame.pmove->usehull; + clgame.pmove->usehull = usehull; + + switch( flags ) + { + case PM_TRACELINE_PHYSENTSONLY: + tr = PM_PlayerTraceExt( clgame.pmove, start, end, 0, clgame.pmove->numphysent, clgame.pmove->physents, ignore_pe, NULL ); + break; + case PM_TRACELINE_ANYVISIBLE: + tr = PM_PlayerTraceExt( clgame.pmove, start, end, 0, clgame.pmove->numvisent, clgame.pmove->visents, ignore_pe, NULL ); + break; + } + + clgame.pmove->usehull = old_usehull; + + return &tr; +} + +static void GAME_EXPORT pfnPlaySoundByNameAtLocation( char *szSound, float volume, float *origin ) +{ + int hSound = S_RegisterSound( szSound ); + S_StartSound( origin, 0, CHAN_ITEM, hSound, volume, 1.0, PITCH_NORM, 0 ); +} + +/* +============= +pfnPrecacheEvent + +============= +*/ +static word GAME_EXPORT pfnPrecacheEvent( int type, const char* psz ) +{ + return CL_EventIndex( psz ); +} + +/* +============= +pfnHookEvent + +============= +*/ +static void GAME_EXPORT pfnHookEvent( const char *filename, pfnEventHook pfn ) +{ + char name[64]; + cl_user_event_t *ev; + int i; + + // ignore blank names + if( !filename || !*filename ) + return; + + Q_strncpy( name, filename, sizeof( name )); + COM_FixSlashes( name ); + + // find an empty slot + for( i = 0; i < MAX_EVENTS; i++ ) + { + ev = clgame.events[i]; + if( !ev ) break; + + if( !Q_stricmp( name, ev->name ) && ev->func != NULL ) + { + MsgDev( D_WARN, "CL_HookEvent: %s already hooked!\n", name ); + return; + } + } + + CL_RegisterEvent( i, name, pfn ); +} + +/* +============= +pfnKillEvent + +============= +*/ +static void GAME_EXPORT pfnKillEvents( int entnum, const char *eventname ) +{ + int i; + event_state_t *es; + event_info_t *ei; + int eventIndex = CL_EventIndex( eventname ); + + if( eventIndex < 0 || eventIndex >= MAX_EVENTS ) + return; + + if( entnum < 0 || entnum > clgame.maxEntities ) + return; + + es = &cl.events; + + // find all events with specified index and kill it + for( i = 0; i < MAX_EVENT_QUEUE; i++ ) + { + ei = &es->ei[i]; + + if( ei->index == eventIndex && ei->entity_index == entnum ) + { + CL_ResetEvent( ei ); + break; + } + } +} + +/* +============= +pfnPlaySound + +============= +*/ +static void GAME_EXPORT pfnPlaySound( int ent, float *org, int chan, const char *samp, float vol, float attn, int flags, int pitch ) +{ + S_StartSound( org, ent, chan, S_RegisterSound( samp ), vol, attn, pitch, flags ); +} + +/* +============= +CL_FindModelIndex + +============= +*/ +int GAME_EXPORT CL_FindModelIndex( const char *m ) +{ + int i; + + if( !m || !m[0] ) + return 0; + + for( i = 1; i < MAX_MODELS && cl.model_precache[i][0]; i++ ) + { + if( !Q_stricmp( cl.model_precache[i], m )) + return i; + } + + if( cls.state == ca_active && Q_strnicmp( m, "models/player/", 14 )) + { + // tell user about problem (but don't spam console about playermodel) + MsgDev( D_NOTE, "CL_ModelIndex: %s not precached\n", m ); + } + return 0; +} + +/* +============= +pfnIsLocal + +============= +*/ +static int GAME_EXPORT pfnIsLocal( int playernum ) +{ + if( playernum == cl.playernum ) + return true; + return false; +} + +/* +============= +pfnLocalPlayerDucking + +============= +*/ +static int GAME_EXPORT pfnLocalPlayerDucking( void ) +{ + return cl.predicted.usehull == 1; +} + +/* +============= +pfnLocalPlayerViewheight + +============= +*/ +static void GAME_EXPORT pfnLocalPlayerViewheight( float *view_ofs ) +{ + // predicted or smoothed + if( !view_ofs ) return; + + if( CL_IsPredicted( )) + VectorCopy( cl.predicted.viewofs, view_ofs ); + else VectorCopy( cl.frame.client.view_ofs, view_ofs ); +} + +/* +============= +pfnLocalPlayerBounds + +============= +*/ +static void GAME_EXPORT pfnLocalPlayerBounds( int hull, float *mins, float *maxs ) +{ + if( hull >= 0 && hull < 4 ) + { + if( mins ) VectorCopy( clgame.pmove->player_mins[hull], mins ); + if( maxs ) VectorCopy( clgame.pmove->player_maxs[hull], maxs ); + } +} + +/* +============= +pfnIndexFromTrace + +============= +*/ +int GAME_EXPORT pfnIndexFromTrace( struct pmtrace_s *pTrace ) +{ + if( pTrace->ent >= 0 && pTrace->ent < clgame.pmove->numphysent ) + { + // return cl.entities number + return clgame.pmove->physents[pTrace->ent].info; + } + return -1; +} + +/* +============= +pfnGetPhysent + +============= +*/ +static physent_t *GAME_EXPORT pfnGetPhysent( int idx ) +{ + if( idx >= 0 && idx < clgame.pmove->numphysent ) + { + // return physent + return &clgame.pmove->physents[idx]; + } + return NULL; +} + + + +/* +============= +pfnSetTraceHull + +============= +*/ +void GAME_EXPORT CL_SetTraceHull( int hull ) +{ + //clgame.old_trace_hull = clgame.pmove->usehull; + clgame.pmove->usehull = bound( 0, hull, 3 ); +} + +/* +============= +pfnPlayerTrace + +============= +*/ +void GAME_EXPORT CL_PlayerTrace( float *start, float *end, int traceFlags, int ignore_pe, pmtrace_t *tr ) +{ + if( !tr ) return; + *tr = PM_PlayerTraceExt( clgame.pmove, start, end, traceFlags, clgame.pmove->numphysent, clgame.pmove->physents, ignore_pe, NULL ); + //clgame.pmove->usehull = clgame.old_trace_hull; // restore old trace hull +} + +/* +============= +pfnPlayerTraceExt + +============= +*/ +void GAME_EXPORT CL_PlayerTraceExt( float *start, float *end, int traceFlags, int (*pfnIgnore)( physent_t *pe ), pmtrace_t *tr ) +{ + if( !tr ) return; + *tr = PM_PlayerTraceExt( clgame.pmove, start, end, traceFlags, clgame.pmove->numphysent, clgame.pmove->physents, -1, pfnIgnore ); + //clgame.pmove->usehull = clgame.old_trace_hull; // restore old trace hull +} + +/* +============= +pfnTraceTexture + +============= +*/ +static const char *GAME_EXPORT pfnTraceTexture( int ground, float *vstart, float *vend ) +{ + physent_t *pe; + + if( ground < 0 || ground >= clgame.pmove->numphysent ) + return NULL; // bad ground + + pe = &clgame.pmove->physents[ground]; + return PM_TraceTexture( pe, vstart, vend ); +} + +/* +============= +pfnTraceSurface + +============= +*/ +static struct msurface_s *GAME_EXPORT pfnTraceSurface( int ground, float *vstart, float *vend ) +{ + physent_t *pe; + + if( ground < 0 || ground >= clgame.pmove->numphysent ) + return NULL; // bad ground + + pe = &clgame.pmove->physents[ground]; + return PM_TraceSurface( pe, vstart, vend ); +} + +/* +============= +pfnStopAllSounds + +============= +*/ +static void GAME_EXPORT pfnStopAllSounds( int ent, int entchannel ) +{ + S_StopSound( ent, entchannel, NULL ); +} + +/* +============= +CL_LoadModel + +============= +*/ +static model_t *GAME_EXPORT CL_LoadModel( const char *modelname, int *index ) +{ + int idx; + + idx = CL_FindModelIndex( modelname ); + if( !idx ) return NULL; + if( index ) *index = idx; + + return Mod_Handle( idx ); +} + +int GAME_EXPORT CL_AddEntity( int entityType, cl_entity_t *pEnt ) +{ + if( !pEnt ) return false; + + // clear effects for all temp entities + if( !pEnt->index ) pEnt->curstate.effects = 0; + + // let the render reject entity without model + return CL_AddVisibleEntity( pEnt, entityType ); +} + +/* +============= +pfnGetGameDirectory + +============= +*/ +static const char *GAME_EXPORT pfnGetGameDirectory( void ) +{ + static char szGetGameDir[MAX_SYSPATH]; + + Q_sprintf( szGetGameDir, "%s", GI->gamefolder ); + return szGetGameDir; +} + +/* +============= +Key_LookupBinding + +============= +*/ +static const char *GAME_EXPORT Key_LookupBinding( const char *pBinding ) +{ + return Key_KeynumToString( Key_GetKey( pBinding )); +} + +/* +============= +pfnGetLevelName + +============= +*/ +static const char *GAME_EXPORT pfnGetLevelName( void ) +{ + static char mapname[64]; + + if( cls.state >= ca_connected ) + Q_snprintf( mapname, sizeof( mapname ), "maps/%s.bsp", clgame.mapname ); + else mapname[0] = '\0'; // not in game + + return mapname; +} + +/* +============= +pfnGetScreenFade + +============= +*/ +static void GAME_EXPORT pfnGetScreenFade( struct screenfade_s *fade ) +{ + if( fade ) *fade = clgame.fade; +} + +/* +============= +pfnSetScreenFade + +============= +*/ +static void GAME_EXPORT pfnSetScreenFade( struct screenfade_s *fade ) +{ + if( fade ) clgame.fade = *fade; +} + +/* +============= +pfnLoadMapSprite + +============= +*/ +static model_t *GAME_EXPORT pfnLoadMapSprite( const char *filename ) +{ + char name[64]; + int i; + int texFlags = TF_NOPICMIP; + + + if( cl_sprite_nearest->integer ) + texFlags |= TF_NEAREST; + + if( !filename || !*filename ) + { + MsgDev( D_ERROR, "CL_LoadMapSprite: bad name!\n" ); + return NULL; + } + + Q_strncpy( name, filename, sizeof( name )); + COM_FixSlashes( name ); + + // slot 0 isn't used + for( i = 1; i < MAX_IMAGES; i++ ) + { + if( !Q_stricmp( clgame.sprites[i].name, name )) + { + // prolonge registration + clgame.sprites[i].needload = clgame.load_sequence; + return &clgame.sprites[i]; + } + } + + // find a free model slot spot + for( i = 1; i < MAX_IMAGES; i++ ) + { + if( !clgame.sprites[i].name[0] ) + break; // this is a valid spot + } + + if( i == MAX_IMAGES ) + { + MsgDev( D_ERROR, "LoadMapSprite: can't load %s, MAX_HSPRITES limit exceeded\n", filename ); + return NULL; + } + + // load new map sprite + if( CL_LoadHudSprite( name, &clgame.sprites[i], true, texFlags )) + { + clgame.sprites[i].needload = clgame.load_sequence; + return &clgame.sprites[i]; + } + return NULL; +} + +/* +============= +PlayerInfo_ValueForKey + +============= +*/ +static const char *GAME_EXPORT PlayerInfo_ValueForKey( int playerNum, const char *key ) +{ + // find the player + if(( playerNum > cl.maxclients ) || ( playerNum < 1 )) + return NULL; + + if( !cl.players[playerNum-1].name[0] ) + return NULL; + + return Info_ValueForKey( cl.players[playerNum-1].userinfo, key ); +} + +/* +============= +PlayerInfo_SetValueForKey + +============= +*/ +static void GAME_EXPORT PlayerInfo_SetValueForKey( const char *key, const char *value ) +{ + cvar_t *var; + + var = (cvar_t *)Cvar_FindVar( key ); + if( !var || !(var->flags & CVAR_USERINFO )) + return; + + Cvar_DirectSet( var, value ); +} + +/* +============= +pfnGetPlayerUniqueID + +============= +*/ +static qboolean GAME_EXPORT pfnGetPlayerUniqueID( int iPlayer, char playerID[16] ) +{ + // TODO: implement + + playerID[0] = '\0'; + return false; +} + +/* +============= +pfnGetTrackerIDForPlayer + +============= +*/ +static int GAME_EXPORT pfnGetTrackerIDForPlayer( int playerSlot ) +{ + playerSlot -= 1; // make into a client index + + if( !cl.players[playerSlot].userinfo[0] || !cl.players[playerSlot].name[0] ) + return 0; + return Q_atoi( Info_ValueForKey( cl.players[playerSlot].userinfo, "*tracker" )); +} + +/* +============= +pfnGetPlayerForTrackerID + +============= +*/ +static int GAME_EXPORT pfnGetPlayerForTrackerID( int trackerID ) +{ + int i; + + for( i = 0; i < MAX_CLIENTS; i++ ) + { + if( !cl.players[i].userinfo[0] || !cl.players[i].name[0] ) + continue; + + if( Q_atoi( Info_ValueForKey( cl.players[i].userinfo, "*tracker" )) == trackerID ) + { + // make into a player slot + return (i+1); + } + } + return 0; +} + +/* +============= +pfnServerCmdUnreliable + +============= +*/ +static int GAME_EXPORT pfnServerCmdUnreliable( char *szCmdString ) +{ + if( !szCmdString || !szCmdString[0] ) + return 0; + + BF_WriteByte( &cls.datagram, clc_stringcmd ); + BF_WriteString( &cls.datagram, szCmdString ); + + return 1; +} + +/* +============= +pfnGetMousePos + +============= +*/ +static void GAME_EXPORT pfnGetMousePos( POINT *ppt ) +{ +#ifdef XASH_SDL + SDL_GetMouseState(&ppt->x, &ppt->y); +#else + ppt->x = ppt->y = 0; +#endif +} + +/* +============= +pfnSetMousePos + +============= +*/ +static void GAME_EXPORT pfnSetMousePos( int mx, int my ) +{ +#ifdef XASH_SDL + SDL_WarpMouseInWindow( host.hWnd, mx, my ); +#endif +} + +/* +============= +pfnSetMouseEnable + +============= +*/ +static void GAME_EXPORT pfnSetMouseEnable( qboolean fEnable ) +{ + if( fEnable ) IN_ActivateMouse( false ); + else IN_DeactivateMouse(); +} + +/* +============= +pfnGetServerTime + +============= +*/ +static float GAME_EXPORT pfnGetClientOldTime( void ) +{ + return cl.oldtime; +} + +/* +============= +pfnGetGravity + +============= +*/ +static float GAME_EXPORT pfnGetGravity( void ) +{ + return clgame.movevars.gravity; +} + +/* +============= +pfnEnableTexSort + +TODO: implement +============= +*/ +static void GAME_EXPORT pfnEnableTexSort( int enable ) +{ +} + +/* +============= +pfnSetLightmapColor + +TODO: implement +============= +*/ +static void GAME_EXPORT pfnSetLightmapColor( float red, float green, float blue ) +{ +} + +/* +============= +pfnSetLightmapScale + +TODO: implement +============= +*/ +static void GAME_EXPORT pfnSetLightmapScale( float scale ) +{ +} + +/* +============= +pfnSPR_DrawGeneric + +============= +*/ +static void GAME_EXPORT pfnSPR_DrawGeneric( int frame, int x, int y, const wrect_t *prc, int blendsrc, int blenddst, int width, int height ) +{ + pglEnable( GL_BLEND ); + pglBlendFunc( blendsrc, blenddst ); // g-cont. are params is valid? + SPR_DrawGeneric( frame, x, y, width, height, prc ); +} + +/* +============= +LocalPlayerInfo_ValueForKey + +============= +*/ +static const char *GAME_EXPORT LocalPlayerInfo_ValueForKey( const char* key ) +{ + return Info_ValueForKey( Cvar_Userinfo(), key ); +} + +/* +============= +pfnVGUI2DrawCharacter + +============= +*/ +static int GAME_EXPORT pfnVGUI2DrawCharacter( int x, int y, int number, unsigned int font ) +{ + if( !cls.creditsFont.valid ) + return 0; + + number &= 255; + + number = Con_UtfProcessChar( number ); + + if( number < 32 ) return 0; + if( y < -clgame.scrInfo.iCharHeight ) + return 0; + + clgame.ds.adjust_size = true; + menu.ds.gl_texturenum = cls.creditsFont.hFontTexture; + pfnPIC_DrawAdditive( x, y, -1, -1, &cls.creditsFont.fontRc[number] ); + clgame.ds.adjust_size = false; + + return clgame.scrInfo.charWidths[number]; +} + +/* +============= +pfnVGUI2DrawCharacterAdditive + +============= +*/ +static int GAME_EXPORT pfnVGUI2DrawCharacterAdditive( int x, int y, int ch, int r, int g, int b, unsigned int font ) +{ + if( !hud_utf8->integer ) + ch = Con_UtfProcessChar( ch ); + + return pfnDrawCharacter( x, y, ch, r, g, b ); +} + +/* +============= +pfnDrawString + +============= +*/ +static int GAME_EXPORT pfnDrawString( int x, int y, const char *str, int r, int g, int b ) +{ + Con_UtfProcessChar(0); + + // draw the string until we hit the null character or a newline character + for ( ; *str != 0 && *str != '\n'; str++ ) + { + x += pfnVGUI2DrawCharacterAdditive( x, y, (unsigned char)*str, r, g, b, 0 ); + } + + return x; +} + +/* +============= +pfnDrawStringReverse + +============= +*/ +static int GAME_EXPORT pfnDrawStringReverse( int x, int y, const char *str, int r, int g, int b ) +{ + // find the end of the string + char *szIt; + for( szIt = (char*)str; *szIt != 0; szIt++ ) + x -= clgame.scrInfo.charWidths[ (unsigned char) *szIt ]; + pfnDrawString( x, y, str, r, g, b ); + return x; +} + +/* +============= +GetCareerGameInterface + +============= +*/ +static void *GAME_EXPORT GetCareerGameInterface( void ) +{ + Msg( "^1Career GameInterface called!\n" ); + return NULL; +} + +/* +============= +pfnPlaySoundVoiceByName + +============= +*/ +static void GAME_EXPORT pfnPlaySoundVoiceByName( char *filename, float volume, int pitch ) +{ + int hSound = S_RegisterSound( filename ); + + S_StartSound( NULL, cl.refdef.viewentity, CHAN_NETWORKVOICE_END + 1, hSound, volume, 1.0, pitch, SND_STOP_LOOPING ); +} + +/* +============= +pfnMP3_InitStream + +============= +*/ +static void GAME_EXPORT pfnMP3_InitStream( char *filename, int looping ) +{ + if( !filename ) + { + S_StopBackgroundTrack(); + return; + } + + if( looping ) + { + S_StartBackgroundTrack( filename, filename, 0 ); + } + else + { + S_StartBackgroundTrack( filename, NULL, 0 ); + } +} + +/* +============= +pfnPlaySoundByNameAtPitch + +============= +*/ +static void GAME_EXPORT pfnPlaySoundByNameAtPitch( char *filename, float volume, int pitch ) +{ + int hSound = S_RegisterSound( filename ); + S_StartSound( NULL, cl.refdef.viewentity, CHAN_ITEM, hSound, volume, 1.0, pitch, SND_STOP_LOOPING ); +} + +/* +============= +pfnFillRGBABlend + +============= +*/ +void GAME_EXPORT CL_FillRGBABlend( int x, int y, int width, int height, int r, int g, int b, int a ) +{ + float x1 = x, y1 = y, w1 = width, h1 = height; + r = bound( 0, r, 255 ); + g = bound( 0, g, 255 ); + b = bound( 0, b, 255 ); + a = bound( 0, a, 255 ); + pglColor4ub( r, g, b, a ); + + SPR_AdjustSize( &x1, &y1, &w1, &h1 ); + + GL_SetRenderMode( kRenderTransTexture ); + R_DrawStretchPic( x1, y1, w1, h1, 0, 0, 1, 1, cls.fillImage ); + pglColor4ub( 255, 255, 255, 255 ); +} + +/* +============= +pfnGetAppID + +============= +*/ +static int GAME_EXPORT pfnGetAppID( void ) +{ + return 70; // Half-Life AppID +} + +/* +============= +pfnVguiWrap2_GetMouseDelta + +TODO: implement +============= +*/ +static void GAME_EXPORT pfnVguiWrap2_GetMouseDelta( int *x, int *y ) +{ +} + +/* +================= +TriApi implementation + +================= +*/ +/* +============= +TriRenderMode + +set rendermode +============= +*/ +void GAME_EXPORT TriRenderMode( int mode ) +{ + switch( mode ) + { + case kRenderNormal: + default: pglDisable( GL_BLEND ); + pglDisable( GL_ALPHA_TEST ); + pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + break; + case kRenderTransColor: + case kRenderTransAlpha: + case kRenderTransTexture: + // NOTE: TriAPI doesn't have 'solid' mode + pglEnable( GL_BLEND ); + pglDisable( GL_ALPHA_TEST ); + pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + break; + case kRenderGlow: + case kRenderTransAdd: + pglEnable( GL_BLEND ); + pglDisable( GL_ALPHA_TEST ); + pglBlendFunc( GL_SRC_ALPHA, GL_ONE ); + pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + break; + } +} + +/* +============= +TriBegin + +begin triangle sequence +============= +*/ +void GAME_EXPORT TriBegin( int mode ) +{ + switch( mode ) + { + case TRI_POINTS: + mode = GL_POINTS; + break; + case TRI_TRIANGLES: + mode = GL_TRIANGLES; + break; + case TRI_TRIANGLE_FAN: + mode = GL_TRIANGLE_FAN; + break; + case TRI_QUADS: + mode = GL_QUADS; + break; + case TRI_LINES: + mode = GL_LINES; + break; + case TRI_TRIANGLE_STRIP: + mode = GL_TRIANGLE_STRIP; + break; + case TRI_QUAD_STRIP: + mode = GL_QUAD_STRIP; + break; + case TRI_POLYGON: + default: mode = GL_POLYGON; + break; + } + + pglBegin( mode ); +} + +/* +============= +TriEnd + +draw triangle sequence +============= +*/ +void GAME_EXPORT TriEnd( void ) +{ + pglEnd(); + pglDisable( GL_ALPHA_TEST ); +} + +/* +============= +TriColor4f + +============= +*/ +void GAME_EXPORT TriColor4f( float r, float g, float b, float a ) +{ + clgame.ds.triColor[0] = (byte)bound( 0, (r * 255.0f), 255 ); + clgame.ds.triColor[1] = (byte)bound( 0, (g * 255.0f), 255 ); + clgame.ds.triColor[2] = (byte)bound( 0, (b * 255.0f), 255 ); + clgame.ds.triColor[3] = (byte)bound( 0, (a * 255.0f), 255 ); + pglColor4ub( clgame.ds.triColor[0], clgame.ds.triColor[1], clgame.ds.triColor[2], clgame.ds.triColor[3] ); +} + +/* +============= +TriColor4ub + +============= +*/ +void GAME_EXPORT TriColor4ub( byte r, byte g, byte b, byte a ) +{ + clgame.ds.triColor[0] = r; + clgame.ds.triColor[1] = g; + clgame.ds.triColor[2] = b; + clgame.ds.triColor[3] = a; + pglColor4ub( r, g, b, a ); +} + +/* +============= +TriTexCoord2f + +============= +*/ +void GAME_EXPORT TriTexCoord2f( float u, float v ) +{ + pglTexCoord2f( u, v ); +} + +/* +============= +TriVertex3fv + +============= +*/ +void GAME_EXPORT TriVertex3fv( const float *v ) +{ + pglVertex3fv( v ); +} + +/* +============= +TriVertex3f + +============= +*/ +void GAME_EXPORT TriVertex3f( float x, float y, float z ) +{ + pglVertex3f( x, y, z ); +} + +/* +============= +TriBrightness + +============= +*/ +void GAME_EXPORT TriBrightness( float brightness ) +{ + rgba_t rgba; + + brightness = max( 0.0f, brightness ); + rgba[0] = clgame.ds.triColor[0] * brightness; + rgba[1] = clgame.ds.triColor[1] * brightness; + rgba[2] = clgame.ds.triColor[2] * brightness; + rgba[3] = clgame.ds.triColor[3] * brightness; + + pglColor4ubv( rgba ); +} + +/* +============= +TriCullFace + +============= +*/ +void GAME_EXPORT TriCullFace( TRICULLSTYLE mode ) +{ + switch( mode ) + { + case TRI_FRONT: + clgame.ds.cullMode = GL_FRONT; + break; + default: + clgame.ds.cullMode = GL_NONE; + break; + } + GL_Cull( clgame.ds.cullMode ); +} + +/* +============= +TriSpriteTexture + +bind current texture +============= +*/ +int GAME_EXPORT TriSpriteTexture( model_t *pSpriteModel, int frame ) +{ + int gl_texturenum; + msprite_t *psprite; + + if(( gl_texturenum = R_GetSpriteTexture( pSpriteModel, frame )) == 0 ) + return 0; + + if( gl_texturenum <= 0 || gl_texturenum > MAX_TEXTURES ) + { + MsgDev( D_ERROR, "TriSpriteTexture: bad index %i\n", gl_texturenum ); + gl_texturenum = tr.defaultTexture; + } + + psprite = pSpriteModel->cache.data; + if( psprite->texFormat == SPR_ALPHTEST ) + { + pglEnable( GL_ALPHA_TEST ); + pglAlphaFunc( GL_GREATER, 0.0f ); + } + + GL_Bind( XASH_TEXTURE0, gl_texturenum ); + + return 1; +} + +/* +============= +TriWorldToScreen + +convert world coordinates (x,y,z) into screen (x, y) +============= +*/ +int TriWorldToScreen( float *world, float *screen ) +{ + int retval; + + retval = R_WorldToScreen( world, screen ); + + screen[0] = 0.5f * screen[0] * (float)cl.refdef.viewport[2]; + screen[1] = -0.5f * screen[1] * (float)cl.refdef.viewport[3]; + screen[0] += 0.5f * (float)cl.refdef.viewport[2]; + screen[1] += 0.5f * (float)cl.refdef.viewport[3]; + + return retval; +} + +/* +============= +TriFog + +enables global fog on the level +============= +*/ +void GAME_EXPORT TriFog( float flFogColor[3], float flStart, float flEnd, int bOn ) +{ + if( RI.fogEnabled ) return; + RI.fogCustom = true; + + if( !bOn ) + { + pglDisable( GL_FOG ); + RI.fogCustom = false; + return; + } + + // copy fog params + RI.fogColor[0] = flFogColor[0] / 255.0f; + RI.fogColor[1] = flFogColor[1] / 255.0f; + RI.fogColor[2] = flFogColor[2] / 255.0f; + RI.fogStart = flStart; + RI.fogDensity = 0.0f; + RI.fogEnd = flEnd; + + if( VectorIsNull( RI.fogColor )) + { + pglDisable( GL_FOG ); + return; + } + + pglEnable( GL_FOG ); + pglFogi( GL_FOG_MODE, GL_LINEAR ); + pglFogf( GL_FOG_START, RI.fogStart ); + pglFogf( GL_FOG_END, RI.fogEnd ); + pglFogfv( GL_FOG_COLOR, RI.fogColor ); + pglHint( GL_FOG_HINT, GL_NICEST ); +} + +/* +============= +TriGetMatrix + +very strange export +============= +*/ +void GAME_EXPORT TriGetMatrix( const int pname, float *matrix ) +{ + pglGetFloatv( pname, matrix ); +} + +/* +============= +TriBoxInPVS + +check box in pvs (absmin, absmax) +============= +*/ +int GAME_EXPORT TriBoxInPVS( float *mins, float *maxs ) +{ + return Mod_BoxVisible( mins, maxs, Mod_GetCurrentVis( )); +} + +/* +============= +TriLightAtPoint + +NOTE: dlights are ignored +============= +*/ +void GAME_EXPORT TriLightAtPoint( float *pos, float *value ) +{ + color24 ambient; + + if( !pos || !value ) + return; + + R_LightForPoint( pos, &ambient, false, false, 0.0f ); + + value[0] = (float)ambient.r * 255.0f; + value[1] = (float)ambient.g * 255.0f; + value[2] = (float)ambient.b * 255.0f; +} + +/* +============= +TriColor4fRendermode + +Heavy legacy of Quake... +============= +*/ +void GAME_EXPORT TriColor4fRendermode( float r, float g, float b, float a, int rendermode ) +{ + if( rendermode == kRenderTransAlpha ) + pglColor4f( r, g, b, a ); + else pglColor4f( r * a, g * a, b * a, 1.0f ); +} + +/* +============= +TriForParams + +============= +*/ +void GAME_EXPORT TriFogParams( float flDensity, int iFogSkybox ) +{ + RI.fogDensity = flDensity; + RI.fogCustom = iFogSkybox; +} + +/* +================= +DemoApi implementation + +================= +*/ +/* +================= +Demo_IsRecording + +================= +*/ +static int GAME_EXPORT Demo_IsRecording( void ) +{ + return cls.demorecording; +} + +/* +================= +Demo_IsPlayingback + +================= +*/ +static int GAME_EXPORT Demo_IsPlayingback( void ) +{ + return cls.demoplayback; +} + +/* +================= +Demo_IsTimeDemo + +================= +*/ +static int GAME_EXPORT Demo_IsTimeDemo( void ) +{ + return cls.timedemo; +} + +/* +================= +Demo_WriteBuffer + +================= +*/ +static void GAME_EXPORT Demo_WriteBuffer( int size, byte *buffer ) +{ + CL_WriteDemoUserMessage( buffer, size ); +} + +/* +================= +NetworkApi implementation + +================= +*/ +/* +================= +NetAPI_InitNetworking + +================= +*/ +static void GAME_EXPORT NetAPI_InitNetworking( void ) +{ + NET_Config( true, false ); // allow remote +} + +/* +================= +NetAPI_Status + +================= +*/ +static void GAME_EXPORT NetAPI_Status( net_status_t *status ) +{ + ASSERT( status != NULL ); + + status->connected = NET_IsLocalAddress( cls.netchan.remote_address ) ? false : true; + status->connection_time = host.realtime - cls.netchan.connect_time; + status->remote_address = cls.netchan.remote_address; + status->packet_loss = cls.packet_loss / 100; // percent + status->latency = cl.frame.latency; + status->local_address = net_local; + status->rate = cls.netchan.rate; +} + +/* +================= +NetAPI_SendRequest + +================= +*/ +static void GAME_EXPORT NetAPI_SendRequest( int context, int request, int flags, double timeout, netadr_t *remote_address, net_api_response_func_t response ) +{ + net_request_t *nr = NULL; + string req; + int i; + + if( !response ) + { + MsgDev( D_ERROR, "Net_SendRequest: no callbcak specified for request with context %i!\n", context ); + return; + } + + // find a free request + for( i = 0; i < MAX_REQUESTS; i++ ) + { + nr = &clgame.net_requests[i]; + if( !nr->pfnFunc || nr->timeout < host.realtime ) + break; + } + + if( i == MAX_REQUESTS ) + { + double max_timeout = 0; + + // no free requests? use older + for( i = 0, nr = NULL; i < MAX_REQUESTS; i++ ) + { + if(( host.realtime - clgame.net_requests[i].timesend ) > max_timeout ) + { + max_timeout = host.realtime - clgame.net_requests[i].timesend; + nr = &clgame.net_requests[i]; + } + } + } + + ASSERT( nr != NULL ); + + // clear slot + Q_memset( nr, 0, sizeof( *nr )); + + // create a new request + nr->timesend = host.realtime; + nr->timeout = nr->timesend + timeout; + nr->pfnFunc = response; + nr->resp.context = context; + nr->resp.type = request; + nr->resp.remote_address = *remote_address; + nr->flags = flags; + + if( request == NETAPI_REQUEST_SERVERLIST ) + { + // UNDONE: build request for master-server + } + else + { + // send request over the net + Q_snprintf( req, sizeof( req ), "netinfo %i %i %i", PROTOCOL_VERSION, context, request ); + Netchan_OutOfBandPrint( NS_CLIENT, nr->resp.remote_address, req ); + } +} + +/* +================= +NetAPI_CancelRequest + +================= +*/ +static void GAME_EXPORT NetAPI_CancelRequest( int context ) +{ + int i; + + // find a specified request + for( i = 0; i < MAX_REQUESTS; i++ ) + { + if( clgame.net_requests[i].resp.context == context ) + { + MsgDev( D_NOTE, "Request with context %i cancelled\n", context ); + Q_memset( &clgame.net_requests[i], 0, sizeof( net_request_t )); + break; + } + } +} + +/* +================= +NetAPI_CancelAllRequests + +================= +*/ +static void GAME_EXPORT NetAPI_CancelAllRequests( void ) +{ + Q_memset( clgame.net_requests, 0, sizeof( clgame.net_requests )); +} + +/* +================= +NetAPI_AdrToString + +================= +*/ +static char *GAME_EXPORT NetAPI_AdrToString( netadr_t *a ) +{ + return NET_AdrToString( *a ); +} + +/* +================= +NetAPI_CompareAdr + +================= +*/ +static int GAME_EXPORT NetAPI_CompareAdr( netadr_t *a, netadr_t *b ) +{ + return NET_CompareAdr( *a, *b ); +} + +/* +================= +NetAPI_StringToAdr + +================= +*/ +static int GAME_EXPORT NetAPI_StringToAdr( char *s, netadr_t *a ) +{ + return NET_StringToAdr( s, a ); +} + +/* +================= +NetAPI_ValueForKey + +================= +*/ +static const char *GAME_EXPORT NetAPI_ValueForKey( const char *s, const char *key ) +{ + return Info_ValueForKey( s, key ); +} + +/* +================= +NetAPI_RemoveKey + +================= +*/ +static void GAME_EXPORT NetAPI_RemoveKey( char *s, const char *key ) +{ + Info_RemoveKey( s, key ); +} + +/* +================= +NetAPI_SetValueForKey + +================= +*/ +static void GAME_EXPORT NetAPI_SetValueForKey( char *s, const char *key, const char *value, int maxsize ) +{ + if( key[0] == '*' ) return; + Info_SetValueForStarKey( s, key, value, maxsize ); +} + + +static void GAME_EXPORT VGui_ViewportPaintBackground( int extents[4] ) +{ + // stub +} + +/* +================= +IVoiceTweak implementation + +================= +*/ +/* +================= +Voice_StartVoiceTweakMode + +================= +*/ +static int GAME_EXPORT Voice_StartVoiceTweakMode( void ) +{ + // TODO: implement + return 0; +} + +/* +================= +Voice_EndVoiceTweakMode + +================= +*/ +static void GAME_EXPORT Voice_EndVoiceTweakMode( void ) +{ + // TODO: implement +} + +/* +================= +Voice_SetControlFloat + +================= +*/ +static void GAME_EXPORT Voice_SetControlFloat( VoiceTweakControl iControl, float value ) +{ + // TODO: implement +} + +/* +================= +Voice_GetControlFloat + +================= +*/ +static float GAME_EXPORT Voice_GetControlFloat( VoiceTweakControl iControl ) +{ + // TODO: implement + return 1.0f; +} + +/* +================= +Voice_GetSpeakingVolume + +================= +*/ +static int GAME_EXPORT Voice_GetSpeakingVolume( void ) +{ + // TODO: implement + return 255; +} + +// shared between client and server +triangleapi_t gTriApi = +{ + TRI_API_VERSION, + TriRenderMode, + TriBegin, + TriEnd, + TriColor4f, + TriColor4ub, + TriTexCoord2f, + (void*)TriVertex3fv, + TriVertex3f, + TriBrightness, + TriCullFace, + TriSpriteTexture, + (void*)R_WorldToScreen, // NOTE: XPROJECT, YPROJECT should be done in client.dll + TriFog, + (void*)R_ScreenToWorld, + TriGetMatrix, + TriBoxInPVS, + TriLightAtPoint, + TriColor4fRendermode, + TriFogParams, +}; + +static efx_api_t gEfxApi = +{ + CL_AllocParticle, + (void*)CL_BlobExplosion, + (void*)CL_Blood, + (void*)CL_BloodSprite, + (void*)CL_BloodStream, + (void*)CL_BreakModel, + (void*)CL_Bubbles, + (void*)CL_BubbleTrail, + (void*)CL_BulletImpactParticles, + CL_EntityParticles, + CL_Explosion, + CL_FizzEffect, + CL_FireField, + (void*)CL_FlickerParticles, + (void*)CL_FunnelSprite, + (void*)CL_Implosion, + (void*)CL_Large_Funnel, + (void*)CL_LavaSplash, + (void*)CL_MultiGunshot, + (void*)CL_MuzzleFlash, + (void*)CL_ParticleBox, + (void*)CL_ParticleBurst, + (void*)CL_ParticleExplosion, + (void*)CL_ParticleExplosion2, + (void*)CL_ParticleLine, + CL_PlayerSprites, + (void*)CL_Projectile, + (void*)CL_RicochetSound, + (void*)CL_RicochetSprite, + (void*)CL_RocketFlare, + CL_RocketTrail, + (void*)CL_RunParticleEffect, + (void*)CL_ShowLine, + (void*)CL_SparkEffect, + (void*)CL_SparkShower, + (void*)CL_SparkStreaks, + (void*)CL_Spray, + CL_Sprite_Explode, + CL_Sprite_Smoke, + (void*)CL_Sprite_Spray, + (void*)CL_Sprite_Trail, + CL_Sprite_WallPuff, + (void*)CL_StreakSplash, + (void*)CL_TracerEffect, + CL_UserTracerParticle, + CL_TracerParticles, + (void*)CL_TeleportSplash, + (void*)CL_TempSphereModel, + (void*)CL_TempModel, + (void*)CL_DefaultSprite, + (void*)CL_TempSprite, + CL_DecalIndex, + (void*)CL_DecalIndexFromName, + CL_DecalShoot, + CL_AttachTentToPlayer, + CL_KillAttachedTents, + (void*)CL_BeamCirclePoints, + (void*)CL_BeamEntPoint, + CL_BeamEnts, + CL_BeamFollow, + CL_BeamKill, + (void*)CL_BeamLightning, + (void*)CL_BeamPoints, + (void*)CL_BeamRing, + CL_AllocDlight, + CL_AllocElight, + (void*)CL_TempEntAlloc, + (void*)CL_TempEntAllocNoModel, + (void*)CL_TempEntAllocHigh, + (void*)CL_TempEntAllocCustom, + CL_GetPackedColor, + CL_LookupColor, + CL_DecalRemoveAll, + CL_FireCustomDecal, +}; + +static event_api_t gEventApi = +{ + EVENT_API_VERSION, + pfnPlaySound, + S_StopSound, + CL_FindModelIndex, + pfnIsLocal, + pfnLocalPlayerDucking, + pfnLocalPlayerViewheight, + pfnLocalPlayerBounds, + pfnIndexFromTrace, + pfnGetPhysent, + CL_SetUpPlayerPrediction, + CL_PushPMStates, + CL_PopPMStates, + CL_SetSolidPlayers, + CL_SetTraceHull, + CL_PlayerTrace, + CL_WeaponAnim, + pfnPrecacheEvent, + CL_PlaybackEvent, + pfnTraceTexture, + pfnStopAllSounds, + pfnKillEvents, + CL_EventIndex, + CL_IndexEvent, + CL_PlayerTraceExt, + CL_SoundFromIndex, + pfnTraceSurface, +}; + +static demo_api_t gDemoApi = +{ + Demo_IsRecording, + Demo_IsPlayingback, + Demo_IsTimeDemo, + Demo_WriteBuffer, +}; + +static net_api_t gNetApi = +{ + NetAPI_InitNetworking, + NetAPI_Status, + NetAPI_SendRequest, + NetAPI_CancelRequest, + NetAPI_CancelAllRequests, + NetAPI_AdrToString, + NetAPI_CompareAdr, + NetAPI_StringToAdr, + NetAPI_ValueForKey, + NetAPI_RemoveKey, + NetAPI_SetValueForKey, +}; + +static IVoiceTweak gVoiceApi = +{ + Voice_StartVoiceTweakMode, + Voice_EndVoiceTweakMode, + Voice_SetControlFloat, + Voice_GetControlFloat, + Voice_GetSpeakingVolume, +}; + +// engine callbacks +static cl_enginefunc_t gEngfuncs = +{ + pfnSPR_Load, + pfnSPR_Frames, + pfnSPR_Height, + pfnSPR_Width, + pfnSPR_Set, + pfnSPR_Draw, + pfnSPR_DrawHoles, + pfnSPR_DrawAdditive, + SPR_EnableScissor, + SPR_DisableScissor, + pfnSPR_GetList, + CL_FillRGBA, + pfnGetScreenInfo, + pfnSetCrosshair, + (void*)pfnCvar_RegisterVariable, + (void*)Cvar_VariableValue, + (void*)Cvar_VariableString, + (void*)pfnAddClientCommand, + (void*)pfnHookUserMsg, + (void*)pfnServerCmd, + (void*)pfnClientCmd, + pfnGetPlayerInfo, + (void*)pfnPlaySoundByName, + pfnPlaySoundByIndex, + AngleVectors, + CL_TextMessageGet, + pfnDrawCharacter, + pfnDrawConsoleString, + pfnDrawSetTextColor, + pfnDrawConsoleStringLen, + pfnConsolePrint, + pfnCenterPrint, + pfnGetWindowCenterX, + pfnGetWindowCenterY, + pfnGetViewAngles, + pfnSetViewAngles, + CL_GetMaxClients, + (void*)Cvar_SetFloat, + Cmd_Argc, + Cmd_Argv, + Con_Printf, + Con_DPrintf, + Con_NPrintf, + Con_NXPrintf, + pfnPhysInfo_ValueForKey, + pfnServerInfo_ValueForKey, + pfnGetClientMaxspeed, + pfnCheckParm, + (void*)Key_Event, + CL_GetMousePosition, + pfnIsNoClipping, + CL_GetLocalPlayer, + pfnGetViewModel, + CL_GetEntityByIndex, + pfnGetClientTime, + pfnCalcShake, + pfnApplyShake, + (void*)pfnPointContents, + (void*)CL_WaterEntity, + pfnTraceLine, + CL_LoadModel, + CL_AddEntity, + CL_GetSpritePointer, + pfnPlaySoundByNameAtLocation, + pfnPrecacheEvent, + CL_PlaybackEvent, + CL_WeaponAnim, + Com_RandomFloat, + Com_RandomLong, + (void*)pfnHookEvent, + (void*)Con_Visible, + pfnGetGameDirectory, + pfnCVarGetPointer, + Key_LookupBinding, + pfnGetLevelName, + pfnGetScreenFade, + pfnSetScreenFade, + pfnVGui_GetPanel, + VGui_ViewportPaintBackground, + (void*)COM_LoadFile, + COM_ParseFile, + COM_FreeFile, + &gTriApi, + &gEfxApi, + &gEventApi, + &gDemoApi, + &gNetApi, + &gVoiceApi, + pfnIsSpectateOnly, + pfnLoadMapSprite, + COM_AddAppDirectoryToSearchPath, + COM_ExpandFilename, + PlayerInfo_ValueForKey, + PlayerInfo_SetValueForKey, + pfnGetPlayerUniqueID, + pfnGetTrackerIDForPlayer, + pfnGetPlayerForTrackerID, + pfnServerCmdUnreliable, + pfnGetMousePos, + pfnSetMousePos, + pfnSetMouseEnable, + Cvar_GetList, + (void*)Cmd_GetFirstFunctionHandle, + (void*)Cmd_GetNextFunctionHandle, + (void*)Cmd_GetName, + pfnGetClientOldTime, + pfnGetGravity, + Mod_Handle, + pfnEnableTexSort, + pfnSetLightmapColor, + pfnSetLightmapScale, + pfnSequenceGet, + pfnSPR_DrawGeneric, + pfnSequencePickSentence, + pfnDrawString, + pfnDrawStringReverse, + LocalPlayerInfo_ValueForKey, + pfnVGUI2DrawCharacter, + pfnVGUI2DrawCharacterAdditive, + (void*)Sound_GetApproxWavePlayLen, + GetCareerGameInterface, + (void*)Cvar_Set, + pfnIsCareerMatch, + pfnPlaySoundVoiceByName, + pfnMP3_InitStream, + Sys_DoubleTime, + pfnProcessTutorMessageDecayBuffer, + pfnConstructTutorMessageDecayBuffer, + pfnResetTutorMessageDecayData, + pfnPlaySoundByNameAtPitch, + CL_FillRGBABlend, + pfnGetAppID, + Cmd_AliasGetList, + pfnVguiWrap2_GetMouseDelta, +}; + +void CL_UnloadProgs( void ) +{ + if( !clgame.hInstance ) return; + + CL_FreeEdicts(); + CL_FreeTempEnts(); + CL_FreeViewBeams(); + CL_FreeParticles(); + CL_ClearAllRemaps(); + Mod_ClearUserData(); + + + // NOTE: HLFX 0.5 has strange bug: hanging on exit if no map was loaded + if( !( !Q_stricmp( GI->gamefolder, "hlfx" ) && GI->version == 0.5f )) + clgame.dllFuncs.pfnShutdown(); + + Cvar_FullSet( "cl_background", "0", CVAR_READ_ONLY ); + Cvar_FullSet( "host_clientloaded", "0", CVAR_INIT ); + + Com_FreeLibrary( clgame.hInstance ); + VGui_Shutdown(); + Mem_FreePool( &cls.mempool ); + Mem_FreePool( &clgame.mempool ); + Q_memset( &clgame, 0, sizeof( clgame )); + + Cvar_Unlink(); + Cmd_Unlink( CMD_CLIENTDLL ); +} + +void Sequence_Init( void ); + +qboolean CL_LoadProgs( const char *name ) +{ + static playermove_t gpMove; + const dllfunc_t *func; + CL_EXPORT_FUNCS F; // export 'F' + qboolean critical_exports = true; + + if( clgame.hInstance ) CL_UnloadProgs(); + + // setup globals + cl.refdef.movevars = &clgame.movevars; + + // initialize PlayerMove + clgame.pmove = &gpMove; + + cls.mempool = Mem_AllocPool( "Client Static Pool" ); + clgame.mempool = Mem_AllocPool( "Client Edicts Zone" ); + clgame.entities = NULL; + + // NOTE: important stuff! + // vgui must startup BEFORE loading client.dll to avoid get error ERROR_NOACESS + // during LoadLibrary + VGui_Startup (menu.globals->scrWidth, menu.globals->scrHeight); + + clgame.hInstance = Com_LoadLibrary( name, false ); + if( !clgame.hInstance ) return false; + + // clear exports + for( func = cdll_exports; func && func->name; func++ ) + *func->func = NULL; + + // trying to get single export named 'F' + if(( F = (void *)Com_GetProcAddress( clgame.hInstance, "F" )) != NULL ) + { + MsgDev( D_NOTE, "CL_LoadProgs: found single callback export\n" ); + + // trying to fill interface now + F( &clgame.dllFuncs ); + + // check critical functions again + for( func = cdll_exports; func && func->name; func++ ) + { + if( func->func == NULL ) + break; // BAH critical function was missed + } + + // because all the exports are loaded through function 'F" + if( !func || !func->name ) + critical_exports = false; + } + + for( func = cdll_exports; func && func->name != NULL; func++ ) + { + if( *func->func != NULL ) + continue; // already get through 'F' + + // functions are cleared before all the extensions are evaluated + if(!( *func->func = (void *)Com_GetProcAddress( clgame.hInstance, func->name ))) + { + MsgDev( D_NOTE, "CL_LoadProgs: failed to get address of %s proc\n", func->name ); + + if( critical_exports ) + { + Com_FreeLibrary( clgame.hInstance ); + clgame.hInstance = NULL; + return false; + } + } + } + + // it may be loaded through 'F' so we don't need to clear them + if( critical_exports ) + { + // clear new exports + for( func = cdll_new_exports; func && func->name; func++ ) + *func->func = NULL; + } + + for( func = cdll_new_exports; func && func->name != NULL; func++ ) + { + if( *func->func != NULL ) + continue; // already get through 'F' + + // functions are cleared before all the extensions are evaluated + // NOTE: new exports can be missed without stop the engine + if(!( *func->func = (void *)Com_GetProcAddress( clgame.hInstance, func->name ))) + MsgDev( D_NOTE, "CL_LoadProgs: failed to get address of %s proc\n", func->name ); + } + + if( !clgame.dllFuncs.pfnInitialize( &gEngfuncs, CLDLL_INTERFACE_VERSION )) + { + Com_FreeLibrary( clgame.hInstance ); + MsgDev( D_NOTE, "CL_LoadProgs: can't init client API\n" ); + clgame.hInstance = NULL; + return false; + } + + Cvar_Get( "cl_nopred", "1", CVAR_ARCHIVE|CVAR_USERINFO, "disable client movement predicting" ); + cl_lw = Cvar_Get( "cl_lw", "0", CVAR_ARCHIVE|CVAR_USERINFO, "enable client weapon predicting" ); + Cvar_Get( "cl_lc", "0", CVAR_ARCHIVE|CVAR_USERINFO, "enable lag compensation" ); + Cvar_FullSet( "host_clientloaded", "1", CVAR_INIT ); + + clgame.maxRemapInfos = 0; // will be alloc on first call CL_InitEdicts(); + clgame.maxEntities = 2; // world + localclient (have valid entities not in game) + + CL_InitCDAudio( "media/cdaudio.txt" ); + CL_InitTitles( "titles.txt" ); + CL_InitParticles (); + CL_InitViewBeams (); + CL_InitTempEnts (); + CL_InitEdicts (); // initailize local player and world + CL_InitClientMove(); // initialize pm_shared + + if( !R_InitRenderAPI()) // Xash3D extension + { + MsgDev( D_WARN, "CL_LoadProgs: couldn't get render API\n" ); + } + Mobile_Init(); // Xash3D extension: mobile interface + + Sequence_Init(); + + // NOTE: some usermessages are handled into the engine + pfnHookUserMsg( "ScreenFade", CL_ParseScreenFade ); + pfnHookUserMsg( "ScreenShake", CL_ParseScreenShake ); + + // initialize game + clgame.dllFuncs.pfnInit(); + + CL_InitStudioAPI( ); + + return true; +} +#endif // XASH_DEDICATED diff --git a/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_main.c b/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_main.c new file mode 100644 index 0000000..89928c5 --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_main.c @@ -0,0 +1,2422 @@ +/* +cl_main.c - client main loop +Copyright (C) 2009 Uncle Mike + +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 3 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. +*/ + +#ifndef XASH_DEDICATED + +#include "common.h" +#include "client.h" +#include "net_encode.h" +#include "cl_tent.h" +#include "gl_local.h" +#include "input.h" +#include "touch.h" +#include "kbutton.h" +#include "vgui_draw.h" +#include "library.h" + +#define MAX_TOTAL_CMDS 16 +#define MIN_CMD_RATE 10.0 +#define MAX_CMD_BUFFER 4000 +#define CONNECTION_PROBLEM_TIME 15.0 // 15 seconds + +void CL_InternetServers_f( void ); + +convar_t *r_oldparticles; +convar_t *rcon_client_password; +convar_t *rcon_address; + +convar_t *cl_timeout; +convar_t *cl_predict; +convar_t *cl_showfps; +convar_t *cl_showpos; +convar_t *cl_nodelta; +convar_t *cl_crosshair; +convar_t *cl_cmdbackup; +convar_t *cl_showerror; +convar_t *cl_nosmooth; +convar_t *cl_smoothtime; +convar_t *cl_draw_particles; +convar_t *cl_lightstyle_lerping; +convar_t *cl_idealpitchscale; +convar_t *cl_solid_players; +convar_t *cl_draw_beams; +convar_t *cl_cmdrate; +convar_t *cl_interp; +convar_t *cl_allow_fragment; +convar_t *cl_lw; +convar_t *cl_trace_events; +convar_t *cl_trace_stufftext; +convar_t *cl_trace_messages; +convar_t *cl_charset; +convar_t *cl_sprite_nearest; +convar_t *cl_updaterate; +convar_t *cl_nat; +convar_t *hud_scale; +convar_t *cl_maxpacket; +convar_t *cl_maxpayload; + +convar_t *r_bmodelinterp; + +convar_t *hud_utf8; + +convar_t *ui_renderworld; +// +// userinfo +// +convar_t *name; +convar_t *model; +convar_t *topcolor; +convar_t *bottomcolor; +convar_t *rate; +convar_t *hltv; + +client_t cl; +client_static_t cls; +clgame_static_t clgame; + +//====================================================================== +qboolean CL_Active( void ) +{ + return ( cls.state == ca_active ); +} + +//====================================================================== +qboolean CL_IsInGame( void ) +{ + if( Host_IsDedicated() ) return true; // always active for dedicated servers + if( CL_GetMaxClients() > 1 ) return true; // always active for multiplayer + return ( cls.key_dest == key_game ); // active if not menu or console +} + +qboolean CL_IsInMenu( void ) +{ + return ( cls.key_dest == key_menu ); +} + +qboolean CL_IsInConsole( void ) +{ + return ( cls.key_dest == key_console ); +} + +qboolean CL_IsIntermission( void ) +{ + return cl.refdef.intermission; +} + +qboolean CL_IsPlaybackDemo( void ) +{ + return cls.demoplayback; +} + +qboolean CL_DisableVisibility( void ) +{ + return cls.envshot_disable_vis; +} + +qboolean CL_IsBackgroundDemo( void ) +{ + return ( cls.demoplayback && cls.demonum != -1 ); +} + +qboolean CL_IsBackgroundMap( void ) +{ + return ( cl.background && !cls.demoplayback ); +} + +/* +=============== +CL_ChangeGame + +This is experiment. Use with precaution +=============== +*/ +qboolean CL_ChangeGame( const char *gamefolder, qboolean bReset ) +{ + if( Host_IsDedicated() ) + return false; + + if( Q_stricmp( host.gamefolder, gamefolder )) + { + kbutton_t *mlook, *jlook; + qboolean mlook_active = false, jlook_active = false; + string mapname, maptitle; + int maxEntities; + + mlook = (kbutton_t *)clgame.dllFuncs.KB_Find( "in_mlook" ); + jlook = (kbutton_t *)clgame.dllFuncs.KB_Find( "in_jlook" ); + + if( mlook && ( mlook->state & 1 )) + mlook_active = true; + + if( jlook && ( jlook->state & 1 )) + jlook_active = true; + + // so reload all images (remote connect) + Mod_ClearAll( true ); + R_ShutdownImages(); + FS_LoadGameInfo( (bReset) ? host.gamefolder : gamefolder ); + R_InitImages(); + + // save parms + maxEntities = clgame.maxEntities; + Q_strncpy( mapname, clgame.mapname, MAX_STRING ); + Q_strncpy( maptitle, clgame.maptitle, MAX_STRING ); + + Com_ResetLibraryError(); + if( !CL_LoadProgs( va( "%s/%s", GI->dll_path, GI->client_lib))) + Sys_Warn( "Can't initialize client library\n%s", Com_GetLibraryError() ); + + // restore parms + clgame.maxEntities = maxEntities; + Q_strncpy( clgame.mapname, mapname, MAX_STRING ); + Q_strncpy( clgame.maptitle, maptitle, MAX_STRING ); + + // invalidate fonts so we can reloading them again + Q_memset( &cls.creditsFont, 0, sizeof( cls.creditsFont )); + SCR_InstallParticlePalette(); + SCR_LoadCreditsFont(); + Con_InvalidateFonts(); + + SCR_RegisterTextures (); + CL_FreeEdicts (); + SCR_VidInit (); + + if( cls.key_dest == key_game ) // restore mouse state + clgame.dllFuncs.IN_ActivateMouse(); + + // restore mlook state + if( mlook_active ) Cmd_ExecuteString( "+mlook\n", src_command ); + if( jlook_active ) Cmd_ExecuteString( "+jlook\n", src_command ); + return true; + } + + return false; +} + +/* +=============== +CL_LerpPoint + +Determines the fraction between the last two messages that the objects +should be put at. +=============== +*/ +static float CL_LerpPoint( void ) +{ + float f, frac; + + f = cl.mtime[0] - cl.mtime[1]; + + if( !f || SV_Active( )) + { + cl.time = cl.mtime[0]; + return 1.0f; + } + + if( f > 0.1f ) + { + // dropped packet, or start of demo + cl.mtime[1] = cl.mtime[0] - 0.1f; + f = 0.1f; + } + + frac = ( cl.time - cl.mtime[1] ) / f; + + if( frac < 0 ) + { + if( frac < -0.01f ) + cl.time = cl.mtime[1]; + frac = 0.0f; + } + else if( frac > 1.0f ) + { + if( frac > 1.01f ) + cl.time = cl.mtime[0]; + frac = 1.0f; + } + + return frac; +} + +/* +================= +CL_ComputePacketLoss + +================= +*/ +void CL_ComputePacketLoss( void ) +{ + int i, frm; + frame_t *frame; + int count = 0; + int lost = 0; + + if( host.realtime < cls.packet_loss_recalc_time ) + return; + + // recalc every second + cls.packet_loss_recalc_time = host.realtime + 1.0; + + // compuate packet loss + for( i = cls.netchan.incoming_sequence - CL_UPDATE_BACKUP + 1; i <= cls.netchan.incoming_sequence; i++ ) + { + frm = i; + frame = &cl.frames[frm & CL_UPDATE_MASK]; + + if( frame->receivedtime == -1.0 ) + lost++; + count++; + } + + if( count <= 0 ) cls.packet_loss = 0.0f; + else cls.packet_loss = ( 100.0f * (float)lost ) / (float)count; +} + +/* +================= +CL_UpdateFrameLerp + +================= +*/ +void CL_UpdateFrameLerp( void ) +{ + // not in server yet, no entities to redraw + if( cls.state != ca_active ) return; + + // we haven't received our first valid update from the server. + if( !cl.frame.valid || !cl.validsequence ) + return; + + // compute last interpolation amount + cl.commands[( cls.netchan.outgoing_sequence - 1 ) & CL_UPDATE_MASK].frame_lerp = cl.lerpFrac; +} + +/* +==================== +CL_CheckUpdateRate + +Check is current cl_updaterate valid +==================== +*/ +void CL_CheckUpdateRate() +{ + const float cl_updaterate_min = 10, cl_updaterate_max = 102; + + if( cl_updaterate->value < cl_updaterate_min ) + { + Cvar_SetFloat( "cl_updaterate", cl_updaterate_min ); + MsgDev( D_INFO, "cl_updaterate minimum is %f, resetting to default (%f)\n", cl_updaterate_min, cl_updaterate_min ); + } + else if( cl_updaterate->value > cl_updaterate_max ) + { + Cvar_SetFloat( "cl_updaterate", cl_updaterate_max ); + MsgDev( D_INFO, "cl_updaterate maximum is %f, resetting to maximum (%f)\n", cl_updaterate_max, cl_updaterate_max ); + } +} + +/* +==================== +CL_DriftInterpAmount + +Smoothly drift lerp_msec +==================== +*/ +int CL_DriftInterpolationAmount( float interp_sec ) +{ + static float interpolationAmount = 0.1f; + + if( interp_sec != interpolationAmount ) + { + float maxmove = host.frametime * 0.05; + float diff = interp_sec - interpolationAmount; + + if( diff > 0 ) + { + if( diff > maxmove ) + diff = maxmove; + } + else + { + diff = -diff; + + if( diff > maxmove ) + diff = -maxmove; + } + + interpolationAmount += diff; + } + + return bound( 0, interpolationAmount * 1000.0, 100 ); +} + +/* +==================== +CL_ComputeClientInterpAmount + +Check update rate, ex_interp value and calculate lerp_msec +==================== +*/ +void CL_ComputeClientInterpAmount( usercmd_t *cmd ) +{ + float interp_min, interp_max; + + CL_CheckUpdateRate(); + + interp_max = 0.2f; // hltv value + interp_min = max( 0.001, 1 / cl_updaterate->value ); + + if( cl_interp->value + 0.001 < interp_min ) + { + MsgDev( D_NOTE, "ex_interp forced up to %.f msec\n", interp_min * 1000 ); + Cvar_SetFloat( "ex_interp", interp_min ); + } + else if( cl_interp->value - 0.001 > interp_max ) + { + MsgDev( D_NOTE, "ex_interp forced down to %.f msec\n", interp_max * 1000 ); + Cvar_SetFloat( "ex_interp", interp_max ); + } + + cmd->lerp_msec = CL_DriftInterpolationAmount( cl_interp->value ); +} + + +/* +======================================================================= + +CLIENT MOVEMENT COMMUNICATION + +======================================================================= +*/ +/* +================= +CL_CreateCmd +================= +*/ +void CL_CreateCmd( void ) +{ + usercmd_t cmd = { 0 }; + runcmd_t *pcmd; + color24 color; + vec3_t angles; + qboolean active; + int i, ms; + + ms = host.frametime * 1000; + if( ms > 250 ) ms = 100; // time was unreasonable + else if( ms <= 0 ) ms = 1; // keep time an actual + + // build list of all solid entities per next frame (exclude clients) + CL_SetSolidEntities (); + CL_PushPMStates(); + CL_SetSolidPlayers ( cl.playernum ); + VectorCopy( cl.refdef.cl_viewangles, angles ); + + // write cdata + VectorCopy( cl.frame.client.origin, cl.data.origin ); + VectorCopy( cl.refdef.cl_viewangles, cl.data.viewangles ); + cl.data.iWeaponBits = cl.frame.client.weapons; + cl.data.fov = cl.scr_fov; + + if( clgame.dllFuncs.pfnUpdateClientData( &cl.data, cl.time ) ) + { + // grab changes if successful + VectorCopy( cl.data.viewangles, cl.refdef.cl_viewangles ); + cl.scr_fov = cl.data.fov; + } + + // allways dump the first ten messages, + // because it may contain leftover inputs + // from the last level + if( ++cl.movemessages <= 10 ) + { + if( !cls.demoplayback ) + { + cl.refdef.cmd = &cl.commands[cls.netchan.outgoing_sequence & CL_UPDATE_MASK].cmd; + *cl.refdef.cmd = cmd; + } + CL_PopPMStates(); + return; + } + + // message we are constructing. + i = cls.netchan.outgoing_sequence & CL_UPDATE_MASK; + + pcmd = &cl.commands[i]; + + pcmd->senttime = cls.demoplayback ? 0.0 : host.realtime; + memset( &pcmd->cmd, 0, sizeof( pcmd->cmd )); + pcmd->receivedtime = -1.0; + pcmd->processedfuncs = false; + pcmd->heldback = false; + pcmd->sendsize = 0; + + active = ( cls.state == ca_active && !cl.refdef.paused && !cls.demoplayback ); + +#ifdef XASH_SDL + if( m_ignore->integer ) + { + int x, y; + SDL_GetRelativeMouseState( &x, &y ); + } +#endif + + clgame.dllFuncs.CL_CreateMove( cl.time - cl.oldtime, &pcmd->cmd, active ); + CL_PopPMStates(); + + + // after command generated in client, + // add motion events from engine controls + IN_EngineAppendMove( host.frametime, &pcmd->cmd, active); + + R_LightForPoint( cl.frame.client.origin, &color, false, false, 128.0f ); + cmd.lightlevel = (color.r + color.g + color.b) / 3; + + // never let client.dll calc frametime for player + // because is potential backdoor for cheating + pcmd->cmd.msec = ms; + CL_ComputeClientInterpAmount( &pcmd->cmd ); + + V_ProcessOverviewCmds( &pcmd->cmd ); + V_ProcessShowTexturesCmds( &pcmd->cmd ); + + if(( cl.background && !cls.demoplayback ) || gl_overview->integer || cls.changelevel ) + { + VectorCopy( angles, cl.refdef.cl_viewangles ); + VectorCopy( angles, pcmd->cmd.viewangles ); + pcmd->cmd.msec = 0; + } + + // demo always have commands + // so don't overwrite them + if( !cls.demoplayback ) cl.refdef.cmd = &pcmd->cmd; +} + +void CL_WriteUsercmd( sizebuf_t *msg, int from, int to ) +{ + usercmd_t nullcmd; + usercmd_t *f, *t; + + ASSERT( from == -1 || ( from >= 0 && from < MULTIPLAYER_BACKUP )); + ASSERT( to >= 0 && to < MULTIPLAYER_BACKUP ); + + if( from == -1 ) + { + Q_memset( &nullcmd, 0, sizeof( nullcmd )); + f = &nullcmd; + } + else + { + f = &cl.commands[from].cmd; + } + + t = &cl.commands[to].cmd; + + // write it into the buffer + MSG_WriteDeltaUsercmd( msg, f, t ); +} + +/* +=================== +CL_WritePacket + +Create and send the command packet to the server +Including both the reliable commands and the usercmds +=================== +*/ +void CL_WritePacket( void ) +{ + sizebuf_t buf; + qboolean send_command = false; + byte data[MAX_CMD_BUFFER]; + int i, from, to, key, size; + int numbackup = 2; + int numcmds; + int newcmds; + int cmdnumber; + + // don't send anything if playing back a demo + if( cls.demoplayback || cls.state == ca_cinematic ) + return; + + if( cls.state == ca_disconnected || cls.state == ca_connecting ) + return; + + CL_ComputePacketLoss (); + +#ifndef _DEBUG + if( cl_cmdrate->value < MIN_CMD_RATE ) + { + Cvar_SetFloat( "cl_cmdrate", MIN_CMD_RATE ); + } +#endif + Q_memset( data, 0, MAX_CMD_BUFFER ); + BF_Init( &buf, "ClientData", data, sizeof( data )); + + // Determine number of backup commands to send along + numbackup = bound( 0, cl_cmdbackup->integer, MAX_BACKUP_COMMANDS ); + if( cls.state == ca_connected ) numbackup = 0; + + // Check to see if we can actually send this command + + // In single player, send commands as fast as possible + // Otherwise, only send when ready and when not choking bandwidth + if(( cl.maxclients == 1 ) || ( NET_IsLocalAddress( cls.netchan.remote_address ) && !host_limitlocal->integer )) + send_command = true; + else if(( host.realtime >= cls.nextcmdtime ) && Netchan_CanPacket( &cls.netchan )) + send_command = true; + + if( cl.force_send_usercmd ) + { + send_command = true; + cl.force_send_usercmd = false; + } + + if(( cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged ) >= CL_UPDATE_MASK ) + { + if(( host.realtime - cls.netchan.last_received ) > CONNECTION_PROBLEM_TIME ) + { + Con_NPrintf( 1, "^3Warning:^1 Connection Problem^7\n" ); + cl.validsequence = 0; + } + } + + if( cl_nodelta->integer ) + { + cl.validsequence = 0; + } + + // send a userinfo update if needed + if( userinfo->modified ) + { + BF_WriteByte( &cls.netchan.message, clc_userinfo ); + BF_WriteString( &cls.netchan.message, Cvar_Userinfo( )); + } + + if( send_command ) + { + int outgoing_sequence; + + if( cl_cmdrate->integer > 0 ) + cls.nextcmdtime = host.realtime + ( 1.0f / cl_cmdrate->value ); + else cls.nextcmdtime = host.realtime; // always able to send right away + + if( cls.lastoutgoingcommand == -1 ) + { + outgoing_sequence = cls.netchan.outgoing_sequence; + cls.lastoutgoingcommand = cls.netchan.outgoing_sequence; + } + else outgoing_sequence = cls.lastoutgoingcommand + 1; + + // begin a client move command + BF_WriteByte( &buf, clc_move ); + + // save the position for a checksum byte + key = BF_GetRealBytesWritten( &buf ); + BF_WriteByte( &buf, 0 ); + + // write packet lossage percentation + BF_WriteByte( &buf, cls.packet_loss ); + + // say how many backups we'll be sending + BF_WriteByte( &buf, numbackup ); + + // how many real commands have queued up + newcmds = ( cls.netchan.outgoing_sequence - cls.lastoutgoingcommand ); + + // put an upper/lower bound on this + newcmds = bound( 0, newcmds, MAX_TOTAL_CMDS ); + if( cls.state == ca_connected ) newcmds = 0; + + BF_WriteByte( &buf, newcmds ); + + numcmds = newcmds + numbackup; + from = -1; + + for( i = numcmds - 1; i >= 0; i-- ) + { + cmdnumber = ( cls.netchan.outgoing_sequence - i ) & CL_UPDATE_MASK; + //if( i == 0 ) cl.commands[cmdnumber].processedfuncs = true; // only last cmd allow to run funcs + + to = cmdnumber; + CL_WriteUsercmd( &buf, from, to ); + from = to; + + if( BF_CheckOverflow( &buf )) + Host_Error( "CL_Move, overflowed command buffer (%i bytes)\n", MAX_CMD_BUFFER ); + } + + // calculate a checksum over the move commands + size = BF_GetRealBytesWritten( &buf ) - key - 1; + buf.pData[key] = CRC32_BlockSequence( buf.pData + key + 1, size, cls.netchan.outgoing_sequence ); + + // message we are constructing. + i = cls.netchan.outgoing_sequence & CL_UPDATE_MASK; + + // determine if we need to ask for a new set of delta's. + if( cl.validsequence && (cls.state == ca_active) && !( cls.demorecording && cls.demowaiting )) + { + cl.delta_sequence = cl.validsequence; + + BF_WriteByte( &buf, clc_delta ); + BF_WriteByte( &buf, cl.validsequence & 0xFF ); + } + else + { + // request delta compression of entities + cl.delta_sequence = -1; + } + + if( BF_CheckOverflow( &buf )) + { + Host_Error( "CL_Move, overflowed command buffer (%i bytes)\n", MAX_CMD_BUFFER ); + } + + // remember outgoing command that we are sending + cls.lastoutgoingcommand = cls.netchan.outgoing_sequence; + + // update size counter for netgraph + cl.commands[cls.netchan.outgoing_sequence & CL_UPDATE_MASK].sendsize = BF_GetNumBytesWritten( &buf ); + + // composite the rest of the datagram.. + if( BF_GetNumBitsWritten( &cls.datagram ) <= BF_GetNumBitsLeft( &buf )) + BF_WriteBits( &buf, BF_GetData( &cls.datagram ), BF_GetNumBitsWritten( &cls.datagram )); + BF_Clear( &cls.datagram ); + + // deliver the message (or update reliable) + Netchan_TransmitBits( &cls.netchan, BF_GetNumBitsWritten( &buf ), BF_GetData( &buf )); + } + else + { + // mark command as held back so we'll send it next time + cl.commands[cls.netchan.outgoing_sequence & CL_UPDATE_MASK].heldback = true; + + // increment sequence number so we can detect that we've held back packets. + cls.netchan.outgoing_sequence++; + } + + if( cls.demorecording ) + { + // Back up one because we've incremented outgoing_sequence each frame by 1 unit + cmdnumber = ( cls.netchan.outgoing_sequence - 1 ) & CL_UPDATE_MASK; + CL_WriteDemoUserCmd( cmdnumber ); + } + + // update download/upload slider. + Netchan_UpdateProgress( &cls.netchan ); +} + +/* +================= +CL_SendCmd + +Called every frame to builds and sends a command packet to the server. +================= +*/ +void CL_SendCmd( void ) +{ + // we create commands even if a demo is playing, + CL_CreateCmd(); + // clc_move, userinfo etc + CL_WritePacket(); + + // make sure what menu and CL_WritePacket catch changes + userinfo->modified = false; +} + +/* +================== +CL_Quit_f +================== +*/ +void CL_Quit_f( void ) +{ + CL_Disconnect(); + Sys_Quit(); +} + +/* +================ +CL_Drop + +Called after an Host_Error was thrown +================ +*/ +void CL_Drop( void ) +{ + if( cls.state == ca_uninitialized ) + return; + CL_Disconnect(); + + // This fixes crash in menu_playersetup after disconnecting from server + CL_ClearEdicts(); + + if( cls.need_save_config && !SV_Active() ) + { + Cbuf_AddText( "host_writeconfig\n" ); + cls.need_save_config = false; + } +} + +/* +================ +CL_TrySaveConfig_f + +Connfiguration changed in menu, so schedule config update +================ +*/ +void CL_TrySaveConfig_f( void ) +{ + if( cls.state <= ca_disconnected ) + Cbuf_AddText( "host_writeconfig\n" ); + else + cls.need_save_config = true; +} + +/* +======================= +CL_SendConnectPacket + +We have gotten a challenge from the server, so try and +connect. +====================== +*/ +void CL_SendConnectPacket( void ) +{ + netadr_t adr; + int port; + unsigned int extensions = 0; + char useragent[MAX_INFO_STRING] = ""; + unsigned int input_devices = 0; + + if( !NET_StringToAdr( cls.servername, &adr )) + { + MsgDev( D_INFO, "CL_SendConnectPacket: bad server address\n"); + cls.connect_time = 0; + return; + } + + if( adr.port == 0 ) adr.port = BF_BigShort( PORT_SERVER ); + port = Cvar_VariableValue( "net_qport" ); + + userinfo->modified = false; + + if( adr.type != NA_LOOPBACK ) + { + qboolean huff = Cvar_VariableInteger( "cl_enable_compress" ); + if( huff ) + extensions |= NET_EXT_HUFF; + + if( Cvar_VariableInteger( "cl_enable_split" ) ) + { + extensions |= NET_EXT_SPLIT; + if( !huff && Cvar_VariableInteger( "cl_enable_splitcompress" ) ) + extensions |= NET_EXT_SPLITHUFF; + } + + if( !m_ignore->integer ) + input_devices |= INPUT_DEVICE_MOUSE; + + if( touch_enable->integer ) + input_devices |= INPUT_DEVICE_TOUCH; + + if( Cvar_VariableInteger( "joy_enable" ) && Cvar_VariableInteger( "joy_found" ) ) + input_devices |= INPUT_DEVICE_JOYSTICK; + + // lock input devices change + Cvar_FullSet( "touch_enable", va( "%s", touch_enable->string ), touch_enable->flags | CVAR_READ_ONLY ); + Cvar_FullSet( "m_ignore", va( "%s", m_ignore->string ), m_ignore->flags | CVAR_READ_ONLY ); + Cvar_FullSet( "joy_enable", va( "%s", Cvar_VariableString( "joy_enable" ) ), CVAR_ARCHIVE | CVAR_READ_ONLY ); + + + Info_SetValueForKey( useragent, "d", va( "%d", input_devices ), sizeof( useragent ) ); + Info_SetValueForKey( useragent, "v", XASH_VERSION, sizeof( useragent ) ); + Info_SetValueForKey( useragent, "b", va( "%d", Q_buildnum() ), sizeof( useragent ) ); + Info_SetValueForKey( useragent, "o", Q_buildos(), sizeof( useragent ) ); + Info_SetValueForKey( useragent, "a", Q_buildarch(), sizeof( useragent ) ); + Info_SetValueForKey( useragent, "i", ID_GetMD5(), sizeof( useragent ) ); + } + else + { + // reset to writable state + Cvar_FullSet( "touch_enable", va( "%s", touch_enable->string ), touch_enable->flags & ~CVAR_READ_ONLY ); + Cvar_FullSet( "m_ignore", va( "%s", m_ignore->string ), m_ignore->flags & ~CVAR_READ_ONLY ); + Cvar_FullSet( "joy_enable", va( "%s", Cvar_VariableString( "joy_enable" ) ), CVAR_ARCHIVE ); + } + + Netchan_OutOfBandPrint( NS_CLIENT, adr, "connect %i %i %i \"%s\" %d %s\n", PROTOCOL_VERSION, port, cls.challenge, Cvar_Userinfo( ), extensions, useragent ); +} + +/* +================= +CL_CheckForResend + +Resend a connect message if the last one has timed out +================= +*/ +void CL_CheckForResend( void ) +{ + netadr_t adr; + int res; + + if( cls.internetservers_wait ) + CL_InternetServers_f(); + + // if the local server is running and we aren't then connect + if( cls.state == ca_disconnected && ( SV_Active( ) ) ) + { + cls.state = ca_connecting; + cls.connect_time = host.realtime; + Q_strncpy( cls.servername, "loopback", sizeof( cls.servername ) ); + cls.serveradr.type = NA_LOOPBACK; + // we don't need a challenge on the localhost + CL_SendConnectPacket(); + return; + } + + // resend if we haven't gotten a reply yet + if( cls.demoplayback || cls.state != ca_connecting ) + return; + + if(( host.realtime - cls.connect_time ) < 10.0f ) + return; + + res = NET_StringToAdrNB( cls.servername, &adr ); + + if( !res ) + { + MsgDev( D_ERROR, "CL_CheckForResend: bad server address\n" ); + cls.state = ca_disconnected; + Q_memset( &cls.serveradr, 0, sizeof( cls.serveradr ) ); + return; + } + + // blocked + if( res == 2 ) + { + cls.connect_time = MAX_HEARTBEAT; + return; + } + + if( adr.port == 0 ) adr.port = BF_BigShort( PORT_SERVER ); + cls.connect_time = host.realtime; // for retransmit requests + + // do not make non-blocking requests again + cls.serveradr = adr; + Q_strncpy( cls.servername, NET_AdrToString( adr ), sizeof( cls.servername )); + + MsgDev( D_NOTE, "Connecting to %s...\n", cls.servername ); + Netchan_OutOfBandPrint( NS_CLIENT, adr, "getchallenge\n" ); +} + +/* +================ +CL_Connect_f + +================ +*/ +void CL_Connect_f( void ) +{ + string server; + + if( Cmd_Argc() != 2 ) + { + Msg( "Usage: connect \n" ); + return; + } + + // default value 40000 ignored as we don't want to grow userinfo string + if( ( cl_maxpacket->integer < 40000 ) && ( cl_maxpacket->integer > 99 ) ) + { + cl_maxpacket->flags |= CVAR_USERINFO; + userinfo->modified = true; + } + else if( cl_maxpacket->flags & CVAR_USERINFO ) + { + cl_maxpacket->flags &= ~CVAR_USERINFO; + userinfo->modified = true; + } + + // allow override payload size for some bad networks + if( ( cl_maxpayload->integer < 40000 ) && ( cl_maxpayload->integer > 99 ) ) + { + cl_maxpayload->flags |= CVAR_USERINFO; + userinfo->modified = true; + } + else if( cl_maxpayload->flags & CVAR_USERINFO ) + { + cl_maxpayload->flags &= ~CVAR_USERINFO; + userinfo->modified = true; + } + + Q_strncpy( server, Cmd_Argv( 1 ), MAX_STRING ); + + if( Host_ServerState()) + { + // if running a local server, kill it and reissue + Q_strncpy( host.finalmsg, "Server quit", MAX_STRING ); + SV_Shutdown( false ); + } + + NET_Config( true, !cl_nat->integer ); // allow remote + + Msg( "server %s\n", server ); + CL_Disconnect(); + + HTTP_Clear_f(); + cls.state = ca_connecting; + Q_strncpy( cls.servername, server, sizeof( cls.servername )); + cls.connect_time = MAX_HEARTBEAT; // CL_CheckForResend() will fire immediately +} + + +/* +===================== +CL_Rcon_f + +Send the rest of the command line over as +an unconnected command. +===================== +*/ +void CL_Rcon_f( void ) +{ + char message[1024]; + netadr_t to; + int i = 1; + + if( !rcon_client_password->string ) + { + Msg( "You must set 'rcon_password' before issuing an rcon command.\n" ); + return; + } + + message[0] = (char)255; + message[1] = (char)255; + message[2] = (char)255; + message[3] = (char)255; + message[4] = 0; + + NET_Config( true, false ); // allow remote + + Q_strncat( message, "rcon ", sizeof( message ) ); + + if( !rcon_client_password->string[0] ) + { + // HACK: allow pass password with first argument + // do not port this to new engine, it is better to fix on server side + Q_strncat( message, Cmd_Argv( 1 ), sizeof( message ) ); + Q_strncat( message, " ", sizeof( message ) ); + i++; + } + else + { + Q_strncat( message, rcon_client_password->string, sizeof( message ) ); + Q_strncat( message, " ", sizeof( message ) ); + } + + for( ; i < Cmd_Argc(); i++ ) + { + string command; + + Com_EscapeCommand( command, Cmd_Argv( i ), MAX_STRING ); + + Q_strncat( message, "\"", sizeof( message ) ); + Q_strncat( message, command, sizeof( message ) ); + Q_strncat( message, "\" ", sizeof( message ) ); + } + + if( cls.state >= ca_connected ) + { + to = cls.netchan.remote_address; + } + else + { + if( !Q_strlen( rcon_address->string )) + { + Msg( "You must either be connected or set the 'rcon_address' cvar to issue rcon commands\n" ); + return; + } + + NET_StringToAdr( rcon_address->string, &to ); + if( to.port == 0 ) to.port = BF_BigShort( PORT_SERVER ); + } + + NET_SendPacket( NS_CLIENT, Q_strlen( message ) + 1, message, to ); +} + +void CL_WarnLostSplitPacket( void ) +{ + if( cls.state != ca_connected ) + return; + + if( Host_IsLocalClient() ) + return; + + if( ++cl.lostpackets == 8 ) + { + CL_Disconnect(); + Cbuf_AddText( "menu_connectionwarning" ); + MsgDev( D_WARN, "Too many lost packets! Showing Network options menu\n" ); + + } +} + + +/* +===================== +CL_ClearState + +===================== +*/ +void CL_ClearState( void ) +{ + S_StopAllSounds (); + R_ClearVBO(); + CL_ClearEffects (); + CL_FreeEdicts (); + + CL_ClearPhysEnts (); + + // wipe the entire cl structure + Q_memset( &cl, 0, sizeof( cl )); + BF_Clear( &cls.netchan.message ); + Q_memset( &clgame.fade, 0, sizeof( clgame.fade )); + Q_memset( &clgame.shake, 0, sizeof( clgame.shake )); + + Cvar_FullSet( "cl_background", "0", CVAR_READ_ONLY ); + cl.refdef.movevars = &clgame.movevars; + cl.maxclients = 1; // allow to drawing player in menu + cl.scr_fov = 90.0f; + + Cvar_SetFloat( "scr_download", 0.0f ); + Cvar_SetFloat( "scr_loading", 0.0f ); + + // restore real developer level + host.developer = host.old_developer; + + if( !SV_Active() && !CL_IsPlaybackDemo() && !cls.demorecording ) + { + Delta_Shutdown(); + Delta_InitClient(); + } + HTTP_ClearCustomServers(); +} + +/* +===================== +CL_SendDisconnectMessage + +Sends a disconnect message to the server +===================== +*/ +void CL_SendDisconnectMessage( void ) +{ + sizebuf_t buf; + byte data[32]; + + if( cls.state == ca_disconnected ) return; + + BF_Init( &buf, "LastMessage", data, sizeof( data )); + BF_WriteByte( &buf, clc_stringcmd ); + BF_WriteString( &buf, "disconnect" ); + + if( !cls.netchan.remote_address.type ) + cls.netchan.remote_address.type = NA_LOOPBACK; + + // make sure message will be delivered + Netchan_Transmit( &cls.netchan, BF_GetNumBytesWritten( &buf ), BF_GetData( &buf )); + Netchan_Transmit( &cls.netchan, BF_GetNumBytesWritten( &buf ), BF_GetData( &buf )); + Netchan_Transmit( &cls.netchan, BF_GetNumBytesWritten( &buf ), BF_GetData( &buf )); +} + +/* +===================== +CL_Disconnect + +Goes from a connected state to full screen console state +Sends a disconnect message to the server +This is also called on Host_Error, so it shouldn't cause any errors +===================== +*/ +void CL_Disconnect( void ) +{ + if( cls.state == ca_disconnected ) + return; + + cls.connect_time = 0; + cls.changedemo = false; + CL_Stop_f(); + + // send a disconnect message to the server + CL_SendDisconnectMessage(); + CL_ClearState (); + + S_StopBackgroundTrack (); + SCR_EndLoadingPlaque (); // get rid of loading plaque + + // clear the network channel, too. + Netchan_Clear( &cls.netchan ); + + cls.state = ca_disconnected; + Q_memset( &cls.serveradr, 0, sizeof( cls.serveradr ) ); + + // restore gamefolder here (in case client was connected to another game) + CL_ChangeGame( GI->gamefolder, true ); + + // reset to writable state + Cvar_FullSet( "touch_enable", va( "%s", touch_enable->string ), touch_enable->flags & ~CVAR_READ_ONLY ); + Cvar_FullSet( "m_ignore", va( "%s", m_ignore->string ), m_ignore->flags & ~CVAR_READ_ONLY ); + Cvar_FullSet( "joy_enable", va( "%s", Cvar_VariableString( "joy_enable" ) ), CVAR_ARCHIVE ); + Cbuf_InsertText( "menu_connectionprogress disconnect\n" ); + + // back to menu if developer mode set to "player" or "mapper" + if( host.developer > 2 ) return; + UI_SetActiveMenu( true ); +} + +void CL_Disconnect_f( void ) +{ + Host_Error( "Disconnected from server\n" ); +} + +void CL_Crashed( void ) +{ + // already freed + if( host.state == HOST_CRASHED ) return; + if( Host_IsDedicated() ) return; + if( !cls.initialized ) return; + + host.state = HOST_CRASHED; + + CL_Stop_f(); // stop any demos + + // send a disconnect message to the server + CL_SendDisconnectMessage(); +} + +/* +================= +CL_LocalServers_f +================= +*/ +void CL_LocalServers_f( void ) +{ + netadr_t adr; + + MsgDev( D_INFO, "Scanning for servers on the local network area...\n" ); + NET_Config( true, true ); // allow remote + + // send a broadcast packet + adr.type = NA_BROADCAST; + adr.port = BF_BigShort( PORT_SERVER ); + + Netchan_OutOfBandPrint( NS_CLIENT, adr, "info %i", PROTOCOL_VERSION ); +} + +#define MS_SCAN_REQUEST "1\xFF" "0.0.0.0:0\0" + +/* +================= +CL_InternetServers_f +================= +*/ +void CL_InternetServers_f( void ) +{ + char fullquery[512] = MS_SCAN_REQUEST; + char *info = fullquery + sizeof( MS_SCAN_REQUEST ) - 1; + const size_t remaining = sizeof( fullquery ) - sizeof( MS_SCAN_REQUEST ); + + Info_SetValueForKey( info, "nat", cl_nat->string, remaining ); + Info_SetValueForKey( info, "gamedir", GI->gamefolder, remaining ); + + // let master know about client version + Info_SetValueForKey( info, "clver", XASH_VERSION, remaining ); + + NET_Config( true, true ); // allow remote + + cls.internetservers_wait = NET_SendToMasters( NS_CLIENT, sizeof( MS_SCAN_REQUEST ) + Q_strlen( info ), fullquery ); + cls.internetservers_pending = true; +} + +/* +==================== +CL_QueryServer_f +==================== +*/ +void CL_QueryServer_f( void ) +{ + netadr_t adr; + + if( Cmd_Argc() != 2 ) + { + MsgDev( D_INFO, "Usage: queryserver \n" ); + return; + } + + NET_Config( true, true ); // allow remote + + if( NET_StringToAdr( Cmd_Argv( 1 ), &adr ) ) + { + Netchan_OutOfBandPrint( NS_CLIENT, adr, "info %i", PROTOCOL_VERSION ); + } + else + { + Msg( "Bad address\n" ); + } +} + +/* +==================== +CL_Packet_f + +packet +Contents allows \n escape character +==================== +*/ +void CL_Packet_f( void ) +{ + char send[2048]; + char *in, *out; + int i, l; + netadr_t adr; + + if( Cmd_Argc() != 3 ) + { + Msg( "packet \n" ); + return; + } + + NET_Config( true, false ); // allow remote + + if( !NET_StringToAdr( Cmd_Argv( 1 ), &adr )) + { + Msg( "Bad address\n" ); + return; + } + + if( !adr.port ) adr.port = BF_BigShort( PORT_SERVER ); + + in = Cmd_Argv( 2 ); + out = send + 4; + send[0] = send[1] = send[2] = send[3] = (char)0xff; + + l = Q_strlen( in ); + + for( i = 0; i < l; i++ ) + { + if( in[i] == '\\' && in[i+1] == 'n' ) + { + *out++ = '\n'; + i++; + } + else *out++ = in[i]; + } + *out = 0; + + NET_SendPacket( NS_CLIENT, out - send, send, adr ); +} + +/* +================= +CL_Reconnect_f + +The server is changing levels +================= +*/ +void CL_Reconnect_f( void ) +{ + if( cls.state == ca_disconnected ) + return; + + S_StopAllSounds (); + + if( cls.state == ca_connected ) + { + cls.demonum = cls.movienum = -1; // not in the demo loop now + cls.state = ca_connected; + + // clear channel and stuff + Netchan_Clear( &cls.netchan ); + BF_Clear( &cls.netchan.message ); + + BF_WriteByte( &cls.netchan.message, clc_stringcmd ); + BF_WriteString( &cls.netchan.message, "new" ); + + cl.validsequence = 0; // haven't gotten a valid frame update yet + cl.delta_sequence = -1; // we'll request a full delta from the baseline + cls.lastoutgoingcommand = -1; // we don't have a backed up cmd history yet + cls.nextcmdtime = host.realtime; // we can send a cmd right away + cl.last_command_ack = -1; + + CL_StartupDemoHeader (); + return; + } + + if( cls.servername[0] ) + { + if( cls.state >= ca_connected ) + { + CL_Disconnect(); + cls.connect_time = host.realtime - 1.5; + } + else cls.connect_time = MAX_HEARTBEAT; // fire immediately + + cls.demonum = cls.movienum = -1; // not in the demo loop now + cls.state = ca_connecting; + Msg( "reconnecting...\n" ); + } +} + +/* +================= +CL_ParseStatusMessage + +Handle a reply from a info +================= +*/ +void CL_ParseStatusMessage( netadr_t from, sizebuf_t *msg ) +{ + char *s; + + s = BF_ReadString( msg ); + MsgDev( D_NOTE, "Got info string: %s\n", s ); + UI_AddServerToList( from, s ); +} + +/* +================= +CL_ParseNETInfoMessage + +Handle a reply from a netinfo +================= +*/ +void CL_ParseNETInfoMessage( netadr_t from, sizebuf_t *msg ) +{ + char *s; + net_request_t *nr; + int i, context, type; + + context = Q_atoi( Cmd_Argv( 1 )); + type = Q_atoi( Cmd_Argv( 2 )); + s = Cmd_Argv( 3 ); + + // find a request with specified context + for( i = 0; i < MAX_REQUESTS; i++ ) + { + nr = &clgame.net_requests[i]; + + if( nr->resp.context == context && nr->resp.type == type ) + { + if( nr->timeout > host.realtime ) + { + // setup the answer + nr->resp.response = s; + nr->resp.remote_address = from; + nr->resp.error = NET_SUCCESS; + nr->resp.ping = host.realtime - nr->timesend; + nr->pfnFunc( &nr->resp ); + + if(!( nr->flags & FNETAPI_MULTIPLE_RESPONSE )) + Q_memset( nr, 0, sizeof( *nr )); // done + } + else + { + Q_memset( nr, 0, sizeof( *nr )); + } + return; + } + } +} + +//=================================================================== + +/* +====================== +CL_PrepSound + +Call before entering a new level, or after changing dlls +====================== +*/ +void CL_PrepSound( void ) +{ + int i, sndcount, step; + + MsgDev( D_NOTE, "CL_PrepSound: %s\n", clgame.mapname ); + for( i = 0, sndcount = 0; i < MAX_SOUNDS && cl.sound_precache[i+1][0]; i++ ) + sndcount++; // total num sounds + step = sndcount/10; + + S_BeginRegistration(); + + for( i = 0; i < MAX_SOUNDS - 1 && cl.sound_precache[i+1][0]; i++ ) + { + cl.sound_index[i+1] = S_RegisterSound( cl.sound_precache[i+1] ); + Cvar_SetFloat( "scr_loading", scr_loading->value + 5.0f / sndcount ); + if( step && !( i % step ) && ( cl_allow_levelshots->integer || cl.background )) + SCR_UpdateScreen(); + } + + S_EndRegistration(); + + if( host.soundList ) + { + // need to reapply all ambient sounds after restarting + for( i = 0; i < host.numsounds; i++) + { + soundlist_t *entry = &host.soundList[i]; + if( entry->looping && entry->entnum != -1 ) + { + MsgDev( D_NOTE, "Restarting sound %s...\n", entry->name ); + S_AmbientSound( entry->origin, entry->entnum, + S_RegisterSound( entry->name ), entry->volume, entry->attenuation, + entry->pitch, 0 ); + } + } + } + + host.soundList = NULL; + host.numsounds = 0; + + cl.audio_prepped = true; +} + +/* +================= +CL_PrepVideo + +Call before entering a new level, or after changing dlls +================= +*/ +void CL_PrepVideo( void ) +{ + string mdlname, mapname; + int i, mdlcount, step; + int map_checksum; // dummy + + if( !cl.model_precache[1][0] ) + return; // no map loaded + + Cvar_SetFloat( "scr_loading", 0.0f ); // reset progress bar + MsgDev( D_NOTE, "CL_PrepVideo: %s\n", clgame.mapname ); + + // let the render dll load the map + Q_strncpy( mapname, cl.model_precache[1], MAX_STRING ); + Mod_LoadWorld( mapname, (uint *)&map_checksum, cl.maxclients > 1 ); + cl.worldmodel = Mod_Handle( 1 ); // get world pointer + Cvar_SetFloat( "scr_loading", 25.0f ); + + SCR_UpdateScreen(); + + // make sure what map is valid + if( !cls.demoplayback && map_checksum != cl.checksum ) + Host_Error( "Local map version differs from server: %i != '%i'\n", map_checksum, cl.checksum ); + + for( i = 0, mdlcount = 0; i < MAX_MODELS && cl.model_precache[i+1][0]; i++ ) + mdlcount++; // total num models + step = mdlcount/10; + + for( i = 0; i < MAX_MODELS - 1 && cl.model_precache[i+1][0]; i++ ) + { + Q_strncpy( mdlname, cl.model_precache[i+1], MAX_STRING ); + Mod_RegisterModel( mdlname, i+1 ); + Cvar_SetFloat( "scr_loading", scr_loading->value + 75.0f / mdlcount ); + if( step && !( i % step ) && ( cl_allow_levelshots->integer || cl.background ) ) + SCR_UpdateScreen(); + } + + // update right muzzleflash indexes + CL_RegisterMuzzleFlashes (); + + // invalidate all decal indexes + Q_memset( cl.decal_index, 0, sizeof( cl.decal_index )); + + CL_ClearWorld (); + + R_NewMap(); // tell the render about new map + + V_SetupOverviewState(); // set overview bounds + + // must be called after lightmap loading! + clgame.dllFuncs.pfnVidInit(); + + // release unused SpriteTextures + for( i = 1; i < MAX_IMAGES; i++ ) + { + if( !clgame.sprites[i].name[0] ) continue; // free slot + if( clgame.sprites[i].needload != clgame.load_sequence ) + Mod_UnloadSpriteModel( &clgame.sprites[i] ); + } + + Mod_FreeUnused (); + + Q_memset( cl.playermodels, 0, sizeof( cl.playermodels ) ); + + Cvar_SetFloat( "scr_loading", 100.0f ); // all done + + if( host.decalList ) + { + // need to reapply all decals after restarting + for( i = 0; i < host.numdecals; i++ ) + { + decallist_t *entry = &host.decalList[i]; + cl_entity_t *pEdict = CL_GetEntityByIndex( entry->entityIndex ); + int decalIndex = CL_DecalIndex( CL_DecalIndexFromName( entry->name )); + int modelIndex = 0; + + if( pEdict ) modelIndex = pEdict->curstate.modelindex; + CL_DecalShoot( decalIndex, entry->entityIndex, modelIndex, entry->position, entry->flags ); + } + Z_Free( host.decalList ); + } + + host.decalList = NULL; + host.numdecals = 0; + + if( host.soundList ) + { + // need to reapply all ambient sounds after restarting + for( i = 0; i < host.numsounds; i++ ) + { + soundlist_t *entry = &host.soundList[i]; + if( entry->looping && entry->entnum != -1 ) + { + MsgDev( D_NOTE, "Restarting sound %s...\n", entry->name ); + S_AmbientSound( entry->origin, entry->entnum, + S_RegisterSound( entry->name ), entry->volume, entry->attenuation, + entry->pitch, 0 ); + } + } + } + + host.soundList = NULL; + host.numsounds = 0; + + if( host.developer <= 2 ) + Con_ClearNotify(); // clear any lines of console text + + SCR_UpdateScreen (); + + cl.video_prepped = true; + cl.force_refdef = true; +} + +/* +================= +CL_IsFromConnectingServer + +Used for connectionless packets, when netchan may not be ready. +================= +*/ +static qboolean CL_IsFromConnectingServer( netadr_t from ) +{ + return NET_IsLocalAddress( from ) || + NET_CompareAdr( cls.serveradr, from ); +} + +/* +================= +CL_ConnectionlessPacket + +Responses to broadcasts, etc +================= +*/ +void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) +{ + char *args; + char *c, buf[MAX_SYSPATH]; + int len = sizeof( buf ), i = 0; + netadr_t servadr; + + BF_Clear( msg ); + BF_ReadLong( msg ); // skip the -1 + + args = BF_ReadStringLine( msg ); + + Cmd_TokenizeString( args ); + c = Cmd_Argv( 0 ); + + MsgDev( D_NOTE, "CL_ConnectionlessPacket: %s : %s\n", NET_AdrToString( from ), c ); + + // server connection + if( !Q_strcmp( c, "client_connect" )) + { + unsigned int extensions; + + if( !CL_IsFromConnectingServer( from ) ) + return; + + extensions = Q_atoi( Cmd_Argv( 1 ) ); + if( cls.state == ca_connected ) + { + MsgDev( D_INFO, "Dup connect received. Ignored.\n"); + return; + } + + Netchan_Setup( NS_CLIENT, &cls.netchan, from, net_qport->integer ); + cls.splitcompress = false; + + if( extensions & NET_EXT_SPLIT ) + { + if( cl_maxpacket->integer >= 40000 || cl_maxpacket->integer < 100 ) + Cvar_SetFloat( "cl_maxpacket", 1400 ); + + cls.netchan.maxpacket = Cvar_VariableInteger( "cl_maxoutpacket" ); + if( cls.netchan.maxpacket < 100 ) + cls.netchan.maxpacket = cl_maxpacket->integer; + + cls.netchan.split = true; + MsgDev( D_INFO, "^2NET_EXT_SPLIT enabled^7 (packet sizes is %d/%d)\n", cl_maxpacket->integer, cls.netchan.maxpacket ); + + if( extensions & NET_EXT_SPLITHUFF ) + { + MsgDev( D_INFO, "^2NET_EXT_SPLITHUFF enabled^7\n"); + cls.splitcompress = true; + } + } + + if( extensions & NET_EXT_HUFF ) + { + MsgDev( D_INFO, "^2NET_EXT_HUFF enabled\n" ); + + cls.netchan.compress = true; + } + + BF_WriteByte( &cls.netchan.message, clc_stringcmd ); + BF_WriteString( &cls.netchan.message, "new" ); + cls.state = ca_connected; + + cl.validsequence = 0; // haven't gotten a valid frame update yet + cl.delta_sequence = -1; // we'll request a full delta from the baseline + cls.lastoutgoingcommand = -1; // we don't have a backed up cmd history yet + cls.nextcmdtime = host.realtime; // we can send a cmd right away + cl.last_command_ack = -1; + + CL_StartupDemoHeader (); + } + else if( !Q_strcmp( c, "info" )) + { + // server responding to a status broadcast + CL_ParseStatusMessage( from, msg ); + } + else if( !Q_strcmp( c, "netinfo" )) + { + // server responding to a status broadcast + CL_ParseNETInfoMessage( from, msg ); + } + else if( !Q_strcmp( c, "cmd" )) + { + // remote command from gui front end + if( !NET_IsLocalAddress( from )) + { + Msg( "Command packet from remote host. Ignored.\n" ); + return; + } +#ifdef XASH_SDL + SDL_RestoreWindow( host.hWnd ); +#endif + args = BF_ReadString( msg ); + Cbuf_AddText( args ); + Cbuf_AddText( "\n" ); + } + else if( !Q_strcmp( c, "print" )) + { + // print command from somewhere + char *str = BF_ReadString( msg ); + Msg("^5r:^7%s", str ); + + if( str[0] == 0 || str[ Q_strlen( str ) - 1 ] != '\n' ) + Msg( "\n" ); + } + else if( !Q_strcmp( c, "errormsg" )) + { + char *str; + + if( !CL_IsFromConnectingServer( from )) + return; + + str = BF_ReadString( msg ); + if( UI_IsVisible() ) + Cmd_ExecuteString( va("menu_showmessagebox \"^3Server message^7\n%s\"", str ), src_command ); + Msg( "%s", str ); + } + else if( !Q_strcmp( c, "updatemsg" )) + { + // got an update message from master server + // show update dialog from menu + netadr_t adr; + qboolean preferStore = true; + + if( !Q_strcmp( Cmd_Argv( 1 ), "nostore" ) ) + preferStore = false; + + if( NET_StringToAdr( DEFAULT_PRIMARY_MASTER, &adr ) ) + { + if( NET_CompareAdr( from, adr )) + { + // update from masterserver + Cbuf_AddText( va( "menu_updatedialog %s\n", preferStore ? "store" : "nostore" ) ); + } + } + else + { + // in case we don't have master anymore + Cbuf_AddText( va( "menu_updatedialog %s\n", preferStore ? "store" : "nostore" ) ); + } + } + else if( !Q_strcmp( c, "ping" )) + { + // ping from somewhere + Netchan_OutOfBandPrint( NS_CLIENT, from, "ack" ); + } + else if( !Q_strcmp( c, "challenge" )) + { + if( !CL_IsFromConnectingServer( from )) + return; + + // challenge from the server we are connecting to + cls.challenge = Q_atoi( Cmd_Argv( 1 )); + CL_SendConnectPacket(); + return; + } + else if( !Q_strcmp( c, "echo" )) + { + // echo request from server + Netchan_OutOfBandPrint( NS_CLIENT, from, "%s", Cmd_Argv( 1 )); + } + else if( !Q_strcmp( c, "disconnect" )) + { + if( !CL_IsFromConnectingServer( from )) + return; + + // a disconnect message from the server, which will happen if the server + // dropped the connection but it is still getting packets from us + CL_Disconnect(); + CL_ClearEdicts(); + } + else if( !Q_strcmp( c, "f") ) + { + // serverlist got from masterserver + while( !msg->bOverflow ) + { + servadr.type = NA_IP; + // 4 bytes for IP + BF_ReadBytes( msg, servadr.ip, sizeof( servadr.ip )); + // 2 bytes for Port + servadr.port = BF_ReadShort( msg ); + + if( !servadr.port ) + break; + + MsgDev( D_INFO, "Found server: %s\n", NET_AdrToString( servadr )); + + NET_Config( true, false ); // allow remote + + Netchan_OutOfBandPrint( NS_CLIENT, servadr, "info %i", PROTOCOL_VERSION ); + } + + // execute at next frame preventing relation on fps + if( cls.internetservers_pending ) + Cbuf_AddText("menu_resetping\n"); + cls.internetservers_pending = false; + } + else if( clgame.dllFuncs.pfnConnectionlessPacket( &from, args, buf, &len )) + { + // user out of band message (must be handled in CL_ConnectionlessPacket) + if( len > 0 ) Netchan_OutOfBand( NS_SERVER, from, len, (byte *)buf ); + } + else MsgDev( D_ERROR, "Bad connectionless packet from %s:\n%s\n", NET_AdrToString( from ), args ); +} + +/* +==================== +CL_GetMessage + +Handles recording and playback of demos, on top of NET_ code +==================== +*/ +static qboolean CL_GetMessage( byte *data, size_t *length ) +{ + if( cls.demoplayback ) + { + return CL_DemoReadMessage( data, length ); + } + + return NET_GetPacket( NS_CLIENT, &net_from, data, length ); +} + +/* +================= +CL_ReadNetMessage +================= +*/ +void CL_ReadNetMessage( void ) +{ + size_t curSize; + + while( CL_GetMessage( net_message_buffer, &curSize )) + { + if( *((int *)&net_message_buffer) == 0xFFFFFFFE ) + // Will rewrite existing packet by merged + if( !NetSplit_GetLong( &cls.netchan.netsplit, &net_from, net_message_buffer, &curSize, cls.splitcompress ) ) + continue; + + BF_Init( &net_message, "ServerData", net_message_buffer, curSize ); + + // check for connectionless packet (0xffffffff) first + if( BF_GetMaxBytes( &net_message ) >= 4 && *(int *)net_message.pData == -1 ) + { + CL_ConnectionlessPacket( net_from, &net_message ); + continue; + } + + // can't be a valid sequenced packet + if( cls.state < ca_connected ) continue; + + if( BF_GetMaxBytes( &net_message ) < 8 ) + { + MsgDev( D_WARN, "%s: runt packet\n", NET_AdrToString( net_from )); + continue; + } + + // packet from server + if( !cls.demoplayback && !NET_CompareAdr( net_from, cls.netchan.remote_address )) + { + MsgDev( D_ERROR, "CL_ReadPackets: %s:sequenced packet without connection\n", NET_AdrToString( net_from )); + continue; + } + + if( !cls.demoplayback && !Netchan_Process( &cls.netchan, &net_message )) + continue; // wasn't accepted for some reason + + CL_ParseServerMessage( &net_message ); + } + + // check for fragmentation/reassembly related packets. + if( cls.state != ca_disconnected && Netchan_IncomingReady( &cls.netchan )) + { + // the header is different lengths for reliable and unreliable messages + int headerBytes = BF_GetNumBytesRead( &net_message ); + + // process the incoming buffer(s) + if( Netchan_CopyNormalFragments( &cls.netchan, &net_message )) + { + CL_ParseServerMessage( &net_message ); + } + + if( Netchan_CopyFileFragments( &cls.netchan, &net_message )) + { + // remove from resource request stuff. + CL_ProcessFile( true, cls.netchan.incomingfilename ); + } + } + + Netchan_UpdateProgress( &cls.netchan ); +} + +void CL_ReadPackets( void ) +{ + CL_ReadNetMessage(); + + cl.lerpFrac = CL_LerpPoint(); + cl.lerpBack = 1.0f - cl.lerpFrac; + + if( clgame.entities ) + cl.thirdperson = clgame.dllFuncs.CL_IsThirdPerson(); + +#if 0 + // keep cheat cvars are unchanged + if( cl.maxclients > 1 && cls.state == ca_active && host.developer <= 1 ) + Cvar_SetCheatState(); +#endif + CL_UpdateFrameLerp (); + + // singleplayer never has connection timeout + if( NET_IsLocalAddress( cls.netchan.remote_address )) + return; + + // check timeout + if( cls.state >= ca_connected && !cls.demoplayback && cls.state != ca_cinematic ) + { + if( host.realtime - cls.netchan.last_received > cl_timeout->value ) + { + if( ++cl.timeoutcount > 5 ) // timeoutcount saves debugger + { + Msg( "\nServer connection timed out.\n" ); + CL_Disconnect(); + CL_ClearEdicts(); + return; + } + } + } + else cl.timeoutcount = 0; + +} + +/* +==================== +CL_ProcessFile + +A file has been received via the fragmentation/reassembly layer, put it in the right spot and + see if we have finished downloading files. +==================== +*/ +void CL_ProcessFile( qboolean successfully_received, const char *filename ) +{ + if( successfully_received) + MsgDev( D_INFO, "Received %s\n", filename ); + else + MsgDev( D_WARN, "Failed to download %s\n", filename ); + + if( downloadfileid == downloadcount - 1 ) + { + MsgDev( D_INFO, "Download completed, resuming connection\n" ); + FS_Rescan(); + + if( cls.state < ca_connecting ) + { + Cbuf_AddText( "menu_connectionprogress dlend\n" ); + return; + } + + BF_WriteByte( &cls.netchan.message, clc_stringcmd ); + BF_WriteString( &cls.netchan.message, "continueloading" ); + downloadfileid = 0; + downloadcount = 0; + return; + } + + downloadfileid++; +} + +//============================================================================= +/* +============== +CL_Userinfo_f +============== +*/ +void CL_Userinfo_f( void ) +{ + Msg( "User info settings:\n" ); + Info_Print( Cvar_Userinfo( )); + Msg( "Total %i symbols\n", Q_strlen( Cvar_Userinfo( ))); +} + +/* +============== +CL_Physinfo_f +============== +*/ +void CL_Physinfo_f( void ) +{ + Msg( "Phys info settings:\n" ); + Info_Print( cl.frame.client.physinfo ); + Msg( "Total %i symbols\n", Q_strlen( cl.frame.client.physinfo )); +} + +/* +================= +CL_Precache_f + +The server will send this command right +before allowing the client into the server +================= +*/ +void CL_Precache_f( void ) +{ + int spawncount; + + spawncount = Q_atoi( Cmd_Argv( 1 )); + + CL_PrepSound(); + CL_PrepVideo(); + + if( Cmd_Argc() > 2 ) + { + int svCheatState = Q_atoi( Cmd_Argv( 2 ) ); + + // don't let server send other values than 1 or 0 + Cvar_SetFloat("sv_cheats", svCheatState ? 1.0f : 0.0f ); + } + else + { + // disable just in case for old servers. + // TODO: move to a part of new protocol + Cvar_SetFloat("sv_cheats", 0.0f ); + } + Cvar_SetCheatState( false ); + + BF_WriteByte( &cls.netchan.message, clc_stringcmd ); + BF_WriteString( &cls.netchan.message, va( "begin %i\n", spawncount )); +} + +/* +================= +CL_Escape_f + +Escape to menu from game +================= +*/ +void CL_Escape_f( void ) +{ + if( cls.key_dest == key_menu ) + return; + + // the final credits is running + if( UI_CreditsActive( )) return; + + if( cls.state == ca_cinematic ) + SCR_NextMovie(); // jump to next movie + else UI_SetActiveMenu( true ); +} + +/* +================= +CL_InitLocal +================= +*/ +void CL_InitLocal( void ) +{ + cls.state = ca_disconnected; + Q_memset( &cls.serveradr, 0, sizeof( cls.serveradr ) ); + + // register our variables + cl_predict = Cvar_Get( "cl_predict", "0", CVAR_ARCHIVE, "enable client movement prediction" ); + cl_crosshair = Cvar_Get( "crosshair", "1", CVAR_ARCHIVE, "show weapon chrosshair" ); + cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0, "disable delta-compression for usercommands" ); + cl_idealpitchscale = Cvar_Get( "cl_idealpitchscale", "0.8", 0, "how much to look up/down slopes and stairs when not using freelook" ); + cl_solid_players = Cvar_Get( "cl_solid_players", "1", 0, "make all players non-solid (can't traceline them)" ); + cl_interp = Cvar_Get( "ex_interp", "0.01", 0, "interpolate object positions starting this many seconds in past" ); + //Cvar_Get( "ex_maxerrordistance", "0", 0, "" ); + cl_allow_fragment = Cvar_Get( "cl_allow_fragment", "0", CVAR_ARCHIVE, "allow downloading files directly from game server" ); + cl_timeout = Cvar_Get( "cl_timeout", "60", 0, "connect timeout (in seconds)" ); + cl_charset = Cvar_Get( "cl_charset", "utf-8", CVAR_ARCHIVE, "1-byte charset to use (iconv style)" ); + + rcon_client_password = Cvar_Get( "rcon_password", "", 0, "remote control client password" ); + rcon_address = Cvar_Get( "rcon_address", "", 0, "remote control address" ); + + r_oldparticles = Cvar_Get("r_oldparticles", "0", CVAR_ARCHIVE, "make some particle textures a simple square, like with software rendering"); + + cl_trace_events = Cvar_Get( "cl_trace_events", "0", CVAR_ARCHIVE|CVAR_CHEAT, "enable client event tracing (good for developers)" ); + cl_trace_messages = Cvar_Get( "cl_trace_messages", "0", CVAR_ARCHIVE|CVAR_CHEAT, "enable message names tracing (good for developers)"); + cl_trace_stufftext = Cvar_Get( "cl_trace_stufftext", "0", CVAR_ARCHIVE|CVAR_CHEAT, "enable stufftext commands tracing (good for developers)" ); + + // userinfo + Cvar_Get( "password", "", CVAR_USERINFO, "player password" ); + // cvar is not registered as userinfo as it not needed usually + // it will be set as userinfo only if it has non-default and correct value + cl_maxpacket = Cvar_Get( "cl_maxpacket", "40000", CVAR_ARCHIVE, "split packet size" ); + cl_maxpayload = Cvar_Get( "cl_maxpayload", "0", CVAR_ARCHIVE, "max netchan size from server durning connection" ); + name = Cvar_Get( "name", Sys_GetCurrentUser(), CVAR_USERINFO|CVAR_ARCHIVE|CVAR_PRINTABLEONLY, "player name" ); + model = Cvar_Get( "model", "player", CVAR_USERINFO|CVAR_ARCHIVE, "player model ('player' is a singleplayer model)" ); + topcolor = Cvar_Get( "topcolor", "0", CVAR_USERINFO|CVAR_ARCHIVE, "player top color" ); + bottomcolor = Cvar_Get( "bottomcolor", "0", CVAR_USERINFO|CVAR_ARCHIVE, "player bottom color" ); + rate = Cvar_Get( "rate", "25000", CVAR_USERINFO|CVAR_ARCHIVE, "player network rate" ); + hltv = Cvar_Get( "hltv", "0", CVAR_USERINFO|CVAR_LATCH, "HLTV mode" ); + cl_showfps = Cvar_Get( "cl_showfps", "1", CVAR_ARCHIVE, "show client fps" ); + cl_showpos = Cvar_Get( "cl_showpos", "0", CVAR_ARCHIVE, "show local player position and velocity" ); + cl_cmdbackup = Cvar_Get( "cl_cmdbackup", "10", CVAR_ARCHIVE, "how many additional history commands are sent" ); + cl_cmdrate = Cvar_Get( "cl_cmdrate", "30", CVAR_ARCHIVE, "max number of command packets sent to server per second" ); + cl_draw_particles = Cvar_Get( "cl_draw_particles", "1", CVAR_ARCHIVE, "disable particle effects" ); + cl_draw_beams = Cvar_Get( "cl_draw_beams", "1", CVAR_ARCHIVE, "disable view beams" ); + cl_lightstyle_lerping = Cvar_Get( "cl_lightstyle_lerping", "0", CVAR_ARCHIVE, "enable animated light lerping (perfomance option)" ); + cl_sprite_nearest = Cvar_Get( "cl_sprite_nearest", "0", CVAR_ARCHIVE, "disable texture filtering on sprites" ); + cl_showerror = Cvar_Get( "cl_showerror", "0", CVAR_ARCHIVE, "show prediction error" ); + cl_updaterate = Cvar_Get( "cl_updaterate", "60", CVAR_USERINFO|CVAR_ARCHIVE, "refresh rate of server messages" ); + cl_nosmooth = Cvar_Get( "cl_nosmooth", "0", CVAR_ARCHIVE, "smooth up stair climbing and interpolate position in multiplayer" ); + cl_smoothtime = Cvar_Get( "cl_smoothtime", "0.1", CVAR_ARCHIVE, "time to smooth up" ); + r_bmodelinterp = Cvar_Get( "r_bmodelinterp", "1", 0, "enable bmodel interpolation" ); + cl_nat = Cvar_Get( "cl_nat", "0", 0, "Show servers running under nat" ); + + hud_scale = Cvar_Get( "hud_scale", "0", CVAR_ARCHIVE|CVAR_LATCH, "scale hud at current resolution" ); + hud_utf8 = Cvar_Get( "hud_utf8", "0", CVAR_ARCHIVE, "Use utf-8 encoding for hud text" ); + + ui_renderworld = Cvar_Get( "ui_renderworld", "0", CVAR_ARCHIVE, "render world when UI is visible" ); + + Cvar_Get( "skin", "", CVAR_USERINFO, "player skin" ); // XDM 3.3 want this cvar + Cvar_Get( "cl_background", "0", CVAR_READ_ONLY, "indicates that background map is running" ); + + Cvar_Get( "cl_enable_compress", "0", CVAR_ARCHIVE, "request huffman compression from server" ); + Cvar_Get( "cl_enable_split", "1", CVAR_ARCHIVE, "request packet split from server" ); + Cvar_Get( "cl_enable_splitcompress", "0", CVAR_ARCHIVE, "request compressing all splitpackets" ); + + Cvar_Get( "cl_maxoutpacket", "0", CVAR_ARCHIVE, "max outcoming packet size (equal cl_maxpacket if 0)" ); + + // these two added to shut up CS 1.5 about 'unknown' commands + Cvar_Get( "lightgamma", "1", 0, "ambient lighting level (legacy, unused)" ); + Cvar_Get( "direct", "1", 0, "direct lighting level (legacy, unused)" ); + Cvar_Get( "voice_serverdebug", "0", 0, "debug voice (legacy, unused)" ); + + // server commands + Cmd_AddCommand ("noclip", NULL, "toggle noclipping mode" ); + Cmd_AddCommand ("notarget", NULL, "notarget mode (monsters do not see you)" ); + Cmd_AddCommand ("fullupdate", NULL, "re-init HUD on start of demo recording" ); + Cmd_AddCommand ("give", NULL, "give specified item or weapon" ); + Cmd_AddCommand ("drop", NULL, "drop current/specified item or weapon" ); + Cmd_AddCommand ("gametitle", NULL, "show game logo" ); + Cmd_AddCommand ("god", NULL, "toggle godmode" ); + Cmd_AddCommand ("fov", NULL, "set client field of view" ); + + Cmd_AddCommand ("kill", NULL, "commit suicide" ); + Cmd_AddCommand ("ent_list", NULL, "list entities on server" ); + Cmd_AddCommand ("ent_fire", NULL, "fire entity command (be careful)" ); + Cmd_AddCommand ("ent_info", NULL, "dump entity information" ); + Cmd_AddCommand ("ent_create", NULL, "create entity with specified values (be careful)" ); + Cmd_AddCommand ("ent_getvars", NULL, "put parameters of specified entities to client's' ent_last_* cvars" ); + + // register our commands + Cmd_AddCommand ("pause", NULL, "pause the game (if the server allows pausing)" ); + Cmd_AddCommand ("localservers", CL_LocalServers_f, "collect info about local servers" ); + Cmd_AddCommand ("internetservers", CL_InternetServers_f, "collect info about internet servers" ); + Cmd_AddCommand ("queryserver", CL_QueryServer_f, "collect info about server by address"); + Cmd_AddCommand ("cd", CL_PlayCDTrack_f, "play cd-track (not real cd-player of course)" ); + Cmd_AddCommand ("mp3", CL_MP3Command_f, "mp3 command" ); + + Cmd_AddCommand ("userinfo", CL_Userinfo_f, "print current client userinfo" ); + Cmd_AddCommand ("physinfo", CL_Physinfo_f, "print current client physinfo" ); + Cmd_AddCommand ("disconnect", CL_Disconnect_f, "disconnect from server" ); + Cmd_AddCommand ("record", CL_Record_f, "record a demo" ); + Cmd_AddCommand ("playdemo", CL_PlayDemo_f, "play a demo" ); + Cmd_AddCommand ("killdemo", CL_DeleteDemo_f, "delete a specified demo file and demoshot" ); + Cmd_AddCommand ("startdemos", CL_StartDemos_f, "start playing back the selected demos sequentially" ); + Cmd_AddCommand ("demos", CL_Demos_f, "restart looping demos defined by the last startdemos command" ); + Cmd_AddCommand ("movie", CL_PlayVideo_f, "play a movie" ); + Cmd_AddCommand ("stop", CL_Stop_f, "stop playing or recording a demo" ); + Cmd_AddCommand ("info", NULL, "collect info about local servers with specified protocol" ); + Cmd_AddCommand ("escape", CL_Escape_f, "escape from game to menu" ); + Cmd_AddCommand ("pointfile", CL_ReadPointFile_f, "show leaks on a map (if present of course)" ); + Cmd_AddCommand ("linefile", CL_ReadLineFile_f, "show leaks on a map (if present of course)" ); + + Cmd_AddCommand ("quit", CL_Quit_f, "quit from game" ); + Cmd_AddCommand ("exit", CL_Quit_f, "quit from game" ); + + Cmd_AddCommand ("screenshot", CL_ScreenShot_f, "takes a screenshot of the next rendered frame" ); + Cmd_AddCommand ("snapshot", CL_SnapShot_f, "takes a snapshot of the next rendered frame" ); + Cmd_AddCommand ("envshot", CL_EnvShot_f, "takes a six-sides cubemap shot with specified name" ); + Cmd_AddCommand ("skyshot", CL_SkyShot_f, "takes a six-sides envmap (skybox) shot with specified name" ); + Cmd_AddCommand ("levelshot", CL_LevelShot_f, "same as \"screenshot\", used to create plaque images" ); + Cmd_AddCommand ("saveshot", CL_SaveShot_f, "used to create save previews with LoadGame menu" ); + Cmd_AddCommand ("demoshot", CL_DemoShot_f, "used to create demo previews with PlayDemo menu" ); + + Cmd_AddCommand ("connect", CL_Connect_f, "connect to a server by hostname" ); + Cmd_AddCommand ("reconnect", CL_Reconnect_f, "reconnect to current level" ); + + Cmd_AddCommand ("rcon", CL_Rcon_f, "sends a command to the server console (rcon_password and rcon_address required)" ); + + // this is dangerous to leave in +// Cmd_AddCommand ("packet", CL_Packet_f, "send a packet with custom contents" ); + + Cmd_AddCommand ("precache", CL_Precache_f, "precache specified resource (by index)" ); + Cmd_AddCommand( "trysaveconfig", CL_TrySaveConfig_f, "schedule config save on disconnected state" ); +} + +//============================================================================ + +/* +================== +CL_SendCommand + +================== +*/ +void CL_SendCommand( void ) +{ + // send intentions now + CL_SendCmd (); + + // resend a connection request if necessary + CL_CheckForResend (); +} + +/* +================== +Host_ClientBegin + +Send command before server runs frame to prevent frame delay +================== +*/ +void Host_ClientBegin( void ) +{ + if( !cls.initialized ) + return; + + if( SV_Active() ) + { + CL_SendCommand(); + + CL_PredictMovement(); + } +} + +/* +================== +Host_ClientFrame + +================== +*/ +int r_stereo_side; // Move this.. this is bad placement +void Host_ClientFrame( int eye ) +{ + // if client is not active, skip render functions + + // decide the simulation time + if (eye == 0) { + cl.oldtime = cl.time; + cl.time += host.frametime; + + if (menu.hInstance) { + // menu time (not paused, not clamped) + menu.globals->time = host.realtime; + menu.globals->frametime = host.realframetime; + menu.globals->demoplayback = cls.demoplayback; + menu.globals->demorecording = cls.demorecording; + } + + VGui_RunFrame(); + + if (cls.initialized) { + clgame.dllFuncs.pfnFrame(host.frametime); + + // fetch results from server + CL_ReadPackets(); + + VID_CheckChanges(); + + // allow sound and video DLL change + if (cls.state == ca_active) { + if (!cl.video_prepped) CL_PrepVideo(); + if (!cl.audio_prepped) CL_PrepSound(); + } + + // send a new command message to the server + if (!SV_Active()) { + CL_SendCommand(); + + // predict all unacknowledged movements + CL_PredictMovement(); + } + } + } + + // update the screen + r_stereo_side = eye; + SCR_UpdateScreen (); + + if (eye == 1) + { + if( cls.initialized ) + { + // update audio + S_RenderFrame( &cl.refdef ); + + // decay dynamic lights + CL_DecayLights (); + + SCR_RunCinematic(); + } + + Con_RunConsole(); + + cls.framecount++; + } +} + + +//============================================================================ + +/* +==================== +CL_Init +==================== +*/ +void CL_Init( void ) +{ + qboolean loaded; + + Q_memset( &cls, 0, sizeof( cls ) ); + + if( Host_IsDedicated() ) + return; // nothing running on the client + + Con_Init(); + CL_InitLocal(); + + R_Init(); // init renderer + S_Init(); // init sound + + // unreliable buffer. unsed for unreliable commands and voice stream + BF_Init( &cls.datagram, "cls.datagram", cls.datagram_buf, sizeof( cls.datagram_buf )); + + Touch_Init(); + + { + char clientlib[256]; + Com_ResetLibraryError(); + if( Sys_GetParmFromCmdLine( "-clientlib", clientlib ) ) + loaded = CL_LoadProgs( clientlib ); + else +#ifdef XASH_INTERNAL_GAMELIBS + loaded = CL_LoadProgs( "client" ); +#else + loaded = CL_LoadProgs( va( "%s/%s" , GI->dll_path, SI.clientlib )); +#endif + if( !loaded ) + { + loaded = CL_LoadProgs( CLIENTDLL ); + } + } + + if( loaded ) + { + cls.initialized = true; + cls.keybind_changed = false; + cl.maxclients = 1; // allow to drawing player in menu + cls.olddemonum = -1; + cls.demonum = -1; + } + else + Sys_Warn("Could not load client library:\n%s", Com_GetLibraryError()); +} + +/* +=============== +CL_Shutdown + +=============== +*/ +void CL_Shutdown( void ) +{ + MsgDev( D_INFO, "CL_Shutdown()\n" ); + + if( cls.initialized && !host.crashed ) + { + Host_WriteOpenGLConfig (); + Host_WriteVideoConfig (); + } + Touch_Shutdown(); + CL_CloseDemoHeader(); + IN_Shutdown (); + Mobile_Shutdown(); + + SCR_Shutdown (); + if( cls.initialized ) + { + CL_UnloadProgs (); + cls.initialized = false; + } + + FS_Delete( "demoheader.tmp" ); // remove tmp file + SCR_FreeCinematic (); // release AVI's *after* client.dll because custom renderer may use them + S_Shutdown (); + R_Shutdown (); +} +#endif // XASH_DEDICATED diff --git a/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_menu.c b/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_menu.c new file mode 100644 index 0000000..c1065cf --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_menu.c @@ -0,0 +1,1154 @@ +/* +cl_menu.c - menu dlls interaction +Copyright (C) 2010 Uncle Mike + +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 3 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. +*/ + +#ifndef XASH_DEDICATED + +#include "common.h" +#include "client.h" +#include "const.h" +#include "gl_local.h" +#include "library.h" +#include "input.h" +#include "server.h" // !!svgame.hInstance +#include "gl_vidnt.h" + +static MENUAPI GetMenuAPI; +static ADDTOUCHBUTTONTOLIST pfnAddTouchButtonToList; +static void UI_UpdateUserinfo( void ); + +menu_static_t menu; + +void UI_UpdateMenu( float realtime ) +{ + if( !menu.hInstance ) return; + menu.dllFuncs.pfnRedraw( realtime ); + UI_UpdateUserinfo(); +} + +void UI_KeyEvent( int key, qboolean down ) +{ + if( !menu.hInstance ) return; + menu.dllFuncs.pfnKeyEvent( key, down ); +} + +void UI_MouseMove( int x, int y ) +{ + if( !menu.hInstance ) return; + menu.dllFuncs.pfnMouseMove( x, y ); +} + +void UI_SetActiveMenu( qboolean fActive ) +{ + movie_state_t *cin_state; + + if( host_xashds_hacks->integer ) + { + if( !cl.refdef.paused && !cls.changelevel && fActive ) + { + Cbuf_InsertText("pause\n"); + Cbuf_Execute(); + } + } + + + if( !menu.hInstance ) + { + if( !fActive ) + Key_SetKeyDest( key_game ); + return; + } + + menu.drawLogo = fActive; + menu.dllFuncs.pfnSetActiveMenu( fActive ); + + if( !fActive ) + { + // close logo when menu is shutdown + cin_state = AVI_GetState( CIN_LOGO ); + AVI_CloseVideo( cin_state ); + } +} + +void UI_AddServerToList( netadr_t adr, const char *info ) +{ + if( !menu.hInstance ) return; + menu.dllFuncs.pfnAddServerToList( adr, info ); +} + +void UI_GetCursorPos( int *pos_x, int *pos_y ) +{ + if( !menu.hInstance ) return; + menu.dllFuncs.pfnGetCursorPos( pos_x, pos_y ); +} + +void UI_SetCursorPos( int pos_x, int pos_y ) +{ + if( !menu.hInstance ) return; + menu.dllFuncs.pfnSetCursorPos( pos_x, pos_y ); +} + +void UI_ShowCursor( qboolean show ) +{ + if( !menu.hInstance ) return; + menu.dllFuncs.pfnShowCursor( show ); +} + +qboolean UI_CreditsActive( void ) +{ + if( !menu.hInstance ) return 0; + return menu.dllFuncs.pfnCreditsActive(); +} + +void UI_CharEvent( int key ) +{ + if( !menu.hInstance ) return; + menu.dllFuncs.pfnCharEvent( key ); +} + +qboolean UI_MouseInRect( void ) +{ + if( !menu.hInstance ) return 1; + return menu.dllFuncs.pfnMouseInRect(); +} + +qboolean UI_IsVisible( void ) +{ + if( !menu.hInstance ) return 0; + return menu.dllFuncs.pfnIsVisible(); +} + +static void UI_DrawLogo( const char *filename, float x, float y, float width, float height ) +{ + static float cin_time; + static int last_frame = -1; + byte *cin_data = NULL; + movie_state_t *cin_state; + int cin_frame; + qboolean redraw = false; + + if( !menu.drawLogo ) return; + cin_state = AVI_GetState( CIN_LOGO ); + + if( !AVI_IsActive( cin_state )) + { + string path; + const char *fullpath; + + // run cinematic if not + Q_snprintf( path, sizeof( path ), "media/%s", filename ); + FS_DefaultExtension( path, ".avi" ); + fullpath = FS_GetDiskPath( path, false ); + + if( FS_FileExists( path, false ) && !fullpath ) + { + MsgDev( D_ERROR, "Couldn't load %s from packfile. Please extract it\n", path ); + menu.drawLogo = false; + return; + } + + AVI_OpenVideo( cin_state, fullpath, false, false, true ); + if( !( AVI_GetVideoInfo( cin_state, &menu.logo_xres, &menu.logo_yres, &menu.logo_length ))) + { + AVI_CloseVideo( cin_state ); + menu.drawLogo = false; + return; + } + + cin_time = 0.0f; + last_frame = -1; + } + + if( width <= 0 || height <= 0 ) + { + // precache call, don't draw + cin_time = 0.0f; + last_frame = -1; + return; + } + + // advances cinematic time (ignores maxfps and host_framerate settings) + cin_time += host.realframetime; + + // restarts the cinematic + if( cin_time > menu.logo_length ) + cin_time = 0.0f; + + // read the next frame + cin_frame = AVI_GetVideoFrameNumber( cin_state, cin_time ); + + if( cin_frame != last_frame ) + { + cin_data = AVI_GetVideoFrame( cin_state, cin_frame ); + last_frame = cin_frame; + redraw = true; + } + + R_DrawStretchRaw( x, y, width, height, menu.logo_xres, menu.logo_yres, cin_data, redraw ); +} + +static int UI_GetLogoWidth( void ) +{ + return menu.logo_xres; +} + +static int UI_GetLogoHeight( void ) +{ + return menu.logo_yres; +} + +static float UI_GetLogoLength( void ) +{ + return menu.logo_length; +} + +static void UI_UpdateUserinfo( void ) +{ + player_info_t *player; + + if( !userinfo->modified ) return; + player = &menu.playerinfo; + + Q_strncpy( player->userinfo, Cvar_Userinfo(), sizeof( player->userinfo )); + Q_strncpy( player->name, Info_ValueForKey( player->userinfo, "name" ), sizeof( player->name )); + Q_strncpy( player->model, Info_ValueForKey( player->userinfo, "model" ), sizeof( player->model )); + player->topcolor = Q_atoi( Info_ValueForKey( player->userinfo, "topcolor" )); + player->bottomcolor = Q_atoi( Info_ValueForKey( player->userinfo, "bottomcolor" )); +} + +void Host_Credits( void ) +{ + if( !menu.hInstance ) return; + menu.dllFuncs.pfnFinalCredits(); +} + +static void UI_ConvertGameInfo( GAMEINFO *out, gameinfo_t *in ) +{ + Q_strncpy( out->gamefolder, in->gamefolder, sizeof( out->gamefolder )); + Q_strncpy( out->startmap, in->startmap, sizeof( out->startmap )); + Q_strncpy( out->trainmap, in->trainmap, sizeof( out->trainmap )); + Q_strncpy( out->title, in->title, sizeof( out->title )); + Q_strncpy( out->version, va( "%g", in->version ), sizeof( out->version )); + + Q_strncpy( out->game_url, in->game_url, sizeof( out->game_url )); + Q_strncpy( out->update_url, in->update_url, sizeof( out->update_url )); + Q_strncpy( out->size, Q_pretifymem( in->size, 0 ), sizeof( out->size )); + Q_strncpy( out->type, in->type, sizeof( out->type )); + Q_strncpy( out->date, in->date, sizeof( out->date )); + + out->gamemode = in->gamemode; + + if( in->nomodels ) + out->flags |= GFL_NOMODELS; +} + +static qboolean PIC_Scissor( float *x, float *y, float *width, float *height, float *u0, float *v0, float *u1, float *v1 ) +{ + float dudx, dvdy; + + // clip sub rect to sprite + if(( width == 0 ) || ( height == 0 )) + return false; + + if( *x + *width <= menu.ds.scissor_x ) + return false; + if( *x >= menu.ds.scissor_x + menu.ds.scissor_width ) + return false; + if( *y + *height <= menu.ds.scissor_y ) + return false; + if( *y >= menu.ds.scissor_y + menu.ds.scissor_height ) + return false; + + dudx = (*u1 - *u0) / *width; + dvdy = (*v1 - *v0) / *height; + + if( *x < menu.ds.scissor_x ) + { + *u0 += (menu.ds.scissor_x - *x) * dudx; + *width -= menu.ds.scissor_x - *x; + *x = menu.ds.scissor_x; + } + + if( *x + *width > menu.ds.scissor_x + menu.ds.scissor_width ) + { + *u1 -= (*x + *width - (menu.ds.scissor_x + menu.ds.scissor_width)) * dudx; + *width = menu.ds.scissor_x + menu.ds.scissor_width - *x; + } + + if( *y < menu.ds.scissor_y ) + { + *v0 += (menu.ds.scissor_y - *y) * dvdy; + *height -= menu.ds.scissor_y - *y; + *y = menu.ds.scissor_y; + } + + if( *y + *height > menu.ds.scissor_y + menu.ds.scissor_height ) + { + *v1 -= (*y + *height - (menu.ds.scissor_y + menu.ds.scissor_height)) * dvdy; + *height = menu.ds.scissor_y + menu.ds.scissor_height - *y; + } + return true; +} + +/* +==================== +PIC_DrawGeneric + +draw hudsprite routine +==================== +*/ +static void PIC_DrawGeneric( float x, float y, float width, float height, const wrect_t *prc ) +{ + float s1, s2, t1, t2; + int w, h; + + // assume we get sizes from image + R_GetTextureParms( &w, &h, menu.ds.gl_texturenum ); + + if( prc ) + { + // calc user-defined rectangle + s1 = (float)prc->left / (float)w; + t1 = (float)prc->top / (float)h; + s2 = (float)prc->right / (float)w; + t2 = (float)prc->bottom / (float)h; + + if( width == -1 && height == -1 ) + { + width = prc->right - prc->left; + height = prc->bottom - prc->top; + } + } + else + { + s1 = t1 = 0.0f; + s2 = t2 = 1.0f; + } + + if( width == -1 && height == -1 ) + { + width = w; + height = h; + } + + // pass scissor test if supposed + if( menu.ds.scissor_test && !PIC_Scissor( &x, &y, &width, &height, &s1, &t1, &s2, &t2 )) + return; + + PicAdjustSize( &x, &y, &width, &height ); + R_DrawStretchPic( x, y, width, height, s1, t1, s2, t2, menu.ds.gl_texturenum ); + pglColor4ub( 255, 255, 255, 255 ); +} + +/* +=============================================================================== + MainUI Builtin Functions + +=============================================================================== +*/ +/* +========= +pfnPIC_Load + +========= +*/ +static HIMAGE pfnPIC_Load( const char *szPicName, const byte *image_buf, int image_size, int flags ) +{ + HIMAGE tx; + + if( !szPicName || !*szPicName ) + { + MsgDev( D_ERROR, "CL_LoadImage: bad name!\n" ); + return 0; + } + + // add default parms to image + flags |= TF_IMAGE; + + host.decal_loading = true; // allow decal images for menu + tx = GL_LoadTexture( szPicName, image_buf, image_size, flags, NULL ); + host.decal_loading = false; + + return tx; +} + +/* +========= +pfnPIC_Width + +========= +*/ +static int pfnPIC_Width( HIMAGE hPic ) +{ + int picWidth; + + R_GetTextureParms( &picWidth, NULL, hPic ); + + return picWidth; +} + +/* +========= +pfnPIC_Height + +========= +*/ +static int pfnPIC_Height( HIMAGE hPic ) +{ + int picHeight; + + R_GetTextureParms( NULL, &picHeight, hPic ); + + return picHeight; +} + +/* +========= +pfnPIC_Set + +========= +*/ +void pfnPIC_Set( HIMAGE hPic, int r, int g, int b, int a ) +{ + menu.ds.gl_texturenum = hPic; + r = bound( 0, r, 255 ); + g = bound( 0, g, 255 ); + b = bound( 0, b, 255 ); + a = bound( 0, a, 255 ); + pglColor4ub( r, g, b, a ); +} + +/* +========= +pfnPIC_Draw + +========= +*/ +void pfnPIC_Draw( int x, int y, int width, int height, const wrect_t *prc ) +{ + GL_SetRenderMode( kRenderNormal ); + PIC_DrawGeneric( x, y, width, height, prc ); +} + +/* +========= +pfnPIC_DrawTrans + +========= +*/ +void pfnPIC_DrawTrans( int x, int y, int width, int height, const wrect_t *prc ) +{ + GL_SetRenderMode( kRenderTransTexture ); + PIC_DrawGeneric( x, y, width, height, prc ); +} + +/* +========= +pfnPIC_DrawHoles + +========= +*/ +void pfnPIC_DrawHoles( int x, int y, int width, int height, const wrect_t *prc ) +{ + GL_SetRenderMode( kRenderTransAlpha ); + PIC_DrawGeneric( x, y, width, height, prc ); +} + +/* +========= +pfnPIC_DrawAdditive + +========= +*/ +void pfnPIC_DrawAdditive( int x, int y, int width, int height, const wrect_t *prc ) +{ + GL_SetRenderMode( kRenderTransAdd ); + PIC_DrawGeneric( x, y, width, height, prc ); +} + +/* +========= +pfnPIC_EnableScissor + +========= +*/ +static void pfnPIC_EnableScissor( int x, int y, int width, int height ) +{ + // check bounds + x = bound( 0, x, menu.globals->scrWidth ); + y = bound( 0, y, menu.globals->scrHeight ); + width = bound( 0, width, menu.globals->scrWidth - x ); + height = bound( 0, height, menu.globals->scrHeight - y ); + + menu.ds.scissor_x = x; + menu.ds.scissor_width = width; + menu.ds.scissor_y = y; + menu.ds.scissor_height = height; + menu.ds.scissor_test = true; +} + +/* +========= +pfnPIC_DisableScissor + +========= +*/ +static void pfnPIC_DisableScissor( void ) +{ + menu.ds.scissor_x = 0; + menu.ds.scissor_width = 0; + menu.ds.scissor_y = 0; + menu.ds.scissor_height = 0; + menu.ds.scissor_test = false; +} + +/* +============= +pfnFillRGBA + +============= +*/ +static void pfnFillRGBA( int x, int y, int width, int height, int r, int g, int b, int a ) +{ + r = bound( 0, r, 255 ); + g = bound( 0, g, 255 ); + b = bound( 0, b, 255 ); + a = bound( 0, a, 255 ); + pglColor4ub( r, g, b, a ); + GL_SetRenderMode( kRenderTransTexture ); + R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, cls.fillImage ); + pglColor4ub( 255, 255, 255, 255 ); +} + +/* +============= +pfnClientCmd + +============= +*/ +static void pfnClientCmd( int exec_now, const char *szCmdString ) +{ + if( !szCmdString || !szCmdString[0] ) + return; + + Cbuf_AddText( szCmdString ); + Cbuf_AddText( "\n" ); + + // client command executes immediately + if( exec_now ) Cbuf_Execute(); +} + +/* +============= +pfnPlaySound + +============= +*/ +static void pfnPlaySound( const char *szSound ) +{ + if( !szSound || !*szSound ) return; + S_StartLocalSound( szSound, VOL_NORM, false ); +} + +/* +============= +pfnDrawCharacter + +quakefont draw character +============= +*/ +static void pfnDrawCharacter( int ix, int iy, int iwidth, int iheight, int ch, int ulRGBA, HIMAGE hFont ) +{ + rgba_t color; + float row, col, size; + float s1, t1, s2, t2; + float x = ix, y = iy; + float width = iwidth; + float height = iheight; + + ch &= 255; + + if( ch == ' ' ) return; + if( y < -height ) return; + + color[3] = (ulRGBA & 0xFF000000) >> 24; + color[0] = (ulRGBA & 0xFF0000) >> 16; + color[1] = (ulRGBA & 0xFF00) >> 8; + color[2] = (ulRGBA & 0xFF) >> 0; + pglColor4ubv( color ); + + col = (ch & 15) * 0.0625f + (0.5f / 256.0f); + row = (ch >> 4) * 0.0625f + (0.5f / 256.0f); + size = 0.0625f - (1.0f / 256.0f); + + s1 = col; + t1 = row; + s2 = s1 + size; + t2 = t1 + size; + + // pass scissor test if supposed + if( menu.ds.scissor_test && !PIC_Scissor( &x, &y, &width, &height, &s1, &t1, &s2, &t2 )) + return; + + GL_SetRenderMode( kRenderTransTexture ); + R_DrawStretchPic( x, y, width, height, s1, t1, s2, t2, hFont ); + pglColor4ub( 255, 255, 255, 255 ); +} + +/* +============= +UI_DrawConsoleString + +drawing string like a console string +============= +*/ +static int UI_DrawConsoleString( int x, int y, const char *string ) +{ + int drawLen; + + if( !string || !*string ) return 0; // silent ignore + drawLen = Con_DrawString( x, y, string, menu.ds.textColor ); + MakeRGBA( menu.ds.textColor, 255, 255, 255, 255 ); + + return (x + drawLen); // exclude color prexfixes +} + +/* +============= +pfnDrawSetTextColor + +set color for anything +============= +*/ +static void UI_DrawSetTextColor( int r, int g, int b, int alpha ) +{ + // bound color and convert to byte + menu.ds.textColor[0] = r; + menu.ds.textColor[1] = g; + menu.ds.textColor[2] = b; + menu.ds.textColor[3] = alpha; +} +/* +======================= +UI_AddTouchButtonToList + +send button parameters to menu +======================= +*/ +void UI_AddTouchButtonToList( const char *name, const char *texture, const char *command, unsigned char *color, int flags ) +{ + if( pfnAddTouchButtonToList ) + { + pfnAddTouchButtonToList( name, texture, command, color, flags ); + } +} + +/* +==================== +pfnGetPlayerModel + +for drawing playermodel previews +==================== +*/ +static cl_entity_t* pfnGetPlayerModel( void ) +{ + return &menu.playermodel; +} + +/* +==================== +pfnSetPlayerModel + +for drawing playermodel previews +==================== +*/ +static void pfnSetPlayerModel( cl_entity_t *ent, const char *path ) +{ + Mod_RegisterModel( path, MAX_MODELS - 1 ); + ent->curstate.modelindex = MAX_MODELS - 1; + ent->model = Mod_Handle( MAX_MODELS - 1 ); +} + +/* +==================== +pfnRenderScene + +for drawing playermodel previews +==================== +*/ +static void pfnRenderScene( const ref_params_t *fd ) +{ + if ( !cls.initialized ) return; + if( cls.state < ca_connecting ) + userinfo->modified = true; + + // to avoid division by zero + if( !fd || fd->fov_x <= 0.0f || fd->fov_y <= 0.0f ) + return; + R_RenderFrame( fd, false ); +} + +/* +==================== +pfnClientJoin + +send client connect +==================== +*/ +static void pfnClientJoin( const netadr_t adr ) +{ + Cbuf_AddText( va( "connect %s\n", NET_AdrToString( adr ))); +} + +/* +==================== +pfnKeyGetOverstrikeMode + +get global key overstrike state +==================== +*/ +static int pfnKeyGetOverstrikeMode( void ) +{ + return host.key_overstrike; +} + +/* +==================== +pfnKeySetOverstrikeMode + +set global key overstrike mode +==================== +*/ +static void pfnKeySetOverstrikeMode( int fActive ) +{ + host.key_overstrike = fActive; +} + +/* +==================== +pfnKeyGetState + +returns kbutton struct if found +==================== +*/ +static void *pfnKeyGetState( const char *name ) +{ + if( clgame.dllFuncs.KB_Find ) + return clgame.dllFuncs.KB_Find( name ); + return NULL; +} + +/* +========= +pfnMemAlloc + +========= +*/ +static void *pfnMemAlloc( size_t cb, const char *filename, const int fileline ) +{ + return _Mem_Alloc( menu.mempool, cb, filename, fileline ); +} + +/* +========= +pfnMemFree + +========= +*/ +static void pfnMemFree( void *mem, const char *filename, const int fileline ) +{ + _Mem_Free( mem, filename, fileline ); +} + +/* +========= +pfnGetGameInfo + +========= +*/ +static int pfnGetGameInfo( GAMEINFO *pgameinfo ) +{ + if( !pgameinfo ) return 0; + + *pgameinfo = menu.gameInfo; + return 1; +} + +/* +========= +pfnGetGamesList + +========= +*/ +static GAMEINFO **pfnGetGamesList( int *numGames ) +{ + if( numGames ) *numGames = SI.numgames; + return menu.modsInfo; +} + +/* +========= +pfnGetFilesList + +release prev search on a next call +========= +*/ +static char **pfnGetFilesList( const char *pattern, int *numFiles, int gamedironly ) +{ + static search_t *t = NULL; + + if( t ) Mem_Free( t ); // release prev search + + t = FS_Search( pattern, true, gamedironly ); + if( !t ) + { + if( numFiles ) *numFiles = 0; + return NULL; + } + + if( numFiles ) *numFiles = t->numfilenames; + return t->filenames; +} + +/* +========= +pfnGetClipboardData + +pointer must be released in call place +========= +*/ +static char *pfnGetClipboardData( void ) +{ + char *cb, *copy; + cb = Sys_GetClipboardData(); + copy = copystring( cb ); + return copy; +} + +/* +========= +pfnCheckGameDll + +========= +*/ +int pfnCheckGameDll( void ) +{ + void *hInst; + +#if TARGET_OS_IPHONE + // loading server library drains too many ram + // so 512MB iPod Touch cannot even connect to + // to servers in cstrike + return true; +#endif + + if( svgame.hInstance ) + return true; + + if( Cvar_VariableInteger("xashds_hacks") ) + return true; + + Com_ResetLibraryError(); + if(( hInst = Com_LoadLibrary( SI.gamedll, true )) != NULL ) + { + return true; + } + MsgDev( D_WARN, "Could not load server library:\n%s", Com_GetLibraryError() ); + Com_ResetLibraryError(); + return false; +} + +/* +========= +pfnChangeInstance + +========= +*/ +static void pfnChangeInstance( const char *newInstance, const char *szFinalMessage ) +{ + if( !szFinalMessage ) szFinalMessage = ""; + if( !newInstance || !*newInstance ) return; + + Host_NewInstance( newInstance, szFinalMessage ); +} + +/* +========= +pfnHostNewGame + +========= +*/ +static void pfnHostNewGame( const char *mapName ) +{ + if( !mapName || !*mapName ) return; + Host_NewGame( mapName, false ); +} + +/* +========= +pfnHostEndGame + +========= +*/ +static void pfnHostEndGame( const char *szFinalMessage ) +{ + if( !szFinalMessage ) szFinalMessage = ""; + Host_EndGame( szFinalMessage ); +} + +/* +========= +pfnStartBackgroundTrack + +========= +*/ +static void pfnStartBackgroundTrack( const char *introTrack, const char *mainTrack ) +{ + S_StartBackgroundTrack( introTrack, mainTrack, 0 ); +} + +static void pfnEnableTextInput( int enable ) +{ + Key_EnableTextInput( enable, false ); +} + +/* +=========== +pfnCvarSet + +Since menu can load script files, it's unsafe to allow +menu code change read-only cvar values +=========== +*/ +static void pfnCvarSet( const char *name, const char *value ) +{ + Cvar_Set2( name, value, false ); +} + +/* +=========== +pfnCvarSetValue + +Since menu can load script files, it's unsafe to allow +menu code change read-only cvar values +=========== +*/ +static void pfnCvarSetValue( const char *name, float value ) +{ + char val[32]; + + if( value == (int)value ) + Q_sprintf( val, "%i", (int)value ); + else Q_sprintf( val, "%f", value ); + + Cvar_Set2( name, val, false ); +} + +static void pfnWriteGameConfig( const char *name ) +{ + // do not use game.cfg or listenserver.cfg + // as it will be executed from hlsdk + Host_WriteGameConfig( "gamesettings.cfg" ); + + // remove old game.cfg, prevent it from resetting settings + FS_Delete( "game.cfg" ); +} + +// engine callbacks +static ui_enginefuncs_t gEngfuncs = +{ + (void*)pfnPIC_Load, + GL_FreeImage, + pfnPIC_Width, + pfnPIC_Height, + pfnPIC_Set, + pfnPIC_Draw, + pfnPIC_DrawHoles, + pfnPIC_DrawTrans, + pfnPIC_DrawAdditive, + pfnPIC_EnableScissor, + pfnPIC_DisableScissor, + pfnFillRGBA, + pfnCvar_RegisterVariable, + Cvar_VariableValue, + Cvar_VariableString, + pfnCvarSet, + pfnCvarSetValue, + pfnAddClientCommand, + pfnClientCmd, + Cmd_RemoveCommand, + Cmd_Argc, + Cmd_Argv, + Cmd_Args, + (void*)Con_Printf, + (void*)Con_DPrintf, + (void*)UI_NPrintf, + (void*)UI_NXPrintf, + pfnPlaySound, + UI_DrawLogo, + UI_GetLogoWidth, + UI_GetLogoHeight, + UI_GetLogoLength, + pfnDrawCharacter, + UI_DrawConsoleString, + UI_DrawSetTextColor, + Con_DrawStringLen, + Con_DefaultColor, + pfnGetPlayerModel, + pfnSetPlayerModel, + R_ClearScene, + pfnRenderScene, + CL_AddEntity, + Host_Error, + (void*)FS_FileExists, + pfnGetGameDir, + (void*)Cmd_CheckMapsList, + (void*)CL_Active, + pfnClientJoin, + COM_LoadFileForMe, + COM_ParseFile, + COM_FreeFile, + Key_ClearStates, + Key_SetKeyDest, + Key_KeynumToString, + Key_GetBinding, + Key_SetBinding, + (void*)Key_IsDown, + pfnKeyGetOverstrikeMode, + pfnKeySetOverstrikeMode, + pfnKeyGetState, + pfnMemAlloc, + pfnMemFree, + pfnGetGameInfo, + pfnGetGamesList, + pfnGetFilesList, + (void*)SV_GetComment, + (void*)CL_GetComment, + pfnCheckGameDll, + pfnGetClipboardData, + (void*)Sys_ShellExecute, + pfnWriteGameConfig, + pfnChangeInstance, + pfnStartBackgroundTrack, + pfnHostEndGame, + Com_RandomFloat, + (void*)Com_RandomLong, + (void*)IN_SetCursor, + pfnIsMapValid, + GL_ProcessTexture, + (void*)COM_CompareFileTime, + VID_GetModeString +}; + +static ui_textfuncs_t gTextfuncs = +{ + pfnEnableTextInput, + Con_UtfProcessChar, + Con_UtfMoveLeft, + Con_UtfMoveRight +}; + +void UI_UnloadProgs( void ) +{ + if( !menu.hInstance ) return; + + // deinitialize game + menu.dllFuncs.pfnShutdown(); + + Com_FreeLibrary( menu.hInstance ); + Mem_FreePool( &menu.mempool ); + Q_memset( &menu, 0, sizeof( menu )); +} + +qboolean UI_LoadProgs( void ) +{ + static ui_enginefuncs_t gpEngfuncs; + static ui_textfuncs_t gpTextfuncs; + static ui_globalvars_t gpGlobals; + int i; + UITEXTAPI GiveTextApi; + if( menu.hInstance ) UI_UnloadProgs(); + + // setup globals + menu.globals = &gpGlobals; +#ifdef XASH_INTERNAL_GAMELIBS + if(!( menu.hInstance = Com_LoadLibrary( "menu", false ))) + return false; +#else + if(!( menu.hInstance = Com_LoadLibrary( va( "%s/" MENUDLL, GI->dll_path ), false ))) + { + FS_AllowDirectPaths( true ); + + if(!( menu.hInstance = Com_LoadLibrary( "../" MENUDLL, false )) + && !( menu.hInstance = Com_LoadLibrary( MENUDLL, false ))) + + { + FS_AllowDirectPaths( false ); + return false; + } + } +#endif + FS_AllowDirectPaths( false ); + if(!( GetMenuAPI = (MENUAPI)Com_GetProcAddress( menu.hInstance, "GetMenuAPI" ))) + { + Com_FreeLibrary( menu.hInstance ); + MsgDev( D_NOTE, "UI_LoadProgs: can't init menu API\n" ); + menu.hInstance = NULL; + return false; + } + + // make local copy of engfuncs to prevent overwrite it with user dll + Q_memcpy( &gpEngfuncs, &gEngfuncs, sizeof( gpEngfuncs )); + + menu.mempool = Mem_AllocPool( "Menu Pool" ); + + if( !GetMenuAPI( &menu.dllFuncs, &gpEngfuncs, menu.globals )) + { + Com_FreeLibrary( menu.hInstance ); + MsgDev( D_NOTE, "UI_LoadProgs: can't init menu API\n" ); + Mem_FreePool( &menu.mempool ); + menu.hInstance = NULL; + return false; + } + + menu.use_text_api = false; + + if( ( GiveTextApi = (UITEXTAPI)Com_GetProcAddress( menu.hInstance, "GiveTextAPI" ) ) ) + { + // make local copy of engfuncs to prevent overwrite it with user dll + Q_memcpy( &gpTextfuncs, &gTextfuncs, sizeof( gpTextfuncs )); + if( GiveTextApi( &gpTextfuncs ) ) + menu.use_text_api = true; + } + + pfnAddTouchButtonToList = (ADDTOUCHBUTTONTOLIST)Com_GetProcAddress( menu.hInstance, "AddTouchButtonToList" ); + + // setup gameinfo + for( i = 0; i < SI.numgames; i++ ) + { + menu.modsInfo[i] = Mem_Alloc( menu.mempool, sizeof( GAMEINFO )); + UI_ConvertGameInfo( menu.modsInfo[i], SI.games[i] ); + } + + UI_ConvertGameInfo( &menu.gameInfo, SI.GameInfo ); // current gameinfo + + // setup globals + menu.globals->developer = host.developer; + + // initialize game + menu.dllFuncs.pfnInit(); + + return true; +} +#endif // XASH_DEDICATED diff --git a/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_mobile.c b/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_mobile.c new file mode 100644 index 0000000..8e9634a --- /dev/null +++ b/Projects/Android/jni/src/Xash3D/xash3d/engine/client/cl_mobile.c @@ -0,0 +1,151 @@ +/* +cl_mobile.c - common mobile interface +Copyright (C) 2015 a1batross + +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 3 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. +*/ + +#ifndef XASH_DEDICATED + +#include "common.h" +#include "client.h" +#include "mobility_int.h" +#include "library.h" +#include "gl_local.h" +#include "touch.h" + +#if defined(__ANDROID__) +#include "platform/android/android-main.h" +#endif + +mobile_engfuncs_t *gMobileEngfuncs; + +convar_t *vibration_length; +convar_t *vibration_enable; + +static void pfnVibrate( float life, char flags ) +{ + if( !vibration_enable->integer ) + return; + + if( life < 0.0f ) + { + MsgDev( D_WARN, "Negative vibrate time: %f\n", life ); + return; + } + + //MsgDev( D_NOTE, "Vibrate: %f %d\n", life, flags ); + + // here goes platform-specific backends +#ifdef __ANDROID__ + Android_Vibrate( life * vibration_length->value, flags ); +#endif +} + +static void Vibrate_f() +{ + if( Cmd_Argc() != 2 ) + { + Msg( "Usage: vibrate