diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7960ca3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,396 @@ +The Yamagi Quake II Vulkan renderer lib is based upon vkQuake2 and +ontains software developed by multiple individuals, projects and +organisations. Following is a list of this software and copys of each +license: + +- Quake II +- stb_image.h, stb_image_write.h + +=============================================================================== + + 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. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 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. + + , 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. + +=============================================================================== + + stb single-file public domain libraries + (stb_image.h, stb_image_resize.h) + https://github.com/nothings/stb/ + Dual-Licensed: Public Domain (Unlicense) or MIT License: + +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +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. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +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 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. + +=============================================================================== diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d528a5a --- /dev/null +++ b/Makefile @@ -0,0 +1,362 @@ +# ----------------------------------------------------- # +# Makefile for the Vulkan renderer lib for Quake II # +# # +# Just type "make" to compile the # +# - Vulkan renderer lib (ref_vk.so / rev_vk.dll) # +# # +# Dependencies: # +# - SDL2 # +# - Vulkan headers # +# # +# Platforms: # +# - FreeBSD # +# - Linux # +# - Mac OS X # +# - OpenBSD # +# - Windows # +# ----------------------------------------------------- # + +# Detect the OS +ifdef SystemRoot +YQ2_OSTYPE ?= Windows +else +YQ2_OSTYPE ?= $(shell uname -s) +endif + +# Special case for MinGW +ifneq (,$(findstring MINGW,$(YQ2_OSTYPE))) +YQ2_OSTYPE := Windows +endif + +# Detect the architecture +ifeq ($(YQ2_OSTYPE), Windows) +ifdef MINGW_CHOST +ifeq ($(MINGW_CHOST), x86_64-w64-mingw32) +YQ2_ARCH ?= x86_64 +else # i686-w64-mingw32 +YQ2_ARCH ?= i386 +endif +else # windows, but MINGW_CHOST not defined +ifdef PROCESSOR_ARCHITEW6432 +# 64 bit Windows +YQ2_ARCH ?= $(PROCESSOR_ARCHITEW6432) +else +# 32 bit Windows +YQ2_ARCH ?= $(PROCESSOR_ARCHITECTURE) +endif +endif # windows but MINGW_CHOST not defined +else +# Normalize some abiguous YQ2_ARCH strings +YQ2_ARCH ?= $(shell uname -m | sed -e 's/i.86/i386/' -e 's/amd64/x86_64/' -e 's/^arm.*/arm/') +endif + +# On Windows / MinGW $(CC) is undefined by default. +ifeq ($(YQ2_OSTYPE),Windows) +CC ?= gcc +endif + +# Detect the compiler +ifeq ($(shell $(CC) -v 2>&1 | grep -c "clang version"), 1) +COMPILER := clang +COMPILERVER := $(shell $(CC) -dumpversion | sed -e 's/\.\([0-9][0-9]\)/\1/g' -e 's/\.\([0-9]\)/0\1/g' -e 's/^[0-9]\{3,4\}$$/&00/') +else ifeq ($(shell $(CC) -v 2>&1 | grep -c -E "(gcc version|gcc-Version)"), 1) +COMPILER := gcc +COMPILERVER := $(shell $(CC) -dumpversion | sed -e 's/\.\([0-9][0-9]\)/\1/g' -e 's/\.\([0-9]\)/0\1/g' -e 's/^[0-9]\{3,4\}$$/&00/') +else +COMPILER := unknown +endif + +# ASAN includes DEBUG +ifdef ASAN +DEBUG=1 +endif + +# UBSAN includes DEBUG +ifdef UBSAN +DEBUG=1 +endif + +# ---------- + +# Base CFLAGS. These may be overridden by the environment. +# Highest supported optimizations are -O2, higher levels +# will likely break this crappy code. +ifdef DEBUG +CFLAGS ?= -O0 -g -Wall -pipe +ifdef ASAN +CFLAGS += -fsanitize=address +endif +ifdef UBSAN +CFLAGS += -fsanitize=undefined +endif +else +CFLAGS ?= -O2 -Wall -pipe -fomit-frame-pointer +endif + +# Always needed are: +# -fno-strict-aliasing since the source doesn't comply +# with strict aliasing rules and it's next to impossible +# to get it there... +# -fwrapv for defined integer wrapping. MSVC6 did this +# and the game code requires it. +# -fvisibility=hidden to keep symbols hidden. This is +# mostly best practice and not really necessary. +override CFLAGS += -std=gnu99 -fno-strict-aliasing -fwrapv -fvisibility=hidden + +# -MMD to generate header dependencies. Unsupported by +# the Clang shipped with OS X. +ifneq ($(YQ2_OSTYPE), Darwin) +override CFLAGS += -MMD +endif + +# OS X architecture. +ifeq ($(YQ2_OSTYPE), Darwin) +override CFLAGS += -arch $(YQ2_ARCH) +endif + +# ---------- + +# Switch of some annoying warnings. +ifeq ($(COMPILER), clang) + # -Wno-missing-braces because otherwise clang complains + # about totally valid 'vec3_t bla = {0}' constructs. + CFLAGS += -Wno-missing-braces +else ifeq ($(COMPILER), gcc) + # GCC 8.0 or higher. + ifeq ($(shell test $(COMPILERVER) -ge 80000; echo $$?),0) + # -Wno-format-truncation and -Wno-format-overflow + # because GCC spams about 50 false positives. + CFLAGS += -Wno-format-truncation -Wno-format-overflow + endif +endif + +# ---------- + +# Defines the operating system and architecture +override CFLAGS += -DYQ2OSTYPE=\"$(YQ2_OSTYPE)\" -DYQ2ARCH=\"$(YQ2_ARCH)\" + +# ---------- + +# For reproduceable builds, look here for details: +# https://reproducible-builds.org/specs/source-date-epoch/ +ifdef SOURCE_DATE_EPOCH +CFLAGS += -DBUILD_DATE=\"$(shell date --utc --date="@${SOURCE_DATE_EPOCH}" +"%b %_d %Y" | sed -e 's/ /\\ /g')\" +endif + +# ---------- + +# Using the default x87 float math on 32bit x86 causes rounding trouble +# -ffloat-store could work around that, but the better solution is to +# just enforce SSE - every x86 CPU since Pentium3 supports that +# and this should even improve the performance on old CPUs +ifeq ($(YQ2_ARCH), i386) +override CFLAGS += -msse -mfpmath=sse +endif + +# Force SSE math on x86_64. All sane compilers should do this +# anyway, just to protect us from broken Linux distros. +ifeq ($(YQ2_ARCH), x86_64) +override CFLAGS += -mfpmath=sse +endif + +# ---------- + +# Extra CFLAGS for SDL. +SDLCFLAGS := $(shell sdl2-config --cflags) + +# ---------- + +# Base include path. +ifeq ($(YQ2_OSTYPE),Linux) +INCLUDE ?= -I/usr/include +else ifeq ($(YQ2_OSTYPE),FreeBSD) +INCLUDE ?= -I/usr/local/include +else ifeq ($(YQ2_OSTYPE),NetBSD) +INCLUDE ?= -I/usr/X11R7/include -I/usr/pkg/include +else ifeq ($(YQ2_OSTYPE),OpenBSD) +INCLUDE ?= -I/usr/local/include +else ifeq ($(YQ2_OSTYPE),Windows) +INCLUDE ?= -I/usr/include +endif + +# ---------- + +# Base LDFLAGS. This is just the library path. +ifeq ($(YQ2_OSTYPE),Linux) +LDFLAGS ?= -L/usr/lib +else ifeq ($(YQ2_OSTYPE),FreeBSD) +LDFLAGS ?= -L/usr/local/lib +else ifeq ($(YQ2_OSTYPE),NetBSD) +LDFLAGS ?= -L/usr/X11R7/lib -Wl,-R/usr/X11R7/lib -L/usr/pkg/lib -Wl,-R/usr/pkg/lib +else ifeq ($(YQ2_OSTYPE),OpenBSD) +LDFLAGS ?= -L/usr/local/lib +else ifeq ($(YQ2_OSTYPE),Windows) +LDFLAGS ?= -L/usr/lib +endif + +# Link address sanitizer if requested. +ifdef ASAN +LDFLAGS += -fsanitize=address +endif + +# Link undefined behavior sanitizer if requested. +ifdef UBSAN +LDFLAGS += -fsanitize=undefined +endif + +# Required libraries. +ifeq ($(YQ2_OSTYPE),Linux) +override LDFLAGS += -lm -ldl -rdynamic +else ifeq ($(YQ2_OSTYPE),FreeBSD) +override LDFLAGS += -lm +else ifeq ($(YQ2_OSTYPE),NetBSD) +override LDFLAGS += -lm +else ifeq ($(YQ2_OSTYPE),OpenBSD) +override LDFLAGS += -lm +else ifeq ($(YQ2_OSTYPE),Windows) +override LDFLAGS += -lws2_32 -lwinmm -static-libgcc +else ifeq ($(YQ2_OSTYPE), Darwin) +override LDFLAGS += -arch $(YQ2_ARCH) +else ifeq ($(YQ2_OSTYPE), Haiku) +override LDFLAGS += -lm +endif + +ifneq ($(YQ2_OSTYPE), Darwin) +ifneq ($(YQ2_OSTYPE), OpenBSD) +# For some reason the OSX & OpenBSD +# linker doesn't support this... +override LDFLAGS += -Wl,--no-undefined +endif +endif + +# It's a shared library. +override LDFLAGS += -shared + +# ---------- + +# Extra LDFLAGS for SDL +ifeq ($(YQ2_OSTYPE), Darwin) +SDLLDFLAGS := -lSDL2 +else # not Darwin +SDLLDFLAGS := $(shell sdl2-config --libs) +endif # Darwin + +# The renderer libs don't need libSDL2main, libmingw32 or -mwindows. +ifeq ($(YQ2_OSTYPE), Windows) +DLL_SDLLDFLAGS = $(subst -mwindows,,$(subst -lmingw32,,$(subst -lSDL2main,,$(SDLLDFLAGS)))) +endif + +# ---------- +# When make is invoked by "make VERBOSE=1" print +# the compiler and linker commands. + +ifdef VERBOSE +Q := +else +Q := @ +endif + +# ---------- + +# Phony targets +.PHONY : all clean xatrix + +# ---------- + +# Builds everything +all: ref_vk + +# ---------- + +# Cleanup +clean: + @echo "===> CLEAN" + ${Q}rm -Rf build release + +# ---------- + +ifeq ($(YQ2_OSTYPE), Windows) +ref_vk: + @echo "===> Building ref_vk.dll" + ${Q}mkdir -p release + $(MAKE) release/ref_vk.dll +else +ref_vk: + @echo "===> Building ref_vk.so" + ${Q}mkdir -p release + $(MAKE) release/ref_vk.so + +release/ref_vk.so : CFLAGS += -fPIC +endif + +build/%.o: %.c + @echo "===> CC $<" + ${Q}mkdir -p $(@D) + ${Q}$(CC) -c $(CFLAGS) $(SDLCFLAGS) $(INCLUDE) -o $@ $< + +# ---------- + +REFVK_OBJS_ := \ + src/vk/vk_buffer.o \ + src/vk/vk_cmd.o \ + src/vk/vk_common.o \ + src/vk/vk_device.o \ + src/vk/vk_draw.o \ + src/vk/vk_image.o \ + src/vk/vk_light.o \ + src/vk/vk_mesh.o \ + src/vk/vk_model.o \ + src/vk/vk_pipeline.o \ + src/vk/vk_rmain.o \ + src/vk/vk_rmisc.o \ + src/vk/vk_rsurf.o \ + src/vk/vk_shaders.o \ + src/vk/vk_swapchain.o \ + src/vk/vk_validation.o \ + src/vk/vk_warp.o \ + src/vk/vk_util.o \ + src/vk/volk/volk.o \ + src/files/pcx.o \ + src/files/stb.o \ + src/files/wal.o \ + src/files/pvs.o \ + src/common/shared.o \ + src/common/md4.o + +ifeq ($(YQ2_OSTYPE), Windows) +REFVK_OBJS_ += \ + src/backends/hunk_windows.o +else # not Windows +REFVK_OBJS_ += \ + src/backends/hunk_unix.o +endif + +# ---------- + +# Rewrite pathes to our object directory +REFVK_OBJS = $(patsubst %,build/%,$(REFVK_OBJS_)) + +# ---------- + +# Generate header dependencies +REFVK_DEPS= $(REFVK_OBJS:.o=.d) + +# ---------- + +# Suck header dependencies in +-include $(REFVK_DEPS) + +# ---------- + +# release/ref_vk.so +ifeq ($(YQ2_OSTYPE), Windows) +release/ref_vk.dll : $(REFVK_OBJS) + @echo "===> LD $@" + ${Q}$(CC) $(REFVK_OBJS) $(LDFLAGS) $(DLL_SDLLDFLAGS) -o $@ +else +release/ref_vk.so : $(REFVK_OBJS) + @echo "===> LD $@" + ${Q}$(CC) $(REFVK_OBJS) $(LDFLAGS) $(SDLLDFLAGS) -o $@ +endif + +# ---------- diff --git a/README.md b/README.md new file mode 100644 index 0000000..d989a09 --- /dev/null +++ b/README.md @@ -0,0 +1,111 @@ +# Vulkan Renderer Library for Yamagi Quake II + +This is the vkQuake2 vulkan renderer library ported to Yamagi Quake II. + + +## Compilation + +You'll need: +* clang or gcc +* GNU Make +* SDL2 with `sdl2-config`. +* vulkan-headers. + +Type `make` to compile the library. If the compilation is successfull, +the library can be found under *release/ref_vk.dll* (Windows) or +*release/ref_vk.so* (unixoid systems). + + +## Usage + +Copy the library next to your Yamagi Quake II executable. You can select +Vulkan through the video menu or by cvar with `vid_renderer vk` followed +by a `vid_restart`. + + +## Console Variables + +* **vk_validation**: Toggle validation layers: + * `0` - disabled (default in Release) + * `1` - only errors and warnings + * `2` - best-practices validation + +* **vk_strings**: Print some basic Vulkan/GPU information. + +* **vk_mem**: Print dynamic vertex/index/uniform/triangle fan buffer + memory usage statistics. + +* **vk_device**: Specify index of the preferred Vulkan device on systems + with multiple GPUs: + * `-1` - prefer first DISCRETE\_GPU (default) + * `0..n` - use device #n (full list of devices is returned by + `vk_strings` command) + +* **vk_sampleshading**: Toggle sample shading for MSAA. (default: `1`) + +* **vk_flashblend**: Toggle the blending of lights onto the environment. + (default: `0`) + +* **vk_polyblend**: Blend fullscreen effects: blood, powerups etc. + (default: `1`) + +* **vk_skymip**: Toggle the usage of mipmap information for the sky + graphics. (default: `0`) + +* **vk_finish**: Inserts a `vkDeviceWaitIdle()` call on frame render + start (default: `0`). Don't use this, it's there just for the sake of + having a `gl_finish` equivalent! + +* **vk_custom_particles**: Toggle particles type: + * `0` - textured triangles for particle rendering + * `1` - between using POINT\_LIST (default) + * `2` - textured square for particle rendering + +* **vk_particle_size**: Rendered particle size. (default: `40`) + +* **vk_particle_att_a**: Intensity of the particle A attribute. + (default: `0.01`) + +* **vk_particle_att_b**: Intensity of the particle B attribute. + (default: `0`) + +* **vk_particle_att_c**: Intensity of the particle C attribute. + (default: `0.01`) + +* **vk_particle_min_size**: The minimum size of a rendered particle. + (default: `2`) + +* **vk_particle_max_size**: The maximum size of a rendered particle. + (default: `40`) + +* **vk_picmip**: Shrink factor for the textures. (default: `0`) + +* **vk_pixel_size**: Pixel size when rendering the world, used to simulate + lower screen resolutions. The value represents the length, in pixels, of the + side of each pixel block. For example, with size 2 pixels are 2x2 squares, + and at 1600x1200 the image is effectively an upscaled 800x600 image. + (default: `1`) + +* **vk_dynamic**: Use dynamic lighting. (default: `1`) + +* **vk_showtris**: Display mesh triangles. (default: `0`) + +* **vk_lightmap**: Display lightmaps. (default: `0`) + +* **vk_postprocess**: Toggle additional color/gamma correction. + (default: `1`) + +* **vk_mip_nearfilter**: Use nearest-neighbor filtering for mipmaps. + (default: `0`) + +* **vk_texturemode**: Change current texture filtering mode: + * `VK_NEAREST` - nearest-neighbor interpolation, no mipmaps + * `VK_LINEAR` - linear interpolation, no mipmaps + * `VK_MIPMAP_NEAREST` - nearest-neighbor interpolation with mipmaps + * `VK_MIPMAP_LINEAR` - linear interpolation with mipmaps (default) + +* **vk_lmaptexturemode**: Same as `vk_texturemode` but applied to + lightmap textures. + +* **vk_underwater**: Warp the scene if underwater. Set to `0` to disable + the effect. Defaults to `1`. diff --git a/shaders/basic.frag b/shaders/basic.frag new file mode 100644 index 0000000..0c73c4e --- /dev/null +++ b/shaders/basic.frag @@ -0,0 +1,24 @@ +#version 450 + +layout(push_constant) uniform PushConstant +{ + // vertex shader has 'mat4 vpMatrix;' at begin. + layout(offset = 68) float gamma; +} pc; + +layout(set = 0, binding = 0) uniform sampler2D sTexture; + +layout(location = 0) in vec2 texCoord; +layout(location = 1) in vec4 color; +layout(location = 2) in float aTreshold; + +layout(location = 0) out vec4 fragmentColor; + +void main() +{ + fragmentColor = texture(sTexture, texCoord) * color; + if(fragmentColor.a < aTreshold) + discard; + + fragmentColor = vec4(pow(fragmentColor.rgb, vec3(pc.gamma)), fragmentColor.a); +} diff --git a/shaders/basic.vert b/shaders/basic.vert new file mode 100644 index 0000000..4208399 --- /dev/null +++ b/shaders/basic.vert @@ -0,0 +1,30 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +// normalized offset and scale +layout(set = 1, binding = 0) uniform imageTransform +{ + vec2 offset; + vec2 scale; + vec2 uvOffset; + vec2 uvScale; +} it; + +layout(location = 0) in vec2 inVertex; +layout(location = 1) in vec2 inTexCoord; + +layout(location = 0) out vec2 texCoord; +layout(location = 1) out vec4 color; +layout(location = 2) out float aTreshold; + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main() { + vec2 vPos = inVertex.xy * it.scale - (vec2(1.0) - it.scale); + gl_Position = vec4(vPos + it.offset * 2.0, 0.0, 1.0); + texCoord = inTexCoord.xy * it.uvScale + it.uvOffset; + color = vec4(1.0, 1.0, 1.0, 1.0); + aTreshold = 0.666; +} diff --git a/shaders/basic_color_quad.frag b/shaders/basic_color_quad.frag new file mode 100644 index 0000000..aec28c4 --- /dev/null +++ b/shaders/basic_color_quad.frag @@ -0,0 +1,10 @@ +#version 450 + +layout(location = 0) in vec4 color; + +layout(location = 0) out vec4 fragmentColor; + +void main() +{ + fragmentColor = color; +} diff --git a/shaders/basic_color_quad.vert b/shaders/basic_color_quad.vert new file mode 100644 index 0000000..dd4b67b --- /dev/null +++ b/shaders/basic_color_quad.vert @@ -0,0 +1,24 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +// normalized offset and scale +layout(set = 0, binding = 0) uniform imageTransform +{ + vec2 offset; + vec2 scale; + vec4 color; +} it; + +layout(location = 0) in vec2 inVertex; + +layout(location = 0) out vec4 color; + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main() { + vec2 vPos = inVertex.xy * it.scale - (vec2(1.0) - it.scale); + gl_Position = vec4(vPos + it.offset * 2.0, 0.0, 1.0); + color = it.color; +} diff --git a/shaders/beam.vert b/shaders/beam.vert new file mode 100644 index 0000000..5d107bf --- /dev/null +++ b/shaders/beam.vert @@ -0,0 +1,25 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 inVertex; + +layout(push_constant) uniform PushConstant +{ + mat4 mvpMatrix; +} pc; + +layout(binding = 0) uniform UniformBufferObject +{ + vec4 color; +} ubo; + +layout(location = 0) out vec4 color; + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main() { + gl_Position = pc.mvpMatrix * vec4(inVertex, 1.0); + color = ubo.color; +} diff --git a/shaders/d_light.vert b/shaders/d_light.vert new file mode 100644 index 0000000..cda70b4 --- /dev/null +++ b/shaders/d_light.vert @@ -0,0 +1,21 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 inVertex; +layout(location = 1) in vec3 inColor; + +layout(binding = 0) uniform UniformBufferObject +{ + mat4 mvpMatrix; +} ubo; + +layout(location = 0) out vec4 color; + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main() { + gl_Position = ubo.mvpMatrix * vec4(inVertex, 1.0); + color = vec4(inColor, 1.0); +} diff --git a/shaders/model.frag b/shaders/model.frag new file mode 100644 index 0000000..1133244 --- /dev/null +++ b/shaders/model.frag @@ -0,0 +1,17 @@ +#version 450 + +layout(set = 0, binding = 0) uniform sampler2D sTexture; + +layout(location = 0) in vec4 color; +layout(location = 1) in vec2 texCoord; +layout(location = 2) in flat int textured; + +layout(location = 0) out vec4 fragmentColor; + +void main() +{ + if(textured != 0) + fragmentColor = texture(sTexture, texCoord) * clamp(color, 0.0, 1.0); + else + fragmentColor = color; +} diff --git a/shaders/model.vert b/shaders/model.vert new file mode 100644 index 0000000..f728e25 --- /dev/null +++ b/shaders/model.vert @@ -0,0 +1,32 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 inVertex; +layout(location = 1) in vec4 inColor; +layout(location = 2) in vec2 inTexCoord; + +layout(push_constant) uniform PushConstant +{ + mat4 vpMatrix; +} pc; + +layout(set = 1, binding = 0) uniform UniformBufferObject +{ + mat4 model; + int textured; +} ubo; + +layout(location = 0) out vec4 color; +layout(location = 1) out vec2 texCoord; +layout(location = 2) out int textured; + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main() { + gl_Position = pc.vpMatrix * ubo.model * vec4(inVertex, 1.0); + color = inColor; + texCoord = inTexCoord; + textured = ubo.textured; +} diff --git a/shaders/nullmodel.vert b/shaders/nullmodel.vert new file mode 100644 index 0000000..ca69677 --- /dev/null +++ b/shaders/nullmodel.vert @@ -0,0 +1,26 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 inVertex; +layout(location = 1) in vec3 inColor; + +layout(push_constant) uniform PushConstant +{ + mat4 vpMatrix; +} pc; + +layout(binding = 0) uniform UniformBufferObject +{ + mat4 model; +} ubo; + +layout(location = 0) out vec4 color; + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main() { + gl_Position = pc.vpMatrix * ubo.model * vec4(inVertex, 1.0); + color = vec4(inColor, 1.0); +} diff --git a/shaders/particle.vert b/shaders/particle.vert new file mode 100644 index 0000000..40fd674 --- /dev/null +++ b/shaders/particle.vert @@ -0,0 +1,26 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 inVertex; +layout(location = 1) in vec4 inColor; +layout(location = 2) in vec2 inTexCoord; + +layout(push_constant) uniform PushConstant +{ + mat4 mvpMatrix; +} pc; + +layout(location = 0) out vec2 texCoord; +layout(location = 1) out vec4 color; +layout(location = 2) out float aTreshold; + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main() { + gl_Position = pc.mvpMatrix * vec4(inVertex, 1.0); + texCoord = inTexCoord; + color = inColor; + aTreshold = 0.5; +} diff --git a/shaders/point_particle.frag b/shaders/point_particle.frag new file mode 100644 index 0000000..f47c881 --- /dev/null +++ b/shaders/point_particle.frag @@ -0,0 +1,14 @@ +#version 450 + +layout(location = 0) in vec4 color; + +layout(location = 0) out vec4 fragmentColor; + +void main() +{ + vec2 cxy = 2.0 * gl_PointCoord - 1.0; + if(dot(cxy, cxy) > 1.0) + discard; + + fragmentColor = color; +} diff --git a/shaders/point_particle.vert b/shaders/point_particle.vert new file mode 100644 index 0000000..ab40744 --- /dev/null +++ b/shaders/point_particle.vert @@ -0,0 +1,37 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 inVertex; +layout(location = 1) in vec4 inColor; + +layout(push_constant) uniform PushConstant +{ + mat4 mvpMatrix; +} pc; + +layout(binding = 0) uniform UniformBufferObject +{ + float pointSize; + float pointScale; + float minPointSize; + float maxPointSize; + float att_a; + float att_b; + float att_c; +} ubo; + +layout(location = 0) out vec4 color; + +out gl_PerVertex { + vec4 gl_Position; + float gl_PointSize; +}; + +void main() { + gl_Position = pc.mvpMatrix * vec4(inVertex, 1.0); + + float dist_atten = ubo.pointScale / (ubo.att_a + ubo.att_b * gl_Position.w + ubo.att_c * gl_Position.w * gl_Position.w); + gl_PointSize = clamp(ubo.pointScale * ubo.pointSize * sqrt(dist_atten), ubo.minPointSize, ubo.maxPointSize); + + color = inColor; +} diff --git a/shaders/polygon.vert b/shaders/polygon.vert new file mode 100644 index 0000000..120a52f --- /dev/null +++ b/shaders/polygon.vert @@ -0,0 +1,30 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 inVertex; +layout(location = 1) in vec2 inTexCoord; + +layout(push_constant) uniform PushConstant +{ + mat4 mvpMatrix; +} pc; + +layout(set = 1, binding = 0) uniform UniformBufferObject +{ + vec4 color; +} ubo; + +layout(location = 0) out vec2 texCoord; +layout(location = 1) out vec4 color; +layout(location = 2) out float aTreshold; + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main() { + gl_Position = pc.mvpMatrix * vec4(inVertex, 1.0); + texCoord = inTexCoord; + color = ubo.color; + aTreshold = 0.0; +} diff --git a/shaders/polygon_lmap.frag b/shaders/polygon_lmap.frag new file mode 100644 index 0000000..cd43691 --- /dev/null +++ b/shaders/polygon_lmap.frag @@ -0,0 +1,17 @@ +#version 450 + +layout(set = 0, binding = 0) uniform sampler2D sTexture; +layout(set = 2, binding = 0) uniform sampler2D sLightmap; + +layout(location = 0) in vec2 texCoord; +layout(location = 1) in vec2 texCoordLmap; +layout(location = 2) in float viewLightmaps; + +layout(location = 0) out vec4 fragmentColor; + +void main() +{ + vec4 color = texture(sTexture, texCoord); + vec4 light = texture(sLightmap, texCoordLmap); + fragmentColor = (1.0 - viewLightmaps) * color * light + viewLightmaps * light; +} diff --git a/shaders/polygon_lmap.vert b/shaders/polygon_lmap.vert new file mode 100644 index 0000000..88882e5 --- /dev/null +++ b/shaders/polygon_lmap.vert @@ -0,0 +1,32 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 inVertex; +layout(location = 1) in vec2 inTexCoord; +layout(location = 2) in vec2 inTexCoordLmap; + +layout(push_constant) uniform PushConstant +{ + mat4 vpMatrix; +} pc; + +layout(set = 1, binding = 0) uniform UniformBufferObject +{ + mat4 model; + float viewLightmaps; +} ubo; + +layout(location = 0) out vec2 texCoord; +layout(location = 1) out vec2 texCoordLmap; +layout(location = 2) out float viewLightmaps; + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main() { + gl_Position = pc.vpMatrix * ubo.model * vec4(inVertex, 1.0); + texCoord = inTexCoord; + texCoordLmap = inTexCoordLmap; + viewLightmaps = ubo.viewLightmaps; +} diff --git a/shaders/polygon_warp.vert b/shaders/polygon_warp.vert new file mode 100644 index 0000000..609a2c0 --- /dev/null +++ b/shaders/polygon_warp.vert @@ -0,0 +1,34 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 inVertex; +layout(location = 1) in vec2 inTexCoord; + +layout(push_constant) uniform PushConstant +{ + mat4 vpMatrix; +} pc; + +layout(set = 1, binding = 0) uniform UniformBufferObject +{ + mat4 model; + vec4 color; + float time; + float scroll; +} ubo; + +layout(location = 0) out vec2 texCoord; +layout(location = 1) out vec4 color; +layout(location = 2) out float aTreshold; + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main() { + gl_Position = pc.vpMatrix * ubo.model * vec4(inVertex, 1.0); + texCoord = inTexCoord + vec2(sin(2.0 * ubo.time + inTexCoord.y * 3.28), sin(2.0 * ubo.time + inTexCoord.x * 3.28)) * 0.05; + texCoord.x += ubo.scroll; + color = ubo.color; + aTreshold = 0.0; +} diff --git a/shaders/postprocess.frag b/shaders/postprocess.frag new file mode 100644 index 0000000..879b555 --- /dev/null +++ b/shaders/postprocess.frag @@ -0,0 +1,33 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(push_constant) uniform PushConstant +{ + layout(offset = 68) float postprocess; + layout(offset = 72) float gamma; + layout(offset = 76) float scrWidth; + layout(offset = 80) float scrHeight; + layout(offset = 84) float offsetX; + layout(offset = 88) float offsetY; +} pc; + +layout(set = 0, binding = 0) uniform sampler2D sTexture; + +layout(location = 0) in vec2 texCoord; +layout(location = 0) out vec4 fragmentColor; + +void main() +{ + vec2 unnormTexCoord = texCoord * vec2(pc.scrWidth, pc.scrHeight) + vec2(pc.offsetX, pc.offsetY); + + // apply any additional world-only postprocessing effects here (if enabled) + if (pc.postprocess > 0.0) + { + //gamma + color intensity bump + fragmentColor = vec4(pow(textureLod(sTexture, unnormTexCoord, 0.0).rgb * 1.5, vec3(pc.gamma)), 1.0); + } + else + { + fragmentColor = textureLod(sTexture, unnormTexCoord, 0.0); + } +} diff --git a/shaders/postprocess.vert b/shaders/postprocess.vert new file mode 100644 index 0000000..438e62e --- /dev/null +++ b/shaders/postprocess.vert @@ -0,0 +1,17 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +// rendering a fullscreen quad (which is actually just a huge triangle) +// source: https://www.saschawillems.de/blog/2016/08/13/vulkan-tutorial-on-rendering-a-fullscreen-quad-without-buffers/ + +out gl_PerVertex { + vec4 gl_Position; +}; + +layout(location = 0) out vec2 texCoord; + +void main() +{ + texCoord = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); + gl_Position = vec4(texCoord * 2.0f + -1.0f, 0.0f, 1.0f); +} diff --git a/shaders/shaders.sh b/shaders/shaders.sh new file mode 100755 index 0000000..cebfced --- /dev/null +++ b/shaders/shaders.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +glslangValidator --variable-name basic_vert_spv -V basic.vert -o ../src/vk/spirv/basic_vert.c +glslangValidator --variable-name basic_frag_spv -V basic.frag -o ../src/vk/spirv/basic_frag.c +glslangValidator --variable-name basic_color_quad_vert_spv -V basic_color_quad.vert -o ../src/vk/spirv/basic_color_quad_vert.c +glslangValidator --variable-name basic_color_quad_frag_spv -V basic_color_quad.frag -o ../src/vk/spirv/basic_color_quad_frag.c +glslangValidator --variable-name model_vert_spv -V model.vert -o ../src/vk/spirv/model_vert.c +glslangValidator --variable-name model_frag_spv -V model.frag -o ../src/vk/spirv/model_frag.c +glslangValidator --variable-name nullmodel_vert_spv -V nullmodel.vert -o ../src/vk/spirv/nullmodel_vert.c +glslangValidator --variable-name particle_vert_spv -V particle.vert -o ../src/vk/spirv/particle_vert.c +glslangValidator --variable-name point_particle_vert_spv -V point_particle.vert -o ../src/vk/spirv/point_particle_vert.c +glslangValidator --variable-name point_particle_frag_spv -V point_particle.frag -o ../src/vk/spirv/point_particle_frag.c +glslangValidator --variable-name sprite_vert_spv -V sprite.vert -o ../src/vk/spirv/sprite_vert.c +glslangValidator --variable-name beam_vert_spv -V beam.vert -o ../src/vk/spirv/beam_vert.c +glslangValidator --variable-name skybox_vert_spv -V skybox.vert -o ../src/vk/spirv/skybox_vert.c +glslangValidator --variable-name d_light_vert_spv -V d_light.vert -o ../src/vk/spirv/d_light_vert.c +glslangValidator --variable-name polygon_vert_spv -V polygon.vert -o ../src/vk/spirv/polygon_vert.c +glslangValidator --variable-name polygon_lmap_vert_spv -V polygon_lmap.vert -o ../src/vk/spirv/polygon_lmap_vert.c +glslangValidator --variable-name polygon_lmap_frag_spv -V polygon_lmap.frag -o ../src/vk/spirv/polygon_lmap_frag.c +glslangValidator --variable-name polygon_warp_vert_spv -V polygon_warp.vert -o ../src/vk/spirv/polygon_warp_vert.c +glslangValidator --variable-name shadows_vert_spv -V shadows.vert -o ../src/vk/spirv/shadows_vert.c +glslangValidator --variable-name postprocess_vert_spv -V postprocess.vert -o ../src/vk/spirv/postprocess_vert.c +glslangValidator --variable-name postprocess_frag_spv -V postprocess.frag -o ../src/vk/spirv/postprocess_frag.c +glslangValidator --variable-name world_warp_vert_spv -V world_warp.vert -o ../src/vk/spirv/world_warp_vert.c +glslangValidator --variable-name world_warp_frag_spv -V world_warp.frag -o ../src/vk/spirv/world_warp_frag.c diff --git a/shaders/shadows.vert b/shaders/shadows.vert new file mode 100644 index 0000000..24fbae9 --- /dev/null +++ b/shaders/shadows.vert @@ -0,0 +1,24 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 inVertex; +layout(location = 0) out vec4 color; + +layout(push_constant) uniform PushConstant +{ + mat4 vpMatrix; +} pc; + +layout(binding = 0) uniform UniformBufferObject +{ + mat4 model; +} ubo; + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main() { + gl_Position = pc.vpMatrix * ubo.model * vec4(inVertex, 1.0); + color = vec4(0.0, 0.0, 0.0, 0.5); +} diff --git a/shaders/skybox.vert b/shaders/skybox.vert new file mode 100644 index 0000000..348777c --- /dev/null +++ b/shaders/skybox.vert @@ -0,0 +1,30 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 inVertex; +layout(location = 1) in vec2 inTexCoord; + +layout(push_constant) uniform PushConstant +{ + mat4 vpMatrix; +} pc; + +layout(set = 1, binding = 0) uniform UniformBufferObject +{ + mat4 model; +} ubo; + +layout(location = 0) out vec2 texCoord; +layout(location = 1) out vec4 color; +layout(location = 2) out float aTreshold; + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main() { + gl_Position = pc.vpMatrix * ubo.model * vec4(inVertex, 1.0); + texCoord = inTexCoord; + color = vec4(1.0, 1.0, 1.0, 1.0); + aTreshold = 0.0; +} diff --git a/shaders/sprite.vert b/shaders/sprite.vert new file mode 100644 index 0000000..f42a66c --- /dev/null +++ b/shaders/sprite.vert @@ -0,0 +1,26 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 inVertex; +layout(location = 1) in vec2 inTexCoord; + +layout(push_constant) uniform PushConstant +{ + mat4 mvpMatrix; + float alpha; +} pc; + +layout(location = 0) out vec2 texCoord; +layout(location = 1) out vec4 color; +layout(location = 2) out float aTreshold; + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main() { + gl_Position = pc.mvpMatrix * vec4(inVertex, 1.0); + texCoord = inTexCoord; + color = vec4(1.0, 1.0, 1.0, pc.alpha); + aTreshold = 0.0666; +} diff --git a/shaders/world_warp.frag b/shaders/world_warp.frag new file mode 100644 index 0000000..cbbeea1 --- /dev/null +++ b/shaders/world_warp.frag @@ -0,0 +1,55 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +// Underwater screen warp effect similar to what software renderer provides. +// Pixel size to simulate lower screen resolutions is used to restore world to full screen size. + +layout(push_constant) uniform PushConstant +{ + layout(offset = 68) float time; + layout(offset = 72) float scale; + layout(offset = 76) float scrWidth; + layout(offset = 80) float scrHeight; + layout(offset = 84) float offsetX; + layout(offset = 88) float offsetY; + layout(offset = 92) float pixelSize; + layout(offset = 96) float refdefX; + layout(offset = 100) float refdefY; + layout(offset = 104) float refdefWidth; + layout(offset = 108) float refdefHeight; +} pc; + +layout(set = 0, binding = 0) uniform sampler2D sTexture; + +layout(location = 0) out vec4 fragmentColor; + +#define PI 3.1415 + +void main() +{ + vec2 scrSize = vec2(pc.scrWidth, pc.scrHeight); + vec2 fragCoord = (gl_FragCoord.xy - vec2(pc.offsetX, pc.offsetY)); + vec2 uv = fragCoord / scrSize; + + float xMin = pc.refdefX; + float xMax = pc.refdefX + pc.refdefWidth; + float yMin = pc.refdefY; + float yMax = pc.refdefY + pc.refdefHeight; + + if (pc.time > 0 && fragCoord.x > xMin && fragCoord.x < xMax && fragCoord.y > yMin && fragCoord.y < yMax) + { + float sx = pc.scale - abs(pc.scrWidth / 2.0 - fragCoord.x) * 2.0 / pc.scrWidth; + float sy = pc.scale - abs(pc.scrHeight / 2.0 - fragCoord.y) * 2.0 / pc.scrHeight; + float xShift = 2.0 * pc.time + uv.y * PI * 10; + float yShift = 2.0 * pc.time + uv.x * PI * 10; + vec2 distortion = vec2(sin(xShift) * sx, sin(yShift) * sy) * 0.00666; + + uv += distortion; + } + + uv /= pc.pixelSize; + + uv = clamp(uv * scrSize, vec2(0.0, 0.0), scrSize - vec2(0.5, 0.5)); + + fragmentColor = textureLod(sTexture, uv, 0.0); +} diff --git a/shaders/world_warp.vert b/shaders/world_warp.vert new file mode 100644 index 0000000..e09723b --- /dev/null +++ b/shaders/world_warp.vert @@ -0,0 +1,17 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main() +{ + vec4 positions[3] = { + vec4(-1.0f, -1.0f, 0.0f, 1.0f), + vec4(3.0f, -1.0f, 0.0f, 1.0f), + vec4(-1.0f, 3.0f, 0.0f, 1.0f) + }; + + gl_Position = positions[gl_VertexIndex % 3]; +} diff --git a/src/backends/hunk_unix.c b/src/backends/hunk_unix.c new file mode 100644 index 0000000..2485fe7 --- /dev/null +++ b/src/backends/hunk_unix.c @@ -0,0 +1,173 @@ +/* + * Copyright (C) 1997-2001 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. + * + * ======================================================================= + * + * This file implements the low level part of the Hunk_* memory system + * + * ======================================================================= + */ + +/* For mremap() - must be before sys/mman.h include! */ +#if defined(__linux__) && !defined(_GNU_SOURCE) + #define _GNU_SOURCE +#endif + +#include +#include +#include +#include + +#include "../common/header/common.h" + +#if defined(__FreeBSD__) || defined(__OpenBSD__) + #include + #define MAP_ANONYMOUS MAP_ANON +#endif + +#if defined(__APPLE__) + #include + #define MAP_ANONYMOUS MAP_ANON +#endif + +byte *membase; +size_t maxhunksize; +size_t curhunksize; + +void * +Hunk_Begin(int maxsize) +{ + + /* reserve a huge chunk of memory, but don't commit any yet */ + /* plus 32 bytes for cacheline */ + maxhunksize = maxsize + sizeof(size_t) + 32; + curhunksize = 0; + int flags = MAP_PRIVATE | MAP_ANONYMOUS; + int prot = PROT_READ | PROT_WRITE; + +#if defined(MAP_ALIGNED_SUPER) + const size_t hgpagesize = 1UL<<21; + size_t page_size = sysconf(_SC_PAGESIZE); + + /* Archs supported has 2MB for super pages size */ + if (maxhunksize >= hgpagesize) + { + maxhunksize = (maxhunksize & ~(page_size-1)) + page_size; + flags |= MAP_ALIGNED_SUPER; + } +#endif + +#if defined(PROT_MAX) + /* For now it is FreeBSD exclusif but could possibly be extended + to other like DFBSD for example */ + prot |= PROT_MAX(prot); +#endif + + membase = mmap(0, maxhunksize, prot, + flags, -1, 0); + + if ((membase == NULL) || (membase == (byte *)-1)) + { + Sys_Error("unable to virtual allocate %d bytes", maxsize); + } + + *((size_t *)membase) = curhunksize; + + return membase + sizeof(size_t); +} + +void * +Hunk_Alloc(int size) +{ + byte *buf; + + /* round to cacheline */ + size = (size + 31) & ~31; + + if (curhunksize + size > maxhunksize) + { + Sys_Error("Hunk_Alloc overflow"); + } + + buf = membase + sizeof(size_t) + curhunksize; + curhunksize += size; + return buf; +} + +int +Hunk_End(void) +{ + byte *n = NULL; + +#if defined(__linux__) + n = (byte *)mremap(membase, maxhunksize, curhunksize + sizeof(size_t), 0); +#elif defined(__NetBSD__) + n = (byte *)mremap(membase, maxhunksize, NULL, curhunksize + sizeof(size_t), 0); +#else + #ifndef round_page + size_t page_size = sysconf(_SC_PAGESIZE); + #define round_page(x) ((((size_t)(x)) + page_size-1) & ~(page_size-1)) + #endif + + size_t old_size = round_page(maxhunksize); + size_t new_size = round_page(curhunksize + sizeof(size_t)); + + if (new_size > old_size) + { + /* Can never happen. If it happens something's very wrong. */ + n = 0; + } + else if (new_size < old_size) + { + /* Hunk is to big, we need to shrink it. */ + n = munmap(membase + new_size, old_size - new_size) + membase; + } + else + { + /* No change necessary. */ + n = membase; + } +#endif + + if (n != membase) + { + Sys_Error("Hunk_End: Could not remap virtual block (%d)", errno); + } + + *((size_t *)membase) = curhunksize + sizeof(size_t); + + return curhunksize; +} + +void +Hunk_Free(void *base) +{ + if (base) + { + byte *m; + + m = ((byte *)base) - sizeof(size_t); + + if (munmap(m, *((size_t *)m))) + { + Sys_Error("Hunk_Free: munmap failed (%d)", errno); + } + } +} + diff --git a/src/backends/hunk_windows.c b/src/backends/hunk_windows.c new file mode 100644 index 0000000..0c5dd0a --- /dev/null +++ b/src/backends/hunk_windows.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 1997-2001 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. + * + * ======================================================================= + * + * Memory handling functions. + * + * ======================================================================= + */ + +#include + +#include "../common/header/common.h" + +byte *membase; +int hunkcount; +size_t hunkmaxsize; +size_t cursize; + +void * +Hunk_Begin(int maxsize) +{ + /* reserve a huge chunk of memory, but don't commit any yet */ + /* plus 32 bytes for cacheline */ + hunkmaxsize = maxsize + sizeof(size_t) + 32; + cursize = 0; + + membase = VirtualAlloc(NULL, hunkmaxsize, MEM_RESERVE, PAGE_NOACCESS); + + if (!membase) + { + Sys_Error("VirtualAlloc reserve failed"); + } + + return (void *)membase; +} + +void * +Hunk_Alloc(int size) +{ + void *buf; + + /* round to cacheline */ + size = (size + 31) & ~31; + + /* commit pages as needed */ + buf = VirtualAlloc(membase, cursize + size, MEM_COMMIT, PAGE_READWRITE); + + if (!buf) + { + Sys_Error("VirtualAlloc commit failed.\n"); + } + + cursize += size; + + if (cursize > hunkmaxsize) + { + Sys_Error("Hunk_Alloc overflow"); + } + + return (void *)(membase + cursize - size); +} + +int +Hunk_End(void) +{ + hunkcount++; + + return cursize; +} + +void +Hunk_Free(void *base) +{ + if (base) + { + VirtualFree(base, 0, MEM_RELEASE); + } + + hunkcount--; +} diff --git a/src/common/header/common.h b/src/common/header/common.h new file mode 100644 index 0000000..ac53365 --- /dev/null +++ b/src/common/header/common.h @@ -0,0 +1,840 @@ +/* + * Copyright (C) 1997-2001 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. + * + * ======================================================================= + * + * Prototypes witch are shared between the client, the server and the + * game. This is the main game API, changes here will most likely + * requiere changes to the game ddl. + * + * ======================================================================= + */ + +#ifndef CO_COMMON_H +#define CO_COMMON_H + +#include "shared.h" +#include "crc.h" + +#define YQ2VERSION "8.00pre" +#define BASEDIRNAME "baseq2" + +#ifndef YQ2OSTYPE +#error YQ2OSTYPE should be defined by the build system +#endif + +#ifndef YQ2ARCH +#error YQ2ARCH should be defined by the build system +#endif + +#ifndef BUILD_DATE +#define BUILD_DATE __DATE__ +#endif + +#ifdef _WIN32 + #define CFGDIR "YamagiQ2" +#else + #define CFGDIR ".yq2" +#endif + +/* ================================================================== */ + +typedef struct sizebuf_s +{ + qboolean allowoverflow; /* if false, do a Com_Error */ + qboolean overflowed; /* set to true if the buffer size failed */ + byte *data; + int maxsize; + int cursize; + int readcount; +} sizebuf_t; + +void SZ_Init(sizebuf_t *buf, byte *data, int length); +void SZ_Clear(sizebuf_t *buf); +void *SZ_GetSpace(sizebuf_t *buf, int length); +void SZ_Write(sizebuf_t *buf, void *data, int length); +void SZ_Print(sizebuf_t *buf, char *data); /* strcats onto the sizebuf */ + +/* ================================================================== */ + +struct usercmd_s; +struct entity_state_s; + +void MSG_WriteChar(sizebuf_t *sb, int c); +void MSG_WriteByte(sizebuf_t *sb, int c); +void MSG_WriteShort(sizebuf_t *sb, int c); +void MSG_WriteLong(sizebuf_t *sb, int c); +void MSG_WriteFloat(sizebuf_t *sb, float f); +void MSG_WriteString(sizebuf_t *sb, char *s); +void MSG_WriteCoord(sizebuf_t *sb, float f); +void MSG_WritePos(sizebuf_t *sb, vec3_t pos); +void MSG_WriteAngle(sizebuf_t *sb, float f); +void MSG_WriteAngle16(sizebuf_t *sb, float f); +void MSG_WriteDeltaUsercmd(sizebuf_t *sb, struct usercmd_s *from, + struct usercmd_s *cmd); +void MSG_WriteDeltaEntity(struct entity_state_s *from, + struct entity_state_s *to, sizebuf_t *msg, + qboolean force, qboolean newentity); +void MSG_WriteDir(sizebuf_t *sb, vec3_t vector); + +void MSG_BeginReading(sizebuf_t *sb); + +int MSG_ReadChar(sizebuf_t *sb); +int MSG_ReadByte(sizebuf_t *sb); +int MSG_ReadShort(sizebuf_t *sb); +int MSG_ReadLong(sizebuf_t *sb); +float MSG_ReadFloat(sizebuf_t *sb); +char *MSG_ReadString(sizebuf_t *sb); +char *MSG_ReadStringLine(sizebuf_t *sb); + +float MSG_ReadCoord(sizebuf_t *sb); +void MSG_ReadPos(sizebuf_t *sb, vec3_t pos); +float MSG_ReadAngle(sizebuf_t *sb); +float MSG_ReadAngle16(sizebuf_t *sb); +void MSG_ReadDeltaUsercmd(sizebuf_t *sb, + struct usercmd_s *from, + struct usercmd_s *cmd); + +void MSG_ReadDir(sizebuf_t *sb, vec3_t vector); + +void MSG_ReadData(sizebuf_t *sb, void *buffer, int size); + +/* ================================================================== */ + +extern qboolean bigendien; + +extern short BigShort(short l); +extern short LittleShort(short l); +extern int BigLong(int l); +extern int LittleLong(int l); +extern float BigFloat(float l); +extern float LittleFloat(float l); + +/* ================================================================== */ + +int COM_Argc(void); +char *COM_Argv(int arg); /* range and null checked */ +void COM_ClearArgv(int arg); +int COM_CheckParm(char *parm); +void COM_AddParm(char *parm); + +void COM_Init(void); +void COM_InitArgv(int argc, char **argv); + +char *CopyString(char *in); + +/* ================================================================== */ + +void Info_Print(char *s); + +/* PROTOCOL */ + +#define PROTOCOL_VERSION 34 + +/* ========================================= */ + +#define PORT_MASTER 27900 +#define PORT_CLIENT 27901 +#define PORT_SERVER 27910 + +/* ========================================= */ + +#define UPDATE_BACKUP 16 /* copies of entity_state_t to keep buffered */ +#define UPDATE_MASK (UPDATE_BACKUP - 1) + +/* server to client */ +enum svc_ops_e +{ + svc_bad, + + /* these ops are known to the game dll */ + svc_muzzleflash, + svc_muzzleflash2, + svc_temp_entity, + svc_layout, + svc_inventory, + + /* the rest are private to the client and server */ + svc_nop, + svc_disconnect, + svc_reconnect, + svc_sound, /* */ + svc_print, /* [byte] id [string] null terminated string */ + svc_stufftext, /* [string] stuffed into client's console buffer, should be \n terminated */ + svc_serverdata, /* [long] protocol ... */ + svc_configstring, /* [short] [string] */ + svc_spawnbaseline, + svc_centerprint, /* [string] to put in center of the screen */ + svc_download, /* [short] size [size bytes] */ + svc_playerinfo, /* variable */ + svc_packetentities, /* [...] */ + svc_deltapacketentities, /* [...] */ + svc_frame +}; + +/* ============================================== */ + +/* client to server */ +enum clc_ops_e +{ + clc_bad, + clc_nop, + clc_move, /* [[usercmd_t] */ + clc_userinfo, /* [[userinfo string] */ + clc_stringcmd /* [string] message */ +}; + +/* ============================================== */ + +/* plyer_state_t communication */ +#define PS_M_TYPE (1 << 0) +#define PS_M_ORIGIN (1 << 1) +#define PS_M_VELOCITY (1 << 2) +#define PS_M_TIME (1 << 3) +#define PS_M_FLAGS (1 << 4) +#define PS_M_GRAVITY (1 << 5) +#define PS_M_DELTA_ANGLES (1 << 6) + +#define PS_VIEWOFFSET (1 << 7) +#define PS_VIEWANGLES (1 << 8) +#define PS_KICKANGLES (1 << 9) +#define PS_BLEND (1 << 10) +#define PS_FOV (1 << 11) +#define PS_WEAPONINDEX (1 << 12) +#define PS_WEAPONFRAME (1 << 13) +#define PS_RDFLAGS (1 << 14) + +/*============================================== */ + +/* user_cmd_t communication */ + +/* ms and light always sent, the others are optional */ +#define CM_ANGLE1 (1 << 0) +#define CM_ANGLE2 (1 << 1) +#define CM_ANGLE3 (1 << 2) +#define CM_FORWARD (1 << 3) +#define CM_SIDE (1 << 4) +#define CM_UP (1 << 5) +#define CM_BUTTONS (1 << 6) +#define CM_IMPULSE (1 << 7) + +/*============================================== */ + +/* a sound without an ent or pos will be a local only sound */ +#define SND_VOLUME (1 << 0) /* a byte */ +#define SND_ATTENUATION (1 << 1) /* a byte */ +#define SND_POS (1 << 2) /* three coordinates */ +#define SND_ENT (1 << 3) /* a short 0-2: channel, 3-12: entity */ +#define SND_OFFSET (1 << 4) /* a byte, msec offset from frame start */ + +#define DEFAULT_SOUND_PACKET_VOLUME 1.0 +#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0 + +/*============================================== */ + +/* entity_state_t communication */ + +/* try to pack the common update flags into the first byte */ +#define U_ORIGIN1 (1 << 0) +#define U_ORIGIN2 (1 << 1) +#define U_ANGLE2 (1 << 2) +#define U_ANGLE3 (1 << 3) +#define U_FRAME8 (1 << 4) /* frame is a byte */ +#define U_EVENT (1 << 5) +#define U_REMOVE (1 << 6) /* REMOVE this entity, don't add it */ +#define U_MOREBITS1 (1 << 7) /* read one additional byte */ + +/* second byte */ +#define U_NUMBER16 (1 << 8) /* NUMBER8 is implicit if not set */ +#define U_ORIGIN3 (1 << 9) +#define U_ANGLE1 (1 << 10) +#define U_MODEL (1 << 11) +#define U_RENDERFX8 (1 << 12) /* fullbright, etc */ +#define U_EFFECTS8 (1 << 14) /* autorotate, trails, etc */ +#define U_MOREBITS2 (1 << 15) /* read one additional byte */ + +/* third byte */ +#define U_SKIN8 (1 << 16) +#define U_FRAME16 (1 << 17) /* frame is a short */ +#define U_RENDERFX16 (1 << 18) /* 8 + 16 = 32 */ +#define U_EFFECTS16 (1 << 19) /* 8 + 16 = 32 */ +#define U_MODEL2 (1 << 20) /* weapons, flags, etc */ +#define U_MODEL3 (1 << 21) +#define U_MODEL4 (1 << 22) +#define U_MOREBITS3 (1 << 23) /* read one additional byte */ + +/* fourth byte */ +#define U_OLDORIGIN (1 << 24) +#define U_SKIN16 (1 << 25) +#define U_SOUND (1 << 26) +#define U_SOLID (1 << 27) + +/* CMD - Command text buffering and command execution */ + +/* + * Any number of commands can be added in a frame, from several different + * sources. Most commands come from either keybindings or console line + * input, but remote servers can also send across commands and entire text + * files can be execed. + * + * The + command line options are also added to the command buffer. + * + * The game starts with a Cbuf_AddText ("exec quake.rc\n"); Cbuf_Execute + * (); + */ + +#define EXEC_NOW 0 /* don't return until completed */ +#define EXEC_INSERT 1 /* insert at current position, but don't run yet */ +#define EXEC_APPEND 2 /* add to end of the command buffer */ + +void Cbuf_Init(void); + +/* allocates an initial text buffer that will grow as needed */ + +void Cbuf_AddText(char *text); + +/* as new commands are generated from the console or keybindings, */ +/* the text is added to the end of the command buffer. */ + +void Cbuf_InsertText(char *text); + +/* when a command wants to issue other commands immediately, the text is */ +/* inserted at the beginning of the buffer, before any remaining unexecuted */ +/* commands. */ + +void Cbuf_ExecuteText(int exec_when, char *text); + +/* this can be used in place of either Cbuf_AddText or Cbuf_InsertText */ + +void Cbuf_AddEarlyCommands(qboolean clear); + +/* adds all the +set commands from the command line */ + +qboolean Cbuf_AddLateCommands(void); + +/* adds all the remaining + commands from the command line */ +/* Returns true if any late commands were added, which */ +/* will keep the demoloop from immediately starting */ + +void Cbuf_Execute(void); + +/* Pulls off \n terminated lines of text from the command buffer and sends */ +/* them through Cmd_ExecuteString. Stops when the buffer is empty. */ +/* Normally called once per frame, but may be explicitly invoked. */ +/* Do not call inside a command function! */ + +void Cbuf_CopyToDefer(void); +void Cbuf_InsertFromDefer(void); + +/* These two functions are used to defer any pending commands while a map */ +/* is being loaded */ + +/*=================================================================== */ + +/* + * Command execution takes a null terminated string, breaks it into tokens, + * then searches for a command or variable that matches the first token. + */ + +typedef void (*xcommand_t)(void); + +void Cmd_Init(void); + +void Cmd_AddCommand(char *cmd_name, xcommand_t function); + +/* called by the init functions of other parts of the program to */ +/* register commands and functions to call for them. */ +/* The cmd_name is referenced later, so it should not be in temp memory */ +/* if function is NULL, the command will be forwarded to the server */ +/* as a clc_stringcmd instead of executed locally */ +void Cmd_RemoveCommand(char *cmd_name); + +qboolean Cmd_Exists(char *cmd_name); + +/* used by the cvar code to check for cvar / command name overlap */ + +char *Cmd_CompleteCommand(char *partial); + +char *Cmd_CompleteMapCommand(char *partial); + +/* attempts to match a partial command for automatic command line completion */ +/* returns NULL if nothing fits */ + +int Cmd_Argc(void); +char *Cmd_Argv(int arg); +char *Cmd_Args(void); + +/* The functions that execute commands get their parameters with these */ +/* functions. Cmd_Argv () will return an empty string, not a NULL */ +/* if arg > argc, so string operations are always safe. */ + +void Cmd_TokenizeString(char *text, qboolean macroExpand); + +/* Takes a null terminated string. Does not need to be /n terminated. */ +/* breaks the string up into arg tokens. */ + +void Cmd_ExecuteString(char *text); + +/* Parses a single line of text into arguments and tries to execute it */ +/* as if it was typed at the console */ + +void Cmd_ForwardToServer(void); + +/* adds the current command line as a clc_stringcmd to the client message. */ +/* things like godmode, noclip, etc, are commands directed to the server, */ +/* so when they are typed in at the console, they will need to be forwarded. */ + +/* CVAR */ + +/* + * cvar_t variables are used to hold scalar or string variables that can be + * changed or displayed at the console or prog code as well as accessed + * directly in C code. + * + * The user can access cvars from the console in three ways: + * r_draworder prints the current value + * r_draworder 0 sets the current value to 0 + * set r_draworder 0 as above, but creates the cvar if not present + * Cvars are restricted from having the same names as commands to keep this + * interface from being ambiguous. + */ + +extern cvar_t *cvar_vars; + +cvar_t *Cvar_Get(char *var_name, char *value, int flags); + +/* creates the variable if it doesn't exist, or returns the existing one */ +/* if it exists, the value will not be changed, but flags will be ORed in */ +/* that allows variables to be unarchived without needing bitflags */ + +cvar_t *Cvar_Set(char *var_name, char *value); + +/* will create the variable if it doesn't exist */ + +cvar_t *Cvar_ForceSet(char *var_name, char *value); + +/* will set the variable even if NOSET or LATCH */ + +cvar_t *Cvar_FullSet(char *var_name, char *value, int flags); + +void Cvar_SetValue(char *var_name, float value); + +/* expands value to a string and calls Cvar_Set */ + +float Cvar_VariableValue(char *var_name); + +/* returns 0 if not defined or non numeric */ + +const char *Cvar_VariableString(const char *var_name); + +/* returns an empty string if not defined */ + +char *Cvar_CompleteVariable(char *partial); + +/* attempts to match a partial variable name for command line completion */ +/* returns NULL if nothing fits */ + +void Cvar_GetLatchedVars(void); + +/* any CVAR_LATCHED variables that have been set will now take effect */ + +qboolean Cvar_Command(void); + +/* called by Cmd_ExecuteString when Cmd_Argv(0) doesn't match a known */ +/* command. Returns true if the command was a variable reference that */ +/* was handled. (print or change) */ + +void Cvar_WriteVariables(char *path); + +/* appends lines containing "set variable value" for all variables */ +/* with the archive flag set to true. */ + +void Cvar_Init(void); + +void Cvar_Fini(void); + +char *Cvar_Userinfo(void); + +/* returns an info string containing all the CVAR_USERINFO cvars */ + +char *Cvar_Serverinfo(void); + +/* returns an info string containing all the CVAR_SERVERINFO cvars */ + +extern qboolean userinfo_modified; +/* this is set each time a CVAR_USERINFO variable is changed */ +/* so that the client knows to send it to the server */ + +/* NET */ + +#define PORT_ANY -1 +#define MAX_MSGLEN 1400 /* max length of a message */ +#define PACKET_HEADER 10 /* two ints and a short */ + +typedef enum +{ + NA_LOOPBACK, + NA_BROADCAST, + NA_IP, + NA_IPX, + NA_BROADCAST_IPX, + NA_IP6, + NA_MULTICAST6 +} netadrtype_t; + +typedef enum {NS_CLIENT, NS_SERVER} netsrc_t; + +typedef struct +{ + netadrtype_t type; + byte ip[16]; + unsigned int scope_id; + byte ipx[10]; + + unsigned short port; +} netadr_t; + +void NET_Init(void); +void NET_Shutdown(void); + +void NET_Config(qboolean multiplayer); + +qboolean NET_GetPacket(netsrc_t sock, netadr_t *net_from, + sizebuf_t *net_message); +void NET_SendPacket(netsrc_t sock, int length, void *data, netadr_t to); + +qboolean NET_CompareAdr(netadr_t a, netadr_t b); +qboolean NET_CompareBaseAdr(netadr_t a, netadr_t b); +qboolean NET_IsLocalAddress(netadr_t adr); +char *NET_AdrToString(netadr_t a); +qboolean NET_StringToAdr(const char *s, netadr_t *a); +void NET_Sleep(int msec); + +/*=================================================================== */ + +#define OLD_AVG 0.99 +#define MAX_LATENT 32 + +typedef struct +{ + qboolean fatal_error; + + netsrc_t sock; + + int dropped; /* between last packet and previous */ + + int last_received; /* for timeouts */ + int last_sent; /* for retransmits */ + + netadr_t remote_address; + int qport; /* qport value to write when transmitting */ + + /* sequencing variables */ + int incoming_sequence; + int incoming_acknowledged; + int incoming_reliable_acknowledged; /* single bit */ + + int incoming_reliable_sequence; /* single bit, maintained local */ + + int outgoing_sequence; + int reliable_sequence; /* single bit */ + int last_reliable_sequence; /* sequence number of last send */ + + /* reliable staging and holding areas */ + sizebuf_t message; /* writing buffer to send to server */ + byte message_buf[MAX_MSGLEN - 16]; /* leave space for header */ + + /* message is copied to this buffer when it is first transfered */ + int reliable_length; + byte reliable_buf[MAX_MSGLEN - 16]; /* unacked reliable message */ +} netchan_t; + +extern netadr_t net_from; +extern sizebuf_t net_message; +extern byte net_message_buffer[MAX_MSGLEN]; + +void Netchan_Init(void); +void Netchan_Setup(netsrc_t sock, netchan_t *chan, netadr_t adr, int qport); + +qboolean Netchan_NeedReliable(netchan_t *chan); +void Netchan_Transmit(netchan_t *chan, int length, byte *data); +void Netchan_OutOfBand(int net_socket, netadr_t adr, int length, byte *data); +void Netchan_OutOfBandPrint(int net_socket, netadr_t adr, char *format, ...); +qboolean Netchan_Process(netchan_t *chan, sizebuf_t *msg); + +qboolean Netchan_CanReliable(netchan_t *chan); + +/* CMODEL */ + +#include "files.h" + +cmodel_t *CM_LoadMap(char *name, qboolean clientload, unsigned *checksum); +cmodel_t *CM_InlineModel(char *name); /* *1, *2, etc */ + +int CM_NumClusters(void); +int CM_NumInlineModels(void); +char *CM_EntityString(void); + +/* creates a clipping hull for an arbitrary box */ +int CM_HeadnodeForBox(vec3_t mins, vec3_t maxs); + +/* returns an ORed contents mask */ +int CM_PointContents(vec3_t p, int headnode); +int CM_TransformedPointContents(vec3_t p, int headnode, + vec3_t origin, vec3_t angles); + +trace_t CM_BoxTrace(vec3_t start, vec3_t end, vec3_t mins, + vec3_t maxs, int headnode, int brushmask); +trace_t CM_TransformedBoxTrace(vec3_t start, vec3_t end, + vec3_t mins, vec3_t maxs, int headnode, + int brushmask, vec3_t origin, vec3_t angles); + +byte *CM_ClusterPVS(int cluster); +byte *CM_ClusterPHS(int cluster); + +int CM_PointLeafnum(vec3_t p); + +/* call with topnode set to the headnode, returns with topnode */ +/* set to the first node that splits the box */ +int CM_BoxLeafnums(vec3_t mins, vec3_t maxs, int *list, + int listsize, int *topnode); + +int CM_LeafContents(int leafnum); +int CM_LeafCluster(int leafnum); +int CM_LeafArea(int leafnum); + +void CM_SetAreaPortalState(int portalnum, qboolean open); +qboolean CM_AreasConnected(int area1, int area2); + +int CM_WriteAreaBits(byte *buffer, int area); +qboolean CM_HeadnodeVisible(int headnode, byte *visbits); + +void CM_WritePortalState(FILE *f); + +/* PLAYER MOVEMENT CODE */ + +extern float pm_airaccelerate; + +void Pmove(pmove_t *pmove); + +/* FILESYSTEM */ + +#define SFF_INPACK 0x20 + +typedef int fileHandle_t; + +typedef enum +{ + FS_READ, + FS_WRITE, + FS_APPEND +} fsMode_t; + +typedef enum +{ + FS_SEEK_CUR, + FS_SEEK_SET, + FS_SEEK_END +} fsOrigin_t; + +typedef enum +{ + FS_SEARCH_PATH_EXTENSION, + FS_SEARCH_BY_FILTER, + FS_SEARCH_FULL_PATH +} fsSearchType_t; + +void FS_DPrintf(const char *format, ...); +int FS_FOpenFile(const char *name, fileHandle_t *f, qboolean gamedir_only); +void FS_FCloseFile(fileHandle_t f); +int FS_Read(void *buffer, int size, fileHandle_t f); +int FS_FRead(void *buffer, int size, int count, fileHandle_t f); + +// returns the filename used to open f, but (if opened from pack) in correct case +// returns NULL if f is no valid handle +const char* FS_GetFilenameForHandle(fileHandle_t f); + +char **FS_ListFiles(char *findname, int *numfiles, + unsigned musthave, unsigned canthave); +char **FS_ListFiles2(char *findname, int *numfiles, + unsigned musthave, unsigned canthave); +void FS_FreeList(char **list, int nfiles); + +void FS_InitFilesystem(void); +void FS_BuildGameSpecificSearchPath(char *dir); +char *FS_Gamedir(void); +char *FS_NextPath(char *prevpath); +int FS_LoadFile(char *path, void **buffer); +qboolean FS_FileInGamedir(const char *file); +qboolean FS_AddPAKFromGamedir(const char *pak); +const char* FS_GetNextRawPath(const char* lastRawPath); +char **FS_ListMods(int *nummods); + +/* a null buffer will just return the file length without loading */ +/* a -1 length is not present */ + +/* properly handles partial reads */ + +void FS_FreeFile(void *buffer); +void FS_CreatePath(char *path); + +/* MISC */ + +#define ERR_FATAL 0 /* exit the entire game with a popup window */ +#define ERR_DROP 1 /* print to console and disconnect from game */ +#define ERR_QUIT 2 /* not an error, just a normal exit */ + +#define EXEC_NOW 0 /* don't return until completed */ +#define EXEC_INSERT 1 /* insert at current position, but don't run yet */ +#define EXEC_APPEND 2 /* add to end of the command buffer */ + +#define PRINT_ALL 0 +#define PRINT_DEVELOPER 1 /* only print when "developer 1" */ + +void Com_BeginRedirect(int target, char *buffer, int buffersize, void (*flush)(int, char *)); +void Com_EndRedirect(void); +void Com_Printf(char *fmt, ...) __attribute__ ((format (printf, 1, 2))); +void Com_DPrintf(char *fmt, ...) __attribute__ ((format (printf, 1, 2))); +void Com_VPrintf(int print_level, const char *fmt, va_list argptr); /* print_level is PRINT_ALL or PRINT_DEVELOPER */ +void Com_MDPrintf(char *fmt, ...) __attribute__ ((format (printf, 1, 2))); +YQ2_ATTR_NORETURN void Com_Error(int code, char *fmt, ...) __attribute__ ((format (printf, 2, 3))); +YQ2_ATTR_NORETURN void Com_Quit(void); + +/* Ugly work around for unsupported + * format specifiers unter mingw. */ +#ifdef WIN32 +#define YQ2_COM_PRId64 "%I64d" +#define YQ2_COM_PRIdS "%Id" +#else +#define YQ2_COM_PRId64 "%ld" +#define YQ2_COM_PRIdS "%zd" +#endif + +// terminate yq2 (with Com_Error()) if VAR is NULL (after malloc() or similar) +// and print message about it +#define YQ2_COM_CHECK_OOM(VAR, ALLOC_FN_NAME, ALLOC_SIZE) \ + if(VAR == NULL) { \ + Com_Error(ERR_FATAL, "%s for " YQ2_COM_PRIdS " bytes failed in %s() (%s == NULL)! Out of Memory?!\n", \ + ALLOC_FN_NAME, (size_t)ALLOC_SIZE, __func__, #VAR); } + +int Com_ServerState(void); /* this should have just been a cvar... */ +void Com_SetServerState(int state); + +unsigned Com_BlockChecksum(void *buffer, int length); +byte COM_BlockSequenceCRCByte(byte *base, int length, int sequence); + +extern cvar_t *developer; +extern cvar_t *modder; +extern cvar_t *dedicated; +extern cvar_t *host_speeds; +extern cvar_t *log_stats; + +/* External entity files. */ +extern cvar_t *sv_entfile; + +/* Hack for portable client */ +extern qboolean is_portable; + +/* Hack for external datadir */ +extern char datadir[MAX_OSPATH]; + +/* Hack for external datadir */ +extern char cfgdir[MAX_OSPATH]; + +/* Hack for working 'game' cmd */ +extern char userGivenGame[MAX_QPATH]; +extern char **mapnames; +extern int nummaps; + +extern FILE *log_stats_file; + +/* host_speeds times */ +extern int time_before_game; +extern int time_after_game; +extern int time_before_ref; +extern int time_after_ref; + +void Z_Free(void *ptr); +void *Z_Malloc(int size); /* returns 0 filled memory */ +void *Z_TagMalloc(int size, int tag); +void Z_FreeTags(int tag); + +void Qcommon_Init(int argc, char **argv); +void Qcommon_ExecConfigs(qboolean addEarlyCmds); +const char* Qcommon_GetInitialGame(void); +void Qcommon_Frame(int msec); +void Qcommon_Shutdown(void); + +#define NUMVERTEXNORMALS 162 +extern vec3_t bytedirs[NUMVERTEXNORMALS]; + +/* this is in the client code, but can be used for debugging from server */ +void SCR_DebugGraph(float value, int color); + +/* CLIENT / SERVER SYSTEMS */ + +void CL_Init(void); +void CL_Drop(void); +void CL_Shutdown(void); +void CL_Frame(int packetdelta, int renderdelta, int timedelta, qboolean packetframe, qboolean renderframe); +void Con_Print(char *text); +void SCR_BeginLoadingPlaque(void); + +void SV_Init(void); +void SV_Shutdown(char *finalmsg, qboolean reconnect); +void SV_Frame(int usec); + +/* ======================================================================= */ + +// Platform specific functions. + +// system.c +char *Sys_ConsoleInput(void); +void Sys_ConsoleOutput(char *string); +YQ2_ATTR_NORETURN void Sys_Error(char *error, ...); +YQ2_ATTR_NORETURN void Sys_Quit(void); +void Sys_Init(void); +char *Sys_GetHomeDir(void); +void Sys_Remove(const char *path); +int Sys_Rename(const char *from, const char *to); +void Sys_RemoveDir(const char *path); +long long Sys_Microseconds(void); +void Sys_Nanosleep(int); +void *Sys_GetProcAddress(void *handle, const char *sym); +void Sys_FreeLibrary(void *handle); +void *Sys_LoadLibrary(const char *path, const char *sym, void **handle); +void *Sys_GetGameAPI(void *parms); +void Sys_UnloadGame(void); +void Sys_GetWorkDir(char *buffer, size_t len); +qboolean Sys_SetWorkDir(char *path); +void Sys_Realpath(const char *in, char *out, size_t size); + +// Windows only (system.c) +#ifdef _WIN32 +void Sys_RedirectStdout(void); +void Sys_SetHighDPIMode(void); +#endif + +// misc.c +const char *Sys_GetBinaryDir(void); +void Sys_SetupFPU(void); + +/* ======================================================================= */ + +#endif diff --git a/src/common/header/crc.h b/src/common/header/crc.h new file mode 100644 index 0000000..267a789 --- /dev/null +++ b/src/common/header/crc.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 1997-2001 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. + * + * ======================================================================= + * + * Corresponding header for crc.c + * + * ======================================================================= + */ + +#ifndef CO_CRC_H +#define CO_CRC_H + +void CRC_Init(unsigned short *crcvalue); +unsigned short CRC_Block(byte *start, int count); + +#endif diff --git a/src/common/header/files.h b/src/common/header/files.h new file mode 100644 index 0000000..2d00a19 --- /dev/null +++ b/src/common/header/files.h @@ -0,0 +1,453 @@ +/* + * Copyright (C) 1997-2001 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. + * + * ======================================================================= + * + * The prototypes for most file formats used by Quake II + * + * ======================================================================= + */ + +#ifndef CO_FILES_H +#define CO_FILES_H + +/* The .pak files are just a linear collapse of a directory tree */ + +#define IDPAKHEADER (('K' << 24) + ('C' << 16) + ('A' << 8) + 'P') + +typedef struct +{ + char name[56]; + int filepos, filelen; +} dpackfile_t; + +typedef struct +{ + int ident; /* == IDPAKHEADER */ + int dirofs; + int dirlen; +} dpackheader_t; + +#define MAX_FILES_IN_PACK 4096 + +/* PCX files are used for as many images as possible */ + +typedef struct +{ + char manufacturer; + char version; + char encoding; + char bits_per_pixel; + unsigned short xmin, ymin, xmax, ymax; + unsigned short hres, vres; + unsigned char palette[48]; + char reserved; + char color_planes; + unsigned short bytes_per_line; + unsigned short palette_type; + char filler[58]; + unsigned char data; /* unbounded */ +} pcx_t; + +/* .MD2 triangle model file format */ + +#define IDALIASHEADER (('2' << 24) + ('P' << 16) + ('D' << 8) + 'I') +#define ALIAS_VERSION 8 + +#define MAX_TRIANGLES 4096 +#define MAX_VERTS 2048 +#define MAX_FRAMES 512 +#define MAX_MD2SKINS 32 +#define MAX_SKINNAME 64 + +typedef struct +{ + short s; + short t; +} dstvert_t; + +typedef struct +{ + short index_xyz[3]; + short index_st[3]; +} dtriangle_t; + +typedef struct +{ + byte v[3]; /* scaled byte to fit in frame mins/maxs */ + byte lightnormalindex; +} dtrivertx_t; + +#define DTRIVERTX_V0 0 +#define DTRIVERTX_V1 1 +#define DTRIVERTX_V2 2 +#define DTRIVERTX_LNI 3 +#define DTRIVERTX_SIZE 4 + +typedef struct +{ + float scale[3]; /* multiply byte verts by this */ + float translate[3]; /* then add this */ + char name[16]; /* frame name from grabbing */ + dtrivertx_t verts[1]; /* variable sized */ +} daliasframe_t; + +/* the glcmd format: + * - a positive integer starts a tristrip command, followed by that many + * vertex structures. + * - a negative integer starts a trifan command, followed by -x vertexes + * a zero indicates the end of the command list. + * - a vertex consists of a floating point s, a floating point t, + * and an integer vertex index. */ + +typedef struct +{ + int ident; + int version; + + int skinwidth; + int skinheight; + int framesize; /* byte size of each frame */ + + int num_skins; + int num_xyz; + int num_st; /* greater than num_xyz for seams */ + int num_tris; + int num_glcmds; /* dwords in strip/fan command list */ + int num_frames; + + int ofs_skins; /* each skin is a MAX_SKINNAME string */ + int ofs_st; /* byte offset from start for stverts */ + int ofs_tris; /* offset for dtriangles */ + int ofs_frames; /* offset for first frame */ + int ofs_glcmds; + int ofs_end; /* end of file */ +} dmdl_t; + +/* .SP2 sprite file format */ + +#define IDSPRITEHEADER (('2' << 24) + ('S' << 16) + ('D' << 8) + 'I') /* little-endian "IDS2" */ +#define SPRITE_VERSION 2 + +typedef struct +{ + int width, height; + int origin_x, origin_y; /* raster coordinates inside pic */ + char name[MAX_SKINNAME]; /* name of pcx file */ +} dsprframe_t; + +typedef struct +{ + int ident; + int version; + int numframes; + dsprframe_t frames[1]; /* variable sized */ +} dsprite_t; + +/* .WAL texture file format */ + +#define MIPLEVELS 4 +typedef struct miptex_s +{ + char name[32]; + unsigned width, height; + unsigned offsets[MIPLEVELS]; /* four mip maps stored */ + char animname[32]; /* next frame in animation chain */ + int flags; + int contents; + int value; +} miptex_t; + +/* .M8 texture file format */ + +#define M8_MIP_LEVELS 16 +#define M8_VERSION 0x2 + +typedef struct { + unsigned char r; + unsigned char g; + unsigned char b; +} rgb_t; + +typedef struct m8tex_s +{ + unsigned version; + char name[32]; + unsigned width[M8_MIP_LEVELS]; + unsigned height[M8_MIP_LEVELS]; + unsigned offsets[M8_MIP_LEVELS]; /* 16 mip maps stored */ + char animname[32]; /* next frame in animation chain */ + rgb_t palette[256]; + int flags; + int contents; + int value; +} m8tex_t; + +/* .BSP file format */ + +#define IDBSPHEADER (('P' << 24) + ('S' << 16) + ('B' << 8) + 'I') /* little-endian "IBSP" */ +#define BSPVERSION 38 + +/* upper design bounds: leaffaces, leafbrushes, planes, and + * verts are still bounded by 16 bit short limits */ +#define MAX_MAP_MODELS 1024 +#define MAX_MAP_BRUSHES 8192 +#define MAX_MAP_ENTITIES 2048 +#define MAX_MAP_ENTSTRING 0x40000 +#define MAX_MAP_TEXINFO 8192 + +#define MAX_MAP_AREAS 256 +#define MAX_MAP_AREAPORTALS 1024 +#define MAX_MAP_PLANES 65536 +#define MAX_MAP_NODES 65536 +#define MAX_MAP_BRUSHSIDES 65536 +#define MAX_MAP_LEAFS 65536 +#define MAX_MAP_VERTS 65536 +#define MAX_MAP_FACES 65536 +#define MAX_MAP_LEAFFACES 65536 +#define MAX_MAP_LEAFBRUSHES 65536 +#define MAX_MAP_PORTALS 65536 +#define MAX_MAP_EDGES 128000 +#define MAX_MAP_SURFEDGES 256000 +#define MAX_MAP_LIGHTING 0x200000 +#define MAX_MAP_VISIBILITY 0x100000 + +/* key / value pair sizes */ + +#define MAX_KEY 32 +#define MAX_VALUE 1024 + +/* ================================================================== */ + +typedef struct +{ + int fileofs, filelen; +} lump_t; + +#define LUMP_ENTITIES 0 +#define LUMP_PLANES 1 +#define LUMP_VERTEXES 2 +#define LUMP_VISIBILITY 3 +#define LUMP_NODES 4 +#define LUMP_TEXINFO 5 +#define LUMP_FACES 6 +#define LUMP_LIGHTING 7 +#define LUMP_LEAFS 8 +#define LUMP_LEAFFACES 9 +#define LUMP_LEAFBRUSHES 10 +#define LUMP_EDGES 11 +#define LUMP_SURFEDGES 12 +#define LUMP_MODELS 13 +#define LUMP_BRUSHES 14 +#define LUMP_BRUSHSIDES 15 +#define LUMP_POP 16 +#define LUMP_AREAS 17 +#define LUMP_AREAPORTALS 18 +#define HEADER_LUMPS 19 + +typedef struct +{ + int ident; + int version; + lump_t lumps[HEADER_LUMPS]; +} dheader_t; + +typedef struct +{ + float mins[3], maxs[3]; + float origin[3]; /* for sounds or lights */ + int headnode; + int firstface, numfaces; /* submodels just draw faces without + walking the bsp tree */ +} dmodel_t; + +typedef struct +{ + float point[3]; +} dvertex_t; + +/* 0-2 are axial planes */ +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 + +/* 3-5 are non-axial planes snapped to the nearest */ +#define PLANE_ANYX 3 +#define PLANE_ANYY 4 +#define PLANE_ANYZ 5 + +/* planes (x&~1) and (x&~1)+1 are always opposites */ + +typedef struct +{ + float normal[3]; + float dist; + int type; /* PLANE_X - PLANE_ANYZ */ +} dplane_t; + +/* contents flags are seperate bits + * - given brush can contribute multiple content bits + * - multiple brushes can be in a single leaf */ + +/* lower bits are stronger, and will eat weaker brushes completely */ +#define CONTENTS_SOLID 1 /* an eye is never valid in a solid */ +#define CONTENTS_WINDOW 2 /* translucent, but not watery */ +#define CONTENTS_AUX 4 +#define CONTENTS_LAVA 8 +#define CONTENTS_SLIME 16 +#define CONTENTS_WATER 32 +#define CONTENTS_MIST 64 +#define LAST_VISIBLE_CONTENTS 64 + +/* remaining contents are non-visible, and don't eat brushes */ +#define CONTENTS_AREAPORTAL 0x8000 + +#define CONTENTS_PLAYERCLIP 0x10000 +#define CONTENTS_MONSTERCLIP 0x20000 + +/* currents can be added to any other contents, and may be mixed */ +#define CONTENTS_CURRENT_0 0x40000 +#define CONTENTS_CURRENT_90 0x80000 +#define CONTENTS_CURRENT_180 0x100000 +#define CONTENTS_CURRENT_270 0x200000 +#define CONTENTS_CURRENT_UP 0x400000 +#define CONTENTS_CURRENT_DOWN 0x800000 + +#define CONTENTS_ORIGIN 0x1000000 /* removed before bsping an entity */ + +#define CONTENTS_MONSTER 0x2000000 /* should never be on a brush, only in game */ +#define CONTENTS_DEADMONSTER 0x4000000 +#define CONTENTS_DETAIL 0x8000000 /* brushes to be added after vis leafs */ +#define CONTENTS_TRANSLUCENT 0x10000000 /* auto set if any surface has trans */ +#define CONTENTS_LADDER 0x20000000 + +#define SURF_LIGHT 0x1 /* value will hold the light strength */ + +#define SURF_SLICK 0x2 /* effects game physics */ + +#define SURF_SKY 0x4 /* don't draw, but add to skybox */ +#define SURF_WARP 0x8 /* turbulent water warp */ +#define SURF_TRANS33 0x10 +#define SURF_TRANS66 0x20 +#define SURF_FLOWING 0x40 /* scroll towards angle */ +#define SURF_NODRAW 0x80 /* don't bother referencing the texture */ + +typedef struct +{ + int planenum; + int children[2]; /* negative numbers are -(leafs+1), not nodes */ + short mins[3]; /* for frustom culling */ + short maxs[3]; + unsigned short firstface; + unsigned short numfaces; /* counting both sides */ +} dnode_t; + +typedef struct texinfo_s +{ + float vecs[2][4]; /* [s/t][xyz offset] */ + int flags; /* miptex flags + overrides light emission, etc */ + int value; + char texture[32]; /* texture name (textures*.wal) */ + int nexttexinfo; /* for animations, -1 = end of chain */ +} texinfo_t; + +/* note that edge 0 is never used, because negative edge + nums are used for counterclockwise use of the edge in + a face */ +typedef struct +{ + unsigned short v[2]; /* vertex numbers */ +} dedge_t; + +#define MAXLIGHTMAPS 4 +typedef struct +{ + unsigned short planenum; + short side; + + int firstedge; /* we must support > 64k edges */ + short numedges; + short texinfo; + + /* lighting info */ + byte styles[MAXLIGHTMAPS]; + int lightofs; /* start of [numstyles*surfsize] samples */ +} dface_t; + +typedef struct +{ + int contents; /* OR of all brushes (not needed?) */ + + short cluster; + short area; + + short mins[3]; /* for frustum culling */ + short maxs[3]; + + unsigned short firstleafface; + unsigned short numleaffaces; + + unsigned short firstleafbrush; + unsigned short numleafbrushes; +} dleaf_t; + +typedef struct +{ + unsigned short planenum; /* facing out of the leaf */ + short texinfo; +} dbrushside_t; + +typedef struct +{ + int firstside; + int numsides; + int contents; +} dbrush_t; + +#define ANGLE_UP -1 +#define ANGLE_DOWN -2 + +/* the visibility lump consists of a header with a count, then + * byte offsets for the PVS and PHS of each cluster, then the raw + * compressed bit vectors */ +#define DVIS_PVS 0 +#define DVIS_PHS 1 +typedef struct +{ + int numclusters; + int bitofs[8][2]; /* bitofs[numclusters][2] */ +} dvis_t; + +/* each area has a list of portals that lead into other areas + * when portals are closed, other areas may not be visible or + * hearable even if the vis info says that it should be */ +typedef struct +{ + int portalnum; + int otherarea; +} dareaportal_t; + +typedef struct +{ + int numareaportals; + int firstareaportal; +} darea_t; + +#endif + diff --git a/src/common/header/ref_api.h b/src/common/header/ref_api.h new file mode 100644 index 0000000..a788e3e --- /dev/null +++ b/src/common/header/ref_api.h @@ -0,0 +1,283 @@ +/* + * Copyright (C) 1997-2001 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. + * + * ======================================================================= + * + * ABI between client and refresher + * + * ======================================================================= + */ + +#ifndef CL_REF_H +#define CL_REF_H + +#include "common.h" +#include "vid.h" + +#define MAX_DLIGHTS 32 +#define MAX_ENTITIES 128 +#define MAX_PARTICLES 4096 +#define MAX_LIGHTSTYLES 256 + +#define POWERSUIT_SCALE 4.0F + +#define SHELL_RED_COLOR 0xF2 +#define SHELL_GREEN_COLOR 0xD0 +#define SHELL_BLUE_COLOR 0xF3 + +#define SHELL_RG_COLOR 0xDC +#define SHELL_RB_COLOR 0x68 +#define SHELL_BG_COLOR 0x78 + +#define SHELL_DOUBLE_COLOR 0xDF +#define SHELL_HALF_DAM_COLOR 0x90 +#define SHELL_CYAN_COLOR 0x72 + +#define SHELL_WHITE_COLOR 0xD7 + +#define ENTITY_FLAGS 68 + +typedef struct entity_s { + struct model_s *model; /* opaque type outside refresh */ + float angles[3]; + + /* most recent data */ + float origin[3]; /* also used as RF_BEAM's "from" */ + int frame; /* also used as RF_BEAM's diameter */ + + /* previous data for lerping */ + float oldorigin[3]; /* also used as RF_BEAM's "to" */ + int oldframe; + + /* misc */ + float backlerp; /* 0.0 = current, 1.0 = old */ + int skinnum; /* also used as RF_BEAM's palette index */ + + int lightstyle; /* for flashing entities */ + float alpha; /* ignore if RF_TRANSLUCENT isn't set */ + + struct image_s *skin; /* NULL for inline skin */ + int flags; +} entity_t; + +typedef struct { + vec3_t origin; + vec3_t color; + float intensity; +} dlight_t; + +typedef struct { + vec3_t origin; + int color; + float alpha; +} particle_t; + +typedef struct { + float rgb[3]; /* 0.0 - 2.0 */ + float white; /* r+g+b */ +} lightstyle_t; + +typedef struct { + int x, y, width, height; /* in virtual screen coordinates */ + float fov_x, fov_y; + float vieworg[3]; + float viewangles[3]; + float blend[4]; /* rgba 0-1 full screen blend */ + float time; /* time is used to auto animate */ + int rdflags; /* RDF_UNDERWATER, etc */ + + byte *areabits; /* if not NULL, only areas with set bits will be drawn */ + + lightstyle_t *lightstyles; /* [MAX_LIGHTSTYLES] */ + + int num_entities; + entity_t *entities; + + int num_dlights; // <= 32 (MAX_DLIGHTS) + dlight_t *dlights; + + int num_particles; + particle_t *particles; +} refdef_t; + +// Renderer restart type. +typedef enum { + RESTART_UNDEF, + RESTART_NO, + RESTART_FULL, + RESTART_PARTIAL +} ref_restart_t; + +// FIXME: bump API_VERSION? +#define API_VERSION 5 +#define EXPORT +#define IMPORT + +// +// these are the functions exported by the refresh module +// +typedef struct +{ + // if api_version is different, the dll cannot be used + int api_version; + + // called when the library is loaded + qboolean (EXPORT *Init) (void); + + // called before the library is unloaded + void (EXPORT *Shutdown) (void); + + // called by GLimp_InitGraphics() before creating window, + // returns flags for SDL window creation, returns -1 on error + int (EXPORT *PrepareForWindow)(void); + + // called by GLimp_InitGraphics() *after* creating window, + // passing the SDL_Window* (void* so we don't spill SDL.h here) + // (or SDL_Surface* for SDL1.2, another reason to use void*) + // returns true (1) on success + int (EXPORT *InitContext)(void* sdl_window); + + // shuts down rendering (OpenGL) context. + void (EXPORT *ShutdownContext)(void); + + // returns true if vsync is active, else false + qboolean (EXPORT *IsVSyncActive)(void); + + // All data that will be used in a level should be + // registered before rendering any frames to prevent disk hits, + // but they can still be registered at a later time + // if necessary. + // + // EndRegistration will free any remaining data that wasn't registered. + // Any model_s or skin_s pointers from before the BeginRegistration + // are no longer valid after EndRegistration. + // + // Skins and images need to be differentiated, because skins + // are flood filled to eliminate mip map edge errors, and pics have + // an implicit "pics/" prepended to the name. (a pic name that starts with a + // slash will not use the "pics/" prefix or the ".pcx" postfix) + void (EXPORT *BeginRegistration) (char *map); + struct model_s * (EXPORT *RegisterModel) (char *name); + struct image_s * (EXPORT *RegisterSkin) (char *name); + + void (EXPORT *SetSky) (char *name, float rotate, vec3_t axis); + void (EXPORT *EndRegistration) (void); + + void (EXPORT *RenderFrame) (refdef_t *fd); + + struct image_s * (EXPORT *DrawFindPic)(char *name); + + void (EXPORT *DrawGetPicSize) (int *w, int *h, char *name); // will return 0 0 if not found + void (EXPORT *DrawPicScaled) (int x, int y, char *pic, float factor); + void (EXPORT *DrawStretchPic) (int x, int y, int w, int h, char *name); + void (EXPORT *DrawCharScaled)(int x, int y, int num, float scale); + void (EXPORT *DrawTileClear) (int x, int y, int w, int h, char *name); + void (EXPORT *DrawFill) (int x, int y, int w, int h, int c); + void (EXPORT *DrawFadeScreen) (void); + + // Draw images for cinematic rendering (which can have a different palette). Note that calls + void (EXPORT *DrawStretchRaw) (int x, int y, int w, int h, int cols, int rows, byte *data); + + /* + ** video mode and refresh state management entry points + */ + void (EXPORT *SetPalette)( const unsigned char *palette); // NULL = game palette + void (EXPORT *BeginFrame)( float camera_separation ); + void (EXPORT *EndFrame) (void); + qboolean (EXPORT *EndWorldRenderpass) (void); // finish world rendering, apply postprocess and switch to UI render pass + + //void (EXPORT *AppActivate)( qboolean activate ); +} refexport_t; + +typedef struct +{ + YQ2_ATTR_NORETURN_FUNCPTR void (IMPORT *Sys_Error) (int err_level, char *str, ...) __attribute__ ((format (printf, 2, 3))); + + void (IMPORT *Cmd_AddCommand) (char *name, void(*cmd)(void)); + void (IMPORT *Cmd_RemoveCommand) (char *name); + int (IMPORT *Cmd_Argc) (void); + char *(IMPORT *Cmd_Argv) (int i); + void (IMPORT *Cmd_ExecuteText) (int exec_when, char *text); + + void (IMPORT *Com_VPrintf) (int print_level, const char *fmt, va_list argptr); + + // files will be memory mapped read only + // the returned buffer may be part of a larger pak file, + // or a discrete file from anywhere in the quake search path + // a -1 return means the file does not exist + // NULL can be passed for buf to just determine existance + int (IMPORT *FS_LoadFile) (char *name, void **buf); + void (IMPORT *FS_FreeFile) (void *buf); + + // gamedir will be the current directory that generated + // files should be stored to, ie: "f:\quake\id1" + char *(IMPORT *FS_Gamedir) (void); + + cvar_t *(IMPORT *Cvar_Get) (char *name, char *value, int flags); + cvar_t *(IMPORT *Cvar_Set) (char *name, char *value); + void (IMPORT *Cvar_SetValue) (char *name, float value); + + qboolean (IMPORT *Vid_GetModeInfo)(int *width, int *height, int mode); + void (IMPORT *Vid_MenuInit)( void ); + // called with image data of width*height pixel which comp bytes per pixel (must be 3 or 4 for RGB or RGBA) + // expects the pixels data to be row-wise, starting at top left + void (IMPORT *Vid_WriteScreenshot)( int width, int height, int comp, const void* data ); + + qboolean (IMPORT *GLimp_InitGraphics)(int fullscreen, int *pwidth, int *pheight); + qboolean (IMPORT *GLimp_GetDesktopMode)(int *pwidth, int *pheight); + + void (IMPORT *Vid_RequestRestart)(ref_restart_t rs); +} refimport_t; + +// this is the only function actually exported at the linker level +typedef refexport_t (EXPORT *GetRefAPI_t) (refimport_t); + +// FIXME: #ifdef client/ref around this +extern refexport_t re; +extern refimport_t ri; + +/* + * Refresh API + */ +void R_BeginRegistration(char *map); +void R_Clear(void); +struct model_s *R_RegisterModel(char *name); +struct image_s *R_RegisterSkin(char *name); +void R_SetSky(char *name, float rotate, vec3_t axis); +void R_EndRegistration(void); +struct image_s *Draw_FindPic(char *name); +void R_RenderFrame(refdef_t *fd); +void Draw_GetPicSize(int *w, int *h, char *name); + +void Draw_StretchPic(int x, int y, int w, int h, char *name); +void Draw_PicScaled(int x, int y, char *pic, float factor); + +void Draw_CharScaled(int x, int y, int num, float scale); +void Draw_TileClear(int x, int y, int w, int h, char *name); +void Draw_Fill(int x, int y, int w, int h, int c); +void Draw_FadeScreen(void); +void Draw_StretchRaw(int x, int y, int w, int h, int cols, int rows, byte *data); +//int R_Init(void *hinstance, void *hWnd); +//void R_Shutdown(void); +void R_SetPalette(const unsigned char *palette); +void R_BeginFrame(float camera_separation); +qboolean R_EndWorldRenderpass(void); +void R_EndFrame(void); + +#endif diff --git a/src/common/header/ref_shared.h b/src/common/header/ref_shared.h new file mode 100644 index 0000000..b6a1bec --- /dev/null +++ b/src/common/header/ref_shared.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 1997-2001 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. + * + * ======================================================================= + * + * Header shared between different refreshers (but not with client) + * + * ======================================================================= + */ + +#ifndef SRC_CLIENT_REFRESH_REF_SHARED_H_ +#define SRC_CLIENT_REFRESH_REF_SHARED_H_ + +#include "ref_api.h" + +/* + * skins will be outline flood filled and mip mapped + * pics and sprites with alpha will be outline flood filled + * pic won't be mip mapped + * + * model skin + * sprite frame + * wall texture + * pic + */ +typedef enum +{ + it_skin, + it_sprite, + it_wall, + it_pic, + it_sky +} imagetype_t; + +typedef enum +{ + mod_bad, + mod_brush, + mod_sprite, + mod_alias +} modtype_t; + +#define MAX_LBM_HEIGHT 480 + +extern void R_Printf(int level, const char* msg, ...) __attribute__ ((format (printf, 2, 3))); + +extern void LoadPCX(char *origname, byte **pic, byte **palette, int *width, int *height); +extern void GetPCXInfo(char *filename, int *width, int *height); + +extern qboolean LoadSTB(const char *origname, const char* type, byte **pic, int *width, int *height); +extern qboolean ResizeSTB(byte *input_pixels, int input_width, int input_height, + byte *output_pixels, int output_width, int output_height); +extern void SmoothColorImage(unsigned *dst, size_t size, size_t rstep); +extern void scale2x(byte *src, byte *dst, int width, int height); +extern void scale3x(byte *src, byte *dst, int width, int height); + +extern void GetWalInfo(char *name, int *width, int *height); +extern void GetM8Info(char *name, int *width, int *height); + +extern float Mod_RadiusFromBounds(const vec3_t mins, const vec3_t maxs); +extern byte* Mod_DecompressVis(byte *in, int row); +#endif /* SRC_CLIENT_REFRESH_REF_SHARED_H_ */ diff --git a/src/common/header/shared.h b/src/common/header/shared.h new file mode 100644 index 0000000..74b5088 --- /dev/null +++ b/src/common/header/shared.h @@ -0,0 +1,1189 @@ +/* + * Copyright (C) 1997-2001 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. + * + * ======================================================================= + * + * This is the main header file shared between client, renderer, server + * and the game. Do NOT edit this file unless you know what you're + * doing. Changes here may break the client <-> renderer <-> server + * <-> game API, leading to problems with mods! + * + * ======================================================================= + */ + +#ifndef COMMON_SHARED_H +#define COMMON_SHARED_H + +#include +#include +#include +#include +#include +#include +#include + +#ifdef true + #undef true +#endif + +#ifdef false + #undef false +#endif + +typedef enum {false, true} qboolean; +typedef unsigned char byte; + +#ifndef NULL + #define NULL ((void *)0) +#endif + +// stuff to align variables/arrays and for noreturn +#if __STDC_VERSION__ >= 201112L // C11 or newer + #define YQ2_ALIGNAS_SIZE(SIZE) _Alignas(SIZE) + #define YQ2_ALIGNAS_TYPE(TYPE) _Alignas(TYPE) + // must be used as prefix (YQ2_ATTR_NORETURN void bla();)! + #define YQ2_ATTR_NORETURN _Noreturn +#elif defined(__GNUC__) // GCC and clang should support this attribute + #define YQ2_ALIGNAS_SIZE(SIZE) __attribute__(( __aligned__(SIZE) )) + #define YQ2_ALIGNAS_TYPE(TYPE) __attribute__(( __aligned__(__alignof__(TYPE)) )) + // must be used as prefix (YQ2_ATTR_NORETURN void bla();)! + #define YQ2_ATTR_NORETURN __attribute__ ((noreturn)) +#elif defined(_MSC_VER) + #define YQ2_ALIGNAS_SIZE(SIZE) __declspec( align(SIZE) ) + #define YQ2_ALIGNAS_TYPE(TYPE) __declspec( align( __alignof(TYPE) ) ) + // must be used as prefix (YQ2_ATTR_NORETURN void bla();)! + #define YQ2_ATTR_NORETURN __declspec(noreturn) +#else + #warning "Please add a case for your compiler here to align correctly" + #define YQ2_ALIGNAS_TYPE(TYPE) + #define YQ2_ATTR_NORETURN +#endif + +#if defined(__GNUC__) + /* ISO C11 _Noreturn can't be attached to function pointers, so + * use the gcc/clang-specific version for function pointers, even + * in C11 mode. MSVC __declspec(noreturn) seems to have the same + * restriction as _Noreturn so can't be used here either. */ + #define YQ2_ATTR_NORETURN_FUNCPTR __attribute__ ((noreturn)) +#else + #define YQ2_ATTR_NORETURN_FUNCPTR /* nothing */ +#endif + +/* angle indexes */ +#define PITCH 0 /* up / down */ +#define YAW 1 /* left / right */ +#define ROLL 2 /* fall over */ + +#ifndef min +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef max +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +#define MAX_STRING_CHARS 2048 /* max length of a string passed to Cmd_TokenizeString */ +#define MAX_STRING_TOKENS 80 /* max tokens resulting from Cmd_TokenizeString */ +#define MAX_TOKEN_CHARS 1024 /* max length of an individual token */ + +#define MAX_QPATH 64 /* max length of a quake game pathname */ + +/* + * DG: For some stupid reason, SV_WriteServerFile() and SV_ReadeServerFile() used + * MAX_OSPATH as buffer length for CVAR_LATCH CVARS and saved the whole buffer + * into $game/save/current/server.ssv, so changing MAX_OSPATH breaks savegames... + * Unfortunately, for some other fucking reason MAX_OSPATH was 128 for non-Windows + * which is just horrible.. so I introduced LATCH_CVAR_SAVELENGTH with the stupid + * values so I could bump MAX_OSPATH. + * TODO: whenever you break savegame compatibility next, make + * LATCH_CVAR_SAVELENGTH system-independent (or remove it and hardcode a + * sensible value in the two functions) + */ + +#ifdef _WIN32 + #define MAX_OSPATH 256 /* max length of a filesystem pathname (same as MAX_PATH) */ + #define LATCH_CVAR_SAVELENGTH 256 + + // by default dlls don't export any functions, use this to + // make a function visible (for GetGameAPI(), GetRefAPI() and similar) + #define Q2_DLL_EXPORTED __declspec(dllexport) + +#else // not Win32 (Linux, BSD, Mac, ..) + + #define MAX_OSPATH 4096 /* max length of a filesystem pathname */ + #define LATCH_CVAR_SAVELENGTH 128 + + // by default our .so/.dylibs don't export any functions, use this to + // make a function visible (for GetGameAPI(), GetRefAPI() and similar) + #define Q2_DLL_EXPORTED __attribute__((__visibility__("default"))) +#endif + +/* per-level limits */ +#define MAX_CLIENTS 256 /* absolute limit */ +#define MAX_EDICTS 1024 /* must change protocol to increase more */ +#define MAX_LIGHTSTYLES 256 +#define MAX_MODELS 256 /* these are sent over the net as bytes */ +#define MAX_SOUNDS 256 /* so they cannot be blindly increased */ +#define MAX_IMAGES 256 +#define MAX_ITEMS 256 +#define MAX_GENERAL (MAX_CLIENTS * 2) /* general config strings */ + +/* game print flags */ +#define PRINT_LOW 0 /* pickup messages */ +#define PRINT_MEDIUM 1 /* death messages */ +#define PRINT_HIGH 2 /* critical messages */ +#define PRINT_CHAT 3 /* chat messages */ + +#define ERR_FATAL 0 /* exit the entire game with a popup window */ +#define ERR_DROP 1 /* print to console and disconnect from game */ +#define ERR_DISCONNECT 2 /* don't kill server */ + +#define PRINT_ALL 0 +#define PRINT_DEVELOPER 1 /* only print when "developer 1" */ +#define PRINT_ALERT 2 + +/* destination class for gi.multicast() */ +typedef enum +{ + MULTICAST_ALL, + MULTICAST_PHS, + MULTICAST_PVS, + MULTICAST_ALL_R, + MULTICAST_PHS_R, + MULTICAST_PVS_R +} multicast_t; + +/* + * ============================================================== + * + * MATHLIB + * + * ============================================================== + */ + +typedef float vec_t; +typedef vec_t vec3_t[3]; +typedef vec_t vec5_t[5]; + +typedef int fixed4_t; +typedef int fixed8_t; +typedef int fixed16_t; + +#ifndef M_PI + #define M_PI 3.14159265358979323846 /* matches value in gcc v2 math.h */ +#endif + +struct cplane_s; + +extern vec3_t vec3_origin; + +#define nanmask (255 << 23) + +#define IS_NAN(x) (((*(int *)&x) & nanmask) == nanmask) + +// FIXME: use int instead of long, it's only used with int anyway? +#define Q_ftol(f) (long)(f) + +#define DotProduct(x, y) (x[0] * y[0] + x[1] * y[1] + x[2] * y[2]) +#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] = a[1] = a[2] = 0) +#define VectorNegate(a, b) (b[0] = -a[0], b[1] = -a[1], b[2] = -a[2]) +#define VectorSet(v, x, y, z) (v[0] = (x), v[1] = (y), v[2] = (z)) + +void VectorMA(vec3_t veca, float scale, vec3_t vecb, vec3_t vecc); + +/* just in case you do't want to use the macros */ +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); + +void ClearBounds(vec3_t mins, vec3_t maxs); +void AddPointToBounds(vec3_t v, vec3_t mins, vec3_t maxs); +int VectorCompare(vec3_t v1, vec3_t v2); +vec_t VectorLength(vec3_t v); +void CrossProduct(vec3_t v1, vec3_t v2, vec3_t cross); +vec_t VectorNormalize(vec3_t v); /* returns vector length */ +vec_t VectorNormalize2(vec3_t v, vec3_t out); +void VectorInverse(vec3_t v); +void VectorScale(vec3_t in, vec_t scale, vec3_t out); +int Q_log2(int val); + +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(vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); +void AngleVectors2(vec3_t value1, vec3_t angles); +int BoxOnPlaneSide(vec3_t emins, vec3_t emaxs, struct cplane_s *plane); +float anglemod(float a); +float LerpAngle(float a1, float a2, float frac); + +#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))) + +void ProjectPointOnPlane(vec3_t dst, const vec3_t p, const vec3_t normal); +void PerpendicularVector(vec3_t dst, const vec3_t src); +void RotatePointAroundVector(vec3_t dst, + const vec3_t dir, + const vec3_t point, + float degrees); + +/* ============================================= */ + +char *COM_SkipPath(char *pathname); +void COM_StripExtension(char *in, char *out); +const char *COM_FileExtension(const char *in); +void COM_FileBase(char *in, char *out); +void COM_FilePath(const char *in, char *out); +void COM_DefaultExtension(char *path, const char *extension); + +char *COM_Parse(char **data_p); + +/* data is an in/out parm, returns a parsed out token */ +void Com_sprintf(char *dest, int size, char *fmt, ...); + +void Com_PageInMemory(byte *buffer, int size); + +/* ============================================= */ + +/* portable case insensitive compare */ +int Q_stricmp(const char *s1, const char *s2); +int Q_strcasecmp(char *s1, char *s2); +int Q_strncasecmp(char *s1, char *s2, int n); + +/* portable string lowercase */ +char *Q_strlwr(char *s); + +/* portable safe string copy/concatenate */ +int Q_strlcpy(char *dst, const char *src, int size); +int Q_strlcat(char *dst, const char *src, int size); + +/* ============================================= */ + +/* Unicode wrappers that also make sure it's a regular file around fopen(). */ +FILE *Q_fopen(const char *file, const char *mode); + +/* Comparator function for qsort(), compares strings. */ +int Q_sort_strcomp(const void *s1, const void *s2); + +/* ============================================= */ + +short BigShort(short l); +short LittleShort(short l); +int BigLong(int l); +int LittleLong(int l); +float BigFloat(float l); +float LittleFloat(float l); + +void Swap_Init(void); +char *va(char *format, ...) __attribute__ ((format (printf, 1, 2))); + +/* ============================================= */ + +/* key / value info strings */ +#define MAX_INFO_KEY 64 +#define MAX_INFO_VALUE 64 +#define MAX_INFO_STRING 512 + +char *Info_ValueForKey(char *s, char *key); +void Info_RemoveKey(char *s, char *key); +void Info_SetValueForKey(char *s, char *key, char *value); +qboolean Info_Validate(char *s); + +/* ============================================= */ + +/* Random number generator */ +int randk(void); +float frandk(void); +float crandk(void); +void randk_seed(void); + +/* + * ============================================================== + * + * SYSTEM SPECIFIC + * + * ============================================================== + */ + +extern int curtime; /* time returned by last Sys_Milliseconds */ + +int Sys_Milliseconds(void); +void Sys_Mkdir(const char *path); +qboolean Sys_IsDir(const char *path); +qboolean Sys_IsFile(const char *path); + +/* large block stack allocation routines */ +void *Hunk_Begin(int maxsize); +void *Hunk_Alloc(int size); +void Hunk_Free(void *buf); +int Hunk_End(void); + +/* directory searching */ +#define SFF_ARCH 0x01 +#define SFF_HIDDEN 0x02 +#define SFF_RDONLY 0x04 +#define SFF_SUBDIR 0x08 +#define SFF_SYSTEM 0x10 + +/* pass in an attribute mask of things you wish to REJECT */ +char *Sys_FindFirst(char *path, unsigned musthave, unsigned canthave); +char *Sys_FindNext(unsigned musthave, unsigned canthave); +void Sys_FindClose(void); + +/* this is only here so the functions in shared source files can link */ +YQ2_ATTR_NORETURN void Sys_Error(char *error, ...); +void Com_Printf(char *msg, ...); + +/* + * ========================================================== + * + * CVARS (console variables) + * + * ========================================================== + */ + +#ifndef CVAR + #define CVAR + + #define CVAR_ARCHIVE 1 /* set to cause it to be saved to vars.rc */ + #define CVAR_USERINFO 2 /* added to userinfo when changed */ + #define CVAR_SERVERINFO 4 /* added to serverinfo when changed */ + #define CVAR_NOSET 8 /* don't allow change from console at all, */ + /* but can be set from the command line */ + #define CVAR_LATCH 16 /* save changes until server restart */ + +/* nothing outside the Cvar_*() functions should modify these fields! */ +typedef struct cvar_s +{ + char *name; + char *string; + char *latched_string; /* for CVAR_LATCH vars */ + int flags; + qboolean modified; /* set each time the cvar is changed */ + float value; + struct cvar_s *next; + + /* Added by YQ2. Must be at the end to preserve ABI. */ + char *default_string; +} cvar_t; + +#endif /* CVAR */ + +/* + * ============================================================== + * + * COLLISION DETECTION + * + * ============================================================== + */ + +/* lower bits are stronger, and will eat weaker brushes completely */ +#define CONTENTS_SOLID 1 /* an eye is never valid in a solid */ +#define CONTENTS_WINDOW 2 /* translucent, but not watery */ +#define CONTENTS_AUX 4 +#define CONTENTS_LAVA 8 +#define CONTENTS_SLIME 16 +#define CONTENTS_WATER 32 +#define CONTENTS_MIST 64 +#define LAST_VISIBLE_CONTENTS 64 + +/* remaining contents are non-visible, and don't eat brushes */ +#define CONTENTS_AREAPORTAL 0x8000 + +#define CONTENTS_PLAYERCLIP 0x10000 +#define CONTENTS_MONSTERCLIP 0x20000 + +/* currents can be added to any other contents, and may be mixed */ +#define CONTENTS_CURRENT_0 0x40000 +#define CONTENTS_CURRENT_90 0x80000 +#define CONTENTS_CURRENT_180 0x100000 +#define CONTENTS_CURRENT_270 0x200000 +#define CONTENTS_CURRENT_UP 0x400000 +#define CONTENTS_CURRENT_DOWN 0x800000 + +#define CONTENTS_ORIGIN 0x1000000 /* removed before bsping an entity */ + +#define CONTENTS_MONSTER 0x2000000 /* should never be on a brush, only in game */ +#define CONTENTS_DEADMONSTER 0x4000000 +#define CONTENTS_DETAIL 0x8000000 /* brushes to be added after vis leafs */ +#define CONTENTS_TRANSLUCENT 0x10000000 /* auto set if any surface has trans */ +#define CONTENTS_LADDER 0x20000000 + +#define SURF_LIGHT 0x1 /* value will hold the light strength */ + +#define SURF_SLICK 0x2 /* effects game physics */ + +#define SURF_SKY 0x4 /* don't draw, but add to skybox */ +#define SURF_WARP 0x8 /* turbulent water warp */ +#define SURF_TRANS33 0x10 +#define SURF_TRANS66 0x20 +#define SURF_FLOWING 0x40 /* scroll towards angle */ +#define SURF_NODRAW 0x80 /* don't bother referencing the texture */ + +/* content masks */ +#define MASK_ALL (-1) +#define MASK_SOLID (CONTENTS_SOLID | CONTENTS_WINDOW) +#define MASK_PLAYERSOLID \ + (CONTENTS_SOLID | CONTENTS_PLAYERCLIP | \ + CONTENTS_WINDOW | CONTENTS_MONSTER) +#define MASK_DEADSOLID (CONTENTS_SOLID | CONTENTS_PLAYERCLIP | CONTENTS_WINDOW) +#define MASK_MONSTERSOLID \ + (CONTENTS_SOLID | CONTENTS_MONSTERCLIP | \ + CONTENTS_WINDOW | CONTENTS_MONSTER) +#define MASK_WATER (CONTENTS_WATER | CONTENTS_LAVA | CONTENTS_SLIME) +#define MASK_OPAQUE (CONTENTS_SOLID | CONTENTS_SLIME | CONTENTS_LAVA) +#define MASK_SHOT \ + (CONTENTS_SOLID | CONTENTS_MONSTER | CONTENTS_WINDOW | \ + CONTENTS_DEADMONSTER) +#define MASK_CURRENT \ + (CONTENTS_CURRENT_0 | CONTENTS_CURRENT_90 | \ + CONTENTS_CURRENT_180 | CONTENTS_CURRENT_270 | \ + CONTENTS_CURRENT_UP | \ + CONTENTS_CURRENT_DOWN) + +/* gi.BoxEdicts() can return a list of either solid or trigger entities */ +#define AREA_SOLID 1 +#define AREA_TRIGGERS 2 + +/* plane_t structure */ +typedef struct cplane_s +{ + vec3_t normal; + float dist; + byte type; /* for fast side tests */ + byte signbits; /* signx + (signy<<1) + (signz<<2) */ + byte pad[2]; +} cplane_t; + +/* structure offset for asm code */ +#define CPLANE_NORMAL_X 0 +#define CPLANE_NORMAL_Y 4 +#define CPLANE_NORMAL_Z 8 +#define CPLANE_DIST 12 +#define CPLANE_TYPE 16 +#define CPLANE_SIGNBITS 17 +#define CPLANE_PAD0 18 +#define CPLANE_PAD1 19 + +typedef struct cmodel_s +{ + vec3_t mins, maxs; + vec3_t origin; /* for sounds or lights */ + int headnode; +} cmodel_t; + +typedef struct csurface_s +{ + char name[16]; + int flags; /* SURF_* */ + int value; /* unused */ +} csurface_t; + +typedef struct mapsurface_s /* used internally due to name len probs */ +{ + csurface_t c; + char rname[32]; +} mapsurface_t; + +/* a trace is returned when a box is swept through the world */ +typedef struct +{ + qboolean allsolid; /* if true, plane is not valid */ + qboolean startsolid; /* if true, the initial point was in a solid area */ + float fraction; /* time completed, 1.0 = didn't hit anything */ + vec3_t endpos; /* final position */ + cplane_t plane; /* surface normal at impact */ + csurface_t *surface; /* surface hit */ + int contents; /* contents on other side of surface hit */ + struct edict_s *ent; /* not set by CM_*() functions */ +} trace_t; + +/* pmove_state_t is the information necessary for client side movement */ +/* prediction */ +typedef enum +{ + /* can accelerate and turn */ + PM_NORMAL, + PM_SPECTATOR, + /* no acceleration or turning */ + PM_DEAD, + PM_GIB, /* different bounding box */ + PM_FREEZE +} pmtype_t; + +/* pmove->pm_flags */ +#define PMF_DUCKED 1 +#define PMF_JUMP_HELD 2 +#define PMF_ON_GROUND 4 +#define PMF_TIME_WATERJUMP 8 /* pm_time is waterjump */ +#define PMF_TIME_LAND 16 /* pm_time is time before rejump */ +#define PMF_TIME_TELEPORT 32 /* pm_time is non-moving time */ +#define PMF_NO_PREDICTION 64 /* temporarily disables prediction (used for grappling hook) */ + +/* this structure needs to be communicated bit-accurate/ + * from the server to the client to guarantee that + * prediction stays in sync, so no floats are used. + * if any part of the game code modifies this struct, it + * will result in a prediction error of some degree. */ +typedef struct +{ + pmtype_t pm_type; + + short origin[3]; /* 12.3 */ + short velocity[3]; /* 12.3 */ + byte pm_flags; /* ducked, jump_held, etc */ + byte pm_time; /* each unit = 8 ms */ + short gravity; + short delta_angles[3]; /* add to command angles to get view direction + * changed by spawns, rotating objects, and teleporters */ +} pmove_state_t; + +/* button bits */ +#define BUTTON_ATTACK 1 +#define BUTTON_USE 2 +#define BUTTON_ANY 128 /* any key whatsoever */ + +/* usercmd_t is sent to the server each client frame */ +typedef struct usercmd_s +{ + byte msec; + byte buttons; + short angles[3]; + short forwardmove, sidemove, upmove; + byte impulse; /* remove? */ + byte lightlevel; /* light level the player is standing on */ +} usercmd_t; + +#define MAXTOUCH 32 +typedef struct +{ + /* state (in / out) */ + pmove_state_t s; + + /* command (in) */ + usercmd_t cmd; + qboolean snapinitial; /* if s has been changed outside pmove */ + + /* results (out) */ + int numtouch; + struct edict_s *touchents[MAXTOUCH]; + + vec3_t viewangles; /* clamped */ + float viewheight; + + vec3_t mins, maxs; /* bounding box size */ + + struct edict_s *groundentity; + int watertype; + int waterlevel; + + /* callbacks to test the world */ + trace_t (*trace)(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end); + int (*pointcontents)(vec3_t point); +} pmove_t; + +/* entity_state_t->effects + * Effects are things handled on the client side (lights, particles, + * frame animations) that happen constantly on the given entity. + * An entity that has effects will be sent to the client even if + * it has a zero index model. */ +#define EF_ROTATE 0x00000001 /* rotate (bonus items) */ +#define EF_GIB 0x00000002 /* leave a trail */ +#define EF_BLASTER 0x00000008 /* redlight + trail */ +#define EF_ROCKET 0x00000010 /* redlight + trail */ +#define EF_GRENADE 0x00000020 +#define EF_HYPERBLASTER 0x00000040 +#define EF_BFG 0x00000080 +#define EF_COLOR_SHELL 0x00000100 +#define EF_POWERSCREEN 0x00000200 +#define EF_ANIM01 0x00000400 /* automatically cycle between frames 0 and 1 at 2 hz */ +#define EF_ANIM23 0x00000800 /* automatically cycle between frames 2 and 3 at 2 hz */ +#define EF_ANIM_ALL 0x00001000 /* automatically cycle through all frames at 2hz */ +#define EF_ANIM_ALLFAST 0x00002000 /* automatically cycle through all frames at 10hz */ +#define EF_FLIES 0x00004000 +#define EF_QUAD 0x00008000 +#define EF_PENT 0x00010000 +#define EF_TELEPORTER 0x00020000 /* particle fountain */ +#define EF_FLAG1 0x00040000 +#define EF_FLAG2 0x00080000 +#define EF_IONRIPPER 0x00100000 +#define EF_GREENGIB 0x00200000 +#define EF_BLUEHYPERBLASTER 0x00400000 +#define EF_SPINNINGLIGHTS 0x00800000 +#define EF_PLASMA 0x01000000 +#define EF_TRAP 0x02000000 +#define EF_TRACKER 0x04000000 +#define EF_DOUBLE 0x08000000 +#define EF_SPHERETRANS 0x10000000 +#define EF_TAGTRAIL 0x20000000 +#define EF_HALF_DAMAGE 0x40000000 +#define EF_TRACKERTRAIL 0x80000000 + +/* entity_state_t->renderfx flags */ +#define RF_MINLIGHT 1 /* allways have some light (viewmodel) */ +#define RF_VIEWERMODEL 2 /* don't draw through eyes, only mirrors */ +#define RF_WEAPONMODEL 4 /* only draw through eyes */ +#define RF_FULLBRIGHT 8 /* allways draw full intensity */ +#define RF_DEPTHHACK 16 /* for view weapon Z crunching */ +#define RF_TRANSLUCENT 32 +#define RF_FRAMELERP 64 +#define RF_BEAM 128 +#define RF_CUSTOMSKIN 256 /* skin is an index in image_precache */ +#define RF_GLOW 512 /* pulse lighting for bonus items */ +#define RF_SHELL_RED 1024 +#define RF_SHELL_GREEN 2048 +#define RF_SHELL_BLUE 4096 +#define RF_NOSHADOW 8192 /* don't draw a shadow */ +#define RF_IR_VISIBLE 0x00008000 /* 32768 */ +#define RF_SHELL_DOUBLE 0x00010000 /* 65536 */ +#define RF_SHELL_HALF_DAM 0x00020000 +#define RF_USE_DISGUISE 0x00040000 + +/* player_state_t->refdef flags */ +#define RDF_UNDERWATER 1 /* warp the screen as apropriate */ +#define RDF_NOWORLDMODEL 2 /* used for player configuration screen */ +#define RDF_IRGOGGLES 4 +#define RDF_UVGOGGLES 8 + +/* muzzle flashes / player effects */ +#define MZ_BLASTER 0 +#define MZ_MACHINEGUN 1 +#define MZ_SHOTGUN 2 +#define MZ_CHAINGUN1 3 +#define MZ_CHAINGUN2 4 +#define MZ_CHAINGUN3 5 +#define MZ_RAILGUN 6 +#define MZ_ROCKET 7 +#define MZ_GRENADE 8 +#define MZ_LOGIN 9 +#define MZ_LOGOUT 10 +#define MZ_RESPAWN 11 +#define MZ_BFG 12 +#define MZ_SSHOTGUN 13 +#define MZ_HYPERBLASTER 14 +#define MZ_ITEMRESPAWN 15 +#define MZ_IONRIPPER 16 +#define MZ_BLUEHYPERBLASTER 17 +#define MZ_PHALANX 18 +#define MZ_SILENCED 128 /* bit flag ORed with one of the above numbers */ +#define MZ_ETF_RIFLE 30 +#define MZ_UNUSED 31 +#define MZ_SHOTGUN2 32 +#define MZ_HEATBEAM 33 +#define MZ_BLASTER2 34 +#define MZ_TRACKER 35 +#define MZ_NUKE1 36 +#define MZ_NUKE2 37 +#define MZ_NUKE4 38 +#define MZ_NUKE8 39 + +/* monster muzzle flashes */ +#define MZ2_TANK_BLASTER_1 1 +#define MZ2_TANK_BLASTER_2 2 +#define MZ2_TANK_BLASTER_3 3 +#define MZ2_TANK_MACHINEGUN_1 4 +#define MZ2_TANK_MACHINEGUN_2 5 +#define MZ2_TANK_MACHINEGUN_3 6 +#define MZ2_TANK_MACHINEGUN_4 7 +#define MZ2_TANK_MACHINEGUN_5 8 +#define MZ2_TANK_MACHINEGUN_6 9 +#define MZ2_TANK_MACHINEGUN_7 10 +#define MZ2_TANK_MACHINEGUN_8 11 +#define MZ2_TANK_MACHINEGUN_9 12 +#define MZ2_TANK_MACHINEGUN_10 13 +#define MZ2_TANK_MACHINEGUN_11 14 +#define MZ2_TANK_MACHINEGUN_12 15 +#define MZ2_TANK_MACHINEGUN_13 16 +#define MZ2_TANK_MACHINEGUN_14 17 +#define MZ2_TANK_MACHINEGUN_15 18 +#define MZ2_TANK_MACHINEGUN_16 19 +#define MZ2_TANK_MACHINEGUN_17 20 +#define MZ2_TANK_MACHINEGUN_18 21 +#define MZ2_TANK_MACHINEGUN_19 22 +#define MZ2_TANK_ROCKET_1 23 +#define MZ2_TANK_ROCKET_2 24 +#define MZ2_TANK_ROCKET_3 25 + +#define MZ2_INFANTRY_MACHINEGUN_1 26 +#define MZ2_INFANTRY_MACHINEGUN_2 27 +#define MZ2_INFANTRY_MACHINEGUN_3 28 +#define MZ2_INFANTRY_MACHINEGUN_4 29 +#define MZ2_INFANTRY_MACHINEGUN_5 30 +#define MZ2_INFANTRY_MACHINEGUN_6 31 +#define MZ2_INFANTRY_MACHINEGUN_7 32 +#define MZ2_INFANTRY_MACHINEGUN_8 33 +#define MZ2_INFANTRY_MACHINEGUN_9 34 +#define MZ2_INFANTRY_MACHINEGUN_10 35 +#define MZ2_INFANTRY_MACHINEGUN_11 36 +#define MZ2_INFANTRY_MACHINEGUN_12 37 +#define MZ2_INFANTRY_MACHINEGUN_13 38 + +#define MZ2_SOLDIER_BLASTER_1 39 +#define MZ2_SOLDIER_BLASTER_2 40 +#define MZ2_SOLDIER_SHOTGUN_1 41 +#define MZ2_SOLDIER_SHOTGUN_2 42 +#define MZ2_SOLDIER_MACHINEGUN_1 43 +#define MZ2_SOLDIER_MACHINEGUN_2 44 + +#define MZ2_GUNNER_MACHINEGUN_1 45 +#define MZ2_GUNNER_MACHINEGUN_2 46 +#define MZ2_GUNNER_MACHINEGUN_3 47 +#define MZ2_GUNNER_MACHINEGUN_4 48 +#define MZ2_GUNNER_MACHINEGUN_5 49 +#define MZ2_GUNNER_MACHINEGUN_6 50 +#define MZ2_GUNNER_MACHINEGUN_7 51 +#define MZ2_GUNNER_MACHINEGUN_8 52 +#define MZ2_GUNNER_GRENADE_1 53 +#define MZ2_GUNNER_GRENADE_2 54 +#define MZ2_GUNNER_GRENADE_3 55 +#define MZ2_GUNNER_GRENADE_4 56 + +#define MZ2_CHICK_ROCKET_1 57 + +#define MZ2_FLYER_BLASTER_1 58 +#define MZ2_FLYER_BLASTER_2 59 + +#define MZ2_MEDIC_BLASTER_1 60 + +#define MZ2_GLADIATOR_RAILGUN_1 61 + +#define MZ2_HOVER_BLASTER_1 62 + +#define MZ2_ACTOR_MACHINEGUN_1 63 + +#define MZ2_SUPERTANK_MACHINEGUN_1 64 +#define MZ2_SUPERTANK_MACHINEGUN_2 65 +#define MZ2_SUPERTANK_MACHINEGUN_3 66 +#define MZ2_SUPERTANK_MACHINEGUN_4 67 +#define MZ2_SUPERTANK_MACHINEGUN_5 68 +#define MZ2_SUPERTANK_MACHINEGUN_6 69 +#define MZ2_SUPERTANK_ROCKET_1 70 +#define MZ2_SUPERTANK_ROCKET_2 71 +#define MZ2_SUPERTANK_ROCKET_3 72 + +#define MZ2_BOSS2_MACHINEGUN_L1 73 +#define MZ2_BOSS2_MACHINEGUN_L2 74 +#define MZ2_BOSS2_MACHINEGUN_L3 75 +#define MZ2_BOSS2_MACHINEGUN_L4 76 +#define MZ2_BOSS2_MACHINEGUN_L5 77 +#define MZ2_BOSS2_ROCKET_1 78 +#define MZ2_BOSS2_ROCKET_2 79 +#define MZ2_BOSS2_ROCKET_3 80 +#define MZ2_BOSS2_ROCKET_4 81 + +#define MZ2_FLOAT_BLASTER_1 82 + +#define MZ2_SOLDIER_BLASTER_3 83 +#define MZ2_SOLDIER_SHOTGUN_3 84 +#define MZ2_SOLDIER_MACHINEGUN_3 85 +#define MZ2_SOLDIER_BLASTER_4 86 +#define MZ2_SOLDIER_SHOTGUN_4 87 +#define MZ2_SOLDIER_MACHINEGUN_4 88 +#define MZ2_SOLDIER_BLASTER_5 89 +#define MZ2_SOLDIER_SHOTGUN_5 90 +#define MZ2_SOLDIER_MACHINEGUN_5 91 +#define MZ2_SOLDIER_BLASTER_6 92 +#define MZ2_SOLDIER_SHOTGUN_6 93 +#define MZ2_SOLDIER_MACHINEGUN_6 94 +#define MZ2_SOLDIER_BLASTER_7 95 +#define MZ2_SOLDIER_SHOTGUN_7 96 +#define MZ2_SOLDIER_MACHINEGUN_7 97 +#define MZ2_SOLDIER_BLASTER_8 98 +#define MZ2_SOLDIER_SHOTGUN_8 99 +#define MZ2_SOLDIER_MACHINEGUN_8 100 + +#define MZ2_MAKRON_BFG 101 +#define MZ2_MAKRON_BLASTER_1 102 +#define MZ2_MAKRON_BLASTER_2 103 +#define MZ2_MAKRON_BLASTER_3 104 +#define MZ2_MAKRON_BLASTER_4 105 +#define MZ2_MAKRON_BLASTER_5 106 +#define MZ2_MAKRON_BLASTER_6 107 +#define MZ2_MAKRON_BLASTER_7 108 +#define MZ2_MAKRON_BLASTER_8 109 +#define MZ2_MAKRON_BLASTER_9 110 +#define MZ2_MAKRON_BLASTER_10 111 +#define MZ2_MAKRON_BLASTER_11 112 +#define MZ2_MAKRON_BLASTER_12 113 +#define MZ2_MAKRON_BLASTER_13 114 +#define MZ2_MAKRON_BLASTER_14 115 +#define MZ2_MAKRON_BLASTER_15 116 +#define MZ2_MAKRON_BLASTER_16 117 +#define MZ2_MAKRON_BLASTER_17 118 +#define MZ2_MAKRON_RAILGUN_1 119 +#define MZ2_JORG_MACHINEGUN_L1 120 +#define MZ2_JORG_MACHINEGUN_L2 121 +#define MZ2_JORG_MACHINEGUN_L3 122 +#define MZ2_JORG_MACHINEGUN_L4 123 +#define MZ2_JORG_MACHINEGUN_L5 124 +#define MZ2_JORG_MACHINEGUN_L6 125 +#define MZ2_JORG_MACHINEGUN_R1 126 +#define MZ2_JORG_MACHINEGUN_R2 127 +#define MZ2_JORG_MACHINEGUN_R3 128 +#define MZ2_JORG_MACHINEGUN_R4 129 +#define MZ2_JORG_MACHINEGUN_R5 130 +#define MZ2_JORG_MACHINEGUN_R6 131 +#define MZ2_JORG_BFG_1 132 +#define MZ2_BOSS2_MACHINEGUN_R1 133 +#define MZ2_BOSS2_MACHINEGUN_R2 134 +#define MZ2_BOSS2_MACHINEGUN_R3 135 +#define MZ2_BOSS2_MACHINEGUN_R4 136 +#define MZ2_BOSS2_MACHINEGUN_R5 137 + +#define MZ2_CARRIER_MACHINEGUN_L1 138 +#define MZ2_CARRIER_MACHINEGUN_R1 139 +#define MZ2_CARRIER_GRENADE 140 +#define MZ2_TURRET_MACHINEGUN 141 +#define MZ2_TURRET_ROCKET 142 +#define MZ2_TURRET_BLASTER 143 +#define MZ2_STALKER_BLASTER 144 +#define MZ2_DAEDALUS_BLASTER 145 +#define MZ2_MEDIC_BLASTER_2 146 +#define MZ2_CARRIER_RAILGUN 147 +#define MZ2_WIDOW_DISRUPTOR 148 +#define MZ2_WIDOW_BLASTER 149 +#define MZ2_WIDOW_RAIL 150 +#define MZ2_WIDOW_PLASMABEAM 151 +#define MZ2_CARRIER_MACHINEGUN_L2 152 +#define MZ2_CARRIER_MACHINEGUN_R2 153 +#define MZ2_WIDOW_RAIL_LEFT 154 +#define MZ2_WIDOW_RAIL_RIGHT 155 +#define MZ2_WIDOW_BLASTER_SWEEP1 156 +#define MZ2_WIDOW_BLASTER_SWEEP2 157 +#define MZ2_WIDOW_BLASTER_SWEEP3 158 +#define MZ2_WIDOW_BLASTER_SWEEP4 159 +#define MZ2_WIDOW_BLASTER_SWEEP5 160 +#define MZ2_WIDOW_BLASTER_SWEEP6 161 +#define MZ2_WIDOW_BLASTER_SWEEP7 162 +#define MZ2_WIDOW_BLASTER_SWEEP8 163 +#define MZ2_WIDOW_BLASTER_SWEEP9 164 +#define MZ2_WIDOW_BLASTER_100 165 +#define MZ2_WIDOW_BLASTER_90 166 +#define MZ2_WIDOW_BLASTER_80 167 +#define MZ2_WIDOW_BLASTER_70 168 +#define MZ2_WIDOW_BLASTER_60 169 +#define MZ2_WIDOW_BLASTER_50 170 +#define MZ2_WIDOW_BLASTER_40 171 +#define MZ2_WIDOW_BLASTER_30 172 +#define MZ2_WIDOW_BLASTER_20 173 +#define MZ2_WIDOW_BLASTER_10 174 +#define MZ2_WIDOW_BLASTER_0 175 +#define MZ2_WIDOW_BLASTER_10L 176 +#define MZ2_WIDOW_BLASTER_20L 177 +#define MZ2_WIDOW_BLASTER_30L 178 +#define MZ2_WIDOW_BLASTER_40L 179 +#define MZ2_WIDOW_BLASTER_50L 180 +#define MZ2_WIDOW_BLASTER_60L 181 +#define MZ2_WIDOW_BLASTER_70L 182 +#define MZ2_WIDOW_RUN_1 183 +#define MZ2_WIDOW_RUN_2 184 +#define MZ2_WIDOW_RUN_3 185 +#define MZ2_WIDOW_RUN_4 186 +#define MZ2_WIDOW_RUN_5 187 +#define MZ2_WIDOW_RUN_6 188 +#define MZ2_WIDOW_RUN_7 189 +#define MZ2_WIDOW_RUN_8 190 +#define MZ2_CARRIER_ROCKET_1 191 +#define MZ2_CARRIER_ROCKET_2 192 +#define MZ2_CARRIER_ROCKET_3 193 +#define MZ2_CARRIER_ROCKET_4 194 +#define MZ2_WIDOW2_BEAMER_1 195 +#define MZ2_WIDOW2_BEAMER_2 196 +#define MZ2_WIDOW2_BEAMER_3 197 +#define MZ2_WIDOW2_BEAMER_4 198 +#define MZ2_WIDOW2_BEAMER_5 199 +#define MZ2_WIDOW2_BEAM_SWEEP_1 200 +#define MZ2_WIDOW2_BEAM_SWEEP_2 201 +#define MZ2_WIDOW2_BEAM_SWEEP_3 202 +#define MZ2_WIDOW2_BEAM_SWEEP_4 203 +#define MZ2_WIDOW2_BEAM_SWEEP_5 204 +#define MZ2_WIDOW2_BEAM_SWEEP_6 205 +#define MZ2_WIDOW2_BEAM_SWEEP_7 206 +#define MZ2_WIDOW2_BEAM_SWEEP_8 207 +#define MZ2_WIDOW2_BEAM_SWEEP_9 208 +#define MZ2_WIDOW2_BEAM_SWEEP_10 209 +#define MZ2_WIDOW2_BEAM_SWEEP_11 210 + +extern vec3_t monster_flash_offset[]; + +/* Temp entity events are for things that happen + * at a location seperate from any existing entity. + * Temporary entity messages are explicitly constructed + * and broadcast. */ +typedef enum +{ + TE_GUNSHOT, + TE_BLOOD, + TE_BLASTER, + TE_RAILTRAIL, + TE_SHOTGUN, + TE_EXPLOSION1, + TE_EXPLOSION2, + TE_ROCKET_EXPLOSION, + TE_GRENADE_EXPLOSION, + TE_SPARKS, + TE_SPLASH, + TE_BUBBLETRAIL, + TE_SCREEN_SPARKS, + TE_SHIELD_SPARKS, + TE_BULLET_SPARKS, + TE_LASER_SPARKS, + TE_PARASITE_ATTACK, + TE_ROCKET_EXPLOSION_WATER, + TE_GRENADE_EXPLOSION_WATER, + TE_MEDIC_CABLE_ATTACK, + TE_BFG_EXPLOSION, + TE_BFG_BIGEXPLOSION, + TE_BOSSTPORT, /* used as '22' in a map, so DON'T RENUMBER!!! */ + TE_BFG_LASER, + TE_GRAPPLE_CABLE, + TE_WELDING_SPARKS, + TE_GREENBLOOD, + TE_BLUEHYPERBLASTER, + TE_PLASMA_EXPLOSION, + TE_TUNNEL_SPARKS, + TE_BLASTER2, + TE_RAILTRAIL2, + TE_FLAME, + TE_LIGHTNING, + TE_DEBUGTRAIL, + TE_PLAIN_EXPLOSION, + TE_FLASHLIGHT, + TE_FORCEWALL, + TE_HEATBEAM, + TE_MONSTER_HEATBEAM, + TE_STEAM, + TE_BUBBLETRAIL2, + TE_MOREBLOOD, + TE_HEATBEAM_SPARKS, + TE_HEATBEAM_STEAM, + TE_CHAINFIST_SMOKE, + TE_ELECTRIC_SPARKS, + TE_TRACKER_EXPLOSION, + TE_TELEPORT_EFFECT, + TE_DBALL_GOAL, + TE_WIDOWBEAMOUT, + TE_NUKEBLAST, + TE_WIDOWSPLASH, + TE_EXPLOSION1_BIG, + TE_EXPLOSION1_NP, + TE_FLECHETTE +} temp_event_t; + +#define SPLASH_UNKNOWN 0 +#define SPLASH_SPARKS 1 +#define SPLASH_BLUE_WATER 2 +#define SPLASH_BROWN_WATER 3 +#define SPLASH_SLIME 4 +#define SPLASH_LAVA 5 +#define SPLASH_BLOOD 6 + +/* sound channels: + * channel 0 never willingly overrides + * other channels (1-7) allways override + * a playing sound on that channel */ +#define CHAN_AUTO 0 +#define CHAN_WEAPON 1 +#define CHAN_VOICE 2 +#define CHAN_ITEM 3 +#define CHAN_BODY 4 +/* modifier flags */ +#define CHAN_NO_PHS_ADD 8 /* send to all clients, not just ones in PHS (ATTN 0 will also do this) */ +#define CHAN_RELIABLE 16 /* send by reliable message, not datagram */ + +/* sound attenuation values */ +#define ATTN_NONE 0 /* full volume the entire level */ +#define ATTN_NORM 1 +#define ATTN_IDLE 2 +#define ATTN_STATIC 3 /* diminish very rapidly with distance */ + +/* player_state->stats[] indexes */ +#define STAT_HEALTH_ICON 0 +#define STAT_HEALTH 1 +#define STAT_AMMO_ICON 2 +#define STAT_AMMO 3 +#define STAT_ARMOR_ICON 4 +#define STAT_ARMOR 5 +#define STAT_SELECTED_ICON 6 +#define STAT_PICKUP_ICON 7 +#define STAT_PICKUP_STRING 8 +#define STAT_TIMER_ICON 9 +#define STAT_TIMER 10 +#define STAT_HELPICON 11 +#define STAT_SELECTED_ITEM 12 +#define STAT_LAYOUTS 13 +#define STAT_FRAGS 14 +#define STAT_FLASHES 15 /* cleared each frame, 1 = health, 2 = armor */ +#define STAT_CHASE 16 +#define STAT_SPECTATOR 17 + +#define MAX_STATS 32 + +/* dmflags->value flags */ +#define DF_NO_HEALTH 0x00000001 /* 1 */ +#define DF_NO_ITEMS 0x00000002 /* 2 */ +#define DF_WEAPONS_STAY 0x00000004 /* 4 */ +#define DF_NO_FALLING 0x00000008 /* 8 */ +#define DF_INSTANT_ITEMS 0x00000010 /* 16 */ +#define DF_SAME_LEVEL 0x00000020 /* 32 */ +#define DF_SKINTEAMS 0x00000040 /* 64 */ +#define DF_MODELTEAMS 0x00000080 /* 128 */ +#define DF_NO_FRIENDLY_FIRE 0x00000100 /* 256 */ +#define DF_SPAWN_FARTHEST 0x00000200 /* 512 */ +#define DF_FORCE_RESPAWN 0x00000400 /* 1024 */ +#define DF_NO_ARMOR 0x00000800 /* 2048 */ +#define DF_ALLOW_EXIT 0x00001000 /* 4096 */ +#define DF_INFINITE_AMMO 0x00002000 /* 8192 */ +#define DF_QUAD_DROP 0x00004000 /* 16384 */ +#define DF_FIXED_FOV 0x00008000 /* 32768 */ +#define DF_QUADFIRE_DROP 0x00010000 /* 65536 */ +#define DF_NO_MINES 0x00020000 +#define DF_NO_STACK_DOUBLE 0x00040000 +#define DF_NO_NUKES 0x00080000 +#define DF_NO_SPHERES 0x00100000 + +#define ROGUE_VERSION_STRING "08/21/1998 Beta 2 for Ensemble" + +/* + * ========================================================== + * + * ELEMENTS COMMUNICATED ACROSS THE NET + * + * ========================================================== + */ + +#define ANGLE2SHORT(x) ((int)((x) * 65536 / 360) & 65535) +#define SHORT2ANGLE(x) ((x) * (360.0 / 65536)) + +/* config strings are a general means of communication from + * the server to all connected clients. Each config string + * can be at most MAX_QPATH characters. */ +#define CS_NAME 0 +#define CS_CDTRACK 1 +#define CS_SKY 2 +#define CS_SKYAXIS 3 /* %f %f %f format */ +#define CS_SKYROTATE 4 +#define CS_STATUSBAR 5 /* display program string */ + +#define CS_AIRACCEL 29 /* air acceleration control */ +#define CS_MAXCLIENTS 30 +#define CS_MAPCHECKSUM 31 /* for catching cheater maps */ + +#define CS_MODELS 32 +#define CS_SOUNDS (CS_MODELS + MAX_MODELS) +#define CS_IMAGES (CS_SOUNDS + MAX_SOUNDS) +#define CS_LIGHTS (CS_IMAGES + MAX_IMAGES) +#define CS_ITEMS (CS_LIGHTS + MAX_LIGHTSTYLES) +#define CS_PLAYERSKINS (CS_ITEMS + MAX_ITEMS) +#define CS_GENERAL (CS_PLAYERSKINS + MAX_CLIENTS) +#define MAX_CONFIGSTRINGS (CS_GENERAL + MAX_GENERAL) + +/* ============================================== */ + +/* entity_state_t->event values + * entity events are for effects that take place reletive + * to an existing entities origin. Very network efficient. + * All muzzle flashes really should be converted to events... */ +typedef enum +{ + EV_NONE, + EV_ITEM_RESPAWN, + EV_FOOTSTEP, + EV_FALLSHORT, + EV_FALL, + EV_FALLFAR, + EV_PLAYER_TELEPORT, + EV_OTHER_TELEPORT +} entity_event_t; + +/* entity_state_t is the information conveyed from the server + * in an update message about entities that the client will + * need to render in some way */ +typedef struct entity_state_s +{ + int number; /* edict index */ + + vec3_t origin; + vec3_t angles; + vec3_t old_origin; /* for lerping */ + int modelindex; + int modelindex2, modelindex3, modelindex4; /* weapons, CTF flags, etc */ + int frame; + int skinnum; + unsigned int effects; + int renderfx; + int solid; /* for client side prediction, 8*(bits 0-4) is x/y radius */ + /* 8*(bits 5-9) is z down distance, 8(bits10-15) is z up */ + /* gi.linkentity sets this properly */ + int sound; /* for looping sounds, to guarantee shutoff */ + int event; /* impulse events -- muzzle flashes, footsteps, etc */ + /* events only go out for a single frame, they */ + /* are automatically cleared each frame */ +} entity_state_t; + +/* ============================================== */ + +/* player_state_t is the information needed in addition to pmove_state_t + * to rendered a view. There will only be 10 player_state_t sent each second, + * but the number of pmove_state_t changes will be reletive to client + * frame rates */ +typedef struct +{ + pmove_state_t pmove; /* for prediction */ + + vec3_t viewangles; /* for fixed views */ + vec3_t viewoffset; /* add to pmovestate->origin */ + vec3_t kick_angles; /* add to view direction to get render angles */ + /* set by weapon kicks, pain effects, etc */ + + vec3_t gunangles; + vec3_t gunoffset; + int gunindex; + int gunframe; + + float blend[4]; /* rgba full screen effect */ + float fov; /* horizontal field of view */ + int rdflags; /* refdef flags */ + + short stats[MAX_STATS]; /* fast status bar updates */ +} player_state_t; + +size_t verify_fread(void *, size_t, size_t, FILE *); +size_t verify_fwrite(void *, size_t, size_t, FILE *); + +#endif /* COMMON_SHARED_H */ diff --git a/src/common/header/vid.h b/src/common/header/vid.h new file mode 100644 index 0000000..c7c9c57 --- /dev/null +++ b/src/common/header/vid.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 1997-2001 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. + * + * ======================================================================= + * + * API between client and renderer. + * + * ======================================================================= + */ + +#ifndef CL_VID_H +#define CL_VID_H + +#include "common.h" + +// FIXME: Remove it, it's unused. +typedef struct vrect_s { + int x,y,width,height; +} vrect_t; + +// Hold the video state. +typedef struct { + int height; + int width; +} viddef_t; + +// Global video state. +extern viddef_t viddef; + +// Generic stuff. +void VID_Init(void); +void VID_Shutdown(void); +void VID_CheckChanges(void); + +void VID_MenuInit(void); +void VID_MenuDraw(void); +const char *VID_MenuKey(int); + +// Stuff provided by platform backend. +extern int glimp_refreshRate; + +const char **GLimp_GetDisplayIndices(void); +int GLimp_GetWindowDisplayIndex(void); +int GLimp_GetNumVideoDisplays(void); +qboolean GLimp_Init(void); +void GLimp_Shutdown(void); +qboolean GLimp_InitGraphics(int fullscreen, int *pwidth, int *pheight); +void GLimp_ShutdownGraphics(void); +void GLimp_GrabInput(qboolean grab); +int GLimp_GetRefreshRate(void); +qboolean GLimp_GetDesktopMode(int *pwidth, int *pheight); + +#endif diff --git a/src/common/md4.c b/src/common/md4.c new file mode 100644 index 0000000..86f358c --- /dev/null +++ b/src/common/md4.c @@ -0,0 +1,224 @@ +/* + * Public Domain C source implementation of RFC 1320 + * - The MD4 Message-Digest Algorithm - + * + * http://www.faqs.org/rfcs/rfc1320.html + * by Steven Fuller + */ + +#include + +#define ROTATELEFT32(x, s) (((x) << (s)) | ((x) >> (32 - (s)))) + +#define F(X, Y, Z) (((X)&(Y)) | ((~X) & (Z))) +#define G(X, Y, Z) (((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z))) +#define H(X, Y, Z) ((X) ^ (Y) ^ (Z)) + +#define S(a, b, c, d, k, s) \ + { \ + a += (F((b), (c), (d)) + X[(k)]); \ + a = ROTATELEFT32(a, s); \ + } +#define T(a, b, c, d, k, s) \ + { \ + a += (G((b), (c), (d)) + X[(k)] + 0x5A827999); \ + a = ROTATELEFT32(a, s); \ + } +#define U(a, b, c, d, k, s) \ + { \ + a += (H((b), (c), (d)) + X[(k)] + 0x6ED9EBA1); \ + a = ROTATELEFT32(a, s); \ + } + +static uint32_t X[16]; +static uint32_t A, AA; +static uint32_t B, BB; +static uint32_t C, CC; +static uint32_t D, DD; + +static void +DoMD4() +{ + AA = A; + BB = B; + CC = C; + DD = D; + + S(A, B, C, D, 0, 3); + S(D, A, B, C, 1, 7); + S(C, D, A, B, 2, 11); + S(B, C, D, A, 3, 19); + S(A, B, C, D, 4, 3); + S(D, A, B, C, 5, 7); + S(C, D, A, B, 6, 11); + S(B, C, D, A, 7, 19); + S(A, B, C, D, 8, 3); + S(D, A, B, C, 9, 7); + S(C, D, A, B, 10, 11); + S(B, C, D, A, 11, 19); + S(A, B, C, D, 12, 3); + S(D, A, B, C, 13, 7); + S(C, D, A, B, 14, 11); + S(B, C, D, A, 15, 19); + + T(A, B, C, D, 0, 3); + T(D, A, B, C, 4, 5); + T(C, D, A, B, 8, 9); + T(B, C, D, A, 12, 13); + T(A, B, C, D, 1, 3); + T(D, A, B, C, 5, 5); + T(C, D, A, B, 9, 9); + T(B, C, D, A, 13, 13); + T(A, B, C, D, 2, 3); + T(D, A, B, C, 6, 5); + T(C, D, A, B, 10, 9); + T(B, C, D, A, 14, 13); + T(A, B, C, D, 3, 3); + T(D, A, B, C, 7, 5); + T(C, D, A, B, 11, 9); + T(B, C, D, A, 15, 13); + + U(A, B, C, D, 0, 3); + U(D, A, B, C, 8, 9); + U(C, D, A, B, 4, 11); + U(B, C, D, A, 12, 15); + U(A, B, C, D, 2, 3); + U(D, A, B, C, 10, 9); + U(C, D, A, B, 6, 11); + U(B, C, D, A, 14, 15); + U(A, B, C, D, 1, 3); + U(D, A, B, C, 9, 9); + U(C, D, A, B, 5, 11); + U(B, C, D, A, 13, 15); + U(A, B, C, D, 3, 3); + U(D, A, B, C, 11, 9); + U(C, D, A, B, 7, 11); + U(B, C, D, A, 15, 15); + + A += AA; + B += BB; + C += CC; + D += DD; +} + +static void +PerformMD4(const unsigned char *buf, int length, unsigned char *digest) +{ + int len = length / 64; /* number of full blocks */ + int rem = length % 64; /* number of left over bytes */ + + int i, j; + const unsigned char *ptr = buf; + + /* initialize the MD buffer */ + A = 0x67452301; + B = 0xEFCDAB89; + C = 0x98BADCFE; + D = 0x10325476; + + for (i = 0; i < len; i++) + { + for (j = 0; j < 16; j++) + { + X[j] = ((ptr[0] << 0) | (ptr[1] << 8) | + (ptr[2] << 16) | (ptr[3] << 24)); + + ptr += 4; + } + + DoMD4(); + } + + i = rem / 4; + + for (j = 0; j < i; j++) + { + X[j] = ((ptr[0] << 0) | (ptr[1] << 8) | + (ptr[2] << 16) | (ptr[3] << 24)); + + ptr += 4; + } + + switch (rem % 4) + { + case 0: + X[j] = 0x80U; + break; + case 1: + X[j] = ((ptr[0] << 0) | ((0x80U) << 8)); + break; + case 2: + X[j] = ((ptr[0] << 0) | (ptr[1] << 8) | ((0x80U) << 16)); + break; + case 3: + X[j] = + ((ptr[0] << + 0) | (ptr[1] << 8) | (ptr[2] << 16) | ((0x80U) << 24)); + break; + } + + j++; + + if (j > 14) + { + for ( ; j < 16; j++) + { + X[j] = 0; + } + + DoMD4(); + + j = 0; + } + + for ( ; j < 14; j++) + { + X[j] = 0; + } + + X[14] = (length & 0x1FFFFFFF) << 3; + X[15] = (length & ~0x1FFFFFFF) >> 29; + + DoMD4(); + + digest[0] = (A & 0x000000FF) >> 0; + digest[1] = (A & 0x0000FF00) >> 8; + digest[2] = (A & 0x00FF0000) >> 16; + digest[3] = (A & 0xFF000000) >> 24; + digest[4] = (B & 0x000000FF) >> 0; + digest[5] = (B & 0x0000FF00) >> 8; + digest[6] = (B & 0x00FF0000) >> 16; + digest[7] = (B & 0xFF000000) >> 24; + digest[8] = (C & 0x000000FF) >> 0; + digest[9] = (C & 0x0000FF00) >> 8; + digest[10] = (C & 0x00FF0000) >> 16; + digest[11] = (C & 0xFF000000) >> 24; + digest[12] = (D & 0x000000FF) >> 0; + digest[13] = (D & 0x0000FF00) >> 8; + digest[14] = (D & 0x00FF0000) >> 16; + digest[15] = (D & 0xFF000000) >> 24; + + A = AA = 0; + B = BB = 0; + C = CC = 0; + D = DD = 0; + + for (j = 0; j < 16; j++) + { + X[j] = 0; + } +} + +unsigned +Com_BlockChecksum(void *buffer, int length) +{ + uint32_t digest[4]; + unsigned val; + + PerformMD4((unsigned char *)buffer, length, (unsigned char *)digest); + + val = digest[0] ^ digest[1] ^ digest[2] ^ digest[3]; + + return val; +} + diff --git a/src/common/shared.c b/src/common/shared.c new file mode 100644 index 0000000..e4e2c78 --- /dev/null +++ b/src/common/shared.c @@ -0,0 +1,1419 @@ +/* + * Copyright (C) 1997-2001 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. + * + * ======================================================================= + * + * Support functions, linked into client, server, renderer and game. + * + * ======================================================================= + */ + +#include + +#include "header/shared.h" + +#define DEG2RAD(a) (a * M_PI) / 180.0F + +vec3_t vec3_origin = {0, 0, 0}; + +/* ============================================================================ */ + +void +RotatePointAroundVector(vec3_t dst, const vec3_t dir, + const vec3_t point, float degrees) +{ + float m[3][3]; + float im[3][3]; + float zrot[3][3]; + float tmpmat[3][3]; + float rot[3][3]; + int i; + vec3_t vr, vup, vf; + + vf[0] = dir[0]; + vf[1] = dir[1]; + vf[2] = dir[2]; + + PerpendicularVector(vr, dir); + CrossProduct(vr, vf, vup); + + m[0][0] = vr[0]; + m[1][0] = vr[1]; + m[2][0] = vr[2]; + + m[0][1] = vup[0]; + m[1][1] = vup[1]; + m[2][1] = vup[2]; + + m[0][2] = vf[0]; + m[1][2] = vf[1]; + m[2][2] = vf[2]; + + memcpy(im, m, sizeof(im)); + + im[0][1] = m[1][0]; + im[0][2] = m[2][0]; + im[1][0] = m[0][1]; + im[1][2] = m[2][1]; + im[2][0] = m[0][2]; + im[2][1] = m[1][2]; + + memset(zrot, 0, sizeof(zrot)); + zrot[2][2] = 1.0F; + + zrot[0][0] = (float)cos(DEG2RAD(degrees)); + zrot[0][1] = (float)sin(DEG2RAD(degrees)); + zrot[1][0] = (float)-sin(DEG2RAD(degrees)); + zrot[1][1] = (float)cos(DEG2RAD(degrees)); + + R_ConcatRotations(m, zrot, tmpmat); + R_ConcatRotations(tmpmat, im, rot); + + for (i = 0; i < 3; i++) + { + dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * + point[2]; + } +} + +void +AngleVectors(vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) +{ + float angle; + static float sr, sp, sy, cr, cp, cy; + + angle = angles[YAW] * (M_PI * 2 / 360); + sy = (float)sin(angle); + cy = (float)cos(angle); + angle = angles[PITCH] * (M_PI * 2 / 360); + sp = (float)sin(angle); + cp = (float)cos(angle); + angle = angles[ROLL] * (M_PI * 2 / 360); + sr = (float)sin(angle); + cr = (float)cos(angle); + + if (forward) + { + forward[0] = cp * cy; + forward[1] = cp * sy; + forward[2] = -sp; + } + + if (right) + { + right[0] = (-1 * sr * sp * cy + - 1 * cr * -sy); + right[1] = (-1 * sr * sp * sy + - 1 * cr * cy); + right[2] = -1 * sr * cp; + } + + if (up) + { + up[0] = (cr * sp * cy + - sr * -sy); + up[1] = (cr * sp * sy + - sr * cy); + up[2] = cr * cp; + } +} + +void +AngleVectors2(vec3_t value1, vec3_t angles) +{ + float forward; + float yaw, pitch; + + if ((value1[1] == 0) && (value1[0] == 0)) + { + yaw = 0; + + if (value1[2] > 0) + { + pitch = 90; + } + + else + { + pitch = 270; + } + } + else + { + if (value1[0]) + { + yaw = ((float)atan2(value1[1], value1[0]) * 180 / M_PI); + } + + else if (value1[1] > 0) + { + yaw = 90; + } + + else + { + yaw = 270; + } + + if (yaw < 0) + { + yaw += 360; + } + + forward = (float)sqrt(value1[0] * value1[0] + value1[1] * value1[1]); + pitch = ((float)atan2(value1[2], forward) * 180 / M_PI); + + if (pitch < 0) + { + pitch += 360; + } + } + + angles[PITCH] = -pitch; + angles[YAW] = yaw; + angles[ROLL] = 0; +} + +void +ProjectPointOnPlane(vec3_t dst, const vec3_t p, const vec3_t normal) +{ + float d; + vec3_t n; + float inv_denom; + + inv_denom = 1.0F / DotProduct(normal, normal); + + d = DotProduct(normal, p) * inv_denom; + + n[0] = normal[0] * inv_denom; + n[1] = normal[1] * inv_denom; + n[2] = normal[2] * inv_denom; + + dst[0] = p[0] - d * n[0]; + dst[1] = p[1] - d * n[1]; + dst[2] = p[2] - d * n[2]; +} + +/* assumes "src" is normalized */ +void +PerpendicularVector(vec3_t dst, const vec3_t src) +{ + int pos; + int i; + float minelem = 1.0F; + vec3_t tempvec; + + /* find the smallest magnitude axially aligned vector */ + for (pos = 0, i = 0; i < 3; i++) + { + if (fabs(src[i]) < minelem) + { + pos = i; + minelem = (float)fabs(src[i]); + } + } + + tempvec[0] = tempvec[1] = tempvec[2] = 0.0F; + tempvec[pos] = 1.0F; + + /* project the point onto the plane defined by src */ + ProjectPointOnPlane(dst, tempvec, src); + + /* normalize the result */ + VectorNormalize(dst); +} + +void +R_ConcatRotations(float in1[3][3], float in2[3][3], float out[3][3]) +{ + out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + + in1[0][2] * in2[2][0]; + out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + + in1[0][2] * in2[2][1]; + out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + + in1[0][2] * in2[2][2]; + out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + + in1[1][2] * in2[2][0]; + out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + + in1[1][2] * in2[2][1]; + out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + + in1[1][2] * in2[2][2]; + out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + + in1[2][2] * in2[2][0]; + out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + + in1[2][2] * in2[2][1]; + out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + + in1[2][2] * in2[2][2]; +} + +void +R_ConcatTransforms(float in1[3][4], float in2[3][4], float out[3][4]) +{ + out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + + in1[0][2] * in2[2][0]; + out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + + in1[0][2] * in2[2][1]; + out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + + in1[0][2] * in2[2][2]; + out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + + in1[0][2] * in2[2][3] + in1[0][3]; + out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + + in1[1][2] * in2[2][0]; + out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + + in1[1][2] * in2[2][1]; + out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + + in1[1][2] * in2[2][2]; + out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + + in1[1][2] * in2[2][3] + in1[1][3]; + out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + + in1[2][2] * in2[2][0]; + out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + + in1[2][2] * in2[2][1]; + out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + + in1[2][2] * in2[2][2]; + out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + + in1[2][2] * in2[2][3] + in1[2][3]; +} + +/* ============================================================================ */ + +float +Q_fabs(float f) +{ + int tmp = *(int *)&f; + + tmp &= 0x7FFFFFFF; + return *(float *)&tmp; +} + +float +LerpAngle(float a2, float a1, float frac) +{ + if (a1 - a2 > 180) + { + a1 -= 360; + } + + if (a1 - a2 < -180) + { + a1 += 360; + } + + return a2 + frac * (a1 - a2); +} + +float +anglemod(float a) +{ + a = (360.0 / 65536) * ((int)(a * (65536 / 360.0)) & 65535); + return a; +} + +/* + * This is the slow, general version + */ +int +BoxOnPlaneSide2(vec3_t emins, vec3_t emaxs, struct cplane_s *p) +{ + int i; + float dist1, dist2; + int sides; + vec3_t corners[2]; + + for (i = 0; i < 3; i++) + { + if (p->normal[i] < 0) + { + corners[0][i] = emins[i]; + corners[1][i] = emaxs[i]; + } + else + { + corners[1][i] = emins[i]; + corners[0][i] = emaxs[i]; + } + } + + dist1 = DotProduct(p->normal, corners[0]) - p->dist; + dist2 = DotProduct(p->normal, corners[1]) - p->dist; + sides = 0; + + if (dist1 >= 0) + { + sides = 1; + } + + if (dist2 < 0) + { + sides |= 2; + } + + return sides; +} + +/* + * Returns 1, 2, or 1 + 2 + */ +int +BoxOnPlaneSide(vec3_t emins, vec3_t emaxs, struct cplane_s *p) +{ + float dist1, dist2; + int sides; + + /* fast axial cases */ + if (p->type < 3) + { + if (p->dist <= emins[p->type]) + { + return 1; + } + + if (p->dist >= emaxs[p->type]) + { + return 2; + } + + return 3; + } + + /* general case */ + switch (p->signbits) + { + case 0: + dist1 = p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + + p->normal[2] * emaxs[2]; + dist2 = p->normal[0] * emins[0] + p->normal[1] * emins[1] + + p->normal[2] * emins[2]; + break; + case 1: + dist1 = p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + + p->normal[2] * emaxs[2]; + dist2 = p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + + p->normal[2] * emins[2]; + break; + case 2: + dist1 = p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + + p->normal[2] * emaxs[2]; + dist2 = p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + + p->normal[2] * emins[2]; + break; + case 3: + dist1 = p->normal[0] * emins[0] + p->normal[1] * emins[1] + + p->normal[2] * emaxs[2]; + dist2 = p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + + p->normal[2] * emins[2]; + break; + case 4: + dist1 = p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + + p->normal[2] * emins[2]; + dist2 = p->normal[0] * emins[0] + p->normal[1] * emins[1] + + p->normal[2] * emaxs[2]; + break; + case 5: + dist1 = p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + + p->normal[2] * emins[2]; + dist2 = p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + + p->normal[2] * emaxs[2]; + break; + case 6: + dist1 = p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + + p->normal[2] * emins[2]; + dist2 = p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + + p->normal[2] * emaxs[2]; + break; + case 7: + dist1 = p->normal[0] * emins[0] + p->normal[1] * emins[1] + + p->normal[2] * emins[2]; + dist2 = p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + + p->normal[2] * emaxs[2]; + break; + default: + dist1 = dist2 = 0; + break; + } + + sides = 0; + + if (dist1 >= p->dist) + { + sides = 1; + } + + if (dist2 < p->dist) + { + sides |= 2; + } + + return sides; +} + +void +ClearBounds(vec3_t mins, vec3_t maxs) +{ + mins[0] = mins[1] = mins[2] = 99999; + maxs[0] = maxs[1] = maxs[2] = -99999; +} + +void +AddPointToBounds(vec3_t v, vec3_t mins, vec3_t maxs) +{ + int i; + vec_t val; + + for (i = 0; i < 3; i++) + { + val = v[i]; + + if (val < mins[i]) + { + mins[i] = val; + } + + if (val > maxs[i]) + { + maxs[i] = val; + } + } +} + +int +VectorCompare(vec3_t v1, vec3_t v2) +{ + if ((v1[0] != v2[0]) || (v1[1] != v2[1]) || (v1[2] != v2[2])) + { + return 0; + } + + return 1; +} + +vec_t +VectorNormalize(vec3_t v) +{ + float length, ilength; + + length = v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; + length = (float)sqrt(length); + + if (length) + { + ilength = 1 / length; + v[0] *= ilength; + v[1] *= ilength; + v[2] *= ilength; + } + + return length; +} + +vec_t +VectorNormalize2(vec3_t v, vec3_t out) +{ + float length, ilength; + + length = v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; + length = (float)sqrt(length); + + if (length) + { + ilength = 1 / length; + out[0] = v[0] * ilength; + out[1] = v[1] * ilength; + out[2] = v[2] * ilength; + } + + return length; +} + +void +VectorMA(vec3_t veca, float scale, vec3_t vecb, vec3_t vecc) +{ + vecc[0] = veca[0] + scale * vecb[0]; + vecc[1] = veca[1] + scale * vecb[1]; + vecc[2] = veca[2] + scale * vecb[2]; +} + +vec_t +_DotProduct(vec3_t v1, vec3_t v2) +{ + return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; +} + +void +_VectorSubtract(vec3_t veca, vec3_t vecb, vec3_t out) +{ + out[0] = veca[0] - vecb[0]; + out[1] = veca[1] - vecb[1]; + out[2] = veca[2] - vecb[2]; +} + +void +_VectorAdd(vec3_t veca, vec3_t vecb, vec3_t out) +{ + out[0] = veca[0] + vecb[0]; + out[1] = veca[1] + vecb[1]; + out[2] = veca[2] + vecb[2]; +} + +void +_VectorCopy(vec3_t in, vec3_t out) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; +} + +void +CrossProduct(vec3_t v1, vec3_t v2, vec3_t cross) +{ + cross[0] = v1[1] * v2[2] - v1[2] * v2[1]; + cross[1] = v1[2] * v2[0] - v1[0] * v2[2]; + cross[2] = v1[0] * v2[1] - v1[1] * v2[0]; +} + +double sqrt(double x); + +vec_t +VectorLength(vec3_t v) +{ + int i; + float length; + + length = 0; + + for (i = 0; i < 3; i++) + { + length += v[i] * v[i]; + } + + length = (float)sqrt(length); + + return length; +} + +void +VectorInverse(vec3_t v) +{ + v[0] = -v[0]; + v[1] = -v[1]; + v[2] = -v[2]; +} + +void +VectorScale(vec3_t in, vec_t scale, vec3_t out) +{ + out[0] = in[0] * scale; + out[1] = in[1] * scale; + out[2] = in[2] * scale; +} + +int +Q_log2(int val) +{ + int answer = 0; + + while (val >>= 1) + { + answer++; + } + + return answer; +} + +/* ==================================================================================== */ + +char * +COM_SkipPath(char *pathname) +{ + char *last; + + last = pathname; + + while (*pathname) + { + if (*pathname == '/') + { + last = pathname + 1; + } + + pathname++; + } + + return last; +} + +void +COM_StripExtension(char *in, char *out) +{ + while (*in && *in != '.') + { + *out++ = *in++; + } + + *out = 0; +} + +const char * +COM_FileExtension(const char *in) +{ + const char *ext = strrchr(in, '.'); + + if (!ext || ext == in) + { + return ""; + } + + return ext + 1; +} + +void +COM_FileBase(char *in, char *out) +{ + char *s, *s2; + + s = in + strlen(in) - 1; + + while (s != in && *s != '.') + { + s--; + } + + for (s2 = s; s2 != in && *s2 != '/'; s2--) + { + } + + if (s - s2 < 2) + { + out[0] = 0; + } + else + { + s--; + memcpy(out, s2 + 1, s - s2); + out[s - s2] = 0; + } +} + +/* + * Returns the path up to, but not including the last / + */ +void +COM_FilePath(const char *in, char *out) +{ + const char *s; + + s = in + strlen(in) - 1; + + while (s != in && *s != '/') + { + s--; + } + + memcpy(out, in, s - in); + out[s - in] = 0; +} + +void +COM_DefaultExtension(char *path, const char *extension) +{ + char *src; + + /* */ + /* if path doesn't have a .EXT, append extension */ + /* (extension should include the .) */ + /* */ + src = path + strlen(path) - 1; + + while (*src != '/' && src != path) + { + if (*src == '.') + { + return; /* it has an extension */ + } + + src--; + } + + strcat(path, extension); +} + +/* + * ============================================================================ + * + * BYTE ORDER FUNCTIONS + * + * ============================================================================ + */ + +qboolean bigendien; + +/* can't just use function pointers, or dll linkage can + mess up when qcommon is included in multiple places */ +short (*_BigShort)(short l); +short (*_LittleShort)(short l); +int (*_BigLong)(int l); +int (*_LittleLong)(int l); +float (*_BigFloat)(float l); +float (*_LittleFloat)(float l); + +short +BigShort(short l) +{ + return _BigShort(l); +} + +short +LittleShort(short l) +{ + return _LittleShort(l); +} + +int +BigLong(int l) +{ + return _BigLong(l); +} + +int +LittleLong(int l) +{ + return _LittleLong(l); +} + +float +BigFloat(float l) +{ + return _BigFloat(l); +} + +float +LittleFloat(float l) +{ + return _LittleFloat(l); +} + +short +ShortSwap(short l) +{ + byte b1, b2; + + b1 = l & 255; + b2 = (l >> 8) & 255; + + return (b1 << 8) + b2; +} + +short +ShortNoSwap(short l) +{ + return l; +} + +int +LongSwap(int l) +{ + byte b1, b2, b3, b4; + + b1 = l & 255; + b2 = (l >> 8) & 255; + b3 = (l >> 16) & 255; + b4 = (l >> 24) & 255; + + return ((int)b1 << 24) + ((int)b2 << 16) + ((int)b3 << 8) + b4; +} + +int +LongNoSwap(int l) +{ + return l; +} + +float +FloatSwap(float f) +{ + union + { + float f; + byte b[4]; + } dat1, dat2; + + dat1.f = f; + dat2.b[0] = dat1.b[3]; + dat2.b[1] = dat1.b[2]; + dat2.b[2] = dat1.b[1]; + dat2.b[3] = dat1.b[0]; + return dat2.f; +} + +float +FloatNoSwap(float f) +{ + return f; +} + +void +Swap_Init(void) +{ + byte swaptest[2] = {1, 0}; + short swapTestShort; + assert(sizeof(short) == 2); + memcpy(&swapTestShort, swaptest, 2); + + /* set the byte swapping variables in a portable manner */ + if (swapTestShort == 1) + { + bigendien = false; + _BigShort = ShortSwap; + _LittleShort = ShortNoSwap; + _BigLong = LongSwap; + _LittleLong = LongNoSwap; + _BigFloat = FloatSwap; + _LittleFloat = FloatNoSwap; + Com_Printf("Byte ordering: little endian\n\n"); + } + else + { + bigendien = true; + _BigShort = ShortNoSwap; + _LittleShort = ShortSwap; + _BigLong = LongNoSwap; + _LittleLong = LongSwap; + _BigFloat = FloatNoSwap; + _LittleFloat = FloatSwap; + Com_Printf("Byte ordering: big endian\n\n"); + } + + if (LittleShort(swapTestShort) != 1) + assert("Error in the endian conversion!"); +} + +/* + * does a varargs printf into a temp buffer, so I don't + * need to have varargs versions of all text functions. + */ +char * +va(char *format, ...) +{ + va_list argptr; + static char string[1024]; + + va_start(argptr, format); + vsnprintf(string, 1024, format, argptr); + va_end(argptr); + + return string; +} + +char com_token[MAX_TOKEN_CHARS]; + +/* + * Parse a token out of a string + */ +char * +COM_Parse(char **data_p) +{ + int c; + int len; + char *data; + + data = *data_p; + len = 0; + com_token[0] = 0; + + if (!data) + { + *data_p = NULL; + return ""; + } + +skipwhite: + + while ((c = *data) <= ' ') + { + if (c == 0) + { + *data_p = NULL; + return ""; + } + + data++; + } + + /* skip // comments */ + if ((c == '/') && (data[1] == '/')) + { + while (*data && *data != '\n') + { + data++; + } + + goto skipwhite; + } + + /* handle quoted strings specially */ + if (c == '\"') + { + data++; + + while (1) + { + c = *data++; + + if ((c == '\"') || !c) + { + goto done; + } + + if (len < MAX_TOKEN_CHARS) + { + com_token[len] = c; + len++; + } + } + } + + /* parse a regular word */ + do + { + if (len < MAX_TOKEN_CHARS) + { + com_token[len] = c; + len++; + } + + data++; + c = *data; + } + while (c > 32); + +done: + if (len == MAX_TOKEN_CHARS) + { + len = 0; + } + + com_token[len] = 0; + + *data_p = data; + return com_token; +} + +static int paged_total = 0; + +void +Com_PageInMemory(byte *buffer, int size) +{ + int i; + + for (i = size - 1; i > 0; i -= 4096) + { + paged_total += buffer[i]; + } +} + +/* + * ============================================================================ + * + * LIBRARY REPLACEMENT FUNCTIONS + * + * ============================================================================ + */ + +int +Q_stricmp(const char *s1, const char *s2) +{ + return strcasecmp(s1, s2); +} + +int +Q_strncasecmp(char *s1, char *s2, int n) +{ + int c1, c2; + + do + { + c1 = *s1++; + c2 = *s2++; + + if (!n--) + { + return 0; /* strings are equal until end point */ + } + + if (c1 != c2) + { + if ((c1 >= 'a') && (c1 <= 'z')) + { + c1 -= ('a' - 'A'); + } + + if ((c2 >= 'a') && (c2 <= 'z')) + { + c2 -= ('a' - 'A'); + } + + if (c1 != c2) + { + return -1; /* strings not equal */ + } + } + } + while (c1); + + return 0; /* strings are equal */ +} + +int +Q_strcasecmp(char *s1, char *s2) +{ + return Q_strncasecmp(s1, s2, 99999); +} + +void +Com_sprintf(char *dest, int size, char *fmt, ...) +{ + int len; + va_list argptr; + + va_start(argptr, fmt); + len = vsnprintf(dest, size, fmt, argptr); + va_end(argptr); + + if (len >= size) + { + Com_Printf("Com_sprintf: overflow\n"); + } +} + +char * +Q_strlwr ( char *s ) +{ + char *p = s; + + while ( *s ) + { + *s = tolower( (unsigned char)*s ); + s++; + } + + return ( p ); +} + +int +Q_strlcpy(char *dst, const char *src, int size) +{ + const char *s = src; + + while (*s) + { + if (size > 1) + { + *dst++ = *s; + size--; + } + s++; + } + if (size > 0) + { + *dst = '\0'; + } + + return s - src; +} + +int +Q_strlcat(char *dst, const char *src, int size) +{ + char *d = dst; + + while (size > 0 && *d) + { + size--; + d++; + } + + return (d - dst) + Q_strlcpy(d, src, size); +} + +/* + * An unicode compatible fopen() Wrapper for Windows. + */ +#ifdef _WIN32 +#include +#include +#include +#include +FILE *Q_fopen(const char *file, const char *mode) +{ + WCHAR wfile[MAX_OSPATH]; + WCHAR wmode[16]; + + int len = MultiByteToWideChar(CP_UTF8, 0, file, -1, wfile, MAX_OSPATH); + + if (len > 0) + { + if (MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, 16) > 0) + { + // make sure it's a regular file and not a directory or sth, see #394 + struct _stat buf; + int statret = _wstat(wfile, &buf); + if((statret == 0 && (buf.st_mode & _S_IFREG) != 0) || (statret == -1 && errno == ENOENT)) + { + return _wfopen(wfile, wmode); + } + } + } + + return NULL; +} +#else +#include +#include +FILE *Q_fopen(const char *file, const char *mode) +{ + // make sure it's a regular file and not a directory or sth, see #394 + struct stat statbuf; + int statret = stat(file, &statbuf); + // (it's ok if it doesn't exist though, maybe we wanna write/create) + if((statret == -1 && errno != ENOENT) || (statret == 0 && (statbuf.st_mode & S_IFREG) == 0)) + { + return NULL; + } + return fopen(file, mode); +} +#endif + +int +Q_sort_strcomp(const void *s1, const void *s2) +{ + return strcmp(*(char **)s1, *(char **)s2); +} + +/* + * ===================================================================== + * + * INFO STRINGS + * + * ===================================================================== + */ + +/* + * Searches the string for the given + * key and returns the associated value, + * or an empty string. + */ +char * +Info_ValueForKey(char *s, char *key) +{ + char pkey[512]; + static char value[2][512]; /* use two buffers so compares + work without stomping on each other */ + static int valueindex; + char *o; + + valueindex ^= 1; + + if (*s == '\\') + { + s++; + } + + while (1) + { + o = pkey; + + while (*s != '\\') + { + if (!*s) + { + return ""; + } + + *o++ = *s++; + } + + *o = 0; + s++; + + o = value[valueindex]; + + while (*s != '\\' && *s) + { + *o++ = *s++; + } + + *o = 0; + + if (!strcmp(key, pkey)) + { + return value[valueindex]; + } + + if (!*s) + { + return ""; + } + + s++; + } +} + +void +Info_RemoveKey(char *s, char *key) +{ + char *start; + char pkey[512]; + char value[512]; + char *o; + + if (strstr(key, "\\")) + { + return; + } + + while (1) + { + start = s; + + if (*s == '\\') + { + s++; + } + + o = pkey; + + while (*s != '\\') + { + if (!*s) + { + return; + } + + *o++ = *s++; + } + + *o = 0; + s++; + + o = value; + + while (*s != '\\' && *s) + { + *o++ = *s++; + } + + *o = 0; + + if (!strcmp(key, pkey)) + { + memmove(start, s, strlen(s) + 1); /* remove this part */ + return; + } + + if (!*s) + { + return; + } + } +} + +/* + * Some characters are illegal in info strings + * because they can mess up the server's parsing + */ +qboolean +Info_Validate(char *s) +{ + if (strstr(s, "\"")) + { + return false; + } + + if (strstr(s, ";")) + { + return false; + } + + return true; +} + +void +Info_SetValueForKey(char *s, char *key, char *value) +{ + char newi[MAX_INFO_STRING], *v; + int c; + int maxsize = MAX_INFO_STRING; + + if (!key) + { + return; + } + + if (strstr(key, "\\") || (value && strstr(value, "\\"))) + { + Com_Printf("Can't use keys or values with a \\\n"); + return; + } + + if (strstr(key, ";")) + { + Com_Printf("Can't use keys with a semicolon\n"); + return; + } + + if (strstr(key, "\"") || (value && strstr(value, "\""))) + { + Com_Printf("Can't use keys or values with a \"\n"); + return; + } + + if ((strlen(key) > MAX_INFO_KEY - 1) || (value && (strlen(value) > MAX_INFO_KEY - 1))) + { + Com_Printf("Keys and values must be < 64 characters.\n"); + return; + } + + Info_RemoveKey(s, key); + + if (!value || !strlen(value)) + { + return; + } + + Com_sprintf(newi, sizeof(newi), "\\%s\\%s", key, value); + + if (strlen(newi) + strlen(s) > maxsize) + { + Com_Printf("Info string length exceeded\n"); + return; + } + + /* only copy ascii values */ + s += strlen(s); + v = newi; + + while (*v) + { + c = *v++; + c &= 127; /* strip high bits */ + + if ((c >= 32) && (c < 127)) + { + *s++ = c; + } + } + + *s = 0; +} diff --git a/src/constants/anorms.h b/src/constants/anorms.h new file mode 100644 index 0000000..1fa8ade --- /dev/null +++ b/src/constants/anorms.h @@ -0,0 +1,188 @@ +/* + * Copyright (C) 1997-2001 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. + * + * ======================================================================= + * + * Precalculates anormal values + * + * ======================================================================= + */ + +{ -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/src/constants/anormtab.h b/src/constants/anormtab.h new file mode 100644 index 0000000..429ffd5 --- /dev/null +++ b/src/constants/anormtab.h @@ -0,0 +1,236 @@ +/* + * Copyright (C) 1997-2001 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. + * + * ======================================================================= + * + * Precalculated anormal tabulations + * + * ======================================================================= + */ + + + { 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/src/constants/warpsin.h b/src/constants/warpsin.h new file mode 100644 index 0000000..01f478b --- /dev/null +++ b/src/constants/warpsin.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 1997-2001 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. + * + * ======================================================================= + * + * Precalculated sinus warps + * + * ======================================================================= + */ + +#if 0 +// In case you wonder how these were generated/what they mean: +for (int i = 0; i < 256; i++) { + r_turbsin[i] = 8.0 * sin( (float)i / TURBSCALE ); // TURBSCALE = 256.0 / (2.0 * M_PI) +} +// so r_turbsin[i] is 8 * sin( i/TURBSCALE ); +// however, the values are multiplied with 0.5 in RI_Init() +// so what's actually used is 4 * sin(i/TURBSCALE) +// in R_EmitWaterPolys() something like +s = os + r_turbsin [ (int) ( ( ot * 0.125 + r_newrefdef.time ) * TURBSCALE ) & 255 ]; +// is used; which should (except for rounding errors from lookup table) be equivalent to +s = os + 4.0*sin( ot*0.125 + r_newrefdef.time ); +#endif // 0 + +0, 0.19633, 0.392541, 0.588517, 0.784137, 0.979285, 1.17384, 1.3677, +1.56072, 1.75281, 1.94384, 2.1337, 2.32228, 2.50945, 2.69512, 2.87916, +3.06147, 3.24193, 3.42044, 3.59689, 3.77117, 3.94319, 4.11282, 4.27998, +4.44456, 4.60647, 4.76559, 4.92185, 5.07515, 5.22538, 5.37247, 5.51632, +5.65685, 5.79398, 5.92761, 6.05767, 6.18408, 6.30677, 6.42566, 6.54068, +6.65176, 6.75883, 6.86183, 6.9607, 7.05537, 7.14579, 7.23191, 7.31368, +7.39104, 7.46394, 7.53235, 7.59623, 7.65552, 7.71021, 7.76025, 7.80562, +7.84628, 7.88222, 7.91341, 7.93984, 7.96148, 7.97832, 7.99036, 7.99759, +8, 7.99759, 7.99036, 7.97832, 7.96148, 7.93984, 7.91341, 7.88222, +7.84628, 7.80562, 7.76025, 7.71021, 7.65552, 7.59623, 7.53235, 7.46394, +7.39104, 7.31368, 7.23191, 7.14579, 7.05537, 6.9607, 6.86183, 6.75883, +6.65176, 6.54068, 6.42566, 6.30677, 6.18408, 6.05767, 5.92761, 5.79398, +5.65685, 5.51632, 5.37247, 5.22538, 5.07515, 4.92185, 4.76559, 4.60647, +4.44456, 4.27998, 4.11282, 3.94319, 3.77117, 3.59689, 3.42044, 3.24193, +3.06147, 2.87916, 2.69512, 2.50945, 2.32228, 2.1337, 1.94384, 1.75281, +1.56072, 1.3677, 1.17384, 0.979285, 0.784137, 0.588517, 0.392541, 0.19633, +9.79717e-16, -0.19633, -0.392541, -0.588517, -0.784137, -0.979285, -1.17384, -1.3677, +-1.56072, -1.75281, -1.94384, -2.1337, -2.32228, -2.50945, -2.69512, -2.87916, +-3.06147, -3.24193, -3.42044, -3.59689, -3.77117, -3.94319, -4.11282, -4.27998, +-4.44456, -4.60647, -4.76559, -4.92185, -5.07515, -5.22538, -5.37247, -5.51632, +-5.65685, -5.79398, -5.92761, -6.05767, -6.18408, -6.30677, -6.42566, -6.54068, +-6.65176, -6.75883, -6.86183, -6.9607, -7.05537, -7.14579, -7.23191, -7.31368, +-7.39104, -7.46394, -7.53235, -7.59623, -7.65552, -7.71021, -7.76025, -7.80562, +-7.84628, -7.88222, -7.91341, -7.93984, -7.96148, -7.97832, -7.99036, -7.99759, +-8, -7.99759, -7.99036, -7.97832, -7.96148, -7.93984, -7.91341, -7.88222, +-7.84628, -7.80562, -7.76025, -7.71021, -7.65552, -7.59623, -7.53235, -7.46394, +-7.39104, -7.31368, -7.23191, -7.14579, -7.05537, -6.9607, -6.86183, -6.75883, +-6.65176, -6.54068, -6.42566, -6.30677, -6.18408, -6.05767, -5.92761, -5.79398, +-5.65685, -5.51632, -5.37247, -5.22538, -5.07515, -4.92185, -4.76559, -4.60647, +-4.44456, -4.27998, -4.11282, -3.94319, -3.77117, -3.59689, -3.42044, -3.24193, +-3.06147, -2.87916, -2.69512, -2.50945, -2.32228, -2.1337, -1.94384, -1.75281, +-1.56072, -1.3677, -1.17384, -0.979285, -0.784137, -0.588517, -0.392541, -0.19633, diff --git a/src/files/pcx.c b/src/files/pcx.c new file mode 100644 index 0000000..fb9bcbf --- /dev/null +++ b/src/files/pcx.c @@ -0,0 +1,317 @@ +/* + * Copyright (C) 1997-2001 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. + * + * ======================================================================= + * + * The PCX file format + * + * ======================================================================= + */ + +#include "../common/header/ref_shared.h" + +// Fix Jennell Jaquays' name in the Quitscreen +// this is 98x11 pixels, each value an index +// into the standard baseq2/pak0/pics/quit.pcx colormap +static unsigned char quitscreenfix[] = { + 191,191,191,47,28,39,4,4,39,1,47,28,47,28,29,1, + 28,28,47,31,31,1,29,31,1,28,47,47,47,47,29,28, + 47,31,30,28,40,40,4,28,28,40,39,40,29,102,102,245, + 28,39,4,4,39,103,40,40,1,1,102,94,47,47,1,94, + 94,94,94,47,102,245,103,103,103,47,1,102,1,102,29,29, + 29,29,47,28,245,31,31,31,47,1,28,1,28,47,1,102, 102,102, + 191,191,142,47,4,8,8,8,8,4,47,28,1,28,29,28, + 29,29,31,1,47,245,47,47,28,28,31,47,28,1,31,1, + 1,245,47,39,8,8,8,40,39,8,8,8,39,1,1,47, + 4,8,8,8,8,4,47,29,28,31,28,28,29,28,28,28, + 29,28,31,28,47,29,1,28,31,47,1,28,1,1,29,29, + 29,47,28,1,28,28,245,28,28,28,28,47,29,28,47,102,102,103, + 191,191,142,31,29,36,8,8,36,31,40,39,40,4,1,1, + 39,40,39,40,40,31,28,40,40,4,39,40,28,47,31,40, + 39,40,4,1,36,8,8,4,47,36,8,8,39,1,1,1, + 29,36,8,8,36,4,4,39,40,4,47,1,47,40,40,39, + 39,40,28,40,40,47,45,39,40,28,4,39,40,4,39,1, + 28,4,40,28,28,4,39,28,47,40,40,39,40,39,28,28,1,103, + 1,142,29,142,28,39,8,8,36,36,8,8,8,8,36,1, + 8,8,8,8,8,36,39,8,8,8,8,8,36,40,36,8, + 8,8,8,36,40,8,8,40,1,4,8,8,40,1,1,31, + 28,39,8,8,36,8,8,8,8,8,36,31,36,8,8,8, + 8,8,36,8,8,4,40,8,8,36,8,8,8,8,8,36, + 40,8,8,40,39,8,8,40,36,8,8,8,8,8,39,29,28,29, + 103,191,142,47,28,40,8,8,40,8,8,33,33,8,8,36, + 8,8,36,36,8,8,36,8,8,36,36,8,8,36,8,8, + 33,33,8,8,36,8,8,4,47,40,8,8,39,47,28,245, + 28,40,8,8,40,40,36,36,33,8,8,36,8,8,36,36, + 8,8,36,8,8,40,40,8,8,40,4,36,36,33,8,8, + 36,8,8,39,39,8,8,36,8,8,33,36,36,39,28,1,47,28, + 103,246,1,47,1,39,8,8,40,8,8,8,8,8,8,36, + 8,8,4,40,8,8,36,8,8,40,4,8,8,36,8,8, + 8,8,8,8,36,8,8,40,29,39,8,8,39,1,1,47, + 1,39,8,8,40,36,8,8,8,8,8,36,8,8,4,40, + 8,8,36,8,8,40,39,8,8,40,36,8,8,8,8,8, + 36,8,8,39,40,8,8,40,36,8,8,8,8,36,28,1,1,29, + 103,47,40,40,4,36,8,8,36,8,8,33,36,36,36,4, + 8,8,39,4,8,8,36,8,8,4,40,8,8,36,8,8, + 33,36,36,36,36,8,8,40,31,40,8,8,40,47,40,40, + 4,36,8,8,36,8,8,33,33,8,8,36,8,8,36,36, + 8,8,36,8,8,36,36,8,8,36,8,8,33,33,8,8, + 36,8,8,36,36,8,8,4,39,36,36,33,8,8,4,40,4,31, + 191,40,8,8,8,8,8,36,29,36,8,8,8,8,8,40, + 8,8,40,4,8,8,36,8,8,40,39,8,8,39,36,8, + 8,8,8,8,39,8,8,39,45,4,8,8,40,40,8,8, + 8,8,8,36,29,36,8,8,8,8,8,40,36,8,8,8, + 8,8,40,36,8,8,8,8,8,40,36,8,8,8,8,8, + 40,36,8,8,8,8,8,36,8,8,8,8,8,36,4,8,8,4, + 47,45,40,39,40,39,39,245,246,1,40,40,40,39,4,47, + 40,4,28,29,39,40,30,39,39,1,28,40,4,28,1,40, + 40,40,39,4,29,40,39,1,1,1,4,4,47,45,40,39, + 40,39,39,245,246,29,39,40,40,40,4,47,28,39,39,36, + 8,8,4,1,39,40,4,40,40,1,29,4,39,4,40,39, + 1,39,36,36,33,8,8,4,39,4,39,4,40,47,36,8,8,40, + 1,28,47,28,28,29,1,28,47,28,31,28,28,27,47,28, + 45,246,30,28,245,29,47,47,29,30,28,47,27,1,246,47, + 47,47,1,28,47,28,47,1,47,47,1,29,29,47,47,28, + 28,29,1,47,1,47,47,28,31,47,47,31,47,47,47,4, + 8,8,39,245,1,47,28,245,28,47,31,28,47,28,28,28, + 40,8,8,8,8,8,36,47,28,1,246,47,1,40,8,8,36,1, + 47,1,102,1,102,102,47,94,94,102,47,47,102,102,102,102, + 94,1,94,47,102,1,102,47,30,30,102,27,47,102,94,1, + 102,47,1,94,102,103,1,102,103,103,47,47,47,29,1,29, + 28,28,29,28,1,47,28,31,29,1,47,29,28,1,1,47, + 4,39,1,47,47,1,28,28,28,47,1,28,45,28,47,47, + 1,40,4,4,40,4,29,28,31,45,47,28,47,47,4,40,28,28 +}; + +static void +fixQuitScreen(byte* px) +{ + // overwrite 11 lines, 98 pixels each, from quitscreenfix[] + // starting at line 140, column 188 + // quitscreen is 320x240 px + int r, qsIdx = 0; + + px += 140*320; // go to line 140 + px += 188; // to colum 188 + for(r=0; r<11; ++r) + { + memcpy(px, quitscreenfix+qsIdx, 98); + qsIdx += 98; + px += 320; + } +} + +void +LoadPCX(char *origname, byte **pic, byte **palette, int *width, int *height) +{ + byte *raw; + pcx_t *pcx; + int x, y; + int len, full_size; + int pcx_width, pcx_height; + qboolean image_issues = false; + int dataByte, runLength; + byte *out, *pix; + char filename[256]; + + Q_strlcpy(filename, origname, sizeof(filename)); + + /* Add the extension */ + if (strcmp(COM_FileExtension(filename), "pcx")) + { + Q_strlcat(filename, ".pcx", sizeof(filename)); + } + + *pic = NULL; + + if (palette) + { + *palette = NULL; + } + + /* load the file */ + len = ri.FS_LoadFile(filename, (void **)&raw); + + if (!raw || len < sizeof(pcx_t)) + { + R_Printf(PRINT_DEVELOPER, "Bad pcx file %s\n", filename); + return; + } + + /* parse the PCX file */ + pcx = (pcx_t *)raw; + + pcx->xmin = LittleShort(pcx->xmin); + pcx->ymin = LittleShort(pcx->ymin); + pcx->xmax = LittleShort(pcx->xmax); + pcx->ymax = LittleShort(pcx->ymax); + pcx->hres = LittleShort(pcx->hres); + pcx->vres = LittleShort(pcx->vres); + pcx->bytes_per_line = LittleShort(pcx->bytes_per_line); + pcx->palette_type = LittleShort(pcx->palette_type); + + raw = &pcx->data; + + pcx_width = pcx->xmax - pcx->xmin; + pcx_height = pcx->ymax - pcx->ymin; + + if ((pcx->manufacturer != 0x0a) || (pcx->version != 5) || + (pcx->encoding != 1) || (pcx->bits_per_pixel != 8) || + (pcx_width >= 4096) || (pcx_height >= 4096)) + { + R_Printf(PRINT_ALL, "Bad pcx file %s\n", filename); + ri.FS_FreeFile(pcx); + return; + } + + full_size = (pcx_height + 1) * (pcx_width + 1); + out = malloc(full_size); + if (!out) + { + R_Printf(PRINT_ALL, "Can't allocate\n"); + ri.FS_FreeFile(pcx); + return; + } + + *pic = out; + + pix = out; + + if (palette) + { + *palette = malloc(768); + if (!(*palette)) + { + R_Printf(PRINT_ALL, "Can't allocate\n"); + free(out); + ri.FS_FreeFile(pcx); + return; + } + if (len > 768) + { + memcpy(*palette, (byte *)pcx + len - 768, 768); + } + else + { + image_issues = true; + } + } + + if (width) + { + *width = pcx_width + 1; + } + + if (height) + { + *height = pcx_height + 1; + } + + for (y = 0; y <= pcx_height; y++, pix += pcx_width + 1) + { + for (x = 0; x <= pcx_width; ) + { + if (raw - (byte *)pcx > len) + { + // no place for read + image_issues = true; + x = pcx_width; + break; + } + dataByte = *raw++; + + if ((dataByte & 0xC0) == 0xC0) + { + runLength = dataByte & 0x3F; + if (raw - (byte *)pcx > len) + { + // no place for read + image_issues = true; + x = pcx_width; + break; + } + dataByte = *raw++; + } + else + { + runLength = 1; + } + + while (runLength-- > 0) + { + if ((*pic + full_size) <= (pix + x)) + { + // no place for write + image_issues = true; + x += runLength; + runLength = 0; + } + else + { + pix[x++] = dataByte; + } + } + } + } + + if (raw - (byte *)pcx > len) + { + R_Printf(PRINT_DEVELOPER, "PCX file %s was malformed", filename); + free(*pic); + *pic = NULL; + } + else if(pcx_width == 319 && pcx_height == 239 + && Q_strcasecmp(origname, "pics/quit.pcx") == 0 + && Com_BlockChecksum(pcx, len) == 3329419434u) + { + // it's the quit screen, and the baseq2 one (identified by checksum) + // so fix it + fixQuitScreen(*pic); + } + + if (image_issues) + { + R_Printf(PRINT_ALL, "PCX file %s has possible size issues.\n", filename); + } + + ri.FS_FreeFile(pcx); +} + +void +GetPCXInfo(char *filename, int *width, int *height) +{ + pcx_t *pcx; + byte *raw; + + ri.FS_LoadFile(filename, (void **)&raw); + + if (!raw) + { + return; + } + + pcx = (pcx_t *)raw; + + *width = pcx->xmax + 1; + *height = pcx->ymax + 1; + + ri.FS_FreeFile(raw); + + return; +} + diff --git a/src/files/pvs.c b/src/files/pvs.c new file mode 100644 index 0000000..5318500 --- /dev/null +++ b/src/files/pvs.c @@ -0,0 +1,90 @@ +/* + * Copyright (C) 1997-2001 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. + * + * ======================================================================= + * + * The PVS Decompress + * + * ======================================================================= + */ + +#include "../common/header/ref_shared.h" + + +/* +=================== +Mod_DecompressVis +=================== +*/ +byte * +Mod_DecompressVis(byte *in, int row) +{ + YQ2_ALIGNAS_TYPE(int) static byte decompressed[MAX_MAP_LEAFS / 8]; + int c; + byte *out; + + out = decompressed; + + if (!in) + { + /* no vis info, so make all visible */ + while (row) + { + *out++ = 0xff; + row--; + } + + return decompressed; + } + + do + { + if (*in) + { + *out++ = *in++; + continue; + } + + c = in[1]; + in += 2; + + while (c) + { + *out++ = 0; + c--; + } + } + while (out - decompressed < row); + + return decompressed; +} + +float +Mod_RadiusFromBounds(const vec3_t mins, const vec3_t maxs) +{ + int i; + vec3_t corner; + + for (i = 0; i < 3; i++) + { + corner[i] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]); + } + + return VectorLength(corner); +} diff --git a/src/files/stb.c b/src/files/stb.c new file mode 100644 index 0000000..b96a84c --- /dev/null +++ b/src/files/stb.c @@ -0,0 +1,425 @@ +/* + * Copyright (C) 1997-2001 Id Software, Inc. + * Copyright (C) 2015 Daniel Gibson + * + * 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. + * + * ======================================================================= + * + * File formats supported by stb_image, for now only tga, png, jpg + * See also https://github.com/nothings/stb + * + * ======================================================================= + */ + +#include + +#include "../common/header/ref_shared.h" + +// don't need HDR stuff +#define STBI_NO_LINEAR +#define STBI_NO_HDR +// make sure STB_image uses standard malloc(), as we'll use standard free() to deallocate +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,sz) realloc(p,sz) +#define STBI_FREE(p) free(p) +// include implementation part of stb_image into this file +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" + +// include resize implementation +#define STB_IMAGE_RESIZE_IMPLEMENTATION +#include "stb_image_resize.h" + +/* + * origname: the filename to be opened, might be without extension + * type: extension of the type we wanna open ("jpg", "png" or "tga") + * pic: pointer RGBA pixel data will be assigned to + */ +qboolean +LoadSTB(const char *origname, const char* type, byte **pic, int *width, int *height) +{ + char filename[256]; + + Q_strlcpy(filename, origname, sizeof(filename)); + + /* Add the extension */ + if (strcmp(COM_FileExtension(filename), type) != 0) + { + Q_strlcat(filename, ".", sizeof(filename)); + Q_strlcat(filename, type, sizeof(filename)); + } + + *pic = NULL; + + byte* rawdata = NULL; + int rawsize = ri.FS_LoadFile(filename, (void **)&rawdata); + if (rawdata == NULL) + { + return false; + } + + int w, h, bytesPerPixel; + byte* data = NULL; + data = stbi_load_from_memory(rawdata, rawsize, &w, &h, &bytesPerPixel, STBI_rgb_alpha); + if (data == NULL) + { + R_Printf(PRINT_ALL, "%s couldn't load data from %s: %s!\n", __func__, filename, stbi_failure_reason()); + ri.FS_FreeFile(rawdata); + return false; + } + + ri.FS_FreeFile(rawdata); + + R_Printf(PRINT_DEVELOPER, "%s() loaded: %s\n", __func__, filename); + + *pic = data; + *width = w; + *height = h; + return true; +} + +qboolean +ResizeSTB(byte *input_pixels, int input_width, int input_height, + byte *output_pixels, int output_width, int output_height) +{ + if (stbir_resize_uint8(input_pixels, input_width, input_height, 0, + output_pixels, output_width, output_height, 0, 4)) + return true; + return false; +} + +// We have 16 color palette, 256 / 16 should be enough +#define COLOR_DISTANCE 16 + +void +SmoothColorImage(unsigned *dst, size_t size, size_t rstep) +{ + unsigned *full_size; + unsigned last_color; + unsigned *last_diff; + + // maximum step for apply + if (rstep < 2) + { + return; + } + + // step one pixel back as with check one pixel more + full_size = dst + size - rstep - 1; + last_diff = dst; + last_color = *dst; + + // skip current point + dst ++; + + while (dst < full_size) + { + if (last_color != *dst) + { + int step = dst - last_diff; + if (step > 1) + { + int a_beg, b_beg, c_beg, d_beg; + int a_end, b_end, c_end, d_end; + int a_step, b_step, c_step, d_step; + int k; + + // minimize effect size to rstep + if (step > rstep) + { + // change place for start effect + last_diff += (step - rstep); + step = rstep; + } + + // compare next pixels + for(k = 1; k <= step; k ++) + { + if (dst[k] != dst[0]) + { + break; + } + } + + // step back as pixel different after previous step + k --; + + // mirror steps + if (k < step) + { + // R_Printf(PRINT_ALL, "%s %d -> %d\n", __func__, k, step); + // change place for start effect + last_diff += (step - k); + step = k; + } + + // update step to correct value + step += k; + dst += k; + + // get colors + a_beg = (last_color >> 0 ) & 0xff; + b_beg = (last_color >> 8 ) & 0xff; + c_beg = (last_color >> 16) & 0xff; + d_beg = (last_color >> 24) & 0xff; + + a_end = (*dst >> 0 ) & 0xff; + b_end = (*dst >> 8 ) & 0xff; + c_end = (*dst >> 16) & 0xff; + d_end = (*dst >> 24) & 0xff; + + a_step = a_end - a_beg; + b_step = b_end - b_beg; + c_step = c_end - c_beg; + d_step = d_end - d_beg; + + if ((abs(a_step) <= COLOR_DISTANCE) && + (abs(b_step) <= COLOR_DISTANCE) && + (abs(c_step) <= COLOR_DISTANCE) && + (abs(d_step) <= COLOR_DISTANCE) && + step > 0) + { + // generate color change steps + a_step = (a_step << 16) / step; + b_step = (b_step << 16) / step; + c_step = (c_step << 16) / step; + d_step = (d_step << 16) / step; + + // apply color changes + for (k=0; k < step; k++) + { + *last_diff = (((a_beg + ((a_step * k) >> 16)) << 0) & 0x000000ff) | + (((b_beg + ((b_step * k) >> 16)) << 8) & 0x0000ff00) | + (((c_beg + ((c_step * k) >> 16)) << 16) & 0x00ff0000) | + (((d_beg + ((d_step * k) >> 16)) << 24) & 0xff000000); + last_diff++; + } + } + } + last_color = *dst; + last_diff = dst; + } + dst ++; + } +} + +/* https://en.wikipedia.org/wiki/Pixel-art_scaling_algorithms */ + +void +scale2x(byte *src, byte *dst, int width, int height) +{ + /* + EPX/Scale2×/AdvMAME2× + + x A x + C P B -> 1 2 + x D x 3 4 + + 1=P; 2=P; 3=P; 4=P; + IF C==A AND C!=D AND A!=B => 1=A + IF A==B AND A!=C AND B!=D => 2=B + IF D==C AND D!=B AND C!=A => 3=C + IF B==D AND B!=A AND D!=C => 4=D + */ + { + byte *in_buff = src; + byte *out_buff = dst; + byte *out_buff_full = dst + ((width * height) << 2); + while (out_buff < out_buff_full) + { + int x; + for (x = 0; x < width; x ++) + { + // copy one source byte to two destinatuion bytes + *out_buff = *in_buff; + out_buff ++; + *out_buff = *in_buff; + out_buff ++; + + // next source pixel + in_buff ++; + } + // copy last line one more time + memcpy(out_buff, out_buff - (width << 1), width << 1); + out_buff += width << 1; + } + } + + { + int y, h, w; + h = height - 1; + w = width - 1; + for (y = 0; y < height; y ++) + { + int x; + for (x = 0; x < width; x ++) + { + byte a, b, c, d, p; + + p = src[(width * (y )) + (x )]; + a = (y > 0) ? src[(width * (y - 1)) + (x )] : p; + b = (x < w) ? src[(width * (y )) + (x + 1)] : p; + c = (x > 0) ? src[(width * (y )) + (x - 1)] : p; + d = (y < h) ? src[(width * (y + 1)) + (x )] : p; + + if ((c == a) && (c != d) && (a != b)) + { + dst[(2 * width * ((y * 2) )) + ((x * 2) )] = a; + } + + if ((a == b) && (a != c) && (b != d)) + { + dst[(2 * width * ((y * 2) )) + ((x * 2) + 1)] = b; + } + + if ((d == c) && (d != b) && (c != a)) + { + dst[(2 * width * ((y * 2) + 1)) + ((x * 2) )] = c; + } + + if ((b == d) && (b != a) && (d != c)) + { + dst[(2 * width * ((y * 2) + 1)) + ((x * 2) + 1)] = d; + } + } + } + } +} + +void +scale3x(byte *src, byte *dst, int width, int height) +{ + /* + Scale3×/AdvMAME3× and ScaleFX + + A B C 1 2 3 + D E F -> 4 5 6 + G H I 7 8 9 + + + 1=E; 2=E; 3=E; 4=E; 5=E; 6=E; 7=E; 8=E; 9=E; + IF D==B AND D!=H AND B!=F => 1=D + IF (D==B AND D!=H AND B!=F AND E!=C) OR (B==F AND B!=D AND F!=H AND E!=A) => 2=B + IF B==F AND B!=D AND F!=H => 3=F + IF (H==D AND H!=F AND D!=B AND E!=A) OR (D==B AND D!=H AND B!=F AND E!=G) => 4=D + 5=E + IF (B==F AND B!=D AND F!=H AND E!=I) OR (F==H AND F!=B AND H!=D AND E!=C) => 6=F + IF H==D AND H!=F AND D!=B => 7=D + IF (F==H AND F!=B AND H!=D AND E!=G) OR (H==D AND H!=F AND D!=B AND E!=I) => 8=H + IF F==H AND F!=B AND H!=D => 9=F + */ + { + byte *in_buff = src; + byte *out_buff = dst; + byte *out_buff_full = dst + ((width * height) * 9); + while (out_buff < out_buff_full) + { + int x; + for (x = 0; x < width; x ++) + { + // copy one source byte to two destinatuion bytes + *out_buff = *in_buff; + out_buff ++; + *out_buff = *in_buff; + out_buff ++; + *out_buff = *in_buff; + out_buff ++; + + // next source pixel + in_buff ++; + } + // copy last line one more time + memcpy(out_buff, out_buff - (width * 3), width * 3); + out_buff += width * 3; + // copy last line one more time + memcpy(out_buff, out_buff - (width * 3), width * 3); + out_buff += width * 3; + } + } + + { + int y, z, w; + z = height - 1; + w = width - 1; + for (y = 0; y < height; y ++) + { + int x; + for (x = 0; x < width; x ++) + { + byte a, b, c, d, e, f, g, h, i; + + e = src[(width * y) + x]; + + a = ((y > 0) && (x > 0)) ? src[(width * (y - 1)) + (x - 1)] : e; + b = ((y > 0) && (x )) ? src[(width * (y - 1)) + (x )] : e; + c = ((y > 0) && (x < w)) ? src[(width * (y - 1)) + (x + 1)] : e; + + d = ( (x > 0)) ? src[(width * (y )) + (x - 1)] : e; + f = ( (x < w)) ? src[(width * (y )) + (x + 1)] : e; + + g = ((y < z) && (x > 0)) ? src[(width * (y + 1)) + (x - 1)] : e; + h = ((y < z) && (x )) ? src[(width * (y + 1)) + (x )] : e; + i = ((y < z) && (x < w)) ? src[(width * (y + 1)) + (x + 1)] : e; + + if ((d == b) && (d != h) && (b != f)) + { + dst[(3 * width * ((y * 3) )) + ((x * 3) )] = d; + } + + if (((d == b) && (d != h) && (b != f) && (e != c)) || + ((b == f) && (b != d) && (f != h) && (e != a))) + { + dst[(3 * width * ((y * 3) )) + ((x * 3) + 1)] = b; + } + + if ((b == f) && (b != d) && (f != h)) + { + dst[(3 * width * ((y * 3) )) + ((x * 3) + 2)] = f; + } + + if (((h == d) && (h != f) && (d != b) && (e != a)) || + ((d == b) && (d != h) && (b != f) && (e != g))) + { + dst[(3 * width * ((y * 3) + 1)) + ((x * 3) )] = d; + } + + if (((b == f) && (b != d) && (f != h) && (e != i)) || + ((f == h) && (f != b) && (h != d) && (e != c))) + { + dst[(3 * width * ((y * 3) + 1)) + ((x * 3) + 2)] = f; + } + + if ((h == d) && (h != f) && (d != b)) + { + dst[(3 * width * ((y * 3) + 2)) + ((x * 3) )] = d; + } + + if (((f == h) && (f != b) && (h != d) && (e != g)) || + ((h == d) && (h != f) && (d != b) && (e != i))) + { + dst[(3 * width * ((y * 3) + 2)) + ((x * 3) + 1)] = h; + } + + if ((f == h) && (f != b) && (h != d)) + { + dst[(3 * width * ((y * 3) + 2)) + ((x * 3) + 2)] = f; + } + } + } + } +} diff --git a/src/files/stb_image.h b/src/files/stb_image.h new file mode 100644 index 0000000..196dfd5 --- /dev/null +++ b/src/files/stb_image.h @@ -0,0 +1,7559 @@ +/* stb_image - v2.23 - public domain image loader - http://nothings.org/stb + no warranty implied; use at your own risk + + Do this: + #define STB_IMAGE_IMPLEMENTATION + before you include this file in *one* C or C++ file to create the implementation. + + // i.e. it should look like this: + #include ... + #include ... + #include ... + #define STB_IMAGE_IMPLEMENTATION + #include "stb_image.h" + + You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. + And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free + + + QUICK NOTES: + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface + + JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) + PNG 1/2/4/8/16-bit-per-channel + + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels, 8/16 bit-per-channel) + + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + PNM (PPM and PGM binary only) + + Animated GIF still needs a proper API, but here's one way to do it: + http://gist.github.com/urraka/685d9a6340b26b830d49 + + - decode from memory or through FILE (define STBI_NO_STDIO to remove code) + - decode from arbitrary I/O callbacks + - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) + + Full documentation under "DOCUMENTATION" below. + + +LICENSE + + See end of file for license information. + +RECENT REVISION HISTORY: + + 2.23 (2019-08-11) fix clang static analysis warning + 2.22 (2019-03-04) gif fixes, fix warnings + 2.21 (2019-02-25) fix typo in comment + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings + 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes + 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 + RGB-format JPEG; remove white matting in PSD; + allocate large structures on the stack; + correct channel count for PNG & BMP + 2.10 (2016-01-22) avoid warning introduced in 2.09 + 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED + + See end of file for full revision history. + + + ============================ Contributors ========================= + + Image formats Extensions, features + Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) + Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) + Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) + Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) + Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) + Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) + Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) + github:urraka (animated gif) Junggon Kim (PNM comments) + Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) + socks-the-fox (16-bit PNG) + Jeremy Sawicki (handle all ImageNet JPGs) + Optimizations & bugfixes Mikhail Morozov (1-bit BMP) + Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) + Arseny Kapoulkine + John-Mark Allen + Carmelo J Fdez-Aguera + + Bug & warning fixes + Marc LeBlanc David Woo Guillaume George Martins Mozeiko + Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan + Dave Moore Roy Eltham Hayaki Saito Nathan Reed + Won Chun Luke Graham Johan Duparc Nick Verigakis + the Horde3D community Thomas Ruf Ronny Chevalier github:rlyeh + Janez Zemva John Bartholomew Michal Cichon github:romigrou + Jonathan Blow Ken Hamada Tero Hanninen github:svdijk + Laurent Gomila Cort Stratton Sergio Gonzalez github:snagar + Aruelien Pocheville Thibault Reuille Cass Everitt github:Zelex + Ryamond Barbiero Paul Du Bois Engin Manap github:grim210 + Aldo Culquicondor Philipp Wiesemann Dale Weiler github:sammyhw + Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus + Julian Raschke Gregory Mullen Baldur Karlsson github:poppolopoppo + Christian Floisand Kevin Schmidt JR Smith github:darealshinji + Blazej Dariusz Roszkowski github:Michaelangel007 +*/ + +#ifndef STBI_INCLUDE_STB_IMAGE_H +#define STBI_INCLUDE_STB_IMAGE_H + +// DOCUMENTATION +// +// Limitations: +// - no 12-bit-per-channel JPEG +// - no JPEGs with arithmetic coding +// - GIF always returns *comp=4 +// +// Basic usage (see HDR discussion below for HDR usage): +// int x,y,n; +// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); +// // ... process data if not NULL ... +// // ... x = width, y = height, n = # 8-bit components per pixel ... +// // ... replace '0' with '1'..'4' to force that many components per pixel +// // ... but 'n' will always be the number that it would have been if you said 0 +// stbi_image_free(data) +// +// Standard parameters: +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *channels_in_file -- outputs # of image components in image file +// int desired_channels -- if non-zero, # of image components requested in result +// +// The return value from an image loader is an 'unsigned char *' which points +// to the pixel data, or NULL on an allocation failure or if the image is +// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, +// with each pixel consisting of N interleaved 8-bit components; the first +// pixel pointed to is top-left-most in the image. There is no padding between +// image scanlines or between pixels, regardless of format. The number of +// components N is 'desired_channels' if desired_channels is non-zero, or +// *channels_in_file otherwise. If desired_channels is non-zero, +// *channels_in_file has the number of components that _would_ have been +// output otherwise. E.g. if you set desired_channels to 4, you will always +// get RGBA output, but you can check *channels_in_file to see if it's trivially +// opaque because e.g. there were only 3 channels in the source image. +// +// An output image with N components has the following components interleaved +// in this order in each pixel: +// +// N=#comp components +// 1 grey +// 2 grey, alpha +// 3 red, green, blue +// 4 red, green, blue, alpha +// +// If image loading fails for any reason, the return value will be NULL, +// and *x, *y, *channels_in_file will be unchanged. The function +// stbi_failure_reason() can be queried for an extremely brief, end-user +// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS +// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly +// more user-friendly ones. +// +// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. +// +// =========================================================================== +// +// UNICODE: +// +// If compiling for Windows and you wish to use Unicode filenames, compile +// with +// #define STBI_WINDOWS_UTF8 +// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert +// Windows wchar_t filenames to utf8. +// +// =========================================================================== +// +// Philosophy +// +// stb libraries are designed with the following priorities: +// +// 1. easy to use +// 2. easy to maintain +// 3. good performance +// +// Sometimes I let "good performance" creep up in priority over "easy to maintain", +// and for best performance I may provide less-easy-to-use APIs that give higher +// performance, in addition to the easy-to-use ones. Nevertheless, it's important +// to keep in mind that from the standpoint of you, a client of this library, +// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. +// +// Some secondary priorities arise directly from the first two, some of which +// provide more explicit reasons why performance can't be emphasized. +// +// - Portable ("ease of use") +// - Small source code footprint ("easy to maintain") +// - No dependencies ("ease of use") +// +// =========================================================================== +// +// I/O callbacks +// +// I/O callbacks allow you to read from arbitrary sources, like packaged +// files or some other source. Data read from callbacks are processed +// through a small internal buffer (currently 128 bytes) to try to reduce +// overhead. +// +// The three functions you must define are "read" (reads some bytes of data), +// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). +// +// =========================================================================== +// +// SIMD support +// +// The JPEG decoder will try to automatically use SIMD kernels on x86 when +// supported by the compiler. For ARM Neon support, you must explicitly +// request it. +// +// (The old do-it-yourself SIMD API is no longer supported in the current +// code.) +// +// On x86, SSE2 will automatically be used when available based on a run-time +// test; if not, the generic C versions are used as a fall-back. On ARM targets, +// the typical path is to have separate builds for NEON and non-NEON devices +// (at least this is true for iOS and Android). Therefore, the NEON support is +// toggled by a build flag: define STBI_NEON to get NEON loops. +// +// If for some reason you do not want to use any of SIMD code, or if +// you have issues compiling it, you can disable it entirely by +// defining STBI_NO_SIMD. +// +// =========================================================================== +// +// HDR image support (disable by defining STBI_NO_HDR) +// +// stb_image supports loading HDR images in general, and currently the Radiance +// .HDR file format specifically. You can still load any file through the existing +// interface; if you attempt to load an HDR file, it will be automatically remapped +// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// both of these constants can be reconfigured through this interface: +// +// stbi_hdr_to_ldr_gamma(2.2f); +// stbi_hdr_to_ldr_scale(1.0f); +// +// (note, do not use _inverse_ constants; stbi_image will invert them +// appropriately). +// +// Additionally, there is a new, parallel interface for loading files as +// (linear) floats to preserve the full dynamic range: +// +// float *data = stbi_loadf(filename, &x, &y, &n, 0); +// +// If you load LDR images through this interface, those images will +// be promoted to floating point values, run through the inverse of +// constants corresponding to the above: +// +// stbi_ldr_to_hdr_scale(1.0f); +// stbi_ldr_to_hdr_gamma(2.2f); +// +// Finally, given a filename (or an open file or memory block--see header +// file for details) containing image data, you can query for the "most +// appropriate" interface to use (that is, whether the image is HDR or +// not), using: +// +// stbi_is_hdr(char *filename); +// +// =========================================================================== +// +// iPhone PNG support: +// +// By default we convert iphone-formatted PNGs back to RGB, even though +// they are internally encoded differently. You can disable this conversion +// by calling stbi_convert_iphone_png_to_rgb(0), in which case +// you will always just get the native iphone "format" through (which +// is BGR stored in RGB). +// +// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per +// pixel to remove any premultiplied alpha *only* if the image file explicitly +// says there's premultiplied data (currently only happens in iPhone images, +// and only if iPhone convert-to-rgb processing is on). +// +// =========================================================================== +// +// ADDITIONAL CONFIGURATION +// +// - You can suppress implementation of any of the decoders to reduce +// your code footprint by #defining one or more of the following +// symbols before creating the implementation. +// +// STBI_NO_JPEG +// STBI_NO_PNG +// STBI_NO_BMP +// STBI_NO_PSD +// STBI_NO_TGA +// STBI_NO_GIF +// STBI_NO_HDR +// STBI_NO_PIC +// STBI_NO_PNM (.ppm and .pgm) +// +// - You can request *only* certain decoders and suppress all other ones +// (this will be more forward-compatible, as addition of new decoders +// doesn't require you to disable them explicitly): +// +// STBI_ONLY_JPEG +// STBI_ONLY_PNG +// STBI_ONLY_BMP +// STBI_ONLY_PSD +// STBI_ONLY_TGA +// STBI_ONLY_GIF +// STBI_ONLY_HDR +// STBI_ONLY_PIC +// STBI_ONLY_PNM (.ppm and .pgm) +// +// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still +// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB +// + + +#ifndef STBI_NO_STDIO +#include +#endif // STBI_NO_STDIO + +#define STBI_VERSION 1 + +enum +{ + STBI_default = 0, // only used for desired_channels + + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 +}; + +#include +typedef unsigned char stbi_uc; +typedef unsigned short stbi_us; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef STBIDEF +#ifdef STB_IMAGE_STATIC +#define STBIDEF static +#else +#define STBIDEF extern +#endif +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// PRIMARY API - works on images of any type +// + +// +// load image by filename, open file, or memory buffer +// + +typedef struct +{ + int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + int (*eof) (void *user); // returns nonzero if we are at end of file/data +} stbi_io_callbacks; + +//////////////////////////////////// +// +// 8-bits-per-channel interface +// + +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +#endif + +#ifdef STBI_WINDOWS_UTF8 +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif + +//////////////////////////////////// +// +// 16-bits-per-channel interface +// + +STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +#endif + +//////////////////////////////////// +// +// float-per-channel interface +// +#ifndef STBI_NO_LINEAR + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + + #ifndef STBI_NO_STDIO + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); + #endif +#endif + +#ifndef STBI_NO_HDR + STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); + STBIDEF void stbi_hdr_to_ldr_scale(float scale); +#endif // STBI_NO_HDR + +#ifndef STBI_NO_LINEAR + STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); + STBIDEF void stbi_ldr_to_hdr_scale(float scale); +#endif // STBI_NO_LINEAR + +// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); +#endif // STBI_NO_STDIO + + +// get a VERY brief reason for failure +// NOT THREADSAFE +STBIDEF const char *stbi_failure_reason (void); + +// free the loaded image -- this is just free() +STBIDEF void stbi_image_free (void *retval_from_stbi_load); + +// get image dimensions & components without fully decoding +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit (char const *filename); +STBIDEF int stbi_is_16_bit_from_file(FILE *f); +#endif + + + +// for image formats that explicitly notate that they have premultiplied alpha, +// we just return the colors as stored in the file. set this flag to force +// unpremultiplication. results are undefined if the unpremultiply overflow. +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); + +// indicate whether we should process iphone images back to canonical format, +// or just pass them through "as-is" +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); + +// flip the image vertically, so the first pixel in the output array is the bottom left +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); + +// ZLIB client - used by PNG, available for other purposes + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + + +#ifdef __cplusplus +} +#endif + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBI_INCLUDE_STB_IMAGE_H + +#ifdef STB_IMAGE_IMPLEMENTATION + +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ + || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ + || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ + || defined(STBI_ONLY_ZLIB) + #ifndef STBI_ONLY_JPEG + #define STBI_NO_JPEG + #endif + #ifndef STBI_ONLY_PNG + #define STBI_NO_PNG + #endif + #ifndef STBI_ONLY_BMP + #define STBI_NO_BMP + #endif + #ifndef STBI_ONLY_PSD + #define STBI_NO_PSD + #endif + #ifndef STBI_ONLY_TGA + #define STBI_NO_TGA + #endif + #ifndef STBI_ONLY_GIF + #define STBI_NO_GIF + #endif + #ifndef STBI_ONLY_HDR + #define STBI_NO_HDR + #endif + #ifndef STBI_ONLY_PIC + #define STBI_NO_PIC + #endif + #ifndef STBI_ONLY_PNM + #define STBI_NO_PNM + #endif +#endif + +#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) +#define STBI_NO_ZLIB +#endif + + +#include +#include // ptrdiff_t on osx +#include +#include +#include + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#include // ldexp, pow +#endif + +#ifndef STBI_NO_STDIO +#include +#endif + +#ifndef STBI_ASSERT +#include +#define STBI_ASSERT(x) assert(x) +#endif + +#ifdef __cplusplus +#define STBI_EXTERN extern "C" +#else +#define STBI_EXTERN extern +#endif + + +#ifndef _MSC_VER + #ifdef __cplusplus + #define stbi_inline inline + #else + #define stbi_inline + #endif +#else + #define stbi_inline __forceinline +#endif + + +#ifdef _MSC_VER +typedef unsigned short stbi__uint16; +typedef signed short stbi__int16; +typedef unsigned int stbi__uint32; +typedef signed int stbi__int32; +#else +#include +typedef uint16_t stbi__uint16; +typedef int16_t stbi__int16; +typedef uint32_t stbi__uint32; +typedef int32_t stbi__int32; +#endif + +// should produce compiler error if size is wrong +typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBI_NOTUSED(v) (void)(v) +#else +#define STBI_NOTUSED(v) (void)sizeof(v) +#endif + +#ifdef _MSC_VER +#define STBI_HAS_LROTL +#endif + +#ifdef STBI_HAS_LROTL + #define stbi_lrot(x,y) _lrotl(x,y) +#else + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) +#endif + +#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) +// ok +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)." +#endif + +#ifndef STBI_MALLOC +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,newsz) realloc(p,newsz) +#define STBI_FREE(p) free(p) +#endif + +#ifndef STBI_REALLOC_SIZED +#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) +#endif + +// x86/x64 detection +#if defined(__x86_64__) || defined(_M_X64) +#define STBI__X64_TARGET +#elif defined(__i386) || defined(_M_IX86) +#define STBI__X86_TARGET +#endif + +#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +// gcc doesn't support sse2 intrinsics unless you compile with -msse2, +// which in turn means it gets to use SSE2 everywhere. This is unfortunate, +// but previous attempts to provide the SSE2 functions with runtime +// detection caused numerous issues. The way architecture extensions are +// exposed in GCC/Clang is, sadly, not really suited for one-file libs. +// New behavior: if compiled with -msse2, we use SSE2 without any +// detection; if not, we don't use it at all. +#define STBI_NO_SIMD +#endif + +#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) +// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET +// +// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the +// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. +// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not +// simultaneously enabling "-mstackrealign". +// +// See https://github.com/nothings/stb/issues/81 for more information. +// +// So default to no SSE2 on 32-bit MinGW. If you've read this far and added +// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. +#define STBI_NO_SIMD +#endif + +#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) +#define STBI_SSE2 +#include + +#ifdef _MSC_VER + +#if _MSC_VER >= 1400 // not VC6 +#include // __cpuid +static int stbi__cpuid3(void) +{ + int info[4]; + __cpuid(info,1); + return info[3]; +} +#else +static int stbi__cpuid3(void) +{ + int res; + __asm { + mov eax,1 + cpuid + mov res,edx + } + return res; +} +#endif + +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; +} +#endif + +#else // assume GCC-style if not VC++ +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + // If we're even attempting to compile this on GCC/Clang, that means + // -msse2 is on, which means the compiler is allowed to use SSE2 + // instructions at will, and so are we. + return 1; +} +#endif + +#endif +#endif + +// ARM NEON +#if defined(STBI_NO_SIMD) && defined(STBI_NEON) +#undef STBI_NEON +#endif + +#ifdef STBI_NEON +#include +// assume GCC or Clang on ARM targets +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) +#endif + +#ifndef STBI_SIMD_ALIGN +#define STBI_SIMD_ALIGN(type, name) type name +#endif + +/////////////////////////////////////////////// +// +// stbi__context struct and start_xxx functions + +// stbi__context structure is our basic context used by all images, so it +// contains all the IO context, plus some basic image information +typedef struct +{ + stbi__uint32 img_x, img_y; + int img_n, img_out_n; + + stbi_io_callbacks io; + void *io_user_data; + + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; + + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; +} stbi__context; + + +static void stbi__refill_buffer(stbi__context *s); + +// initialize a memory-decode context +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) +{ + s->io.read = NULL; + s->read_from_callbacks = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; +} + +// initialize a callback-based context +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) +{ + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; +} + +#ifndef STBI_NO_STDIO + +static int stbi__stdio_read(void *user, char *data, int size) +{ + return (int) fread(data,1,size,(FILE*) user); +} + +static void stbi__stdio_skip(void *user, int n) +{ + fseek((FILE*) user, n, SEEK_CUR); +} + +static int stbi__stdio_eof(void *user) +{ + return feof((FILE*) user); +} + +static stbi_io_callbacks stbi__stdio_callbacks = +{ + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, +}; + +static void stbi__start_file(stbi__context *s, FILE *f) +{ + stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); +} + +//static void stop_file(stbi__context *s) { } + +#endif // !STBI_NO_STDIO + +static void stbi__rewind(stbi__context *s) +{ + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; + s->img_buffer_end = s->img_buffer_original_end; +} + +enum +{ + STBI_ORDER_RGB, + STBI_ORDER_BGR +}; + +typedef struct +{ + int bits_per_channel; + int num_channels; + int channel_order; +} stbi__result_info; + +#ifndef STBI_NO_JPEG +static int stbi__jpeg_test(stbi__context *s); +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNG +static int stbi__png_test(stbi__context *s); +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__png_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_BMP +static int stbi__bmp_test(stbi__context *s); +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_TGA +static int stbi__tga_test(stbi__context *s); +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s); +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__psd_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_HDR +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_test(stbi__context *s); +static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_GIF +static int stbi__gif_test(stbi__context *s); +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNM +static int stbi__pnm_test(stbi__context *s); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +// this is not threadsafe +static const char *stbi__g_failure_reason; + +STBIDEF const char *stbi_failure_reason(void) +{ + return stbi__g_failure_reason; +} + +static int stbi__err(const char *str) +{ + stbi__g_failure_reason = str; + return 0; +} + +static void *stbi__malloc(size_t size) +{ + return STBI_MALLOC(size); +} + +// stb_image uses ints pervasively, including for offset calculations. +// therefore the largest decoded image size we can support with the +// current code, even on 64-bit targets, is INT_MAX. this is not a +// significant limitation for the intended use case. +// +// we do, however, need to make sure our size calculations don't +// overflow. hence a few helper functions for size calculations that +// multiply integers together, making sure that they're non-negative +// and no overflow occurs. + +// return 1 if the sum is valid, 0 on overflow. +// negative terms are considered invalid. +static int stbi__addsizes_valid(int a, int b) +{ + if (b < 0) return 0; + // now 0 <= b <= INT_MAX, hence also + // 0 <= INT_MAX - b <= INTMAX. + // And "a + b <= INT_MAX" (which might overflow) is the + // same as a <= INT_MAX - b (no overflow) + return a <= INT_MAX - b; +} + +// returns 1 if the product is valid, 0 on overflow. +// negative factors are considered invalid. +static int stbi__mul2sizes_valid(int a, int b) +{ + if (a < 0 || b < 0) return 0; + if (b == 0) return 1; // mul-by-0 is always safe + // portable way to check for no overflows in a*b + return a <= INT_MAX/b; +} + +// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow +static int stbi__mad2sizes_valid(int a, int b, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); +} + +// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow +static int stbi__mad3sizes_valid(int a, int b, int c, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__addsizes_valid(a*b*c, add); +} + +// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); +} +#endif + +// mallocs with size overflow checking +static void *stbi__malloc_mad2(int a, int b, int add) +{ + if (!stbi__mad2sizes_valid(a, b, add)) return NULL; + return stbi__malloc(a*b + add); +} + +static void *stbi__malloc_mad3(int a, int b, int c, int add) +{ + if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; + return stbi__malloc(a*b*c + add); +} + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) +{ + if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; + return stbi__malloc(a*b*c*d + add); +} +#endif + +// stbi__err - error +// stbi__errpf - error returning pointer to float +// stbi__errpuc - error returning pointer to unsigned char + +#ifdef STBI_NO_FAILURE_STRINGS + #define stbi__err(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define stbi__err(x,y) stbi__err(y) +#else + #define stbi__err(x,y) stbi__err(x) +#endif + +#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) + +STBIDEF void stbi_image_free(void *retval_from_stbi_load) +{ + STBI_FREE(retval_from_stbi_load); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +#endif + +#ifndef STBI_NO_HDR +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +static int stbi__vertically_flip_on_load = 0; + +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load = flag_true_if_should_flip; +} + +static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields + ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed + ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order + ri->num_channels = 0; + + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNG + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_GIF + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PSD + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); + #endif + #ifndef STBI_NO_PIC + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + #ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s,x,y,comp,req_comp, ri); + #endif + + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); +} + +static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi_uc *reduced; + + reduced = (stbi_uc *) stbi__malloc(img_len); + if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling + + STBI_FREE(orig); + return reduced; +} + +static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi__uint16 *enlarged; + + enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); + if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + + STBI_FREE(orig); + return enlarged; +} + +static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) +{ + int row; + size_t bytes_per_row = (size_t)w * bytes_per_pixel; + stbi_uc temp[2048]; + stbi_uc *bytes = (stbi_uc *)image; + + for (row = 0; row < (h>>1); row++) { + stbi_uc *row0 = bytes + row*bytes_per_row; + stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; + // swap row0 with row1 + size_t bytes_left = bytes_per_row; + while (bytes_left) { + size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); + memcpy(temp, row0, bytes_copy); + memcpy(row0, row1, bytes_copy); + memcpy(row1, temp, bytes_copy); + row0 += bytes_copy; + row1 += bytes_copy; + bytes_left -= bytes_copy; + } + } +} + +#ifndef STBI_NO_GIF +static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) +{ + int slice; + int slice_size = w * h * bytes_per_pixel; + + stbi_uc *bytes = (stbi_uc *)image; + for (slice = 0; slice < z; ++slice) { + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; + } +} +#endif + +static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); + + if (result == NULL) + return NULL; + + if (ri.bits_per_channel != 8) { + STBI_ASSERT(ri.bits_per_channel == 16); + result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } + + // @TODO: move stbi__convert_format to here + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } + + return (unsigned char *) result; +} + +static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); + + if (result == NULL) + return NULL; + + if (ri.bits_per_channel != 16) { + STBI_ASSERT(ri.bits_per_channel == 8); + result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } + + // @TODO: move stbi__convert_format16 to here + // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); + } + + return (stbi__uint16 *) result; +} + +#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR) +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) +{ + if (stbi__vertically_flip_on_load && result != NULL) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); + } +} +#endif + +#ifndef STBI_NO_STDIO + +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); +#endif + +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbi__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) + return 0; + +#if _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + + +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__uint16 *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + stbi__uint16 *result; + if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file_16(f,x,y,comp,req_comp); + fclose(f); + return result; +} + + +#endif //!STBI_NO_STDIO + +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_mem(&s,buffer,len); + + result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); + if (stbi__vertically_flip_on_load) { + stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); + } + + return result; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + stbi__result_info ri; + float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); + if (hdr_data) + stbi__float_postprocess(hdr_data,x,y,comp,req_comp); + return hdr_data; + } + #endif + data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +} + +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} +#endif // !STBI_NO_STDIO + +#endif // !STBI_NO_LINEAR + +// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is +// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always +// reports false! + +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; + #endif +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +STBIDEF int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + long pos = ftell(f); + int res; + stbi__context s; + stbi__start_file(&s,f); + res = stbi__hdr_test(&s); + fseek(f, pos, SEEK_SET); + return res; + #else + STBI_NOTUSED(f); + return 0; + #endif +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; + #endif +} + +#ifndef STBI_NO_LINEAR +static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; + +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +#endif + +static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; + +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +enum +{ + STBI__SCAN_load=0, + STBI__SCAN_type, + STBI__SCAN_header +}; + +static void stbi__refill_buffer(stbi__context *s) +{ + int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start+1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } +} + +stbi_inline static stbi_uc stbi__get8(stbi__context *s) +{ + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; +} + +stbi_inline static int stbi__at_eof(stbi__context *s) +{ + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) return 1; + } + + return s->img_buffer >= s->img_buffer_end; +} + +static void stbi__skip(stbi__context *s, int n) +{ + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; +} + +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) +{ + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + int res, count; + + memcpy(buffer, s->img_buffer, blen); + + count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); + res = (count == (n-blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } + + if (s->img_buffer+n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} + +static int stbi__get16be(stbi__context *s) +{ + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); +} + +static stbi__uint32 stbi__get32be(stbi__context *s) +{ + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); +} + +#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) +// nothing +#else +static int stbi__get16le(stbi__context *s) +{ + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); +} +#endif + +#ifndef STBI_NO_BMP +static stbi__uint32 stbi__get32le(stbi__context *s) +{ + stbi__uint32 z = stbi__get16le(s); + return z + (stbi__get16le(s) << 16); +} +#endif + +#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings + + +////////////////////////////////////////////////////////////////////////////// +// +// generic converter from built-in img_n to req_comp +// individual types do this automatically as much as possible (e.g. jpeg +// does all cases internally since it needs to colorspace convert anyway, +// and it never has alpha, so very few cases ). png can automatically +// interleave an alpha=255 channel, but falls back to this for other cases +// +// assume data buffer is malloced, so malloc a new one and free that one +// only failure mode is malloc failing + +static stbi_uc stbi__compute_y(int r, int g, int b) +{ + return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +} + +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + unsigned char *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + unsigned char *src = data + j * x * img_n ; + unsigned char *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} + +static stbi__uint16 stbi__compute_y_16(int r, int g, int b) +{ + return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); +} + +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + stbi__uint16 *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); + if (good == NULL) { + STBI_FREE(data); + return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + stbi__uint16 *src = data + j * x * img_n ; + stbi__uint16 *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output; + if (!data) return NULL; + output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); + } + } + if (n < comp) { + for (i=0; i < x*y; ++i) { + output[i*comp + n] = data[i*comp + n]/255.0f; + } + } + STBI_FREE(data); + return output; +} +#endif + +#ifndef STBI_NO_HDR +#define stbi__float2int(x) ((int) (x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output; + if (!data) return NULL; + output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + if (k < comp) { + float z = data[i*comp+k] * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + } + STBI_FREE(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder +// +// simple implementation +// - doesn't support delayed output of y-dimension +// - simple interface (only one output format: 8-bit interleaved RGB) +// - doesn't try to recover corrupt jpegs +// - doesn't allow partial loading, loading multiple at once +// - still fast on x86 (copying globals into locals doesn't help x86) +// - allocates lots of intermediate memory (full size of all components) +// - non-interleaved case requires this anyway +// - allows good upsampling (see next) +// high-quality +// - upsampled channels are bilinearly interpolated, even across blocks +// - quality integer IDCT derived from IJG's 'slow' +// performance +// - fast huffman; reasonable integer IDCT +// - some SIMD kernels for common paths on targets with SSE2/NEON +// - uses a lot of intermediate memory, could cache poorly + +#ifndef STBI_NO_JPEG + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} stbi__huffman; + +typedef struct +{ + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi__uint16 dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; + +// sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; + +// definition of jpeg image component + struct + { + int id; + int h,v; + int tq; + int hd,ha; + int dc_pred; + + int x,y,w2,h2; + stbi_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; + + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop + + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + int jfif; + int app14_color_transform; // Adobe APP14 tag + int rgb; + + int scan_n, order[4]; + int restart_interval, todo; + +// kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); +} stbi__jpeg; + +static int stbi__build_huffman(stbi__huffman *h, int *count) +{ + int i,j,k=0; + unsigned int code; + // build size list for each symbol (from JPEG spec) + for (i=0; i < 16; ++i) + for (j=0; j < count[i]; ++j) + h->size[k++] = (stbi_uc) (i+1); + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j=1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (stbi__uint16) (code++); + if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16-j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i=0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS-s); + int m = 1 << (FAST_BITS-s); + for (j=0; j < m; ++j) { + h->fast[c+j] = (stbi_uc) i; + } + } + } + return 1; +} + +// build a table that decodes both magnitude and value of small ACs in +// one go. +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) +{ + int i; + for (i=0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; + + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) k += (~0U << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); + } + } + } +} + +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) +{ + do { + unsigned int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes + if (c != 0) { + j->marker = (unsigned char) c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); +} + +// (1 << n) - 1 +static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; + +// decode a jpeg huffman value from the bitstream +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) +{ + unsigned int temp; + int c,k; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k=FAST_BITS+1 ; ; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } + + if (k > j->code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; +} + +// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); + + sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB + k = stbi_lrot(j->code_buffer, n); + STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & ~sgn); +} + +// get some unsigned bits +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) +{ + unsigned int k; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; +} + +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) +{ + unsigned int k; + if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; +} + +// given a value that's at position X in the zigzag stream, +// where does it appear in the 8x8 matrix coded as row-major? +static const stbi_uc stbi__jpeg_dezigzag[64+15] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63 +}; + +// decode one 64-entry block-- +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) +{ + int diff,dc,k; + int t; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + memset(data,0,64*sizeof(data[0])); + + diff = t ? stbi__extend_receive(j, t) : 0; + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc * dequant[0]); + + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); + } + } + } while (k < 64); + return 1; +} + +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) +{ + int diff,dc; + int t; + if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data,0,64*sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + diff = t ? stbi__extend_receive(j, t) : 0; + + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc << j->succ_low); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short) (1 << j->succ_low); + } + return 1; +} + +// @OPTIMIZE: store non-zigzagged during the decode passes, +// and only de-zigzag when dequantizing +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) +{ + int k; + if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->succ_high == 0) { + int shift = j->succ_low; + + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) << shift); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) << shift); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + + short bit = (short) (1 << j->succ_low); + + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r,s; + int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k++]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if (r == 0) { + *p = (short) s; + break; + } + --r; + } + } + } while (k <= j->spec_end); + } + } + return 1; +} + +// take a -128..127 value and stbi__clamp it and convert to 0..255 +stbi_inline static stbi_uc stbi__clamp(int x) +{ + // trick to use a single test to catch both cases + if ((unsigned int) x > 255) { + if (x < 0) return 0; + if (x > 255) return 255; + } + return (stbi_uc) x; +} + +#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) +#define stbi__fsh(x) ((x) * 4096) + +// derived from jidctint -- DCT_ISLOW +#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ + int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2+p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3*stbi__f2f(-1.847759065f); \ + t3 = p1 + p2*stbi__f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2+p3); \ + t1 = stbi__fsh(p2-p3); \ + x0 = t0+t3; \ + x3 = t0-t3; \ + x1 = t1+t2; \ + x2 = t1-t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0+t2; \ + p4 = t1+t3; \ + p1 = t0+t3; \ + p2 = t1+t2; \ + p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ + t0 = t0*stbi__f2f( 0.298631336f); \ + t1 = t1*stbi__f2f( 2.053119869f); \ + t2 = t2*stbi__f2f( 3.072711026f); \ + t3 = t3*stbi__f2f( 1.501321110f); \ + p1 = p5 + p1*stbi__f2f(-0.899976223f); \ + p2 = p5 + p2*stbi__f2f(-2.562915447f); \ + p3 = p3*stbi__f2f(-1.961570560f); \ + p4 = p4*stbi__f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) +{ + int i,val[64],*v=val; + stbi_uc *o; + short *d = data; + + // columns + for (i=0; i < 8; ++i,++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0]*4; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128<<17); + x1 += 65536 + (128<<17); + x2 += 65536 + (128<<17); + x3 += 65536 + (128<<17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0+t3) >> 17); + o[7] = stbi__clamp((x0-t3) >> 17); + o[1] = stbi__clamp((x1+t2) >> 17); + o[6] = stbi__clamp((x1-t2) >> 17); + o[2] = stbi__clamp((x2+t1) >> 17); + o[5] = stbi__clamp((x2-t1) >> 17); + o[3] = stbi__clamp((x3+t0) >> 17); + o[4] = stbi__clamp((x3-t0) >> 17); + } +} + +#ifdef STBI_SSE2 +// sse2 integer IDCT. not the fastest possible implementation but it +// produces bit-identical results to the generic C version so it's +// fully "transparent". +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; + + // dot product constant: even elems=x, odd elems=y + #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) + + // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) + // out(1) = c1[even]*x + c1[odd]*y + #define dct_rot(out0,out1, x,y,c0,c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) + + // out = in << 12 (in 16-bit, out 32-bit) + #define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) + + // wide add + #define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) + + // wide sub + #define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) + + // butterfly a/b, add bias, then shift by "s" and pack + #define dct_bfly32o(out0, out1, a,b,bias,s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } + + // 8-bit interleave step (for transposes) + #define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) + + // 16-bit interleave step (for transposes) + #define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) + + #define dct_pass(bias,shift) \ + { \ + /* even part */ \ + dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ + dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0,row7, x0,x7,bias,shift); \ + dct_bfly32o(row1,row6, x1,x6,bias,shift); \ + dct_bfly32o(row2,row5, x2,x5,bias,shift); \ + dct_bfly32o(row3,row4, x3,x4,bias,shift); \ + } + + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + + // load + row0 = _mm_load_si128((const __m128i *) (data + 0*8)); + row1 = _mm_load_si128((const __m128i *) (data + 1*8)); + row2 = _mm_load_si128((const __m128i *) (data + 2*8)); + row3 = _mm_load_si128((const __m128i *) (data + 3*8)); + row4 = _mm_load_si128((const __m128i *) (data + 4*8)); + row5 = _mm_load_si128((const __m128i *) (data + 5*8)); + row6 = _mm_load_si128((const __m128i *) (data + 6*8)); + row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + + // column pass + dct_pass(bias_0, 10); + + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); + + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); + + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } + + // row pass + dct_pass(bias_1, 17); + + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); + + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... + + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... + + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... + + // store + _mm_storel_epi64((__m128i *) out, p0); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p2); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p1); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p3); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); + } + +#undef dct_const +#undef dct_rot +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_interleave8 +#undef dct_interleave16 +#undef dct_pass +} + +#endif // STBI_SSE2 + +#ifdef STBI_NEON + +// NEON integer IDCT. should produce bit-identical +// results to the generic C version. +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; + + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) + +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) + +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) + +// wide add +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) + +// wide sub +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) + +// butterfly a/b, then shift using "shiftop" by "s" and pack +#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } + +#define dct_pass(shiftop, shift) \ + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ + dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ + dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ + dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ + } + + // load + row0 = vld1q_s16(data + 0*8); + row1 = vld1q_s16(data + 1*8); + row2 = vld1q_s16(data + 2*8); + row3 = vld1q_s16(data + 3*8); + row4 = vld1q_s16(data + 4*8); + row5 = vld1q_s16(data + 5*8); + row6 = vld1q_s16(data + 6*8); + row7 = vld1q_s16(data + 7*8); + + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + + // column pass + dct_pass(vrshrn_n_s32, 10); + + // 16bit 8x8 transpose + { +// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. +// whether compilers actually get this is another story, sadly. +#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } +#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } + + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); + + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); + + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); + +#undef dct_trn16 +#undef dct_trn32 +#undef dct_trn64 + } + + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); + + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } +#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } + + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! + + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); + + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); + + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); + + // store + vst1_u8(out, p0); out += out_stride; + vst1_u8(out, p1); out += out_stride; + vst1_u8(out, p2); out += out_stride; + vst1_u8(out, p3); out += out_stride; + vst1_u8(out, p4); out += out_stride; + vst1_u8(out, p5); out += out_stride; + vst1_u8(out, p6); out += out_stride; + vst1_u8(out, p7); + +#undef dct_trn8_8 +#undef dct_trn8_16 +#undef dct_trn8_32 + } + +#undef dct_long_mul +#undef dct_long_mac +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_pass +} + +#endif // STBI_NEON + +#define STBI__MARKER_none 0xff +// if there's a pending marker from the entropy stream, return that +// otherwise, fetch from the stream and get a marker. if there's no +// marker, return 0xff, which is never a valid marker value +static stbi_uc stbi__get_marker(stbi__jpeg *j) +{ + stbi_uc x; + if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } + x = stbi__get8(j->s); + if (x != 0xff) return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); // consume repeated 0xff fill bytes + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, stbi__jpeg_reset the entropy decoder and +// the dc prediction +static void stbi__jpeg_reset(stbi__jpeg *j) +{ + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int stbi__parse_entropy_coded_data(stbi__jpeg *z) +{ + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i,j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + STBI_SIMD_ALIGN(short, data[64]); + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x)*8; + int y2 = (j*z->img_comp[n].v + y)*8; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i,j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x); + int y2 = (j*z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} + +static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) +{ + int i; + for (i=0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) +{ + if (z->progressive) { + // dequantize and idct the data + int i,j,n; + for (n=0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + } + } + } + } +} + +static int stbi__process_marker(stbi__jpeg *z, int m) +{ + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker","Corrupt JPEG"); + + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s)-2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4, sixteen = (p != 0); + int t = q & 15,i; + if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); + if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + + for (i=0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); + L -= (sixteen ? 129 : 65); + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s)-2; + while (L > 0) { + stbi_uc *v; + int sizes[16],i,n=0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for (i=0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L==0; + } + + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + L = stbi__get16be(z->s); + if (L < 2) { + if (m == 0xFE) + return stbi__err("bad COM len","Corrupt JPEG"); + else + return stbi__err("bad APP len","Corrupt JPEG"); + } + L -= 2; + + if (m == 0xE0 && L >= 5) { // JFIF APP0 segment + static const unsigned char tag[5] = {'J','F','I','F','\0'}; + int ok = 1; + int i; + for (i=0; i < 5; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 5; + if (ok) + z->jfif = 1; + } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment + static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; + int ok = 1; + int i; + for (i=0; i < 6; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 6; + if (ok) { + stbi__get8(z->s); // version + stbi__get16be(z->s); // flags0 + stbi__get16be(z->s); // flags1 + z->app14_color_transform = stbi__get8(z->s); // color transform + L -= 6; + } + } + + stbi__skip(z->s, L); + return 1; + } + + return stbi__err("unknown marker","Corrupt JPEG"); +} + +// after we see SOS +static int stbi__process_scan_header(stbi__jpeg *z) +{ + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); + for (i=0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) return 0; // no match + z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); + z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); + z->order[i] = which; + } + + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); + z->spec_end = 63; + } + } + + return 1; +} + +static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) +{ + int i; + for (i=0; i < ncomp; ++i) { + if (z->img_comp[i].raw_data) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + z->img_comp[i].data = NULL; + } + if (z->img_comp[i].raw_coeff) { + STBI_FREE(z->img_comp[i].raw_coeff); + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].coeff = 0; + } + if (z->img_comp[i].linebuf) { + STBI_FREE(z->img_comp[i].linebuf); + z->img_comp[i].linebuf = NULL; + } + } + return why; +} + +static int stbi__process_frame_header(stbi__jpeg *z, int scan) +{ + stbi__context *s = z->s; + int Lf,p,i,q, h_max=1,v_max=1,c; + Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG + p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + c = stbi__get8(s); + if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); + s->img_n = c; + for (i=0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); + + z->rgb = 0; + for (i=0; i < s->img_n; ++i) { + static const unsigned char rgb[3] = { 'R', 'G', 'B' }; + z->img_comp[i].id = stbi__get8(s); + if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) + ++z->rgb; + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); + z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); + } + + if (scan != STBI__SCAN_load) return 1; + + if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); + + for (i=0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + // these sizes can't be more than 17 bits + z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + + for (i=0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + // + // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) + // so these muls can't overflow with 32-bit ints (which we require) + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].linebuf = NULL; + z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); + if (z->img_comp[i].raw_data == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + if (z->progressive) { + // w2, h2 are multiples of 8 (see above) + z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; + z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; + z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); + if (z->img_comp[i].raw_coeff == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); + } + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) + +#define stbi__SOF_progressive(x) ((x) == 0xc2) + +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) +{ + int m; + z->jfif = 0; + z->app14_color_transform = -1; // valid values are 0,1,2 + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); + if (scan == STBI__SCAN_type) return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z,m)) return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) return 0; + return 1; +} + +// decode image to YCbCr format +static int stbi__decode_jpeg_image(stbi__jpeg *j) +{ + int m; + for (m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) return 0; + if (!stbi__parse_entropy_coded_data(j)) return 0; + if (j->marker == STBI__MARKER_none ) { + // handle 0s at the end of image data from IP Kamera 9060 + while (!stbi__at_eof(j->s)) { + int x = stbi__get8(j->s); + if (x == 255) { + j->marker = stbi__get8(j->s); + break; + } + } + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 + } + } else if (stbi__DNL(m)) { + int Ld = stbi__get16be(j->s); + stbi__uint32 NL = stbi__get16be(j->s); + if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); + if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); + } else { + if (!stbi__process_marker(j, m)) return 0; + } + m = stbi__get_marker(j); + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, + int w, int hs); + +#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) + +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; +} + +static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i=0; i < w; ++i) + out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *input = in_near; + + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } + + out[0] = input[0]; + out[1] = stbi__div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = stbi__div4(n+input[i-1]); + out[i*2+1] = stbi__div4(n+input[i+1]); + } + out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); + out[i*2+1] = input[w-1]; + + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); + + return out; +} + +#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) + +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i,t0,t1; + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = stbi__div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i=0,t0,t1; + + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w-1) & ~7); i += 8) { +#if defined(STBI_SSE2) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); + + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); + + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *) (out + i*2), outv); +#elif defined(STBI_NEON) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); + + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i*2, o); +#endif + + // "previous" value for next iter + t1 = 3*in_near[i+7] + in_far[i+7]; + } + + t0 = t1; + t1 = 3*in_near[i] + in_far[i]; + out[i*2] = stbi__div16(3*t1 + t0 + 8); + + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} +#endif + +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // resample with nearest-neighbor + int i,j; + STBI_NOTUSED(in_far); + for (i=0; i < w; ++i) + for (j=0; j < hs; ++j) + out[i*hs+j] = in_near[i]; + return out; +} + +// this is a reduced-precision calculation of YCbCr-to-RGB introduced +// to make sure the code produces the same results in both SIMD and scalar +#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) +{ + int i = 0; + +#ifdef STBI_SSE2 + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); + __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); + __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); + __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); + __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); + __m128i xw = _mm_set1_epi16(255); // alpha channel + + for (; i+7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); + + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); + + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); + + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); + + // store + _mm_storeu_si128((__m128i *) (out + 0), o0); + _mm_storeu_si128((__m128i *) (out + 16), o1); + out += 32; + } + } +#endif + +#ifdef STBI_NEON + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); + int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); + int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); + int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + + for (; i+7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); + + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); + + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); + + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8*4; + } + } +#endif + + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +// set up the kernels +static void stbi__setup_jpeg(stbi__jpeg *j) +{ + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; + +#ifdef STBI_SSE2 + if (stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } +#endif + +#ifdef STBI_NEON + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; +#endif +} + +// clean up the temporary component buffers +static void stbi__cleanup_jpeg(stbi__jpeg *j) +{ + stbi__free_jpeg_components(j, j->s->img_n, 0); +} + +typedef struct +{ + resample_row_func resample; + stbi_uc *line0,*line1; + int hs,vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on +} stbi__resample; + +// fast 0..255 * 0..255 => 0..255 rounded multiplication +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) +{ + unsigned int t = x*y + 128; + return (stbi_uc) ((t + (t >>8)) >> 8); +} + +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) +{ + int n, decode_n, is_rgb; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe + + // validate req_comp + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; + + is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + + if (z->s->img_n == 3 && n < 3 && !is_rgb) + decode_n = 1; + else + decode_n = z->s->img_n; + + // resample and color-convert + { + int k; + unsigned int i,j; + stbi_uc *output; + stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL }; + + stbi__resample res_comp[4]; + + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs-1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; + else r->resample = stbi__resample_row_generic; + } + + // can't error after this so, this is safe + output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); + if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < z->s->img_y; ++j) { + stbi_uc *out = output + n * z->s->img_x * j; + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + stbi_uc *y = coutput[0]; + if (z->s->img_n == 3) { + if (is_rgb) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = y[i]; + out[1] = coutput[1][i]; + out[2] = coutput[2][i]; + out[3] = 255; + out += n; + } + } else { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else if (z->s->img_n == 4) { + if (z->app14_color_transform == 0) { // CMYK + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(coutput[0][i], m); + out[1] = stbi__blinn_8x8(coutput[1][i], m); + out[2] = stbi__blinn_8x8(coutput[2][i], m); + out[3] = 255; + out += n; + } + } else if (z->app14_color_transform == 2) { // YCCK + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(255 - out[0], m); + out[1] = stbi__blinn_8x8(255 - out[1], m); + out[2] = stbi__blinn_8x8(255 - out[2], m); + out += n; + } + } else { // YCbCr + alpha? Ignore the fourth channel for now + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else + for (i=0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + if (is_rgb) { + if (n == 1) + for (i=0; i < z->s->img_x; ++i) + *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + else { + for (i=0; i < z->s->img_x; ++i, out += 2) { + out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + out[1] = 255; + } + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); + stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); + stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); + out[0] = stbi__compute_y(r, g, b); + out[1] = 255; + out += n; + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); + out[1] = 255; + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; } + } + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output + return output; + } +} + +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + unsigned char* result; + stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + STBI_NOTUSED(ri); + j->s = s; + stbi__setup_jpeg(j); + result = load_jpeg_image(j, x,y,comp,req_comp); + STBI_FREE(j); + return result; +} + +static int stbi__jpeg_test(stbi__context *s) +{ + int r; + stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); + stbi__rewind(s); + STBI_FREE(j); + return r; +} + +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) +{ + if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind( j->s ); + return 0; + } + if (x) *x = j->s->img_x; + if (y) *y = j->s->img_y; + if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; + return 1; +} + +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) +{ + int result; + stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); + j->s = s; + result = stbi__jpeg_info_raw(j, x, y, comp); + STBI_FREE(j); + return result; +} +#endif + +// public domain zlib decode v0.2 Sean Barrett 2006-11-18 +// simple implementation +// - all input must be provided in an upfront buffer +// - all output is written to a single output buffer (can malloc/realloc) +// performance +// - fast huffman + +#ifndef STBI_NO_ZLIB + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[288]; + stbi__uint16 value[288]; +} stbi__zhuffman; + +stbi_inline static int stbi__bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +stbi_inline static int stbi__bit_reverse(int v, int bits) +{ + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16-bits); +} + +static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 0, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16) code; + z->firstsymbol[i] = (stbi__uint16) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); + z->maxcode[i] = code << (16-i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); + z->size [c] = (stbi_uc ) s; + z->value[c] = (stbi__uint16) i; + if (s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s],s); + while (j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +// zlib-from-memory implementation for PNG reading +// because PNG allows splitting the zlib stream arbitrarily, +// and it's annoying structurally to have PNG call ZLIB call PNG, +// we require PNG read all the IDATs and combine them into a single +// memory buffer + +typedef struct +{ + stbi_uc *zbuffer, *zbuffer_end; + int num_bits; + stbi__uint32 code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; + + stbi__zhuffman z_length, z_distance; +} stbi__zbuf; + +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) +{ + if (z->zbuffer >= z->zbuffer_end) return 0; + return *z->zbuffer++; +} + +static void stbi__fill_bits(stbi__zbuf *z) +{ + do { + STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); + z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s,k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s=STBI__ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s == 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + STBI_ASSERT(z->size[b] == s); + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s; + if (a->num_bits < 16) stbi__fill_bits(a); + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); +} + +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +{ + char *q; + int cur, limit, old_limit; + z->zout = zout; + if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); + cur = (int) (z->zout - z->zout_start); + limit = old_limit = (int) (z->zout_end - z->zout_start); + while (cur + n > limit) + limit *= 2; + q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); + STBI_NOTUSED(old_limit); + if (q == NULL) return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static const int stbi__zlength_base[31] = { + 3,4,5,6,7,8,9,10,11,13, + 15,17,19,23,27,31,35,43,51,59, + 67,83,99,115,131,163,195,227,258,0,0 }; + +static const int stbi__zlength_extra[31]= +{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + +static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + +static const int stbi__zdist_extra[32] = +{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +static int stbi__parse_huffman_block(stbi__zbuf *a) +{ + char *zout = a->zout; + for(;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) return 0; + zout = a->zout; + } + *zout++ = (char) z; + } else { + stbi_uc *p; + int len,dist; + if (z == 256) { + a->zout = zout; + return 1; + } + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + if (zout + len > a->zout_end) { + if (!stbi__zexpand(a, zout, len)) return 0; + zout = a->zout; + } + p = (stbi_uc *) (zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if (len) { do *zout++ = v; while (--len); } + } else { + if (len) { do *zout++ = *p++; while (--len); } + } + } + } +} + +static int stbi__compute_huffman_codes(stbi__zbuf *a) +{ + static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286+32+137];//padding for maximum single op + stbi_uc codelength_sizes[19]; + int i,n; + + int hlit = stbi__zreceive(a,5) + 257; + int hdist = stbi__zreceive(a,5) + 1; + int hclen = stbi__zreceive(a,4) + 4; + int ntot = hlit + hdist; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = stbi__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < ntot) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); + if (c < 16) + lencodes[n++] = (stbi_uc) c; + else { + stbi_uc fill = 0; + if (c == 16) { + c = stbi__zreceive(a,2)+3; + if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n-1]; + } else if (c == 17) + c = stbi__zreceive(a,3)+3; + else { + STBI_ASSERT(c == 18); + c = stbi__zreceive(a,7)+11; + } + if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); + memset(lencodes+n, fill, c); + n += c; + } + } + if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int stbi__parse_uncompressed_block(stbi__zbuf *a) +{ + stbi_uc header[4]; + int len,nlen,k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + STBI_ASSERT(a->num_bits == 0); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int stbi__parse_zlib_header(stbi__zbuf *a) +{ + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +static const stbi_uc stbi__zdefault_length[288] = +{ + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 +}; +static const stbi_uc stbi__zdefault_distance[32] = +{ + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 +}; +/* +Init algorithm: +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; + + for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; +} +*/ + +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) +{ + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + do { + final = stbi__zreceive(a,1); + type = stbi__zreceive(a,2); + if (type == 0) { + if (!stbi__parse_uncompressed_block(a)) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + } else { + if (!stbi__compute_huffman_codes(a)) return 0; + } + if (!stbi__parse_huffman_block(a)) return 0; + } + } while (!final); + return 1; +} + +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) +{ + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; + + return stbi__parse_zlib(a, parse_header); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(16384); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer+len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zout_start); + else + return -1; +} +#endif + +// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 +// simple implementation +// - only 8-bit samples +// - no CRC checking +// - allocates lots of intermediate memory +// - avoids problem of streaming data between subsystems +// - avoids explicit window management +// performance +// - uses stb_zlib, a PD zlib implementation with fast huffman decoding + +#ifndef STBI_NO_PNG +typedef struct +{ + stbi__uint32 length; + stbi__uint32 type; +} stbi__pngchunk; + +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) +{ + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; +} + +static int stbi__check_png_header(stbi__context *s) +{ + static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); + return 1; +} + +typedef struct +{ + stbi__context *s; + stbi_uc *idata, *expanded, *out; + int depth; +} stbi__png; + + +enum { + STBI__F_none=0, + STBI__F_sub=1, + STBI__F_up=2, + STBI__F_avg=3, + STBI__F_paeth=4, + // synthetic filters used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static stbi_uc first_row_filter[5] = +{ + STBI__F_none, + STBI__F_sub, + STBI__F_none, + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static int stbi__paeth(int a, int b, int c) +{ + int p = a + b - c; + int pa = abs(p-a); + int pb = abs(p-b); + int pc = abs(p-c); + if (pa <= pb && pa <= pc) return a; + if (pb <= pc) return b; + return c; +} + +static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; + +// create the png data from post-deflated data +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) +{ + int bytes = (depth == 16? 2 : 1); + stbi__context *s = a->s; + stbi__uint32 i,j,stride = x*out_n*bytes; + stbi__uint32 img_len, img_width_bytes; + int k; + int img_n = s->img_n; // copy it into a local for later + + int output_bytes = out_n*bytes; + int filter_bytes = img_n*bytes; + int width = x; + + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); + a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into + if (!a->out) return stbi__err("outofmem", "Out of memory"); + + if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + img_len = (img_width_bytes + 1) * y; + + // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, + // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), + // so just check for raw_len < img_len always. + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *prior; + int filter = *raw++; + + if (filter > 4) + return stbi__err("invalid filter","Corrupt PNG"); + + if (depth < 8) { + STBI_ASSERT(img_width_bytes <= x); + cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place + filter_bytes = 1; + width = img_width_bytes; + } + prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above + + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + + // handle first byte explicitly + for (k=0; k < filter_bytes; ++k) { + switch (filter) { + case STBI__F_none : cur[k] = raw[k]; break; + case STBI__F_sub : cur[k] = raw[k]; break; + case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; + case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; + case STBI__F_avg_first : cur[k] = raw[k]; break; + case STBI__F_paeth_first: cur[k] = raw[k]; break; + } + } + + if (depth == 8) { + if (img_n != out_n) + cur[img_n] = 255; // first pixel + raw += img_n; + cur += out_n; + prior += out_n; + } else if (depth == 16) { + if (img_n != out_n) { + cur[filter_bytes] = 255; // first pixel top byte + cur[filter_bytes+1] = 255; // first pixel bottom byte + } + raw += filter_bytes; + cur += output_bytes; + prior += output_bytes; + } else { + raw += 1; + cur += 1; + prior += 1; + } + + // this is a little gross, so that we don't switch per-pixel or per-component + if (depth < 8 || img_n == out_n) { + int nk = (width - 1)*filter_bytes; + #define STBI__CASE(f) \ + case f: \ + for (k=0; k < nk; ++k) + switch (filter) { + // "none" filter turns into a memcpy here; make that explicit. + case STBI__F_none: memcpy(cur, raw, nk); break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; + } + #undef STBI__CASE + raw += nk; + } else { + STBI_ASSERT(img_n+1 == out_n); + #define STBI__CASE(f) \ + case f: \ + for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ + for (k=0; k < filter_bytes; ++k) + switch (filter) { + STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; + } + #undef STBI__CASE + + // the loop above sets the high byte of the pixels' alpha, but for + // 16 bit png files we also need the low byte set. we'll do that here. + if (depth == 16) { + cur = a->out + stride*j; // start at the beginning of the row again + for (i=0; i < x; ++i,cur+=output_bytes) { + cur[filter_bytes+1] = 255; + } + } + } + } + + // we make a separate pass to expand bits to pixels; for performance, + // this could run two scanlines behind the above code, so it won't + // intefere with filtering but will still be in the cache. + if (depth < 8) { + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; + // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit + // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + + // note that the final byte might overshoot and write more data than desired. + // we can allocate enough data that this never writes out of memory, but it + // could also overwrite the next scanline. can it overwrite non-empty data + // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. + // so we need to explicitly clamp the final ones + + if (depth == 4) { + for (k=x*img_n; k >= 2; k-=2, ++in) { + *cur++ = scale * ((*in >> 4) ); + *cur++ = scale * ((*in ) & 0x0f); + } + if (k > 0) *cur++ = scale * ((*in >> 4) ); + } else if (depth == 2) { + for (k=x*img_n; k >= 4; k-=4, ++in) { + *cur++ = scale * ((*in >> 6) ); + *cur++ = scale * ((*in >> 4) & 0x03); + *cur++ = scale * ((*in >> 2) & 0x03); + *cur++ = scale * ((*in ) & 0x03); + } + if (k > 0) *cur++ = scale * ((*in >> 6) ); + if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); + if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); + } else if (depth == 1) { + for (k=x*img_n; k >= 8; k-=8, ++in) { + *cur++ = scale * ((*in >> 7) ); + *cur++ = scale * ((*in >> 6) & 0x01); + *cur++ = scale * ((*in >> 5) & 0x01); + *cur++ = scale * ((*in >> 4) & 0x01); + *cur++ = scale * ((*in >> 3) & 0x01); + *cur++ = scale * ((*in >> 2) & 0x01); + *cur++ = scale * ((*in >> 1) & 0x01); + *cur++ = scale * ((*in ) & 0x01); + } + if (k > 0) *cur++ = scale * ((*in >> 7) ); + if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); + if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); + if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); + if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); + if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); + if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); + } + if (img_n != out_n) { + int q; + // insert alpha = 255 + cur = a->out + stride*j; + if (img_n == 1) { + for (q=x-1; q >= 0; --q) { + cur[q*2+1] = 255; + cur[q*2+0] = cur[q]; + } + } else { + STBI_ASSERT(img_n == 3); + for (q=x-1; q >= 0; --q) { + cur[q*4+3] = 255; + cur[q*4+2] = cur[q*3+2]; + cur[q*4+1] = cur[q*3+1]; + cur[q*4+0] = cur[q*3+0]; + } + } + } + } + } else if (depth == 16) { + // force the image data from big-endian to platform-native. + // this is done in a separate pass due to the decoding relying + // on the data being untouched, but could probably be done + // per-line during decode if care is taken. + stbi_uc *cur = a->out; + stbi__uint16 *cur16 = (stbi__uint16*)cur; + + for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { + *cur16 = (cur[0] << 8) | cur[1]; + } + } + + return 1; +} + +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) +{ + int bytes = (depth == 16 ? 2 : 1); + int out_bytes = out_n * bytes; + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + + // de-interlacing + final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + for (p=0; p < 7; ++p) { + int xorig[] = { 0,4,0,2,0,1,0 }; + int yorig[] = { 0,0,4,0,2,0,1 }; + int xspc[] = { 8,8,4,4,2,2,1 }; + int yspc[] = { 8,8,8,4,4,2,2 }; + int i,j,x,y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; + if (x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for (j=0; j < y; ++j) { + for (i=0; i < x; ++i) { + int out_y = j*yspc[p]+yorig[p]; + int out_x = i*xspc[p]+xorig[p]; + memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, + a->out + (j*x+i)*out_bytes, out_bytes); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; + + return 1; +} + +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i=0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i=0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi__uint16 *p = (stbi__uint16*) z->out; + + // compute color-based transparency, assuming we've + // already got 65535 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 65535); + p += 2; + } + } else { + for (i = 0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) +{ + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; + + p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); + if (p == NULL) return stbi__err("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p += 3; + } + } else { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p[3] = palette[n+3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; +} + +static int stbi__unpremultiply_on_load = 0; +static int stbi__de_iphone_flag = 0; + +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag = flag_true_if_should_convert; +} + +static void stbi__de_iphone(stbi__png *z) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if (stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i=0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + stbi_uc half = a / 2; + p[0] = (p[2] * 255 + half) / a; + p[1] = (p[1] * 255 + half) / a; + p[2] = ( t * 255 + half) / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) + +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) +{ + stbi_uc palette[1024], pal_img_n=0; + stbi_uc has_trans=0, tc[3]={0}; + stbi__uint16 tc16[3]; + stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, color=0, is_iphone=0; + stbi__context *s = z->s; + + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; + + if (!stbi__check_png_header(s)) return 0; + + if (scan == STBI__SCAN_type) return 1; + + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C','g','B','I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I','H','D','R'): { + int comp,filter; + if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); + s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); + color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); + comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); + filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); + interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + if (scan == STBI__SCAN_header) return 1; + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); + // if SCAN_header, have to scan to see if we have a tRNS + } + break; + } + + case STBI__PNG_TYPE('P','L','T','E'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + } + break; + } + + case STBI__PNG_TYPE('t','R','N','S'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } + if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); + if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); + has_trans = 1; + if (z->depth == 16) { + for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + } else { + for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger + } + } + break; + } + + case STBI__PNG_TYPE('I','D','A','T'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); + if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } + if ((int)(ioff + c.length) < (int)ioff) return 0; + if (ioff + c.length > idata_limit) { + stbi__uint32 idata_limit_old = idata_limit; + stbi_uc *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + STBI_NOTUSED(idata_limit_old); + p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); + ioff += c.length; + break; + } + + case STBI__PNG_TYPE('I','E','N','D'): { + stbi__uint32 raw_len, bpl; + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) return 1; + if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); + if (z->expanded == NULL) return 0; // zlib should set error + STBI_FREE(z->idata); z->idata = NULL; + if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n+1; + else + s->img_out_n = s->img_n; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; + if (has_trans) { + if (z->depth == 16) { + if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; + } else { + if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + } + } + if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) s->img_out_n = req_comp; + if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } else if (has_trans) { + // non-paletted image with tRNS -> source image has (constant) alpha + ++s->img_n; + } + STBI_FREE(z->expanded); z->expanded = NULL; + return 1; + } + + default: + // if critical, fail + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); + #endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } +} + +static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) +{ + void *result=NULL; + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + if (p->depth < 8) + ri->bits_per_channel = 8; + else + ri->bits_per_channel = p->depth; + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + if (ri->bits_per_channel == 8) + result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + else + result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) *n = p->s->img_n; + } + STBI_FREE(p->out); p->out = NULL; + STBI_FREE(p->expanded); p->expanded = NULL; + STBI_FREE(p->idata); p->idata = NULL; + + return result; +} + +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi__png p; + p.s = s; + return stbi__do_png(&p, x,y,comp,req_comp, ri); +} + +static int stbi__png_test(stbi__context *s) +{ + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; +} + +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) +{ + if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { + stbi__rewind( p->s ); + return 0; + } + if (x) *x = p->s->img_x; + if (y) *y = p->s->img_y; + if (comp) *comp = p->s->img_n; + return 1; +} + +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); +} + +static int stbi__png_is16(stbi__context *s) +{ + stbi__png p; + p.s = s; + if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) + return 0; + if (p.depth != 16) { + stbi__rewind(p.s); + return 0; + } + return 1; +} +#endif + +// Microsoft/Windows BMP image + +#ifndef STBI_NO_BMP +static int stbi__bmp_test_raw(stbi__context *s) +{ + int r; + int sz; + if (stbi__get8(s) != 'B') return 0; + if (stbi__get8(s) != 'M') return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; +} + +static int stbi__bmp_test(stbi__context *s) +{ + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; +} + + +// returns 0..31 for the highest set bit +static int stbi__high_bit(unsigned int z) +{ + int n=0; + if (z == 0) return -1; + if (z >= 0x10000) { n += 16; z >>= 16; } + if (z >= 0x00100) { n += 8; z >>= 8; } + if (z >= 0x00010) { n += 4; z >>= 4; } + if (z >= 0x00004) { n += 2; z >>= 2; } + if (z >= 0x00002) { n += 1;/* >>= 1;*/ } + return n; +} + +static int stbi__bitcount(unsigned int a) +{ + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; +} + +// extract an arbitrarily-aligned N-bit value (N=bits) +// from v, and then make it 8-bits long and fractionally +// extend it to full full range. +static int stbi__shiftsigned(unsigned int v, int shift, int bits) +{ + static unsigned int mul_table[9] = { + 0, + 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, + 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, + }; + static unsigned int shift_table[9] = { + 0, 0,0,1,0,2,4,6,0, + }; + if (shift < 0) + v <<= -shift; + else + v >>= shift; + STBI_ASSERT(v >= 0 && v < 256); + v >>= (8-bits); + STBI_ASSERT(bits >= 0 && bits <= 8); + return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; +} + +typedef struct +{ + int bpp, offset, hsz; + unsigned int mr,mg,mb,ma, all_a; +} stbi__bmp_data; + +static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) +{ + int hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + info->offset = stbi__get32le(s); + info->hsz = hsz = stbi__get32le(s); + info->mr = info->mg = info->mb = info->ma = 0; + + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); + info->bpp = stbi__get16le(s); + if (hsz != 12) { + int compress = stbi__get32le(s); + if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (info->bpp == 16 || info->bpp == 32) { + if (compress == 0) { + if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } + } else if (compress == 3) { + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + // not documented, but generated by photoshop and handled by mspaint + if (info->mr == info->mg && info->mg == info->mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + int i; + if (hsz != 108 && hsz != 124) + return stbi__errpuc("bad BMP", "bad BMP"); + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->ma = stbi__get32le(s); + stbi__get32le(s); // discard color space + for (i=0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + } + return (void *) 1; +} + + +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + unsigned int mr=0,mg=0,mb=0,ma=0, all_a; + stbi_uc pal[256][4]; + int psize=0,i,j,width; + int flip_vertically, pad, target; + stbi__bmp_data info; + STBI_NOTUSED(ri); + + info.all_a = 255; + if (stbi__bmp_parse_header(s, &info) == NULL) + return NULL; // error code already set + + flip_vertically = ((int) s->img_y) > 0; + s->img_y = abs((int) s->img_y); + + mr = info.mr; + mg = info.mg; + mb = info.mb; + ma = info.ma; + all_a = info.all_a; + + if (info.hsz == 12) { + if (info.bpp < 24) + psize = (info.offset - 14 - 24) / 3; + } else { + if (info.bpp < 16) + psize = (info.offset - 14 - info.hsz) >> 2; + } + + if (info.bpp == 24 && ma == 0xff000000) + s->img_n = 3; + else + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + + // sanity-check size + if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "Corrupt BMP"); + + out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (info.bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } + for (i=0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (info.hsz != 12) stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + if (info.bpp == 1) width = (s->img_x + 7) >> 3; + else if (info.bpp == 4) width = (s->img_x + 1) >> 1; + else if (info.bpp == 8) width = s->img_x; + else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } + pad = (-width)&3; + if (info.bpp == 1) { + for (j=0; j < (int) s->img_y; ++j) { + int bit_offset = 7, v = stbi__get8(s); + for (i=0; i < (int) s->img_x; ++i) { + int color = (v>>bit_offset)&0x1; + out[z++] = pal[color][0]; + out[z++] = pal[color][1]; + out[z++] = pal[color][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + if((--bit_offset) < 0) { + bit_offset = 7; + v = stbi__get8(s); + } + } + stbi__skip(s, pad); + } + } else { + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=stbi__get8(s),v2=0; + if (info.bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + v = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + stbi__skip(s, pad); + } + } + } else { + int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; + int z = 0; + int easy=0; + stbi__skip(s, info.offset - 14 - info.hsz); + if (info.bpp == 24) width = 3 * s->img_x; + else if (info.bpp == 16) width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (info.bpp == 24) { + easy = 1; + } else if (info.bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { + for (i=0; i < (int) s->img_x; ++i) { + unsigned char a; + out[z+2] = stbi__get8(s); + out[z+1] = stbi__get8(s); + out[z+0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if (target == 4) out[z++] = a; + } + } else { + int bpp = info.bpp; + for (i=0; i < (int) s->img_x; ++i) { + stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); + unsigned int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if (target == 4) out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } + + // if alpha channel is all 0s, replace with all 255s + if (target == 4 && all_a == 0) + for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) + out[i] = 255; + + if (flip_vertically) { + stbi_uc t; + for (j=0; j < (int) s->img_y>>1; ++j) { + stbi_uc *p1 = out + j *s->img_x*target; + stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; + for (i=0; i < (int) s->img_x*target; ++i) { + t = p1[i]; p1[i] = p2[i]; p2[i] = t; + } + } + } + + if (req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + return out; +} +#endif + +// Targa Truevision - TGA +// by Jonathan Dummer +#ifndef STBI_NO_TGA +// returns STBI_rgb or whatever, 0 on error +static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) +{ + // only RGB or RGBA (incl. 16bit) or grey allowed + if (is_rgb16) *is_rgb16 = 0; + switch(bits_per_pixel) { + case 8: return STBI_grey; + case 16: if(is_grey) return STBI_grey_alpha; + // fallthrough + case 15: if(is_rgb16) *is_rgb16 = 1; + return STBI_rgb; + case 24: // fallthrough + case 32: return bits_per_pixel/8; + default: return 0; + } +} + +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) +{ + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; + int sz, tga_colormap_type; + stbi__get8(s); // discard Offset + tga_colormap_type = stbi__get8(s); // colormap type + if( tga_colormap_type > 1 ) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + tga_image_type = stbi__get8(s); // image type + if ( tga_colormap_type == 1 ) { // colormapped (paletted) image + if (tga_image_type != 1 && tga_image_type != 9) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip image x and y origin + tga_colormap_bpp = sz; + } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE + if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { + stbi__rewind(s); + return 0; // only RGB or grey allowed, +/- RLE + } + stbi__skip(s,9); // skip colormap specification and image x/y origin + tga_colormap_bpp = 0; + } + tga_w = stbi__get16le(s); + if( tga_w < 1 ) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if( tga_h < 1 ) { + stbi__rewind(s); + return 0; // test height + } + tga_bits_per_pixel = stbi__get8(s); // bits per pixel + stbi__get8(s); // ignore alpha bits + if (tga_colormap_bpp != 0) { + if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { + // when using a colormap, tga_bits_per_pixel is the size of the indexes + // I don't think anything but 8 or 16bit indexes makes sense + stbi__rewind(s); + return 0; + } + tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); + } else { + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); + } + if(!tga_comp) { + stbi__rewind(s); + return 0; + } + if (x) *x = tga_w; + if (y) *y = tga_h; + if (comp) *comp = tga_comp; + return 1; // seems to have passed everything +} + +static int stbi__tga_test(stbi__context *s) +{ + int res = 0; + int sz, tga_color_type; + stbi__get8(s); // discard Offset + tga_color_type = stbi__get8(s); // color type + if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if ( tga_color_type == 1 ) { // colormapped (paletted) image + if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + stbi__skip(s,4); // skip image x and y origin + } else { // "normal" image w/o colormap + if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE + stbi__skip(s,9); // skip colormap specification and image x/y origin + } + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height + sz = stbi__get8(s); // bits per pixel + if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + + res = 1; // if we got this far, everything's good and we can return 1 instead of 0 + +errorEnd: + stbi__rewind(s); + return res; +} + +// read 16bit value and convert to 24bit RGB +static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) +{ + stbi__uint16 px = (stbi__uint16)stbi__get16le(s); + stbi__uint16 fiveBitMask = 31; + // we have 3 channels with 5bits each + int r = (px >> 10) & fiveBitMask; + int g = (px >> 5) & fiveBitMask; + int b = px & fiveBitMask; + // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later + out[0] = (stbi_uc)((r * 255)/31); + out[1] = (stbi_uc)((g * 255)/31); + out[2] = (stbi_uc)((b * 255)/31); + + // some people claim that the most significant bit might be used for alpha + // (possibly if an alpha-bit is set in the "image descriptor byte") + // but that only made 16bit test images completely translucent.. + // so let's treat all 15 and 16bit TGAs as RGB with no alpha. +} + +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp, tga_rgb16=0; + int tga_inverted = stbi__get8(s); + // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4] = {0}; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + STBI_NOTUSED(ri); + STBI_NOTUSED(tga_x_origin); // @TODO + STBI_NOTUSED(tga_y_origin); // @TODO + + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // If I'm paletted, then I'll use the number of bits from the palette + if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); + else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); + + if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency + return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); + + // tga info + *x = tga_width; + *y = tga_height; + if (comp) *comp = tga_comp; + + if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) + return stbi__errpuc("too large", "Corrupt TGA"); + + tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); + if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset ); + + if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { + for (i=0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height -i - 1 : i; + stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if ( tga_indexed) + { + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start ); + // load the palette + tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + if (tga_rgb16) { + stbi_uc *pal_entry = tga_palette; + STBI_ASSERT(tga_comp == STBI_rgb); + for (i=0; i < tga_palette_len; ++i) { + stbi__tga_read_rgb16(s, pal_entry); + pal_entry += tga_comp; + } + } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + } + // load the data + for (i=0; i < tga_width * tga_height; ++i) + { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if ( tga_is_RLE ) + { + if ( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if ( !RLE_repeating ) + { + read_next_pixel = 1; + } + } else + { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if ( read_next_pixel ) + { + // load however much data we did have + if ( tga_indexed ) + { + // read in index, then perform the lookup + int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); + if ( pal_idx >= tga_palette_len ) { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_comp; + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else if(tga_rgb16) { + STBI_ASSERT(tga_comp == STBI_rgb); + stbi__tga_read_rgb16(s, raw_data); + } else { + // read in the data raw + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + + // copy data + for (j = 0; j < tga_comp; ++j) + tga_data[i*tga_comp+j] = raw_data[j]; + + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if ( tga_inverted ) + { + for (j = 0; j*2 < tga_height; ++j) + { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_comp; i > 0; --i) + { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if ( tga_palette != NULL ) + { + STBI_FREE( tga_palette ); + } + } + + // swap RGB - if the source data was RGB16, it already is in the right order + if (tga_comp >= 3 && !tga_rgb16) + { + unsigned char* tga_pixel = tga_data; + for (i=0; i < tga_width * tga_height; ++i) + { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } + + // convert to target component count + if (req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + STBI_NOTUSED(tga_palette_start); + // OK, done + return tga_data; +} +#endif + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s) +{ + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; +} + +static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) +{ + int count, nleft, len; + + count = 0; + while ((nleft = pixelCount - count) > 0) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + if (len > nleft) return 0; // corrupt data + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len = 257 - len; + if (len > nleft) return 0; // corrupt data + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + + return 1; +} + +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + int pixelCount; + int channelCount, compression; + int channel, i; + int bitdepth; + int w,h; + stbi_uc *out; + STBI_NOTUSED(ri); + + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + stbi__skip(s, 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); + + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + stbi__skip(s,stbi__get32be(s) ); + + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s) ); + + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s) ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + + // Check size + if (!stbi__mad3sizes_valid(4, w, h, 0)) + return stbi__errpuc("too large", "Corrupt PSD"); + + // Create the destination image. + + if (!compression && bitdepth == 16 && bpc == 16) { + out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); + ri->bits_per_channel = 16; + } else + out = (stbi_uc *) stbi__malloc(4 * w*h); + + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w*h; + + // Initialize the data to zero. + //memset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop + + // The RLE-compressed data is preceded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); + } else { + // Read the RLE data. + if (!stbi__psd_decode_rle(s, p, pixelCount)) { + STBI_FREE(out); + return stbi__errpuc("corrupt", "bad RLE data"); + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + if (channel >= channelCount) { + // Fill this channel with default data. + if (bitdepth == 16 && bpc == 16) { + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + stbi__uint16 val = channel == 3 ? 65535 : 0; + for (i = 0; i < pixelCount; i++, q += 4) + *q = val; + } else { + stbi_uc *p = out+channel; + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; + } + } else { + if (ri->bits_per_channel == 16) { // output bpc + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + for (i = 0; i < pixelCount; i++, q += 4) + *q = (stbi__uint16) stbi__get16be(s); + } else { + stbi_uc *p = out+channel; + if (bitdepth == 16) { // input bpc + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc) (stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + } + + // remove weird white matte from PSD + if (channelCount >= 4) { + if (ri->bits_per_channel == 16) { + for (i=0; i < w*h; ++i) { + stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; + if (pixel[3] != 0 && pixel[3] != 65535) { + float a = pixel[3] / 65535.0f; + float ra = 1.0f / a; + float inv_a = 65535.0f * (1 - ra); + pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); + pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); + pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); + } + } + } else { + for (i=0; i < w*h; ++i) { + unsigned char *pixel = out + 4*i; + if (pixel[3] != 0 && pixel[3] != 255) { + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); + pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); + pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); + } + } + } + } + + // convert to desired output format + if (req_comp && req_comp != 4) { + if (ri->bits_per_channel == 16) + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); + else + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + if (comp) *comp = 4; + *y = h; + *x = w; + + return out; +} +#endif + +// ************************************************************************************************* +// Softimage PIC loader +// by Tom Seddon +// +// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format +// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ + +#ifndef STBI_NO_PIC +static int stbi__pic_is4(stbi__context *s,const char *str) +{ + int i; + for (i=0; i<4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) + return 0; + + return 1; +} + +static int stbi__pic_test_core(stbi__context *s) +{ + int i; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) + return 0; + + for(i=0;i<84;++i) + stbi__get8(s); + + if (!stbi__pic_is4(s,"PICT")) + return 0; + + return 1; +} + +typedef struct +{ + stbi_uc size,type,channel; +} stbi__pic_packet; + +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) +{ + int mask=0x80, i; + + for (i=0; i<4; ++i, mask>>=1) { + if (channel & mask) { + if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); + dest[i]=stbi__get8(s); + } + } + + return dest; +} + +static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) +{ + int mask=0x80,i; + + for (i=0;i<4; ++i, mask>>=1) + if (channel&mask) + dest[i]=src[i]; +} + +static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) +{ + int act_comp=0,num_packets=0,y,chained; + stbi__pic_packet packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return stbi__errpuc("bad format","too many packets"); + + packet = &packets[num_packets++]; + + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + + act_comp |= packet->channel; + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); + if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for(y=0; ytype) { + default: + return stbi__errpuc("bad format","packet has bad compression type"); + + case 0: {//uncompressed + int x; + + for(x=0;xchannel,dest)) + return 0; + break; + } + + case 1://Pure RLE + { + int left=width, i; + + while (left>0) { + stbi_uc count,value[4]; + + count=stbi__get8(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + + if (count > left) + count = (stbi_uc) left; + + if (!stbi__readval(s,packet->channel,value)) return 0; + + for(i=0; ichannel,dest,value); + left -= count; + } + } + break; + + case 2: {//Mixed RLE + int left=width; + while (left>0) { + int count = stbi__get8(s), i; + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + + if (count==128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file","scanline overrun"); + + if (!stbi__readval(s,packet->channel,value)) + return 0; + + for(i=0;ichannel,dest,value); + } else { // Raw + ++count; + if (count>left) return stbi__errpuc("bad file","scanline overrun"); + + for(i=0;ichannel,dest)) + return 0; + } + left-=count; + } + break; + } + } + } + } + + return result; +} + +static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) +{ + stbi_uc *result; + int i, x,y, internal_comp; + STBI_NOTUSED(ri); + + if (!comp) comp = &internal_comp; + + for (i=0; i<92; ++i) + stbi__get8(s); + + x = stbi__get16be(s); + y = stbi__get16be(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); + if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); + + stbi__get32be(s); //skip `ratio' + stbi__get16be(s); //skip `fields' + stbi__get16be(s); //skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); + memset(result, 0xff, x*y*4); + + if (!stbi__pic_load_core(s,x,y,comp, result)) { + STBI_FREE(result); + result=0; + } + *px = x; + *py = y; + if (req_comp == 0) req_comp = *comp; + result=stbi__convert_format(result,4,req_comp,x,y); + + return result; +} + +static int stbi__pic_test(stbi__context *s) +{ + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; +} +#endif + +// ************************************************************************************************* +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb + +#ifndef STBI_NO_GIF +typedef struct +{ + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; +} stbi__gif_lzw; + +typedef struct +{ + int w,h; + stbi_uc *out; // output buffer (always 4 components) + stbi_uc *background; // The current "background" as far as a gif is concerned + stbi_uc *history; + int flags, bgindex, ratio, transparent, eflags; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[8192]; + stbi_uc *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; + int delay; +} stbi__gif; + +static int stbi__gif_test_raw(stbi__context *s) +{ + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') return 0; + if (stbi__get8(s) != 'a') return 0; + return 1; +} + +static int stbi__gif_test(stbi__context *s) +{ + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; +} + +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) +{ + int i; + for (i=0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } +} + +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) +{ + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); + + version = stbi__get8(s); + if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; + + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + + if (is_info) return 1; + + if (g->flags & 0x80) + stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + + return 1; +} + +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + if (!stbi__gif_header(s, g, comp, 1)) { + STBI_FREE(g); + stbi__rewind( s ); + return 0; + } + if (x) *x = g->w; + if (y) *y = g->h; + STBI_FREE(g); + return 1; +} + +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) +{ + stbi_uc *p, *c; + int idx; + + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); + + if (g->cur_y >= g->max_y) return; + + idx = g->cur_x + g->cur_y; + p = &g->out[idx]; + g->history[idx / 4] = 1; + + c = &g->color_table[g->codes[code].suffix * 4]; + if (c[3] > 128) { // don't render transparent pixels; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) +{ + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; + + lzw_cs = stbi__get8(s); + if (lzw_cs > 12) return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc) init_code; + g->codes[init_code].suffix = (stbi_uc) init_code; + } + + // support no starting clear code + avail = clear+2; + oldcode = -1; + + len = 0; + for(;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32) stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s,len); + return g->out; + } else if (code <= avail) { + if (first) { + return stbi__errpuc("no clear code", "Corrupt GIF"); + } + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 8192) { + return stbi__errpuc("too many codes", "Corrupt GIF"); + } + + p->prefix = (stbi__int16) oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + + stbi__out_gif_code(g, (stbi__uint16) code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +// this function is designed to support animated gifs, although stb_image doesn't support it +// two back is the image from two frames ago, used for a very specific disposal format +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) +{ + int dispose; + int first_frame; + int pi; + int pcount; + STBI_NOTUSED(req_comp); + + // on first frame, any non-written pixels get the background colour (non-transparent) + first_frame = 0; + if (g->out == 0) { + if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header + if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) + return stbi__errpuc("too large", "GIF image is too large"); + pcount = g->w * g->h; + g->out = (stbi_uc *) stbi__malloc(4 * pcount); + g->background = (stbi_uc *) stbi__malloc(4 * pcount); + g->history = (stbi_uc *) stbi__malloc(pcount); + if (!g->out || !g->background || !g->history) + return stbi__errpuc("outofmem", "Out of memory"); + + // image is treated as "transparent" at the start - ie, nothing overwrites the current background; + // background colour is only used for pixels that are not rendered first frame, after that "background" + // color refers to the color that was there the previous frame. + memset(g->out, 0x00, 4 * pcount); + memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) + memset(g->history, 0x00, pcount); // pixels that were affected previous frame + first_frame = 1; + } else { + // second frame - how do we dispoase of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; + + if ((dispose == 3) && (two_back == 0)) { + dispose = 2; // if I don't have an image to revert back to, default to the old background + } + + if (dispose == 3) { // use previous graphic + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + } + } + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); + } + } + } else { + // This is a non-disposal case eithe way, so just + // leave the pixels as is, and they will become the new background + // 1: do not dispose + // 0: not specified. + } + + // background is what out is after the undoing of the previou frame; + memcpy( g->background, g->out, 4 * g->w * g->h ); + } + + // clear my history; + memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + + for (;;) { + int tag = stbi__get8(s); + switch (tag) { + case 0x2C: /* Image Descriptor */ + { + stbi__int32 x, y, w, h; + stbi_uc *o; + + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; + + // if the width of the specified rectangle is 0, that means + // we may not see *any* pixels or the image is malformed; + // to make sure this is caught, move the current y down to + // max_y (which is what out_gif_code checks). + if (w == 0) + g->cur_y = g->max_y; + + g->lflags = stbi__get8(s); + + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } + + if (g->lflags & 0x80) { + stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc *) g->lpal; + } else if (g->flags & 0x80) { + g->color_table = (stbi_uc *) g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); + + o = stbi__process_gif_raster(s, g); + if (!o) return NULL; + + // if this was the first frame, + pcount = g->w * g->h; + if (first_frame && (g->bgindex > 0)) { + // if first frame, any pixel not drawn to gets the background color + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi] == 0) { + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); + } + } + } + + return o; + } + + case 0x21: // Comment Extension. + { + int len; + int ext = stbi__get8(s); + if (ext == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. + + // unset old transparent + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 255; + } + if (g->eflags & 0x01) { + g->transparent = stbi__get8(s); + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 0; + } + } else { + // don't need transparent + stbi__skip(s, 1); + g->transparent = -1; + } + } else { + stbi__skip(s, len); + break; + } + } + while ((len = stbi__get8(s)) != 0) { + stbi__skip(s, len); + } + break; + } + + case 0x3B: // gif stream termination code + return (stbi_uc *) s; // using '1' causes warning on some compilers + + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } +} + +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + if (stbi__gif_test(s)) { + int layers = 0; + stbi_uc *u = 0; + stbi_uc *out = 0; + stbi_uc *two_back = 0; + stbi__gif g; + int stride; + memset(&g, 0, sizeof(g)); + if (delays) { + *delays = 0; + } + + do { + u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + + if (u) { + *x = g.w; + *y = g.h; + ++layers; + stride = g.w * g.h * 4; + + if (out) { + out = (stbi_uc*) STBI_REALLOC( out, layers * stride ); + if (delays) { + *delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers ); + } + } else { + out = (stbi_uc*)stbi__malloc( layers * stride ); + if (delays) { + *delays = (int*) stbi__malloc( layers * sizeof(int) ); + } + } + memcpy( out + ((layers - 1) * stride), u, stride ); + if (layers >= 2) { + two_back = out - 2 * stride; + } + + if (delays) { + (*delays)[layers - 1U] = g.delay; + } + } + } while (u != 0); + + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + + // do the final conversion after loading everything; + if (req_comp && req_comp != 4) + out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); + + *z = layers; + return out; + } else { + return stbi__errpuc("not GIF", "Image was not as a gif type."); + } +} + +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *u = 0; + stbi__gif g; + memset(&g, 0, sizeof(g)); + STBI_NOTUSED(ri); + + u = stbi__gif_load_next(s, &g, comp, req_comp, 0); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + + // moved conversion to after successful load so that the same + // can be done for multiple frames. + if (req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } else if (g.out) { + // if there was an error and we allocated an image buffer, free it! + STBI_FREE(g.out); + } + + // free buffers needed for multiple frame loading; + STBI_FREE(g.history); + STBI_FREE(g.background); + + return u; +} + +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) +{ + return stbi__gif_info_raw(s,x,y,comp); +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int stbi__hdr_test_core(stbi__context *s, const char *signature) +{ + int i; + for (i=0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + stbi__rewind(s); + return 1; +} + +static int stbi__hdr_test(stbi__context* s) +{ + int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); + stbi__rewind(s); + if(!r) { + r = stbi__hdr_test_core(s, "#?RGBE\n"); + stbi__rewind(s); + } + return r; +} + +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) +{ + int len=0; + char c = '\0'; + + c = (char) stbi__get8(z); + + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN-1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char) stbi__get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) +{ + if ( input[3] != 0 ) { + float f1; + // Exponent + f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) output[1] = 1; + if (req_comp == 4) output[3] = 1; + } else { + switch (req_comp) { + case 4: output[3] = 1; /* fallthrough */ + case 3: output[0] = output[1] = output[2] = 0; + break; + case 2: output[1] = 1; /* fallthrough */ + case 1: output[0] = 0; + break; + } + } +} + +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1,c2, z; + const char *headerToken; + STBI_NOTUSED(ri); + + // Check identifier + headerToken = stbi__hdr_gettoken(s,buffer); + if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); + + // Parse header + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int) strtol(token, NULL, 10); + + *x = width; + *y = height; + + if (comp) *comp = 3; + if (req_comp == 0) req_comp = 3; + + if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) + return stbi__errpf("too large", "HDR image is too large"); + + // Read data + hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); + if (!hdr_data) + return stbi__errpf("outofmem", "Out of memory"); + + // Load image data + // image data is stored as some number of sca + if ( width < 8 || width >= 32768) { + // Read flat data + for (j=0; j < height; ++j) { + for (i=0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc) c1; + rgbe[1] = (stbi_uc) c2; + rgbe[2] = (stbi_uc) len; + rgbe[3] = (stbi_uc) stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) { + scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); + if (!scanline) { + STBI_FREE(hdr_data); + return stbi__errpf("outofmem", "Out of memory"); + } + } + + for (k = 0; k < 4; ++k) { + int nleft; + i = 0; + while ((nleft = width - i) > 0) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for (i=0; i < width; ++i) + stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + if (scanline) + STBI_FREE(scanline); + } + + return hdr_data; +} + +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int dummy; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (stbi__hdr_test(s) == 0) { + stbi__rewind( s ); + return 0; + } + + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) { + stbi__rewind( s ); + return 0; + } + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *y = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *x = (int) strtol(token, NULL, 10); + *comp = 3; + return 1; +} +#endif // STBI_NO_HDR + +#ifndef STBI_NO_BMP +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) +{ + void *p; + stbi__bmp_data info; + + info.all_a = 255; + p = stbi__bmp_parse_header(s, &info); + stbi__rewind( s ); + if (p == NULL) + return 0; + if (x) *x = s->img_x; + if (y) *y = s->img_y; + if (comp) { + if (info.bpp == 24 && info.ma == 0xff000000) + *comp = 3; + else + *comp = info.ma ? 4 : 3; + } + return 1; +} +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) +{ + int channelCount, dummy, depth; + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 8 && depth != 16) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind( s ); + return 0; + } + *comp = 4; + return 1; +} + +static int stbi__psd_is16(stbi__context *s) +{ + int channelCount, depth; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + (void) stbi__get32be(s); + (void) stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 16) { + stbi__rewind( s ); + return 0; + } + return 1; +} +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) +{ + int act_comp=0,num_packets=0,chained,dummy; + stbi__pic_packet packets[10]; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 88); + + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) { + stbi__rewind( s); + return 0; + } + if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind( s ); + return 0; + } + + stbi__skip(s, 8); + + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; + + if (stbi__at_eof(s)) { + stbi__rewind( s ); + return 0; + } + if (packet->size != 8) { + stbi__rewind( s ); + return 0; + } + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); + + return 1; +} +#endif + +// ************************************************************************************************* +// Portable Gray Map and Portable Pixel Map loader +// by Ken Miller +// +// PGM: http://netpbm.sourceforge.net/doc/pgm.html +// PPM: http://netpbm.sourceforge.net/doc/ppm.html +// +// Known limitations: +// Does not support comments in the header section +// Does not support ASCII image data (formats P2 and P3) +// Does not support 16-bit-per-channel + +#ifndef STBI_NO_PNM + +static int stbi__pnm_test(stbi__context *s) +{ + char p, t; + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + return 1; +} + +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + STBI_NOTUSED(ri); + + if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) + return 0; + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + + if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "PNM too large"); + + out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + stbi__getn(s, out, s->img_n * s->img_x * s->img_y); + + if (req_comp && req_comp != s->img_n) { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; +} + +static int stbi__pnm_isspace(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +} + +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) +{ + for (;;) { + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char) stbi__get8(s); + + if (stbi__at_eof(s) || *c != '#') + break; + + while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) + *c = (char) stbi__get8(s); + } +} + +static int stbi__pnm_isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static int stbi__pnm_getinteger(stbi__context *s, char *c) +{ + int value = 0; + + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value*10 + (*c - '0'); + *c = (char) stbi__get8(s); + } + + return value; +} + +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) +{ + int maxv, dummy; + char c, p, t; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + stbi__rewind(s); + + // Get identifier + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } + + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + + c = (char) stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); + + *x = stbi__pnm_getinteger(s, &c); // read width + stbi__pnm_skip_whitespace(s, &c); + + *y = stbi__pnm_getinteger(s, &c); // read height + stbi__pnm_skip_whitespace(s, &c); + + maxv = stbi__pnm_getinteger(s, &c); // read max value + + if (maxv > 255) + return stbi__err("max value > 255", "PPM image not 8-bit"); + else + return 1; +} +#endif + +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) return 1; + #endif + + // test tga last because it's a crappy test! + #ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; + #endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +} + +static int stbi__is_16_main(stbi__context *s) +{ + #ifndef STBI_NO_PNG + if (stbi__png_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_is16(s)) return 1; + #endif + + return 0; +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s,x,y,comp); + fseek(f,pos,SEEK_SET); + return r; +} + +STBIDEF int stbi_is_16_bit(char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_is_16_bit_from_file(f); + fclose(f); + return result; +} + +STBIDEF int stbi_is_16_bit_from_file(FILE *f) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__is_16_main(&s); + fseek(f,pos,SEEK_SET); + return r; +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__is_16_main(&s); +} + +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__is_16_main(&s); +} + +#endif // STB_IMAGE_IMPLEMENTATION + +/* + revision history: + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug + 1-bit BMP + *_is_16_bit api + avoid warnings + 2.16 (2017-07-23) all functions have 16-bit variants; + STBI_NO_STDIO works again; + compilation fixes; + fix rounding in unpremultiply; + optimize vertical flip; + disable raw_len validation; + documentation fixes + 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; + warning fixes; disable run-time SSE detection on gcc; + uniform handling of optional "return" values; + thread-safe initialization of zlib tables + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) allocate large structures on the stack + remove white matting for transparent PSD + fix reported channel count for PNG & BMP + re-enable SSE2 in non-gcc 64-bit + support RGB-formatted JPEG + read 16-bit PNGs (only as 8-bit) + 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED + 2.09 (2016-01-16) allow comments in PNM files + 16-bit-per-pixel TGA (not bit-per-component) + info() for TGA could break due to .hdr handling + info() for BMP to shares code instead of sloppy parse + can use STBI_REALLOC_SIZED if allocator doesn't support realloc + code cleanup + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) fix compiler warnings + partial animated GIF support + limited 16-bpc PSD support + #ifdef unused functions + bug with < 92 byte PIC,PNM,HDR,TGA + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) extra corruption checking (mmozeiko) + stbi_set_flip_vertically_on_load (nguillemot) + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) + 1.46 (2014-08-26) + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + 1.45 (2014-08-16) + fix MSVC-ARM internal compiler error by wrapping malloc + 1.44 (2014-08-07) + various warning fixes from Ronny Chevalier + 1.43 (2014-07-15) + fix MSVC-only compiler problem in code changed in 1.42 + 1.42 (2014-07-09) + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring assert.h + 1.41 (2014-06-25) + fix search&replace from 1.36 that messed up comments/error messages + 1.40 (2014-06-22) + fix gcc struct-initialization warning + 1.39 (2014-06-15) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) + 1.38 (2014-06-06) + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O + 1.37 (2014-06-04) + remove duplicate typedef + 1.36 (2014-06-03) + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + 1.35 (2014-05-27) + various warnings + fix broken STBI_SIMD path + fix bug where stbi_load_from_file no longer left file pointer in correct place + fix broken non-easy path for 32-bit BMP (possibly never used) + TGA optimization by Arseny Kapoulkine + 1.34 (unknown) + use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case + 1.33 (2011-07-14) + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + 1.32 (2011-07-13) + support for "info" function for all supported filetypes (SpartanJ) + 1.31 (2011-06-20) + a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway + error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) + fix inefficiency in decoding 32-bit BMP (David Woo) + 1.29 (2010-08-16) + various warning fixes from Aurelien Pocheville + 1.28 (2010-08-01) + fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) + cast-to-stbi_uc to fix warnings + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) + 1.21 fix use of 'stbi_uc' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 (2008-08-02) + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - stbi__convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant + 0.50 (2006-11-19) + first released version +*/ + + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +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. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +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 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. +------------------------------------------------------------------------------ +*/ diff --git a/src/files/stb_image_resize.h b/src/files/stb_image_resize.h new file mode 100644 index 0000000..4f6ad35 --- /dev/null +++ b/src/files/stb_image_resize.h @@ -0,0 +1,2630 @@ +/* stb_image_resize - v0.96 - public domain image resizing + by Jorge L Rodriguez (@VinoBS) - 2014 + http://github.com/nothings/stb + + Written with emphasis on usability, portability, and efficiency. (No + SIMD or threads, so it be easily outperformed by libs that use those.) + Only scaling and translation is supported, no rotations or shears. + Easy API downsamples w/Mitchell filter, upsamples w/cubic interpolation. + + COMPILING & LINKING + In one C/C++ file that #includes this file, do this: + #define STB_IMAGE_RESIZE_IMPLEMENTATION + before the #include. That will create the implementation in that file. + + QUICKSTART + stbir_resize_uint8( input_pixels , in_w , in_h , 0, + output_pixels, out_w, out_h, 0, num_channels) + stbir_resize_float(...) + stbir_resize_uint8_srgb( input_pixels , in_w , in_h , 0, + output_pixels, out_w, out_h, 0, + num_channels , alpha_chan , 0) + stbir_resize_uint8_srgb_edgemode( + input_pixels , in_w , in_h , 0, + output_pixels, out_w, out_h, 0, + num_channels , alpha_chan , 0, STBIR_EDGE_CLAMP) + // WRAP/REFLECT/ZERO + + FULL API + See the "header file" section of the source for API documentation. + + ADDITIONAL DOCUMENTATION + + SRGB & FLOATING POINT REPRESENTATION + The sRGB functions presume IEEE floating point. If you do not have + IEEE floating point, define STBIR_NON_IEEE_FLOAT. This will use + a slower implementation. + + MEMORY ALLOCATION + The resize functions here perform a single memory allocation using + malloc. To control the memory allocation, before the #include that + triggers the implementation, do: + + #define STBIR_MALLOC(size,context) ... + #define STBIR_FREE(ptr,context) ... + + Each resize function makes exactly one call to malloc/free, so to use + temp memory, store the temp memory in the context and return that. + + ASSERT + Define STBIR_ASSERT(boolval) to override assert() and not use assert.h + + OPTIMIZATION + Define STBIR_SATURATE_INT to compute clamp values in-range using + integer operations instead of float operations. This may be faster + on some platforms. + + DEFAULT FILTERS + For functions which don't provide explicit control over what filters + to use, you can change the compile-time defaults with + + #define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_something + #define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_something + + See stbir_filter in the header-file section for the list of filters. + + NEW FILTERS + A number of 1D filter kernels are used. For a list of + supported filters see the stbir_filter enum. To add a new filter, + write a filter function and add it to stbir__filter_info_table. + + PROGRESS + For interactive use with slow resize operations, you can install + a progress-report callback: + + #define STBIR_PROGRESS_REPORT(val) some_func(val) + + The parameter val is a float which goes from 0 to 1 as progress is made. + + For example: + + static void my_progress_report(float progress); + #define STBIR_PROGRESS_REPORT(val) my_progress_report(val) + + #define STB_IMAGE_RESIZE_IMPLEMENTATION + #include "stb_image_resize.h" + + static void my_progress_report(float progress) + { + printf("Progress: %f%%\n", progress*100); + } + + MAX CHANNELS + If your image has more than 64 channels, define STBIR_MAX_CHANNELS + to the max you'll have. + + ALPHA CHANNEL + Most of the resizing functions provide the ability to control how + the alpha channel of an image is processed. The important things + to know about this: + + 1. The best mathematically-behaved version of alpha to use is + called "premultiplied alpha", in which the other color channels + have had the alpha value multiplied in. If you use premultiplied + alpha, linear filtering (such as image resampling done by this + library, or performed in texture units on GPUs) does the "right + thing". While premultiplied alpha is standard in the movie CGI + industry, it is still uncommon in the videogame/real-time world. + + If you linearly filter non-premultiplied alpha, strange effects + occur. (For example, the 50/50 average of 99% transparent bright green + and 1% transparent black produces 50% transparent dark green when + non-premultiplied, whereas premultiplied it produces 50% + transparent near-black. The former introduces green energy + that doesn't exist in the source image.) + + 2. Artists should not edit premultiplied-alpha images; artists + want non-premultiplied alpha images. Thus, art tools generally output + non-premultiplied alpha images. + + 3. You will get best results in most cases by converting images + to premultiplied alpha before processing them mathematically. + + 4. If you pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, the + resizer does not do anything special for the alpha channel; + it is resampled identically to other channels. This produces + the correct results for premultiplied-alpha images, but produces + less-than-ideal results for non-premultiplied-alpha images. + + 5. If you do not pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, + then the resizer weights the contribution of input pixels + based on their alpha values, or, equivalently, it multiplies + the alpha value into the color channels, resamples, then divides + by the resultant alpha value. Input pixels which have alpha=0 do + not contribute at all to output pixels unless _all_ of the input + pixels affecting that output pixel have alpha=0, in which case + the result for that pixel is the same as it would be without + STBIR_FLAG_ALPHA_PREMULTIPLIED. However, this is only true for + input images in integer formats. For input images in float format, + input pixels with alpha=0 have no effect, and output pixels + which have alpha=0 will be 0 in all channels. (For float images, + you can manually achieve the same result by adding a tiny epsilon + value to the alpha channel of every image, and then subtracting + or clamping it at the end.) + + 6. You can suppress the behavior described in #5 and make + all-0-alpha pixels have 0 in all channels by #defining + STBIR_NO_ALPHA_EPSILON. + + 7. You can separately control whether the alpha channel is + interpreted as linear or affected by the colorspace. By default + it is linear; you almost never want to apply the colorspace. + (For example, graphics hardware does not apply sRGB conversion + to the alpha channel.) + + CONTRIBUTORS + Jorge L Rodriguez: Implementation + Sean Barrett: API design, optimizations + Aras Pranckevicius: bugfix + Nathan Reed: warning fixes + + REVISIONS + 0.96 (2019-03-04) fixed warnings + 0.95 (2017-07-23) fixed warnings + 0.94 (2017-03-18) fixed warnings + 0.93 (2017-03-03) fixed bug with certain combinations of heights + 0.92 (2017-01-02) fix integer overflow on large (>2GB) images + 0.91 (2016-04-02) fix warnings; fix handling of subpixel regions + 0.90 (2014-09-17) first released version + + LICENSE + See end of file for license information. + + TODO + Don't decode all of the image data when only processing a partial tile + Don't use full-width decode buffers when only processing a partial tile + When processing wide images, break processing into tiles so data fits in L1 cache + Installable filters? + Resize that respects alpha test coverage + (Reference code: FloatImage::alphaTestCoverage and FloatImage::scaleAlphaToCoverage: + https://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvimage/FloatImage.cpp ) +*/ + +#ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE_H +#define STBIR_INCLUDE_STB_IMAGE_RESIZE_H + +#ifdef _MSC_VER +typedef unsigned char stbir_uint8; +typedef unsigned short stbir_uint16; +typedef unsigned int stbir_uint32; +#else +#include +typedef uint8_t stbir_uint8; +typedef uint16_t stbir_uint16; +typedef uint32_t stbir_uint32; +#endif + +#ifndef STBIRDEF +#ifdef STB_IMAGE_RESIZE_STATIC +#define STBIRDEF static +#else +#ifdef __cplusplus +#define STBIRDEF extern "C" +#else +#define STBIRDEF extern +#endif +#endif +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// Easy-to-use API: +// +// * "input pixels" points to an array of image data with 'num_channels' channels (e.g. RGB=3, RGBA=4) +// * input_w is input image width (x-axis), input_h is input image height (y-axis) +// * stride is the offset between successive rows of image data in memory, in bytes. you can +// specify 0 to mean packed continuously in memory +// * alpha channel is treated identically to other channels. +// * colorspace is linear or sRGB as specified by function name +// * returned result is 1 for success or 0 in case of an error. +// #define STBIR_ASSERT() to trigger an assert on parameter validation errors. +// * Memory required grows approximately linearly with input and output size, but with +// discontinuities at input_w == output_w and input_h == output_h. +// * These functions use a "default" resampling filter defined at compile time. To change the filter, +// you can change the compile-time defaults by #defining STBIR_DEFAULT_FILTER_UPSAMPLE +// and STBIR_DEFAULT_FILTER_DOWNSAMPLE, or you can use the medium-complexity API. + +STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels); + +STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + float *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels); + + +// The following functions interpret image data as gamma-corrected sRGB. +// Specify STBIR_ALPHA_CHANNEL_NONE if you have no alpha channel, +// or otherwise provide the index of the alpha channel. Flags value +// of 0 will probably do the right thing if you're not sure what +// the flags mean. + +#define STBIR_ALPHA_CHANNEL_NONE -1 + +// Set this flag if your texture has premultiplied alpha. Otherwise, stbir will +// use alpha-weighted resampling (effectively premultiplying, resampling, +// then unpremultiplying). +#define STBIR_FLAG_ALPHA_PREMULTIPLIED (1 << 0) +// The specified alpha channel should be handled as gamma-corrected value even +// when doing sRGB operations. +#define STBIR_FLAG_ALPHA_USES_COLORSPACE (1 << 1) + +STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags); + + +typedef enum +{ + STBIR_EDGE_CLAMP = 1, + STBIR_EDGE_REFLECT = 2, + STBIR_EDGE_WRAP = 3, + STBIR_EDGE_ZERO = 4, +} stbir_edge; + +// This function adds the ability to specify how requests to sample off the edge of the image are handled. +STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode); + +////////////////////////////////////////////////////////////////////////////// +// +// Medium-complexity API +// +// This extends the easy-to-use API as follows: +// +// * Alpha-channel can be processed separately +// * If alpha_channel is not STBIR_ALPHA_CHANNEL_NONE +// * Alpha channel will not be gamma corrected (unless flags&STBIR_FLAG_GAMMA_CORRECT) +// * Filters will be weighted by alpha channel (unless flags&STBIR_FLAG_ALPHA_PREMULTIPLIED) +// * Filter can be selected explicitly +// * uint16 image type +// * sRGB colorspace available for all types +// * context parameter for passing to STBIR_MALLOC + +typedef enum +{ + STBIR_FILTER_DEFAULT = 0, // use same filter type that easy-to-use API chooses + STBIR_FILTER_BOX = 1, // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios + STBIR_FILTER_TRIANGLE = 2, // On upsampling, produces same results as bilinear texture filtering + STBIR_FILTER_CUBICBSPLINE = 3, // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque + STBIR_FILTER_CATMULLROM = 4, // An interpolating cubic spline + STBIR_FILTER_MITCHELL = 5, // Mitchell-Netrevalli filter with B=1/3, C=1/3 +} stbir_filter; + +typedef enum +{ + STBIR_COLORSPACE_LINEAR, + STBIR_COLORSPACE_SRGB, + + STBIR_MAX_COLORSPACES, +} stbir_colorspace; + +// The following functions are all identical except for the type of the image data + +STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context); + +STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context); + +STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + float *output_pixels , int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context); + + + +////////////////////////////////////////////////////////////////////////////// +// +// Full-complexity API +// +// This extends the medium API as follows: +// +// * uint32 image type +// * not typesafe +// * separate filter types for each axis +// * separate edge modes for each axis +// * can specify scale explicitly for subpixel correctness +// * can specify image source tile using texture coordinates + +typedef enum +{ + STBIR_TYPE_UINT8 , + STBIR_TYPE_UINT16, + STBIR_TYPE_UINT32, + STBIR_TYPE_FLOAT , + + STBIR_MAX_TYPES +} stbir_datatype; + +STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context); + +STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context, + float x_scale, float y_scale, + float x_offset, float y_offset); + +STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context, + float s0, float t0, float s1, float t1); +// (s0, t0) & (s1, t1) are the top-left and bottom right corner (uv addressing style: [0, 1]x[0, 1]) of a region of the input image to use. + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBIR_INCLUDE_STB_IMAGE_RESIZE_H + + + + + +#ifdef STB_IMAGE_RESIZE_IMPLEMENTATION + +#ifndef STBIR_ASSERT +#include +#define STBIR_ASSERT(x) assert(x) +#endif + +// For memset +#include + +#include + +#ifndef STBIR_MALLOC +#include +// use comma operator to evaluate c, to avoid "unused parameter" warnings +#define STBIR_MALLOC(size,c) ((void)(c), malloc(size)) +#define STBIR_FREE(ptr,c) ((void)(c), free(ptr)) +#endif + +#ifndef _MSC_VER +#ifdef __cplusplus +#define stbir__inline inline +#else +#define stbir__inline +#endif +#else +#define stbir__inline __forceinline +#endif + + +// should produce compiler error if size is wrong +typedef unsigned char stbir__validate_uint32[sizeof(stbir_uint32) == 4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBIR__NOTUSED(v) (void)(v) +#else +#define STBIR__NOTUSED(v) (void)sizeof(v) +#endif + +#define STBIR__ARRAY_SIZE(a) (sizeof((a))/sizeof((a)[0])) + +#ifndef STBIR_DEFAULT_FILTER_UPSAMPLE +#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM +#endif + +#ifndef STBIR_DEFAULT_FILTER_DOWNSAMPLE +#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL +#endif + +#ifndef STBIR_PROGRESS_REPORT +#define STBIR_PROGRESS_REPORT(float_0_to_1) +#endif + +#ifndef STBIR_MAX_CHANNELS +#define STBIR_MAX_CHANNELS 64 +#endif + +#if STBIR_MAX_CHANNELS > 65536 +#error "Too many channels; STBIR_MAX_CHANNELS must be no more than 65536." +// because we store the indices in 16-bit variables +#endif + +// This value is added to alpha just before premultiplication to avoid +// zeroing out color values. It is equivalent to 2^-80. If you don't want +// that behavior (it may interfere if you have floating point images with +// very small alpha values) then you can define STBIR_NO_ALPHA_EPSILON to +// disable it. +#ifndef STBIR_ALPHA_EPSILON +#define STBIR_ALPHA_EPSILON ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20)) +#endif + + + +#ifdef _MSC_VER +#define STBIR__UNUSED_PARAM(v) (void)(v) +#else +#define STBIR__UNUSED_PARAM(v) (void)sizeof(v) +#endif + +// must match stbir_datatype +static unsigned char stbir__type_size[] = { + 1, // STBIR_TYPE_UINT8 + 2, // STBIR_TYPE_UINT16 + 4, // STBIR_TYPE_UINT32 + 4, // STBIR_TYPE_FLOAT +}; + +// Kernel function centered at 0 +typedef float (stbir__kernel_fn)(float x, float scale); +typedef float (stbir__support_fn)(float scale); + +typedef struct +{ + stbir__kernel_fn* kernel; + stbir__support_fn* support; +} stbir__filter_info; + +// When upsampling, the contributors are which source pixels contribute. +// When downsampling, the contributors are which destination pixels are contributed to. +typedef struct +{ + int n0; // First contributing pixel + int n1; // Last contributing pixel +} stbir__contributors; + +typedef struct +{ + const void* input_data; + int input_w; + int input_h; + int input_stride_bytes; + + void* output_data; + int output_w; + int output_h; + int output_stride_bytes; + + float s0, t0, s1, t1; + + float horizontal_shift; // Units: output pixels + float vertical_shift; // Units: output pixels + float horizontal_scale; + float vertical_scale; + + int channels; + int alpha_channel; + stbir_uint32 flags; + stbir_datatype type; + stbir_filter horizontal_filter; + stbir_filter vertical_filter; + stbir_edge edge_horizontal; + stbir_edge edge_vertical; + stbir_colorspace colorspace; + + stbir__contributors* horizontal_contributors; + float* horizontal_coefficients; + + stbir__contributors* vertical_contributors; + float* vertical_coefficients; + + int decode_buffer_pixels; + float* decode_buffer; + + float* horizontal_buffer; + + // cache these because ceil/floor are inexplicably showing up in profile + int horizontal_coefficient_width; + int vertical_coefficient_width; + int horizontal_filter_pixel_width; + int vertical_filter_pixel_width; + int horizontal_filter_pixel_margin; + int vertical_filter_pixel_margin; + int horizontal_num_contributors; + int vertical_num_contributors; + + int ring_buffer_length_bytes; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter) + int ring_buffer_num_entries; // Total number of entries in the ring buffer. + int ring_buffer_first_scanline; + int ring_buffer_last_scanline; + int ring_buffer_begin_index; // first_scanline is at this index in the ring buffer + float* ring_buffer; + + float* encode_buffer; // A temporary buffer to store floats so we don't lose precision while we do multiply-adds. + + int horizontal_contributors_size; + int horizontal_coefficients_size; + int vertical_contributors_size; + int vertical_coefficients_size; + int decode_buffer_size; + int horizontal_buffer_size; + int ring_buffer_size; + int encode_buffer_size; +} stbir__info; + + +static const float stbir__max_uint8_as_float = 255.0f; +static const float stbir__max_uint16_as_float = 65535.0f; +static const double stbir__max_uint32_as_float = 4294967295.0; + + +static stbir__inline int stbir__min(int a, int b) +{ + return a < b ? a : b; +} + +static stbir__inline float stbir__saturate(float x) +{ + if (x < 0) + return 0; + + if (x > 1) + return 1; + + return x; +} + +#ifdef STBIR_SATURATE_INT +static stbir__inline stbir_uint8 stbir__saturate8(int x) +{ + if ((unsigned int) x <= 255) + return x; + + if (x < 0) + return 0; + + return 255; +} + +static stbir__inline stbir_uint16 stbir__saturate16(int x) +{ + if ((unsigned int) x <= 65535) + return x; + + if (x < 0) + return 0; + + return 65535; +} +#endif + +static float stbir__srgb_uchar_to_linear_float[256] = { + 0.000000f, 0.000304f, 0.000607f, 0.000911f, 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f, + 0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, 0.006049f, 0.006512f, 0.006995f, 0.007499f, + 0.008023f, 0.008568f, 0.009134f, 0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f, 0.014444f, + 0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f, 0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f, + 0.025187f, 0.026241f, 0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f, 0.035601f, 0.036889f, + 0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f, 0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f, + 0.054480f, 0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f, 0.068478f, 0.070360f, 0.072272f, + 0.074214f, 0.076185f, 0.078187f, 0.080220f, 0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f, + 0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f, 0.114435f, 0.116971f, 0.119538f, 0.122139f, + 0.124772f, 0.127438f, 0.130136f, 0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f, 0.152926f, + 0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f, 0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f, + 0.191202f, 0.194618f, 0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f, 0.223228f, 0.226966f, + 0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f, 0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f, + 0.274677f, 0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f, 0.309469f, 0.313989f, 0.318547f, + 0.323143f, 0.327778f, 0.332452f, 0.337164f, 0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f, + 0.376262f, 0.381326f, 0.386430f, 0.391573f, 0.396755f, 0.401978f, 0.407240f, 0.412543f, 0.417885f, 0.423268f, 0.428691f, + 0.434154f, 0.439657f, 0.445201f, 0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473532f, 0.479320f, 0.485150f, 0.491021f, + 0.496933f, 0.502887f, 0.508881f, 0.514918f, 0.520996f, 0.527115f, 0.533276f, 0.539480f, 0.545725f, 0.552011f, 0.558340f, + 0.564712f, 0.571125f, 0.577581f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f, 0.623960f, 0.630757f, + 0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f, 0.672443f, 0.679543f, 0.686685f, 0.693872f, 0.701102f, 0.708376f, + 0.715694f, 0.723055f, 0.730461f, 0.737911f, 0.745404f, 0.752942f, 0.760525f, 0.768151f, 0.775822f, 0.783538f, 0.791298f, + 0.799103f, 0.806952f, 0.814847f, 0.822786f, 0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f, + 0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f, 0.947307f, 0.955974f, 0.964686f, 0.973445f, + 0.982251f, 0.991102f, 1.0f +}; + +static float stbir__srgb_to_linear(float f) +{ + if (f <= 0.04045f) + return f / 12.92f; + else + return (float)pow((f + 0.055f) / 1.055f, 2.4f); +} + +static float stbir__linear_to_srgb(float f) +{ + if (f <= 0.0031308f) + return f * 12.92f; + else + return 1.055f * (float)pow(f, 1 / 2.4f) - 0.055f; +} + +#ifndef STBIR_NON_IEEE_FLOAT +// From https://gist.github.com/rygorous/2203834 + +typedef union +{ + stbir_uint32 u; + float f; +} stbir__FP32; + +static const stbir_uint32 fp32_to_srgb8_tab4[104] = { + 0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d, + 0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a, + 0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033, + 0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067, + 0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5, + 0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2, + 0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143, + 0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af, + 0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240, + 0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300, + 0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401, + 0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559, + 0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723, +}; + +static stbir_uint8 stbir__linear_to_srgb_uchar(float in) +{ + static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps + static const stbir__FP32 minval = { (127-13) << 23 }; + stbir_uint32 tab,bias,scale,t; + stbir__FP32 f; + + // Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively. + // The tests are carefully written so that NaNs map to 0, same as in the reference + // implementation. + if (!(in > minval.f)) // written this way to catch NaNs + in = minval.f; + if (in > almostone.f) + in = almostone.f; + + // Do the table lookup and unpack bias, scale + f.f = in; + tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20]; + bias = (tab >> 16) << 9; + scale = tab & 0xffff; + + // Grab next-highest mantissa bits and perform linear interpolation + t = (f.u >> 12) & 0xff; + return (unsigned char) ((bias + scale*t) >> 16); +} + +#else +// sRGB transition values, scaled by 1<<28 +static int stbir__srgb_offset_to_linear_scaled[256] = +{ + 0, 40738, 122216, 203693, 285170, 366648, 448125, 529603, + 611080, 692557, 774035, 855852, 942009, 1033024, 1128971, 1229926, + 1335959, 1447142, 1563542, 1685229, 1812268, 1944725, 2082664, 2226148, + 2375238, 2529996, 2690481, 2856753, 3028870, 3206888, 3390865, 3580856, + 3776916, 3979100, 4187460, 4402049, 4622919, 4850123, 5083710, 5323731, + 5570236, 5823273, 6082892, 6349140, 6622065, 6901714, 7188133, 7481369, + 7781466, 8088471, 8402427, 8723380, 9051372, 9386448, 9728650, 10078021, + 10434603, 10798439, 11169569, 11548036, 11933879, 12327139, 12727857, 13136073, + 13551826, 13975156, 14406100, 14844697, 15290987, 15745007, 16206795, 16676389, + 17153826, 17639142, 18132374, 18633560, 19142734, 19659934, 20185196, 20718552, + 21260042, 21809696, 22367554, 22933648, 23508010, 24090680, 24681686, 25281066, + 25888850, 26505076, 27129772, 27762974, 28404716, 29055026, 29713942, 30381490, + 31057708, 31742624, 32436272, 33138682, 33849884, 34569912, 35298800, 36036568, + 36783260, 37538896, 38303512, 39077136, 39859796, 40651528, 41452360, 42262316, + 43081432, 43909732, 44747252, 45594016, 46450052, 47315392, 48190064, 49074096, + 49967516, 50870356, 51782636, 52704392, 53635648, 54576432, 55526772, 56486700, + 57456236, 58435408, 59424248, 60422780, 61431036, 62449032, 63476804, 64514376, + 65561776, 66619028, 67686160, 68763192, 69850160, 70947088, 72053992, 73170912, + 74297864, 75434880, 76581976, 77739184, 78906536, 80084040, 81271736, 82469648, + 83677792, 84896192, 86124888, 87363888, 88613232, 89872928, 91143016, 92423512, + 93714432, 95015816, 96327688, 97650056, 98982952, 100326408, 101680440, 103045072, + 104420320, 105806224, 107202800, 108610064, 110028048, 111456776, 112896264, 114346544, + 115807632, 117279552, 118762328, 120255976, 121760536, 123276016, 124802440, 126339832, + 127888216, 129447616, 131018048, 132599544, 134192112, 135795792, 137410592, 139036528, + 140673648, 142321952, 143981456, 145652208, 147334208, 149027488, 150732064, 152447968, + 154175200, 155913792, 157663776, 159425168, 161197984, 162982240, 164777968, 166585184, + 168403904, 170234160, 172075968, 173929344, 175794320, 177670896, 179559120, 181458992, + 183370528, 185293776, 187228736, 189175424, 191133888, 193104112, 195086128, 197079968, + 199085648, 201103184, 203132592, 205173888, 207227120, 209292272, 211369392, 213458480, + 215559568, 217672656, 219797792, 221934976, 224084240, 226245600, 228419056, 230604656, + 232802400, 235012320, 237234432, 239468736, 241715280, 243974080, 246245120, 248528464, + 250824112, 253132064, 255452368, 257785040, 260130080, 262487520, 264857376, 267239664, +}; + +static stbir_uint8 stbir__linear_to_srgb_uchar(float f) +{ + int x = (int) (f * (1 << 28)); // has headroom so you don't need to clamp + int v = 0; + int i; + + // Refine the guess with a short binary search. + i = v + 128; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 64; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 32; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 16; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 8; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 4; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 2; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 1; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + + return (stbir_uint8) v; +} +#endif + +static float stbir__filter_trapezoid(float x, float scale) +{ + float halfscale = scale / 2; + float t = 0.5f + halfscale; + STBIR_ASSERT(scale <= 1); + + x = (float)fabs(x); + + if (x >= t) + return 0; + else + { + float r = 0.5f - halfscale; + if (x <= r) + return 1; + else + return (t - x) / scale; + } +} + +static float stbir__support_trapezoid(float scale) +{ + STBIR_ASSERT(scale <= 1); + return 0.5f + scale / 2; +} + +static float stbir__filter_triangle(float x, float s) +{ + STBIR__UNUSED_PARAM(s); + + x = (float)fabs(x); + + if (x <= 1.0f) + return 1 - x; + else + return 0; +} + +static float stbir__filter_cubic(float x, float s) +{ + STBIR__UNUSED_PARAM(s); + + x = (float)fabs(x); + + if (x < 1.0f) + return (4 + x*x*(3*x - 6))/6; + else if (x < 2.0f) + return (8 + x*(-12 + x*(6 - x)))/6; + + return (0.0f); +} + +static float stbir__filter_catmullrom(float x, float s) +{ + STBIR__UNUSED_PARAM(s); + + x = (float)fabs(x); + + if (x < 1.0f) + return 1 - x*x*(2.5f - 1.5f*x); + else if (x < 2.0f) + return 2 - x*(4 + x*(0.5f*x - 2.5f)); + + return (0.0f); +} + +static float stbir__filter_mitchell(float x, float s) +{ + STBIR__UNUSED_PARAM(s); + + x = (float)fabs(x); + + if (x < 1.0f) + return (16 + x*x*(21 * x - 36))/18; + else if (x < 2.0f) + return (32 + x*(-60 + x*(36 - 7*x)))/18; + + return (0.0f); +} + +static float stbir__support_zero(float s) +{ + STBIR__UNUSED_PARAM(s); + return 0; +} + +static float stbir__support_one(float s) +{ + STBIR__UNUSED_PARAM(s); + return 1; +} + +static float stbir__support_two(float s) +{ + STBIR__UNUSED_PARAM(s); + return 2; +} + +static stbir__filter_info stbir__filter_info_table[] = { + { NULL, stbir__support_zero }, + { stbir__filter_trapezoid, stbir__support_trapezoid }, + { stbir__filter_triangle, stbir__support_one }, + { stbir__filter_cubic, stbir__support_two }, + { stbir__filter_catmullrom, stbir__support_two }, + { stbir__filter_mitchell, stbir__support_two }, +}; + +stbir__inline static int stbir__use_upsampling(float ratio) +{ + return ratio > 1; +} + +stbir__inline static int stbir__use_width_upsampling(stbir__info* stbir_info) +{ + return stbir__use_upsampling(stbir_info->horizontal_scale); +} + +stbir__inline static int stbir__use_height_upsampling(stbir__info* stbir_info) +{ + return stbir__use_upsampling(stbir_info->vertical_scale); +} + +// This is the maximum number of input samples that can affect an output sample +// with the given filter +static int stbir__get_filter_pixel_width(stbir_filter filter, float scale) +{ + STBIR_ASSERT(filter != 0); + STBIR_ASSERT(filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); + + if (stbir__use_upsampling(scale)) + return (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2); + else + return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2 / scale); +} + +// This is how much to expand buffers to account for filters seeking outside +// the image boundaries. +static int stbir__get_filter_pixel_margin(stbir_filter filter, float scale) +{ + return stbir__get_filter_pixel_width(filter, scale) / 2; +} + +static int stbir__get_coefficient_width(stbir_filter filter, float scale) +{ + if (stbir__use_upsampling(scale)) + return (int)ceil(stbir__filter_info_table[filter].support(1 / scale) * 2); + else + return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2); +} + +static int stbir__get_contributors(float scale, stbir_filter filter, int input_size, int output_size) +{ + if (stbir__use_upsampling(scale)) + return output_size; + else + return (input_size + stbir__get_filter_pixel_margin(filter, scale) * 2); +} + +static int stbir__get_total_horizontal_coefficients(stbir__info* info) +{ + return info->horizontal_num_contributors + * stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale); +} + +static int stbir__get_total_vertical_coefficients(stbir__info* info) +{ + return info->vertical_num_contributors + * stbir__get_coefficient_width (info->vertical_filter, info->vertical_scale); +} + +static stbir__contributors* stbir__get_contributor(stbir__contributors* contributors, int n) +{ + return &contributors[n]; +} + +// For perf reasons this code is duplicated in stbir__resample_horizontal_upsample/downsample, +// if you change it here change it there too. +static float* stbir__get_coefficient(float* coefficients, stbir_filter filter, float scale, int n, int c) +{ + int width = stbir__get_coefficient_width(filter, scale); + return &coefficients[width*n + c]; +} + +static int stbir__edge_wrap_slow(stbir_edge edge, int n, int max) +{ + switch (edge) + { + case STBIR_EDGE_ZERO: + return 0; // we'll decode the wrong pixel here, and then overwrite with 0s later + + case STBIR_EDGE_CLAMP: + if (n < 0) + return 0; + + if (n >= max) + return max - 1; + + return n; // NOTREACHED + + case STBIR_EDGE_REFLECT: + { + if (n < 0) + { + if (n < max) + return -n; + else + return max - 1; + } + + if (n >= max) + { + int max2 = max * 2; + if (n >= max2) + return 0; + else + return max2 - n - 1; + } + + return n; // NOTREACHED + } + + case STBIR_EDGE_WRAP: + if (n >= 0) + return (n % max); + else + { + int m = (-n) % max; + + if (m != 0) + m = max - m; + + return (m); + } + // NOTREACHED + + default: + STBIR_ASSERT(!"Unimplemented edge type"); + return 0; + } +} + +stbir__inline static int stbir__edge_wrap(stbir_edge edge, int n, int max) +{ + // avoid per-pixel switch + if (n >= 0 && n < max) + return n; + return stbir__edge_wrap_slow(edge, n, max); +} + +// What input pixels contribute to this output pixel? +static void stbir__calculate_sample_range_upsample(int n, float out_filter_radius, float scale_ratio, float out_shift, int* in_first_pixel, int* in_last_pixel, float* in_center_of_out) +{ + float out_pixel_center = (float)n + 0.5f; + float out_pixel_influence_lowerbound = out_pixel_center - out_filter_radius; + float out_pixel_influence_upperbound = out_pixel_center + out_filter_radius; + + float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) / scale_ratio; + float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) / scale_ratio; + + *in_center_of_out = (out_pixel_center + out_shift) / scale_ratio; + *in_first_pixel = (int)(floor(in_pixel_influence_lowerbound + 0.5)); + *in_last_pixel = (int)(floor(in_pixel_influence_upperbound - 0.5)); +} + +// What output pixels does this input pixel contribute to? +static void stbir__calculate_sample_range_downsample(int n, float in_pixels_radius, float scale_ratio, float out_shift, int* out_first_pixel, int* out_last_pixel, float* out_center_of_in) +{ + float in_pixel_center = (float)n + 0.5f; + float in_pixel_influence_lowerbound = in_pixel_center - in_pixels_radius; + float in_pixel_influence_upperbound = in_pixel_center + in_pixels_radius; + + float out_pixel_influence_lowerbound = in_pixel_influence_lowerbound * scale_ratio - out_shift; + float out_pixel_influence_upperbound = in_pixel_influence_upperbound * scale_ratio - out_shift; + + *out_center_of_in = in_pixel_center * scale_ratio - out_shift; + *out_first_pixel = (int)(floor(out_pixel_influence_lowerbound + 0.5)); + *out_last_pixel = (int)(floor(out_pixel_influence_upperbound - 0.5)); +} + +static void stbir__calculate_coefficients_upsample(stbir_filter filter, float scale, int in_first_pixel, int in_last_pixel, float in_center_of_out, stbir__contributors* contributor, float* coefficient_group) +{ + int i; + float total_filter = 0; + float filter_scale; + + STBIR_ASSERT(in_last_pixel - in_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical. + + contributor->n0 = in_first_pixel; + contributor->n1 = in_last_pixel; + + STBIR_ASSERT(contributor->n1 >= contributor->n0); + + for (i = 0; i <= in_last_pixel - in_first_pixel; i++) + { + float in_pixel_center = (float)(i + in_first_pixel) + 0.5f; + coefficient_group[i] = stbir__filter_info_table[filter].kernel(in_center_of_out - in_pixel_center, 1 / scale); + + // If the coefficient is zero, skip it. (Don't do the <0 check here, we want the influence of those outside pixels.) + if (i == 0 && !coefficient_group[i]) + { + contributor->n0 = ++in_first_pixel; + i--; + continue; + } + + total_filter += coefficient_group[i]; + } + + STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0); + + STBIR_ASSERT(total_filter > 0.9); + STBIR_ASSERT(total_filter < 1.1f); // Make sure it's not way off. + + // Make sure the sum of all coefficients is 1. + filter_scale = 1 / total_filter; + + for (i = 0; i <= in_last_pixel - in_first_pixel; i++) + coefficient_group[i] *= filter_scale; + + for (i = in_last_pixel - in_first_pixel; i >= 0; i--) + { + if (coefficient_group[i]) + break; + + // This line has no weight. We can skip it. + contributor->n1 = contributor->n0 + i - 1; + } +} + +static void stbir__calculate_coefficients_downsample(stbir_filter filter, float scale_ratio, int out_first_pixel, int out_last_pixel, float out_center_of_in, stbir__contributors* contributor, float* coefficient_group) +{ + int i; + + STBIR_ASSERT(out_last_pixel - out_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(scale_ratio) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical. + + contributor->n0 = out_first_pixel; + contributor->n1 = out_last_pixel; + + STBIR_ASSERT(contributor->n1 >= contributor->n0); + + for (i = 0; i <= out_last_pixel - out_first_pixel; i++) + { + float out_pixel_center = (float)(i + out_first_pixel) + 0.5f; + float x = out_pixel_center - out_center_of_in; + coefficient_group[i] = stbir__filter_info_table[filter].kernel(x, scale_ratio) * scale_ratio; + } + + STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0); + + for (i = out_last_pixel - out_first_pixel; i >= 0; i--) + { + if (coefficient_group[i]) + break; + + // This line has no weight. We can skip it. + contributor->n1 = contributor->n0 + i - 1; + } +} + +static void stbir__normalize_downsample_coefficients(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, int input_size, int output_size) +{ + int num_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size); + int num_coefficients = stbir__get_coefficient_width(filter, scale_ratio); + int i, j; + int skip; + + for (i = 0; i < output_size; i++) + { + float scale; + float total = 0; + + for (j = 0; j < num_contributors; j++) + { + if (i >= contributors[j].n0 && i <= contributors[j].n1) + { + float coefficient = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0); + total += coefficient; + } + else if (i < contributors[j].n0) + break; + } + + STBIR_ASSERT(total > 0.9f); + STBIR_ASSERT(total < 1.1f); + + scale = 1 / total; + + for (j = 0; j < num_contributors; j++) + { + if (i >= contributors[j].n0 && i <= contributors[j].n1) + *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0) *= scale; + else if (i < contributors[j].n0) + break; + } + } + + // Optimize: Skip zero coefficients and contributions outside of image bounds. + // Do this after normalizing because normalization depends on the n0/n1 values. + for (j = 0; j < num_contributors; j++) + { + int range, max, width; + + skip = 0; + while (*stbir__get_coefficient(coefficients, filter, scale_ratio, j, skip) == 0) + skip++; + + contributors[j].n0 += skip; + + while (contributors[j].n0 < 0) + { + contributors[j].n0++; + skip++; + } + + range = contributors[j].n1 - contributors[j].n0 + 1; + max = stbir__min(num_coefficients, range); + + width = stbir__get_coefficient_width(filter, scale_ratio); + for (i = 0; i < max; i++) + { + if (i + skip >= width) + break; + + *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i) = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i + skip); + } + + continue; + } + + // Using min to avoid writing into invalid pixels. + for (i = 0; i < num_contributors; i++) + contributors[i].n1 = stbir__min(contributors[i].n1, output_size - 1); +} + +// Each scan line uses the same kernel values so we should calculate the kernel +// values once and then we can use them for every scan line. +static void stbir__calculate_filters(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size) +{ + int n; + int total_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size); + + if (stbir__use_upsampling(scale_ratio)) + { + float out_pixels_radius = stbir__filter_info_table[filter].support(1 / scale_ratio) * scale_ratio; + + // Looping through out pixels + for (n = 0; n < total_contributors; n++) + { + float in_center_of_out; // Center of the current out pixel in the in pixel space + int in_first_pixel, in_last_pixel; + + stbir__calculate_sample_range_upsample(n, out_pixels_radius, scale_ratio, shift, &in_first_pixel, &in_last_pixel, &in_center_of_out); + + stbir__calculate_coefficients_upsample(filter, scale_ratio, in_first_pixel, in_last_pixel, in_center_of_out, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0)); + } + } + else + { + float in_pixels_radius = stbir__filter_info_table[filter].support(scale_ratio) / scale_ratio; + + // Looping through in pixels + for (n = 0; n < total_contributors; n++) + { + float out_center_of_in; // Center of the current out pixel in the in pixel space + int out_first_pixel, out_last_pixel; + int n_adjusted = n - stbir__get_filter_pixel_margin(filter, scale_ratio); + + stbir__calculate_sample_range_downsample(n_adjusted, in_pixels_radius, scale_ratio, shift, &out_first_pixel, &out_last_pixel, &out_center_of_in); + + stbir__calculate_coefficients_downsample(filter, scale_ratio, out_first_pixel, out_last_pixel, out_center_of_in, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0)); + } + + stbir__normalize_downsample_coefficients(contributors, coefficients, filter, scale_ratio, input_size, output_size); + } +} + +static float* stbir__get_decode_buffer(stbir__info* stbir_info) +{ + // The 0 index of the decode buffer starts after the margin. This makes + // it okay to use negative indexes on the decode buffer. + return &stbir_info->decode_buffer[stbir_info->horizontal_filter_pixel_margin * stbir_info->channels]; +} + +#define STBIR__DECODE(type, colorspace) ((type) * (STBIR_MAX_COLORSPACES) + (colorspace)) + +static void stbir__decode_scanline(stbir__info* stbir_info, int n) +{ + int c; + int channels = stbir_info->channels; + int alpha_channel = stbir_info->alpha_channel; + int type = stbir_info->type; + int colorspace = stbir_info->colorspace; + int input_w = stbir_info->input_w; + size_t input_stride_bytes = stbir_info->input_stride_bytes; + float* decode_buffer = stbir__get_decode_buffer(stbir_info); + stbir_edge edge_horizontal = stbir_info->edge_horizontal; + stbir_edge edge_vertical = stbir_info->edge_vertical; + size_t in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info->input_h) * input_stride_bytes; + const void* input_data = (char *) stbir_info->input_data + in_buffer_row_offset; + int max_x = input_w + stbir_info->horizontal_filter_pixel_margin; + int decode = STBIR__DECODE(type, colorspace); + + int x = -stbir_info->horizontal_filter_pixel_margin; + + // special handling for STBIR_EDGE_ZERO because it needs to return an item that doesn't appear in the input, + // and we want to avoid paying overhead on every pixel if not STBIR_EDGE_ZERO + if (edge_vertical == STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info->input_h)) + { + for (; x < max_x; x++) + for (c = 0; c < channels; c++) + decode_buffer[x*channels + c] = 0; + return; + } + + switch (decode) + { + case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = ((float)((const unsigned char*)input_data)[input_pixel_index + c]) / stbir__max_uint8_as_float; + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = stbir__srgb_uchar_to_linear_float[((const unsigned char*)input_data)[input_pixel_index + c]]; + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned char*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint8_as_float; + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = ((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float; + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float); + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned short*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint16_as_float; + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float); + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float)); + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + decode_buffer[decode_pixel_index + alpha_channel] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint32_as_float); + } + break; + + case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = ((const float*)input_data)[input_pixel_index + c]; + } + break; + + case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((const float*)input_data)[input_pixel_index + c]); + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + decode_buffer[decode_pixel_index + alpha_channel] = ((const float*)input_data)[input_pixel_index + alpha_channel]; + } + + break; + + default: + STBIR_ASSERT(!"Unknown type/colorspace/channels combination."); + break; + } + + if (!(stbir_info->flags & STBIR_FLAG_ALPHA_PREMULTIPLIED)) + { + for (x = -stbir_info->horizontal_filter_pixel_margin; x < max_x; x++) + { + int decode_pixel_index = x * channels; + + // If the alpha value is 0 it will clobber the color values. Make sure it's not. + float alpha = decode_buffer[decode_pixel_index + alpha_channel]; +#ifndef STBIR_NO_ALPHA_EPSILON + if (stbir_info->type != STBIR_TYPE_FLOAT) { + alpha += STBIR_ALPHA_EPSILON; + decode_buffer[decode_pixel_index + alpha_channel] = alpha; + } +#endif + for (c = 0; c < channels; c++) + { + if (c == alpha_channel) + continue; + + decode_buffer[decode_pixel_index + c] *= alpha; + } + } + } + + if (edge_horizontal == STBIR_EDGE_ZERO) + { + for (x = -stbir_info->horizontal_filter_pixel_margin; x < 0; x++) + { + for (c = 0; c < channels; c++) + decode_buffer[x*channels + c] = 0; + } + for (x = input_w; x < max_x; x++) + { + for (c = 0; c < channels; c++) + decode_buffer[x*channels + c] = 0; + } + } +} + +static float* stbir__get_ring_buffer_entry(float* ring_buffer, int index, int ring_buffer_length) +{ + return &ring_buffer[index * ring_buffer_length]; +} + +static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n) +{ + int ring_buffer_index; + float* ring_buffer; + + stbir_info->ring_buffer_last_scanline = n; + + if (stbir_info->ring_buffer_begin_index < 0) + { + ring_buffer_index = stbir_info->ring_buffer_begin_index = 0; + stbir_info->ring_buffer_first_scanline = n; + } + else + { + ring_buffer_index = (stbir_info->ring_buffer_begin_index + (stbir_info->ring_buffer_last_scanline - stbir_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries; + STBIR_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index); + } + + ring_buffer = stbir__get_ring_buffer_entry(stbir_info->ring_buffer, ring_buffer_index, stbir_info->ring_buffer_length_bytes / sizeof(float)); + memset(ring_buffer, 0, stbir_info->ring_buffer_length_bytes); + + return ring_buffer; +} + + +static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, float* output_buffer) +{ + int x, k; + int output_w = stbir_info->output_w; + int channels = stbir_info->channels; + float* decode_buffer = stbir__get_decode_buffer(stbir_info); + stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors; + float* horizontal_coefficients = stbir_info->horizontal_coefficients; + int coefficient_width = stbir_info->horizontal_coefficient_width; + + for (x = 0; x < output_w; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int out_pixel_index = x * channels; + int coefficient_group = coefficient_width * x; + int coefficient_counter = 0; + + STBIR_ASSERT(n1 >= n0); + STBIR_ASSERT(n0 >= -stbir_info->horizontal_filter_pixel_margin); + STBIR_ASSERT(n1 >= -stbir_info->horizontal_filter_pixel_margin); + STBIR_ASSERT(n0 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin); + STBIR_ASSERT(n1 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin); + + switch (channels) { + case 1: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * 1; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + } + break; + case 2: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * 2; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + } + break; + case 3: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * 3; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; + } + break; + case 4: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * 4; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; + output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient; + } + break; + default: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * channels; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + int c; + STBIR_ASSERT(coefficient != 0); + for (c = 0; c < channels; c++) + output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient; + } + break; + } + } +} + +static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float* output_buffer) +{ + int x, k; + int input_w = stbir_info->input_w; + int channels = stbir_info->channels; + float* decode_buffer = stbir__get_decode_buffer(stbir_info); + stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors; + float* horizontal_coefficients = stbir_info->horizontal_coefficients; + int coefficient_width = stbir_info->horizontal_coefficient_width; + int filter_pixel_margin = stbir_info->horizontal_filter_pixel_margin; + int max_x = input_w + filter_pixel_margin * 2; + + STBIR_ASSERT(!stbir__use_width_upsampling(stbir_info)); + + switch (channels) { + case 1: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * 1; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int out_pixel_index = k * 1; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + } + } + break; + + case 2: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * 2; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int out_pixel_index = k * 2; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + } + } + break; + + case 3: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * 3; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int out_pixel_index = k * 3; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; + } + } + break; + + case 4: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * 4; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int out_pixel_index = k * 4; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; + output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient; + } + } + break; + + default: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * channels; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int c; + int out_pixel_index = k * channels; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + for (c = 0; c < channels; c++) + output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient; + } + } + break; + } +} + +static void stbir__decode_and_resample_upsample(stbir__info* stbir_info, int n) +{ + // Decode the nth scanline from the source image into the decode buffer. + stbir__decode_scanline(stbir_info, n); + + // Now resample it into the ring buffer. + if (stbir__use_width_upsampling(stbir_info)) + stbir__resample_horizontal_upsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n)); + else + stbir__resample_horizontal_downsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n)); + + // Now it's sitting in the ring buffer ready to be used as source for the vertical sampling. +} + +static void stbir__decode_and_resample_downsample(stbir__info* stbir_info, int n) +{ + // Decode the nth scanline from the source image into the decode buffer. + stbir__decode_scanline(stbir_info, n); + + memset(stbir_info->horizontal_buffer, 0, stbir_info->output_w * stbir_info->channels * sizeof(float)); + + // Now resample it into the horizontal buffer. + if (stbir__use_width_upsampling(stbir_info)) + stbir__resample_horizontal_upsample(stbir_info, stbir_info->horizontal_buffer); + else + stbir__resample_horizontal_downsample(stbir_info, stbir_info->horizontal_buffer); + + // Now it's sitting in the horizontal buffer ready to be distributed into the ring buffers. +} + +// Get the specified scan line from the ring buffer. +static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buffer, int begin_index, int first_scanline, int ring_buffer_num_entries, int ring_buffer_length) +{ + int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_num_entries; + return stbir__get_ring_buffer_entry(ring_buffer, ring_buffer_index, ring_buffer_length); +} + + +static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void *output_buffer, float *encode_buffer, int channels, int alpha_channel, int decode) +{ + int x; + int n; + int num_nonalpha; + stbir_uint16 nonalpha[STBIR_MAX_CHANNELS]; + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)) + { + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + float alpha = encode_buffer[pixel_index + alpha_channel]; + float reciprocal_alpha = alpha ? 1.0f / alpha : 0; + + // unrolling this produced a 1% slowdown upscaling a large RGBA linear-space image on my machine - stb + for (n = 0; n < channels; n++) + if (n != alpha_channel) + encode_buffer[pixel_index + n] *= reciprocal_alpha; + + // We added in a small epsilon to prevent the color channel from being deleted with zero alpha. + // Because we only add it for integer types, it will automatically be discarded on integer + // conversion, so we don't need to subtract it back out (which would be problematic for + // numeric precision reasons). + } + } + + // build a table of all channels that need colorspace correction, so + // we don't perform colorspace correction on channels that don't need it. + for (x = 0, num_nonalpha = 0; x < channels; ++x) + { + if (x != alpha_channel || (stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE)) + { + nonalpha[num_nonalpha++] = (stbir_uint16)x; + } + } + + #define STBIR__ROUND_INT(f) ((int) ((f)+0.5)) + #define STBIR__ROUND_UINT(f) ((stbir_uint32) ((f)+0.5)) + + #ifdef STBIR__SATURATE_INT + #define STBIR__ENCODE_LINEAR8(f) stbir__saturate8 (STBIR__ROUND_INT((f) * stbir__max_uint8_as_float )) + #define STBIR__ENCODE_LINEAR16(f) stbir__saturate16(STBIR__ROUND_INT((f) * stbir__max_uint16_as_float)) + #else + #define STBIR__ENCODE_LINEAR8(f) (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint8_as_float ) + #define STBIR__ENCODE_LINEAR16(f) (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint16_as_float) + #endif + + switch (decode) + { + case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < channels; n++) + { + int index = pixel_index + n; + ((unsigned char*)output_buffer)[index] = STBIR__ENCODE_LINEAR8(encode_buffer[index]); + } + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < num_nonalpha; n++) + { + int index = pixel_index + nonalpha[n]; + ((unsigned char*)output_buffer)[index] = stbir__linear_to_srgb_uchar(encode_buffer[index]); + } + + if (!(stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE)) + ((unsigned char *)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR8(encode_buffer[pixel_index+alpha_channel]); + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < channels; n++) + { + int index = pixel_index + n; + ((unsigned short*)output_buffer)[index] = STBIR__ENCODE_LINEAR16(encode_buffer[index]); + } + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < num_nonalpha; n++) + { + int index = pixel_index + nonalpha[n]; + ((unsigned short*)output_buffer)[index] = (unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * stbir__max_uint16_as_float); + } + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + ((unsigned short*)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR16(encode_buffer[pixel_index + alpha_channel]); + } + + break; + + case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < channels; n++) + { + int index = pixel_index + n; + ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__saturate(encode_buffer[index])) * stbir__max_uint32_as_float); + } + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < num_nonalpha; n++) + { + int index = pixel_index + nonalpha[n]; + ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * stbir__max_uint32_as_float); + } + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + ((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)STBIR__ROUND_INT(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * stbir__max_uint32_as_float); + } + break; + + case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < channels; n++) + { + int index = pixel_index + n; + ((float*)output_buffer)[index] = encode_buffer[index]; + } + } + break; + + case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < num_nonalpha; n++) + { + int index = pixel_index + nonalpha[n]; + ((float*)output_buffer)[index] = stbir__linear_to_srgb(encode_buffer[index]); + } + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + ((float*)output_buffer)[pixel_index + alpha_channel] = encode_buffer[pixel_index + alpha_channel]; + } + break; + + default: + STBIR_ASSERT(!"Unknown type/colorspace/channels combination."); + break; + } +} + +static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n) +{ + int x, k; + int output_w = stbir_info->output_w; + stbir__contributors* vertical_contributors = stbir_info->vertical_contributors; + float* vertical_coefficients = stbir_info->vertical_coefficients; + int channels = stbir_info->channels; + int alpha_channel = stbir_info->alpha_channel; + int type = stbir_info->type; + int colorspace = stbir_info->colorspace; + int ring_buffer_entries = stbir_info->ring_buffer_num_entries; + void* output_data = stbir_info->output_data; + float* encode_buffer = stbir_info->encode_buffer; + int decode = STBIR__DECODE(type, colorspace); + int coefficient_width = stbir_info->vertical_coefficient_width; + int coefficient_counter; + int contributor = n; + + float* ring_buffer = stbir_info->ring_buffer; + int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index; + int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline; + int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float); + + int n0,n1, output_row_start; + int coefficient_group = coefficient_width * contributor; + + n0 = vertical_contributors[contributor].n0; + n1 = vertical_contributors[contributor].n1; + + output_row_start = n * stbir_info->output_stride_bytes; + + STBIR_ASSERT(stbir__use_height_upsampling(stbir_info)); + + memset(encode_buffer, 0, output_w * sizeof(float) * channels); + + // I tried reblocking this for better cache usage of encode_buffer + // (using x_outer, k, x_inner), but it lost speed. -- stb + + coefficient_counter = 0; + switch (channels) { + case 1: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * 1; + encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; + } + } + break; + case 2: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * 2; + encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; + encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient; + } + } + break; + case 3: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * 3; + encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; + encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient; + encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient; + } + } + break; + case 4: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * 4; + encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; + encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient; + encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient; + encode_buffer[in_pixel_index + 3] += ring_buffer_entry[in_pixel_index + 3] * coefficient; + } + } + break; + default: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * channels; + int c; + for (c = 0; c < channels; c++) + encode_buffer[in_pixel_index + c] += ring_buffer_entry[in_pixel_index + c] * coefficient; + } + } + break; + } + stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, encode_buffer, channels, alpha_channel, decode); +} + +static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n) +{ + int x, k; + int output_w = stbir_info->output_w; + stbir__contributors* vertical_contributors = stbir_info->vertical_contributors; + float* vertical_coefficients = stbir_info->vertical_coefficients; + int channels = stbir_info->channels; + int ring_buffer_entries = stbir_info->ring_buffer_num_entries; + float* horizontal_buffer = stbir_info->horizontal_buffer; + int coefficient_width = stbir_info->vertical_coefficient_width; + int contributor = n + stbir_info->vertical_filter_pixel_margin; + + float* ring_buffer = stbir_info->ring_buffer; + int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index; + int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline; + int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float); + int n0,n1; + + n0 = vertical_contributors[contributor].n0; + n1 = vertical_contributors[contributor].n1; + + STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info)); + + for (k = n0; k <= n1; k++) + { + int coefficient_index = k - n0; + int coefficient_group = coefficient_width * contributor; + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + + switch (channels) { + case 1: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * 1; + ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; + } + break; + case 2: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * 2; + ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; + ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient; + } + break; + case 3: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * 3; + ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; + ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient; + ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient; + } + break; + case 4: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * 4; + ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; + ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient; + ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient; + ring_buffer_entry[in_pixel_index + 3] += horizontal_buffer[in_pixel_index + 3] * coefficient; + } + break; + default: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * channels; + + int c; + for (c = 0; c < channels; c++) + ring_buffer_entry[in_pixel_index + c] += horizontal_buffer[in_pixel_index + c] * coefficient; + } + break; + } + } +} + +static void stbir__buffer_loop_upsample(stbir__info* stbir_info) +{ + int y; + float scale_ratio = stbir_info->vertical_scale; + float out_scanlines_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(1/scale_ratio) * scale_ratio; + + STBIR_ASSERT(stbir__use_height_upsampling(stbir_info)); + + for (y = 0; y < stbir_info->output_h; y++) + { + float in_center_of_out = 0; // Center of the current out scanline in the in scanline space + int in_first_scanline = 0, in_last_scanline = 0; + + stbir__calculate_sample_range_upsample(y, out_scanlines_radius, scale_ratio, stbir_info->vertical_shift, &in_first_scanline, &in_last_scanline, &in_center_of_out); + + STBIR_ASSERT(in_last_scanline - in_first_scanline + 1 <= stbir_info->ring_buffer_num_entries); + + if (stbir_info->ring_buffer_begin_index >= 0) + { + // Get rid of whatever we don't need anymore. + while (in_first_scanline > stbir_info->ring_buffer_first_scanline) + { + if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline) + { + // We just popped the last scanline off the ring buffer. + // Reset it to the empty state. + stbir_info->ring_buffer_begin_index = -1; + stbir_info->ring_buffer_first_scanline = 0; + stbir_info->ring_buffer_last_scanline = 0; + break; + } + else + { + stbir_info->ring_buffer_first_scanline++; + stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries; + } + } + } + + // Load in new ones. + if (stbir_info->ring_buffer_begin_index < 0) + stbir__decode_and_resample_upsample(stbir_info, in_first_scanline); + + while (in_last_scanline > stbir_info->ring_buffer_last_scanline) + stbir__decode_and_resample_upsample(stbir_info, stbir_info->ring_buffer_last_scanline + 1); + + // Now all buffers should be ready to write a row of vertical sampling. + stbir__resample_vertical_upsample(stbir_info, y); + + STBIR_PROGRESS_REPORT((float)y / stbir_info->output_h); + } +} + +static void stbir__empty_ring_buffer(stbir__info* stbir_info, int first_necessary_scanline) +{ + int output_stride_bytes = stbir_info->output_stride_bytes; + int channels = stbir_info->channels; + int alpha_channel = stbir_info->alpha_channel; + int type = stbir_info->type; + int colorspace = stbir_info->colorspace; + int output_w = stbir_info->output_w; + void* output_data = stbir_info->output_data; + int decode = STBIR__DECODE(type, colorspace); + + float* ring_buffer = stbir_info->ring_buffer; + int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float); + + if (stbir_info->ring_buffer_begin_index >= 0) + { + // Get rid of whatever we don't need anymore. + while (first_necessary_scanline > stbir_info->ring_buffer_first_scanline) + { + if (stbir_info->ring_buffer_first_scanline >= 0 && stbir_info->ring_buffer_first_scanline < stbir_info->output_h) + { + int output_row_start = stbir_info->ring_buffer_first_scanline * output_stride_bytes; + float* ring_buffer_entry = stbir__get_ring_buffer_entry(ring_buffer, stbir_info->ring_buffer_begin_index, ring_buffer_length); + stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, ring_buffer_entry, channels, alpha_channel, decode); + STBIR_PROGRESS_REPORT((float)stbir_info->ring_buffer_first_scanline / stbir_info->output_h); + } + + if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline) + { + // We just popped the last scanline off the ring buffer. + // Reset it to the empty state. + stbir_info->ring_buffer_begin_index = -1; + stbir_info->ring_buffer_first_scanline = 0; + stbir_info->ring_buffer_last_scanline = 0; + break; + } + else + { + stbir_info->ring_buffer_first_scanline++; + stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries; + } + } + } +} + +static void stbir__buffer_loop_downsample(stbir__info* stbir_info) +{ + int y; + float scale_ratio = stbir_info->vertical_scale; + int output_h = stbir_info->output_h; + float in_pixels_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(scale_ratio) / scale_ratio; + int pixel_margin = stbir_info->vertical_filter_pixel_margin; + int max_y = stbir_info->input_h + pixel_margin; + + STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info)); + + for (y = -pixel_margin; y < max_y; y++) + { + float out_center_of_in; // Center of the current out scanline in the in scanline space + int out_first_scanline, out_last_scanline; + + stbir__calculate_sample_range_downsample(y, in_pixels_radius, scale_ratio, stbir_info->vertical_shift, &out_first_scanline, &out_last_scanline, &out_center_of_in); + + STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries); + + if (out_last_scanline < 0 || out_first_scanline >= output_h) + continue; + + stbir__empty_ring_buffer(stbir_info, out_first_scanline); + + stbir__decode_and_resample_downsample(stbir_info, y); + + // Load in new ones. + if (stbir_info->ring_buffer_begin_index < 0) + stbir__add_empty_ring_buffer_entry(stbir_info, out_first_scanline); + + while (out_last_scanline > stbir_info->ring_buffer_last_scanline) + stbir__add_empty_ring_buffer_entry(stbir_info, stbir_info->ring_buffer_last_scanline + 1); + + // Now the horizontal buffer is ready to write to all ring buffer rows. + stbir__resample_vertical_downsample(stbir_info, y); + } + + stbir__empty_ring_buffer(stbir_info, stbir_info->output_h); +} + +static void stbir__setup(stbir__info *info, int input_w, int input_h, int output_w, int output_h, int channels) +{ + info->input_w = input_w; + info->input_h = input_h; + info->output_w = output_w; + info->output_h = output_h; + info->channels = channels; +} + +static void stbir__calculate_transform(stbir__info *info, float s0, float t0, float s1, float t1, float *transform) +{ + info->s0 = s0; + info->t0 = t0; + info->s1 = s1; + info->t1 = t1; + + if (transform) + { + info->horizontal_scale = transform[0]; + info->vertical_scale = transform[1]; + info->horizontal_shift = transform[2]; + info->vertical_shift = transform[3]; + } + else + { + info->horizontal_scale = ((float)info->output_w / info->input_w) / (s1 - s0); + info->vertical_scale = ((float)info->output_h / info->input_h) / (t1 - t0); + + info->horizontal_shift = s0 * info->output_w / (s1 - s0); + info->vertical_shift = t0 * info->output_h / (t1 - t0); + } +} + +static void stbir__choose_filter(stbir__info *info, stbir_filter h_filter, stbir_filter v_filter) +{ + if (h_filter == 0) + h_filter = stbir__use_upsampling(info->horizontal_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE; + if (v_filter == 0) + v_filter = stbir__use_upsampling(info->vertical_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE; + info->horizontal_filter = h_filter; + info->vertical_filter = v_filter; +} + +static stbir_uint32 stbir__calculate_memory(stbir__info *info) +{ + int pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale); + int filter_height = stbir__get_filter_pixel_width(info->vertical_filter, info->vertical_scale); + + info->horizontal_num_contributors = stbir__get_contributors(info->horizontal_scale, info->horizontal_filter, info->input_w, info->output_w); + info->vertical_num_contributors = stbir__get_contributors(info->vertical_scale , info->vertical_filter , info->input_h, info->output_h); + + // One extra entry because floating point precision problems sometimes cause an extra to be necessary. + info->ring_buffer_num_entries = filter_height + 1; + + info->horizontal_contributors_size = info->horizontal_num_contributors * sizeof(stbir__contributors); + info->horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info) * sizeof(float); + info->vertical_contributors_size = info->vertical_num_contributors * sizeof(stbir__contributors); + info->vertical_coefficients_size = stbir__get_total_vertical_coefficients(info) * sizeof(float); + info->decode_buffer_size = (info->input_w + pixel_margin * 2) * info->channels * sizeof(float); + info->horizontal_buffer_size = info->output_w * info->channels * sizeof(float); + info->ring_buffer_size = info->output_w * info->channels * info->ring_buffer_num_entries * sizeof(float); + info->encode_buffer_size = info->output_w * info->channels * sizeof(float); + + STBIR_ASSERT(info->horizontal_filter != 0); + STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late + STBIR_ASSERT(info->vertical_filter != 0); + STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late + + if (stbir__use_height_upsampling(info)) + // The horizontal buffer is for when we're downsampling the height and we + // can't output the result of sampling the decode buffer directly into the + // ring buffers. + info->horizontal_buffer_size = 0; + else + // The encode buffer is to retain precision in the height upsampling method + // and isn't used when height downsampling. + info->encode_buffer_size = 0; + + return info->horizontal_contributors_size + info->horizontal_coefficients_size + + info->vertical_contributors_size + info->vertical_coefficients_size + + info->decode_buffer_size + info->horizontal_buffer_size + + info->ring_buffer_size + info->encode_buffer_size; +} + +static int stbir__resize_allocated(stbir__info *info, + const void* input_data, int input_stride_in_bytes, + void* output_data, int output_stride_in_bytes, + int alpha_channel, stbir_uint32 flags, stbir_datatype type, + stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace, + void* tempmem, size_t tempmem_size_in_bytes) +{ + size_t memory_required = stbir__calculate_memory(info); + + int width_stride_input = input_stride_in_bytes ? input_stride_in_bytes : info->channels * info->input_w * stbir__type_size[type]; + int width_stride_output = output_stride_in_bytes ? output_stride_in_bytes : info->channels * info->output_w * stbir__type_size[type]; + +#ifdef STBIR_DEBUG_OVERWRITE_TEST +#define OVERWRITE_ARRAY_SIZE 8 + unsigned char overwrite_output_before_pre[OVERWRITE_ARRAY_SIZE]; + unsigned char overwrite_tempmem_before_pre[OVERWRITE_ARRAY_SIZE]; + unsigned char overwrite_output_after_pre[OVERWRITE_ARRAY_SIZE]; + unsigned char overwrite_tempmem_after_pre[OVERWRITE_ARRAY_SIZE]; + + size_t begin_forbidden = width_stride_output * (info->output_h - 1) + info->output_w * info->channels * stbir__type_size[type]; + memcpy(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE); + memcpy(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE); + memcpy(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE); + memcpy(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE); +#endif + + STBIR_ASSERT(info->channels >= 0); + STBIR_ASSERT(info->channels <= STBIR_MAX_CHANNELS); + + if (info->channels < 0 || info->channels > STBIR_MAX_CHANNELS) + return 0; + + STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); + STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); + + if (info->horizontal_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table)) + return 0; + if (info->vertical_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table)) + return 0; + + if (alpha_channel < 0) + flags |= STBIR_FLAG_ALPHA_USES_COLORSPACE | STBIR_FLAG_ALPHA_PREMULTIPLIED; + + if (!(flags&STBIR_FLAG_ALPHA_USES_COLORSPACE) || !(flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)) { + STBIR_ASSERT(alpha_channel >= 0 && alpha_channel < info->channels); + } + + if (alpha_channel >= info->channels) + return 0; + + STBIR_ASSERT(tempmem); + + if (!tempmem) + return 0; + + STBIR_ASSERT(tempmem_size_in_bytes >= memory_required); + + if (tempmem_size_in_bytes < memory_required) + return 0; + + memset(tempmem, 0, tempmem_size_in_bytes); + + info->input_data = input_data; + info->input_stride_bytes = width_stride_input; + + info->output_data = output_data; + info->output_stride_bytes = width_stride_output; + + info->alpha_channel = alpha_channel; + info->flags = flags; + info->type = type; + info->edge_horizontal = edge_horizontal; + info->edge_vertical = edge_vertical; + info->colorspace = colorspace; + + info->horizontal_coefficient_width = stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale); + info->vertical_coefficient_width = stbir__get_coefficient_width (info->vertical_filter , info->vertical_scale ); + info->horizontal_filter_pixel_width = stbir__get_filter_pixel_width (info->horizontal_filter, info->horizontal_scale); + info->vertical_filter_pixel_width = stbir__get_filter_pixel_width (info->vertical_filter , info->vertical_scale ); + info->horizontal_filter_pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale); + info->vertical_filter_pixel_margin = stbir__get_filter_pixel_margin(info->vertical_filter , info->vertical_scale ); + + info->ring_buffer_length_bytes = info->output_w * info->channels * sizeof(float); + info->decode_buffer_pixels = info->input_w + info->horizontal_filter_pixel_margin * 2; + +#define STBIR__NEXT_MEMPTR(current, newtype) (newtype*)(((unsigned char*)current) + current##_size) + + info->horizontal_contributors = (stbir__contributors *) tempmem; + info->horizontal_coefficients = STBIR__NEXT_MEMPTR(info->horizontal_contributors, float); + info->vertical_contributors = STBIR__NEXT_MEMPTR(info->horizontal_coefficients, stbir__contributors); + info->vertical_coefficients = STBIR__NEXT_MEMPTR(info->vertical_contributors, float); + info->decode_buffer = STBIR__NEXT_MEMPTR(info->vertical_coefficients, float); + + if (stbir__use_height_upsampling(info)) + { + info->horizontal_buffer = NULL; + info->ring_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float); + info->encode_buffer = STBIR__NEXT_MEMPTR(info->ring_buffer, float); + + STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->encode_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes); + } + else + { + info->horizontal_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float); + info->ring_buffer = STBIR__NEXT_MEMPTR(info->horizontal_buffer, float); + info->encode_buffer = NULL; + + STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->ring_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes); + } + +#undef STBIR__NEXT_MEMPTR + + // This signals that the ring buffer is empty + info->ring_buffer_begin_index = -1; + + stbir__calculate_filters(info->horizontal_contributors, info->horizontal_coefficients, info->horizontal_filter, info->horizontal_scale, info->horizontal_shift, info->input_w, info->output_w); + stbir__calculate_filters(info->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h); + + STBIR_PROGRESS_REPORT(0); + + if (stbir__use_height_upsampling(info)) + stbir__buffer_loop_upsample(info); + else + stbir__buffer_loop_downsample(info); + + STBIR_PROGRESS_REPORT(1); + +#ifdef STBIR_DEBUG_OVERWRITE_TEST + STBIR_ASSERT(memcmp(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0); + STBIR_ASSERT(memcmp(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE) == 0); + STBIR_ASSERT(memcmp(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0); + STBIR_ASSERT(memcmp(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE) == 0); +#endif + + return 1; +} + + +static int stbir__resize_arbitrary( + void *alloc_context, + const void* input_data, int input_w, int input_h, int input_stride_in_bytes, + void* output_data, int output_w, int output_h, int output_stride_in_bytes, + float s0, float t0, float s1, float t1, float *transform, + int channels, int alpha_channel, stbir_uint32 flags, stbir_datatype type, + stbir_filter h_filter, stbir_filter v_filter, + stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace) +{ + stbir__info info; + int result; + size_t memory_required; + void* extra_memory; + + stbir__setup(&info, input_w, input_h, output_w, output_h, channels); + stbir__calculate_transform(&info, s0,t0,s1,t1,transform); + stbir__choose_filter(&info, h_filter, v_filter); + memory_required = stbir__calculate_memory(&info); + extra_memory = STBIR_MALLOC(memory_required, alloc_context); + + if (!extra_memory) + return 0; + + result = stbir__resize_allocated(&info, input_data, input_stride_in_bytes, + output_data, output_stride_in_bytes, + alpha_channel, flags, type, + edge_horizontal, edge_vertical, + colorspace, extra_memory, memory_required); + + STBIR_FREE(extra_memory, alloc_context); + + return result; +} + +STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels) +{ + return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, + STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR); +} + +STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + float *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels) +{ + return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_FLOAT, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, + STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR); +} + +STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags) +{ + return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, + STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB); +} + +STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode) +{ + return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, + edge_wrap_mode, edge_wrap_mode, STBIR_COLORSPACE_SRGB); +} + +STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, filter, filter, + edge_wrap_mode, edge_wrap_mode, space); +} + +STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT16, filter, filter, + edge_wrap_mode, edge_wrap_mode, space); +} + + +STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + float *output_pixels , int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_FLOAT, filter, filter, + edge_wrap_mode, edge_wrap_mode, space); +} + + +STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical, + edge_mode_horizontal, edge_mode_vertical, space); +} + + +STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context, + float x_scale, float y_scale, + float x_offset, float y_offset) +{ + float transform[4]; + transform[0] = x_scale; + transform[1] = y_scale; + transform[2] = x_offset; + transform[3] = y_offset; + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,transform,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical, + edge_mode_horizontal, edge_mode_vertical, space); +} + +STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context, + float s0, float t0, float s1, float t1) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + s0,t0,s1,t1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical, + edge_mode_horizontal, edge_mode_vertical, space); +} + +#endif // STB_IMAGE_RESIZE_IMPLEMENTATION + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +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. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +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 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. +------------------------------------------------------------------------------ +*/ diff --git a/src/files/wal.c b/src/files/wal.c new file mode 100644 index 0000000..ddc184c --- /dev/null +++ b/src/files/wal.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 1997-2001 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. + * + * ======================================================================= + * + * The Wal image format + * + * ======================================================================= + */ + +#include "../common/header/ref_shared.h" + +/* + * NOTE: LoadWal() is in *_image.c because it needs the renderer-specific image_t + */ + +void +GetWalInfo(char *name, int *width, int *height) +{ + miptex_t *mt; + int size; + + size = ri.FS_LoadFile(name, (void **)&mt); + + if (!mt) + { + return; + } + + if (size < sizeof(miptex_t)) + { + ri.FS_FreeFile((void *)mt); + return; + } + + *width = LittleLong(mt->width); + *height = LittleLong(mt->height); + + ri.FS_FreeFile((void *)mt); + + return; +} + +void +GetM8Info(char *name, int *width, int *height) +{ + m8tex_t *mt; + int size; + + size = ri.FS_LoadFile(name, (void **)&mt); + + if (!mt) + { + return; + } + + + if (size < sizeof(m8tex_t) || LittleLong (mt->version) != M8_VERSION) + { + ri.FS_FreeFile((void *)mt); + return; + } + + *width = LittleLong(mt->width[0]); + *height = LittleLong(mt->height[0]); + + ri.FS_FreeFile((void *)mt); + + return; +} diff --git a/src/vk/header/local.h b/src/vk/header/local.h new file mode 100644 index 0000000..c078961 --- /dev/null +++ b/src/vk/header/local.h @@ -0,0 +1,331 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. +Copyright (C) 2018-2019 Krzysztof Kondrak + +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. +*/ + +#ifndef __VK_LOCAL_H__ +#define __VK_LOCAL_H__ + +#include +#include + +#include +#include + + +#include "../../common/header/ref_shared.h" +#include "../volk/volk.h" +#include "qvk.h" + +// verify if VkResult is VK_SUCCESS +#define VK_VERIFY(x) { \ + VkResult res = (x); \ + if(res != VK_SUCCESS) { \ + R_Printf(PRINT_ALL, "%s:%d: VkResult verification failed: %s\n", \ + __func__, __LINE__, QVk_GetError(res)); \ + } \ +} + +// up / down +#define PITCH 0 + +// left / right +#define YAW 1 + +// fall over +#define ROLL 2 + +extern viddef_t vid; + +typedef struct image_s +{ + char name[MAX_QPATH]; // game path, including extension + imagetype_t type; + int width, height; // source image + int upload_width, upload_height; // after power of two and picmip + int registration_sequence; // 0 = free + struct msurface_s *texturechain; // for sort-by-texture world drawing + qvktexture_t vk_texture; // Vulkan texture handle +} image_t; + +#define MAX_VKTEXTURES 1024 + +//=================================================================== + +typedef enum +{ + rserr_ok, + + rserr_invalid_fullscreen, + rserr_invalid_mode, + + rserr_unknown +} rserr_t; + +#include "model.h" + +#define MAX_LBM_HEIGHT 480 + +#define BACKFACE_EPSILON 0.01 + + +//==================================================== + +extern image_t vktextures[MAX_VKTEXTURES]; +extern int numvktextures; + +extern image_t *r_notexture; +extern image_t *r_particletexture; +extern image_t *r_squaretexture; +extern int r_visframecount; +extern int r_framecount; +extern cplane_t frustum[4]; +extern int c_brush_polys, c_alias_polys; + +// +// view origin +// +extern vec3_t vup; +extern vec3_t vpn; +extern vec3_t vright; +extern vec3_t r_origin; + +// +// screen size info +// +extern refdef_t r_newrefdef; +extern int r_viewcluster, r_viewcluster2, r_oldviewcluster, r_oldviewcluster2; + +extern cvar_t *r_lefthand; +extern cvar_t *r_drawworld; +extern cvar_t *r_novis; +extern cvar_t *r_lerpmodels; +extern cvar_t *r_lockpvs; +extern cvar_t *r_modulate; +extern cvar_t *r_vsync; +extern cvar_t *r_clear; +extern cvar_t *r_lightlevel; // FIXME: This is a HACK to get the client's light level +extern cvar_t *r_gunfov; +extern cvar_t *r_farsee; + +extern cvar_t *vk_overbrightbits; +extern cvar_t *vk_validation; +extern cvar_t *vk_picmip; +extern cvar_t *vk_skymip; +extern cvar_t *vk_flashblend; +extern cvar_t *vk_finish; +extern cvar_t *vk_shadows; +extern cvar_t *vk_dynamic; +extern cvar_t *vk_msaa; +extern cvar_t *vk_showtris; +extern cvar_t *vk_lightmap; +extern cvar_t *vk_texturemode; +extern cvar_t *vk_lmaptexturemode; +extern cvar_t *vk_aniso; +extern cvar_t *vk_sampleshading; +extern cvar_t *vk_device_idx; +extern cvar_t *vk_retexturing; +extern cvar_t *vk_nolerp_list; +extern cvar_t *vk_pixel_size; +extern cvar_t *r_fixsurfsky; + +extern cvar_t *vid_fullscreen; +extern cvar_t *vid_gamma; + +extern int c_visible_lightmaps; +extern int c_visible_textures; + +extern float r_viewproj_matrix[16]; + +void R_LightPoint (vec3_t p, vec3_t color, entity_t *currententity); +void R_PushDlights (void); + +//==================================================================== + +extern model_t *r_worldmodel; + +extern unsigned d_8to24table[256]; + +extern int registration_sequence; +extern qvksampler_t vk_current_sampler; +extern qvksampler_t vk_current_lmap_sampler; + +void RE_Shutdown( void ); + +void Vk_ScreenShot_f (void); +void R_DrawAliasModel (entity_t *currententity, model_t *currentmodel); +void R_DrawBrushModel (entity_t *currententity, model_t *currentmodel); +void R_DrawSpriteModel (entity_t *currententity, model_t *currentmodel); +void R_DrawBeam (entity_t *currententity); +void R_DrawWorld (void); +void R_RenderDlights (void); +void R_DrawAlphaSurfaces (void); +void RE_InitParticleTexture (void); +void Draw_InitLocal (void); +void Vk_SubdivideSurface (msurface_t *fa, model_t *loadmodel); +qboolean R_CullBox (vec3_t mins, vec3_t maxs); +void R_RotateForEntity (entity_t *e, float *mvMatrix); +void R_MarkLeaves (void); + +void EmitWaterPolys (msurface_t *fa, image_t *texture, + float *modelMatrix, float *color, + qboolean solid_surface); +void R_AddSkySurface (msurface_t *fa); +void R_ClearSkyBox (void); +void R_DrawSkyBox (void); +void R_MarkLights (dlight_t *light, int bit, mnode_t *node); + +struct image_s *RE_Draw_FindPic (char *name); + +void RE_Draw_GetPicSize (int *w, int *h, char *name); +void RE_Draw_PicScaled (int x, int y, char *name, float scale); +void RE_Draw_StretchPic (int x, int y, int w, int h, char *name); +void RE_Draw_CharScaled (int x, int y, int num, float scale); +void RE_Draw_TileClear (int x, int y, int w, int h, char *name); +void RE_Draw_Fill (int x, int y, int w, int h, int c); +void RE_Draw_FadeScreen (void); +void RE_Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data); + +qboolean RE_EndWorldRenderpass( void ); + +struct image_s *RE_RegisterSkin (char *name); + +void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height); +image_t *Vk_LoadPic(char *name, byte *pic, int width, int realwidth, + int height, int realheight, imagetype_t type, + int bits); +image_t *Vk_FindImage (char *name, imagetype_t type); +void Vk_TextureMode( char *string ); +void Vk_LmapTextureMode( char *string ); +void Vk_ImageList_f (void); + +void Vk_BuildPolygonFromSurface(msurface_t *fa, model_t *currentmodel); +void Vk_CreateSurfaceLightmap (msurface_t *surf); +void Vk_EndBuildingLightmaps (void); +void Vk_BeginBuildingLightmaps (model_t *m); + +void Vk_InitImages (void); +void Vk_ShutdownImages (void); +void Vk_FreeUnusedImages (void); +qboolean Vk_ImageHasFreeSpace(void); + +void RE_BeginRegistration (char *model); +struct model_s *RE_RegisterModel (char *name); +struct image_s *RE_RegisterSkin (char *name); +void RE_SetSky (char *name, float rotate, vec3_t axis); +void RE_EndRegistration (void); + +void Mat_Identity(float *matrix); +void Mat_Mul(float *m1, float *m2, float *res); +void Mat_Translate(float *matrix, float x, float y, float z); +void Mat_Rotate(float *matrix, float deg, float x, float y, float z); +void Mat_Scale(float *matrix, float x, float y, float z); +void Mat_Perspective(float *matrix, float *correction_matrix, float fovy, float aspect, float zNear, float zFar); +void Mat_Ortho(float *matrix, float left, float right, float bottom, float top, float zNear, float zFar); + +typedef struct +{ + uint32_t vk_version; + const char *vendor_name; + const char *device_type; + const char *present_mode; + const char *supported_present_modes[256]; + const char *extensions[256]; + const char *layers[256]; + uint32_t vertex_buffer_usage; + uint32_t vertex_buffer_max_usage; + uint32_t vertex_buffer_size; + uint32_t index_buffer_usage; + uint32_t index_buffer_max_usage; + uint32_t index_buffer_size; + uint32_t uniform_buffer_usage; + uint32_t uniform_buffer_max_usage; + uint32_t uniform_buffer_size; + uint32_t triangle_index_usage; + uint32_t triangle_index_max_usage; + uint32_t triangle_index_count; +} vkconfig_t; + +#define MAX_LIGHTMAPS 128 +#define DYNLIGHTMAP_OFFSET MAX_LIGHTMAPS + +typedef struct +{ + float inverse_intensity; + qboolean fullscreen; + + int prev_mode; + + unsigned char *d_16to8table; + + qvktexture_t lightmap_textures[MAX_LIGHTMAPS*2]; + + int currenttextures[2]; + int currenttmu; + + float camera_separation; + qboolean stereo_enabled; + + VkPipeline current_pipeline; + qvkrenderpasstype_t current_renderpass; +} vkstate_t; + +extern vkconfig_t vk_config; +extern vkstate_t vk_state; + +/* +==================================================================== + +IMPORTED FUNCTIONS + +==================================================================== +*/ + +extern refimport_t ri; + + +/* +==================================================================== + +IMPLEMENTATION SPECIFIC FUNCTIONS + +==================================================================== +*/ + +qboolean Vkimp_CreateSurface(SDL_Window *window); + +// buffers reallocate +typedef struct { + float vertex[3]; + float texCoord[2]; +} polyvert_t; + +typedef struct { + float vertex[3]; + float texCoord[2]; + float texCoordLmap[2]; +} lmappolyvert_t; + +extern polyvert_t *verts_buffer; +extern lmappolyvert_t *lmappolyverts_buffer; + +void Mesh_Init (void); +void Mesh_Free (void); +int Mesh_VertsRealloc(int count); + +#endif diff --git a/src/vk/header/model.h b/src/vk/header/model.h new file mode 100644 index 0000000..4821f6c --- /dev/null +++ b/src/vk/header/model.h @@ -0,0 +1,254 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. +Copyright (C) 2018-2019 Krzysztof Kondrak + +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. + +*/ + +#ifndef __VK_MODEL_H__ +#define __VK_MODEL_H__ + +/* + +d*_t structures are on-disk representations +m*_t structures are in-memory + +*/ + +/* +============================================================================== + +BRUSH MODELS + +============================================================================== +*/ + + +// +// in memory representation +// +typedef struct +{ + vec3_t position; +} mvertex_t; + + +#define SIDE_FRONT 0 +#define SIDE_BACK 1 +#define SIDE_ON 2 + + +#define SURF_PLANEBACK 2 +#define SURF_DRAWSKY 4 +#define SURF_DRAWTURB 0x10 +#define SURF_DRAWBACKGROUND 0x40 +#define SURF_UNDERWATER 0x80 + +typedef struct +{ + unsigned short v[2]; + unsigned int cachededgeoffset; +} medge_t; + +typedef struct mtexinfo_s +{ + float vecs[2][4]; + int flags; + int numframes; + struct mtexinfo_s *next; // animation chain + image_t *image; +} mtexinfo_t; + +#define VERTEXSIZE 7 + +typedef struct vkpoly_s +{ + struct vkpoly_s *next; + struct vkpoly_s *chain; + int numverts; + int flags; // for SURF_UNDERWATER (not needed anymore?) + float verts[4][VERTEXSIZE]; // variable sized (xyz s1t1 s2t2) +} vkpoly_t; + +typedef struct msurface_s +{ + int visframe; // should be drawn when node is crossed + + cplane_t *plane; + int flags; + + 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 + int dlight_s, dlight_t; // gl lightmap coordinates for dynamic lightmaps + + vkpoly_t *polys; // multiple if warped + struct msurface_s *texturechain; + struct msurface_s *lightmapchain; + + mtexinfo_t *texinfo; + +// lighting info + int dlightframe; + int dlightbits; + + int lightmaptexturenum; + byte styles[MAXLIGHTMAPS]; + float cached_light[MAXLIGHTMAPS]; // values currently used in lightmap + byte *samples; // [numstyles*surfsize] +} msurface_t; + +typedef struct mnode_s +{ +// common with leaf + int contents; // -1, 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 + cplane_t *plane; + struct mnode_s *children[2]; + + unsigned short firstsurface; + unsigned short numsurfaces; +} mnode_t; + + + +typedef struct mleaf_s +{ +// common with node + int contents; // wil be a negative contents number + int visframe; // node needs to be traversed if current + + float minmaxs[6]; // for bounding box culling + + struct mnode_s *parent; + +// leaf specific + int cluster; + int area; + + msurface_t **firstmarksurface; + int nummarksurfaces; +} mleaf_t; + + +//=================================================================== + +// +// Whole model +// + +typedef struct model_s +{ + char name[MAX_QPATH]; + + int registration_sequence; + + modtype_t type; + int numframes; + + int flags; + +// +// volume occupied by the model graphics +// + vec3_t mins, maxs; + float radius; + +// +// solid volume for clipping +// + qboolean clipbox; + vec3_t clipmins, clipmaxs; + +// +// brush model +// + int firstmodelsurface, nummodelsurfaces; + int lightmap; // only for submodels + + int numsubmodels; + struct model_s *submodels; + + int numplanes; + cplane_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; + int firstnode; + mnode_t *nodes; + + int numtexinfo; + mtexinfo_t *texinfo; + + int numsurfaces; + msurface_t *surfaces; + + int numsurfedges; + int *surfedges; + + int nummarksurfaces; + msurface_t **marksurfaces; + + dvis_t *vis; + + byte *lightdata; + + // for alias models and skins + image_t *skins[MAX_MD2SKINS]; + + int extradatasize; + void *extradata; + + // submodules + vec3_t origin; // for sounds or lights +} model_t; + +//============================================================================ + +void Mod_Init (void); +mleaf_t *Mod_PointInLeaf (float *p, model_t *model); +byte *Mod_ClusterPVS (int cluster, model_t *model); + +void Mod_Modellist_f (void); + +void *Hunk_Begin (int maxsize); +void *Hunk_Alloc (int size); +int Hunk_End (void); +void Hunk_Free (void *base); + +void Mod_FreeAll (void); +void Mod_FreeModelsKnown (void); + +#endif diff --git a/src/vk/header/qvk.h b/src/vk/header/qvk.h new file mode 100644 index 0000000..fb58d28 --- /dev/null +++ b/src/vk/header/qvk.h @@ -0,0 +1,326 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. +Copyright (C) 2018-2019 Krzysztof Kondrak + +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. + +*/ +/* +** QVK.H +*/ + +#ifndef __QVK_H__ +#define __QVK_H__ + +#ifdef _WIN32 +# include +#endif + +#include "local.h" +#include "util.h" +#include "shaders.h" + +// Vulkan device +typedef struct +{ + VkPhysicalDevice physical; + VkDevice logical; + VkPhysicalDeviceMemoryProperties mem_properties; + VkPhysicalDeviceProperties properties; + VkPhysicalDeviceFeatures features; + VkQueue gfxQueue; + VkQueue presentQueue; + VkQueue transferQueue; + int gfxFamilyIndex; + int presentFamilyIndex; + int transferFamilyIndex; + qboolean screenshotSupported; +} qvkdevice_t; + +// Vulkan swapchain +typedef struct +{ + VkSwapchainKHR sc; + VkFormat format; + VkPresentModeKHR presentMode; + VkExtent2D extent; + VkImage *images; + int imageCount; +} qvkswapchain_t; + +// available sampler types +typedef enum +{ + S_NEAREST = 0, + S_LINEAR = 1, + S_MIPMAP_NEAREST = 2, + S_MIPMAP_LINEAR = 3, + S_NEAREST_UNNORMALIZED = 4, + S_SAMPLER_CNT = 5 +} qvksampler_t; + +#define NUM_SAMPLERS (S_SAMPLER_CNT * 2) + +// texture object +typedef struct +{ + ImageResource_t resource; + + VkImageView imageView; + VkSharingMode sharingMode; + VkSampleCountFlagBits sampleCount; + VkFormat format; + VkDescriptorSet descriptorSet; + uint32_t mipLevels; + qboolean clampToEdge; +} qvktexture_t; + +#define QVVKTEXTURE_INIT { \ + .resource = { \ + .image = VK_NULL_HANDLE, \ + .memory = VK_NULL_HANDLE, \ + .size = 0, \ + }, \ + .imageView = VK_NULL_HANDLE, \ + .sharingMode = VK_SHARING_MODE_MAX_ENUM, \ + .sampleCount = VK_SAMPLE_COUNT_1_BIT, \ + .format = VK_FORMAT_R8G8B8A8_UNORM, \ + .descriptorSet = VK_NULL_HANDLE, \ + .mipLevels = 1, \ +} + +#define QVVKTEXTURE_CLEAR(i) { \ + (i).resource.image = VK_NULL_HANDLE; \ + (i).resource.memory = VK_NULL_HANDLE; \ + (i).resource.size = 0; \ + (i).imageView = VK_NULL_HANDLE; \ + (i).sharingMode = VK_SHARING_MODE_MAX_ENUM; \ + (i).sampleCount = VK_SAMPLE_COUNT_1_BIT; \ + (i).format = VK_FORMAT_R8G8B8A8_UNORM; \ + (i).mipLevels = 1; \ +} + +// Vulkan renderpass +typedef struct +{ + VkRenderPass rp; + VkAttachmentLoadOp colorLoadOp; + VkSampleCountFlagBits sampleCount; +} qvkrenderpass_t; + +// Vulkan buffer +typedef struct +{ + VkDeviceSize currentOffset; + + BufferResource_t resource; + void *pMappedData; +} qvkbuffer_t; + +// Vulkan staging buffer +typedef struct +{ + VkDeviceSize currentOffset; + VkCommandBuffer cmdBuffer; + VkFence fence; + qboolean submitted; + + BufferResource_t resource; + void *pMappedData; +} qvkstagingbuffer_t; + +// Vulkan buffer options +typedef struct +{ + VkBufferUsageFlags usage; + VkMemoryPropertyFlags reqMemFlags; + VkMemoryPropertyFlags prefMemFlags; +} qvkbufferopts_t; + +// Vulkan pipeline +typedef struct +{ + VkPipelineLayout layout; + VkPipeline pl; + VkPipelineCreateFlags flags; + VkCullModeFlags cullMode; + VkPrimitiveTopology topology; + VkPipelineColorBlendAttachmentState blendOpts; + VkBool32 depthTestEnable; + VkBool32 depthWriteEnable; +} qvkpipeline_t; + +// Vulkan shader +typedef struct +{ + VkPipelineShaderStageCreateInfo createInfo; + VkShaderModule module; +} qvkshader_t; + +#define QVKPIPELINE_INIT { \ + .layout = VK_NULL_HANDLE, \ + .pl = VK_NULL_HANDLE, \ + .flags = 0, \ + .cullMode = VK_CULL_MODE_BACK_BIT, \ + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, \ + .blendOpts = { \ + .blendEnable = VK_FALSE, \ + .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA, \ + .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, \ + .colorBlendOp = VK_BLEND_OP_ADD, \ + .srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA, \ + .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, \ + .alphaBlendOp = VK_BLEND_OP_ADD, \ + .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT \ + }, \ + .depthTestEnable = VK_TRUE, \ + .depthWriteEnable = VK_TRUE \ +} + +// renderpass type +typedef enum +{ + RP_WORLD = 0, // renders game world to offscreen buffer + RP_UI = 1, // render UI elements and game console + RP_WORLD_WARP = 2, // perform postprocessing on RP_WORLD (underwater screen warp) + RP_COUNT = 3 +} qvkrenderpasstype_t; + +// Vulkan constants: command and dynamic buffer count +#define NUM_CMDBUFFERS 2 +#define NUM_DYNBUFFERS 2 + +// Vulkan instance +extern VkInstance vk_instance; +// Vulkan surface +extern VkSurfaceKHR vk_surface; +// Vulkan device +extern qvkdevice_t vk_device; +// Vulkan swapchain +extern qvkswapchain_t vk_swapchain; +// Vulkan command buffer currently in use +extern VkCommandBuffer vk_activeCmdbuffer; +// Vulkan command pools +extern VkCommandPool vk_commandPool[NUM_CMDBUFFERS]; +extern VkCommandPool vk_transferCommandPool; +// Vulkan descriptor pool +extern VkDescriptorPool vk_descriptorPool; +// viewport/scissor +extern VkViewport vk_viewport; +extern VkRect2D vk_scissor; + +// Vulkan descriptor sets +extern VkDescriptorSetLayout vk_samplerDescSetLayout; + +// *** pipelines *** +extern qvkpipeline_t vk_drawTexQuadPipeline[RP_COUNT]; +extern qvkpipeline_t vk_drawColorQuadPipeline[RP_COUNT]; +extern qvkpipeline_t vk_drawModelPipelineFan[RP_COUNT]; +extern qvkpipeline_t vk_drawNoDepthModelPipelineFan; +extern qvkpipeline_t vk_drawLefthandModelPipelineFan; +extern qvkpipeline_t vk_drawNullModelPipeline; +extern qvkpipeline_t vk_drawParticlesPipeline; +extern qvkpipeline_t vk_drawPointParticlesPipeline; +extern qvkpipeline_t vk_drawSpritePipeline; +extern qvkpipeline_t vk_drawPolyPipeline; +extern qvkpipeline_t vk_drawPolyLmapPipeline; +extern qvkpipeline_t vk_drawPolyWarpPipeline; +extern qvkpipeline_t vk_drawPolySolidWarpPipeline; +extern qvkpipeline_t vk_drawBeamPipeline; +extern qvkpipeline_t vk_drawSkyboxPipeline; +extern qvkpipeline_t vk_drawDLightPipeline; +extern qvkpipeline_t vk_showTrisPipeline; +extern qvkpipeline_t vk_shadowsPipelineFan; +extern qvkpipeline_t vk_worldWarpPipeline; +extern qvkpipeline_t vk_postprocessPipeline; + +// color buffer containing main game/world view +extern qvktexture_t vk_colorbuffer; +// color buffer with postprocessed game view +extern qvktexture_t vk_colorbufferWarp; +// indicator if the frame is currently being rendered +extern qboolean vk_frameStarted; +// Indicates if the renderer needs to be restarted. +extern qboolean vk_restartNeeded; +// is QVk initialized? +extern qboolean vk_initialized; + +// function pointers +extern PFN_vkCreateDebugUtilsMessengerEXT qvkCreateDebugUtilsMessengerEXT; +extern PFN_vkDestroyDebugUtilsMessengerEXT qvkDestroyDebugUtilsMessengerEXT; +extern PFN_vkSetDebugUtilsObjectNameEXT qvkSetDebugUtilsObjectNameEXT; +extern PFN_vkSetDebugUtilsObjectTagEXT qvkSetDebugUtilsObjectTagEXT; +extern PFN_vkCmdBeginDebugUtilsLabelEXT qvkCmdBeginDebugUtilsLabelEXT; +extern PFN_vkCmdEndDebugUtilsLabelEXT qvkCmdEndDebugUtilsLabelEXT; +extern PFN_vkCmdInsertDebugUtilsLabelEXT qvkInsertDebugUtilsLabelEXT; + +// The Interface Functions (tm) +void QVk_SetWindow(SDL_Window*); +qboolean QVk_Init(void); +void QVk_PostInit(void); +void QVk_WaitAndShutdownAll(void); +void QVk_Shutdown(void); +void QVk_Restart(void); +void QVk_CreateValidationLayers(void); +void QVk_DestroyValidationLayers(void); +qboolean QVk_CreateDevice(int preferredDeviceIdx); +VkResult QVk_CreateSwapchain(void); +VkFormat QVk_FindDepthFormat(void); +VkResult QVk_CreateCommandPool(VkCommandPool *commandPool, uint32_t queueFamilyIndex); +VkResult QVk_CreateImageView(const VkImage *image, VkImageAspectFlags aspectFlags, VkImageView *imageView, VkFormat format, uint32_t mipLevels); +VkResult QVk_CreateImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, qvktexture_t *texture); +void QVk_CreateDepthBuffer(VkSampleCountFlagBits sampleCount, qvktexture_t *depthBuffer); +void QVk_CreateColorBuffer(VkSampleCountFlagBits sampleCount, qvktexture_t *colorBuffer, int extraFlags); +void QVk_CreateTexture(qvktexture_t *texture, const unsigned char *data, uint32_t width, uint32_t height, qvksampler_t samplerType, qboolean clampToEdge); +void QVk_UpdateTextureData(qvktexture_t *texture, const unsigned char *data, uint32_t offset_x, uint32_t offset_y, uint32_t width, uint32_t height); +VkSampler QVk_UpdateTextureSampler(qvktexture_t *texture, qvksampler_t samplerType, qboolean clampToEdge); +void QVk_ReadPixels(uint8_t *dstBuffer, const VkOffset2D *offset, const VkExtent2D *extent); +VkResult QVk_BeginCommand(const VkCommandBuffer *commandBuffer); +void QVk_SubmitCommand(const VkCommandBuffer *commandBuffer, const VkQueue *queue); +VkCommandBuffer QVk_CreateCommandBuffer(const VkCommandPool *commandPool, VkCommandBufferLevel level); +const char* QVk_GetError(VkResult errorCode); +VkResult QVk_BeginFrame(const VkViewport* viewport, const VkRect2D* scissor); +VkResult QVk_EndFrame(qboolean force); +void QVk_BeginRenderpass(qvkrenderpasstype_t rpType); +void QVk_FreeStagingBuffer(qvkstagingbuffer_t *buffer); +VkResult QVk_CreateBuffer(VkDeviceSize size, qvkbuffer_t *dstBuffer, const qvkbufferopts_t options); +void QVk_FreeBuffer(qvkbuffer_t *buffer); +VkResult QVk_CreateStagingBuffer(VkDeviceSize size, qvkstagingbuffer_t *dstBuffer, VkMemoryPropertyFlags reqMemFlags, VkMemoryPropertyFlags prefMemFlags); +VkResult QVk_CreateUniformBuffer(VkDeviceSize size, qvkbuffer_t *dstBuffer, VkMemoryPropertyFlags reqMemFlags, VkMemoryPropertyFlags prefMemFlags); +void QVk_CreateVertexBuffer(const void *data, VkDeviceSize size, qvkbuffer_t *dstBuffer, VkMemoryPropertyFlags reqMemFlags, VkMemoryPropertyFlags prefMemFlags); +void QVk_CreateIndexBuffer(const void *data, VkDeviceSize size, qvkbuffer_t *dstBuffer, VkMemoryPropertyFlags reqMemFlags, VkMemoryPropertyFlags prefMemFlags); +qvkshader_t QVk_CreateShader(const uint32_t *shaderSrc, size_t shaderCodeSize, VkShaderStageFlagBits shaderStage); +void QVk_CreatePipeline(const VkDescriptorSetLayout *descriptorLayout, const uint32_t descLayoutCount, const VkPipelineVertexInputStateCreateInfo *vertexInputInfo, qvkpipeline_t *pipeline, const qvkrenderpass_t *renderpass, const qvkshader_t *shaders, uint32_t shaderCount); +void QVk_DestroyPipeline(qvkpipeline_t *pipeline); +uint8_t* QVk_GetVertexBuffer(VkDeviceSize size, VkBuffer *dstBuffer, VkDeviceSize *dstOffset); +uint8_t* QVk_GetUniformBuffer(VkDeviceSize size, uint32_t *dstOffset, VkDescriptorSet *dstUboDescriptorSet); +uint8_t* QVk_GetStagingBuffer(VkDeviceSize size, int alignment, VkCommandBuffer *cmdBuffer, VkBuffer *buffer, uint32_t *dstOffset); +VkBuffer QVk_GetTriangleFanIbo(VkDeviceSize indexCount); +VkBuffer QVk_GetTriangleStripIbo(VkDeviceSize indexCount); +void QVk_DrawColorRect(float *ubo, VkDeviceSize uboSize, qvkrenderpasstype_t rpType); +void QVk_DrawTexRect(const float *ubo, VkDeviceSize uboSize, qvktexture_t *texture); +void QVk_BindPipeline(qvkpipeline_t *pipeline); +void QVk_SubmitStagingBuffers(void); +void Qvk_MemoryBarrier(VkCommandBuffer cmdBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); +qboolean QVk_CheckExtent(void); + +// debug label related functions +void QVk_DebugSetObjectName(uint64_t obj, VkObjectType objType, const char *objName); +void QVk_DebugSetObjectTag(uint64_t obj, VkObjectType objType, uint64_t tagName, size_t tagSize, const void *tagData); +void QVk_DebugLabelBegin(const VkCommandBuffer *cmdBuffer, const char *labelName, const float r, const float g, const float b); +void QVk_DebugLabelEnd(const VkCommandBuffer *cmdBuffer); +void QVk_DebugLabelInsert(const VkCommandBuffer *cmdBuffer, const char *labelName, const float r, const float g, const float b); +#endif diff --git a/src/vk/header/shaders.h b/src/vk/header/shaders.h new file mode 100644 index 0000000..64f6e67 --- /dev/null +++ b/src/vk/header/shaders.h @@ -0,0 +1,115 @@ +/* +Copyright (C) 2018-2019 Krzysztof Kondrak + +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. + +*/ + +// +// game shaders, compiled offline +// + +#ifndef __VK_SHADERS_H__ +#define __VK_SHADERS_H__ +#include +#include + +// textured quad (alpha) +extern const uint32_t basic_vert_spv[]; +extern const size_t basic_vert_size; + +extern const uint32_t basic_frag_spv[]; +extern const size_t basic_frag_size; + +// colored quad (alpha) +extern const uint32_t basic_color_quad_vert_spv[]; +extern const size_t basic_color_quad_vert_size; + +extern const uint32_t basic_color_quad_frag_spv[]; +extern const size_t basic_color_quad_frag_size; + +// textured model +extern const uint32_t model_vert_spv[]; +extern const size_t model_vert_size; + +extern const uint32_t model_frag_spv[]; +extern const size_t model_frag_size; + +// null model +extern const uint32_t nullmodel_vert_spv[]; +extern const size_t nullmodel_vert_size; + +// particle (texture) +extern const uint32_t particle_vert_spv[]; +extern const size_t particle_vert_size; + +// particle (point) +extern const uint32_t point_particle_vert_spv[]; +extern const size_t point_particle_vert_size; + +extern const uint32_t point_particle_frag_spv[]; +extern const size_t point_particle_frag_size; + +// sprite model +extern const uint32_t sprite_vert_spv[]; +extern const size_t sprite_vert_size; + +// beam +extern const uint32_t beam_vert_spv[]; +extern const size_t beam_vert_size; + +// skybox +extern const uint32_t skybox_vert_spv[]; +extern const size_t skybox_vert_size; + +// dynamic lights +extern const uint32_t d_light_vert_spv[]; +extern const size_t d_light_vert_size; + +// textured, alpha blended polygon +extern const uint32_t polygon_vert_spv[]; +extern const size_t polygon_vert_size; + +// textured, lightmapped polygon +extern const uint32_t polygon_lmap_vert_spv[]; +extern const size_t polygon_lmap_vert_size; + +extern const uint32_t polygon_lmap_frag_spv[]; +extern const size_t polygon_lmap_frag_size; + +// warped polygon (liquids) +extern const uint32_t polygon_warp_vert_spv[]; +extern const size_t polygon_warp_vert_size; + +// entity shadows +extern const uint32_t shadows_vert_spv[]; +extern const size_t shadows_vert_size; + +// postprocess +extern const uint32_t postprocess_vert_spv[]; +extern const size_t postprocess_vert_size; + +extern const uint32_t postprocess_frag_spv[]; +extern const size_t postprocess_frag_size; + +// underwater vision warp +extern const uint32_t world_warp_vert_spv[]; +extern const size_t world_warp_vert_size; + +extern const uint32_t world_warp_frag_spv[]; +extern const size_t world_warp_frag_size; + +#endif diff --git a/src/vk/header/util.h b/src/vk/header/util.h new file mode 100644 index 0000000..92ffc1a --- /dev/null +++ b/src/vk/header/util.h @@ -0,0 +1,71 @@ +/* +Copyright (C) 2018 Christoph Schied +Copyright (C) 2020 Denis Pauk + +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. +*/ + +#ifndef __VK_UTIL_H__ +#define __VK_UTIL_H__ + +#include "../volk/volk.h" + +#define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1)) + +typedef struct BufferResource_s { + VkBuffer buffer; + // shared memory used for buffer + VkDeviceMemory memory; + // image size + VkDeviceSize size; + // posision in shared memory + VkDeviceSize offset; + // is mapped? + VkBool32 is_mapped; +} BufferResource_t; + +typedef struct ImageResource_s { + VkImage image; + // shared memory used for image + VkDeviceMemory memory; + // image size + VkDeviceSize size; + // posision in shared memory + VkDeviceSize offset; +} ImageResource_t; + +VkResult buffer_create(BufferResource_t *buf, + VkBufferCreateInfo buf_create_info, + VkMemoryPropertyFlags mem_properties, + VkMemoryPropertyFlags mem_preferences); + +VkResult buffer_destroy(BufferResource_t *buf); +void buffer_unmap(BufferResource_t *buf); +void *buffer_map(BufferResource_t *buf); +VkResult buffer_flush(BufferResource_t *buf); +VkResult buffer_invalidate(BufferResource_t *buf); + +VkResult image_create(ImageResource_t *img, + VkImageCreateInfo img_create_info, + VkMemoryPropertyFlags mem_properties, + VkMemoryPropertyFlags mem_preferences); +VkResult image_destroy(ImageResource_t *img); + +void vulkan_memory_init(void); +void vulkan_memory_types_show(void); +void vulkan_memory_free_unused(void); +void vulkan_memory_delete(void); + +#endif /*__VK_UTIL_H__*/ diff --git a/src/vk/spirv/basic_color_quad_frag.c b/src/vk/spirv/basic_color_quad_frag.c new file mode 100644 index 0000000..4fb19bf --- /dev/null +++ b/src/vk/spirv/basic_color_quad_frag.c @@ -0,0 +1,16 @@ + // 8.13.3559 + #pragma once +const uint32_t basic_color_quad_frag_spv[] = { + 0x07230203,0x00010000,0x00080008,0x0000000d,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000009,0x0000000b,0x00030010, + 0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d, + 0x00000000,0x00060005,0x00000009,0x67617266,0x746e656d,0x6f6c6f43,0x00000072,0x00040005, + 0x0000000b,0x6f6c6f63,0x00000072,0x00040047,0x00000009,0x0000001e,0x00000000,0x00040047, + 0x0000000b,0x0000001e,0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002, + 0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040020, + 0x00000008,0x00000003,0x00000007,0x0004003b,0x00000008,0x00000009,0x00000003,0x00040020, + 0x0000000a,0x00000001,0x00000007,0x0004003b,0x0000000a,0x0000000b,0x00000001,0x00050036, + 0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003d,0x00000007, + 0x0000000c,0x0000000b,0x0003003e,0x00000009,0x0000000c,0x000100fd,0x00010038 +}; \ No newline at end of file diff --git a/src/vk/spirv/basic_color_quad_vert.c b/src/vk/spirv/basic_color_quad_vert.c new file mode 100644 index 0000000..c884bef --- /dev/null +++ b/src/vk/spirv/basic_color_quad_vert.c @@ -0,0 +1,48 @@ + // 8.13.3559 + #pragma once +const uint32_t basic_color_quad_vert_spv[] = { + 0x07230203,0x00010000,0x00080008,0x00000032,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0008000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000b,0x0000001f,0x0000002d, + 0x00030003,0x00000002,0x000001c2,0x00090004,0x415f4c47,0x735f4252,0x72617065,0x5f657461, + 0x64616873,0x6f5f7265,0x63656a62,0x00007374,0x00040005,0x00000004,0x6e69616d,0x00000000, + 0x00040005,0x00000009,0x736f5076,0x00000000,0x00050005,0x0000000b,0x65566e69,0x78657472, + 0x00000000,0x00060005,0x0000000e,0x67616d69,0x61725465,0x6f66736e,0x00006d72,0x00050006, + 0x0000000e,0x00000000,0x7366666f,0x00007465,0x00050006,0x0000000e,0x00000001,0x6c616373, + 0x00000065,0x00050006,0x0000000e,0x00000002,0x6f6c6f63,0x00000072,0x00030005,0x00000010, + 0x00007469,0x00060005,0x0000001d,0x505f6c67,0x65567265,0x78657472,0x00000000,0x00060006, + 0x0000001d,0x00000000,0x505f6c67,0x7469736f,0x006e6f69,0x00030005,0x0000001f,0x00000000, + 0x00040005,0x0000002d,0x6f6c6f63,0x00000072,0x00040047,0x0000000b,0x0000001e,0x00000000, + 0x00050048,0x0000000e,0x00000000,0x00000023,0x00000000,0x00050048,0x0000000e,0x00000001, + 0x00000023,0x00000008,0x00050048,0x0000000e,0x00000002,0x00000023,0x00000010,0x00030047, + 0x0000000e,0x00000002,0x00040047,0x00000010,0x00000022,0x00000000,0x00040047,0x00000010, + 0x00000021,0x00000000,0x00050048,0x0000001d,0x00000000,0x0000000b,0x00000000,0x00030047, + 0x0000001d,0x00000002,0x00040047,0x0000002d,0x0000001e,0x00000000,0x00020013,0x00000002, + 0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,0x00000020,0x00040017,0x00000007, + 0x00000006,0x00000002,0x00040020,0x00000008,0x00000007,0x00000007,0x00040020,0x0000000a, + 0x00000001,0x00000007,0x0004003b,0x0000000a,0x0000000b,0x00000001,0x00040017,0x0000000d, + 0x00000006,0x00000004,0x0005001e,0x0000000e,0x00000007,0x00000007,0x0000000d,0x00040020, + 0x0000000f,0x00000002,0x0000000e,0x0004003b,0x0000000f,0x00000010,0x00000002,0x00040015, + 0x00000011,0x00000020,0x00000001,0x0004002b,0x00000011,0x00000012,0x00000001,0x00040020, + 0x00000013,0x00000002,0x00000007,0x0004002b,0x00000006,0x00000017,0x3f800000,0x0005002c, + 0x00000007,0x00000018,0x00000017,0x00000017,0x0003001e,0x0000001d,0x0000000d,0x00040020, + 0x0000001e,0x00000003,0x0000001d,0x0004003b,0x0000001e,0x0000001f,0x00000003,0x0004002b, + 0x00000011,0x00000020,0x00000000,0x0004002b,0x00000006,0x00000024,0x40000000,0x0004002b, + 0x00000006,0x00000027,0x00000000,0x00040020,0x0000002b,0x00000003,0x0000000d,0x0004003b, + 0x0000002b,0x0000002d,0x00000003,0x0004002b,0x00000011,0x0000002e,0x00000002,0x00040020, + 0x0000002f,0x00000002,0x0000000d,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003, + 0x000200f8,0x00000005,0x0004003b,0x00000008,0x00000009,0x00000007,0x0004003d,0x00000007, + 0x0000000c,0x0000000b,0x00050041,0x00000013,0x00000014,0x00000010,0x00000012,0x0004003d, + 0x00000007,0x00000015,0x00000014,0x00050085,0x00000007,0x00000016,0x0000000c,0x00000015, + 0x00050041,0x00000013,0x00000019,0x00000010,0x00000012,0x0004003d,0x00000007,0x0000001a, + 0x00000019,0x00050083,0x00000007,0x0000001b,0x00000018,0x0000001a,0x00050083,0x00000007, + 0x0000001c,0x00000016,0x0000001b,0x0003003e,0x00000009,0x0000001c,0x0004003d,0x00000007, + 0x00000021,0x00000009,0x00050041,0x00000013,0x00000022,0x00000010,0x00000020,0x0004003d, + 0x00000007,0x00000023,0x00000022,0x0005008e,0x00000007,0x00000025,0x00000023,0x00000024, + 0x00050081,0x00000007,0x00000026,0x00000021,0x00000025,0x00050051,0x00000006,0x00000028, + 0x00000026,0x00000000,0x00050051,0x00000006,0x00000029,0x00000026,0x00000001,0x00070050, + 0x0000000d,0x0000002a,0x00000028,0x00000029,0x00000027,0x00000017,0x00050041,0x0000002b, + 0x0000002c,0x0000001f,0x00000020,0x0003003e,0x0000002c,0x0000002a,0x00050041,0x0000002f, + 0x00000030,0x00000010,0x0000002e,0x0004003d,0x0000000d,0x00000031,0x00000030,0x0003003e, + 0x0000002d,0x00000031,0x000100fd,0x00010038 +}; \ No newline at end of file diff --git a/src/vk/spirv/basic_frag.c b/src/vk/spirv/basic_frag.c new file mode 100644 index 0000000..9885101 --- /dev/null +++ b/src/vk/spirv/basic_frag.c @@ -0,0 +1,48 @@ + // 8.13.3559 + #pragma once +const uint32_t basic_frag_spv[] = { + 0x07230203,0x00010000,0x00080008,0x00000038,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0009000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000009,0x00000011,0x00000015, + 0x0000001e,0x00030010,0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005, + 0x00000004,0x6e69616d,0x00000000,0x00060005,0x00000009,0x67617266,0x746e656d,0x6f6c6f43, + 0x00000072,0x00050005,0x0000000d,0x78655473,0x65727574,0x00000000,0x00050005,0x00000011, + 0x43786574,0x64726f6f,0x00000000,0x00040005,0x00000015,0x6f6c6f63,0x00000072,0x00050005, + 0x0000001e,0x65725461,0x6c6f6873,0x00000064,0x00060005,0x00000028,0x68737550,0x736e6f43, + 0x746e6174,0x00000000,0x00050006,0x00000028,0x00000000,0x6d6d6167,0x00000061,0x00030005, + 0x0000002a,0x00006370,0x00040047,0x00000009,0x0000001e,0x00000000,0x00040047,0x0000000d, + 0x00000022,0x00000000,0x00040047,0x0000000d,0x00000021,0x00000000,0x00040047,0x00000011, + 0x0000001e,0x00000000,0x00040047,0x00000015,0x0000001e,0x00000001,0x00040047,0x0000001e, + 0x0000001e,0x00000002,0x00050048,0x00000028,0x00000000,0x00000023,0x00000044,0x00030047, + 0x00000028,0x00000002,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016, + 0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040020,0x00000008, + 0x00000003,0x00000007,0x0004003b,0x00000008,0x00000009,0x00000003,0x00090019,0x0000000a, + 0x00000006,0x00000001,0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x0003001b, + 0x0000000b,0x0000000a,0x00040020,0x0000000c,0x00000000,0x0000000b,0x0004003b,0x0000000c, + 0x0000000d,0x00000000,0x00040017,0x0000000f,0x00000006,0x00000002,0x00040020,0x00000010, + 0x00000001,0x0000000f,0x0004003b,0x00000010,0x00000011,0x00000001,0x00040020,0x00000014, + 0x00000001,0x00000007,0x0004003b,0x00000014,0x00000015,0x00000001,0x00040015,0x00000018, + 0x00000020,0x00000000,0x0004002b,0x00000018,0x00000019,0x00000003,0x00040020,0x0000001a, + 0x00000003,0x00000006,0x00040020,0x0000001d,0x00000001,0x00000006,0x0004003b,0x0000001d, + 0x0000001e,0x00000001,0x00020014,0x00000020,0x00040017,0x00000025,0x00000006,0x00000003, + 0x0003001e,0x00000028,0x00000006,0x00040020,0x00000029,0x00000009,0x00000028,0x0004003b, + 0x00000029,0x0000002a,0x00000009,0x00040015,0x0000002b,0x00000020,0x00000001,0x0004002b, + 0x0000002b,0x0000002c,0x00000000,0x00040020,0x0000002d,0x00000009,0x00000006,0x00050036, + 0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003d,0x0000000b, + 0x0000000e,0x0000000d,0x0004003d,0x0000000f,0x00000012,0x00000011,0x00050057,0x00000007, + 0x00000013,0x0000000e,0x00000012,0x0004003d,0x00000007,0x00000016,0x00000015,0x00050085, + 0x00000007,0x00000017,0x00000013,0x00000016,0x0003003e,0x00000009,0x00000017,0x00050041, + 0x0000001a,0x0000001b,0x00000009,0x00000019,0x0004003d,0x00000006,0x0000001c,0x0000001b, + 0x0004003d,0x00000006,0x0000001f,0x0000001e,0x000500b8,0x00000020,0x00000021,0x0000001c, + 0x0000001f,0x000300f7,0x00000023,0x00000000,0x000400fa,0x00000021,0x00000022,0x00000023, + 0x000200f8,0x00000022,0x000100fc,0x000200f8,0x00000023,0x0004003d,0x00000007,0x00000026, + 0x00000009,0x0008004f,0x00000025,0x00000027,0x00000026,0x00000026,0x00000000,0x00000001, + 0x00000002,0x00050041,0x0000002d,0x0000002e,0x0000002a,0x0000002c,0x0004003d,0x00000006, + 0x0000002f,0x0000002e,0x00060050,0x00000025,0x00000030,0x0000002f,0x0000002f,0x0000002f, + 0x0007000c,0x00000025,0x00000031,0x00000001,0x0000001a,0x00000027,0x00000030,0x00050041, + 0x0000001a,0x00000032,0x00000009,0x00000019,0x0004003d,0x00000006,0x00000033,0x00000032, + 0x00050051,0x00000006,0x00000034,0x00000031,0x00000000,0x00050051,0x00000006,0x00000035, + 0x00000031,0x00000001,0x00050051,0x00000006,0x00000036,0x00000031,0x00000002,0x00070050, + 0x00000007,0x00000037,0x00000034,0x00000035,0x00000036,0x00000033,0x0003003e,0x00000009, + 0x00000037,0x000100fd,0x00010038 +}; \ No newline at end of file diff --git a/src/vk/spirv/basic_vert.c b/src/vk/spirv/basic_vert.c new file mode 100644 index 0000000..3e15183 --- /dev/null +++ b/src/vk/spirv/basic_vert.c @@ -0,0 +1,61 @@ + // 8.13.3559 + #pragma once +const uint32_t basic_vert_spv[] = { + 0x07230203,0x00010000,0x00080008,0x0000003e,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x000b000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000b,0x0000001f,0x0000002e, + 0x0000002f,0x00000039,0x0000003c,0x00030003,0x00000002,0x000001c2,0x00090004,0x415f4c47, + 0x735f4252,0x72617065,0x5f657461,0x64616873,0x6f5f7265,0x63656a62,0x00007374,0x00040005, + 0x00000004,0x6e69616d,0x00000000,0x00040005,0x00000009,0x736f5076,0x00000000,0x00050005, + 0x0000000b,0x65566e69,0x78657472,0x00000000,0x00060005,0x0000000d,0x67616d69,0x61725465, + 0x6f66736e,0x00006d72,0x00050006,0x0000000d,0x00000000,0x7366666f,0x00007465,0x00050006, + 0x0000000d,0x00000001,0x6c616373,0x00000065,0x00060006,0x0000000d,0x00000002,0x664f7675, + 0x74657366,0x00000000,0x00050006,0x0000000d,0x00000003,0x63537675,0x00656c61,0x00030005, + 0x0000000f,0x00007469,0x00060005,0x0000001d,0x505f6c67,0x65567265,0x78657472,0x00000000, + 0x00060006,0x0000001d,0x00000000,0x505f6c67,0x7469736f,0x006e6f69,0x00030005,0x0000001f, + 0x00000000,0x00050005,0x0000002e,0x43786574,0x64726f6f,0x00000000,0x00050005,0x0000002f, + 0x65546e69,0x6f6f4378,0x00006472,0x00040005,0x00000039,0x6f6c6f63,0x00000072,0x00050005, + 0x0000003c,0x65725461,0x6c6f6873,0x00000064,0x00040047,0x0000000b,0x0000001e,0x00000000, + 0x00050048,0x0000000d,0x00000000,0x00000023,0x00000000,0x00050048,0x0000000d,0x00000001, + 0x00000023,0x00000008,0x00050048,0x0000000d,0x00000002,0x00000023,0x00000010,0x00050048, + 0x0000000d,0x00000003,0x00000023,0x00000018,0x00030047,0x0000000d,0x00000002,0x00040047, + 0x0000000f,0x00000022,0x00000001,0x00040047,0x0000000f,0x00000021,0x00000000,0x00050048, + 0x0000001d,0x00000000,0x0000000b,0x00000000,0x00030047,0x0000001d,0x00000002,0x00040047, + 0x0000002e,0x0000001e,0x00000000,0x00040047,0x0000002f,0x0000001e,0x00000001,0x00040047, + 0x00000039,0x0000001e,0x00000001,0x00040047,0x0000003c,0x0000001e,0x00000002,0x00020013, + 0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,0x00000020,0x00040017, + 0x00000007,0x00000006,0x00000002,0x00040020,0x00000008,0x00000007,0x00000007,0x00040020, + 0x0000000a,0x00000001,0x00000007,0x0004003b,0x0000000a,0x0000000b,0x00000001,0x0006001e, + 0x0000000d,0x00000007,0x00000007,0x00000007,0x00000007,0x00040020,0x0000000e,0x00000002, + 0x0000000d,0x0004003b,0x0000000e,0x0000000f,0x00000002,0x00040015,0x00000010,0x00000020, + 0x00000001,0x0004002b,0x00000010,0x00000011,0x00000001,0x00040020,0x00000012,0x00000002, + 0x00000007,0x0004002b,0x00000006,0x00000016,0x3f800000,0x0005002c,0x00000007,0x00000017, + 0x00000016,0x00000016,0x00040017,0x0000001c,0x00000006,0x00000004,0x0003001e,0x0000001d, + 0x0000001c,0x00040020,0x0000001e,0x00000003,0x0000001d,0x0004003b,0x0000001e,0x0000001f, + 0x00000003,0x0004002b,0x00000010,0x00000020,0x00000000,0x0004002b,0x00000006,0x00000024, + 0x40000000,0x0004002b,0x00000006,0x00000027,0x00000000,0x00040020,0x0000002b,0x00000003, + 0x0000001c,0x00040020,0x0000002d,0x00000003,0x00000007,0x0004003b,0x0000002d,0x0000002e, + 0x00000003,0x0004003b,0x0000000a,0x0000002f,0x00000001,0x0004002b,0x00000010,0x00000031, + 0x00000003,0x0004002b,0x00000010,0x00000035,0x00000002,0x0004003b,0x0000002b,0x00000039, + 0x00000003,0x0007002c,0x0000001c,0x0000003a,0x00000016,0x00000016,0x00000016,0x00000016, + 0x00040020,0x0000003b,0x00000003,0x00000006,0x0004003b,0x0000003b,0x0000003c,0x00000003, + 0x0004002b,0x00000006,0x0000003d,0x3f2a7efa,0x00050036,0x00000002,0x00000004,0x00000000, + 0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000008,0x00000009,0x00000007,0x0004003d, + 0x00000007,0x0000000c,0x0000000b,0x00050041,0x00000012,0x00000013,0x0000000f,0x00000011, + 0x0004003d,0x00000007,0x00000014,0x00000013,0x00050085,0x00000007,0x00000015,0x0000000c, + 0x00000014,0x00050041,0x00000012,0x00000018,0x0000000f,0x00000011,0x0004003d,0x00000007, + 0x00000019,0x00000018,0x00050083,0x00000007,0x0000001a,0x00000017,0x00000019,0x00050083, + 0x00000007,0x0000001b,0x00000015,0x0000001a,0x0003003e,0x00000009,0x0000001b,0x0004003d, + 0x00000007,0x00000021,0x00000009,0x00050041,0x00000012,0x00000022,0x0000000f,0x00000020, + 0x0004003d,0x00000007,0x00000023,0x00000022,0x0005008e,0x00000007,0x00000025,0x00000023, + 0x00000024,0x00050081,0x00000007,0x00000026,0x00000021,0x00000025,0x00050051,0x00000006, + 0x00000028,0x00000026,0x00000000,0x00050051,0x00000006,0x00000029,0x00000026,0x00000001, + 0x00070050,0x0000001c,0x0000002a,0x00000028,0x00000029,0x00000027,0x00000016,0x00050041, + 0x0000002b,0x0000002c,0x0000001f,0x00000020,0x0003003e,0x0000002c,0x0000002a,0x0004003d, + 0x00000007,0x00000030,0x0000002f,0x00050041,0x00000012,0x00000032,0x0000000f,0x00000031, + 0x0004003d,0x00000007,0x00000033,0x00000032,0x00050085,0x00000007,0x00000034,0x00000030, + 0x00000033,0x00050041,0x00000012,0x00000036,0x0000000f,0x00000035,0x0004003d,0x00000007, + 0x00000037,0x00000036,0x00050081,0x00000007,0x00000038,0x00000034,0x00000037,0x0003003e, + 0x0000002e,0x00000038,0x0003003e,0x00000039,0x0000003a,0x0003003e,0x0000003c,0x0000003d, + 0x000100fd,0x00010038 +}; \ No newline at end of file diff --git a/src/vk/spirv/beam_vert.c b/src/vk/spirv/beam_vert.c new file mode 100644 index 0000000..9dc6b07 --- /dev/null +++ b/src/vk/spirv/beam_vert.c @@ -0,0 +1,42 @@ + // 8.13.3559 + #pragma once +const uint32_t beam_vert_spv[] = { + 0x07230203,0x00010000,0x00080008,0x00000027,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0008000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000a,0x00000016,0x00000020, + 0x00030003,0x00000002,0x000001c2,0x00090004,0x415f4c47,0x735f4252,0x72617065,0x5f657461, + 0x64616873,0x6f5f7265,0x63656a62,0x00007374,0x00040005,0x00000004,0x6e69616d,0x00000000, + 0x00060005,0x00000008,0x505f6c67,0x65567265,0x78657472,0x00000000,0x00060006,0x00000008, + 0x00000000,0x505f6c67,0x7469736f,0x006e6f69,0x00030005,0x0000000a,0x00000000,0x00060005, + 0x0000000e,0x68737550,0x736e6f43,0x746e6174,0x00000000,0x00060006,0x0000000e,0x00000000, + 0x4d70766d,0x69727461,0x00000078,0x00030005,0x00000010,0x00006370,0x00050005,0x00000016, + 0x65566e69,0x78657472,0x00000000,0x00040005,0x00000020,0x6f6c6f63,0x00000072,0x00070005, + 0x00000021,0x66696e55,0x426d726f,0x65666675,0x6a624f72,0x00746365,0x00050006,0x00000021, + 0x00000000,0x6f6c6f63,0x00000072,0x00030005,0x00000023,0x006f6275,0x00050048,0x00000008, + 0x00000000,0x0000000b,0x00000000,0x00030047,0x00000008,0x00000002,0x00040048,0x0000000e, + 0x00000000,0x00000005,0x00050048,0x0000000e,0x00000000,0x00000023,0x00000000,0x00050048, + 0x0000000e,0x00000000,0x00000007,0x00000010,0x00030047,0x0000000e,0x00000002,0x00040047, + 0x00000016,0x0000001e,0x00000000,0x00040047,0x00000020,0x0000001e,0x00000000,0x00050048, + 0x00000021,0x00000000,0x00000023,0x00000000,0x00030047,0x00000021,0x00000002,0x00040047, + 0x00000023,0x00000022,0x00000000,0x00040047,0x00000023,0x00000021,0x00000000,0x00020013, + 0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,0x00000020,0x00040017, + 0x00000007,0x00000006,0x00000004,0x0003001e,0x00000008,0x00000007,0x00040020,0x00000009, + 0x00000003,0x00000008,0x0004003b,0x00000009,0x0000000a,0x00000003,0x00040015,0x0000000b, + 0x00000020,0x00000001,0x0004002b,0x0000000b,0x0000000c,0x00000000,0x00040018,0x0000000d, + 0x00000007,0x00000004,0x0003001e,0x0000000e,0x0000000d,0x00040020,0x0000000f,0x00000009, + 0x0000000e,0x0004003b,0x0000000f,0x00000010,0x00000009,0x00040020,0x00000011,0x00000009, + 0x0000000d,0x00040017,0x00000014,0x00000006,0x00000003,0x00040020,0x00000015,0x00000001, + 0x00000014,0x0004003b,0x00000015,0x00000016,0x00000001,0x0004002b,0x00000006,0x00000018, + 0x3f800000,0x00040020,0x0000001e,0x00000003,0x00000007,0x0004003b,0x0000001e,0x00000020, + 0x00000003,0x0003001e,0x00000021,0x00000007,0x00040020,0x00000022,0x00000002,0x00000021, + 0x0004003b,0x00000022,0x00000023,0x00000002,0x00040020,0x00000024,0x00000002,0x00000007, + 0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x00050041, + 0x00000011,0x00000012,0x00000010,0x0000000c,0x0004003d,0x0000000d,0x00000013,0x00000012, + 0x0004003d,0x00000014,0x00000017,0x00000016,0x00050051,0x00000006,0x00000019,0x00000017, + 0x00000000,0x00050051,0x00000006,0x0000001a,0x00000017,0x00000001,0x00050051,0x00000006, + 0x0000001b,0x00000017,0x00000002,0x00070050,0x00000007,0x0000001c,0x00000019,0x0000001a, + 0x0000001b,0x00000018,0x00050091,0x00000007,0x0000001d,0x00000013,0x0000001c,0x00050041, + 0x0000001e,0x0000001f,0x0000000a,0x0000000c,0x0003003e,0x0000001f,0x0000001d,0x00050041, + 0x00000024,0x00000025,0x00000023,0x0000000c,0x0004003d,0x00000007,0x00000026,0x00000025, + 0x0003003e,0x00000020,0x00000026,0x000100fd,0x00010038 +}; \ No newline at end of file diff --git a/src/vk/spirv/d_light_vert.c b/src/vk/spirv/d_light_vert.c new file mode 100644 index 0000000..8f8e04b --- /dev/null +++ b/src/vk/spirv/d_light_vert.c @@ -0,0 +1,41 @@ + // 8.13.3559 + #pragma once +const uint32_t d_light_vert_spv[] = { + 0x07230203,0x00010000,0x00080008,0x00000027,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0009000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000a,0x00000016,0x00000020, + 0x00000021,0x00030003,0x00000002,0x000001c2,0x00090004,0x415f4c47,0x735f4252,0x72617065, + 0x5f657461,0x64616873,0x6f5f7265,0x63656a62,0x00007374,0x00040005,0x00000004,0x6e69616d, + 0x00000000,0x00060005,0x00000008,0x505f6c67,0x65567265,0x78657472,0x00000000,0x00060006, + 0x00000008,0x00000000,0x505f6c67,0x7469736f,0x006e6f69,0x00030005,0x0000000a,0x00000000, + 0x00070005,0x0000000e,0x66696e55,0x426d726f,0x65666675,0x6a624f72,0x00746365,0x00060006, + 0x0000000e,0x00000000,0x4d70766d,0x69727461,0x00000078,0x00030005,0x00000010,0x006f6275, + 0x00050005,0x00000016,0x65566e69,0x78657472,0x00000000,0x00040005,0x00000020,0x6f6c6f63, + 0x00000072,0x00040005,0x00000021,0x6f436e69,0x00726f6c,0x00050048,0x00000008,0x00000000, + 0x0000000b,0x00000000,0x00030047,0x00000008,0x00000002,0x00040048,0x0000000e,0x00000000, + 0x00000005,0x00050048,0x0000000e,0x00000000,0x00000023,0x00000000,0x00050048,0x0000000e, + 0x00000000,0x00000007,0x00000010,0x00030047,0x0000000e,0x00000002,0x00040047,0x00000010, + 0x00000022,0x00000000,0x00040047,0x00000010,0x00000021,0x00000000,0x00040047,0x00000016, + 0x0000001e,0x00000000,0x00040047,0x00000020,0x0000001e,0x00000000,0x00040047,0x00000021, + 0x0000001e,0x00000001,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016, + 0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x0003001e,0x00000008, + 0x00000007,0x00040020,0x00000009,0x00000003,0x00000008,0x0004003b,0x00000009,0x0000000a, + 0x00000003,0x00040015,0x0000000b,0x00000020,0x00000001,0x0004002b,0x0000000b,0x0000000c, + 0x00000000,0x00040018,0x0000000d,0x00000007,0x00000004,0x0003001e,0x0000000e,0x0000000d, + 0x00040020,0x0000000f,0x00000002,0x0000000e,0x0004003b,0x0000000f,0x00000010,0x00000002, + 0x00040020,0x00000011,0x00000002,0x0000000d,0x00040017,0x00000014,0x00000006,0x00000003, + 0x00040020,0x00000015,0x00000001,0x00000014,0x0004003b,0x00000015,0x00000016,0x00000001, + 0x0004002b,0x00000006,0x00000018,0x3f800000,0x00040020,0x0000001e,0x00000003,0x00000007, + 0x0004003b,0x0000001e,0x00000020,0x00000003,0x0004003b,0x00000015,0x00000021,0x00000001, + 0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x00050041, + 0x00000011,0x00000012,0x00000010,0x0000000c,0x0004003d,0x0000000d,0x00000013,0x00000012, + 0x0004003d,0x00000014,0x00000017,0x00000016,0x00050051,0x00000006,0x00000019,0x00000017, + 0x00000000,0x00050051,0x00000006,0x0000001a,0x00000017,0x00000001,0x00050051,0x00000006, + 0x0000001b,0x00000017,0x00000002,0x00070050,0x00000007,0x0000001c,0x00000019,0x0000001a, + 0x0000001b,0x00000018,0x00050091,0x00000007,0x0000001d,0x00000013,0x0000001c,0x00050041, + 0x0000001e,0x0000001f,0x0000000a,0x0000000c,0x0003003e,0x0000001f,0x0000001d,0x0004003d, + 0x00000014,0x00000022,0x00000021,0x00050051,0x00000006,0x00000023,0x00000022,0x00000000, + 0x00050051,0x00000006,0x00000024,0x00000022,0x00000001,0x00050051,0x00000006,0x00000025, + 0x00000022,0x00000002,0x00070050,0x00000007,0x00000026,0x00000023,0x00000024,0x00000025, + 0x00000018,0x0003003e,0x00000020,0x00000026,0x000100fd,0x00010038 +}; \ No newline at end of file diff --git a/src/vk/spirv/model_frag.c b/src/vk/spirv/model_frag.c new file mode 100644 index 0000000..953ca57 --- /dev/null +++ b/src/vk/spirv/model_frag.c @@ -0,0 +1,37 @@ + // 8.13.3559 + #pragma once +const uint32_t model_frag_spv[] = { + 0x07230203,0x00010000,0x00080008,0x00000028,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0009000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000008,0x00000012,0x0000001a, + 0x0000001e,0x00030010,0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005, + 0x00000004,0x6e69616d,0x00000000,0x00050005,0x00000008,0x74786574,0x64657275,0x00000000, + 0x00060005,0x00000012,0x67617266,0x746e656d,0x6f6c6f43,0x00000072,0x00050005,0x00000016, + 0x78655473,0x65727574,0x00000000,0x00050005,0x0000001a,0x43786574,0x64726f6f,0x00000000, + 0x00040005,0x0000001e,0x6f6c6f63,0x00000072,0x00030047,0x00000008,0x0000000e,0x00040047, + 0x00000008,0x0000001e,0x00000002,0x00040047,0x00000012,0x0000001e,0x00000000,0x00040047, + 0x00000016,0x00000022,0x00000000,0x00040047,0x00000016,0x00000021,0x00000000,0x00040047, + 0x0000001a,0x0000001e,0x00000001,0x00040047,0x0000001e,0x0000001e,0x00000000,0x00020013, + 0x00000002,0x00030021,0x00000003,0x00000002,0x00040015,0x00000006,0x00000020,0x00000001, + 0x00040020,0x00000007,0x00000001,0x00000006,0x0004003b,0x00000007,0x00000008,0x00000001, + 0x0004002b,0x00000006,0x0000000a,0x00000000,0x00020014,0x0000000b,0x00030016,0x0000000f, + 0x00000020,0x00040017,0x00000010,0x0000000f,0x00000004,0x00040020,0x00000011,0x00000003, + 0x00000010,0x0004003b,0x00000011,0x00000012,0x00000003,0x00090019,0x00000013,0x0000000f, + 0x00000001,0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x0003001b,0x00000014, + 0x00000013,0x00040020,0x00000015,0x00000000,0x00000014,0x0004003b,0x00000015,0x00000016, + 0x00000000,0x00040017,0x00000018,0x0000000f,0x00000002,0x00040020,0x00000019,0x00000001, + 0x00000018,0x0004003b,0x00000019,0x0000001a,0x00000001,0x00040020,0x0000001d,0x00000001, + 0x00000010,0x0004003b,0x0000001d,0x0000001e,0x00000001,0x0004002b,0x0000000f,0x00000020, + 0x00000000,0x0004002b,0x0000000f,0x00000021,0x3f800000,0x00050036,0x00000002,0x00000004, + 0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003d,0x00000006,0x00000009,0x00000008, + 0x000500ab,0x0000000b,0x0000000c,0x00000009,0x0000000a,0x000300f7,0x0000000e,0x00000000, + 0x000400fa,0x0000000c,0x0000000d,0x00000026,0x000200f8,0x0000000d,0x0004003d,0x00000014, + 0x00000017,0x00000016,0x0004003d,0x00000018,0x0000001b,0x0000001a,0x00050057,0x00000010, + 0x0000001c,0x00000017,0x0000001b,0x0004003d,0x00000010,0x0000001f,0x0000001e,0x00070050, + 0x00000010,0x00000022,0x00000020,0x00000020,0x00000020,0x00000020,0x00070050,0x00000010, + 0x00000023,0x00000021,0x00000021,0x00000021,0x00000021,0x0008000c,0x00000010,0x00000024, + 0x00000001,0x0000002b,0x0000001f,0x00000022,0x00000023,0x00050085,0x00000010,0x00000025, + 0x0000001c,0x00000024,0x0003003e,0x00000012,0x00000025,0x000200f9,0x0000000e,0x000200f8, + 0x00000026,0x0004003d,0x00000010,0x00000027,0x0000001e,0x0003003e,0x00000012,0x00000027, + 0x000200f9,0x0000000e,0x000200f8,0x0000000e,0x000100fd,0x00010038 +}; \ No newline at end of file diff --git a/src/vk/spirv/model_vert.c b/src/vk/spirv/model_vert.c new file mode 100644 index 0000000..86462f5 --- /dev/null +++ b/src/vk/spirv/model_vert.c @@ -0,0 +1,59 @@ + // 8.13.3559 + #pragma once +const uint32_t model_vert_spv[] = { + 0x07230203,0x00010000,0x00080008,0x00000037,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x000c000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000a,0x0000001d,0x00000027, + 0x00000029,0x0000002d,0x0000002f,0x00000032,0x00030003,0x00000002,0x000001c2,0x00090004, + 0x415f4c47,0x735f4252,0x72617065,0x5f657461,0x64616873,0x6f5f7265,0x63656a62,0x00007374, + 0x00040005,0x00000004,0x6e69616d,0x00000000,0x00060005,0x00000008,0x505f6c67,0x65567265, + 0x78657472,0x00000000,0x00060006,0x00000008,0x00000000,0x505f6c67,0x7469736f,0x006e6f69, + 0x00030005,0x0000000a,0x00000000,0x00060005,0x0000000e,0x68737550,0x736e6f43,0x746e6174, + 0x00000000,0x00060006,0x0000000e,0x00000000,0x614d7076,0x78697274,0x00000000,0x00030005, + 0x00000010,0x00006370,0x00070005,0x00000014,0x66696e55,0x426d726f,0x65666675,0x6a624f72, + 0x00746365,0x00050006,0x00000014,0x00000000,0x65646f6d,0x0000006c,0x00060006,0x00000014, + 0x00000001,0x74786574,0x64657275,0x00000000,0x00030005,0x00000016,0x006f6275,0x00050005, + 0x0000001d,0x65566e69,0x78657472,0x00000000,0x00040005,0x00000027,0x6f6c6f63,0x00000072, + 0x00040005,0x00000029,0x6f436e69,0x00726f6c,0x00050005,0x0000002d,0x43786574,0x64726f6f, + 0x00000000,0x00050005,0x0000002f,0x65546e69,0x6f6f4378,0x00006472,0x00050005,0x00000032, + 0x74786574,0x64657275,0x00000000,0x00050048,0x00000008,0x00000000,0x0000000b,0x00000000, + 0x00030047,0x00000008,0x00000002,0x00040048,0x0000000e,0x00000000,0x00000005,0x00050048, + 0x0000000e,0x00000000,0x00000023,0x00000000,0x00050048,0x0000000e,0x00000000,0x00000007, + 0x00000010,0x00030047,0x0000000e,0x00000002,0x00040048,0x00000014,0x00000000,0x00000005, + 0x00050048,0x00000014,0x00000000,0x00000023,0x00000000,0x00050048,0x00000014,0x00000000, + 0x00000007,0x00000010,0x00050048,0x00000014,0x00000001,0x00000023,0x00000040,0x00030047, + 0x00000014,0x00000002,0x00040047,0x00000016,0x00000022,0x00000001,0x00040047,0x00000016, + 0x00000021,0x00000000,0x00040047,0x0000001d,0x0000001e,0x00000000,0x00040047,0x00000027, + 0x0000001e,0x00000000,0x00040047,0x00000029,0x0000001e,0x00000001,0x00040047,0x0000002d, + 0x0000001e,0x00000001,0x00040047,0x0000002f,0x0000001e,0x00000002,0x00040047,0x00000032, + 0x0000001e,0x00000002,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016, + 0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x0003001e,0x00000008, + 0x00000007,0x00040020,0x00000009,0x00000003,0x00000008,0x0004003b,0x00000009,0x0000000a, + 0x00000003,0x00040015,0x0000000b,0x00000020,0x00000001,0x0004002b,0x0000000b,0x0000000c, + 0x00000000,0x00040018,0x0000000d,0x00000007,0x00000004,0x0003001e,0x0000000e,0x0000000d, + 0x00040020,0x0000000f,0x00000009,0x0000000e,0x0004003b,0x0000000f,0x00000010,0x00000009, + 0x00040020,0x00000011,0x00000009,0x0000000d,0x0004001e,0x00000014,0x0000000d,0x0000000b, + 0x00040020,0x00000015,0x00000002,0x00000014,0x0004003b,0x00000015,0x00000016,0x00000002, + 0x00040020,0x00000017,0x00000002,0x0000000d,0x00040017,0x0000001b,0x00000006,0x00000003, + 0x00040020,0x0000001c,0x00000001,0x0000001b,0x0004003b,0x0000001c,0x0000001d,0x00000001, + 0x0004002b,0x00000006,0x0000001f,0x3f800000,0x00040020,0x00000025,0x00000003,0x00000007, + 0x0004003b,0x00000025,0x00000027,0x00000003,0x00040020,0x00000028,0x00000001,0x00000007, + 0x0004003b,0x00000028,0x00000029,0x00000001,0x00040017,0x0000002b,0x00000006,0x00000002, + 0x00040020,0x0000002c,0x00000003,0x0000002b,0x0004003b,0x0000002c,0x0000002d,0x00000003, + 0x00040020,0x0000002e,0x00000001,0x0000002b,0x0004003b,0x0000002e,0x0000002f,0x00000001, + 0x00040020,0x00000031,0x00000003,0x0000000b,0x0004003b,0x00000031,0x00000032,0x00000003, + 0x0004002b,0x0000000b,0x00000033,0x00000001,0x00040020,0x00000034,0x00000002,0x0000000b, + 0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x00050041, + 0x00000011,0x00000012,0x00000010,0x0000000c,0x0004003d,0x0000000d,0x00000013,0x00000012, + 0x00050041,0x00000017,0x00000018,0x00000016,0x0000000c,0x0004003d,0x0000000d,0x00000019, + 0x00000018,0x00050092,0x0000000d,0x0000001a,0x00000013,0x00000019,0x0004003d,0x0000001b, + 0x0000001e,0x0000001d,0x00050051,0x00000006,0x00000020,0x0000001e,0x00000000,0x00050051, + 0x00000006,0x00000021,0x0000001e,0x00000001,0x00050051,0x00000006,0x00000022,0x0000001e, + 0x00000002,0x00070050,0x00000007,0x00000023,0x00000020,0x00000021,0x00000022,0x0000001f, + 0x00050091,0x00000007,0x00000024,0x0000001a,0x00000023,0x00050041,0x00000025,0x00000026, + 0x0000000a,0x0000000c,0x0003003e,0x00000026,0x00000024,0x0004003d,0x00000007,0x0000002a, + 0x00000029,0x0003003e,0x00000027,0x0000002a,0x0004003d,0x0000002b,0x00000030,0x0000002f, + 0x0003003e,0x0000002d,0x00000030,0x00050041,0x00000034,0x00000035,0x00000016,0x00000033, + 0x0004003d,0x0000000b,0x00000036,0x00000035,0x0003003e,0x00000032,0x00000036,0x000100fd, + 0x00010038 +}; \ No newline at end of file diff --git a/src/vk/spirv/nullmodel_vert.c b/src/vk/spirv/nullmodel_vert.c new file mode 100644 index 0000000..b86cff4 --- /dev/null +++ b/src/vk/spirv/nullmodel_vert.c @@ -0,0 +1,49 @@ + // 8.13.3559 + #pragma once +const uint32_t nullmodel_vert_spv[] = { + 0x07230203,0x00010000,0x00080008,0x0000002e,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0009000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000a,0x0000001d,0x00000027, + 0x00000028,0x00030003,0x00000002,0x000001c2,0x00090004,0x415f4c47,0x735f4252,0x72617065, + 0x5f657461,0x64616873,0x6f5f7265,0x63656a62,0x00007374,0x00040005,0x00000004,0x6e69616d, + 0x00000000,0x00060005,0x00000008,0x505f6c67,0x65567265,0x78657472,0x00000000,0x00060006, + 0x00000008,0x00000000,0x505f6c67,0x7469736f,0x006e6f69,0x00030005,0x0000000a,0x00000000, + 0x00060005,0x0000000e,0x68737550,0x736e6f43,0x746e6174,0x00000000,0x00060006,0x0000000e, + 0x00000000,0x614d7076,0x78697274,0x00000000,0x00030005,0x00000010,0x00006370,0x00070005, + 0x00000014,0x66696e55,0x426d726f,0x65666675,0x6a624f72,0x00746365,0x00050006,0x00000014, + 0x00000000,0x65646f6d,0x0000006c,0x00030005,0x00000016,0x006f6275,0x00050005,0x0000001d, + 0x65566e69,0x78657472,0x00000000,0x00040005,0x00000027,0x6f6c6f63,0x00000072,0x00040005, + 0x00000028,0x6f436e69,0x00726f6c,0x00050048,0x00000008,0x00000000,0x0000000b,0x00000000, + 0x00030047,0x00000008,0x00000002,0x00040048,0x0000000e,0x00000000,0x00000005,0x00050048, + 0x0000000e,0x00000000,0x00000023,0x00000000,0x00050048,0x0000000e,0x00000000,0x00000007, + 0x00000010,0x00030047,0x0000000e,0x00000002,0x00040048,0x00000014,0x00000000,0x00000005, + 0x00050048,0x00000014,0x00000000,0x00000023,0x00000000,0x00050048,0x00000014,0x00000000, + 0x00000007,0x00000010,0x00030047,0x00000014,0x00000002,0x00040047,0x00000016,0x00000022, + 0x00000000,0x00040047,0x00000016,0x00000021,0x00000000,0x00040047,0x0000001d,0x0000001e, + 0x00000000,0x00040047,0x00000027,0x0000001e,0x00000000,0x00040047,0x00000028,0x0000001e, + 0x00000001,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006, + 0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x0003001e,0x00000008,0x00000007, + 0x00040020,0x00000009,0x00000003,0x00000008,0x0004003b,0x00000009,0x0000000a,0x00000003, + 0x00040015,0x0000000b,0x00000020,0x00000001,0x0004002b,0x0000000b,0x0000000c,0x00000000, + 0x00040018,0x0000000d,0x00000007,0x00000004,0x0003001e,0x0000000e,0x0000000d,0x00040020, + 0x0000000f,0x00000009,0x0000000e,0x0004003b,0x0000000f,0x00000010,0x00000009,0x00040020, + 0x00000011,0x00000009,0x0000000d,0x0003001e,0x00000014,0x0000000d,0x00040020,0x00000015, + 0x00000002,0x00000014,0x0004003b,0x00000015,0x00000016,0x00000002,0x00040020,0x00000017, + 0x00000002,0x0000000d,0x00040017,0x0000001b,0x00000006,0x00000003,0x00040020,0x0000001c, + 0x00000001,0x0000001b,0x0004003b,0x0000001c,0x0000001d,0x00000001,0x0004002b,0x00000006, + 0x0000001f,0x3f800000,0x00040020,0x00000025,0x00000003,0x00000007,0x0004003b,0x00000025, + 0x00000027,0x00000003,0x0004003b,0x0000001c,0x00000028,0x00000001,0x00050036,0x00000002, + 0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x00050041,0x00000011,0x00000012, + 0x00000010,0x0000000c,0x0004003d,0x0000000d,0x00000013,0x00000012,0x00050041,0x00000017, + 0x00000018,0x00000016,0x0000000c,0x0004003d,0x0000000d,0x00000019,0x00000018,0x00050092, + 0x0000000d,0x0000001a,0x00000013,0x00000019,0x0004003d,0x0000001b,0x0000001e,0x0000001d, + 0x00050051,0x00000006,0x00000020,0x0000001e,0x00000000,0x00050051,0x00000006,0x00000021, + 0x0000001e,0x00000001,0x00050051,0x00000006,0x00000022,0x0000001e,0x00000002,0x00070050, + 0x00000007,0x00000023,0x00000020,0x00000021,0x00000022,0x0000001f,0x00050091,0x00000007, + 0x00000024,0x0000001a,0x00000023,0x00050041,0x00000025,0x00000026,0x0000000a,0x0000000c, + 0x0003003e,0x00000026,0x00000024,0x0004003d,0x0000001b,0x00000029,0x00000028,0x00050051, + 0x00000006,0x0000002a,0x00000029,0x00000000,0x00050051,0x00000006,0x0000002b,0x00000029, + 0x00000001,0x00050051,0x00000006,0x0000002c,0x00000029,0x00000002,0x00070050,0x00000007, + 0x0000002d,0x0000002a,0x0000002b,0x0000002c,0x0000001f,0x0003003e,0x00000027,0x0000002d, + 0x000100fd,0x00010038 +}; \ No newline at end of file diff --git a/src/vk/spirv/particle_vert.c b/src/vk/spirv/particle_vert.c new file mode 100644 index 0000000..a0206ec --- /dev/null +++ b/src/vk/spirv/particle_vert.c @@ -0,0 +1,47 @@ + // 8.13.3743 + #pragma once +const uint32_t particle_vert_spv[] = { + 0x07230203,0x00010000,0x00080008,0x0000002d,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x000c000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000a,0x00000016,0x00000022, + 0x00000024,0x00000026,0x00000028,0x0000002b,0x00030003,0x00000002,0x000001c2,0x00090004, + 0x415f4c47,0x735f4252,0x72617065,0x5f657461,0x64616873,0x6f5f7265,0x63656a62,0x00007374, + 0x00040005,0x00000004,0x6e69616d,0x00000000,0x00060005,0x00000008,0x505f6c67,0x65567265, + 0x78657472,0x00000000,0x00060006,0x00000008,0x00000000,0x505f6c67,0x7469736f,0x006e6f69, + 0x00030005,0x0000000a,0x00000000,0x00060005,0x0000000e,0x68737550,0x736e6f43,0x746e6174, + 0x00000000,0x00060006,0x0000000e,0x00000000,0x4d70766d,0x69727461,0x00000078,0x00030005, + 0x00000010,0x00006370,0x00050005,0x00000016,0x65566e69,0x78657472,0x00000000,0x00050005, + 0x00000022,0x43786574,0x64726f6f,0x00000000,0x00050005,0x00000024,0x65546e69,0x6f6f4378, + 0x00006472,0x00040005,0x00000026,0x6f6c6f63,0x00000072,0x00040005,0x00000028,0x6f436e69, + 0x00726f6c,0x00050005,0x0000002b,0x65725461,0x6c6f6873,0x00000064,0x00050048,0x00000008, + 0x00000000,0x0000000b,0x00000000,0x00030047,0x00000008,0x00000002,0x00040048,0x0000000e, + 0x00000000,0x00000005,0x00050048,0x0000000e,0x00000000,0x00000023,0x00000000,0x00050048, + 0x0000000e,0x00000000,0x00000007,0x00000010,0x00030047,0x0000000e,0x00000002,0x00040047, + 0x00000016,0x0000001e,0x00000000,0x00040047,0x00000022,0x0000001e,0x00000000,0x00040047, + 0x00000024,0x0000001e,0x00000002,0x00040047,0x00000026,0x0000001e,0x00000001,0x00040047, + 0x00000028,0x0000001e,0x00000001,0x00040047,0x0000002b,0x0000001e,0x00000002,0x00020013, + 0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,0x00000020,0x00040017, + 0x00000007,0x00000006,0x00000004,0x0003001e,0x00000008,0x00000007,0x00040020,0x00000009, + 0x00000003,0x00000008,0x0004003b,0x00000009,0x0000000a,0x00000003,0x00040015,0x0000000b, + 0x00000020,0x00000001,0x0004002b,0x0000000b,0x0000000c,0x00000000,0x00040018,0x0000000d, + 0x00000007,0x00000004,0x0003001e,0x0000000e,0x0000000d,0x00040020,0x0000000f,0x00000009, + 0x0000000e,0x0004003b,0x0000000f,0x00000010,0x00000009,0x00040020,0x00000011,0x00000009, + 0x0000000d,0x00040017,0x00000014,0x00000006,0x00000003,0x00040020,0x00000015,0x00000001, + 0x00000014,0x0004003b,0x00000015,0x00000016,0x00000001,0x0004002b,0x00000006,0x00000018, + 0x3f800000,0x00040020,0x0000001e,0x00000003,0x00000007,0x00040017,0x00000020,0x00000006, + 0x00000002,0x00040020,0x00000021,0x00000003,0x00000020,0x0004003b,0x00000021,0x00000022, + 0x00000003,0x00040020,0x00000023,0x00000001,0x00000020,0x0004003b,0x00000023,0x00000024, + 0x00000001,0x0004003b,0x0000001e,0x00000026,0x00000003,0x00040020,0x00000027,0x00000001, + 0x00000007,0x0004003b,0x00000027,0x00000028,0x00000001,0x00040020,0x0000002a,0x00000003, + 0x00000006,0x0004003b,0x0000002a,0x0000002b,0x00000003,0x0004002b,0x00000006,0x0000002c, + 0x3f000000,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005, + 0x00050041,0x00000011,0x00000012,0x00000010,0x0000000c,0x0004003d,0x0000000d,0x00000013, + 0x00000012,0x0004003d,0x00000014,0x00000017,0x00000016,0x00050051,0x00000006,0x00000019, + 0x00000017,0x00000000,0x00050051,0x00000006,0x0000001a,0x00000017,0x00000001,0x00050051, + 0x00000006,0x0000001b,0x00000017,0x00000002,0x00070050,0x00000007,0x0000001c,0x00000019, + 0x0000001a,0x0000001b,0x00000018,0x00050091,0x00000007,0x0000001d,0x00000013,0x0000001c, + 0x00050041,0x0000001e,0x0000001f,0x0000000a,0x0000000c,0x0003003e,0x0000001f,0x0000001d, + 0x0004003d,0x00000020,0x00000025,0x00000024,0x0003003e,0x00000022,0x00000025,0x0004003d, + 0x00000007,0x00000029,0x00000028,0x0003003e,0x00000026,0x00000029,0x0003003e,0x0000002b, + 0x0000002c,0x000100fd,0x00010038 +}; \ No newline at end of file diff --git a/src/vk/spirv/point_particle_frag.c b/src/vk/spirv/point_particle_frag.c new file mode 100644 index 0000000..3dc1bc3 --- /dev/null +++ b/src/vk/spirv/point_particle_frag.c @@ -0,0 +1,28 @@ + // 8.13.3559 + #pragma once +const uint32_t point_particle_frag_spv[] = { + 0x07230203,0x00010000,0x00080008,0x00000020,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0008000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x0000000c,0x0000001c,0x0000001e, + 0x00030010,0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004, + 0x6e69616d,0x00000000,0x00030005,0x00000009,0x00797863,0x00060005,0x0000000c,0x505f6c67, + 0x746e696f,0x726f6f43,0x00000064,0x00060005,0x0000001c,0x67617266,0x746e656d,0x6f6c6f43, + 0x00000072,0x00040005,0x0000001e,0x6f6c6f63,0x00000072,0x00040047,0x0000000c,0x0000000b, + 0x00000010,0x00040047,0x0000001c,0x0000001e,0x00000000,0x00040047,0x0000001e,0x0000001e, + 0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006, + 0x00000020,0x00040017,0x00000007,0x00000006,0x00000002,0x00040020,0x00000008,0x00000007, + 0x00000007,0x0004002b,0x00000006,0x0000000a,0x40000000,0x00040020,0x0000000b,0x00000001, + 0x00000007,0x0004003b,0x0000000b,0x0000000c,0x00000001,0x0004002b,0x00000006,0x0000000f, + 0x3f800000,0x00020014,0x00000015,0x00040017,0x0000001a,0x00000006,0x00000004,0x00040020, + 0x0000001b,0x00000003,0x0000001a,0x0004003b,0x0000001b,0x0000001c,0x00000003,0x00040020, + 0x0000001d,0x00000001,0x0000001a,0x0004003b,0x0000001d,0x0000001e,0x00000001,0x00050036, + 0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000008, + 0x00000009,0x00000007,0x0004003d,0x00000007,0x0000000d,0x0000000c,0x0005008e,0x00000007, + 0x0000000e,0x0000000d,0x0000000a,0x00050050,0x00000007,0x00000010,0x0000000f,0x0000000f, + 0x00050083,0x00000007,0x00000011,0x0000000e,0x00000010,0x0003003e,0x00000009,0x00000011, + 0x0004003d,0x00000007,0x00000012,0x00000009,0x0004003d,0x00000007,0x00000013,0x00000009, + 0x00050094,0x00000006,0x00000014,0x00000012,0x00000013,0x000500ba,0x00000015,0x00000016, + 0x00000014,0x0000000f,0x000300f7,0x00000018,0x00000000,0x000400fa,0x00000016,0x00000017, + 0x00000018,0x000200f8,0x00000017,0x000100fc,0x000200f8,0x00000018,0x0004003d,0x0000001a, + 0x0000001f,0x0000001e,0x0003003e,0x0000001c,0x0000001f,0x000100fd,0x00010038 +}; \ No newline at end of file diff --git a/src/vk/spirv/point_particle_vert.c b/src/vk/spirv/point_particle_vert.c new file mode 100644 index 0000000..d257aeb --- /dev/null +++ b/src/vk/spirv/point_particle_vert.c @@ -0,0 +1,82 @@ + // 8.13.3559 + #pragma once +const uint32_t point_particle_vert_spv[] = { + 0x07230203,0x00010000,0x00080008,0x00000055,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0009000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000a,0x00000016,0x00000051, + 0x00000053,0x00030003,0x00000002,0x000001c2,0x00090004,0x415f4c47,0x735f4252,0x72617065, + 0x5f657461,0x64616873,0x6f5f7265,0x63656a62,0x00007374,0x00040005,0x00000004,0x6e69616d, + 0x00000000,0x00060005,0x00000008,0x505f6c67,0x65567265,0x78657472,0x00000000,0x00060006, + 0x00000008,0x00000000,0x505f6c67,0x7469736f,0x006e6f69,0x00070006,0x00000008,0x00000001, + 0x505f6c67,0x746e696f,0x657a6953,0x00000000,0x00030005,0x0000000a,0x00000000,0x00060005, + 0x0000000e,0x68737550,0x736e6f43,0x746e6174,0x00000000,0x00060006,0x0000000e,0x00000000, + 0x4d70766d,0x69727461,0x00000078,0x00030005,0x00000010,0x00006370,0x00050005,0x00000016, + 0x65566e69,0x78657472,0x00000000,0x00050005,0x00000021,0x74736964,0x7474615f,0x00006e65, + 0x00070005,0x00000022,0x66696e55,0x426d726f,0x65666675,0x6a624f72,0x00746365,0x00060006, + 0x00000022,0x00000000,0x6e696f70,0x7a695374,0x00000065,0x00060006,0x00000022,0x00000001, + 0x6e696f70,0x61635374,0x0000656c,0x00070006,0x00000022,0x00000002,0x506e696d,0x746e696f, + 0x657a6953,0x00000000,0x00070006,0x00000022,0x00000003,0x5078616d,0x746e696f,0x657a6953, + 0x00000000,0x00050006,0x00000022,0x00000004,0x5f747461,0x00000061,0x00050006,0x00000022, + 0x00000005,0x5f747461,0x00000062,0x00050006,0x00000022,0x00000006,0x5f747461,0x00000063, + 0x00030005,0x00000024,0x006f6275,0x00040005,0x00000051,0x6f6c6f63,0x00000072,0x00040005, + 0x00000053,0x6f436e69,0x00726f6c,0x00050048,0x00000008,0x00000000,0x0000000b,0x00000000, + 0x00050048,0x00000008,0x00000001,0x0000000b,0x00000001,0x00030047,0x00000008,0x00000002, + 0x00040048,0x0000000e,0x00000000,0x00000005,0x00050048,0x0000000e,0x00000000,0x00000023, + 0x00000000,0x00050048,0x0000000e,0x00000000,0x00000007,0x00000010,0x00030047,0x0000000e, + 0x00000002,0x00040047,0x00000016,0x0000001e,0x00000000,0x00050048,0x00000022,0x00000000, + 0x00000023,0x00000000,0x00050048,0x00000022,0x00000001,0x00000023,0x00000004,0x00050048, + 0x00000022,0x00000002,0x00000023,0x00000008,0x00050048,0x00000022,0x00000003,0x00000023, + 0x0000000c,0x00050048,0x00000022,0x00000004,0x00000023,0x00000010,0x00050048,0x00000022, + 0x00000005,0x00000023,0x00000014,0x00050048,0x00000022,0x00000006,0x00000023,0x00000018, + 0x00030047,0x00000022,0x00000002,0x00040047,0x00000024,0x00000022,0x00000000,0x00040047, + 0x00000024,0x00000021,0x00000000,0x00040047,0x00000051,0x0000001e,0x00000000,0x00040047, + 0x00000053,0x0000001e,0x00000001,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002, + 0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x0004001e, + 0x00000008,0x00000007,0x00000006,0x00040020,0x00000009,0x00000003,0x00000008,0x0004003b, + 0x00000009,0x0000000a,0x00000003,0x00040015,0x0000000b,0x00000020,0x00000001,0x0004002b, + 0x0000000b,0x0000000c,0x00000000,0x00040018,0x0000000d,0x00000007,0x00000004,0x0003001e, + 0x0000000e,0x0000000d,0x00040020,0x0000000f,0x00000009,0x0000000e,0x0004003b,0x0000000f, + 0x00000010,0x00000009,0x00040020,0x00000011,0x00000009,0x0000000d,0x00040017,0x00000014, + 0x00000006,0x00000003,0x00040020,0x00000015,0x00000001,0x00000014,0x0004003b,0x00000015, + 0x00000016,0x00000001,0x0004002b,0x00000006,0x00000018,0x3f800000,0x00040020,0x0000001e, + 0x00000003,0x00000007,0x00040020,0x00000020,0x00000007,0x00000006,0x0009001e,0x00000022, + 0x00000006,0x00000006,0x00000006,0x00000006,0x00000006,0x00000006,0x00000006,0x00040020, + 0x00000023,0x00000002,0x00000022,0x0004003b,0x00000023,0x00000024,0x00000002,0x0004002b, + 0x0000000b,0x00000025,0x00000001,0x00040020,0x00000026,0x00000002,0x00000006,0x0004002b, + 0x0000000b,0x00000029,0x00000004,0x0004002b,0x0000000b,0x0000002c,0x00000005,0x00040015, + 0x0000002f,0x00000020,0x00000000,0x0004002b,0x0000002f,0x00000030,0x00000003,0x00040020, + 0x00000031,0x00000003,0x00000006,0x0004002b,0x0000000b,0x00000036,0x00000006,0x0004002b, + 0x0000000b,0x00000049,0x00000002,0x0004002b,0x0000000b,0x0000004c,0x00000003,0x0004003b, + 0x0000001e,0x00000051,0x00000003,0x00040020,0x00000052,0x00000001,0x00000007,0x0004003b, + 0x00000052,0x00000053,0x00000001,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003, + 0x000200f8,0x00000005,0x0004003b,0x00000020,0x00000021,0x00000007,0x00050041,0x00000011, + 0x00000012,0x00000010,0x0000000c,0x0004003d,0x0000000d,0x00000013,0x00000012,0x0004003d, + 0x00000014,0x00000017,0x00000016,0x00050051,0x00000006,0x00000019,0x00000017,0x00000000, + 0x00050051,0x00000006,0x0000001a,0x00000017,0x00000001,0x00050051,0x00000006,0x0000001b, + 0x00000017,0x00000002,0x00070050,0x00000007,0x0000001c,0x00000019,0x0000001a,0x0000001b, + 0x00000018,0x00050091,0x00000007,0x0000001d,0x00000013,0x0000001c,0x00050041,0x0000001e, + 0x0000001f,0x0000000a,0x0000000c,0x0003003e,0x0000001f,0x0000001d,0x00050041,0x00000026, + 0x00000027,0x00000024,0x00000025,0x0004003d,0x00000006,0x00000028,0x00000027,0x00050041, + 0x00000026,0x0000002a,0x00000024,0x00000029,0x0004003d,0x00000006,0x0000002b,0x0000002a, + 0x00050041,0x00000026,0x0000002d,0x00000024,0x0000002c,0x0004003d,0x00000006,0x0000002e, + 0x0000002d,0x00060041,0x00000031,0x00000032,0x0000000a,0x0000000c,0x00000030,0x0004003d, + 0x00000006,0x00000033,0x00000032,0x00050085,0x00000006,0x00000034,0x0000002e,0x00000033, + 0x00050081,0x00000006,0x00000035,0x0000002b,0x00000034,0x00050041,0x00000026,0x00000037, + 0x00000024,0x00000036,0x0004003d,0x00000006,0x00000038,0x00000037,0x00060041,0x00000031, + 0x00000039,0x0000000a,0x0000000c,0x00000030,0x0004003d,0x00000006,0x0000003a,0x00000039, + 0x00050085,0x00000006,0x0000003b,0x00000038,0x0000003a,0x00060041,0x00000031,0x0000003c, + 0x0000000a,0x0000000c,0x00000030,0x0004003d,0x00000006,0x0000003d,0x0000003c,0x00050085, + 0x00000006,0x0000003e,0x0000003b,0x0000003d,0x00050081,0x00000006,0x0000003f,0x00000035, + 0x0000003e,0x00050088,0x00000006,0x00000040,0x00000028,0x0000003f,0x0003003e,0x00000021, + 0x00000040,0x00050041,0x00000026,0x00000041,0x00000024,0x00000025,0x0004003d,0x00000006, + 0x00000042,0x00000041,0x00050041,0x00000026,0x00000043,0x00000024,0x0000000c,0x0004003d, + 0x00000006,0x00000044,0x00000043,0x00050085,0x00000006,0x00000045,0x00000042,0x00000044, + 0x0004003d,0x00000006,0x00000046,0x00000021,0x0006000c,0x00000006,0x00000047,0x00000001, + 0x0000001f,0x00000046,0x00050085,0x00000006,0x00000048,0x00000045,0x00000047,0x00050041, + 0x00000026,0x0000004a,0x00000024,0x00000049,0x0004003d,0x00000006,0x0000004b,0x0000004a, + 0x00050041,0x00000026,0x0000004d,0x00000024,0x0000004c,0x0004003d,0x00000006,0x0000004e, + 0x0000004d,0x0008000c,0x00000006,0x0000004f,0x00000001,0x0000002b,0x00000048,0x0000004b, + 0x0000004e,0x00050041,0x00000031,0x00000050,0x0000000a,0x00000025,0x0003003e,0x00000050, + 0x0000004f,0x0004003d,0x00000007,0x00000054,0x00000053,0x0003003e,0x00000051,0x00000054, + 0x000100fd,0x00010038 +}; \ No newline at end of file diff --git a/src/vk/spirv/polygon_lmap_frag.c b/src/vk/spirv/polygon_lmap_frag.c new file mode 100644 index 0000000..5673000 --- /dev/null +++ b/src/vk/spirv/polygon_lmap_frag.c @@ -0,0 +1,40 @@ + // 8.13.3559 + #pragma once +const uint32_t polygon_lmap_frag_spv[] = { + 0x07230203,0x00010000,0x00080008,0x00000029,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0009000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000011,0x00000017,0x0000001b, + 0x0000001e,0x00030010,0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005, + 0x00000004,0x6e69616d,0x00000000,0x00040005,0x00000009,0x6f6c6f63,0x00000072,0x00050005, + 0x0000000d,0x78655473,0x65727574,0x00000000,0x00050005,0x00000011,0x43786574,0x64726f6f, + 0x00000000,0x00040005,0x00000014,0x6867696c,0x00000074,0x00050005,0x00000015,0x67694c73, + 0x616d7468,0x00000070,0x00060005,0x00000017,0x43786574,0x64726f6f,0x70616d4c,0x00000000, + 0x00060005,0x0000001b,0x67617266,0x746e656d,0x6f6c6f43,0x00000072,0x00060005,0x0000001e, + 0x77656976,0x6867694c,0x70616d74,0x00000073,0x00040047,0x0000000d,0x00000022,0x00000000, + 0x00040047,0x0000000d,0x00000021,0x00000000,0x00040047,0x00000011,0x0000001e,0x00000000, + 0x00040047,0x00000015,0x00000022,0x00000002,0x00040047,0x00000015,0x00000021,0x00000000, + 0x00040047,0x00000017,0x0000001e,0x00000001,0x00040047,0x0000001b,0x0000001e,0x00000000, + 0x00040047,0x0000001e,0x0000001e,0x00000002,0x00020013,0x00000002,0x00030021,0x00000003, + 0x00000002,0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000004, + 0x00040020,0x00000008,0x00000007,0x00000007,0x00090019,0x0000000a,0x00000006,0x00000001, + 0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x0003001b,0x0000000b,0x0000000a, + 0x00040020,0x0000000c,0x00000000,0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000000, + 0x00040017,0x0000000f,0x00000006,0x00000002,0x00040020,0x00000010,0x00000001,0x0000000f, + 0x0004003b,0x00000010,0x00000011,0x00000001,0x0004003b,0x0000000c,0x00000015,0x00000000, + 0x0004003b,0x00000010,0x00000017,0x00000001,0x00040020,0x0000001a,0x00000003,0x00000007, + 0x0004003b,0x0000001a,0x0000001b,0x00000003,0x0004002b,0x00000006,0x0000001c,0x3f800000, + 0x00040020,0x0000001d,0x00000001,0x00000006,0x0004003b,0x0000001d,0x0000001e,0x00000001, + 0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b, + 0x00000008,0x00000009,0x00000007,0x0004003b,0x00000008,0x00000014,0x00000007,0x0004003d, + 0x0000000b,0x0000000e,0x0000000d,0x0004003d,0x0000000f,0x00000012,0x00000011,0x00050057, + 0x00000007,0x00000013,0x0000000e,0x00000012,0x0003003e,0x00000009,0x00000013,0x0004003d, + 0x0000000b,0x00000016,0x00000015,0x0004003d,0x0000000f,0x00000018,0x00000017,0x00050057, + 0x00000007,0x00000019,0x00000016,0x00000018,0x0003003e,0x00000014,0x00000019,0x0004003d, + 0x00000006,0x0000001f,0x0000001e,0x00050083,0x00000006,0x00000020,0x0000001c,0x0000001f, + 0x0004003d,0x00000007,0x00000021,0x00000009,0x0005008e,0x00000007,0x00000022,0x00000021, + 0x00000020,0x0004003d,0x00000007,0x00000023,0x00000014,0x00050085,0x00000007,0x00000024, + 0x00000022,0x00000023,0x0004003d,0x00000006,0x00000025,0x0000001e,0x0004003d,0x00000007, + 0x00000026,0x00000014,0x0005008e,0x00000007,0x00000027,0x00000026,0x00000025,0x00050081, + 0x00000007,0x00000028,0x00000024,0x00000027,0x0003003e,0x0000001b,0x00000028,0x000100fd, + 0x00010038 +}; \ No newline at end of file diff --git a/src/vk/spirv/polygon_lmap_vert.c b/src/vk/spirv/polygon_lmap_vert.c new file mode 100644 index 0000000..4e66eeb --- /dev/null +++ b/src/vk/spirv/polygon_lmap_vert.c @@ -0,0 +1,59 @@ + // 8.13.3559 + #pragma once +const uint32_t polygon_lmap_vert_spv[] = { + 0x07230203,0x00010000,0x00080008,0x00000036,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x000c000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000a,0x0000001d,0x00000029, + 0x0000002b,0x0000002d,0x0000002e,0x00000031,0x00030003,0x00000002,0x000001c2,0x00090004, + 0x415f4c47,0x735f4252,0x72617065,0x5f657461,0x64616873,0x6f5f7265,0x63656a62,0x00007374, + 0x00040005,0x00000004,0x6e69616d,0x00000000,0x00060005,0x00000008,0x505f6c67,0x65567265, + 0x78657472,0x00000000,0x00060006,0x00000008,0x00000000,0x505f6c67,0x7469736f,0x006e6f69, + 0x00030005,0x0000000a,0x00000000,0x00060005,0x0000000e,0x68737550,0x736e6f43,0x746e6174, + 0x00000000,0x00060006,0x0000000e,0x00000000,0x614d7076,0x78697274,0x00000000,0x00030005, + 0x00000010,0x00006370,0x00070005,0x00000014,0x66696e55,0x426d726f,0x65666675,0x6a624f72, + 0x00746365,0x00050006,0x00000014,0x00000000,0x65646f6d,0x0000006c,0x00070006,0x00000014, + 0x00000001,0x77656976,0x6867694c,0x70616d74,0x00000073,0x00030005,0x00000016,0x006f6275, + 0x00050005,0x0000001d,0x65566e69,0x78657472,0x00000000,0x00050005,0x00000029,0x43786574, + 0x64726f6f,0x00000000,0x00050005,0x0000002b,0x65546e69,0x6f6f4378,0x00006472,0x00060005, + 0x0000002d,0x43786574,0x64726f6f,0x70616d4c,0x00000000,0x00060005,0x0000002e,0x65546e69, + 0x6f6f4378,0x6d4c6472,0x00007061,0x00060005,0x00000031,0x77656976,0x6867694c,0x70616d74, + 0x00000073,0x00050048,0x00000008,0x00000000,0x0000000b,0x00000000,0x00030047,0x00000008, + 0x00000002,0x00040048,0x0000000e,0x00000000,0x00000005,0x00050048,0x0000000e,0x00000000, + 0x00000023,0x00000000,0x00050048,0x0000000e,0x00000000,0x00000007,0x00000010,0x00030047, + 0x0000000e,0x00000002,0x00040048,0x00000014,0x00000000,0x00000005,0x00050048,0x00000014, + 0x00000000,0x00000023,0x00000000,0x00050048,0x00000014,0x00000000,0x00000007,0x00000010, + 0x00050048,0x00000014,0x00000001,0x00000023,0x00000040,0x00030047,0x00000014,0x00000002, + 0x00040047,0x00000016,0x00000022,0x00000001,0x00040047,0x00000016,0x00000021,0x00000000, + 0x00040047,0x0000001d,0x0000001e,0x00000000,0x00040047,0x00000029,0x0000001e,0x00000000, + 0x00040047,0x0000002b,0x0000001e,0x00000001,0x00040047,0x0000002d,0x0000001e,0x00000001, + 0x00040047,0x0000002e,0x0000001e,0x00000002,0x00040047,0x00000031,0x0000001e,0x00000002, + 0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,0x00000020, + 0x00040017,0x00000007,0x00000006,0x00000004,0x0003001e,0x00000008,0x00000007,0x00040020, + 0x00000009,0x00000003,0x00000008,0x0004003b,0x00000009,0x0000000a,0x00000003,0x00040015, + 0x0000000b,0x00000020,0x00000001,0x0004002b,0x0000000b,0x0000000c,0x00000000,0x00040018, + 0x0000000d,0x00000007,0x00000004,0x0003001e,0x0000000e,0x0000000d,0x00040020,0x0000000f, + 0x00000009,0x0000000e,0x0004003b,0x0000000f,0x00000010,0x00000009,0x00040020,0x00000011, + 0x00000009,0x0000000d,0x0004001e,0x00000014,0x0000000d,0x00000006,0x00040020,0x00000015, + 0x00000002,0x00000014,0x0004003b,0x00000015,0x00000016,0x00000002,0x00040020,0x00000017, + 0x00000002,0x0000000d,0x00040017,0x0000001b,0x00000006,0x00000003,0x00040020,0x0000001c, + 0x00000001,0x0000001b,0x0004003b,0x0000001c,0x0000001d,0x00000001,0x0004002b,0x00000006, + 0x0000001f,0x3f800000,0x00040020,0x00000025,0x00000003,0x00000007,0x00040017,0x00000027, + 0x00000006,0x00000002,0x00040020,0x00000028,0x00000003,0x00000027,0x0004003b,0x00000028, + 0x00000029,0x00000003,0x00040020,0x0000002a,0x00000001,0x00000027,0x0004003b,0x0000002a, + 0x0000002b,0x00000001,0x0004003b,0x00000028,0x0000002d,0x00000003,0x0004003b,0x0000002a, + 0x0000002e,0x00000001,0x00040020,0x00000030,0x00000003,0x00000006,0x0004003b,0x00000030, + 0x00000031,0x00000003,0x0004002b,0x0000000b,0x00000032,0x00000001,0x00040020,0x00000033, + 0x00000002,0x00000006,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8, + 0x00000005,0x00050041,0x00000011,0x00000012,0x00000010,0x0000000c,0x0004003d,0x0000000d, + 0x00000013,0x00000012,0x00050041,0x00000017,0x00000018,0x00000016,0x0000000c,0x0004003d, + 0x0000000d,0x00000019,0x00000018,0x00050092,0x0000000d,0x0000001a,0x00000013,0x00000019, + 0x0004003d,0x0000001b,0x0000001e,0x0000001d,0x00050051,0x00000006,0x00000020,0x0000001e, + 0x00000000,0x00050051,0x00000006,0x00000021,0x0000001e,0x00000001,0x00050051,0x00000006, + 0x00000022,0x0000001e,0x00000002,0x00070050,0x00000007,0x00000023,0x00000020,0x00000021, + 0x00000022,0x0000001f,0x00050091,0x00000007,0x00000024,0x0000001a,0x00000023,0x00050041, + 0x00000025,0x00000026,0x0000000a,0x0000000c,0x0003003e,0x00000026,0x00000024,0x0004003d, + 0x00000027,0x0000002c,0x0000002b,0x0003003e,0x00000029,0x0000002c,0x0004003d,0x00000027, + 0x0000002f,0x0000002e,0x0003003e,0x0000002d,0x0000002f,0x00050041,0x00000033,0x00000034, + 0x00000016,0x00000032,0x0004003d,0x00000006,0x00000035,0x00000034,0x0003003e,0x00000031, + 0x00000035,0x000100fd,0x00010038 +}; \ No newline at end of file diff --git a/src/vk/spirv/polygon_vert.c b/src/vk/spirv/polygon_vert.c new file mode 100644 index 0000000..e7bc662 --- /dev/null +++ b/src/vk/spirv/polygon_vert.c @@ -0,0 +1,51 @@ + // 8.13.3559 + #pragma once +const uint32_t polygon_vert_spv[] = { + 0x07230203,0x00010000,0x00080008,0x00000030,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x000b000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000a,0x00000016,0x00000022, + 0x00000024,0x00000026,0x0000002e,0x00030003,0x00000002,0x000001c2,0x00090004,0x415f4c47, + 0x735f4252,0x72617065,0x5f657461,0x64616873,0x6f5f7265,0x63656a62,0x00007374,0x00040005, + 0x00000004,0x6e69616d,0x00000000,0x00060005,0x00000008,0x505f6c67,0x65567265,0x78657472, + 0x00000000,0x00060006,0x00000008,0x00000000,0x505f6c67,0x7469736f,0x006e6f69,0x00030005, + 0x0000000a,0x00000000,0x00060005,0x0000000e,0x68737550,0x736e6f43,0x746e6174,0x00000000, + 0x00060006,0x0000000e,0x00000000,0x4d70766d,0x69727461,0x00000078,0x00030005,0x00000010, + 0x00006370,0x00050005,0x00000016,0x65566e69,0x78657472,0x00000000,0x00050005,0x00000022, + 0x43786574,0x64726f6f,0x00000000,0x00050005,0x00000024,0x65546e69,0x6f6f4378,0x00006472, + 0x00040005,0x00000026,0x6f6c6f63,0x00000072,0x00070005,0x00000027,0x66696e55,0x426d726f, + 0x65666675,0x6a624f72,0x00746365,0x00050006,0x00000027,0x00000000,0x6f6c6f63,0x00000072, + 0x00030005,0x00000029,0x006f6275,0x00050005,0x0000002e,0x65725461,0x6c6f6873,0x00000064, + 0x00050048,0x00000008,0x00000000,0x0000000b,0x00000000,0x00030047,0x00000008,0x00000002, + 0x00040048,0x0000000e,0x00000000,0x00000005,0x00050048,0x0000000e,0x00000000,0x00000023, + 0x00000000,0x00050048,0x0000000e,0x00000000,0x00000007,0x00000010,0x00030047,0x0000000e, + 0x00000002,0x00040047,0x00000016,0x0000001e,0x00000000,0x00040047,0x00000022,0x0000001e, + 0x00000000,0x00040047,0x00000024,0x0000001e,0x00000001,0x00040047,0x00000026,0x0000001e, + 0x00000001,0x00050048,0x00000027,0x00000000,0x00000023,0x00000000,0x00030047,0x00000027, + 0x00000002,0x00040047,0x00000029,0x00000022,0x00000001,0x00040047,0x00000029,0x00000021, + 0x00000000,0x00040047,0x0000002e,0x0000001e,0x00000002,0x00020013,0x00000002,0x00030021, + 0x00000003,0x00000002,0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,0x00000006, + 0x00000004,0x0003001e,0x00000008,0x00000007,0x00040020,0x00000009,0x00000003,0x00000008, + 0x0004003b,0x00000009,0x0000000a,0x00000003,0x00040015,0x0000000b,0x00000020,0x00000001, + 0x0004002b,0x0000000b,0x0000000c,0x00000000,0x00040018,0x0000000d,0x00000007,0x00000004, + 0x0003001e,0x0000000e,0x0000000d,0x00040020,0x0000000f,0x00000009,0x0000000e,0x0004003b, + 0x0000000f,0x00000010,0x00000009,0x00040020,0x00000011,0x00000009,0x0000000d,0x00040017, + 0x00000014,0x00000006,0x00000003,0x00040020,0x00000015,0x00000001,0x00000014,0x0004003b, + 0x00000015,0x00000016,0x00000001,0x0004002b,0x00000006,0x00000018,0x3f800000,0x00040020, + 0x0000001e,0x00000003,0x00000007,0x00040017,0x00000020,0x00000006,0x00000002,0x00040020, + 0x00000021,0x00000003,0x00000020,0x0004003b,0x00000021,0x00000022,0x00000003,0x00040020, + 0x00000023,0x00000001,0x00000020,0x0004003b,0x00000023,0x00000024,0x00000001,0x0004003b, + 0x0000001e,0x00000026,0x00000003,0x0003001e,0x00000027,0x00000007,0x00040020,0x00000028, + 0x00000002,0x00000027,0x0004003b,0x00000028,0x00000029,0x00000002,0x00040020,0x0000002a, + 0x00000002,0x00000007,0x00040020,0x0000002d,0x00000003,0x00000006,0x0004003b,0x0000002d, + 0x0000002e,0x00000003,0x0004002b,0x00000006,0x0000002f,0x00000000,0x00050036,0x00000002, + 0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x00050041,0x00000011,0x00000012, + 0x00000010,0x0000000c,0x0004003d,0x0000000d,0x00000013,0x00000012,0x0004003d,0x00000014, + 0x00000017,0x00000016,0x00050051,0x00000006,0x00000019,0x00000017,0x00000000,0x00050051, + 0x00000006,0x0000001a,0x00000017,0x00000001,0x00050051,0x00000006,0x0000001b,0x00000017, + 0x00000002,0x00070050,0x00000007,0x0000001c,0x00000019,0x0000001a,0x0000001b,0x00000018, + 0x00050091,0x00000007,0x0000001d,0x00000013,0x0000001c,0x00050041,0x0000001e,0x0000001f, + 0x0000000a,0x0000000c,0x0003003e,0x0000001f,0x0000001d,0x0004003d,0x00000020,0x00000025, + 0x00000024,0x0003003e,0x00000022,0x00000025,0x00050041,0x0000002a,0x0000002b,0x00000029, + 0x0000000c,0x0004003d,0x00000007,0x0000002c,0x0000002b,0x0003003e,0x00000026,0x0000002c, + 0x0003003e,0x0000002e,0x0000002f,0x000100fd,0x00010038 +}; \ No newline at end of file diff --git a/src/vk/spirv/polygon_warp_vert.c b/src/vk/spirv/polygon_warp_vert.c new file mode 100644 index 0000000..b1127ae --- /dev/null +++ b/src/vk/spirv/polygon_warp_vert.c @@ -0,0 +1,80 @@ + // 8.13.3559 + #pragma once +const uint32_t polygon_warp_vert_spv[] = { + 0x07230203,0x00010000,0x00080008,0x00000058,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x000b000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000a,0x0000001d,0x00000029, + 0x0000002b,0x00000051,0x00000056,0x00030003,0x00000002,0x000001c2,0x00090004,0x415f4c47, + 0x735f4252,0x72617065,0x5f657461,0x64616873,0x6f5f7265,0x63656a62,0x00007374,0x00040005, + 0x00000004,0x6e69616d,0x00000000,0x00060005,0x00000008,0x505f6c67,0x65567265,0x78657472, + 0x00000000,0x00060006,0x00000008,0x00000000,0x505f6c67,0x7469736f,0x006e6f69,0x00030005, + 0x0000000a,0x00000000,0x00060005,0x0000000e,0x68737550,0x736e6f43,0x746e6174,0x00000000, + 0x00060006,0x0000000e,0x00000000,0x614d7076,0x78697274,0x00000000,0x00030005,0x00000010, + 0x00006370,0x00070005,0x00000014,0x66696e55,0x426d726f,0x65666675,0x6a624f72,0x00746365, + 0x00050006,0x00000014,0x00000000,0x65646f6d,0x0000006c,0x00050006,0x00000014,0x00000001, + 0x6f6c6f63,0x00000072,0x00050006,0x00000014,0x00000002,0x656d6974,0x00000000,0x00050006, + 0x00000014,0x00000003,0x6f726373,0x00006c6c,0x00030005,0x00000016,0x006f6275,0x00050005, + 0x0000001d,0x65566e69,0x78657472,0x00000000,0x00050005,0x00000029,0x43786574,0x64726f6f, + 0x00000000,0x00050005,0x0000002b,0x65546e69,0x6f6f4378,0x00006472,0x00040005,0x00000051, + 0x6f6c6f63,0x00000072,0x00050005,0x00000056,0x65725461,0x6c6f6873,0x00000064,0x00050048, + 0x00000008,0x00000000,0x0000000b,0x00000000,0x00030047,0x00000008,0x00000002,0x00040048, + 0x0000000e,0x00000000,0x00000005,0x00050048,0x0000000e,0x00000000,0x00000023,0x00000000, + 0x00050048,0x0000000e,0x00000000,0x00000007,0x00000010,0x00030047,0x0000000e,0x00000002, + 0x00040048,0x00000014,0x00000000,0x00000005,0x00050048,0x00000014,0x00000000,0x00000023, + 0x00000000,0x00050048,0x00000014,0x00000000,0x00000007,0x00000010,0x00050048,0x00000014, + 0x00000001,0x00000023,0x00000040,0x00050048,0x00000014,0x00000002,0x00000023,0x00000050, + 0x00050048,0x00000014,0x00000003,0x00000023,0x00000054,0x00030047,0x00000014,0x00000002, + 0x00040047,0x00000016,0x00000022,0x00000001,0x00040047,0x00000016,0x00000021,0x00000000, + 0x00040047,0x0000001d,0x0000001e,0x00000000,0x00040047,0x00000029,0x0000001e,0x00000000, + 0x00040047,0x0000002b,0x0000001e,0x00000001,0x00040047,0x00000051,0x0000001e,0x00000001, + 0x00040047,0x00000056,0x0000001e,0x00000002,0x00020013,0x00000002,0x00030021,0x00000003, + 0x00000002,0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000004, + 0x0003001e,0x00000008,0x00000007,0x00040020,0x00000009,0x00000003,0x00000008,0x0004003b, + 0x00000009,0x0000000a,0x00000003,0x00040015,0x0000000b,0x00000020,0x00000001,0x0004002b, + 0x0000000b,0x0000000c,0x00000000,0x00040018,0x0000000d,0x00000007,0x00000004,0x0003001e, + 0x0000000e,0x0000000d,0x00040020,0x0000000f,0x00000009,0x0000000e,0x0004003b,0x0000000f, + 0x00000010,0x00000009,0x00040020,0x00000011,0x00000009,0x0000000d,0x0006001e,0x00000014, + 0x0000000d,0x00000007,0x00000006,0x00000006,0x00040020,0x00000015,0x00000002,0x00000014, + 0x0004003b,0x00000015,0x00000016,0x00000002,0x00040020,0x00000017,0x00000002,0x0000000d, + 0x00040017,0x0000001b,0x00000006,0x00000003,0x00040020,0x0000001c,0x00000001,0x0000001b, + 0x0004003b,0x0000001c,0x0000001d,0x00000001,0x0004002b,0x00000006,0x0000001f,0x3f800000, + 0x00040020,0x00000025,0x00000003,0x00000007,0x00040017,0x00000027,0x00000006,0x00000002, + 0x00040020,0x00000028,0x00000003,0x00000027,0x0004003b,0x00000028,0x00000029,0x00000003, + 0x00040020,0x0000002a,0x00000001,0x00000027,0x0004003b,0x0000002a,0x0000002b,0x00000001, + 0x0004002b,0x00000006,0x0000002d,0x40000000,0x0004002b,0x0000000b,0x0000002e,0x00000002, + 0x00040020,0x0000002f,0x00000002,0x00000006,0x00040015,0x00000033,0x00000020,0x00000000, + 0x0004002b,0x00000033,0x00000034,0x00000001,0x00040020,0x00000035,0x00000001,0x00000006, + 0x0004002b,0x00000006,0x00000038,0x4051eb85,0x0004002b,0x00000033,0x0000003f,0x00000000, + 0x0004002b,0x00000006,0x00000046,0x3d4ccccd,0x0004002b,0x0000000b,0x00000049,0x00000003, + 0x00040020,0x0000004c,0x00000003,0x00000006,0x0004003b,0x00000025,0x00000051,0x00000003, + 0x0004002b,0x0000000b,0x00000052,0x00000001,0x00040020,0x00000053,0x00000002,0x00000007, + 0x0004003b,0x0000004c,0x00000056,0x00000003,0x0004002b,0x00000006,0x00000057,0x00000000, + 0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x00050041, + 0x00000011,0x00000012,0x00000010,0x0000000c,0x0004003d,0x0000000d,0x00000013,0x00000012, + 0x00050041,0x00000017,0x00000018,0x00000016,0x0000000c,0x0004003d,0x0000000d,0x00000019, + 0x00000018,0x00050092,0x0000000d,0x0000001a,0x00000013,0x00000019,0x0004003d,0x0000001b, + 0x0000001e,0x0000001d,0x00050051,0x00000006,0x00000020,0x0000001e,0x00000000,0x00050051, + 0x00000006,0x00000021,0x0000001e,0x00000001,0x00050051,0x00000006,0x00000022,0x0000001e, + 0x00000002,0x00070050,0x00000007,0x00000023,0x00000020,0x00000021,0x00000022,0x0000001f, + 0x00050091,0x00000007,0x00000024,0x0000001a,0x00000023,0x00050041,0x00000025,0x00000026, + 0x0000000a,0x0000000c,0x0003003e,0x00000026,0x00000024,0x0004003d,0x00000027,0x0000002c, + 0x0000002b,0x00050041,0x0000002f,0x00000030,0x00000016,0x0000002e,0x0004003d,0x00000006, + 0x00000031,0x00000030,0x00050085,0x00000006,0x00000032,0x0000002d,0x00000031,0x00050041, + 0x00000035,0x00000036,0x0000002b,0x00000034,0x0004003d,0x00000006,0x00000037,0x00000036, + 0x00050085,0x00000006,0x00000039,0x00000037,0x00000038,0x00050081,0x00000006,0x0000003a, + 0x00000032,0x00000039,0x0006000c,0x00000006,0x0000003b,0x00000001,0x0000000d,0x0000003a, + 0x00050041,0x0000002f,0x0000003c,0x00000016,0x0000002e,0x0004003d,0x00000006,0x0000003d, + 0x0000003c,0x00050085,0x00000006,0x0000003e,0x0000002d,0x0000003d,0x00050041,0x00000035, + 0x00000040,0x0000002b,0x0000003f,0x0004003d,0x00000006,0x00000041,0x00000040,0x00050085, + 0x00000006,0x00000042,0x00000041,0x00000038,0x00050081,0x00000006,0x00000043,0x0000003e, + 0x00000042,0x0006000c,0x00000006,0x00000044,0x00000001,0x0000000d,0x00000043,0x00050050, + 0x00000027,0x00000045,0x0000003b,0x00000044,0x0005008e,0x00000027,0x00000047,0x00000045, + 0x00000046,0x00050081,0x00000027,0x00000048,0x0000002c,0x00000047,0x0003003e,0x00000029, + 0x00000048,0x00050041,0x0000002f,0x0000004a,0x00000016,0x00000049,0x0004003d,0x00000006, + 0x0000004b,0x0000004a,0x00050041,0x0000004c,0x0000004d,0x00000029,0x0000003f,0x0004003d, + 0x00000006,0x0000004e,0x0000004d,0x00050081,0x00000006,0x0000004f,0x0000004e,0x0000004b, + 0x00050041,0x0000004c,0x00000050,0x00000029,0x0000003f,0x0003003e,0x00000050,0x0000004f, + 0x00050041,0x00000053,0x00000054,0x00000016,0x00000052,0x0004003d,0x00000007,0x00000055, + 0x00000054,0x0003003e,0x00000051,0x00000055,0x0003003e,0x00000056,0x00000057,0x000100fd, + 0x00010038 +}; \ No newline at end of file diff --git a/src/vk/spirv/postprocess_frag.c b/src/vk/spirv/postprocess_frag.c new file mode 100644 index 0000000..7196d32 --- /dev/null +++ b/src/vk/spirv/postprocess_frag.c @@ -0,0 +1,64 @@ + // 1011.0.0 + #pragma once +const uint32_t postprocess_frag_spv[] = { + 0x07230203,0x00010000,0x0008000a,0x00000046,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x0000000b,0x0000002c,0x00030010, + 0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00090004,0x415f4c47,0x735f4252, + 0x72617065,0x5f657461,0x64616873,0x6f5f7265,0x63656a62,0x00007374,0x00040005,0x00000004, + 0x6e69616d,0x00000000,0x00060005,0x00000009,0x6f6e6e75,0x65546d72,0x6f6f4378,0x00006472, + 0x00050005,0x0000000b,0x43786574,0x64726f6f,0x00000000,0x00060005,0x0000000d,0x68737550, + 0x736e6f43,0x746e6174,0x00000000,0x00060006,0x0000000d,0x00000000,0x74736f70,0x636f7270, + 0x00737365,0x00050006,0x0000000d,0x00000001,0x6d6d6167,0x00000061,0x00060006,0x0000000d, + 0x00000002,0x57726373,0x68746469,0x00000000,0x00060006,0x0000000d,0x00000003,0x48726373, + 0x68676965,0x00000074,0x00050006,0x0000000d,0x00000004,0x7366666f,0x00587465,0x00050006, + 0x0000000d,0x00000005,0x7366666f,0x00597465,0x00030005,0x0000000f,0x00006370,0x00060005, + 0x0000002c,0x67617266,0x746e656d,0x6f6c6f43,0x00000072,0x00050005,0x00000030,0x78655473, + 0x65727574,0x00000000,0x00040047,0x0000000b,0x0000001e,0x00000000,0x00050048,0x0000000d, + 0x00000000,0x00000023,0x00000044,0x00050048,0x0000000d,0x00000001,0x00000023,0x00000048, + 0x00050048,0x0000000d,0x00000002,0x00000023,0x0000004c,0x00050048,0x0000000d,0x00000003, + 0x00000023,0x00000050,0x00050048,0x0000000d,0x00000004,0x00000023,0x00000054,0x00050048, + 0x0000000d,0x00000005,0x00000023,0x00000058,0x00030047,0x0000000d,0x00000002,0x00040047, + 0x0000002c,0x0000001e,0x00000000,0x00040047,0x00000030,0x00000022,0x00000000,0x00040047, + 0x00000030,0x00000021,0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002, + 0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000002,0x00040020, + 0x00000008,0x00000007,0x00000007,0x00040020,0x0000000a,0x00000001,0x00000007,0x0004003b, + 0x0000000a,0x0000000b,0x00000001,0x0008001e,0x0000000d,0x00000006,0x00000006,0x00000006, + 0x00000006,0x00000006,0x00000006,0x00040020,0x0000000e,0x00000009,0x0000000d,0x0004003b, + 0x0000000e,0x0000000f,0x00000009,0x00040015,0x00000010,0x00000020,0x00000001,0x0004002b, + 0x00000010,0x00000011,0x00000002,0x00040020,0x00000012,0x00000009,0x00000006,0x0004002b, + 0x00000010,0x00000015,0x00000003,0x0004002b,0x00000010,0x0000001a,0x00000004,0x0004002b, + 0x00000010,0x0000001d,0x00000005,0x0004002b,0x00000010,0x00000022,0x00000000,0x0004002b, + 0x00000006,0x00000025,0x00000000,0x00020014,0x00000026,0x00040017,0x0000002a,0x00000006, + 0x00000004,0x00040020,0x0000002b,0x00000003,0x0000002a,0x0004003b,0x0000002b,0x0000002c, + 0x00000003,0x00090019,0x0000002d,0x00000006,0x00000001,0x00000000,0x00000000,0x00000000, + 0x00000001,0x00000000,0x0003001b,0x0000002e,0x0000002d,0x00040020,0x0000002f,0x00000000, + 0x0000002e,0x0004003b,0x0000002f,0x00000030,0x00000000,0x00040017,0x00000034,0x00000006, + 0x00000003,0x0004002b,0x00000006,0x00000036,0x3fc00000,0x0004002b,0x00000010,0x00000038, + 0x00000001,0x0004002b,0x00000006,0x0000003d,0x3f800000,0x00050036,0x00000002,0x00000004, + 0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000008,0x00000009,0x00000007, + 0x0004003d,0x00000007,0x0000000c,0x0000000b,0x00050041,0x00000012,0x00000013,0x0000000f, + 0x00000011,0x0004003d,0x00000006,0x00000014,0x00000013,0x00050041,0x00000012,0x00000016, + 0x0000000f,0x00000015,0x0004003d,0x00000006,0x00000017,0x00000016,0x00050050,0x00000007, + 0x00000018,0x00000014,0x00000017,0x00050085,0x00000007,0x00000019,0x0000000c,0x00000018, + 0x00050041,0x00000012,0x0000001b,0x0000000f,0x0000001a,0x0004003d,0x00000006,0x0000001c, + 0x0000001b,0x00050041,0x00000012,0x0000001e,0x0000000f,0x0000001d,0x0004003d,0x00000006, + 0x0000001f,0x0000001e,0x00050050,0x00000007,0x00000020,0x0000001c,0x0000001f,0x00050081, + 0x00000007,0x00000021,0x00000019,0x00000020,0x0003003e,0x00000009,0x00000021,0x00050041, + 0x00000012,0x00000023,0x0000000f,0x00000022,0x0004003d,0x00000006,0x00000024,0x00000023, + 0x000500ba,0x00000026,0x00000027,0x00000024,0x00000025,0x000300f7,0x00000029,0x00000000, + 0x000400fa,0x00000027,0x00000028,0x00000042,0x000200f8,0x00000028,0x0004003d,0x0000002e, + 0x00000031,0x00000030,0x0004003d,0x00000007,0x00000032,0x00000009,0x00070058,0x0000002a, + 0x00000033,0x00000031,0x00000032,0x00000002,0x00000025,0x0008004f,0x00000034,0x00000035, + 0x00000033,0x00000033,0x00000000,0x00000001,0x00000002,0x0005008e,0x00000034,0x00000037, + 0x00000035,0x00000036,0x00050041,0x00000012,0x00000039,0x0000000f,0x00000038,0x0004003d, + 0x00000006,0x0000003a,0x00000039,0x00060050,0x00000034,0x0000003b,0x0000003a,0x0000003a, + 0x0000003a,0x0007000c,0x00000034,0x0000003c,0x00000001,0x0000001a,0x00000037,0x0000003b, + 0x00050051,0x00000006,0x0000003e,0x0000003c,0x00000000,0x00050051,0x00000006,0x0000003f, + 0x0000003c,0x00000001,0x00050051,0x00000006,0x00000040,0x0000003c,0x00000002,0x00070050, + 0x0000002a,0x00000041,0x0000003e,0x0000003f,0x00000040,0x0000003d,0x0003003e,0x0000002c, + 0x00000041,0x000200f9,0x00000029,0x000200f8,0x00000042,0x0004003d,0x0000002e,0x00000043, + 0x00000030,0x0004003d,0x00000007,0x00000044,0x00000009,0x00070058,0x0000002a,0x00000045, + 0x00000043,0x00000044,0x00000002,0x00000025,0x0003003e,0x0000002c,0x00000045,0x000200f9, + 0x00000029,0x000200f8,0x00000029,0x000100fd,0x00010038 +}; \ No newline at end of file diff --git a/src/vk/spirv/postprocess_vert.c b/src/vk/spirv/postprocess_vert.c new file mode 100644 index 0000000..7ce9dbe --- /dev/null +++ b/src/vk/spirv/postprocess_vert.c @@ -0,0 +1,36 @@ + // 8.13.3559 + #pragma once +const uint32_t postprocess_vert_spv[] = { + 0x07230203,0x00010000,0x00080008,0x00000029,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0008000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x00000009,0x0000000c,0x0000001a, + 0x00030003,0x00000002,0x000001c2,0x00090004,0x415f4c47,0x735f4252,0x72617065,0x5f657461, + 0x64616873,0x6f5f7265,0x63656a62,0x00007374,0x00040005,0x00000004,0x6e69616d,0x00000000, + 0x00050005,0x00000009,0x43786574,0x64726f6f,0x00000000,0x00060005,0x0000000c,0x565f6c67, + 0x65747265,0x646e4978,0x00007865,0x00060005,0x00000018,0x505f6c67,0x65567265,0x78657472, + 0x00000000,0x00060006,0x00000018,0x00000000,0x505f6c67,0x7469736f,0x006e6f69,0x00030005, + 0x0000001a,0x00000000,0x00040047,0x00000009,0x0000001e,0x00000000,0x00040047,0x0000000c, + 0x0000000b,0x0000002a,0x00050048,0x00000018,0x00000000,0x0000000b,0x00000000,0x00030047, + 0x00000018,0x00000002,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016, + 0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000002,0x00040020,0x00000008, + 0x00000003,0x00000007,0x0004003b,0x00000008,0x00000009,0x00000003,0x00040015,0x0000000a, + 0x00000020,0x00000001,0x00040020,0x0000000b,0x00000001,0x0000000a,0x0004003b,0x0000000b, + 0x0000000c,0x00000001,0x0004002b,0x0000000a,0x0000000e,0x00000001,0x0004002b,0x0000000a, + 0x00000010,0x00000002,0x00040017,0x00000017,0x00000006,0x00000004,0x0003001e,0x00000018, + 0x00000017,0x00040020,0x00000019,0x00000003,0x00000018,0x0004003b,0x00000019,0x0000001a, + 0x00000003,0x0004002b,0x0000000a,0x0000001b,0x00000000,0x0004002b,0x00000006,0x0000001d, + 0x40000000,0x0004002b,0x00000006,0x0000001f,0xbf800000,0x0004002b,0x00000006,0x00000022, + 0x00000000,0x0004002b,0x00000006,0x00000023,0x3f800000,0x00040020,0x00000027,0x00000003, + 0x00000017,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005, + 0x0004003d,0x0000000a,0x0000000d,0x0000000c,0x000500c4,0x0000000a,0x0000000f,0x0000000d, + 0x0000000e,0x000500c7,0x0000000a,0x00000011,0x0000000f,0x00000010,0x0004006f,0x00000006, + 0x00000012,0x00000011,0x0004003d,0x0000000a,0x00000013,0x0000000c,0x000500c7,0x0000000a, + 0x00000014,0x00000013,0x00000010,0x0004006f,0x00000006,0x00000015,0x00000014,0x00050050, + 0x00000007,0x00000016,0x00000012,0x00000015,0x0003003e,0x00000009,0x00000016,0x0004003d, + 0x00000007,0x0000001c,0x00000009,0x0005008e,0x00000007,0x0000001e,0x0000001c,0x0000001d, + 0x00050050,0x00000007,0x00000020,0x0000001f,0x0000001f,0x00050081,0x00000007,0x00000021, + 0x0000001e,0x00000020,0x00050051,0x00000006,0x00000024,0x00000021,0x00000000,0x00050051, + 0x00000006,0x00000025,0x00000021,0x00000001,0x00070050,0x00000017,0x00000026,0x00000024, + 0x00000025,0x00000022,0x00000023,0x00050041,0x00000027,0x00000028,0x0000001a,0x0000001b, + 0x0003003e,0x00000028,0x00000026,0x000100fd,0x00010038 +}; \ No newline at end of file diff --git a/src/vk/spirv/shadows_vert.c b/src/vk/spirv/shadows_vert.c new file mode 100644 index 0000000..5114b8a --- /dev/null +++ b/src/vk/spirv/shadows_vert.c @@ -0,0 +1,46 @@ + // 8.13.3559 + #pragma once +const uint32_t shadows_vert_spv[] = { + 0x07230203,0x00010000,0x00080008,0x0000002b,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0008000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000a,0x0000001d,0x00000027, + 0x00030003,0x00000002,0x000001c2,0x00090004,0x415f4c47,0x735f4252,0x72617065,0x5f657461, + 0x64616873,0x6f5f7265,0x63656a62,0x00007374,0x00040005,0x00000004,0x6e69616d,0x00000000, + 0x00060005,0x00000008,0x505f6c67,0x65567265,0x78657472,0x00000000,0x00060006,0x00000008, + 0x00000000,0x505f6c67,0x7469736f,0x006e6f69,0x00030005,0x0000000a,0x00000000,0x00060005, + 0x0000000e,0x68737550,0x736e6f43,0x746e6174,0x00000000,0x00060006,0x0000000e,0x00000000, + 0x614d7076,0x78697274,0x00000000,0x00030005,0x00000010,0x00006370,0x00070005,0x00000014, + 0x66696e55,0x426d726f,0x65666675,0x6a624f72,0x00746365,0x00050006,0x00000014,0x00000000, + 0x65646f6d,0x0000006c,0x00030005,0x00000016,0x006f6275,0x00050005,0x0000001d,0x65566e69, + 0x78657472,0x00000000,0x00040005,0x00000027,0x6f6c6f63,0x00000072,0x00050048,0x00000008, + 0x00000000,0x0000000b,0x00000000,0x00030047,0x00000008,0x00000002,0x00040048,0x0000000e, + 0x00000000,0x00000005,0x00050048,0x0000000e,0x00000000,0x00000023,0x00000000,0x00050048, + 0x0000000e,0x00000000,0x00000007,0x00000010,0x00030047,0x0000000e,0x00000002,0x00040048, + 0x00000014,0x00000000,0x00000005,0x00050048,0x00000014,0x00000000,0x00000023,0x00000000, + 0x00050048,0x00000014,0x00000000,0x00000007,0x00000010,0x00030047,0x00000014,0x00000002, + 0x00040047,0x00000016,0x00000022,0x00000000,0x00040047,0x00000016,0x00000021,0x00000000, + 0x00040047,0x0000001d,0x0000001e,0x00000000,0x00040047,0x00000027,0x0000001e,0x00000000, + 0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,0x00000020, + 0x00040017,0x00000007,0x00000006,0x00000004,0x0003001e,0x00000008,0x00000007,0x00040020, + 0x00000009,0x00000003,0x00000008,0x0004003b,0x00000009,0x0000000a,0x00000003,0x00040015, + 0x0000000b,0x00000020,0x00000001,0x0004002b,0x0000000b,0x0000000c,0x00000000,0x00040018, + 0x0000000d,0x00000007,0x00000004,0x0003001e,0x0000000e,0x0000000d,0x00040020,0x0000000f, + 0x00000009,0x0000000e,0x0004003b,0x0000000f,0x00000010,0x00000009,0x00040020,0x00000011, + 0x00000009,0x0000000d,0x0003001e,0x00000014,0x0000000d,0x00040020,0x00000015,0x00000002, + 0x00000014,0x0004003b,0x00000015,0x00000016,0x00000002,0x00040020,0x00000017,0x00000002, + 0x0000000d,0x00040017,0x0000001b,0x00000006,0x00000003,0x00040020,0x0000001c,0x00000001, + 0x0000001b,0x0004003b,0x0000001c,0x0000001d,0x00000001,0x0004002b,0x00000006,0x0000001f, + 0x3f800000,0x00040020,0x00000025,0x00000003,0x00000007,0x0004003b,0x00000025,0x00000027, + 0x00000003,0x0004002b,0x00000006,0x00000028,0x00000000,0x0004002b,0x00000006,0x00000029, + 0x3f000000,0x0007002c,0x00000007,0x0000002a,0x00000028,0x00000028,0x00000028,0x00000029, + 0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x00050041, + 0x00000011,0x00000012,0x00000010,0x0000000c,0x0004003d,0x0000000d,0x00000013,0x00000012, + 0x00050041,0x00000017,0x00000018,0x00000016,0x0000000c,0x0004003d,0x0000000d,0x00000019, + 0x00000018,0x00050092,0x0000000d,0x0000001a,0x00000013,0x00000019,0x0004003d,0x0000001b, + 0x0000001e,0x0000001d,0x00050051,0x00000006,0x00000020,0x0000001e,0x00000000,0x00050051, + 0x00000006,0x00000021,0x0000001e,0x00000001,0x00050051,0x00000006,0x00000022,0x0000001e, + 0x00000002,0x00070050,0x00000007,0x00000023,0x00000020,0x00000021,0x00000022,0x0000001f, + 0x00050091,0x00000007,0x00000024,0x0000001a,0x00000023,0x00050041,0x00000025,0x00000026, + 0x0000000a,0x0000000c,0x0003003e,0x00000026,0x00000024,0x0003003e,0x00000027,0x0000002a, + 0x000100fd,0x00010038 +}; \ No newline at end of file diff --git a/src/vk/spirv/skybox_vert.c b/src/vk/spirv/skybox_vert.c new file mode 100644 index 0000000..2797070 --- /dev/null +++ b/src/vk/spirv/skybox_vert.c @@ -0,0 +1,54 @@ + // 8.13.3559 + #pragma once +const uint32_t skybox_vert_spv[] = { + 0x07230203,0x00010000,0x00080008,0x00000032,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x000b000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000a,0x0000001d,0x00000029, + 0x0000002b,0x0000002d,0x00000030,0x00030003,0x00000002,0x000001c2,0x00090004,0x415f4c47, + 0x735f4252,0x72617065,0x5f657461,0x64616873,0x6f5f7265,0x63656a62,0x00007374,0x00040005, + 0x00000004,0x6e69616d,0x00000000,0x00060005,0x00000008,0x505f6c67,0x65567265,0x78657472, + 0x00000000,0x00060006,0x00000008,0x00000000,0x505f6c67,0x7469736f,0x006e6f69,0x00030005, + 0x0000000a,0x00000000,0x00060005,0x0000000e,0x68737550,0x736e6f43,0x746e6174,0x00000000, + 0x00060006,0x0000000e,0x00000000,0x614d7076,0x78697274,0x00000000,0x00030005,0x00000010, + 0x00006370,0x00070005,0x00000014,0x66696e55,0x426d726f,0x65666675,0x6a624f72,0x00746365, + 0x00050006,0x00000014,0x00000000,0x65646f6d,0x0000006c,0x00030005,0x00000016,0x006f6275, + 0x00050005,0x0000001d,0x65566e69,0x78657472,0x00000000,0x00050005,0x00000029,0x43786574, + 0x64726f6f,0x00000000,0x00050005,0x0000002b,0x65546e69,0x6f6f4378,0x00006472,0x00040005, + 0x0000002d,0x6f6c6f63,0x00000072,0x00050005,0x00000030,0x65725461,0x6c6f6873,0x00000064, + 0x00050048,0x00000008,0x00000000,0x0000000b,0x00000000,0x00030047,0x00000008,0x00000002, + 0x00040048,0x0000000e,0x00000000,0x00000005,0x00050048,0x0000000e,0x00000000,0x00000023, + 0x00000000,0x00050048,0x0000000e,0x00000000,0x00000007,0x00000010,0x00030047,0x0000000e, + 0x00000002,0x00040048,0x00000014,0x00000000,0x00000005,0x00050048,0x00000014,0x00000000, + 0x00000023,0x00000000,0x00050048,0x00000014,0x00000000,0x00000007,0x00000010,0x00030047, + 0x00000014,0x00000002,0x00040047,0x00000016,0x00000022,0x00000001,0x00040047,0x00000016, + 0x00000021,0x00000000,0x00040047,0x0000001d,0x0000001e,0x00000000,0x00040047,0x00000029, + 0x0000001e,0x00000000,0x00040047,0x0000002b,0x0000001e,0x00000001,0x00040047,0x0000002d, + 0x0000001e,0x00000001,0x00040047,0x00000030,0x0000001e,0x00000002,0x00020013,0x00000002, + 0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,0x00000020,0x00040017,0x00000007, + 0x00000006,0x00000004,0x0003001e,0x00000008,0x00000007,0x00040020,0x00000009,0x00000003, + 0x00000008,0x0004003b,0x00000009,0x0000000a,0x00000003,0x00040015,0x0000000b,0x00000020, + 0x00000001,0x0004002b,0x0000000b,0x0000000c,0x00000000,0x00040018,0x0000000d,0x00000007, + 0x00000004,0x0003001e,0x0000000e,0x0000000d,0x00040020,0x0000000f,0x00000009,0x0000000e, + 0x0004003b,0x0000000f,0x00000010,0x00000009,0x00040020,0x00000011,0x00000009,0x0000000d, + 0x0003001e,0x00000014,0x0000000d,0x00040020,0x00000015,0x00000002,0x00000014,0x0004003b, + 0x00000015,0x00000016,0x00000002,0x00040020,0x00000017,0x00000002,0x0000000d,0x00040017, + 0x0000001b,0x00000006,0x00000003,0x00040020,0x0000001c,0x00000001,0x0000001b,0x0004003b, + 0x0000001c,0x0000001d,0x00000001,0x0004002b,0x00000006,0x0000001f,0x3f800000,0x00040020, + 0x00000025,0x00000003,0x00000007,0x00040017,0x00000027,0x00000006,0x00000002,0x00040020, + 0x00000028,0x00000003,0x00000027,0x0004003b,0x00000028,0x00000029,0x00000003,0x00040020, + 0x0000002a,0x00000001,0x00000027,0x0004003b,0x0000002a,0x0000002b,0x00000001,0x0004003b, + 0x00000025,0x0000002d,0x00000003,0x0007002c,0x00000007,0x0000002e,0x0000001f,0x0000001f, + 0x0000001f,0x0000001f,0x00040020,0x0000002f,0x00000003,0x00000006,0x0004003b,0x0000002f, + 0x00000030,0x00000003,0x0004002b,0x00000006,0x00000031,0x00000000,0x00050036,0x00000002, + 0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x00050041,0x00000011,0x00000012, + 0x00000010,0x0000000c,0x0004003d,0x0000000d,0x00000013,0x00000012,0x00050041,0x00000017, + 0x00000018,0x00000016,0x0000000c,0x0004003d,0x0000000d,0x00000019,0x00000018,0x00050092, + 0x0000000d,0x0000001a,0x00000013,0x00000019,0x0004003d,0x0000001b,0x0000001e,0x0000001d, + 0x00050051,0x00000006,0x00000020,0x0000001e,0x00000000,0x00050051,0x00000006,0x00000021, + 0x0000001e,0x00000001,0x00050051,0x00000006,0x00000022,0x0000001e,0x00000002,0x00070050, + 0x00000007,0x00000023,0x00000020,0x00000021,0x00000022,0x0000001f,0x00050091,0x00000007, + 0x00000024,0x0000001a,0x00000023,0x00050041,0x00000025,0x00000026,0x0000000a,0x0000000c, + 0x0003003e,0x00000026,0x00000024,0x0004003d,0x00000027,0x0000002c,0x0000002b,0x0003003e, + 0x00000029,0x0000002c,0x0003003e,0x0000002d,0x0000002e,0x0003003e,0x00000030,0x00000031, + 0x000100fd,0x00010038 +}; \ No newline at end of file diff --git a/src/vk/spirv/sprite_vert.c b/src/vk/spirv/sprite_vert.c new file mode 100644 index 0000000..090a158 --- /dev/null +++ b/src/vk/spirv/sprite_vert.c @@ -0,0 +1,49 @@ + // 8.13.3559 + #pragma once +const uint32_t sprite_vert_spv[] = { + 0x07230203,0x00010000,0x00080008,0x0000002f,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x000b000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000a,0x00000016,0x00000022, + 0x00000024,0x00000026,0x0000002d,0x00030003,0x00000002,0x000001c2,0x00090004,0x415f4c47, + 0x735f4252,0x72617065,0x5f657461,0x64616873,0x6f5f7265,0x63656a62,0x00007374,0x00040005, + 0x00000004,0x6e69616d,0x00000000,0x00060005,0x00000008,0x505f6c67,0x65567265,0x78657472, + 0x00000000,0x00060006,0x00000008,0x00000000,0x505f6c67,0x7469736f,0x006e6f69,0x00030005, + 0x0000000a,0x00000000,0x00060005,0x0000000e,0x68737550,0x736e6f43,0x746e6174,0x00000000, + 0x00060006,0x0000000e,0x00000000,0x4d70766d,0x69727461,0x00000078,0x00050006,0x0000000e, + 0x00000001,0x68706c61,0x00000061,0x00030005,0x00000010,0x00006370,0x00050005,0x00000016, + 0x65566e69,0x78657472,0x00000000,0x00050005,0x00000022,0x43786574,0x64726f6f,0x00000000, + 0x00050005,0x00000024,0x65546e69,0x6f6f4378,0x00006472,0x00040005,0x00000026,0x6f6c6f63, + 0x00000072,0x00050005,0x0000002d,0x65725461,0x6c6f6873,0x00000064,0x00050048,0x00000008, + 0x00000000,0x0000000b,0x00000000,0x00030047,0x00000008,0x00000002,0x00040048,0x0000000e, + 0x00000000,0x00000005,0x00050048,0x0000000e,0x00000000,0x00000023,0x00000000,0x00050048, + 0x0000000e,0x00000000,0x00000007,0x00000010,0x00050048,0x0000000e,0x00000001,0x00000023, + 0x00000040,0x00030047,0x0000000e,0x00000002,0x00040047,0x00000016,0x0000001e,0x00000000, + 0x00040047,0x00000022,0x0000001e,0x00000000,0x00040047,0x00000024,0x0000001e,0x00000001, + 0x00040047,0x00000026,0x0000001e,0x00000001,0x00040047,0x0000002d,0x0000001e,0x00000002, + 0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,0x00000020, + 0x00040017,0x00000007,0x00000006,0x00000004,0x0003001e,0x00000008,0x00000007,0x00040020, + 0x00000009,0x00000003,0x00000008,0x0004003b,0x00000009,0x0000000a,0x00000003,0x00040015, + 0x0000000b,0x00000020,0x00000001,0x0004002b,0x0000000b,0x0000000c,0x00000000,0x00040018, + 0x0000000d,0x00000007,0x00000004,0x0004001e,0x0000000e,0x0000000d,0x00000006,0x00040020, + 0x0000000f,0x00000009,0x0000000e,0x0004003b,0x0000000f,0x00000010,0x00000009,0x00040020, + 0x00000011,0x00000009,0x0000000d,0x00040017,0x00000014,0x00000006,0x00000003,0x00040020, + 0x00000015,0x00000001,0x00000014,0x0004003b,0x00000015,0x00000016,0x00000001,0x0004002b, + 0x00000006,0x00000018,0x3f800000,0x00040020,0x0000001e,0x00000003,0x00000007,0x00040017, + 0x00000020,0x00000006,0x00000002,0x00040020,0x00000021,0x00000003,0x00000020,0x0004003b, + 0x00000021,0x00000022,0x00000003,0x00040020,0x00000023,0x00000001,0x00000020,0x0004003b, + 0x00000023,0x00000024,0x00000001,0x0004003b,0x0000001e,0x00000026,0x00000003,0x0004002b, + 0x0000000b,0x00000027,0x00000001,0x00040020,0x00000028,0x00000009,0x00000006,0x00040020, + 0x0000002c,0x00000003,0x00000006,0x0004003b,0x0000002c,0x0000002d,0x00000003,0x0004002b, + 0x00000006,0x0000002e,0x3d886595,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003, + 0x000200f8,0x00000005,0x00050041,0x00000011,0x00000012,0x00000010,0x0000000c,0x0004003d, + 0x0000000d,0x00000013,0x00000012,0x0004003d,0x00000014,0x00000017,0x00000016,0x00050051, + 0x00000006,0x00000019,0x00000017,0x00000000,0x00050051,0x00000006,0x0000001a,0x00000017, + 0x00000001,0x00050051,0x00000006,0x0000001b,0x00000017,0x00000002,0x00070050,0x00000007, + 0x0000001c,0x00000019,0x0000001a,0x0000001b,0x00000018,0x00050091,0x00000007,0x0000001d, + 0x00000013,0x0000001c,0x00050041,0x0000001e,0x0000001f,0x0000000a,0x0000000c,0x0003003e, + 0x0000001f,0x0000001d,0x0004003d,0x00000020,0x00000025,0x00000024,0x0003003e,0x00000022, + 0x00000025,0x00050041,0x00000028,0x00000029,0x00000010,0x00000027,0x0004003d,0x00000006, + 0x0000002a,0x00000029,0x00070050,0x00000007,0x0000002b,0x00000018,0x00000018,0x00000018, + 0x0000002a,0x0003003e,0x00000026,0x0000002b,0x0003003e,0x0000002d,0x0000002e,0x000100fd, + 0x00010038 +}; \ No newline at end of file diff --git a/src/vk/spirv/world_warp_frag.c b/src/vk/spirv/world_warp_frag.c new file mode 100644 index 0000000..0f6ba66 --- /dev/null +++ b/src/vk/spirv/world_warp_frag.c @@ -0,0 +1,154 @@ + // 1011.0.0 + #pragma once +const uint32_t world_warp_frag_spv[] = { + 0x07230203,0x00010000,0x0008000a,0x000000c1,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000019,0x000000b9,0x00030010, + 0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00090004,0x415f4c47,0x735f4252, + 0x72617065,0x5f657461,0x64616873,0x6f5f7265,0x63656a62,0x00007374,0x00040005,0x00000004, + 0x6e69616d,0x00000000,0x00040005,0x00000009,0x53726373,0x00657a69,0x00060005,0x0000000a, + 0x68737550,0x736e6f43,0x746e6174,0x00000000,0x00050006,0x0000000a,0x00000000,0x656d6974, + 0x00000000,0x00050006,0x0000000a,0x00000001,0x6c616373,0x00000065,0x00060006,0x0000000a, + 0x00000002,0x57726373,0x68746469,0x00000000,0x00060006,0x0000000a,0x00000003,0x48726373, + 0x68676965,0x00000074,0x00050006,0x0000000a,0x00000004,0x7366666f,0x00587465,0x00050006, + 0x0000000a,0x00000005,0x7366666f,0x00597465,0x00060006,0x0000000a,0x00000006,0x65786970, + 0x7a69536c,0x00000065,0x00050006,0x0000000a,0x00000007,0x64666572,0x00586665,0x00050006, + 0x0000000a,0x00000008,0x64666572,0x00596665,0x00060006,0x0000000a,0x00000009,0x64666572, + 0x69576665,0x00687464,0x00070006,0x0000000a,0x0000000a,0x64666572,0x65486665,0x74686769, + 0x00000000,0x00030005,0x0000000c,0x00006370,0x00050005,0x00000016,0x67617266,0x726f6f43, + 0x00000064,0x00060005,0x00000019,0x465f6c67,0x43676172,0x64726f6f,0x00000000,0x00030005, + 0x00000024,0x00007675,0x00040005,0x00000029,0x6e694d78,0x00000000,0x00040005,0x0000002d, + 0x78614d78,0x00000000,0x00040005,0x00000034,0x6e694d79,0x00000000,0x00040005,0x00000038, + 0x78614d79,0x00000000,0x00030005,0x00000066,0x00007873,0x00030005,0x00000077,0x00007973, + 0x00040005,0x00000086,0x69685378,0x00007466,0x00040005,0x00000091,0x69685379,0x00007466, + 0x00050005,0x0000009a,0x74736964,0x6974726f,0x00006e6f,0x00060005,0x000000b9,0x67617266, + 0x746e656d,0x6f6c6f43,0x00000072,0x00050005,0x000000bd,0x78655473,0x65727574,0x00000000, + 0x00050048,0x0000000a,0x00000000,0x00000023,0x00000044,0x00050048,0x0000000a,0x00000001, + 0x00000023,0x00000048,0x00050048,0x0000000a,0x00000002,0x00000023,0x0000004c,0x00050048, + 0x0000000a,0x00000003,0x00000023,0x00000050,0x00050048,0x0000000a,0x00000004,0x00000023, + 0x00000054,0x00050048,0x0000000a,0x00000005,0x00000023,0x00000058,0x00050048,0x0000000a, + 0x00000006,0x00000023,0x0000005c,0x00050048,0x0000000a,0x00000007,0x00000023,0x00000060, + 0x00050048,0x0000000a,0x00000008,0x00000023,0x00000064,0x00050048,0x0000000a,0x00000009, + 0x00000023,0x00000068,0x00050048,0x0000000a,0x0000000a,0x00000023,0x0000006c,0x00030047, + 0x0000000a,0x00000002,0x00040047,0x00000019,0x0000000b,0x0000000f,0x00040047,0x000000b9, + 0x0000001e,0x00000000,0x00040047,0x000000bd,0x00000022,0x00000000,0x00040047,0x000000bd, + 0x00000021,0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016, + 0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000002,0x00040020,0x00000008, + 0x00000007,0x00000007,0x000d001e,0x0000000a,0x00000006,0x00000006,0x00000006,0x00000006, + 0x00000006,0x00000006,0x00000006,0x00000006,0x00000006,0x00000006,0x00000006,0x00040020, + 0x0000000b,0x00000009,0x0000000a,0x0004003b,0x0000000b,0x0000000c,0x00000009,0x00040015, + 0x0000000d,0x00000020,0x00000001,0x0004002b,0x0000000d,0x0000000e,0x00000002,0x00040020, + 0x0000000f,0x00000009,0x00000006,0x0004002b,0x0000000d,0x00000012,0x00000003,0x00040017, + 0x00000017,0x00000006,0x00000004,0x00040020,0x00000018,0x00000001,0x00000017,0x0004003b, + 0x00000018,0x00000019,0x00000001,0x0004002b,0x0000000d,0x0000001c,0x00000004,0x0004002b, + 0x0000000d,0x0000001f,0x00000005,0x00040020,0x00000028,0x00000007,0x00000006,0x0004002b, + 0x0000000d,0x0000002a,0x00000007,0x0004002b,0x0000000d,0x00000030,0x00000009,0x0004002b, + 0x0000000d,0x00000035,0x00000008,0x0004002b,0x0000000d,0x0000003b,0x0000000a,0x00020014, + 0x0000003f,0x0004002b,0x0000000d,0x00000040,0x00000000,0x0004002b,0x00000006,0x00000043, + 0x00000000,0x00040015,0x00000047,0x00000020,0x00000000,0x0004002b,0x00000047,0x00000048, + 0x00000000,0x0004002b,0x00000047,0x00000057,0x00000001,0x0004002b,0x0000000d,0x00000067, + 0x00000001,0x0004002b,0x00000006,0x0000006c,0x40000000,0x0004002b,0x00000006,0x0000008c, + 0x40490e56,0x0004002b,0x00000006,0x0000008e,0x41200000,0x0004002b,0x00000006,0x000000a4, + 0x3bda3c21,0x0004002b,0x0000000d,0x000000a9,0x00000006,0x0005002c,0x00000007,0x000000b2, + 0x00000043,0x00000043,0x0004002b,0x00000006,0x000000b4,0x3f000000,0x0005002c,0x00000007, + 0x000000b5,0x000000b4,0x000000b4,0x00040020,0x000000b8,0x00000003,0x00000017,0x0004003b, + 0x000000b8,0x000000b9,0x00000003,0x00090019,0x000000ba,0x00000006,0x00000001,0x00000000, + 0x00000000,0x00000000,0x00000001,0x00000000,0x0003001b,0x000000bb,0x000000ba,0x00040020, + 0x000000bc,0x00000000,0x000000bb,0x0004003b,0x000000bc,0x000000bd,0x00000000,0x00050036, + 0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000008, + 0x00000009,0x00000007,0x0004003b,0x00000008,0x00000016,0x00000007,0x0004003b,0x00000008, + 0x00000024,0x00000007,0x0004003b,0x00000028,0x00000029,0x00000007,0x0004003b,0x00000028, + 0x0000002d,0x00000007,0x0004003b,0x00000028,0x00000034,0x00000007,0x0004003b,0x00000028, + 0x00000038,0x00000007,0x0004003b,0x00000028,0x00000066,0x00000007,0x0004003b,0x00000028, + 0x00000077,0x00000007,0x0004003b,0x00000028,0x00000086,0x00000007,0x0004003b,0x00000028, + 0x00000091,0x00000007,0x0004003b,0x00000008,0x0000009a,0x00000007,0x00050041,0x0000000f, + 0x00000010,0x0000000c,0x0000000e,0x0004003d,0x00000006,0x00000011,0x00000010,0x00050041, + 0x0000000f,0x00000013,0x0000000c,0x00000012,0x0004003d,0x00000006,0x00000014,0x00000013, + 0x00050050,0x00000007,0x00000015,0x00000011,0x00000014,0x0003003e,0x00000009,0x00000015, + 0x0004003d,0x00000017,0x0000001a,0x00000019,0x0007004f,0x00000007,0x0000001b,0x0000001a, + 0x0000001a,0x00000000,0x00000001,0x00050041,0x0000000f,0x0000001d,0x0000000c,0x0000001c, + 0x0004003d,0x00000006,0x0000001e,0x0000001d,0x00050041,0x0000000f,0x00000020,0x0000000c, + 0x0000001f,0x0004003d,0x00000006,0x00000021,0x00000020,0x00050050,0x00000007,0x00000022, + 0x0000001e,0x00000021,0x00050083,0x00000007,0x00000023,0x0000001b,0x00000022,0x0003003e, + 0x00000016,0x00000023,0x0004003d,0x00000007,0x00000025,0x00000016,0x0004003d,0x00000007, + 0x00000026,0x00000009,0x00050088,0x00000007,0x00000027,0x00000025,0x00000026,0x0003003e, + 0x00000024,0x00000027,0x00050041,0x0000000f,0x0000002b,0x0000000c,0x0000002a,0x0004003d, + 0x00000006,0x0000002c,0x0000002b,0x0003003e,0x00000029,0x0000002c,0x00050041,0x0000000f, + 0x0000002e,0x0000000c,0x0000002a,0x0004003d,0x00000006,0x0000002f,0x0000002e,0x00050041, + 0x0000000f,0x00000031,0x0000000c,0x00000030,0x0004003d,0x00000006,0x00000032,0x00000031, + 0x00050081,0x00000006,0x00000033,0x0000002f,0x00000032,0x0003003e,0x0000002d,0x00000033, + 0x00050041,0x0000000f,0x00000036,0x0000000c,0x00000035,0x0004003d,0x00000006,0x00000037, + 0x00000036,0x0003003e,0x00000034,0x00000037,0x00050041,0x0000000f,0x00000039,0x0000000c, + 0x00000035,0x0004003d,0x00000006,0x0000003a,0x00000039,0x00050041,0x0000000f,0x0000003c, + 0x0000000c,0x0000003b,0x0004003d,0x00000006,0x0000003d,0x0000003c,0x00050081,0x00000006, + 0x0000003e,0x0000003a,0x0000003d,0x0003003e,0x00000038,0x0000003e,0x00050041,0x0000000f, + 0x00000041,0x0000000c,0x00000040,0x0004003d,0x00000006,0x00000042,0x00000041,0x000500ba, + 0x0000003f,0x00000044,0x00000042,0x00000043,0x000300f7,0x00000046,0x00000000,0x000400fa, + 0x00000044,0x00000045,0x00000046,0x000200f8,0x00000045,0x00050041,0x00000028,0x00000049, + 0x00000016,0x00000048,0x0004003d,0x00000006,0x0000004a,0x00000049,0x0004003d,0x00000006, + 0x0000004b,0x00000029,0x000500ba,0x0000003f,0x0000004c,0x0000004a,0x0000004b,0x000200f9, + 0x00000046,0x000200f8,0x00000046,0x000700f5,0x0000003f,0x0000004d,0x00000044,0x00000005, + 0x0000004c,0x00000045,0x000300f7,0x0000004f,0x00000000,0x000400fa,0x0000004d,0x0000004e, + 0x0000004f,0x000200f8,0x0000004e,0x00050041,0x00000028,0x00000050,0x00000016,0x00000048, + 0x0004003d,0x00000006,0x00000051,0x00000050,0x0004003d,0x00000006,0x00000052,0x0000002d, + 0x000500b8,0x0000003f,0x00000053,0x00000051,0x00000052,0x000200f9,0x0000004f,0x000200f8, + 0x0000004f,0x000700f5,0x0000003f,0x00000054,0x0000004d,0x00000046,0x00000053,0x0000004e, + 0x000300f7,0x00000056,0x00000000,0x000400fa,0x00000054,0x00000055,0x00000056,0x000200f8, + 0x00000055,0x00050041,0x00000028,0x00000058,0x00000016,0x00000057,0x0004003d,0x00000006, + 0x00000059,0x00000058,0x0004003d,0x00000006,0x0000005a,0x00000034,0x000500ba,0x0000003f, + 0x0000005b,0x00000059,0x0000005a,0x000200f9,0x00000056,0x000200f8,0x00000056,0x000700f5, + 0x0000003f,0x0000005c,0x00000054,0x0000004f,0x0000005b,0x00000055,0x000300f7,0x0000005e, + 0x00000000,0x000400fa,0x0000005c,0x0000005d,0x0000005e,0x000200f8,0x0000005d,0x00050041, + 0x00000028,0x0000005f,0x00000016,0x00000057,0x0004003d,0x00000006,0x00000060,0x0000005f, + 0x0004003d,0x00000006,0x00000061,0x00000038,0x000500b8,0x0000003f,0x00000062,0x00000060, + 0x00000061,0x000200f9,0x0000005e,0x000200f8,0x0000005e,0x000700f5,0x0000003f,0x00000063, + 0x0000005c,0x00000056,0x00000062,0x0000005d,0x000300f7,0x00000065,0x00000000,0x000400fa, + 0x00000063,0x00000064,0x00000065,0x000200f8,0x00000064,0x00050041,0x0000000f,0x00000068, + 0x0000000c,0x00000067,0x0004003d,0x00000006,0x00000069,0x00000068,0x00050041,0x0000000f, + 0x0000006a,0x0000000c,0x0000000e,0x0004003d,0x00000006,0x0000006b,0x0000006a,0x00050088, + 0x00000006,0x0000006d,0x0000006b,0x0000006c,0x00050041,0x00000028,0x0000006e,0x00000016, + 0x00000048,0x0004003d,0x00000006,0x0000006f,0x0000006e,0x00050083,0x00000006,0x00000070, + 0x0000006d,0x0000006f,0x0006000c,0x00000006,0x00000071,0x00000001,0x00000004,0x00000070, + 0x00050085,0x00000006,0x00000072,0x00000071,0x0000006c,0x00050041,0x0000000f,0x00000073, + 0x0000000c,0x0000000e,0x0004003d,0x00000006,0x00000074,0x00000073,0x00050088,0x00000006, + 0x00000075,0x00000072,0x00000074,0x00050083,0x00000006,0x00000076,0x00000069,0x00000075, + 0x0003003e,0x00000066,0x00000076,0x00050041,0x0000000f,0x00000078,0x0000000c,0x00000067, + 0x0004003d,0x00000006,0x00000079,0x00000078,0x00050041,0x0000000f,0x0000007a,0x0000000c, + 0x00000012,0x0004003d,0x00000006,0x0000007b,0x0000007a,0x00050088,0x00000006,0x0000007c, + 0x0000007b,0x0000006c,0x00050041,0x00000028,0x0000007d,0x00000016,0x00000057,0x0004003d, + 0x00000006,0x0000007e,0x0000007d,0x00050083,0x00000006,0x0000007f,0x0000007c,0x0000007e, + 0x0006000c,0x00000006,0x00000080,0x00000001,0x00000004,0x0000007f,0x00050085,0x00000006, + 0x00000081,0x00000080,0x0000006c,0x00050041,0x0000000f,0x00000082,0x0000000c,0x00000012, + 0x0004003d,0x00000006,0x00000083,0x00000082,0x00050088,0x00000006,0x00000084,0x00000081, + 0x00000083,0x00050083,0x00000006,0x00000085,0x00000079,0x00000084,0x0003003e,0x00000077, + 0x00000085,0x00050041,0x0000000f,0x00000087,0x0000000c,0x00000040,0x0004003d,0x00000006, + 0x00000088,0x00000087,0x00050085,0x00000006,0x00000089,0x0000006c,0x00000088,0x00050041, + 0x00000028,0x0000008a,0x00000024,0x00000057,0x0004003d,0x00000006,0x0000008b,0x0000008a, + 0x00050085,0x00000006,0x0000008d,0x0000008b,0x0000008c,0x00050085,0x00000006,0x0000008f, + 0x0000008d,0x0000008e,0x00050081,0x00000006,0x00000090,0x00000089,0x0000008f,0x0003003e, + 0x00000086,0x00000090,0x00050041,0x0000000f,0x00000092,0x0000000c,0x00000040,0x0004003d, + 0x00000006,0x00000093,0x00000092,0x00050085,0x00000006,0x00000094,0x0000006c,0x00000093, + 0x00050041,0x00000028,0x00000095,0x00000024,0x00000048,0x0004003d,0x00000006,0x00000096, + 0x00000095,0x00050085,0x00000006,0x00000097,0x00000096,0x0000008c,0x00050085,0x00000006, + 0x00000098,0x00000097,0x0000008e,0x00050081,0x00000006,0x00000099,0x00000094,0x00000098, + 0x0003003e,0x00000091,0x00000099,0x0004003d,0x00000006,0x0000009b,0x00000086,0x0006000c, + 0x00000006,0x0000009c,0x00000001,0x0000000d,0x0000009b,0x0004003d,0x00000006,0x0000009d, + 0x00000066,0x00050085,0x00000006,0x0000009e,0x0000009c,0x0000009d,0x0004003d,0x00000006, + 0x0000009f,0x00000091,0x0006000c,0x00000006,0x000000a0,0x00000001,0x0000000d,0x0000009f, + 0x0004003d,0x00000006,0x000000a1,0x00000077,0x00050085,0x00000006,0x000000a2,0x000000a0, + 0x000000a1,0x00050050,0x00000007,0x000000a3,0x0000009e,0x000000a2,0x0005008e,0x00000007, + 0x000000a5,0x000000a3,0x000000a4,0x0003003e,0x0000009a,0x000000a5,0x0004003d,0x00000007, + 0x000000a6,0x0000009a,0x0004003d,0x00000007,0x000000a7,0x00000024,0x00050081,0x00000007, + 0x000000a8,0x000000a7,0x000000a6,0x0003003e,0x00000024,0x000000a8,0x000200f9,0x00000065, + 0x000200f8,0x00000065,0x00050041,0x0000000f,0x000000aa,0x0000000c,0x000000a9,0x0004003d, + 0x00000006,0x000000ab,0x000000aa,0x0004003d,0x00000007,0x000000ac,0x00000024,0x00050050, + 0x00000007,0x000000ad,0x000000ab,0x000000ab,0x00050088,0x00000007,0x000000ae,0x000000ac, + 0x000000ad,0x0003003e,0x00000024,0x000000ae,0x0004003d,0x00000007,0x000000af,0x00000024, + 0x0004003d,0x00000007,0x000000b0,0x00000009,0x00050085,0x00000007,0x000000b1,0x000000af, + 0x000000b0,0x0004003d,0x00000007,0x000000b3,0x00000009,0x00050083,0x00000007,0x000000b6, + 0x000000b3,0x000000b5,0x0008000c,0x00000007,0x000000b7,0x00000001,0x0000002b,0x000000b1, + 0x000000b2,0x000000b6,0x0003003e,0x00000024,0x000000b7,0x0004003d,0x000000bb,0x000000be, + 0x000000bd,0x0004003d,0x00000007,0x000000bf,0x00000024,0x00070058,0x00000017,0x000000c0, + 0x000000be,0x000000bf,0x00000002,0x00000043,0x0003003e,0x000000b9,0x000000c0,0x000100fd, + 0x00010038 +}; \ No newline at end of file diff --git a/src/vk/spirv/world_warp_vert.c b/src/vk/spirv/world_warp_vert.c new file mode 100644 index 0000000..8614c78 --- /dev/null +++ b/src/vk/spirv/world_warp_vert.c @@ -0,0 +1,33 @@ + // 8.13.3559 + #pragma once +const uint32_t world_warp_vert_spv[] = { + 0x07230203,0x00010000,0x00080008,0x00000024,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0007000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x00000017,0x0000001b,0x00030003, + 0x00000002,0x000001c2,0x00090004,0x415f4c47,0x735f4252,0x72617065,0x5f657461,0x64616873, + 0x6f5f7265,0x63656a62,0x00007374,0x00040005,0x00000004,0x6e69616d,0x00000000,0x00050005, + 0x0000000c,0x69736f70,0x6e6f6974,0x00000073,0x00060005,0x00000015,0x505f6c67,0x65567265, + 0x78657472,0x00000000,0x00060006,0x00000015,0x00000000,0x505f6c67,0x7469736f,0x006e6f69, + 0x00030005,0x00000017,0x00000000,0x00060005,0x0000001b,0x565f6c67,0x65747265,0x646e4978, + 0x00007865,0x00050048,0x00000015,0x00000000,0x0000000b,0x00000000,0x00030047,0x00000015, + 0x00000002,0x00040047,0x0000001b,0x0000000b,0x0000002a,0x00020013,0x00000002,0x00030021, + 0x00000003,0x00000002,0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,0x00000006, + 0x00000004,0x00040015,0x00000008,0x00000020,0x00000000,0x0004002b,0x00000008,0x00000009, + 0x00000003,0x0004001c,0x0000000a,0x00000007,0x00000009,0x00040020,0x0000000b,0x00000007, + 0x0000000a,0x0004002b,0x00000006,0x0000000d,0xbf800000,0x0004002b,0x00000006,0x0000000e, + 0x00000000,0x0004002b,0x00000006,0x0000000f,0x3f800000,0x0007002c,0x00000007,0x00000010, + 0x0000000d,0x0000000d,0x0000000e,0x0000000f,0x0004002b,0x00000006,0x00000011,0x40400000, + 0x0007002c,0x00000007,0x00000012,0x00000011,0x0000000d,0x0000000e,0x0000000f,0x0007002c, + 0x00000007,0x00000013,0x0000000d,0x00000011,0x0000000e,0x0000000f,0x0006002c,0x0000000a, + 0x00000014,0x00000010,0x00000012,0x00000013,0x0003001e,0x00000015,0x00000007,0x00040020, + 0x00000016,0x00000003,0x00000015,0x0004003b,0x00000016,0x00000017,0x00000003,0x00040015, + 0x00000018,0x00000020,0x00000001,0x0004002b,0x00000018,0x00000019,0x00000000,0x00040020, + 0x0000001a,0x00000001,0x00000018,0x0004003b,0x0000001a,0x0000001b,0x00000001,0x0004002b, + 0x00000018,0x0000001d,0x00000003,0x00040020,0x0000001f,0x00000007,0x00000007,0x00040020, + 0x00000022,0x00000003,0x00000007,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003, + 0x000200f8,0x00000005,0x0004003b,0x0000000b,0x0000000c,0x00000007,0x0003003e,0x0000000c, + 0x00000014,0x0004003d,0x00000018,0x0000001c,0x0000001b,0x0005008b,0x00000018,0x0000001e, + 0x0000001c,0x0000001d,0x00050041,0x0000001f,0x00000020,0x0000000c,0x0000001e,0x0004003d, + 0x00000007,0x00000021,0x00000020,0x00050041,0x00000022,0x00000023,0x00000017,0x00000019, + 0x0003003e,0x00000023,0x00000021,0x000100fd,0x00010038 +}; \ No newline at end of file diff --git a/src/vk/vk_buffer.c b/src/vk/vk_buffer.c new file mode 100644 index 0000000..b5f9587 --- /dev/null +++ b/src/vk/vk_buffer.c @@ -0,0 +1,205 @@ +/* +Copyright (C) 2018-2019 Krzysztof Kondrak + +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. +*/ + +#include "header/local.h" + +// internal helper +static void +copyBuffer(const VkBuffer * src, VkBuffer * dst, VkDeviceSize size) +{ + VkCommandBuffer commandBuffer = QVk_CreateCommandBuffer(&vk_transferCommandPool, + VK_COMMAND_BUFFER_LEVEL_PRIMARY); + QVk_BeginCommand(&commandBuffer); + + VkBufferCopy copyRegion = { + .srcOffset = 0, + .dstOffset = 0, + .size = size + }; + vkCmdCopyBuffer(commandBuffer, *src, *dst, 1, ©Region); + + QVk_SubmitCommand(&commandBuffer, &vk_device.transferQueue); + vkFreeCommandBuffers(vk_device.logical, vk_transferCommandPool, 1, + &commandBuffer); +} + +// internal helper +static void +createStagedBuffer(const void *data, VkDeviceSize size, qvkbuffer_t * dstBuffer, + qvkbufferopts_t bufferOpts) +{ + qvkstagingbuffer_t *stgBuffer; + stgBuffer = (qvkstagingbuffer_t *) malloc(sizeof(qvkstagingbuffer_t)); + VK_VERIFY(QVk_CreateStagingBuffer(size, stgBuffer, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + VK_MEMORY_PROPERTY_HOST_CACHED_BIT)); + + if (data) + { + void *dst; + // staging buffers in vkQuake2 are required to be host coherent, + // so no flushing/invalidation is involved + dst = buffer_map(&stgBuffer->resource); + memcpy(dst, data, (size_t) size); + buffer_unmap(&stgBuffer->resource); + } + + VK_VERIFY(QVk_CreateBuffer(size, dstBuffer, bufferOpts)); + copyBuffer(&stgBuffer->resource.buffer, &dstBuffer->resource.buffer, size); + + QVk_FreeStagingBuffer(stgBuffer); + free(stgBuffer); +} + +VkResult +QVk_CreateBuffer(VkDeviceSize size, qvkbuffer_t *dstBuffer, + const qvkbufferopts_t options) +{ + VkBufferCreateInfo bcInfo = { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .size = size, + .usage = options.usage, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = NULL, + }; + + // separate transfer queue makes sense only if the buffer is targetted + // for being transfered to GPU, so ignore it if it's CPU-only + uint32_t queueFamilies[] = { + (uint32_t)vk_device.gfxFamilyIndex, + (uint32_t)vk_device.transferFamilyIndex + }; + + if (vk_device.gfxFamilyIndex != vk_device.transferFamilyIndex) + { + bcInfo.sharingMode = VK_SHARING_MODE_CONCURRENT; + bcInfo.queueFamilyIndexCount = 2; + bcInfo.pQueueFamilyIndices = queueFamilies; + } + + dstBuffer->currentOffset = 0; + return buffer_create(&dstBuffer->resource, bcInfo, + options.reqMemFlags, options.prefMemFlags); +} + +void +QVk_FreeBuffer(qvkbuffer_t *buffer) +{ + buffer_destroy(&buffer->resource); + buffer->currentOffset = 0; +} + +void +QVk_FreeStagingBuffer(qvkstagingbuffer_t *buffer) +{ + buffer_destroy(&buffer->resource); + buffer->currentOffset = 0; +} + +VkResult +QVk_CreateStagingBuffer(VkDeviceSize size, qvkstagingbuffer_t *dstBuffer, + VkMemoryPropertyFlags reqMemFlags, + VkMemoryPropertyFlags prefMemFlags) +{ + VkBufferCreateInfo bcInfo = { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .size = ROUNDUP(size, 1024), + .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = NULL, + }; + + reqMemFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + + dstBuffer->currentOffset = 0; + return buffer_create(&dstBuffer->resource, bcInfo, reqMemFlags, + prefMemFlags); +} + +VkResult +QVk_CreateUniformBuffer(VkDeviceSize size, qvkbuffer_t *dstBuffer, + VkMemoryPropertyFlags reqMemFlags, + VkMemoryPropertyFlags prefMemFlags) +{ + qvkbufferopts_t dstOpts = { + .usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + .reqMemFlags = reqMemFlags, + .prefMemFlags = prefMemFlags, + }; + + dstOpts.reqMemFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + + if((vk_device.properties.deviceType != VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) || + (dstOpts.prefMemFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) + { + dstOpts.prefMemFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } + + return QVk_CreateBuffer(size, dstBuffer, dstOpts); +} + +void +QVk_CreateVertexBuffer(const void *data, VkDeviceSize size, + qvkbuffer_t *dstBuffer, + VkMemoryPropertyFlags reqMemFlags, + VkMemoryPropertyFlags prefMemFlags) +{ + qvkbufferopts_t dstOpts = { + .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + .reqMemFlags = reqMemFlags, + .prefMemFlags = prefMemFlags, + }; + + if((vk_device.properties.deviceType != VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) || + (dstOpts.prefMemFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) + { + dstOpts.prefMemFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } + + createStagedBuffer(data, size, dstBuffer, dstOpts); +} + +void +QVk_CreateIndexBuffer(const void *data, VkDeviceSize size, + qvkbuffer_t *dstBuffer, + VkMemoryPropertyFlags reqMemFlags, + VkMemoryPropertyFlags prefMemFlags) +{ + qvkbufferopts_t dstOpts = { + .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, + .reqMemFlags = reqMemFlags, + .prefMemFlags = prefMemFlags, + }; + + if((vk_device.properties.deviceType != VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) || + (dstOpts.prefMemFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) + { + dstOpts.prefMemFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } + + createStagedBuffer(data, size, dstBuffer, dstOpts); +} diff --git a/src/vk/vk_cmd.c b/src/vk/vk_cmd.c new file mode 100644 index 0000000..af55936 --- /dev/null +++ b/src/vk/vk_cmd.c @@ -0,0 +1,91 @@ +/* +Copyright (C) 2018-2019 Krzysztof Kondrak + +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. + +*/ + +#include "header/local.h" + +VkResult QVk_BeginCommand(const VkCommandBuffer *commandBuffer) +{ + VkCommandBufferBeginInfo cmdInfo = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .pNext = NULL, + .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, + .pInheritanceInfo = NULL + }; + + return vkBeginCommandBuffer(*commandBuffer, &cmdInfo); +} + +void QVk_SubmitCommand(const VkCommandBuffer *commandBuffer, const VkQueue *queue) +{ + VK_VERIFY(vkEndCommandBuffer(*commandBuffer)); + + VkSubmitInfo submitInfo = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .pNext = NULL, + .waitSemaphoreCount = 0, + .pWaitSemaphores = NULL, + .pWaitDstStageMask = NULL, + .commandBufferCount = 1, + .pCommandBuffers = commandBuffer, + .signalSemaphoreCount = 0, + .pSignalSemaphores = NULL + }; + + VkFenceCreateInfo fCreateInfo = { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .pNext = NULL, + .flags = 0 + }; + + VkFence queueFence; + VK_VERIFY(vkCreateFence(vk_device.logical, &fCreateInfo, NULL, &queueFence)); + VK_VERIFY(vkQueueSubmit(*queue, 1, &submitInfo, queueFence)); + VK_VERIFY(vkWaitForFences(vk_device.logical, 1, &queueFence, VK_TRUE, UINT64_MAX)); + + vkDestroyFence(vk_device.logical, queueFence, NULL); +} + +VkResult QVk_CreateCommandPool(VkCommandPool *commandPool, uint32_t queueFamilyIndex) +{ + VkCommandPoolCreateInfo cpCreateInfo = { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .pNext = NULL, + // allow the command pool to be explicitly reset without reallocating it manually during recording each frame + .flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, + .queueFamilyIndex = queueFamilyIndex + }; + + return vkCreateCommandPool(vk_device.logical, &cpCreateInfo, NULL, commandPool); +} + +VkCommandBuffer QVk_CreateCommandBuffer(const VkCommandPool *commandPool, VkCommandBufferLevel level) +{ + VkCommandBuffer commandBuffer = VK_NULL_HANDLE; + VkCommandBufferAllocateInfo allocInfo = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .pNext = NULL, + .commandPool = *commandPool, + .level = level, + .commandBufferCount = 1 + }; + + VK_VERIFY(vkAllocateCommandBuffers(vk_device.logical, &allocInfo, &commandBuffer)); + return commandBuffer; +} diff --git a/src/vk/vk_common.c b/src/vk/vk_common.c new file mode 100644 index 0000000..ecb6876 --- /dev/null +++ b/src/vk/vk_common.c @@ -0,0 +1,2644 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. +Copyright (C) 2018-2019 Krzysztof Kondrak + +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. +*/ + +/* +** VK_COMMON.C +** +** This file implements the operating system binding of Vk to QVk function +** pointers. When doing a port of Quake2 you must implement the following +** two functions: +** +** QVk_Init() - loads libraries, assigns function pointers, etc. +** QVk_Shutdown() - unloads libraries, NULLs function pointers +*/ +#include +#include "header/local.h" + +static SDL_Window *vk_window; + +// Vulkan instance, surface and memory allocator +VkInstance vk_instance = VK_NULL_HANDLE; +VkSurfaceKHR vk_surface = VK_NULL_HANDLE; + +// Vulkan device +qvkdevice_t vk_device = { + .physical = VK_NULL_HANDLE, + .logical = VK_NULL_HANDLE, + .gfxQueue = VK_NULL_HANDLE, + .presentQueue = VK_NULL_HANDLE, + .transferQueue = VK_NULL_HANDLE, + .gfxFamilyIndex = -1, + .presentFamilyIndex = -1, + .transferFamilyIndex = -1, + .screenshotSupported = false +}; + +// Vulkan swapchain +qvkswapchain_t vk_swapchain = { + .sc = VK_NULL_HANDLE, + .format = VK_FORMAT_UNDEFINED, + .presentMode = VK_PRESENT_MODE_MAILBOX_KHR, + .extent = { 0, 0 }, + .images = NULL, + .imageCount = 0 +}; + +// Vulkan renderpasses +qvkrenderpass_t vk_renderpasses[RP_COUNT] = { + // RP_WORLD + { + .rp = VK_NULL_HANDLE, + .colorLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .sampleCount = VK_SAMPLE_COUNT_1_BIT + }, + // RP_UI + { + .rp = VK_NULL_HANDLE, + .colorLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .sampleCount = VK_SAMPLE_COUNT_1_BIT + }, + // RP_WORLD_WARP + { + .rp = VK_NULL_HANDLE, + .colorLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .sampleCount = VK_SAMPLE_COUNT_1_BIT + } +}; + +// Vulkan pools +VkCommandPool vk_commandPool[NUM_CMDBUFFERS] = { VK_NULL_HANDLE, VK_NULL_HANDLE }; +VkCommandPool vk_transferCommandPool = VK_NULL_HANDLE; +VkDescriptorPool vk_descriptorPool = VK_NULL_HANDLE; +static VkCommandPool vk_stagingCommandPool[NUM_DYNBUFFERS] = { VK_NULL_HANDLE, VK_NULL_HANDLE }; +// Vulkan image views +static VkImageView *vk_imageviews = NULL; +// Vulkan framebuffers +static VkFramebuffer *vk_framebuffers[RP_COUNT]; +// color buffer containing main game/world view +qvktexture_t vk_colorbuffer = QVVKTEXTURE_INIT; +// color buffer with postprocessed game view +qvktexture_t vk_colorbufferWarp = QVVKTEXTURE_INIT; +// depth buffer +qvktexture_t vk_depthbuffer = QVVKTEXTURE_INIT; +// depth buffer for UI renderpass +static qvktexture_t vk_ui_depthbuffer = QVVKTEXTURE_INIT; +// render target for MSAA resolve +static qvktexture_t vk_msaaColorbuffer = QVVKTEXTURE_INIT; +// viewport and scissor +VkViewport vk_viewport = { .0f, .0f, .0f, .0f, .0f, .0f }; +VkRect2D vk_scissor = { { 0, 0 }, { 0, 0 } }; + +// Vulkan command buffers +static VkCommandBuffer *vk_commandbuffers = NULL; +// command buffer double buffering fences +static VkFence vk_fences[NUM_CMDBUFFERS]; +// semaphore: signal when next image is available for rendering +static VkSemaphore vk_imageAvailableSemaphores[NUM_CMDBUFFERS]; +// semaphore: signal when rendering to current command buffer is complete +static VkSemaphore vk_renderFinishedSemaphores[NUM_CMDBUFFERS]; +// tracker variables +VkCommandBuffer vk_activeCmdbuffer = VK_NULL_HANDLE; +// index of active command buffer +int vk_activeBufferIdx = 0; +// index of currently acquired image +static uint32_t vk_imageIndex = 0; +// index of currently used staging buffer +static int vk_activeStagingBuffer = 0; +// started rendering frame? +qboolean vk_frameStarted = false; +// the renderer needs to be restarted. +qboolean vk_restartNeeded = false; +// is QVk initialized? +qboolean vk_initialized = false; + +// render pipelines +qvkpipeline_t vk_drawTexQuadPipeline[RP_COUNT] = { + QVKPIPELINE_INIT, QVKPIPELINE_INIT, QVKPIPELINE_INIT }; +qvkpipeline_t vk_drawColorQuadPipeline[RP_COUNT] = { + QVKPIPELINE_INIT, QVKPIPELINE_INIT, QVKPIPELINE_INIT }; +qvkpipeline_t vk_drawModelPipelineFan[RP_COUNT] = { + QVKPIPELINE_INIT, QVKPIPELINE_INIT, QVKPIPELINE_INIT }; +qvkpipeline_t vk_drawNoDepthModelPipelineFan = QVKPIPELINE_INIT; +qvkpipeline_t vk_drawLefthandModelPipelineFan = QVKPIPELINE_INIT; +qvkpipeline_t vk_drawNullModelPipeline = QVKPIPELINE_INIT; +qvkpipeline_t vk_drawParticlesPipeline = QVKPIPELINE_INIT; +qvkpipeline_t vk_drawPointParticlesPipeline = QVKPIPELINE_INIT; +qvkpipeline_t vk_drawSpritePipeline = QVKPIPELINE_INIT; +qvkpipeline_t vk_drawPolyPipeline = QVKPIPELINE_INIT; +qvkpipeline_t vk_drawPolyLmapPipeline = QVKPIPELINE_INIT; +qvkpipeline_t vk_drawPolyWarpPipeline = QVKPIPELINE_INIT; +qvkpipeline_t vk_drawPolySolidWarpPipeline = QVKPIPELINE_INIT; +qvkpipeline_t vk_drawBeamPipeline = QVKPIPELINE_INIT; +qvkpipeline_t vk_drawSkyboxPipeline = QVKPIPELINE_INIT; +qvkpipeline_t vk_drawDLightPipeline = QVKPIPELINE_INIT; +qvkpipeline_t vk_showTrisPipeline = QVKPIPELINE_INIT; +qvkpipeline_t vk_shadowsPipelineStrip = QVKPIPELINE_INIT; +qvkpipeline_t vk_shadowsPipelineFan = QVKPIPELINE_INIT; +qvkpipeline_t vk_worldWarpPipeline = QVKPIPELINE_INIT; +qvkpipeline_t vk_postprocessPipeline = QVKPIPELINE_INIT; + +// samplers +static VkSampler vk_samplers[NUM_SAMPLERS]; + +// Vulkan function pointers +PFN_vkCreateDebugUtilsMessengerEXT qvkCreateDebugUtilsMessengerEXT; +PFN_vkDestroyDebugUtilsMessengerEXT qvkDestroyDebugUtilsMessengerEXT; +PFN_vkSetDebugUtilsObjectNameEXT qvkSetDebugUtilsObjectNameEXT; +PFN_vkSetDebugUtilsObjectTagEXT qvkSetDebugUtilsObjectTagEXT; +PFN_vkCmdBeginDebugUtilsLabelEXT qvkCmdBeginDebugUtilsLabelEXT; +PFN_vkCmdEndDebugUtilsLabelEXT qvkCmdEndDebugUtilsLabelEXT; +PFN_vkCmdInsertDebugUtilsLabelEXT qvkInsertDebugUtilsLabelEXT; + +#define VK_INPUTBIND_DESC(s) { \ + .binding = 0, \ + .stride = s, \ + .inputRate = VK_VERTEX_INPUT_RATE_VERTEX \ +}; + +#define VK_INPUTATTR_DESC(l, f, o) { \ + .binding = 0, \ + .location = l, \ + .format = f, \ + .offset = o \ +} + +#define VK_VERTEXINPUT_CINF(b, a) { \ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, \ + .pNext = NULL, \ + .flags = 0, \ + .vertexBindingDescriptionCount = 1, \ + .pVertexBindingDescriptions = &b, \ + .vertexAttributeDescriptionCount = sizeof(a) / sizeof(a[0]), \ + .pVertexAttributeDescriptions = a \ +} + +#define VK_VERTINFO(name, bindSize, ...) \ + VkVertexInputAttributeDescription attrDesc##name[] = { __VA_ARGS__ }; \ + VkVertexInputBindingDescription name##bindingDesc = VK_INPUTBIND_DESC(bindSize); \ + VkPipelineVertexInputStateCreateInfo vertInfo##name = VK_VERTEXINPUT_CINF(name##bindingDesc, attrDesc##name); + +#define VK_NULL_VERTEXINPUT_CINF { \ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, \ + .pNext = NULL, \ + .flags = 0, \ + .vertexBindingDescriptionCount = 0, \ + .pVertexBindingDescriptions = NULL, \ + .vertexAttributeDescriptionCount = 0, \ + .pVertexAttributeDescriptions = NULL \ +} + +enum { + SHADER_VERT_INDEX = 0, + SHADER_FRAG_INDEX = 1, + SHADER_INDEX_SIZE = 2 +}; + +#define VK_LOAD_VERTFRAG_SHADERS(shaders, namevert, namefrag) \ + DestroyShaderModule(shaders); \ + shaders[SHADER_VERT_INDEX] = QVk_CreateShader(namevert##_vert_spv, namevert##_vert_size, VK_SHADER_STAGE_VERTEX_BIT); \ + shaders[SHADER_FRAG_INDEX] = QVk_CreateShader(namefrag##_frag_spv, namefrag##_frag_size, VK_SHADER_STAGE_FRAGMENT_BIT); \ + QVk_DebugSetObjectName((uint64_t)shaders[SHADER_VERT_INDEX].module, VK_OBJECT_TYPE_SHADER_MODULE, "Shader Module: "#namevert".vert"); \ + QVk_DebugSetObjectName((uint64_t)shaders[SHADER_FRAG_INDEX].module, VK_OBJECT_TYPE_SHADER_MODULE, "Shader Module: "#namefrag".frag"); + +// global static buffers (reused, never changing) +static qvkbuffer_t vk_texRectVbo; +static qvkbuffer_t vk_colorRectVbo; +static qvkbuffer_t vk_rectIbo; + +// global dynamic buffers (double buffered) +static qvkbuffer_t vk_dynVertexBuffers[NUM_DYNBUFFERS]; +static qvkbuffer_t vk_dynIndexBuffers[NUM_DYNBUFFERS]; +static qvkbuffer_t vk_dynUniformBuffers[NUM_DYNBUFFERS]; +static VkDescriptorSet vk_uboDescriptorSets[NUM_DYNBUFFERS]; +static qvkstagingbuffer_t vk_stagingBuffers[NUM_DYNBUFFERS]; +static int vk_activeDynBufferIdx = 0; +static int vk_activeSwapBufferIdx = 0; + +// index buffer for triangle fan/strip emulation - all because Metal/MoltenVK don't support them +static VkBuffer *vk_triangleFanIbo = NULL; +static VkBuffer *vk_triangleStripIbo = NULL; +static uint32_t vk_triangleFanIboUsage = 0; + +// swap buffers used if primary dynamic buffers get full +#define NUM_SWAPBUFFER_SLOTS 4 +static int vk_swapBuffersCnt[NUM_SWAPBUFFER_SLOTS]; +static int vk_swapDescSetsCnt[NUM_SWAPBUFFER_SLOTS]; +static qvkbuffer_t *vk_swapBuffers[NUM_SWAPBUFFER_SLOTS]; +static VkDescriptorSet *vk_swapDescriptorSets[NUM_SWAPBUFFER_SLOTS]; + +// by how much will the dynamic buffers be resized if we run out of space? +#define BUFFER_RESIZE_FACTOR 2.f +// size in bytes used for uniform descriptor update +#define UNIFORM_ALLOC_SIZE 1024 +// start values for dynamic buffer sizes - bound to change if the application runs out of space (sizes in bytes) +#define VERTEX_BUFFER_SIZE (1024 * 1024) +#define INDEX_BUFFER_SIZE (2 * 1024) +#define UNIFORM_BUFFER_SIZE (2048 * 1024) +// staging buffer is constant in size but has a max limit beyond which it will be submitted +#define STAGING_BUFFER_MAXSIZE (8192 * 1024) +// initial index count in triangle fan buffer - assuming 200 indices (200*3 = 600 triangles) per object +#define TRIANGLE_INDEX_CNT 200 + +// Vulkan common descriptor sets for UBO, primary texture sampler and optional lightmap texture +static VkDescriptorSetLayout vk_uboDescSetLayout; +VkDescriptorSetLayout vk_samplerDescSetLayout; +static VkDescriptorSetLayout vk_samplerLightmapDescSetLayout; + +static const char *renderpassObjectNames[] = { + "RP_WORLD", + "RP_UI", + "RP_WORLD_WARP" +}; + +VkFormat QVk_FindDepthFormat() +{ + VkFormat depthFormats[] = { + VK_FORMAT_D32_SFLOAT_S8_UINT, + VK_FORMAT_D32_SFLOAT, + VK_FORMAT_D24_UNORM_S8_UINT, + VK_FORMAT_D16_UNORM_S8_UINT, + VK_FORMAT_D16_UNORM + }; + + for (int i = 0; i < 5; ++i) + { + VkFormatProperties formatProps; + vkGetPhysicalDeviceFormatProperties(vk_device.physical, depthFormats[i], &formatProps); + + if (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) + return depthFormats[i]; + } + + return VK_FORMAT_D16_UNORM; +} + +// internal helper +static VkSampleCountFlagBits GetSampleCount(int msaa, VkSampleCountFlagBits supportedMsaa) +{ + int step = 0, value = 64; + + static VkSampleCountFlagBits msaaModes[] = { + VK_SAMPLE_COUNT_64_BIT, + VK_SAMPLE_COUNT_32_BIT, + VK_SAMPLE_COUNT_16_BIT, + VK_SAMPLE_COUNT_8_BIT, + VK_SAMPLE_COUNT_4_BIT, + VK_SAMPLE_COUNT_2_BIT, + VK_SAMPLE_COUNT_1_BIT + }; + + while ((msaa < value && value > 1) || + ((supportedMsaa & msaaModes[step]) != msaaModes[step])) + { + value >>= 1; + step ++; + } + + R_Printf(PRINT_ALL, "MSAAx%d is used...\n", value); + + return msaaModes[step]; +} + +// internal helper +static void DestroyImageViews() +{ + if(!vk_imageviews) + return; + + for (int i = 0; i < vk_swapchain.imageCount; i++) + { + vkDestroyImageView(vk_device.logical, vk_imageviews[i], NULL); + } + free(vk_imageviews); + vk_imageviews = NULL; +} + +// internal helper +static VkResult CreateImageViews() +{ + VkResult res = VK_SUCCESS; + vk_imageviews = (VkImageView *)malloc(vk_swapchain.imageCount * sizeof(VkImageView)); + + for (size_t i = 0; i < vk_swapchain.imageCount; ++i) + { + res = QVk_CreateImageView(&vk_swapchain.images[i], + VK_IMAGE_ASPECT_COLOR_BIT, &vk_imageviews[i], vk_swapchain.format, 1); + QVk_DebugSetObjectName((uint64_t)vk_swapchain.images[i], + VK_OBJECT_TYPE_IMAGE, va("Swap Chain Image #" YQ2_COM_PRIdS, i)); + QVk_DebugSetObjectName((uint64_t)vk_imageviews[i], + VK_OBJECT_TYPE_IMAGE_VIEW, va("Swap Chain Image View #" YQ2_COM_PRIdS, i)); + + if (res != VK_SUCCESS) + { + DestroyImageViews(); + return res; + } + } + + return res; +} + +// internal helper +static void DestroyFramebuffers() +{ + for (int f = 0; f < RP_COUNT; f++) + { + if (vk_framebuffers[f]) + { + for (int i = 0; i < vk_swapchain.imageCount; ++i) + { + vkDestroyFramebuffer(vk_device.logical, vk_framebuffers[f][i], NULL); + } + + free(vk_framebuffers[f]); + vk_framebuffers[f] = NULL; + } + } +} + +// internal helper +static VkResult CreateFramebuffers() +{ + for(int i = 0; i < RP_COUNT; ++i) + vk_framebuffers[i] = (VkFramebuffer *)malloc(vk_swapchain.imageCount * sizeof(VkFramebuffer)); + + VkFramebufferCreateInfo fbCreateInfos[] = { + // RP_WORLD: main world view framebuffer + { + .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .renderPass = vk_renderpasses[RP_WORLD].rp, + .attachmentCount = (vk_renderpasses[RP_WORLD].sampleCount != VK_SAMPLE_COUNT_1_BIT) ? 3 : 2, + .width = vk_swapchain.extent.width, + .height = vk_swapchain.extent.height, + .layers = 1 + }, + // RP_UI: UI framebuffer + { + .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .renderPass = vk_renderpasses[RP_UI].rp, + .attachmentCount = 3, + .width = vk_swapchain.extent.width, + .height = vk_swapchain.extent.height, + .layers = 1 + }, + // RP_WORLD_WARP: warped main world view (postprocessing) framebuffer + { + .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .renderPass = vk_renderpasses[RP_WORLD_WARP].rp, + .attachmentCount = 2, + .width = vk_swapchain.extent.width, + .height = vk_swapchain.extent.height, + .layers = 1 + } + }; + + VkImageView worldAttachments[] = { vk_colorbuffer.imageView, vk_depthbuffer.imageView, vk_msaaColorbuffer.imageView }; + VkImageView warpAttachments[] = { vk_colorbuffer.imageView, vk_colorbufferWarp.imageView }; + + fbCreateInfos[RP_WORLD].pAttachments = worldAttachments; + fbCreateInfos[RP_WORLD_WARP].pAttachments = warpAttachments; + + for (size_t i = 0; i < vk_swapchain.imageCount; ++i) + { + VkImageView uiAttachments[] = { vk_colorbufferWarp.imageView, vk_ui_depthbuffer.imageView, vk_imageviews[i] }; + fbCreateInfos[RP_UI].pAttachments = uiAttachments; + + for (int j = 0; j < RP_COUNT; ++j) + { + VkResult res = vkCreateFramebuffer(vk_device.logical, &fbCreateInfos[j], NULL, &vk_framebuffers[j][i]); + QVk_DebugSetObjectName((uint64_t)vk_framebuffers[j][i], + VK_OBJECT_TYPE_FRAMEBUFFER, va("Framebuffer #" YQ2_COM_PRIdS "for Render Pass %s", + i, renderpassObjectNames[j])); + + if (res != VK_SUCCESS) + { + R_Printf(PRINT_ALL, "%s(): framebuffer #%d create error: %s\n", __func__, j, QVk_GetError(res)); + DestroyFramebuffers(); + return res; + } + } + } + + return VK_SUCCESS; +} + +// internal helper +static VkResult CreateRenderpasses() +{ + qboolean msaaEnabled = vk_renderpasses[RP_WORLD].sampleCount != VK_SAMPLE_COUNT_1_BIT; + + /* + * world view setup + */ + // The color attachment is loaded from the previous frame and stored + // after the frame is drawn to mask geometry errors in the skybox + // that may leave some pixels without coverage. + VkAttachmentDescription worldAttachments[] = { + // Single-sample color attachment. + { + .flags = 0, + .format = vk_swapchain.format, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = (msaaEnabled ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : VK_ATTACHMENT_LOAD_OP_LOAD), + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + .finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + }, + // depth attachment + { + .flags = 0, + .format = QVk_FindDepthFormat(), + .samples = vk_renderpasses[RP_WORLD].sampleCount, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL + }, + // MSAA attachment + { + .flags = 0, + .format = vk_swapchain.format, + .samples = vk_renderpasses[RP_WORLD].sampleCount, + .loadOp = (msaaEnabled ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : VK_ATTACHMENT_LOAD_OP_LOAD), + .storeOp = (msaaEnabled ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE), + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL + } + }; + + VkAttachmentReference worldAttachmentRefs[] = { + // color + { + .attachment = msaaEnabled ? 2 : 0, + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + }, + // depth + { + .attachment = 1, + .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL + }, + // MSAA resolve + { + .attachment = 0, + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL + } + }; + + // primary renderpass writes to color, depth and optional MSAA resolve + VkSubpassDescription worldSubpassDesc = { + .flags = 0, + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .inputAttachmentCount = 0, + .pInputAttachments = NULL, + .colorAttachmentCount = 1, + .pColorAttachments = &worldAttachmentRefs[0], + .pResolveAttachments = msaaEnabled ? &worldAttachmentRefs[2] : NULL, + .pDepthStencilAttachment = &worldAttachmentRefs[1], + .preserveAttachmentCount = 0, + .pPreserveAttachments = NULL + }; + + /* + * world warp setup + */ + VkAttachmentDescription warpAttachments[] = { + // color attachment - input from RP_WORLD renderpass + { + .flags = 0, + .format = vk_swapchain.format, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + .finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + }, + // color attachment output - warped/postprocessed image that ends up in RP_UI + { + .flags = 0, + .format = vk_swapchain.format, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + } + }; + + VkAttachmentReference warpAttachmentRef = { + // output color + .attachment = 1, + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL + }; + + // world view postprocess writes to a separate color buffer + VkSubpassDescription warpSubpassDesc = { + .flags = 0, + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .inputAttachmentCount = 0, + .pInputAttachments = NULL, + .colorAttachmentCount = 1, + .pColorAttachments = &warpAttachmentRef, + .pResolveAttachments = NULL, + .pDepthStencilAttachment = NULL, + .preserveAttachmentCount = 0, + .pPreserveAttachments = NULL + }; + + /* + * UI setup + */ + VkAttachmentDescription uiAttachments[] = { + // color attachment + { + .flags = 0, + .format = vk_swapchain.format, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + .finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + }, + // depth attachment - because of player model preview in settings screen + { + .flags = 0, + .format = QVk_FindDepthFormat(), + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL + }, + // swapchain presentation + { + .flags = 0, + .format = vk_swapchain.format, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR + } + }; + + // UI renderpass writes to depth (for player model in setup screen) and outputs to swapchain + VkAttachmentReference uiAttachmentRefs[] = { + // depth + { + .attachment = 1, + .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL + }, + // swapchain output + { + .attachment = 2, + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL + } + }; + + VkSubpassDescription uiSubpassDesc = { + .flags = 0, + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .inputAttachmentCount = 0, + .pInputAttachments = NULL, + .colorAttachmentCount = 1, + .pColorAttachments = &uiAttachmentRefs[1], + .pResolveAttachments = NULL, + .pDepthStencilAttachment = &uiAttachmentRefs[0], + .preserveAttachmentCount = 0, + .pPreserveAttachments = NULL + }; + + /* + * create the render passes + */ + // we're using 3 render passes which depend on each other (main color -> warp/postprocessing -> ui) + VkSubpassDependency subpassDeps[2] = { + { + .srcSubpass = VK_SUBPASS_EXTERNAL, + .dstSubpass = 0, + .srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .srcAccessMask = VK_ACCESS_SHADER_READ_BIT, + .dstAccessMask = (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT), + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT + }, + { + .srcSubpass = 0, + .dstSubpass = VK_SUBPASS_EXTERNAL, + .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT + } + }; + + VkRenderPassCreateInfo rpCreateInfos[] = { + // offscreen world rendering to color buffer (RP_WORLD) + { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .attachmentCount = msaaEnabled ? 3 : 2, + .pAttachments = worldAttachments, + .subpassCount = 1, + .pSubpasses = &worldSubpassDesc, + .dependencyCount = 2, + .pDependencies = subpassDeps + }, + // UI rendering (RP_UI) + { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .attachmentCount = 3, + .pAttachments = uiAttachments, + .subpassCount = 1, + .pSubpasses = &uiSubpassDesc, + .dependencyCount = 2, + .pDependencies = subpassDeps + }, + // world warp/postprocessing render pass (RP_WORLD_WARP) + { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .attachmentCount = 2, + .pAttachments = warpAttachments, + .subpassCount = 1, + .pSubpasses = &warpSubpassDesc, + .dependencyCount = 2, + .pDependencies = subpassDeps + } + }; + + for (int i = 0; i < RP_COUNT; ++i) + { + VkResult res = vkCreateRenderPass(vk_device.logical, &rpCreateInfos[i], NULL, &vk_renderpasses[i].rp); + if (res != VK_SUCCESS) + { + R_Printf(PRINT_ALL, "%s(): renderpass #%d create error: %s\n", __func__, i, QVk_GetError(res)); + return res; + } + QVk_DebugSetObjectName((uint64_t)vk_renderpasses[i].rp, VK_OBJECT_TYPE_RENDER_PASS, + va("Render Pass: %s", renderpassObjectNames[i])); + } + + return VK_SUCCESS; +} + +// internal helper +static void CreateDrawBuffers() +{ + QVk_CreateDepthBuffer(vk_renderpasses[RP_WORLD].sampleCount, + &vk_depthbuffer); + R_Printf(PRINT_ALL, "...created world depth buffer\n"); + QVk_CreateDepthBuffer(VK_SAMPLE_COUNT_1_BIT, &vk_ui_depthbuffer); + R_Printf(PRINT_ALL, "...created UI depth buffer\n"); + QVk_CreateColorBuffer(VK_SAMPLE_COUNT_1_BIT, &vk_colorbuffer, + VK_IMAGE_USAGE_SAMPLED_BIT); + R_Printf(PRINT_ALL, "...created world color buffer\n"); + QVk_CreateColorBuffer(VK_SAMPLE_COUNT_1_BIT, &vk_colorbufferWarp, + VK_IMAGE_USAGE_SAMPLED_BIT); + R_Printf(PRINT_ALL, "...created world postpocess color buffer\n"); + + if (vk_renderpasses[RP_WORLD].sampleCount > 1) + { + QVk_CreateColorBuffer(vk_renderpasses[RP_WORLD].sampleCount, &vk_msaaColorbuffer, + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT); + R_Printf(PRINT_ALL, "...created MSAAx%d color buffer\n", + vk_renderpasses[RP_WORLD].sampleCount); + } + + QVk_DebugSetObjectName((uint64_t)vk_depthbuffer.resource.image, + VK_OBJECT_TYPE_IMAGE, "Depth Buffer: World"); + QVk_DebugSetObjectName((uint64_t)vk_depthbuffer.imageView, + VK_OBJECT_TYPE_IMAGE_VIEW, "Image View: World Depth Buffer"); + QVk_DebugSetObjectName((uint64_t)vk_depthbuffer.resource.memory, + VK_OBJECT_TYPE_DEVICE_MEMORY, "Memory: World Depth Buffer"); + QVk_DebugSetObjectName((uint64_t)vk_ui_depthbuffer.resource.image, + VK_OBJECT_TYPE_IMAGE, "Depth Buffer: UI"); + QVk_DebugSetObjectName((uint64_t)vk_ui_depthbuffer.imageView, + VK_OBJECT_TYPE_IMAGE_VIEW, "Image View: UI Depth Buffer"); + QVk_DebugSetObjectName((uint64_t)vk_ui_depthbuffer.resource.memory, + VK_OBJECT_TYPE_DEVICE_MEMORY, "Memory: UI Depth Buffer"); + QVk_DebugSetObjectName((uint64_t)vk_colorbuffer.resource.image, + VK_OBJECT_TYPE_IMAGE, "Color Buffer: World"); + QVk_DebugSetObjectName((uint64_t)vk_colorbuffer.imageView, + VK_OBJECT_TYPE_IMAGE_VIEW, "Image View: World Color Buffer"); + QVk_DebugSetObjectName((uint64_t)vk_colorbuffer.resource.memory, + VK_OBJECT_TYPE_DEVICE_MEMORY, "Memory: World Color Buffer"); + QVk_DebugSetObjectName((uint64_t)vk_colorbufferWarp.resource.image, + VK_OBJECT_TYPE_IMAGE, "Color Buffer: Warp Postprocess"); + QVk_DebugSetObjectName((uint64_t)vk_colorbufferWarp.imageView, + VK_OBJECT_TYPE_IMAGE_VIEW, "Image View: Warp Postprocess Color Buffer"); + QVk_DebugSetObjectName((uint64_t)vk_colorbufferWarp.resource.memory, + VK_OBJECT_TYPE_DEVICE_MEMORY, "Memory: Warp Postprocess Color Buffer"); + + if (vk_renderpasses[RP_WORLD].sampleCount > 1) + { + QVk_DebugSetObjectName((uint64_t)vk_msaaColorbuffer.resource.image, + VK_OBJECT_TYPE_IMAGE, "Color Buffer: MSAA"); + QVk_DebugSetObjectName((uint64_t)vk_msaaColorbuffer.imageView, + VK_OBJECT_TYPE_IMAGE_VIEW, "Image View: MSAA Color Buffer"); + QVk_DebugSetObjectName((uint64_t)vk_msaaColorbuffer.resource.memory, + VK_OBJECT_TYPE_DEVICE_MEMORY, "Memory: MSAA Color Buffer"); + } +} + +// internal helper +static void DestroyDrawBuffer(qvktexture_t *drawBuffer) +{ + if (drawBuffer->imageView != VK_NULL_HANDLE) + { + vkDestroyImageView(vk_device.logical, drawBuffer->imageView, NULL); + drawBuffer->imageView = VK_NULL_HANDLE; + } + + if (drawBuffer->resource.image != VK_NULL_HANDLE) + { + image_destroy(&drawBuffer->resource); + } +} + +// internal helper +static void DestroyDrawBuffers() +{ + DestroyDrawBuffer(&vk_depthbuffer); + DestroyDrawBuffer(&vk_ui_depthbuffer); + DestroyDrawBuffer(&vk_colorbuffer); + DestroyDrawBuffer(&vk_colorbufferWarp); + DestroyDrawBuffer(&vk_msaaColorbuffer); +} + +// internal helper +static void CreateDescriptorSetLayouts() +{ + VkDescriptorSetLayoutBinding layoutBinding = { + .binding = 0, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, + .pImmutableSamplers = NULL + }; + + VkDescriptorSetLayoutCreateInfo layoutInfo = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .bindingCount = 1, + .pBindings = &layoutBinding + }; + + // uniform buffer object layout + VK_VERIFY(vkCreateDescriptorSetLayout(vk_device.logical, &layoutInfo, NULL, &vk_uboDescSetLayout)); + // sampler layout + layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + layoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + VK_VERIFY(vkCreateDescriptorSetLayout(vk_device.logical, &layoutInfo, NULL, &vk_samplerDescSetLayout)); + // secondary sampler: lightmaps + VK_VERIFY(vkCreateDescriptorSetLayout(vk_device.logical, &layoutInfo, NULL, &vk_samplerLightmapDescSetLayout)); + + QVk_DebugSetObjectName((uint64_t)vk_uboDescSetLayout, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, "Descriptor Set Layout: UBO"); + QVk_DebugSetObjectName((uint64_t)vk_samplerDescSetLayout, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, "Descriptor Set Layout: Sampler"); + QVk_DebugSetObjectName((uint64_t)vk_samplerLightmapDescSetLayout, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, "Descriptor Set Layout: Sampler + Lightmap"); +} + +// internal helper +static void CreateSamplersHelper(VkSampler *samplers, VkSamplerAddressMode addressMode) +{ + VkSamplerCreateInfo samplerInfo = { + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .magFilter = VK_FILTER_NEAREST, + .minFilter = VK_FILTER_NEAREST, + .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, + .addressModeU = addressMode, + .addressModeV = addressMode, + .addressModeW = addressMode, + .mipLodBias = 0.f, + .anisotropyEnable = VK_FALSE, + .maxAnisotropy = 1.f, + .compareEnable = VK_FALSE, + .compareOp = VK_COMPARE_OP_ALWAYS, + .minLod = 0.f, + .maxLod = 1.f, + .borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK, + .unnormalizedCoordinates = VK_FALSE + }; + + assert((vk_device.properties.limits.maxSamplerAnisotropy > 1.f) && "maxSamplerAnisotropy is 1"); + if (vk_device.features.samplerAnisotropy && vk_aniso->value > 0.f) + { + const float maxAniso = min(max(vk_aniso->value, 1.f), vk_device.properties.limits.maxSamplerAnisotropy); + samplerInfo.anisotropyEnable = VK_TRUE; + samplerInfo.maxAnisotropy = maxAniso; + } + + VK_VERIFY(vkCreateSampler(vk_device.logical, &samplerInfo, NULL, &samplers[S_NEAREST])); + QVk_DebugSetObjectName((uint64_t)samplers[S_NEAREST], VK_OBJECT_TYPE_SAMPLER, "Sampler: S_NEAREST"); + + { + VkSamplerCreateInfo nuSamplerInfo = samplerInfo; + + // unnormalizedCoordinates set to VK_TRUE forces other parameters to have restricted values. + nuSamplerInfo.minLod = 0.f; + nuSamplerInfo.maxLod = 0.f; + nuSamplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + nuSamplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + nuSamplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + nuSamplerInfo.unnormalizedCoordinates = VK_TRUE; + nuSamplerInfo.anisotropyEnable = VK_FALSE; + nuSamplerInfo.maxAnisotropy = 1.f; + + VK_VERIFY(vkCreateSampler(vk_device.logical, &nuSamplerInfo, NULL, &samplers[S_NEAREST_UNNORMALIZED])); + QVk_DebugSetObjectName((uint64_t)samplers[S_NEAREST_UNNORMALIZED], VK_OBJECT_TYPE_SAMPLER, "Sampler: S_NEAREST_UNNORMALIZED"); + } + + samplerInfo.maxLod = FLT_MAX; + VK_VERIFY(vkCreateSampler(vk_device.logical, &samplerInfo, NULL, &samplers[S_MIPMAP_NEAREST])); + QVk_DebugSetObjectName((uint64_t)samplers[S_MIPMAP_NEAREST], VK_OBJECT_TYPE_SAMPLER, "Sampler: S_MIPMAP_NEAREST"); + + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + VK_VERIFY(vkCreateSampler(vk_device.logical, &samplerInfo, NULL, &samplers[S_MIPMAP_LINEAR])); + QVk_DebugSetObjectName((uint64_t)samplers[S_MIPMAP_LINEAR], VK_OBJECT_TYPE_SAMPLER, "Sampler: S_MIPMAP_LINEAR"); + + samplerInfo.maxLod = 1.f; + VK_VERIFY(vkCreateSampler(vk_device.logical, &samplerInfo, NULL, &samplers[S_LINEAR])); + QVk_DebugSetObjectName((uint64_t)samplers[S_LINEAR], VK_OBJECT_TYPE_SAMPLER, "Sampler: S_LINEAR"); +} + +// internal helper +static void CreateSamplers() +{ + CreateSamplersHelper(vk_samplers, VK_SAMPLER_ADDRESS_MODE_REPEAT); + CreateSamplersHelper(vk_samplers + S_SAMPLER_CNT, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); +} + +// internal helper +static void DestroySamplers() +{ + int i; + for (i = 0; i < NUM_SAMPLERS; ++i) + { + if (vk_samplers[i] != VK_NULL_HANDLE) + vkDestroySampler(vk_device.logical, vk_samplers[i], NULL); + + vk_samplers[i] = VK_NULL_HANDLE; + } +} + +// internal helper +static void CreateDescriptorPool() +{ + VkDescriptorPoolSize poolSizes[] = { + // UBO + { + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, + .descriptorCount = 16 + }, + // sampler + { + .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .descriptorCount = MAX_VKTEXTURES + 1 + } + }; + + VkDescriptorPoolCreateInfo poolInfo = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .pNext = NULL, + .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, + .maxSets = MAX_VKTEXTURES + 32, + .poolSizeCount = sizeof(poolSizes) / sizeof(poolSizes[0]), + .pPoolSizes = poolSizes, + }; + + VK_VERIFY(vkCreateDescriptorPool(vk_device.logical, &poolInfo, NULL, &vk_descriptorPool)); + QVk_DebugSetObjectName((uint64_t)vk_descriptorPool, VK_OBJECT_TYPE_DESCRIPTOR_POOL, "Descriptor Pool: Sampler + UBO"); +} + +// internal helper +static void CreateUboDescriptorSet(VkDescriptorSet *descSet, VkBuffer buffer) +{ + VkDescriptorSetAllocateInfo dsAllocInfo = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .pNext = NULL, + .descriptorPool = vk_descriptorPool, + .descriptorSetCount = 1, + .pSetLayouts = &vk_uboDescSetLayout + }; + + VK_VERIFY(vkAllocateDescriptorSets(vk_device.logical, &dsAllocInfo, descSet)); + + VkDescriptorBufferInfo bufferInfo = { + .buffer = buffer, + .offset = 0, + .range = UNIFORM_ALLOC_SIZE + }; + + VkWriteDescriptorSet descriptorWrite = { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = NULL, + .dstSet = *descSet, + .dstBinding = 0, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, + .pImageInfo = NULL, + .pBufferInfo = &bufferInfo, + .pTexelBufferView = NULL, + }; + + vkUpdateDescriptorSets(vk_device.logical, 1, &descriptorWrite, 0, NULL); +} + +// internal helper +static void CreateDynamicBuffers() +{ + for (int i = 0; i < NUM_DYNBUFFERS; ++i) + { + QVk_CreateVertexBuffer(NULL, vk_config.vertex_buffer_size, &vk_dynVertexBuffers[i], + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_MEMORY_PROPERTY_HOST_CACHED_BIT); + QVk_CreateIndexBuffer(NULL, vk_config.index_buffer_size, &vk_dynIndexBuffers[i], + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_MEMORY_PROPERTY_HOST_CACHED_BIT); + VK_VERIFY(QVk_CreateUniformBuffer(vk_config.uniform_buffer_size, + &vk_dynUniformBuffers[i], VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + VK_MEMORY_PROPERTY_HOST_CACHED_BIT)); + // keep dynamic buffers persistently mapped + vk_dynVertexBuffers[i].pMappedData = buffer_map(&vk_dynVertexBuffers[i].resource); + vk_dynIndexBuffers[i].pMappedData = buffer_map(&vk_dynIndexBuffers[i].resource); + vk_dynUniformBuffers[i].pMappedData = buffer_map(&vk_dynUniformBuffers[i].resource); + // create descriptor set for the uniform buffer + CreateUboDescriptorSet(&vk_uboDescriptorSets[i], vk_dynUniformBuffers[i].resource.buffer); + + QVk_DebugSetObjectName((uint64_t)vk_uboDescriptorSets[i], + VK_OBJECT_TYPE_DESCRIPTOR_SET, va("Dynamic UBO Descriptor Set #%d", i)); + QVk_DebugSetObjectName((uint64_t)vk_dynVertexBuffers[i].resource.buffer, + VK_OBJECT_TYPE_BUFFER, va("Dynamic Vertex Buffer #%d", i)); + QVk_DebugSetObjectName((uint64_t)vk_dynVertexBuffers[i].resource.memory, + VK_OBJECT_TYPE_DEVICE_MEMORY, va("Memory: Dynamic Vertex Buffer #%d", i)); + QVk_DebugSetObjectName((uint64_t)vk_dynIndexBuffers[i].resource.buffer, + VK_OBJECT_TYPE_BUFFER, va("Dynamic Index Buffer #%d", i)); + QVk_DebugSetObjectName((uint64_t)vk_dynIndexBuffers[i].resource.memory, + VK_OBJECT_TYPE_DEVICE_MEMORY, va("Memory: Dynamic Index Buffer #%d", i)); + QVk_DebugSetObjectName((uint64_t)vk_dynUniformBuffers[i].resource.buffer, + VK_OBJECT_TYPE_BUFFER, va("Dynamic Uniform Buffer #%d", i)); + QVk_DebugSetObjectName((uint64_t)vk_dynUniformBuffers[i].resource.memory, + VK_OBJECT_TYPE_DEVICE_MEMORY, va("Memory: Dynamic Uniform Buffer #%d", i)); + } +} + +// internal helper +static void ReleaseSwapBuffers() +{ + vk_activeSwapBufferIdx = (vk_activeSwapBufferIdx + 1) % NUM_SWAPBUFFER_SLOTS; + int releaseBufferIdx = (vk_activeSwapBufferIdx + 1) % NUM_SWAPBUFFER_SLOTS; + + if (vk_swapBuffersCnt[releaseBufferIdx] > 0) + { + for (int i = 0; i < vk_swapBuffersCnt[releaseBufferIdx]; i++) + QVk_FreeBuffer(&vk_swapBuffers[releaseBufferIdx][i]); + + free(vk_swapBuffers[releaseBufferIdx]); + vk_swapBuffers[releaseBufferIdx] = NULL; + vk_swapBuffersCnt[releaseBufferIdx] = 0; + } + + if (vk_swapDescSetsCnt[releaseBufferIdx] > 0) + { + vkFreeDescriptorSets(vk_device.logical, vk_descriptorPool, vk_swapDescSetsCnt[releaseBufferIdx], vk_swapDescriptorSets[releaseBufferIdx]); + + free(vk_swapDescriptorSets[releaseBufferIdx]); + vk_swapDescriptorSets[releaseBufferIdx] = NULL; + vk_swapDescSetsCnt[releaseBufferIdx] = 0; + } +} + +// internal helper +static int NextPow2(int v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; +} + +// internal helper +static uint8_t *QVk_GetIndexBuffer(VkDeviceSize size, VkDeviceSize *dstOffset, int currentBufferIdx); +static void RebuildTriangleIndexBuffer() +{ + int idx = 0; + VkDeviceSize dstOffset = 0; + VkDeviceSize bufferSize = 3 * vk_config.triangle_index_count * sizeof(uint16_t); + uint16_t *iboData = NULL; + uint16_t *fanData = malloc(bufferSize); + uint16_t *stripData = malloc(bufferSize); + + // fill the index buffer so that we can emulate triangle fans via triangle lists + for (int i = 0; i < vk_config.triangle_index_count; ++i) + { + fanData[idx++] = 0; + fanData[idx++] = i + 1; + fanData[idx++] = i + 2; + } + + // fill the index buffer so that we can emulate triangle strips via triangle lists + idx = 0; + for (int i = 2; i < (vk_config.triangle_index_count + 2); ++i) + { + if ((i%2) == 0) + { + stripData[idx++] = i - 2; + stripData[idx++] = i - 1; + stripData[idx++] = i; + } + else + { + stripData[idx++] = i; + stripData[idx++] = i - 1; + stripData[idx++] = i - 2; + } + } + + for (int i = 0; i < NUM_DYNBUFFERS; ++i) + { + VK_VERIFY(buffer_invalidate(&vk_dynIndexBuffers[i].resource)); + + iboData = (uint16_t *)QVk_GetIndexBuffer(bufferSize, &dstOffset, i); + if ((i%2) == 0) + { + memcpy(iboData, fanData, bufferSize); + } + else + { + memcpy(iboData, stripData, bufferSize); + } + + VK_VERIFY(buffer_flush(&vk_dynIndexBuffers[i].resource)); + } + + vk_triangleFanIbo = &vk_dynIndexBuffers[0].resource.buffer; + vk_triangleStripIbo = &vk_dynIndexBuffers[1].resource.buffer; + vk_triangleFanIboUsage = ((bufferSize % 4) == 0) ? bufferSize : (bufferSize + 4 - (bufferSize % 4)); + + free(fanData); + free(stripData); +} + +static void CreateStagingBuffer(VkDeviceSize size, qvkstagingbuffer_t *dstBuffer, int i) +{ + VkFenceCreateInfo fCreateInfo = { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .flags = 0 + }; + + VK_VERIFY(QVk_CreateStagingBuffer(size, + dstBuffer, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + VK_MEMORY_PROPERTY_HOST_CACHED_BIT)); + dstBuffer->pMappedData = buffer_map(&dstBuffer->resource); + dstBuffer->submitted = false; + + VK_VERIFY(vkCreateFence(vk_device.logical, &fCreateInfo, + NULL, &dstBuffer->fence)); + + dstBuffer->cmdBuffer = QVk_CreateCommandBuffer(&vk_stagingCommandPool[i], + VK_COMMAND_BUFFER_LEVEL_PRIMARY); + VK_VERIFY(QVk_BeginCommand(&dstBuffer->cmdBuffer)); + + QVk_DebugSetObjectName((uint64_t)dstBuffer->fence, + VK_OBJECT_TYPE_FENCE, va("Fence: Staging Buffer #%d", i)); + QVk_DebugSetObjectName((uint64_t)dstBuffer->resource.buffer, + VK_OBJECT_TYPE_BUFFER, va("Staging Buffer #%d", i)); + QVk_DebugSetObjectName((uint64_t)dstBuffer->resource.memory, + VK_OBJECT_TYPE_DEVICE_MEMORY, va("Memory: Staging Buffer #%d", i)); + QVk_DebugSetObjectName((uintptr_t)dstBuffer->cmdBuffer, + VK_OBJECT_TYPE_COMMAND_BUFFER, va("Command Buffer: Staging Buffer #%d", i)); +} + +// internal helper +static void CreateStagingBuffers() +{ + for (int i = 0; i < NUM_DYNBUFFERS; ++i) + { + VK_VERIFY(QVk_CreateCommandPool(&vk_stagingCommandPool[i], + vk_device.gfxFamilyIndex)); + QVk_DebugSetObjectName((uint64_t)vk_stagingCommandPool[i], + VK_OBJECT_TYPE_COMMAND_POOL, va("Command Pool #%d: Staging", i)); + + CreateStagingBuffer(STAGING_BUFFER_MAXSIZE, &vk_stagingBuffers[i], i); + } +} + +// Records a memory barrier in the given command buffer. +void Qvk_MemoryBarrier(VkCommandBuffer cmdBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask) +{ + const VkMemoryBarrier memBarrier = { + .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, + .pNext = NULL, + .srcAccessMask = srcAccessMask, + .dstAccessMask = dstAccessMask, + }; + vkCmdPipelineBarrier(cmdBuffer, srcStageMask, dstStageMask, 0u, 1u, &memBarrier, 0u, NULL, 0u, NULL); +} + +// internal helper +static void SubmitStagingBuffer(int index) +{ + if (vk_stagingBuffers[index].submitted) + { + // buffer is alredy submitted + return; + } + + Qvk_MemoryBarrier(vk_stagingBuffers[index].cmdBuffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT, + (VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT)); + + VK_VERIFY(vkEndCommandBuffer(vk_stagingBuffers[index].cmdBuffer)); + + VkSubmitInfo submitInfo = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .waitSemaphoreCount = 0, + .pWaitSemaphores = NULL, + .signalSemaphoreCount = 0, + .pSignalSemaphores = NULL, + .pWaitDstStageMask = NULL, + .commandBufferCount = 1, + .pCommandBuffers = &vk_stagingBuffers[index].cmdBuffer + }; + + VK_VERIFY(vkQueueSubmit(vk_device.gfxQueue, 1, &submitInfo, vk_stagingBuffers[index].fence)); + + vk_stagingBuffers[index].submitted = true; + vk_activeStagingBuffer = (vk_activeStagingBuffer + 1) % NUM_DYNBUFFERS; +} + +// internal helper +static void CreateStaticBuffers() +{ + const float texVerts[] = { -1., -1., 0., 0., + 1., 1., 1., 1., + -1., 1., 0., 1., + 1., -1., 1., 0. }; + + const float colorVerts[] = { -1., -1., + 1., 1., + -1., 1., + 1., -1. }; + + const uint32_t indices[] = { 0, 1, 2, 0, 3, 1 }; + + QVk_CreateVertexBuffer(texVerts, sizeof(texVerts), + &vk_texRectVbo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0); + QVk_CreateVertexBuffer(colorVerts, sizeof(colorVerts), + &vk_colorRectVbo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0); + QVk_CreateIndexBuffer(indices, sizeof(indices), + &vk_rectIbo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0); + + QVk_DebugSetObjectName((uint64_t)vk_texRectVbo.resource.buffer, + VK_OBJECT_TYPE_BUFFER, "Static Buffer: Textured Rectangle VBO"); + QVk_DebugSetObjectName((uint64_t)vk_texRectVbo.resource.memory, + VK_OBJECT_TYPE_DEVICE_MEMORY, "Memory: Textured Rectangle VBO"); + QVk_DebugSetObjectName((uint64_t)vk_colorRectVbo.resource.buffer, + VK_OBJECT_TYPE_BUFFER, "Static Buffer: Colored Rectangle VBO"); + QVk_DebugSetObjectName((uint64_t)vk_colorRectVbo.resource.memory, + VK_OBJECT_TYPE_DEVICE_MEMORY, "Memory: Colored Rectangle VBO"); + QVk_DebugSetObjectName((uint64_t)vk_rectIbo.resource.buffer, + VK_OBJECT_TYPE_BUFFER, "Static Buffer: Rectangle IBO"); + QVk_DebugSetObjectName((uint64_t)vk_rectIbo.resource.memory, + VK_OBJECT_TYPE_DEVICE_MEMORY, "Memory: Rectangle IBO"); +} + +static void +DestroyShaderModule(qvkshader_t *shaders) +{ + // final shader cleanup + for (int i = 0; i < SHADER_INDEX_SIZE; ++i) + { + if (shaders[i].module) + { + vkDestroyShaderModule(vk_device.logical, shaders[i].module, NULL); + memset(&shaders[i], 0, sizeof(qvkshader_t)); + } + } +} + +// internal helper +static void CreatePipelines() +{ + // shared pipeline vertex input state create infos + VK_VERTINFO(RG, sizeof(float) * 2, VK_INPUTATTR_DESC(0, VK_FORMAT_R32G32_SFLOAT, 0)); + + VK_VERTINFO(RGB, sizeof(float) * 3, VK_INPUTATTR_DESC(0, VK_FORMAT_R32G32B32_SFLOAT, 0)); + + VK_VERTINFO(RG_RG, sizeof(float) * 4, VK_INPUTATTR_DESC(0, VK_FORMAT_R32G32_SFLOAT, 0), + VK_INPUTATTR_DESC(1, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 2)); + + VK_VERTINFO(RGB_RG, sizeof(float) * 5, VK_INPUTATTR_DESC(0, VK_FORMAT_R32G32B32_SFLOAT, 0), + VK_INPUTATTR_DESC(1, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 3)); + + VK_VERTINFO(RGB_RGB, sizeof(float) * 6, VK_INPUTATTR_DESC(0, VK_FORMAT_R32G32B32_SFLOAT, 0), + VK_INPUTATTR_DESC(1, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 3)); + + VK_VERTINFO(RGB_RGBA, sizeof(float) * 7, VK_INPUTATTR_DESC(0, VK_FORMAT_R32G32B32_SFLOAT, 0), + VK_INPUTATTR_DESC(1, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(float) * 3)); + + VK_VERTINFO(RGB_RG_RG, sizeof(float) * 7, VK_INPUTATTR_DESC(0, VK_FORMAT_R32G32B32_SFLOAT, 0), + VK_INPUTATTR_DESC(1, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 3), + VK_INPUTATTR_DESC(2, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 5)); + + VK_VERTINFO(RGB_RGBA_RG, sizeof(float) * 9, VK_INPUTATTR_DESC(0, VK_FORMAT_R32G32B32_SFLOAT, 0), + VK_INPUTATTR_DESC(1, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(float) * 3), + VK_INPUTATTR_DESC(2, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 7)); + // no vertices passed to the pipeline (postprocessing) + VkPipelineVertexInputStateCreateInfo vertInfoNull = VK_NULL_VERTEXINPUT_CINF; + + // shared descriptor set layouts + VkDescriptorSetLayout samplerUboDsLayouts[] = { vk_samplerDescSetLayout, vk_uboDescSetLayout }; + VkDescriptorSetLayout samplerUboLmapDsLayouts[] = { vk_samplerDescSetLayout, vk_uboDescSetLayout, vk_samplerLightmapDescSetLayout }; + + // shader array (vertex and fragment, no compute... yet) + qvkshader_t shaders[SHADER_INDEX_SIZE] = {0}; + + // textured quad pipeline + VK_LOAD_VERTFRAG_SHADERS(shaders, basic, basic); + for (int i = 0; i < RP_COUNT; ++i) + { + vk_drawTexQuadPipeline[i].depthTestEnable = VK_FALSE; + QVk_CreatePipeline(samplerUboDsLayouts, 2, &vertInfoRG_RG, &vk_drawTexQuadPipeline[i], &vk_renderpasses[i], shaders, 2); + QVk_DebugSetObjectName((uint64_t)vk_drawTexQuadPipeline[i].layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, + va("Pipeline Layout: textured quad (%s)", renderpassObjectNames[i])); + QVk_DebugSetObjectName((uint64_t)vk_drawTexQuadPipeline[i].pl, VK_OBJECT_TYPE_PIPELINE, + va("Pipeline: textured quad (%s)", renderpassObjectNames[i])); + } + + // draw particles pipeline (using a texture) + VK_LOAD_VERTFRAG_SHADERS(shaders, particle, basic); + vk_drawParticlesPipeline.depthWriteEnable = VK_TRUE; + vk_drawParticlesPipeline.blendOpts.blendEnable = VK_TRUE; + QVk_CreatePipeline(&vk_samplerDescSetLayout, 1, &vertInfoRGB_RGBA_RG, &vk_drawParticlesPipeline, &vk_renderpasses[RP_WORLD], shaders, 2); + QVk_DebugSetObjectName((uint64_t)vk_drawParticlesPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: textured particles"); + QVk_DebugSetObjectName((uint64_t)vk_drawParticlesPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: textured particles"); + + // draw particles pipeline (using point list) + VK_LOAD_VERTFRAG_SHADERS(shaders, point_particle, point_particle); + vk_drawPointParticlesPipeline.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; + vk_drawPointParticlesPipeline.depthWriteEnable = VK_TRUE; + vk_drawPointParticlesPipeline.blendOpts.blendEnable = VK_TRUE; + QVk_CreatePipeline(&vk_uboDescSetLayout, 1, &vertInfoRGB_RGBA, &vk_drawPointParticlesPipeline, &vk_renderpasses[RP_WORLD], shaders, 2); + QVk_DebugSetObjectName((uint64_t)vk_drawPointParticlesPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: point particles"); + QVk_DebugSetObjectName((uint64_t)vk_drawPointParticlesPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: point particles"); + + // colored quad pipeline + VK_LOAD_VERTFRAG_SHADERS(shaders, basic_color_quad, basic_color_quad); + for (int i = 0; i < RP_COUNT; ++i) + { + vk_drawColorQuadPipeline[i].depthTestEnable = VK_FALSE; + vk_drawColorQuadPipeline[i].blendOpts.blendEnable = VK_TRUE; + QVk_CreatePipeline(&vk_uboDescSetLayout, 1, &vertInfoRG, &vk_drawColorQuadPipeline[i], &vk_renderpasses[i], shaders, 2); + QVk_DebugSetObjectName((uint64_t)vk_drawColorQuadPipeline[i].layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, + va("Pipeline Layout: colored quad (%s)", renderpassObjectNames[i])); + QVk_DebugSetObjectName((uint64_t)vk_drawColorQuadPipeline[i].pl, VK_OBJECT_TYPE_PIPELINE, + va("Pipeline: colored quad (%s)", renderpassObjectNames[i])); + } + + // untextured null model + VK_LOAD_VERTFRAG_SHADERS(shaders, nullmodel, basic_color_quad); + vk_drawNullModelPipeline.cullMode = VK_CULL_MODE_NONE; + vk_drawNullModelPipeline.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + QVk_CreatePipeline(&vk_uboDescSetLayout, 1, &vertInfoRGB_RGB, &vk_drawNullModelPipeline, &vk_renderpasses[RP_WORLD], shaders, 2); + QVk_DebugSetObjectName((uint64_t)vk_drawNullModelPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: null model"); + QVk_DebugSetObjectName((uint64_t)vk_drawNullModelPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: null model"); + + // textured model + VK_LOAD_VERTFRAG_SHADERS(shaders, model, model); + for (int i = 0; i < RP_COUNT; ++i) + { + vk_drawModelPipelineFan[i].topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + vk_drawModelPipelineFan[i].blendOpts.blendEnable = VK_TRUE; + QVk_CreatePipeline(samplerUboDsLayouts, 2, &vertInfoRGB_RGBA_RG, &vk_drawModelPipelineFan[i], &vk_renderpasses[i], shaders, 2); + QVk_DebugSetObjectName((uint64_t)vk_drawModelPipelineFan[i].layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, + va("Pipeline Layout: draw model: fan (%s)", renderpassObjectNames[i])); + QVk_DebugSetObjectName((uint64_t)vk_drawModelPipelineFan[i].pl, VK_OBJECT_TYPE_PIPELINE, + va("Pipeline: draw model: fan (%s)", renderpassObjectNames[i])); + } + + // dedicated model pipelines for translucent objects with depth write disabled + vk_drawNoDepthModelPipelineFan.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + vk_drawNoDepthModelPipelineFan.depthWriteEnable = VK_FALSE; + vk_drawNoDepthModelPipelineFan.blendOpts.blendEnable = VK_TRUE; + QVk_CreatePipeline(samplerUboDsLayouts, 2, &vertInfoRGB_RGBA_RG, &vk_drawNoDepthModelPipelineFan, &vk_renderpasses[RP_WORLD], shaders, 2); + QVk_DebugSetObjectName((uint64_t)vk_drawNoDepthModelPipelineFan.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: translucent model: fan"); + QVk_DebugSetObjectName((uint64_t)vk_drawNoDepthModelPipelineFan.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: translucent model: fan"); + + // dedicated model pipelines for when left-handed weapon model is drawn + vk_drawLefthandModelPipelineFan.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + vk_drawLefthandModelPipelineFan.cullMode = VK_CULL_MODE_FRONT_BIT; + QVk_CreatePipeline(samplerUboDsLayouts, 2, &vertInfoRGB_RGBA_RG, &vk_drawLefthandModelPipelineFan, &vk_renderpasses[RP_WORLD], shaders, 2); + QVk_DebugSetObjectName((uint64_t)vk_drawLefthandModelPipelineFan.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: left-handed model: fan"); + QVk_DebugSetObjectName((uint64_t)vk_drawLefthandModelPipelineFan.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: left-handed model: fan"); + + // draw sprite pipeline + VK_LOAD_VERTFRAG_SHADERS(shaders, sprite, basic); + vk_drawSpritePipeline.blendOpts.blendEnable = VK_TRUE; + QVk_CreatePipeline(&vk_samplerDescSetLayout, 1, &vertInfoRGB_RG, &vk_drawSpritePipeline, &vk_renderpasses[RP_WORLD], shaders, 2); + QVk_DebugSetObjectName((uint64_t)vk_drawSpritePipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: sprite"); + QVk_DebugSetObjectName((uint64_t)vk_drawSpritePipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: sprite"); + + // draw polygon pipeline + VK_LOAD_VERTFRAG_SHADERS(shaders, polygon, basic); + vk_drawPolyPipeline.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + vk_drawPolyPipeline.blendOpts.blendEnable = VK_TRUE; + QVk_CreatePipeline(samplerUboDsLayouts, 2, &vertInfoRGB_RG, &vk_drawPolyPipeline, &vk_renderpasses[RP_WORLD], shaders, 2); + QVk_DebugSetObjectName((uint64_t)vk_drawPolyPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: polygon"); + QVk_DebugSetObjectName((uint64_t)vk_drawPolyPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: polygon"); + + // draw lightmapped polygon + VK_LOAD_VERTFRAG_SHADERS(shaders, polygon_lmap, polygon_lmap); + vk_drawPolyLmapPipeline.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + QVk_CreatePipeline(samplerUboLmapDsLayouts, 3, &vertInfoRGB_RG_RG, &vk_drawPolyLmapPipeline, &vk_renderpasses[RP_WORLD], shaders, 2); + QVk_DebugSetObjectName((uint64_t)vk_drawPolyLmapPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: lightmapped polygon"); + QVk_DebugSetObjectName((uint64_t)vk_drawPolyLmapPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: lightmapped polygon"); + + // draw polygon with warp effect (liquid) pipeline + VK_LOAD_VERTFRAG_SHADERS(shaders, polygon_warp, basic); + vk_drawPolyWarpPipeline.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + vk_drawPolyWarpPipeline.blendOpts.blendEnable = VK_TRUE; + QVk_CreatePipeline(samplerUboLmapDsLayouts, 2, &vertInfoRGB_RG, &vk_drawPolyWarpPipeline, &vk_renderpasses[RP_WORLD], shaders, 2); + QVk_DebugSetObjectName((uint64_t)vk_drawPolyWarpPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: warped polygon (liquids)"); + QVk_DebugSetObjectName((uint64_t)vk_drawPolyWarpPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: warped polygon (liquids)"); + + // draw solid polygon with warp effect (liquid) pipeline + VK_LOAD_VERTFRAG_SHADERS(shaders, polygon_warp, basic); + vk_drawPolySolidWarpPipeline.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + QVk_CreatePipeline(samplerUboLmapDsLayouts, 2, &vertInfoRGB_RG, + &vk_drawPolySolidWarpPipeline, &vk_renderpasses[RP_WORLD], + shaders, 2); + QVk_DebugSetObjectName((uint64_t)vk_drawPolySolidWarpPipeline.layout, + VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: warped solid polygon (liquids)"); + QVk_DebugSetObjectName((uint64_t)vk_drawPolySolidWarpPipeline.pl, + VK_OBJECT_TYPE_PIPELINE, "Pipeline: warped solid polygon (liquids)"); + + // draw beam pipeline + VK_LOAD_VERTFRAG_SHADERS(shaders, beam, basic_color_quad); + vk_drawBeamPipeline.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + vk_drawBeamPipeline.depthWriteEnable = VK_FALSE; + vk_drawBeamPipeline.blendOpts.blendEnable = VK_TRUE; + QVk_CreatePipeline(&vk_uboDescSetLayout, 1, &vertInfoRGB, &vk_drawBeamPipeline, &vk_renderpasses[RP_WORLD], shaders, 2); + QVk_DebugSetObjectName((uint64_t)vk_drawBeamPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: beam"); + QVk_DebugSetObjectName((uint64_t)vk_drawBeamPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: beam"); + + // draw skybox pipeline + VK_LOAD_VERTFRAG_SHADERS(shaders, skybox, basic); + QVk_CreatePipeline(samplerUboDsLayouts, 2, &vertInfoRGB_RG, &vk_drawSkyboxPipeline, &vk_renderpasses[RP_WORLD], shaders, 2); + QVk_DebugSetObjectName((uint64_t)vk_drawSkyboxPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: skybox"); + QVk_DebugSetObjectName((uint64_t)vk_drawSkyboxPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: skybox"); + + // draw dynamic light pipeline + VK_LOAD_VERTFRAG_SHADERS(shaders, d_light, basic_color_quad); + vk_drawDLightPipeline.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + vk_drawDLightPipeline.depthWriteEnable = VK_FALSE; + vk_drawDLightPipeline.cullMode = VK_CULL_MODE_FRONT_BIT; + vk_drawDLightPipeline.blendOpts.blendEnable = VK_TRUE; + vk_drawDLightPipeline.blendOpts.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; + vk_drawDLightPipeline.blendOpts.dstColorBlendFactor = VK_BLEND_FACTOR_ONE; + vk_drawDLightPipeline.blendOpts.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + vk_drawDLightPipeline.blendOpts.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + QVk_CreatePipeline(&vk_uboDescSetLayout, 1, &vertInfoRGB_RGB, &vk_drawDLightPipeline, &vk_renderpasses[RP_WORLD], shaders, 2); + QVk_DebugSetObjectName((uint64_t)vk_drawDLightPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: dynamic light"); + QVk_DebugSetObjectName((uint64_t)vk_drawDLightPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: dynamic light"); + + // vk_showtris render pipeline + VK_LOAD_VERTFRAG_SHADERS(shaders, d_light, basic_color_quad); + vk_showTrisPipeline.cullMode = VK_CULL_MODE_NONE; + vk_showTrisPipeline.depthTestEnable = VK_FALSE; + vk_showTrisPipeline.depthWriteEnable = VK_FALSE; + vk_showTrisPipeline.topology = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; + QVk_CreatePipeline(&vk_uboDescSetLayout, 1, &vertInfoRGB_RGB, &vk_showTrisPipeline, &vk_renderpasses[RP_WORLD], shaders, 2); + QVk_DebugSetObjectName((uint64_t)vk_showTrisPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: show triangles"); + QVk_DebugSetObjectName((uint64_t)vk_showTrisPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: show triangles"); + + //vk_shadows render pipeline + VK_LOAD_VERTFRAG_SHADERS(shaders, shadows, basic_color_quad); + vk_shadowsPipelineFan.blendOpts.blendEnable = VK_TRUE; + vk_shadowsPipelineFan.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + QVk_CreatePipeline(&vk_uboDescSetLayout, 1, &vertInfoRGB, &vk_shadowsPipelineFan, &vk_renderpasses[RP_WORLD], shaders, 2); + QVk_DebugSetObjectName((uint64_t)vk_shadowsPipelineFan.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: draw shadows: fan"); + QVk_DebugSetObjectName((uint64_t)vk_shadowsPipelineFan.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: draw shadows: fan"); + + // underwater world warp pipeline (postprocess) + VK_LOAD_VERTFRAG_SHADERS(shaders, world_warp, world_warp); + vk_worldWarpPipeline.depthTestEnable = VK_FALSE; + vk_worldWarpPipeline.depthWriteEnable = VK_FALSE; + vk_worldWarpPipeline.cullMode = VK_CULL_MODE_NONE; + QVk_CreatePipeline(&vk_samplerDescSetLayout, 1, &vertInfoNull, &vk_worldWarpPipeline, &vk_renderpasses[RP_WORLD_WARP], shaders, 2); + QVk_DebugSetObjectName((uint64_t)vk_worldWarpPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: underwater view warp"); + QVk_DebugSetObjectName((uint64_t)vk_worldWarpPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: underwater view warp"); + + // postprocessing pipeline + VK_LOAD_VERTFRAG_SHADERS(shaders, postprocess, postprocess); + vk_postprocessPipeline.depthTestEnable = VK_FALSE; + vk_postprocessPipeline.depthWriteEnable = VK_FALSE; + vk_postprocessPipeline.cullMode = VK_CULL_MODE_NONE; + QVk_CreatePipeline(&vk_samplerDescSetLayout, 1, &vertInfoNull, &vk_postprocessPipeline, &vk_renderpasses[RP_UI], shaders, 2); + QVk_DebugSetObjectName((uint64_t)vk_postprocessPipeline.layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "Pipeline Layout: world postprocess"); + QVk_DebugSetObjectName((uint64_t)vk_postprocessPipeline.pl, VK_OBJECT_TYPE_PIPELINE, "Pipeline: world postprocess"); + + DestroyShaderModule(shaders); +} + +static void DestroyStagingBuffer(qvkstagingbuffer_t *dstBuffer) +{ + if (dstBuffer->resource.buffer != VK_NULL_HANDLE) + { + // wait only if something is submitted + if (dstBuffer->submitted) + { + VK_VERIFY(vkWaitForFences(vk_device.logical, 1, &dstBuffer->fence, + VK_TRUE, UINT64_MAX)); + } + + buffer_unmap(&dstBuffer->resource); + QVk_FreeStagingBuffer(dstBuffer); + vkDestroyFence(vk_device.logical, dstBuffer->fence, NULL); + } +} + +/* +** QVk_Shutdown +** +** Destroy all Vulkan related resources. +*/ +void QVk_Shutdown( void ) +{ + if (!vk_initialized) + { + return; + } + + if (vk_instance != VK_NULL_HANDLE) + { + R_Printf(PRINT_ALL, "Shutting down Vulkan\n"); + + for (int i = 0; i < RP_COUNT; ++i) + { + QVk_DestroyPipeline(&vk_drawColorQuadPipeline[i]); + QVk_DestroyPipeline(&vk_drawModelPipelineFan[i]); + QVk_DestroyPipeline(&vk_drawTexQuadPipeline[i]); + } + QVk_DestroyPipeline(&vk_drawNullModelPipeline); + QVk_DestroyPipeline(&vk_drawNoDepthModelPipelineFan); + QVk_DestroyPipeline(&vk_drawLefthandModelPipelineFan); + QVk_DestroyPipeline(&vk_drawParticlesPipeline); + QVk_DestroyPipeline(&vk_drawPointParticlesPipeline); + QVk_DestroyPipeline(&vk_drawSpritePipeline); + QVk_DestroyPipeline(&vk_drawPolyPipeline); + QVk_DestroyPipeline(&vk_drawPolyLmapPipeline); + QVk_DestroyPipeline(&vk_drawPolyWarpPipeline); + QVk_DestroyPipeline(&vk_drawPolySolidWarpPipeline); + QVk_DestroyPipeline(&vk_drawBeamPipeline); + QVk_DestroyPipeline(&vk_drawSkyboxPipeline); + QVk_DestroyPipeline(&vk_drawDLightPipeline); + QVk_DestroyPipeline(&vk_showTrisPipeline); + QVk_DestroyPipeline(&vk_shadowsPipelineFan); + QVk_DestroyPipeline(&vk_worldWarpPipeline); + QVk_DestroyPipeline(&vk_postprocessPipeline); + QVk_FreeBuffer(&vk_texRectVbo); + QVk_FreeBuffer(&vk_colorRectVbo); + QVk_FreeBuffer(&vk_rectIbo); + for (int i = 0; i < NUM_DYNBUFFERS; ++i) + { + if (vk_dynUniformBuffers[i].resource.buffer != VK_NULL_HANDLE) + { + buffer_unmap(&vk_dynUniformBuffers[i].resource); + QVk_FreeBuffer(&vk_dynUniformBuffers[i]); + } + if (vk_dynIndexBuffers[i].resource.buffer != VK_NULL_HANDLE) + { + buffer_unmap(&vk_dynIndexBuffers[i].resource); + QVk_FreeBuffer(&vk_dynIndexBuffers[i]); + } + if (vk_dynVertexBuffers[i].resource.buffer != VK_NULL_HANDLE) + { + buffer_unmap(&vk_dynVertexBuffers[i].resource); + QVk_FreeBuffer(&vk_dynVertexBuffers[i]); + } + DestroyStagingBuffer(&vk_stagingBuffers[i]); + if (vk_stagingCommandPool[i] != VK_NULL_HANDLE) + { + vkDestroyCommandPool(vk_device.logical, vk_stagingCommandPool[i], NULL); + vk_stagingCommandPool[i] = VK_NULL_HANDLE; + } + } + if (vk_descriptorPool != VK_NULL_HANDLE) + vkDestroyDescriptorPool(vk_device.logical, vk_descriptorPool, NULL); + if (vk_uboDescSetLayout != VK_NULL_HANDLE) + vkDestroyDescriptorSetLayout(vk_device.logical, vk_uboDescSetLayout, NULL); + if (vk_samplerDescSetLayout != VK_NULL_HANDLE) + vkDestroyDescriptorSetLayout(vk_device.logical, vk_samplerDescSetLayout, NULL); + if (vk_samplerLightmapDescSetLayout != VK_NULL_HANDLE) + vkDestroyDescriptorSetLayout(vk_device.logical, vk_samplerLightmapDescSetLayout, NULL); + for (int i = 0; i < RP_COUNT; i++) + { + if (vk_renderpasses[i].rp != VK_NULL_HANDLE) + vkDestroyRenderPass(vk_device.logical, vk_renderpasses[i].rp, NULL); + vk_renderpasses[i].rp = VK_NULL_HANDLE; + } + + for (int i = 0; i < NUM_CMDBUFFERS; i++) + { + if (vk_commandPool[i] != VK_NULL_HANDLE) + { + vkFreeCommandBuffers(vk_device.logical, vk_commandPool[i], 1, &vk_commandbuffers[i]); + vkDestroyCommandPool(vk_device.logical, vk_commandPool[i], NULL); + vk_commandPool[i] = VK_NULL_HANDLE; + } + } + if (vk_commandbuffers != NULL) + { + free(vk_commandbuffers); + vk_commandbuffers = NULL; + } + if (vk_transferCommandPool != VK_NULL_HANDLE) + vkDestroyCommandPool(vk_device.logical, vk_transferCommandPool, NULL); + DestroySamplers(); + DestroyFramebuffers(); + DestroyImageViews(); + DestroyDrawBuffers(); + if (vk_swapchain.sc != VK_NULL_HANDLE) + { + vkDestroySwapchainKHR(vk_device.logical, vk_swapchain.sc, NULL); + free(vk_swapchain.images); + vk_swapchain.sc = VK_NULL_HANDLE; + vk_swapchain.images = NULL; + vk_swapchain.imageCount = 0; + } + if (vk_device.logical != VK_NULL_HANDLE) + { + for (int i = 0; i < NUM_CMDBUFFERS; ++i) + { + vkDestroySemaphore(vk_device.logical, vk_imageAvailableSemaphores[i], NULL); + vkDestroySemaphore(vk_device.logical, vk_renderFinishedSemaphores[i], NULL); + vkDestroyFence(vk_device.logical, vk_fences[i], NULL); + } + } + // free all memory + vulkan_memory_delete(); + + if (vk_device.logical != VK_NULL_HANDLE) + vkDestroyDevice(vk_device.logical, NULL); + if(vk_surface != VK_NULL_HANDLE) + vkDestroySurfaceKHR(vk_instance, vk_surface, NULL); + QVk_DestroyValidationLayers(); + + vkDestroyInstance(vk_instance, NULL); + vk_instance = VK_NULL_HANDLE; + vk_activeCmdbuffer = VK_NULL_HANDLE; + vk_descriptorPool = VK_NULL_HANDLE; + vk_uboDescSetLayout = VK_NULL_HANDLE; + vk_samplerDescSetLayout = VK_NULL_HANDLE; + vk_samplerLightmapDescSetLayout = VK_NULL_HANDLE; + vk_transferCommandPool = VK_NULL_HANDLE; + vk_activeBufferIdx = 0; + vk_imageIndex = 0; + } +} + +void QVk_SetWindow(SDL_Window *window) +{ + vk_window = window; +} + +void QVk_WaitAndShutdownAll (void) +{ + if (!vk_initialized) + { + return; + } + + if (vk_device.logical != VK_NULL_HANDLE) + { + vkDeviceWaitIdle(vk_device.logical); + } + + Mod_FreeAll(); + Mod_FreeModelsKnown(); + Vk_ShutdownImages(); + Mesh_Free(); + QVk_Shutdown(); + + vk_frameStarted = false; + vk_initialized = false; +} + +void QVk_Restart(void) +{ + QVk_WaitAndShutdownAll(); + if (!QVk_Init()) + ri.Sys_Error(ERR_FATAL, "Unable to restart Vulkan renderer"); + QVk_PostInit(); + ri.Vid_RequestRestart(RESTART_PARTIAL); +} + +void QVk_PostInit(void) +{ + Mesh_Init(); + Vk_InitImages(); + Mod_Init(); + RE_InitParticleTexture(); + Draw_InitLocal(); +} + +/* +** QVk_Init +** +** This is responsible for initializing Vulkan. +** +*/ +qboolean QVk_Init(void) +{ + PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion)vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion"); + uint32_t instanceVersion = VK_API_VERSION_1_0; + + if (vkEnumerateInstanceVersion) + { + VK_VERIFY(vkEnumerateInstanceVersion(&instanceVersion)); + } + + VkApplicationInfo appInfo = { + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pNext = NULL, + .pApplicationName = "Quake 2", + .applicationVersion = VK_MAKE_VERSION(3, 21, 0), + .pEngineName = "id Tech 2", + .engineVersion = VK_MAKE_VERSION(2, 0, 0), + .apiVersion = instanceVersion + }; + + uint32_t extCount; + const char **wantedExtensions; + memset(vk_config.supported_present_modes, 0, sizeof(vk_config.supported_present_modes)); + memset(vk_config.extensions, 0, sizeof(vk_config.extensions)); + memset(vk_config.layers, 0, sizeof(vk_config.layers)); + vk_config.vk_version = instanceVersion; + vk_config.vertex_buffer_usage = 0; + vk_config.vertex_buffer_max_usage = 0; + vk_config.vertex_buffer_size = VERTEX_BUFFER_SIZE; + vk_config.index_buffer_usage = 0; + vk_config.index_buffer_max_usage = 0; + vk_config.index_buffer_size = INDEX_BUFFER_SIZE; + vk_config.uniform_buffer_usage = 0; + vk_config.uniform_buffer_max_usage = 0; + vk_config.uniform_buffer_size = UNIFORM_BUFFER_SIZE; + vk_config.triangle_index_usage = 0; + vk_config.triangle_index_max_usage = 0; + vk_config.triangle_index_count = TRIANGLE_INDEX_CNT; + + if (!SDL_Vulkan_GetInstanceExtensions(vk_window, &extCount, NULL)) + { + R_Printf(PRINT_ALL, "%s() SDL_Vulkan_GetInstanceExtensions failed: %s", + __func__, SDL_GetError()); + return false; + } + + // add space for validation layer + if (vk_validation->value) + extCount++; + + wantedExtensions = malloc(extCount * sizeof(const char *)); + if (!SDL_Vulkan_GetInstanceExtensions(vk_window, &extCount, wantedExtensions)) + { + R_Printf(PRINT_ALL, "%s() SDL_Vulkan_GetInstanceExtensions failed: %s", + __func__, SDL_GetError()); + return false; + } + + // restore extensions count + if (vk_validation->value) + { + extCount++; + wantedExtensions[extCount - 1] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME; + } + + R_Printf(PRINT_ALL, "Enabled extensions: "); + for (int i = 0; i < extCount; i++) + { + R_Printf(PRINT_ALL, "%s ", wantedExtensions[i]); + vk_config.extensions[i] = wantedExtensions[i]; + } + R_Printf(PRINT_ALL, "\n"); + + VkInstanceCreateInfo createInfo = { + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pNext = NULL, + .pApplicationInfo = &appInfo, + .enabledLayerCount = 0, + .ppEnabledLayerNames = NULL, + .enabledExtensionCount = extCount, + .ppEnabledExtensionNames = (const char* const*)wantedExtensions + }; + +// introduced in SDK 1.1.121 +#if VK_HEADER_VERSION > 114 + VkValidationFeatureEnableEXT validationFeaturesEnable[] = { VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT }; + VkValidationFeaturesEXT validationFeatures = { + .sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT, + .pNext = NULL, + .enabledValidationFeatureCount = sizeof(validationFeaturesEnable) / sizeof(validationFeaturesEnable[0]), + .pEnabledValidationFeatures = validationFeaturesEnable, + .disabledValidationFeatureCount = 0, + .pDisabledValidationFeatures = NULL + }; + + if (vk_validation->value > 1) + { + createInfo.pNext = &validationFeatures; + } +#endif + +// introduced in SDK 1.1.106 +#if VK_HEADER_VERSION > 101 + const char *validationLayers[] = { "VK_LAYER_KHRONOS_validation" }; +#else + const char *validationLayers[] = { "VK_LAYER_LUNARG_standard_validation" }; +#endif + + if (vk_validation->value) + { + createInfo.enabledLayerCount = sizeof(validationLayers) / sizeof(validationLayers[0]); + createInfo.ppEnabledLayerNames = validationLayers; + for (int i = 0; i < createInfo.enabledLayerCount; i++) + { + vk_config.layers[i] = validationLayers[i]; + } + } + + VkResult res = vkCreateInstance(&createInfo, NULL, &vk_instance); + free(wantedExtensions); + + volkLoadInstance(vk_instance); + + if (res != VK_SUCCESS) + { + R_Printf(PRINT_ALL, "%s(): Could not create Vulkan instance: %s\n", __func__, QVk_GetError(res)); + return false; + } + R_Printf(PRINT_ALL, "...created Vulkan instance\n"); + + if (vk_validation->value) + { + // initialize function pointers + qvkCreateDebugUtilsMessengerEXT = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(vk_instance, "vkCreateDebugUtilsMessengerEXT"); + qvkDestroyDebugUtilsMessengerEXT = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(vk_instance, "vkDestroyDebugUtilsMessengerEXT"); + qvkSetDebugUtilsObjectNameEXT = (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(vk_instance, "vkSetDebugUtilsObjectNameEXT"); + qvkSetDebugUtilsObjectTagEXT = (PFN_vkSetDebugUtilsObjectTagEXT)vkGetInstanceProcAddr(vk_instance, "vkSetDebugUtilsObjectTagEXT"); + qvkCmdBeginDebugUtilsLabelEXT = (PFN_vkCmdBeginDebugUtilsLabelEXT)vkGetInstanceProcAddr(vk_instance, "vkCmdBeginDebugUtilsLabelEXT"); + qvkCmdEndDebugUtilsLabelEXT = (PFN_vkCmdEndDebugUtilsLabelEXT)vkGetInstanceProcAddr(vk_instance, "vkCmdEndDebugUtilsLabelEXT"); + qvkInsertDebugUtilsLabelEXT = (PFN_vkCmdInsertDebugUtilsLabelEXT)vkGetInstanceProcAddr(vk_instance, "vkCmdInsertDebugUtilsLabelEXT"); + } + else + { + qvkCreateDebugUtilsMessengerEXT = NULL; + qvkDestroyDebugUtilsMessengerEXT = NULL; + qvkSetDebugUtilsObjectNameEXT = NULL; + qvkSetDebugUtilsObjectTagEXT = NULL; + qvkCmdBeginDebugUtilsLabelEXT = NULL; + qvkCmdEndDebugUtilsLabelEXT = NULL; + qvkInsertDebugUtilsLabelEXT = NULL; + } + + if (vk_validation->value) + QVk_CreateValidationLayers(); + + if (!Vkimp_CreateSurface(vk_window)) + { + return false; + } + R_Printf(PRINT_ALL, "...created Vulkan surface\n"); + + // create Vulkan device - see if the user prefers any specific device if there's more than one GPU in the system + if (!QVk_CreateDevice((int)vk_device_idx->value)) + { + return false; + } + QVk_DebugSetObjectName((uintptr_t)vk_device.physical, VK_OBJECT_TYPE_PHYSICAL_DEVICE, va("Physical Device: %s", vk_config.vendor_name)); + + if (vk_validation->value) + vulkan_memory_types_show(); + + // setup swapchain + res = QVk_CreateSwapchain(); + if (res != VK_SUCCESS) + { + R_Printf(PRINT_ALL, "%s(): Could not create Vulkan swapchain: %s\n", __func__, QVk_GetError(res)); + return false; + } + R_Printf(PRINT_ALL, "...created Vulkan swapchain\n"); + + // set viewport and scissor + if (vid_fullscreen->value == 2) + { + // Center viewport in "keep resolution mode". + vk_viewport.x = max(0.f, (float)(vk_swapchain.extent.width - (uint32_t)(vid.width)) / 2.0f); + vk_viewport.y = max(0.f, (float)(vk_swapchain.extent.height - (uint32_t)(vid.height)) / 2.0f); + } + else + { + vk_viewport.x = 0.f; + vk_viewport.y = 0.f; + } + vk_viewport.minDepth = 0.f; + vk_viewport.maxDepth = 1.f; + vk_viewport.width = min((float)vid.width, (float)(vk_swapchain.extent.width) - vk_viewport.x); + vk_viewport.height = min((float)vid.height, (float)(vk_swapchain.extent.height) - vk_viewport.y); + vk_scissor.offset.x = 0; + vk_scissor.offset.y = 0; + vk_scissor.extent = vk_swapchain.extent; + + // setup fences and semaphores + VkFenceCreateInfo fCreateInfo = { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .pNext = NULL, + .flags = VK_FENCE_CREATE_SIGNALED_BIT + }; + VkSemaphoreCreateInfo sCreateInfo = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + .pNext = NULL, + .flags = 0 + }; + for (int i = 0; i < NUM_CMDBUFFERS; ++i) + { + VK_VERIFY(vkCreateFence(vk_device.logical, &fCreateInfo, NULL, &vk_fences[i])); + VK_VERIFY(vkCreateSemaphore(vk_device.logical, &sCreateInfo, NULL, &vk_imageAvailableSemaphores[i])); + VK_VERIFY(vkCreateSemaphore(vk_device.logical, &sCreateInfo, NULL, &vk_renderFinishedSemaphores[i])); + + QVk_DebugSetObjectName((uint64_t)vk_fences[i], + VK_OBJECT_TYPE_FENCE, va("Fence #%d", i)); + QVk_DebugSetObjectName((uint64_t)vk_imageAvailableSemaphores[i], + VK_OBJECT_TYPE_SEMAPHORE, va("Semaphore: image available #%d", i)); + QVk_DebugSetObjectName((uint64_t)vk_renderFinishedSemaphores[i], + VK_OBJECT_TYPE_SEMAPHORE, va("Semaphore: render finished #%d", i)); + } + R_Printf(PRINT_ALL, "...created synchronization objects\n"); + + // setup render passes + for (int i = 0; i < RP_COUNT; ++i) + { + vk_renderpasses[i].colorLoadOp = r_clear->value ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } + + VkSampleCountFlagBits msaaMode = GetSampleCount((int)vk_msaa->value, + vk_device.properties.limits.framebufferColorSampleCounts); + + // MSAA setting will be only relevant for the primary world render pass + vk_renderpasses[RP_WORLD].sampleCount = msaaMode; + + res = CreateRenderpasses(); + if (res != VK_SUCCESS) + { + R_Printf(PRINT_ALL, "%s(): Could not create Vulkan render passes: %s\n", __func__, QVk_GetError(res)); + return false; + } + R_Printf(PRINT_ALL, "...created %d Vulkan render passes\n", RP_COUNT); + + // setup command pools + for (int i = 0; i < NUM_CMDBUFFERS; i++) + { + res = QVk_CreateCommandPool(&vk_commandPool[i], vk_device.gfxFamilyIndex); + if (res != VK_SUCCESS) + { + R_Printf(PRINT_ALL, "%s(): Could not create Vulkan command pool #%d for graphics: %s\n", __func__, i, QVk_GetError(res)); + return false; + } + QVk_DebugSetObjectName((uint64_t)vk_commandPool[i], + VK_OBJECT_TYPE_COMMAND_POOL, va("Command Pool #%d: Graphics", i)); + } + + res = QVk_CreateCommandPool(&vk_transferCommandPool, vk_device.transferFamilyIndex); + if (res != VK_SUCCESS) + { + R_Printf(PRINT_ALL, "%s(): Could not create Vulkan command pool for transfer: %s\n", __func__, QVk_GetError(res)); + return false; + } + + QVk_DebugSetObjectName((uint64_t)vk_transferCommandPool, + VK_OBJECT_TYPE_COMMAND_POOL, "Command Pool: Transfer"); + R_Printf(PRINT_ALL, "...created Vulkan command pools\n"); + + // setup draw buffers + CreateDrawBuffers(); + + // setup image views + res = CreateImageViews(); + if (res != VK_SUCCESS) + { + R_Printf(PRINT_ALL, "%s(): Could not create Vulkan image views: %s\n", __func__, QVk_GetError(res)); + return false; + } + R_Printf(PRINT_ALL, "...created %d Vulkan image view(s)\n", vk_swapchain.imageCount); + + // setup framebuffers + res = CreateFramebuffers(); + if (res != VK_SUCCESS) + { + R_Printf(PRINT_ALL, "%s(): Could not create Vulkan framebuffers: %s\n", __func__, QVk_GetError(res)); + return false; + } + R_Printf(PRINT_ALL, "...created %d Vulkan framebuffers\n", vk_swapchain.imageCount); + + // setup command buffers (double buffering) + vk_commandbuffers = (VkCommandBuffer *)malloc(NUM_CMDBUFFERS * sizeof(VkCommandBuffer)); + + for (int i = 0; i < NUM_CMDBUFFERS; i++) + { + VkCommandBufferAllocateInfo cbInfo = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .pNext = NULL, + .commandPool = vk_commandPool[i], + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = 1 + }; + + res = vkAllocateCommandBuffers(vk_device.logical, &cbInfo, &vk_commandbuffers[i]); + if (res != VK_SUCCESS) + { + R_Printf(PRINT_ALL, "%s(): Could not create Vulkan commandbuffers: %s\n", __func__, QVk_GetError(res)); + free(vk_commandbuffers); + vk_commandbuffers = NULL; + return false; + } + } + R_Printf(PRINT_ALL, "...created %d Vulkan commandbuffers\n", NUM_CMDBUFFERS); + + // initialize tracker variables + vk_activeCmdbuffer = vk_commandbuffers[vk_activeBufferIdx]; + + CreateDescriptorSetLayouts(); + CreateDescriptorPool(); + // create static vertex/index buffers reused in the games + CreateStaticBuffers(); + // create vertex, index and uniform buffer pools + CreateDynamicBuffers(); + // create staging buffers + CreateStagingBuffers(); + // assign a dynamic index buffer for triangle fan emulation + RebuildTriangleIndexBuffer(); + CreatePipelines(); + CreateSamplers(); + + // main and world warp color buffers will be sampled for postprocessing effects, so they need descriptors and samplers + VkDescriptorSetAllocateInfo dsAllocInfo = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .pNext = NULL, + .descriptorPool = vk_descriptorPool, + .descriptorSetCount = 1, + .pSetLayouts = &vk_samplerDescSetLayout + }; + + VK_VERIFY(vkAllocateDescriptorSets(vk_device.logical, &dsAllocInfo, &vk_colorbuffer.descriptorSet)); + QVk_UpdateTextureSampler(&vk_colorbuffer, S_NEAREST_UNNORMALIZED, false); + VK_VERIFY(vkAllocateDescriptorSets(vk_device.logical, &dsAllocInfo, &vk_colorbufferWarp.descriptorSet)); + QVk_UpdateTextureSampler(&vk_colorbufferWarp, S_NEAREST_UNNORMALIZED, false); + + QVk_DebugSetObjectName((uint64_t)vk_colorbuffer.descriptorSet, + VK_OBJECT_TYPE_DESCRIPTOR_SET, "Descriptor Set: World Color Buffer"); + QVk_DebugSetObjectName((uint64_t)vk_colorbufferWarp.descriptorSet, + VK_OBJECT_TYPE_DESCRIPTOR_SET, "Descriptor Set: Warp Postprocess Color Buffer"); + + vk_frameStarted = false; + vk_initialized = true; + return true; +} + +VkResult QVk_BeginFrame(const VkViewport* viewport, const VkRect2D* scissor) +{ + // reset tracking variables + vk_state.current_pipeline = VK_NULL_HANDLE; + vk_state.current_renderpass = RP_COUNT; + vk_config.vertex_buffer_usage = 0; + // triangle fan index buffer data will not be cleared between frames unless the buffer itself is too small + vk_config.index_buffer_usage = vk_triangleFanIboUsage; + vk_config.uniform_buffer_usage = 0; + vk_config.triangle_index_usage = 0; + + ReleaseSwapBuffers(); + + static int restartcount; + VkResult result = vkAcquireNextImageKHR(vk_device.logical, vk_swapchain.sc, 500000000, vk_imageAvailableSemaphores[vk_activeBufferIdx], VK_NULL_HANDLE, &vk_imageIndex); + if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || result == VK_ERROR_SURFACE_LOST_KHR || result == VK_TIMEOUT) + { + if (restartcount > 2) + { + Sys_Error("%s(): tried to restart 3 times after vkAcquireNextImageKHR: %s", __func__, QVk_GetError(result)); + } + else + { + restartcount++; + } + + // for VK_OUT_OF_DATE_KHR and VK_SUBOPTIMAL_KHR it'd be fine to just rebuild the swapchain but let's take the easy way out and restart Vulkan. + R_Printf(PRINT_ALL, "%s(): received %s after vkAcquireNextImageKHR - restarting video!\n", __func__, QVk_GetError(result)); + return result; + } + else if (result != VK_SUCCESS) + { + Sys_Error("%s(): unexpected error after vkAcquireNextImageKHR: %s", __func__, QVk_GetError(result)); + } + + restartcount = 0; + vk_activeCmdbuffer = vk_commandbuffers[vk_activeBufferIdx]; + + // swap dynamic buffers + vk_activeDynBufferIdx = (vk_activeDynBufferIdx + 1) % NUM_DYNBUFFERS; + vk_dynUniformBuffers[vk_activeDynBufferIdx].currentOffset = 0; + vk_dynVertexBuffers[vk_activeDynBufferIdx].currentOffset = 0; + // triangle fan index data is placed in the beginning of the buffer + vk_dynIndexBuffers[vk_activeDynBufferIdx].currentOffset = vk_triangleFanIboUsage; + VK_VERIFY(buffer_invalidate(&vk_dynUniformBuffers[vk_activeDynBufferIdx].resource)); + VK_VERIFY(buffer_invalidate(&vk_dynVertexBuffers[vk_activeDynBufferIdx].resource)); + VK_VERIFY(buffer_invalidate(&vk_dynIndexBuffers[vk_activeDynBufferIdx].resource)); + + VK_VERIFY(vkWaitForFences(vk_device.logical, 1, &vk_fences[vk_activeBufferIdx], VK_TRUE, UINT32_MAX)); + VK_VERIFY(vkResetFences(vk_device.logical, 1, &vk_fences[vk_activeBufferIdx])); + + // setup command buffers and render pass for drawing + VkCommandBufferBeginInfo beginInfo = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .pNext = NULL, + .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, + .pInheritanceInfo = NULL + }; + + // Command buffers are implicitly reset by vkBeginCommandBuffer if VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT is set - this is expensive. + // It's more efficient to reset entire pool instead and it also fixes the VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT performance warning. + // see also: https://github.com/KhronosGroup/Vulkan-Samples/blob/master/samples/performance/command_buffer_usage/command_buffer_usage_tutorial.md + vkResetCommandPool(vk_device.logical, vk_commandPool[vk_activeBufferIdx], 0); + VK_VERIFY(vkBeginCommandBuffer(vk_commandbuffers[vk_activeBufferIdx], &beginInfo)); + + vkCmdSetViewport(vk_commandbuffers[vk_activeBufferIdx], 0, 1, viewport); + vkCmdSetScissor(vk_commandbuffers[vk_activeBufferIdx], 0, 1, scissor); + + vk_frameStarted = true; + return VK_SUCCESS; +} + +VkResult QVk_EndFrame(qboolean force) +{ + // continue only if QVk_BeginFrame() had been previously issued + if (!vk_frameStarted) + return VK_SUCCESS; + + // this may happen if Sys_Error is issued mid-frame, so we need to properly advance the draw pipeline + if (force) + { + if(!RE_EndWorldRenderpass()) + // buffers is not initialized + return VK_NOT_READY; + } + + // submit + QVk_SubmitStagingBuffers(); + VK_VERIFY(buffer_flush(&vk_dynUniformBuffers[vk_activeDynBufferIdx].resource)); + VK_VERIFY(buffer_flush(&vk_dynVertexBuffers[vk_activeDynBufferIdx].resource)); + VK_VERIFY(buffer_flush(&vk_dynIndexBuffers[vk_activeDynBufferIdx].resource)); + + vkCmdEndRenderPass(vk_commandbuffers[vk_activeBufferIdx]); + QVk_DebugLabelEnd(&vk_commandbuffers[vk_activeBufferIdx]); + VK_VERIFY(vkEndCommandBuffer(vk_commandbuffers[vk_activeBufferIdx])); + + VkPipelineStageFlags waitStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkSubmitInfo submitInfo = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .waitSemaphoreCount = 1, + .pWaitSemaphores = &vk_imageAvailableSemaphores[vk_activeBufferIdx], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &vk_renderFinishedSemaphores[vk_activeBufferIdx], + .pWaitDstStageMask = &waitStages, + .commandBufferCount = 1, + .pCommandBuffers = &vk_commandbuffers[vk_activeBufferIdx] + }; + + VK_VERIFY(vkQueueSubmit(vk_device.gfxQueue, 1, &submitInfo, vk_fences[vk_activeBufferIdx])); + + // present + VkPresentInfoKHR presentInfo = { + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + .waitSemaphoreCount = 1, + .pWaitSemaphores = &vk_renderFinishedSemaphores[vk_activeBufferIdx], + .swapchainCount = 1, + .pSwapchains = &vk_swapchain.sc, + .pImageIndices = &vk_imageIndex, + .pResults = NULL + }; + + VkResult renderResult = vkQueuePresentKHR(vk_device.presentQueue, &presentInfo); + + // for VK_OUT_OF_DATE_KHR and VK_SUBOPTIMAL_KHR it'd be fine to just rebuild the swapchain but let's take the easy way out and restart video system + if (renderResult == VK_ERROR_OUT_OF_DATE_KHR || renderResult == VK_SUBOPTIMAL_KHR || renderResult == VK_ERROR_SURFACE_LOST_KHR) + { + R_Printf(PRINT_ALL, "%s(): received %s after vkQueuePresentKHR - will restart video!\n", __func__, QVk_GetError(renderResult)); + vk_restartNeeded = true; + } + else if (renderResult != VK_SUCCESS) + { + Sys_Error("%s(): unexpected error after vkQueuePresentKHR: %s", __func__, QVk_GetError(renderResult)); + } + + vk_activeBufferIdx = (vk_activeBufferIdx + 1) % NUM_CMDBUFFERS; + + vk_frameStarted = false; + return renderResult; +} + +void QVk_BeginRenderpass(qvkrenderpasstype_t rpType) +{ + const VkClearValue clearColors[3] = { + {.color = {.float32 = { 1.f, .0f, .5f, 1.f } } }, + {.depthStencil = { 1.f, 0 } }, + {.color = {.float32 = { 1.f, .0f, .5f, 1.f } } }, + }; + + const VkClearValue warpClearColors[2] = { + clearColors[0], + {.color = {.float32 = { 0.f, .0f, .0f, 1.f } } }, + }; + + const VkClearValue uiClearColors[3] = { + clearColors[0], + clearColors[1], + {.color = {.float32 = { 0.f, .0f, .0f, 1.f } } }, + }; + + VkRenderPassBeginInfo renderBeginInfo[] = { + // RP_WORLD + { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .renderPass = vk_renderpasses[RP_WORLD].rp, + .framebuffer = vk_framebuffers[RP_WORLD][vk_imageIndex], + .renderArea.offset = { 0, 0 }, + .renderArea.extent = vk_swapchain.extent, + .clearValueCount = vk_renderpasses[RP_WORLD].sampleCount != VK_SAMPLE_COUNT_1_BIT ? 3 : 2, + .pClearValues = clearColors + }, + // RP_UI + { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .renderPass = vk_renderpasses[RP_UI].rp, + .framebuffer = vk_framebuffers[RP_UI][vk_imageIndex], + .renderArea.offset = { 0, 0 }, + .renderArea.extent = vk_swapchain.extent, + .clearValueCount = 3, + .pClearValues = uiClearColors + }, + // RP_WORLD_WARP + { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .renderPass = vk_renderpasses[RP_WORLD_WARP].rp, + .framebuffer = vk_framebuffers[RP_WORLD_WARP][vk_imageIndex], + .renderArea.offset = { 0, 0 }, + .renderArea.extent = vk_swapchain.extent, + .clearValueCount = 2, + .pClearValues = warpClearColors + } + }; + + if (rpType == RP_WORLD) { + QVk_DebugLabelBegin(&vk_commandbuffers[vk_activeBufferIdx], "Draw World", 0.f, 1.f, 0.f); + } + if (rpType == RP_UI) { + QVk_DebugLabelEnd(&vk_commandbuffers[vk_activeBufferIdx]); + QVk_DebugLabelBegin(&vk_commandbuffers[vk_activeBufferIdx], "Draw UI", 1.f, 1.f, 0.f); + } + if (rpType == RP_WORLD_WARP) { + QVk_DebugLabelEnd(&vk_commandbuffers[vk_activeBufferIdx]); + QVk_DebugLabelBegin(&vk_commandbuffers[vk_activeBufferIdx], "Draw View Warp", 1.f, 0.f, .5f); + } + + vkCmdBeginRenderPass(vk_commandbuffers[vk_activeBufferIdx], &renderBeginInfo[rpType], VK_SUBPASS_CONTENTS_INLINE); + vk_state.current_renderpass = rpType; +} + +#if 0 +void QVk_RecreateSwapchain() +{ + vkDeviceWaitIdle( vk_device.logical ); + DestroyFramebuffers(); + DestroyImageViews(); + VK_VERIFY(QVk_CreateSwapchain()); + vk_viewport.width = (float)vid.width; + vk_viewport.height = (float)vid.height; + vk_scissor.extent = vk_swapchain.extent; + DestroyDrawBuffers(); + CreateDrawBuffers(); + VK_VERIFY(CreateImageViews()); + VK_VERIFY(CreateFramebuffers()); +} +#endif + +uint8_t *QVk_GetVertexBuffer(VkDeviceSize size, VkBuffer *dstBuffer, VkDeviceSize *dstOffset) +{ + if (vk_dynVertexBuffers[vk_activeDynBufferIdx].currentOffset + size > vk_config.vertex_buffer_size) + { + vk_config.vertex_buffer_size = max(vk_config.vertex_buffer_size * BUFFER_RESIZE_FACTOR, NextPow2(size)); + + R_Printf(PRINT_ALL, "Resizing dynamic vertex buffer to %ukB\n", vk_config.vertex_buffer_size / 1024); + int swapBufferOffset = vk_swapBuffersCnt[vk_activeSwapBufferIdx]; + vk_swapBuffersCnt[vk_activeSwapBufferIdx] += NUM_DYNBUFFERS; + + if (vk_swapBuffers[vk_activeSwapBufferIdx] == NULL) + vk_swapBuffers[vk_activeSwapBufferIdx] = malloc(sizeof(qvkbuffer_t) * vk_swapBuffersCnt[vk_activeSwapBufferIdx]); + else + vk_swapBuffers[vk_activeSwapBufferIdx] = realloc(vk_swapBuffers[vk_activeSwapBufferIdx], sizeof(qvkbuffer_t) * vk_swapBuffersCnt[vk_activeSwapBufferIdx]); + + for (int i = 0; i < NUM_DYNBUFFERS; ++i) + { + // need unmap before copy to swapBuffers + buffer_unmap(&vk_dynVertexBuffers[i].resource); + vk_swapBuffers[vk_activeSwapBufferIdx][swapBufferOffset + i] = vk_dynVertexBuffers[i]; + + QVk_CreateVertexBuffer(NULL, vk_config.vertex_buffer_size, + &vk_dynVertexBuffers[i], VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_MEMORY_PROPERTY_HOST_CACHED_BIT); + vk_dynVertexBuffers[i].pMappedData = buffer_map(&vk_dynVertexBuffers[i].resource); + + QVk_DebugSetObjectName((uint64_t)vk_dynVertexBuffers[i].resource.buffer, + VK_OBJECT_TYPE_BUFFER, va("Dynamic Vertex Buffer #%d", i)); + QVk_DebugSetObjectName((uint64_t)vk_dynVertexBuffers[i].resource.memory, + VK_OBJECT_TYPE_DEVICE_MEMORY, va("Memory: Dynamic Vertex Buffer #%d", i)); + } + } + + *dstOffset = vk_dynVertexBuffers[vk_activeDynBufferIdx].currentOffset; + *dstBuffer = vk_dynVertexBuffers[vk_activeDynBufferIdx].resource.buffer; + vk_dynVertexBuffers[vk_activeDynBufferIdx].currentOffset += size; + + vk_config.vertex_buffer_usage = vk_dynVertexBuffers[vk_activeDynBufferIdx].currentOffset; + if (vk_config.vertex_buffer_max_usage < vk_config.vertex_buffer_usage) + vk_config.vertex_buffer_max_usage = vk_config.vertex_buffer_usage; + + return (uint8_t *)vk_dynVertexBuffers[vk_activeDynBufferIdx].pMappedData + (*dstOffset); +} + +static uint8_t *QVk_GetIndexBuffer(VkDeviceSize size, VkDeviceSize *dstOffset, int currentBufferIdx) +{ + // align to 4 bytes, so that we can reuse the buffer for both VK_INDEX_TYPE_UINT16 and VK_INDEX_TYPE_UINT32 + const uint32_t aligned_size = ROUNDUP(size, 4); + + if (vk_dynIndexBuffers[currentBufferIdx].currentOffset + aligned_size > vk_config.index_buffer_size) + { + vk_config.index_buffer_size = max(vk_config.index_buffer_size * BUFFER_RESIZE_FACTOR, NextPow2(size)); + + R_Printf(PRINT_ALL, "Resizing dynamic index buffer to %ukB\n", vk_config.index_buffer_size / 1024); + int swapBufferOffset = vk_swapBuffersCnt[vk_activeSwapBufferIdx]; + vk_swapBuffersCnt[vk_activeSwapBufferIdx] += NUM_DYNBUFFERS; + + if (vk_swapBuffers[vk_activeSwapBufferIdx] == NULL) + vk_swapBuffers[vk_activeSwapBufferIdx] = malloc(sizeof(qvkbuffer_t) * vk_swapBuffersCnt[vk_activeSwapBufferIdx]); + else + vk_swapBuffers[vk_activeSwapBufferIdx] = realloc(vk_swapBuffers[vk_activeSwapBufferIdx], sizeof(qvkbuffer_t) * vk_swapBuffersCnt[vk_activeSwapBufferIdx]); + + for (int i = 0; i < NUM_DYNBUFFERS; ++i) + { + // need unmap before copy to swapBuffers + buffer_unmap(&vk_dynIndexBuffers[i].resource); + vk_swapBuffers[vk_activeSwapBufferIdx][swapBufferOffset + i] = vk_dynIndexBuffers[i]; + + QVk_CreateIndexBuffer(NULL, vk_config.index_buffer_size, + &vk_dynIndexBuffers[i], VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_MEMORY_PROPERTY_HOST_CACHED_BIT); + vk_dynIndexBuffers[i].pMappedData = buffer_map(&vk_dynIndexBuffers[i].resource); + + QVk_DebugSetObjectName((uint64_t)vk_dynIndexBuffers[i].resource.buffer, + VK_OBJECT_TYPE_BUFFER, va("Dynamic Index Buffer #%d", i)); + QVk_DebugSetObjectName((uint64_t)vk_dynIndexBuffers[i].resource.memory, + VK_OBJECT_TYPE_DEVICE_MEMORY, va("Memory: Dynamic Index Buffer #%d", i)); + } + } + + *dstOffset = vk_dynIndexBuffers[currentBufferIdx].currentOffset; + vk_dynIndexBuffers[currentBufferIdx].currentOffset += aligned_size; + + vk_config.index_buffer_usage = vk_dynIndexBuffers[currentBufferIdx].currentOffset; + if (vk_config.index_buffer_max_usage < vk_config.index_buffer_usage) + vk_config.index_buffer_max_usage = vk_config.index_buffer_usage; + + return (uint8_t *)vk_dynIndexBuffers[currentBufferIdx].pMappedData + (*dstOffset); +} + +uint8_t *QVk_GetUniformBuffer(VkDeviceSize size, uint32_t *dstOffset, VkDescriptorSet *dstUboDescriptorSet) +{ + // 0x100 alignment is required by Vulkan spec + const uint32_t aligned_size = ROUNDUP(size, 0x100); + + if (vk_dynUniformBuffers[vk_activeDynBufferIdx].currentOffset + UNIFORM_ALLOC_SIZE > vk_config.uniform_buffer_size) + { + vk_config.uniform_buffer_size = max(vk_config.uniform_buffer_size * BUFFER_RESIZE_FACTOR, NextPow2(size)); + + R_Printf(PRINT_ALL, "Resizing dynamic uniform buffer to %ukB\n", vk_config.uniform_buffer_size / 1024); + int swapBufferOffset = vk_swapBuffersCnt[vk_activeSwapBufferIdx]; + int swapDescSetsOffset = vk_swapDescSetsCnt[vk_activeSwapBufferIdx]; + vk_swapBuffersCnt[vk_activeSwapBufferIdx] += NUM_DYNBUFFERS; + vk_swapDescSetsCnt[vk_activeSwapBufferIdx] += NUM_DYNBUFFERS; + + if (vk_swapBuffers[vk_activeSwapBufferIdx] == NULL) + vk_swapBuffers[vk_activeSwapBufferIdx] = malloc(sizeof(qvkbuffer_t) * vk_swapBuffersCnt[vk_activeSwapBufferIdx]); + else + vk_swapBuffers[vk_activeSwapBufferIdx] = realloc(vk_swapBuffers[vk_activeSwapBufferIdx], sizeof(qvkbuffer_t) * vk_swapBuffersCnt[vk_activeSwapBufferIdx]); + + if (vk_swapDescriptorSets[vk_activeSwapBufferIdx] == NULL) + vk_swapDescriptorSets[vk_activeSwapBufferIdx] = malloc(sizeof(VkDescriptorSet) * vk_swapDescSetsCnt[vk_activeSwapBufferIdx]); + else + vk_swapDescriptorSets[vk_activeSwapBufferIdx] = realloc(vk_swapDescriptorSets[vk_activeSwapBufferIdx], sizeof(VkDescriptorSet) * vk_swapDescSetsCnt[vk_activeSwapBufferIdx]); + + for (int i = 0; i < NUM_DYNBUFFERS; ++i) + { + // need unmap before copy to swapBuffers + buffer_unmap(&vk_dynUniformBuffers[i].resource); + vk_swapBuffers[vk_activeSwapBufferIdx][swapBufferOffset + i] = vk_dynUniformBuffers[i]; + vk_swapDescriptorSets[vk_activeSwapBufferIdx][swapDescSetsOffset + i] = vk_uboDescriptorSets[i]; + + VK_VERIFY(QVk_CreateUniformBuffer(vk_config.uniform_buffer_size, + &vk_dynUniformBuffers[i], VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_MEMORY_PROPERTY_HOST_CACHED_BIT)); + vk_dynUniformBuffers[i].pMappedData = buffer_map(&vk_dynUniformBuffers[i].resource); + CreateUboDescriptorSet(&vk_uboDescriptorSets[i], + vk_dynUniformBuffers[i].resource.buffer); + + QVk_DebugSetObjectName((uint64_t)vk_uboDescriptorSets[i], + VK_OBJECT_TYPE_DESCRIPTOR_SET, va("Dynamic UBO Descriptor Set #%d", i)); + QVk_DebugSetObjectName((uint64_t)vk_dynUniformBuffers[i].resource.buffer, + VK_OBJECT_TYPE_BUFFER, va("Dynamic Uniform Buffer #%d", i)); + QVk_DebugSetObjectName((uint64_t)vk_dynUniformBuffers[i].resource.memory, + VK_OBJECT_TYPE_DEVICE_MEMORY, va("Memory: Dynamic Uniform Buffer #%d", i)); + } + } + + *dstOffset = vk_dynUniformBuffers[vk_activeDynBufferIdx].currentOffset; + *dstUboDescriptorSet = vk_uboDescriptorSets[vk_activeDynBufferIdx]; + vk_dynUniformBuffers[vk_activeDynBufferIdx].currentOffset += aligned_size; + + vk_config.uniform_buffer_usage = vk_dynUniformBuffers[vk_activeDynBufferIdx].currentOffset; + if (vk_config.uniform_buffer_max_usage < vk_config.uniform_buffer_usage) + vk_config.uniform_buffer_max_usage = vk_config.uniform_buffer_usage; + + return (uint8_t *)vk_dynUniformBuffers[vk_activeDynBufferIdx].pMappedData + (*dstOffset); +} + +uint8_t *QVk_GetStagingBuffer(VkDeviceSize size, int alignment, VkCommandBuffer *cmdBuffer, VkBuffer *buffer, uint32_t *dstOffset) +{ + qvkstagingbuffer_t * stagingBuffer = &vk_stagingBuffers[vk_activeStagingBuffer]; + stagingBuffer->currentOffset = ROUNDUP(stagingBuffer->currentOffset, alignment); + + if (((stagingBuffer->currentOffset + size) >= stagingBuffer->resource.size) && !stagingBuffer->submitted) + SubmitStagingBuffer(vk_activeStagingBuffer); + + stagingBuffer = &vk_stagingBuffers[vk_activeStagingBuffer]; + if (size > stagingBuffer->resource.size) + { + R_Printf(PRINT_ALL, "%s: %d: Resize stanging buffer" YQ2_COM_PRId64 "->" YQ2_COM_PRId64 "\n", + __func__, vk_activeStagingBuffer, stagingBuffer->resource.size, size); + + DestroyStagingBuffer(stagingBuffer); + CreateStagingBuffer(size, stagingBuffer, vk_activeStagingBuffer); + } + else + { + if (stagingBuffer->submitted) + { + VK_VERIFY(vkWaitForFences(vk_device.logical, 1, &stagingBuffer->fence, VK_TRUE, UINT64_MAX)); + VK_VERIFY(vkResetFences(vk_device.logical, 1, &stagingBuffer->fence)); + + stagingBuffer->currentOffset = 0; + stagingBuffer->submitted = false; + + VkCommandBufferBeginInfo beginInfo = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .pNext = NULL, + .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, + .pInheritanceInfo = NULL + }; + + // Command buffers are implicitly reset by vkBeginCommandBuffer if VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT is set - this is expensive. + // It's more efficient to reset entire pool instead and it also fixes the VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT performance warning. + // see also: https://github.com/KhronosGroup/Vulkan-Samples/blob/master/samples/performance/command_buffer_usage/command_buffer_usage_tutorial.md + vkResetCommandPool(vk_device.logical, vk_stagingCommandPool[vk_activeStagingBuffer], 0); + VK_VERIFY(vkBeginCommandBuffer(stagingBuffer->cmdBuffer, &beginInfo)); + } + } + + if (cmdBuffer) + *cmdBuffer = stagingBuffer->cmdBuffer; + if (buffer) + *buffer = stagingBuffer->resource.buffer; + if (dstOffset) + *dstOffset = stagingBuffer->currentOffset; + + unsigned char *data = (uint8_t *)stagingBuffer->pMappedData + stagingBuffer->currentOffset; + stagingBuffer->currentOffset += size; + + return data; +} + +static void +QVk_CheckTriangleIbo(VkDeviceSize indexCount) +{ + if (indexCount > vk_config.triangle_index_usage) + vk_config.triangle_index_usage = indexCount; + + if (vk_config.triangle_index_usage > vk_config.triangle_index_max_usage) + vk_config.triangle_index_max_usage = vk_config.triangle_index_usage; + + if (indexCount > vk_config.triangle_index_count) + { + vk_config.triangle_index_count *= BUFFER_RESIZE_FACTOR; + R_Printf(PRINT_ALL, "Resizing triangle index buffer to %u indices.\n", vk_config.triangle_index_count); + RebuildTriangleIndexBuffer(); + } +} + +VkBuffer QVk_GetTriangleFanIbo(VkDeviceSize indexCount) +{ + QVk_CheckTriangleIbo(indexCount); + + return *vk_triangleFanIbo; +} + +VkBuffer QVk_GetTriangleStripIbo(VkDeviceSize indexCount) +{ + QVk_CheckTriangleIbo(indexCount); + + return *vk_triangleStripIbo; +} + +void QVk_SubmitStagingBuffers() +{ + for (int i = 0; i < NUM_DYNBUFFERS; ++i) + { + if (!vk_stagingBuffers[i].submitted && vk_stagingBuffers[i].currentOffset > 0) + SubmitStagingBuffer(i); + } +} + +VkSampler QVk_UpdateTextureSampler(qvktexture_t *texture, qvksampler_t samplerType, qboolean clampToEdge) +{ + const int samplerIndex = samplerType + (clampToEdge ? S_SAMPLER_CNT : 0); + + assert((vk_samplers[samplerIndex] != VK_NULL_HANDLE) && "Sampler is VK_NULL_HANDLE!"); + + texture->clampToEdge = clampToEdge; + + VkDescriptorImageInfo dImgInfo = { + .sampler = vk_samplers[samplerIndex], + .imageView = texture->imageView, + .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + }; + + VkWriteDescriptorSet writeSet = { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = NULL, + .dstSet = texture->descriptorSet, + .dstBinding = 0, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .pImageInfo = &dImgInfo, + .pBufferInfo = NULL, + .pTexelBufferView = NULL + }; + + vkUpdateDescriptorSets(vk_device.logical, 1, &writeSet, 0, NULL); + + return vk_samplers[samplerIndex]; +} + +void QVk_DrawColorRect(float *ubo, VkDeviceSize uboSize, qvkrenderpasstype_t rpType) +{ + uint32_t uboOffset; + VkDescriptorSet uboDescriptorSet; + uint8_t *vertData = QVk_GetUniformBuffer(uboSize, + &uboOffset, &uboDescriptorSet); + memcpy(vertData, ubo, uboSize); + + QVk_BindPipeline(&vk_drawColorQuadPipeline[rpType]); + VkDeviceSize offsets = 0; + vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + vk_drawColorQuadPipeline[rpType].layout, 0, 1, &uboDescriptorSet, 1, &uboOffset); + vkCmdBindVertexBuffers(vk_activeCmdbuffer, 0, 1, + &vk_colorRectVbo.resource.buffer, &offsets); + vkCmdBindIndexBuffer(vk_activeCmdbuffer, vk_rectIbo.resource.buffer, + 0, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(vk_activeCmdbuffer, 6, 1, 0, 0, 0); +} + +void QVk_DrawTexRect(const float *ubo, VkDeviceSize uboSize, qvktexture_t *texture) +{ + uint32_t uboOffset; + VkDescriptorSet uboDescriptorSet; + uint8_t *uboData = QVk_GetUniformBuffer(uboSize, &uboOffset, &uboDescriptorSet); + memcpy(uboData, ubo, uboSize); + + QVk_BindPipeline(&vk_drawTexQuadPipeline[vk_state.current_renderpass]); + VkDeviceSize offsets = 0; + VkDescriptorSet descriptorSets[] = { texture->descriptorSet, uboDescriptorSet }; + + float gamma = 2.1F - vid_gamma->value; + + vkCmdPushConstants(vk_activeCmdbuffer, vk_drawTexQuadPipeline[vk_state.current_renderpass].layout, + VK_SHADER_STAGE_FRAGMENT_BIT, 17 * sizeof(float), sizeof(gamma), &gamma); + + vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vk_drawTexQuadPipeline[vk_state.current_renderpass].layout, 0, 2, descriptorSets, 1, &uboOffset); + vkCmdBindVertexBuffers(vk_activeCmdbuffer, 0, 1, + &vk_texRectVbo.resource.buffer, &offsets); + vkCmdBindIndexBuffer(vk_activeCmdbuffer, + vk_rectIbo.resource.buffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(vk_activeCmdbuffer, 6, 1, 0, 0, 0); +} + +void QVk_BindPipeline(qvkpipeline_t *pipeline) +{ + if (vk_state.current_pipeline != pipeline->pl) + { + vkCmdBindPipeline(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pl); + vk_state.current_pipeline = pipeline->pl; + } +} + +const char *QVk_GetError(VkResult errorCode) +{ +#define ERRSTR(r) case VK_ ##r: return "VK_"#r + switch (errorCode) + { + ERRSTR(SUCCESS); + ERRSTR(NOT_READY); + ERRSTR(TIMEOUT); + ERRSTR(EVENT_SET); + ERRSTR(EVENT_RESET); + ERRSTR(INCOMPLETE); + ERRSTR(ERROR_OUT_OF_HOST_MEMORY); + ERRSTR(ERROR_OUT_OF_DEVICE_MEMORY); + ERRSTR(ERROR_INITIALIZATION_FAILED); + ERRSTR(ERROR_DEVICE_LOST); + ERRSTR(ERROR_MEMORY_MAP_FAILED); + ERRSTR(ERROR_LAYER_NOT_PRESENT); + ERRSTR(ERROR_EXTENSION_NOT_PRESENT); + ERRSTR(ERROR_FEATURE_NOT_PRESENT); + ERRSTR(ERROR_INCOMPATIBLE_DRIVER); + ERRSTR(ERROR_TOO_MANY_OBJECTS); + ERRSTR(ERROR_FORMAT_NOT_SUPPORTED); + ERRSTR(ERROR_SURFACE_LOST_KHR); + ERRSTR(ERROR_NATIVE_WINDOW_IN_USE_KHR); + ERRSTR(SUBOPTIMAL_KHR); + ERRSTR(ERROR_OUT_OF_DATE_KHR); + ERRSTR(ERROR_INCOMPATIBLE_DISPLAY_KHR); + ERRSTR(ERROR_VALIDATION_FAILED_EXT); + ERRSTR(ERROR_INVALID_SHADER_NV); + default: return ""; + } +#undef ERRSTR + return "UNKNOWN ERROR"; +} diff --git a/src/vk/vk_device.c b/src/vk/vk_device.c new file mode 100644 index 0000000..cbd75a1 --- /dev/null +++ b/src/vk/vk_device.c @@ -0,0 +1,365 @@ +/* +Copyright (C) 2018-2019 Krzysztof Kondrak + +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. +*/ + +#include "header/local.h" + +// internal helper +static qboolean deviceExtensionsSupported(const VkPhysicalDevice *physicalDevice, const char* extensionName) +{ + uint32_t availableExtCount = 0; + qboolean vk_extension_available = false; + VK_VERIFY(vkEnumerateDeviceExtensionProperties(*physicalDevice, NULL, &availableExtCount, NULL)); + + if (availableExtCount > 0) + { + VkExtensionProperties *extensions = (VkExtensionProperties *)malloc(availableExtCount * sizeof(VkExtensionProperties)); + VK_VERIFY(vkEnumerateDeviceExtensionProperties(*physicalDevice, NULL, &availableExtCount, extensions)); + + for (uint32_t i = 0; i < availableExtCount; ++i) + { + vk_extension_available |= strcmp(extensions[i].extensionName, extensionName) == 0; + } + + free(extensions); + } + + // lack of extension disqualifies the device + return vk_extension_available; +} + +// internal helper +static void getBestPhysicalDevice(const VkPhysicalDevice *devices, int preferredIdx, int count) +{ + VkPhysicalDeviceProperties deviceProperties; + VkPhysicalDeviceFeatures deviceFeatures; + uint32_t queueFamilyCount = 0; + + for (int i = 0; i < count; ++i) + { + vkGetPhysicalDeviceProperties(devices[i], &deviceProperties); + vkGetPhysicalDeviceFeatures(devices[i], &deviceFeatures); + vkGetPhysicalDeviceQueueFamilyProperties(devices[i], &queueFamilyCount, NULL); + + if (queueFamilyCount == 0) + continue; + + // prefer discrete GPU but if it's the only one available then don't be picky + // also - if the user specifies a preferred device, select it + qboolean bestProperties = deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU; + if (preferredIdx == i || (bestProperties && preferredIdx < 0) || count == 1) + { + uint32_t formatCount = 0; + uint32_t presentModesCount = 0; + + // check if requested device extensions are present + qboolean extSupported = deviceExtensionsSupported(&devices[i], VK_KHR_SWAPCHAIN_EXTENSION_NAME); + + // no required extensions? try next device + if (!extSupported) + continue; + + // if extensions are fine, query surface formats and present modes to see if the device can be used + VK_VERIFY(vkGetPhysicalDeviceSurfaceFormatsKHR(devices[i], vk_surface, &formatCount, NULL)); + VK_VERIFY(vkGetPhysicalDeviceSurfacePresentModesKHR(devices[i], vk_surface, &presentModesCount, NULL)); + + if (formatCount == 0 || presentModesCount == 0) + continue; + + VkQueueFamilyProperties *queueFamilies = (VkQueueFamilyProperties *)malloc(queueFamilyCount * sizeof(VkQueueFamilyProperties)); + vkGetPhysicalDeviceQueueFamilyProperties(devices[i], &queueFamilyCount, queueFamilies); + + // secondary check - device is OK if there's at least on queue with VK_QUEUE_GRAPHICS_BIT set + for (uint32_t j = 0; j < queueFamilyCount; ++j) + { + // check if this queue family has support for presentation + VkBool32 presentSupported; + VK_VERIFY(vkGetPhysicalDeviceSurfaceSupportKHR(devices[i], j, vk_surface, &presentSupported)); + + // good optimization would be to find a queue where presentIdx == gfxQueueIdx for less overhead + if (vk_device.presentFamilyIndex < 0 && queueFamilies[j].queueCount > 0 && presentSupported) + { + vk_device.presentFamilyIndex = j; + } + + if (vk_device.gfxFamilyIndex < 0 && queueFamilies[j].queueCount > 0 && (queueFamilies[j].queueFlags & VK_QUEUE_GRAPHICS_BIT)) + { + vk_device.gfxFamilyIndex = j; + } + + if (vk_device.transferFamilyIndex < 0 && queueFamilies[j].queueCount > 0 && !(queueFamilies[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) && (queueFamilies[j].queueFlags & VK_QUEUE_TRANSFER_BIT)) + { + vk_device.transferFamilyIndex = j; + } + } + + free(queueFamilies); + + // accept only device that has support for presentation and drawing + if (vk_device.presentFamilyIndex >= 0 && vk_device.gfxFamilyIndex >= 0) + { + if (vk_device.transferFamilyIndex < 0) + { + vk_device.transferFamilyIndex = vk_device.gfxFamilyIndex; + } + + vk_device.physical = devices[i]; + vk_device.properties = deviceProperties; + vk_device.features = deviceFeatures; + return; + } + } + } +} + +// internal helper +static qboolean selectPhysicalDevice(int preferredDeviceIdx) +{ + uint32_t physicalDeviceCount = 0; + VK_VERIFY(vkEnumeratePhysicalDevices(vk_instance, &physicalDeviceCount, NULL)); + + if (physicalDeviceCount == 0) + { + R_Printf(PRINT_ALL, "No Vulkan-capable devices found!\n"); + return false; + } + + R_Printf(PRINT_ALL, "...found %d Vulkan-capable device(s)\n", physicalDeviceCount); + + VkPhysicalDevice *physicalDevices = (VkPhysicalDevice *)malloc(physicalDeviceCount * sizeof(VkPhysicalDevice)); + VK_VERIFY(vkEnumeratePhysicalDevices(vk_instance, &physicalDeviceCount, physicalDevices)); + + getBestPhysicalDevice(physicalDevices, preferredDeviceIdx < physicalDeviceCount ? preferredDeviceIdx : -1, physicalDeviceCount); + free(physicalDevices); + + if (vk_device.physical == VK_NULL_HANDLE) + { + R_Printf(PRINT_ALL, "Could not find a suitable physical device!\n"); + return false; + } + + if (!vk_device.features.samplerAnisotropy) + { + R_Printf(PRINT_ALL, "...anisotropy filtering is unsupported.\n"); + } + + return true; +} + +// internal helper +static VkResult createLogicalDevice() +{ + // at least one queue (graphics and present combined) has to be present + uint32_t numQueues = 1; + float queuePriority = 1.f; + VkDeviceQueueCreateInfo queueCreateInfo[3]; + queueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo[0].pNext = NULL; + queueCreateInfo[0].flags = 0; + queueCreateInfo[0].queueFamilyIndex = vk_device.gfxFamilyIndex; + queueCreateInfo[0].queueCount = 1; + queueCreateInfo[0].pQueuePriorities = &queuePriority; + queueCreateInfo[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo[1].pNext = NULL; + queueCreateInfo[1].flags = 0; + queueCreateInfo[1].queueFamilyIndex = 0; + queueCreateInfo[1].queueCount = 1; + queueCreateInfo[1].pQueuePriorities = &queuePriority; + queueCreateInfo[2].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo[2].pNext = NULL; + queueCreateInfo[2].flags = 0; + queueCreateInfo[2].queueFamilyIndex = 0; + queueCreateInfo[2].queueCount = 1; + queueCreateInfo[2].pQueuePriorities = &queuePriority; + + VkPhysicalDeviceFeatures wantedDeviceFeatures = { + .samplerAnisotropy = vk_device.features.samplerAnisotropy, + .fillModeNonSolid = vk_device.features.fillModeNonSolid, // for wireframe rendering + .sampleRateShading = vk_device.features.sampleRateShading, // for sample shading + }; + + // a graphics and present queue are different - two queues have to be created + if (vk_device.gfxFamilyIndex != vk_device.presentFamilyIndex) + { + queueCreateInfo[numQueues++].queueFamilyIndex = vk_device.presentFamilyIndex; + } + + // a separate transfer queue exists that's different from present and graphics queue? + if (vk_device.transferFamilyIndex != vk_device.gfxFamilyIndex && vk_device.transferFamilyIndex != vk_device.presentFamilyIndex) + { + queueCreateInfo[numQueues++].queueFamilyIndex = vk_device.transferFamilyIndex; + } + + const char *deviceExtensions[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; + + VkDeviceCreateInfo deviceCreateInfo = { + .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .pEnabledFeatures = &wantedDeviceFeatures, + .ppEnabledExtensionNames = deviceExtensions, + .enabledExtensionCount = 1, + .enabledLayerCount = 0, + .ppEnabledLayerNames = NULL, + .queueCreateInfoCount = numQueues, + .pQueueCreateInfos = queueCreateInfo + }; + +#if VK_HEADER_VERSION > 101 + const char *validationLayers[] = { "VK_LAYER_KHRONOS_validation" }; +#else + const char *validationLayers[] = { "VK_LAYER_LUNARG_standard_validation" }; +#endif + + if (vk_validation->value) + { + deviceCreateInfo.enabledLayerCount = sizeof(validationLayers)/sizeof(validationLayers[0]); + deviceCreateInfo.ppEnabledLayerNames = validationLayers; + } + + return vkCreateDevice(vk_device.physical, &deviceCreateInfo, NULL, &vk_device.logical); +} + +// internal helper +static const char *deviceTypeString(VkPhysicalDeviceType dType) +{ +#define DEVTYPESTR(r) case VK_ ##r: return "VK_"#r + switch (dType) + { + DEVTYPESTR(PHYSICAL_DEVICE_TYPE_OTHER); + DEVTYPESTR(PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU); + DEVTYPESTR(PHYSICAL_DEVICE_TYPE_DISCRETE_GPU); + DEVTYPESTR(PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU); + DEVTYPESTR(PHYSICAL_DEVICE_TYPE_CPU); + default: return ""; + } +#undef DEVTYPESTR + return "UNKNOWN DEVICE"; +} + +// internal helper +static const char *vendorNameString(uint32_t vendorId) +{ + switch (vendorId) + { + case 0x1002: return "AMD"; + case 0x1010: return "ImgTec"; + case 0x10DE: return "NVIDIA"; + case 0x13B5: return "ARM"; + case 0x5143: return "Qualcomm"; + case 0x8086: return "Intel"; + default: return "unknown"; + } +} + +qboolean QVk_CreateDevice(int preferredDeviceIdx) +{ + if (!selectPhysicalDevice(preferredDeviceIdx)) + return false; + + vk_config.vendor_name = vendorNameString(vk_device.properties.vendorID); + vk_config.device_type = deviceTypeString(vk_device.properties.deviceType); + + VkResult res = createLogicalDevice(); + if (res != VK_SUCCESS) + { + R_Printf(PRINT_ALL, "Could not create Vulkan logical device: %s\n", QVk_GetError(res)); + return false; + } + + vkGetDeviceQueue(vk_device.logical, vk_device.gfxFamilyIndex, 0, &vk_device.gfxQueue); + vkGetDeviceQueue(vk_device.logical, vk_device.presentFamilyIndex, 0, &vk_device.presentQueue); + vkGetDeviceQueue(vk_device.logical, vk_device.transferFamilyIndex, 0, &vk_device.transferQueue); + vkGetPhysicalDeviceMemoryProperties(vk_device.physical, &vk_device.mem_properties); + // init our memory management + vulkan_memory_init(); + + return true; +} + +// debug label related functions +void QVk_DebugSetObjectName(uint64_t obj, VkObjectType objType, const char *objName) +{ + if (qvkSetDebugUtilsObjectNameEXT) + { + VkDebugUtilsObjectNameInfoEXT oNameInf = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, + .pNext = NULL, + .objectType = objType, + .objectHandle = obj, + .pObjectName = objName + }; + + qvkSetDebugUtilsObjectNameEXT(vk_device.logical, &oNameInf); + } +} + +void QVk_DebugSetObjectTag(uint64_t obj, VkObjectType objType, uint64_t tagName, + size_t tagSize, const void *tagData) +{ + if (qvkSetDebugUtilsObjectTagEXT) + { + VkDebugUtilsObjectTagInfoEXT oTagInf = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_TAG_INFO_EXT, + .pNext = NULL, + .objectType = objType, + .objectHandle = obj, + .tagName = tagName, + .tagSize = tagSize, + .pTag = tagData + }; + + qvkSetDebugUtilsObjectTagEXT(vk_device.logical, &oTagInf); + } +} + +void QVk_DebugLabelBegin(const VkCommandBuffer *cmdBuffer, const char *labelName, const float r, const float g, const float b) +{ + if (qvkCmdBeginDebugUtilsLabelEXT) + { + VkDebugUtilsLabelEXT labelInfo = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, + .pNext = NULL, + .pLabelName = labelName, + .color = { r, g, b, 1.f } + }; + + qvkCmdBeginDebugUtilsLabelEXT(*cmdBuffer, &labelInfo); + } +} + +void QVk_DebugLabelEnd(const VkCommandBuffer *cmdBuffer) +{ + if (qvkCmdEndDebugUtilsLabelEXT) + { + qvkCmdEndDebugUtilsLabelEXT(*cmdBuffer); + } +} + +void QVk_DebugLabelInsert(const VkCommandBuffer *cmdBuffer, const char *labelName, const float r, const float g, const float b) +{ + if (qvkInsertDebugUtilsLabelEXT) + { + VkDebugUtilsLabelEXT labelInfo = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, + .pNext = NULL, + .pLabelName = labelName, + .color = { r, g, b, 1.f } + }; + + qvkInsertDebugUtilsLabelEXT(*cmdBuffer, &labelInfo); + } +} diff --git a/src/vk/vk_draw.c b/src/vk/vk_draw.c new file mode 100644 index 0000000..6d12ff6 --- /dev/null +++ b/src/vk/vk_draw.c @@ -0,0 +1,371 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. +Copyright (C) 2018-2019 Krzysztof Kondrak + +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. +*/ + +// vk_draw.c + +#include "header/local.h" + +static image_t *draw_chars; + +/* +=============== +Draw_InitLocal +=============== +*/ +void Draw_InitLocal (void) +{ + draw_chars = Vk_FindImage("pics/conchars.pcx", it_pic); + if (!draw_chars) + { + ri.Sys_Error(ERR_FATAL, "%s: Couldn't load pics/conchars.pcx", __func__); + } +} + + + +/* +================ +RE_Draw_CharScaled + +Draws one 8*8 graphics character with 0 being transparent. +It can be clipped to the top of the screen to allow the console to be +smoothly scrolled off. +================ +*/ +void RE_Draw_CharScaled (int x, int y, int num, float scale) +{ + int row, col; + float frow, fcol, size; + + if (!vk_frameStarted) + return; + + num &= 255; + + if ((num & 127) == 32) + return; // space + + if (y <= -8) + return; // totally off screen + + row = num >> 4; + col = num & 15; + + frow = row * 0.0625; + fcol = col * 0.0625; + size = 0.0625; + + float imgTransform[] = { (float)x / vid.width, (float)y / vid.height, + 8.f * scale / vid.width, 8.f * scale / vid.height, + fcol, frow, size, size }; + QVk_DrawTexRect(imgTransform, sizeof(imgTransform), &draw_chars->vk_texture); +} + +/* +============= +RE_Draw_FindPic +============= +*/ +image_t *RE_Draw_FindPic (char *name) +{ + image_t *vk; + + if (name[0] != '/' && name[0] != '\\') + { + char fullname[MAX_QPATH]; + + Com_sprintf(fullname, sizeof(fullname), "pics/%s.pcx", name); + vk = Vk_FindImage(fullname, it_pic); + } + else + vk = Vk_FindImage(name + 1, it_pic); + + return vk; +} + +/* +============= +RE_Draw_GetPicSize +============= +*/ +void RE_Draw_GetPicSize (int *w, int *h, char *name) +{ + image_t *vk; + + vk = RE_Draw_FindPic(name); + if (!vk) + { + *w = *h = -1; + return; + } + + *w = vk->width; + *h = vk->height; +} + +/* +============= +RE_Draw_StretchPic +============= +*/ +void RE_Draw_StretchPic (int x, int y, int w, int h, char *name) +{ + image_t *vk; + + if (!vk_frameStarted) + return; + + vk = RE_Draw_FindPic(name); + if (!vk) + { + R_Printf(PRINT_ALL, "%s(): Can't find pic: %s\n", __func__, name); + return; + } + + float imgTransform[] = { (float)x / vid.width, (float)y / vid.height, + (float)w / vid.width, (float)h / vid.height, + 0, 0, 1, 1 }; + QVk_DrawTexRect(imgTransform, sizeof(imgTransform), &vk->vk_texture); +} + + +/* +============= +RE_Draw_PicScaled +============= +*/ +void RE_Draw_PicScaled (int x, int y, char *name, float scale) +{ + image_t *vk; + + vk = RE_Draw_FindPic(name); + if (!vk) + { + R_Printf(PRINT_ALL, "%s(): Can't find pic: %s\n", __func__, name); + return; + } + + RE_Draw_StretchPic(x, y, vk->width*scale, vk->height*scale, name); +} + +/* +============= +RE_Draw_TileClear + +This repeats a 64*64 tile graphic to fill the screen around a sized down +refresh window. +============= +*/ +void RE_Draw_TileClear (int x, int y, int w, int h, char *name) +{ + image_t *image; + + if (!vk_frameStarted) + return; + + image = RE_Draw_FindPic(name); + if (!image) + { + R_Printf(PRINT_ALL, "%s(): Can't find pic: %s\n", __func__, name); + return; + } + + // Change viewport and scissor to draw in the top left corner as the world view. + VkViewport tileViewport = vk_viewport; + VkRect2D tileScissor = vk_scissor; + + tileViewport.x = 0.f; + tileViewport.y = 0.f; + tileScissor.offset.x = 0; + tileScissor.offset.y = 0; + + vkCmdSetViewport(vk_activeCmdbuffer, 0u, 1u, &tileViewport); + vkCmdSetScissor(vk_activeCmdbuffer, 0u, 1u, &tileScissor); + + const float divisor = (vk_pixel_size->value < 1.0f ? 1.0f : vk_pixel_size->value); + float imgTransform[] = { (float)x / (vid.width * divisor), (float)y / (vid.height * divisor), + (float)w / (vid.width * divisor), (float)h / (vid.height * divisor), + (float)x / (64.0 * divisor), (float)y / (64.0 * divisor), + (float)w / (64.0 * divisor), (float)h / (64.0 * divisor) }; + QVk_DrawTexRect(imgTransform, sizeof(imgTransform), &image->vk_texture); + + // Restore viewport and scissor. + vkCmdSetViewport(vk_activeCmdbuffer, 0u, 1u, &vk_viewport); + vkCmdSetScissor(vk_activeCmdbuffer, 0u, 1u, &vk_scissor); +} + + +/* +============= +RE_Draw_Fill + +Fills a box of pixels with a single color +============= +*/ +void RE_Draw_Fill (int x, int y, int w, int h, int c) +{ + union + { + unsigned c; + byte v[4]; + } color; + + if (!vk_frameStarted) + return; + + if ((unsigned)c > 255) + ri.Sys_Error(ERR_FATAL, "%s: bad color", __func__); + + color.c = d_8to24table[c]; + + float imgTransform[] = { (float)x / vid.width, (float)y / vid.height, + (float)w / vid.width, (float)h / vid.height, + color.v[0] / 255.f, color.v[1] / 255.f, color.v[2] / 255.f, 1.f }; + QVk_DrawColorRect(imgTransform, sizeof(imgTransform), RP_UI); +} + +//============================================================================= + +/* +================ +RE_Draw_FadeScreen + +================ +*/ +void RE_Draw_FadeScreen (void) +{ + float imgTransform[] = { 0.f, 0.f, vid.width, vid.height, 0.f, 0.f, 0.f, .8f }; + + if (!vk_frameStarted) + return; + + QVk_DrawColorRect(imgTransform, sizeof(imgTransform), RP_UI); +} + + +//==================================================================== + + +/* +============= +RE_Draw_StretchRaw +============= +*/ +extern unsigned r_rawpalette[256]; +extern qvktexture_t vk_rawTexture; +static int scaled_size = 512; + +void RE_Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data) +{ + + int i, j; + int hscale, vscale; + unsigned *dest; + byte *source; + byte *image_scaled; + unsigned *raw_image32; + + if (!vk_frameStarted) + return; + + if (vk_retexturing->value) + { + // triple scaling + if (cols < (vid.width / 3) || rows < (vid.height / 3)) + { + image_scaled = malloc(cols * rows * 9); + + scale3x(data, image_scaled, cols, rows); + + cols = cols * 3; + rows = rows * 3; + } + else + // double scaling + { + image_scaled = malloc(cols * rows * 4); + + scale2x(data, image_scaled, cols, rows); + + cols = cols * 2; + rows = rows * 2; + } + } + else + { + image_scaled = data; + } + + if (vk_rawTexture.resource.image == VK_NULL_HANDLE) + { + // get power of two image size, + // could be updated only size only after recreate texture + for (scaled_size = 512; scaled_size < cols && scaled_size < rows; scaled_size <<= 1) + ; + } + + raw_image32 = malloc(scaled_size * scaled_size * sizeof(unsigned)); + + hscale = cols * 0x10000 / scaled_size; + vscale = rows * 0x10000 / scaled_size; + + source = image_scaled; + dest = raw_image32; + for (i = 0; i < scaled_size; i++) + { + for (j = 0; j < scaled_size; j++) + { + *dest = r_rawpalette[*(source + ((j * hscale) >> 16))]; + dest ++; + } + source = image_scaled + (((i * vscale) >> 16) * cols); + } + + if (vk_retexturing->value) + { + free(image_scaled); + SmoothColorImage(raw_image32, scaled_size * scaled_size, scaled_size >> 7); + } + + if (vk_rawTexture.resource.image != VK_NULL_HANDLE) + { + QVk_UpdateTextureData(&vk_rawTexture, (unsigned char*)raw_image32, 0, 0, scaled_size, scaled_size); + } + else + { + QVVKTEXTURE_CLEAR(vk_rawTexture); + QVk_CreateTexture(&vk_rawTexture, (unsigned char*)raw_image32, scaled_size, scaled_size, + vk_current_sampler, false); + QVk_DebugSetObjectName((uint64_t)vk_rawTexture.resource.image, + VK_OBJECT_TYPE_IMAGE, "Image: raw texture"); + QVk_DebugSetObjectName((uint64_t)vk_rawTexture.imageView, + VK_OBJECT_TYPE_IMAGE_VIEW, "Image View: raw texture"); + QVk_DebugSetObjectName((uint64_t)vk_rawTexture.descriptorSet, + VK_OBJECT_TYPE_DESCRIPTOR_SET, "Descriptor Set: raw texture"); + QVk_DebugSetObjectName((uint64_t)vk_rawTexture.resource.memory, + VK_OBJECT_TYPE_DEVICE_MEMORY, "Memory: raw texture"); + } + free(raw_image32); + + float imgTransform[] = { (float)x / vid.width, (float)y / vid.height, + (float)w / vid.width, (float)h / vid.height, + 0.f, 0.f, 1.f, 1.0f }; + QVk_DrawTexRect(imgTransform, sizeof(imgTransform), &vk_rawTexture); +} diff --git a/src/vk/vk_image.c b/src/vk/vk_image.c new file mode 100644 index 0000000..4dc555a --- /dev/null +++ b/src/vk/vk_image.c @@ -0,0 +1,1584 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. +Copyright (C) 2018-2019 Krzysztof Kondrak + +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. +*/ + +#include "header/local.h" + +image_t vktextures[MAX_VKTEXTURES]; +int numvktextures = 0; +static int img_loaded = 0; +static int image_max = 0; + +// texture for storing raw image data (cinematics, endscreens, etc.) +qvktexture_t vk_rawTexture = QVVKTEXTURE_INIT; + +static byte intensitytable[256]; +static unsigned char overbrightable[256]; + +static cvar_t *intensity; +extern cvar_t *vk_mip_nearfilter; + +unsigned d_8to24table[256]; + +// default global texture and lightmap samplers +qvksampler_t vk_current_sampler = S_MIPMAP_LINEAR; +qvksampler_t vk_current_lmap_sampler = S_MIPMAP_LINEAR; + +// internal helper +static VkImageAspectFlags getDepthStencilAspect(VkFormat depthFormat) +{ + switch (depthFormat) + { + case VK_FORMAT_D32_SFLOAT_S8_UINT: + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_D16_UNORM_S8_UINT: + return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + default: + return VK_IMAGE_ASPECT_DEPTH_BIT; + } +} + +// internal helper +static void transitionImageLayout(const VkCommandBuffer *cmdBuffer, const VkQueue *queue, const qvktexture_t *texture, const VkImageLayout oldLayout, const VkImageLayout newLayout) +{ + VkPipelineStageFlags srcStage = 0; + VkPipelineStageFlags dstStage = 0; + + VkImageMemoryBarrier imgBarrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = NULL, + .oldLayout = oldLayout, + .newLayout = newLayout, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = texture->resource.image, + .subresourceRange.baseMipLevel = 0, // no mip mapping levels + .subresourceRange.baseArrayLayer = 0, + .subresourceRange.layerCount = 1, + .subresourceRange.levelCount = texture->mipLevels + }; + + if (newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) + { + imgBarrier.subresourceRange.aspectMask = getDepthStencilAspect(texture->format); + } + else + { + imgBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + } + + if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) + { + imgBarrier.srcAccessMask = 0; + imgBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + } + // transiton that may occur when updating existing image + else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) + { + imgBarrier.srcAccessMask = 0; + imgBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + } + else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + { + if (vk_device.transferQueue == vk_device.gfxQueue) + { + imgBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + imgBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + } + else + { + if (vk_device.transferQueue == *queue) + { + // if the image is exclusively shared, start queue ownership transfer process (release) - only for VK_SHARING_MODE_EXCLUSIVE + imgBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + imgBarrier.dstAccessMask = 0; + imgBarrier.srcQueueFamilyIndex = vk_device.transferFamilyIndex; + imgBarrier.dstQueueFamilyIndex = vk_device.gfxFamilyIndex; + srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + dstStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + } + else + { + // continuing queue transfer (acquisition) - this will only happen for VK_SHARING_MODE_EXCLUSIVE images + if (texture->sharingMode == VK_SHARING_MODE_EXCLUSIVE) + { + imgBarrier.srcAccessMask = 0; + imgBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + imgBarrier.srcQueueFamilyIndex = vk_device.transferFamilyIndex; + imgBarrier.dstQueueFamilyIndex = vk_device.gfxFamilyIndex; + srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + } + else + { + imgBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + imgBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + } + } + } + } + else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) + { + imgBarrier.srcAccessMask = 0; + imgBarrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + dstStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + } + else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + { + imgBarrier.srcAccessMask = 0; + imgBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + dstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + } + else + { + assert(0 && !"Invalid image stage!"); + } + + vkCmdPipelineBarrier(*cmdBuffer, srcStage, dstStage, 0, 0, NULL, 0, NULL, 1, &imgBarrier); +} + +// internal helper +static void generateMipmaps(const VkCommandBuffer *cmdBuffer, const qvktexture_t *texture, uint32_t width, uint32_t height) +{ + int32_t mipWidth = width; + int32_t mipHeight = height; + VkFilter mipFilter = vk_mip_nearfilter->value > 0 ? VK_FILTER_NEAREST : VK_FILTER_LINEAR; + + VkImageMemoryBarrier imgBarrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = NULL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = texture->resource.image, + .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .subresourceRange.levelCount = 1, + .subresourceRange.baseArrayLayer = 0, + .subresourceRange.layerCount = 1 + }; + + // copy rescaled mip data between consecutive levels (each higher level is half the size of the previous level) + for (uint32_t i = 1; i < texture->mipLevels; ++i) + { + imgBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + imgBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + imgBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + imgBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + imgBarrier.subresourceRange.baseMipLevel = i - 1; + + vkCmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &imgBarrier); + + VkImageBlit blit = { + .srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .srcSubresource.mipLevel = i - 1, + .srcSubresource.baseArrayLayer = 0, + .srcSubresource.layerCount = 1, + .srcOffsets[0] = { 0, 0, 0 }, + .srcOffsets[1] = { mipWidth, mipHeight, 1 }, + .dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .dstSubresource.mipLevel = i, + .dstSubresource.baseArrayLayer = 0, + .dstSubresource.layerCount = 1, + .dstOffsets[0] = { 0, 0, 0 }, + .dstOffsets[1] = { mipWidth > 1 ? mipWidth >> 1 : 1, + mipHeight > 1 ? mipHeight >> 1 : 1, 1 } // each mip level is half the size of the previous level + }; + + // src image == dst image, because we're blitting between different mip levels of the same image + vkCmdBlitImage(*cmdBuffer, texture->resource.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + texture->resource.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, mipFilter); + + imgBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + imgBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + imgBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + imgBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + vkCmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &imgBarrier); + + // avoid zero-sized mip levels + if (mipWidth > 1) mipWidth >>= 1; + if (mipHeight > 1) mipHeight >>= 1; + } + + imgBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + imgBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + imgBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + imgBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imgBarrier.subresourceRange.baseMipLevel = texture->mipLevels - 1; + + vkCmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &imgBarrier); +} + +// internal helper +static void createTextureImage(qvktexture_t *dstTex, const unsigned char *data, uint32_t width, uint32_t height) +{ + int unifiedTransferAndGfx = vk_device.transferQueue == vk_device.gfxQueue ? 1 : 0; + // assuming 32bit images + uint32_t imageSize = width * height * 4; + + VkBuffer staging_buffer; + VkCommandBuffer command_buffer; + uint32_t staging_offset; + void *imgData = QVk_GetStagingBuffer(imageSize, 4, &command_buffer, &staging_buffer, &staging_offset); + if (!imgData) + Sys_Error("%s: Staging buffers is smaller than image: %d.\n", __func__, imageSize); + + memcpy(imgData, data, (size_t)imageSize); + + VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + // set extra image usage flag if we're dealing with mipmapped image - will need it for copying data between mip levels + if (dstTex->mipLevels > 1) + imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + + VK_VERIFY(QVk_CreateImage(width, height, dstTex->format, VK_IMAGE_TILING_OPTIMAL, imageUsage, dstTex)); + + transitionImageLayout(&command_buffer, &vk_device.transferQueue, dstTex, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + // copy buffer to image + VkBufferImageCopy region = { + .bufferOffset = staging_offset, + .bufferRowLength = 0, + .bufferImageHeight = 0, + .imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .imageSubresource.mipLevel = 0, + .imageSubresource.baseArrayLayer = 0, + .imageSubresource.layerCount = 1, + .imageOffset = { 0, 0, 0 }, + .imageExtent = { width, height, 1 } + }; + + vkCmdCopyBufferToImage(command_buffer, staging_buffer, dstTex->resource.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + if (dstTex->mipLevels > 1) + { + // vkCmdBlitImage requires a queue with GRAPHICS_BIT present + generateMipmaps(&command_buffer, dstTex, width, height); + } + else + { + // for non-unified transfer and graphics, this step begins queue ownership transfer to graphics queue (for exclusive sharing only) + if (unifiedTransferAndGfx || dstTex->sharingMode == VK_SHARING_MODE_EXCLUSIVE) + transitionImageLayout(&command_buffer, &vk_device.transferQueue, dstTex, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + if (!unifiedTransferAndGfx) + { + transitionImageLayout(&command_buffer, &vk_device.gfxQueue, dstTex, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + } + } +} + +VkResult QVk_CreateImageView(const VkImage *image, VkImageAspectFlags aspectFlags, VkImageView *imageView, VkFormat format, uint32_t mipLevels) +{ + VkImageViewCreateInfo ivCreateInfo = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .image = *image, + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = format, + .components.r = VK_COMPONENT_SWIZZLE_IDENTITY, + .components.g = VK_COMPONENT_SWIZZLE_IDENTITY, + .components.b = VK_COMPONENT_SWIZZLE_IDENTITY, + .components.a = VK_COMPONENT_SWIZZLE_IDENTITY, + .subresourceRange.aspectMask = aspectFlags, + .subresourceRange.baseArrayLayer = 0, + .subresourceRange.baseMipLevel = 0, + .subresourceRange.layerCount = 1, + .subresourceRange.levelCount = mipLevels + }; + + return vkCreateImageView(vk_device.logical, &ivCreateInfo, NULL, imageView); +} + +VkResult QVk_CreateImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, qvktexture_t *texture) +{ + VkImageCreateInfo imageInfo = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .imageType = VK_IMAGE_TYPE_2D, + .extent.width = width, + .extent.height = height, + .extent.depth = 1, + .mipLevels = texture->mipLevels, + .arrayLayers = 1, + .format = format, + .tiling = tiling, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .usage = usage, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .samples = texture->sampleCount, + .flags = 0 + }; + + uint32_t queueFamilies[] = { (uint32_t)vk_device.gfxFamilyIndex, (uint32_t)vk_device.transferFamilyIndex }; + if (vk_device.gfxFamilyIndex != vk_device.transferFamilyIndex) + { + imageInfo.sharingMode = VK_SHARING_MODE_CONCURRENT; + imageInfo.queueFamilyIndexCount = 2; + imageInfo.pQueueFamilyIndices = queueFamilies; + } + + texture->sharingMode = imageInfo.sharingMode; + return image_create( + &texture->resource, imageInfo, + /*mem_properties*/ 0, + /*mem_preferences*/ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); +} + +void QVk_CreateDepthBuffer(VkSampleCountFlagBits sampleCount, qvktexture_t *depthBuffer) +{ + depthBuffer->format = QVk_FindDepthFormat(); + depthBuffer->sampleCount = sampleCount; + + VK_VERIFY(QVk_CreateImage(vk_swapchain.extent.width, vk_swapchain.extent.height, depthBuffer->format, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, depthBuffer)); + VK_VERIFY(QVk_CreateImageView(&depthBuffer->resource.image, getDepthStencilAspect(depthBuffer->format), &depthBuffer->imageView, depthBuffer->format, depthBuffer->mipLevels)); +} + +static void ChangeColorBufferLayout(VkImage image, VkImageLayout fromLayout, VkImageLayout toLayout) +{ + VkCommandBuffer commandBuffer = QVk_CreateCommandBuffer(&vk_transferCommandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); + QVk_BeginCommand(&commandBuffer); + + const VkImageSubresourceRange subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0u, + .levelCount = 1u, + .baseArrayLayer = 0u, + .layerCount = 1u, + }; + + const VkImageMemoryBarrier imageBarrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = NULL, + .srcAccessMask = 0u, + .dstAccessMask = 0u, + .oldLayout = fromLayout, + .newLayout = toLayout, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = image, + .subresourceRange = subresourceRange, + }; + + vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0u, 0u, NULL, 0u, NULL, 1u, &imageBarrier); + + QVk_SubmitCommand(&commandBuffer, &vk_device.transferQueue); + vkFreeCommandBuffers(vk_device.logical, vk_transferCommandPool, 1, &commandBuffer); +} + +void QVk_CreateColorBuffer(VkSampleCountFlagBits sampleCount, qvktexture_t *colorBuffer, int extraFlags) +{ + colorBuffer->format = vk_swapchain.format; + colorBuffer->sampleCount = sampleCount; + + VK_VERIFY(QVk_CreateImage(vk_swapchain.extent.width, vk_swapchain.extent.height, colorBuffer->format, VK_IMAGE_TILING_OPTIMAL, extraFlags | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, colorBuffer)); + VK_VERIFY(QVk_CreateImageView(&colorBuffer->resource.image, VK_IMAGE_ASPECT_COLOR_BIT, &colorBuffer->imageView, colorBuffer->format, colorBuffer->mipLevels)); + + // The single-sample color attachment ends every frame as + // SHADER_READ_ONLY_OPTIMAL as used in the post-processing stage, so its + // initial image layout is specified as such. + // + // The multi-sample color attachment is always COLOR_ATTACHMENT_OPTIMAL. + // + const VkImageLayout newLayout = ((sampleCount == VK_SAMPLE_COUNT_1_BIT) ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + ChangeColorBufferLayout(colorBuffer->resource.image, VK_IMAGE_LAYOUT_UNDEFINED, newLayout); +} + +void QVk_CreateTexture(qvktexture_t *texture, const unsigned char *data, uint32_t width, uint32_t height, qvksampler_t samplerType, qboolean clampToEdge) +{ + createTextureImage(texture, data, width, height); + VK_VERIFY(QVk_CreateImageView(&texture->resource.image, VK_IMAGE_ASPECT_COLOR_BIT, &texture->imageView, texture->format, texture->mipLevels)); + + // create descriptor set for the texture + VkDescriptorSetAllocateInfo dsAllocInfo = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .pNext = NULL, + .descriptorPool = vk_descriptorPool, + .descriptorSetCount = 1, + .pSetLayouts = &vk_samplerDescSetLayout + }; + + VK_VERIFY(vkAllocateDescriptorSets(vk_device.logical, &dsAllocInfo, &texture->descriptorSet)); + + // attach sampler + QVk_UpdateTextureSampler(texture, samplerType, clampToEdge); +} + +void QVk_UpdateTextureData(qvktexture_t *texture, const unsigned char *data, uint32_t offset_x, uint32_t offset_y, uint32_t width, uint32_t height) +{ + int unifiedTransferAndGfx = vk_device.transferQueue == vk_device.gfxQueue ? 1 : 0; + // assuming 32bit images + uint32_t imageSize = width * height * 4; + + VkBuffer staging_buffer; + VkCommandBuffer command_buffer; + uint32_t staging_offset; + void *imgData = QVk_GetStagingBuffer(imageSize, 4, &command_buffer, &staging_buffer, &staging_offset); + if (!imgData) + Sys_Error("%s: Staging buffers is smaller than image: %d.\n", __func__, imageSize); + + memcpy(imgData, data, (size_t)imageSize); + + transitionImageLayout(&command_buffer, &vk_device.transferQueue, texture, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + // copy buffer to image + VkBufferImageCopy region = { + .bufferOffset = staging_offset, + .bufferRowLength = 0, + .bufferImageHeight = 0, + .imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .imageSubresource.mipLevel = 0, + .imageSubresource.baseArrayLayer = 0, + .imageSubresource.layerCount = 1, + .imageOffset = { offset_x, offset_y, 0 }, + .imageExtent = { width, height, 1 } + }; + + vkCmdCopyBufferToImage(command_buffer, staging_buffer, texture->resource.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + if (texture->mipLevels > 1) + { + // vkCmdBlitImage requires a queue with GRAPHICS_BIT present + generateMipmaps(&command_buffer, texture, width, height); + } + else + { + // for non-unified transfer and graphics, this step begins queue ownership transfer to graphics queue (for exclusive sharing only) + if (unifiedTransferAndGfx || texture->sharingMode == VK_SHARING_MODE_EXCLUSIVE) + transitionImageLayout(&command_buffer, &vk_device.transferQueue, texture, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + if (!unifiedTransferAndGfx) + { + transitionImageLayout(&command_buffer, &vk_device.gfxQueue, texture, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + } + } +} + +static void QVk_ReleaseTexture(qvktexture_t *texture) +{ + QVk_SubmitStagingBuffers(); + if (vk_device.logical != VK_NULL_HANDLE) + { + vkDeviceWaitIdle(vk_device.logical); + } + + if (texture->imageView != VK_NULL_HANDLE) + { + vkDestroyImageView(vk_device.logical, texture->imageView, NULL); + texture->imageView = VK_NULL_HANDLE; + } + + if (texture->resource.image != VK_NULL_HANDLE) + image_destroy(&texture->resource); + + if (texture->descriptorSet != VK_NULL_HANDLE) + vkFreeDescriptorSets(vk_device.logical, vk_descriptorPool, 1, &texture->descriptorSet); + + texture->descriptorSet = VK_NULL_HANDLE; +} + +void QVk_ReadPixels(uint8_t *dstBuffer, const VkOffset2D *offset, const VkExtent2D *extent) +{ + BufferResource_t buff; + uint8_t *pMappedData; + VkCommandBuffer cmdBuffer; + extern int vk_activeBufferIdx; + + VkBufferCreateInfo bcInfo = { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .size = extent->width * extent->height * 4, + .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = NULL, + }; + + VK_VERIFY(buffer_create(&buff, bcInfo, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VK_MEMORY_PROPERTY_HOST_CACHED_BIT)); + + cmdBuffer = QVk_CreateCommandBuffer(&vk_commandPool[vk_activeBufferIdx], VK_COMMAND_BUFFER_LEVEL_PRIMARY); + VK_VERIFY(QVk_BeginCommand(&cmdBuffer)); + + // transition the current swapchain image to be a source of data transfer to our buffer + VkImageMemoryBarrier imgBarrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = NULL, + .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, + .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = vk_swapchain.images[vk_activeBufferIdx], + .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .subresourceRange.baseMipLevel = 0, + .subresourceRange.baseArrayLayer = 0, + .subresourceRange.layerCount = 1, + .subresourceRange.levelCount = 1 + }; + + vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &imgBarrier); + + VkBufferImageCopy region = { + .bufferOffset = 0, + .bufferRowLength = extent->width, + .bufferImageHeight = extent->height, + .imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .imageSubresource.mipLevel = 0, + .imageSubresource.baseArrayLayer = 0, + .imageSubresource.layerCount = 1, + .imageOffset = { offset->x, offset->y, 0 }, + .imageExtent = { extent->width, extent->height, 1 } + }; + + // copy the swapchain image + vkCmdCopyImageToBuffer(cmdBuffer, vk_swapchain.images[vk_activeBufferIdx], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buff.buffer, 1, ®ion); + VK_VERIFY(vkDeviceWaitIdle(vk_device.logical)); + QVk_SubmitCommand(&cmdBuffer, &vk_device.gfxQueue); + + // store image in destination buffer + pMappedData = buffer_map(&buff); + memcpy(dstBuffer, pMappedData, extent->width * extent->height * 4); + buffer_unmap(&buff); + + buffer_destroy(&buff); +} + +/* +=============== +Vk_ImageList_f +=============== +*/ +void Vk_ImageList_f (void) +{ + int i, used, texels; + image_t *image; + qboolean freeup; + + R_Printf(PRINT_ALL, "------------------\n"); + texels = 0; + used = 0; + + for (i = 0, image = vktextures; i < numvktextures; i++, image++) + { + char *in_use = ""; + + if (image->vk_texture.resource.image == VK_NULL_HANDLE) + continue; + + if (image->registration_sequence == registration_sequence) + { + in_use = "*"; + used++; + } + + texels += image->upload_width*image->upload_height; + switch (image->type) + { + case it_skin: + R_Printf(PRINT_ALL, "M"); + break; + case it_sprite: + R_Printf(PRINT_ALL, "S"); + break; + case it_wall: + R_Printf(PRINT_ALL, "W"); + break; + case it_pic: + R_Printf(PRINT_ALL, "P"); + break; + default: + R_Printf(PRINT_ALL, " "); + break; + } + + R_Printf(PRINT_ALL, " %4i %4i RGB: %s (%dx%d) %s\n", + image->upload_width, image->upload_height, image->name, + image->width, image->height, in_use); + } + R_Printf(PRINT_ALL, "Total texel count (not counting mipmaps): %i in %d images\n", texels, img_loaded); + freeup = Vk_ImageHasFreeSpace(); + R_Printf(PRINT_ALL, "Used %d of %d images%s.\n", used, image_max, freeup ? ", has free space" : ""); +} + +typedef struct +{ + char *name; + qvksampler_t samplerType; +} vkmode_t; + +static vkmode_t modes[] = { + {"VK_NEAREST", S_NEAREST }, + {"VK_LINEAR", S_LINEAR }, + {"VK_MIPMAP_NEAREST", S_MIPMAP_NEAREST }, + {"VK_MIPMAP_LINEAR", S_MIPMAP_LINEAR } +}; + +#define NUM_VK_MODES (sizeof(modes) / sizeof (vkmode_t)) + +/* + =============== + Vk_TextureMode + =============== + */ +void Vk_TextureMode( char *string ) +{ + int i,j; + image_t *image; + static char prev_mode[32] = { "VK_MIPMAP_LINEAR" }; + + for (i = 0; i < NUM_VK_MODES; i++) + { + if (!Q_stricmp(modes[i].name, string)) + break; + } + + if (i == NUM_VK_MODES) + { + R_Printf(PRINT_ALL, "bad filter name (valid values: VK_NEAREST, VK_LINEAR, VK_MIPMAP_NEAREST, VK_MIPMAP_LINEAR)\n"); + ri.Cvar_Set("vk_texturemode", prev_mode); + return; + } + + memcpy(prev_mode, string, strlen(string)); + prev_mode[strlen(string)] = '\0'; + + vk_current_sampler = i; + + vkDeviceWaitIdle(vk_device.logical); + for (j = 0, image = vktextures; j < numvktextures; j++, image++) + { + // skip console characters - we want them unfiltered at all times + if (image->vk_texture.resource.image != VK_NULL_HANDLE && Q_stricmp(image->name, "pics/conchars.pcx")) + QVk_UpdateTextureSampler(&image->vk_texture, i, image->vk_texture.clampToEdge); + } + + if (vk_rawTexture.resource.image != VK_NULL_HANDLE) + QVk_UpdateTextureSampler(&vk_rawTexture, i, vk_rawTexture.clampToEdge); +} + +/* + =============== + Vk_LmapTextureMode + =============== + */ +void Vk_LmapTextureMode( char *string ) +{ + int i,j; + static char prev_mode[32] = { "VK_MIPMAP_LINEAR" }; + + for (i = 0; i < NUM_VK_MODES; i++) + { + if (!Q_stricmp(modes[i].name, string)) + break; + } + + if (i == NUM_VK_MODES) + { + R_Printf(PRINT_ALL, "bad filter name (valid values: VK_NEAREST, VK_LINEAR, VK_MIPMAP_NEAREST, VK_MIPMAP_LINEAR)\n"); + ri.Cvar_Set("vk_lmaptexturemode", prev_mode); + return; + } + + memcpy(prev_mode, string, strlen(string)); + prev_mode[strlen(string)] = '\0'; + + vk_current_lmap_sampler = i; + + vkDeviceWaitIdle(vk_device.logical); + for (j = 0; j < MAX_LIGHTMAPS*2; j++) + { + if (vk_state.lightmap_textures[j].resource.image != VK_NULL_HANDLE) + QVk_UpdateTextureSampler(&vk_state.lightmap_textures[j], i, vk_state.lightmap_textures[j].clampToEdge); + } +} + +/* +==================================================================== + +IMAGE FLOOD FILLING + +==================================================================== +*/ + + +/* +================= +Mod_FloodFillSkin + +Fill background pixels so mipmapping doesn't have haloes +================= +*/ + +typedef struct +{ + short x, y; +} floodfill_t; + +/* must be a power of 2 */ +#define FLOODFILL_FIFO_SIZE 0x1000 +#define FLOODFILL_FIFO_MASK (FLOODFILL_FIFO_SIZE - 1) + +#define FLOODFILL_STEP(off, dx, dy) \ + { \ + if (pos[off] == fillcolor) \ + { \ + pos[off] = 255; \ + fifo[inpt].x = x + (dx), fifo[inpt].y = y + (dy); \ + inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; \ + } \ + else if (pos[off] != 255) \ + { \ + fdc = pos[off]; \ + } \ + } + +/* + * Fill background pixels so mipmapping doesn't have haloes + */ +static void +FloodFillSkin(byte *skin, int skinwidth, int skinheight) +{ + byte fillcolor = *skin; /* assume this is the pixel to fill */ + floodfill_t fifo[FLOODFILL_FIFO_SIZE]; + int inpt = 0, outpt = 0; + int filledcolor = 0; + int i; + + /* attempt to find opaque black */ + for (i = 0; i < 256; ++i) + { + if (LittleLong(d_8to24table[i]) == (255 << 0)) /* alpha 1.0 */ + { + filledcolor = i; + break; + } + } + + /* can't fill to filled color or to transparent color (used as visited marker) */ + if ((fillcolor == filledcolor) || (fillcolor == 255)) + { + return; + } + + fifo[inpt].x = 0, fifo[inpt].y = 0; + inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; + + while (outpt != inpt) + { + int x = fifo[outpt].x, y = fifo[outpt].y; + int fdc = filledcolor; + byte *pos = &skin[x + skinwidth * y]; + + outpt = (outpt + 1) & FLOODFILL_FIFO_MASK; + + if (x > 0) + { + FLOODFILL_STEP(-1, -1, 0); + } + + if (x < skinwidth - 1) + { + FLOODFILL_STEP(1, 1, 0); + } + + if (y > 0) + { + FLOODFILL_STEP(-skinwidth, 0, -1); + } + + if (y < skinheight - 1) + { + FLOODFILL_STEP(skinwidth, 0, 1); + } + + skin[x + skinwidth * y] = fdc; + } +} + + +/* +================ +Vk_LightScaleTexture + +Scale up the pixel values in a texture to increase the +lighting range +================ +*/ +static void Vk_LightScaleTexture (byte *in, int inwidth, int inheight) +{ + int i, c; + byte *p; + + p = (byte *)in; + + c = inwidth*inheight; + for (i=0 ; i>= (int)vk_picmip->value; + scaled_height >>= (int)vk_picmip->value; + } + + if (scaled_width < 1) + scaled_width = 1; + if (scaled_height < 1) + scaled_height = 1; + + *texBuffer = malloc(scaled_width * scaled_height * 4); + if (!*texBuffer) + ri.Sys_Error(ERR_DROP, "%s: too big", __func__); + + *upload_width = scaled_width; + *upload_height = scaled_height; + + if (scaled_width == width && scaled_height == height) + { + memcpy(*texBuffer, data, scaled_width * scaled_height * 4); + } + else + { + ResizeSTB(data, width, height, + *texBuffer, scaled_width, scaled_height); + } + + // world textures + if (type != it_pic && type != it_sky) + { + Vk_LightScaleTexture(*texBuffer, scaled_width, scaled_height); + } + + while (scaled_width > 1 || scaled_height > 1) + { + scaled_width >>= 1; + scaled_height >>= 1; + if (scaled_width < 1) + scaled_width = 1; + if (scaled_height < 1) + scaled_height = 1; + miplevel++; + } + + return miplevel; +} + +/* +=============== +Vk_Upload8 + +Returns number of mip levels +=============== +*/ + +static uint32_t Vk_Upload8 (byte *data, int width, int height, imagetype_t type, + byte **texBuffer, int *upload_width, int *upload_height) +{ + unsigned *trans; + int i, s; + int miplevel; + + s = width * height; + + trans = malloc(s * sizeof(*trans)); + if (!trans) + ri.Sys_Error(ERR_DROP, "%s: too large", __func__); + + for (i = 0; i < s; i++) + { + int p; + + p = data[i]; + trans[i] = d_8to24table[p]; + } + + if (type != it_sky && type != it_wall) + { + for (i = 0; i < s; i++) + { + int p; + + p = data[i]; + + if (p == 255) + { // transparent, so scan around for another color + // to avoid alpha fringes + // FIXME: do a full flood fill so mips work... + if (i > width && data[i - width] != 255) + p = data[i - width]; + else if (i < s - width && data[i + width] != 255) + p = data[i + width]; + else if (i > 0 && data[i - 1] != 255) + p = data[i - 1]; + else if (i < s - 1 && data[i + 1] != 255) + p = data[i + 1]; + else + p = 0; + // copy rgb components + ((byte *)&trans[i])[0] = ((byte *)&d_8to24table[p])[0]; + ((byte *)&trans[i])[1] = ((byte *)&d_8to24table[p])[1]; + ((byte *)&trans[i])[2] = ((byte *)&d_8to24table[p])[2]; + } + } + } + + // optimize 8bit images only when we forced such logic + if (vk_retexturing->value >= 2) + { + SmoothColorImage(trans, s, s >> 7); + } + + miplevel = Vk_Upload32((byte *)trans, width, height, type, texBuffer, upload_width, upload_height); + free(trans); + return miplevel; +} + + +/* +================ +Vk_LoadPic + +This is also used as an entry point for the generated r_notexture +================ +*/ +image_t * +Vk_LoadPic(char *name, byte *pic, int width, int realwidth, + int height, int realheight, imagetype_t type, + int bits) +{ + image_t *image; + byte *texBuffer; + int upload_width, upload_height; + + qboolean nolerp = false; + + if (vk_nolerp_list != NULL && vk_nolerp_list->string != NULL) + { + nolerp = strstr(vk_nolerp_list->string, name) != NULL; + } + + { + int i; + // find a free image_t + for (i = 0, image = vktextures; ivk_texture.resource.image == VK_NULL_HANDLE) + break; + } + if (i == numvktextures) + { + if (numvktextures == MAX_VKTEXTURES) + ri.Sys_Error(ERR_DROP, "%s: MAX_VKTEXTURES", __func__); + numvktextures++; + } + image = &vktextures[i]; + } + + if (strlen(name) >= sizeof(image->name)) + ri.Sys_Error(ERR_DROP, "%s: \"%s\" is too long", __func__, name); + strcpy(image->name, name); + image->registration_sequence = registration_sequence; + // zero-clear Vulkan texture handle + QVVKTEXTURE_CLEAR(image->vk_texture); + image->width = realwidth; + image->height = realheight; + image->type = type; + // update count of loaded images + img_loaded ++; + if (vk_validation->value) + { + R_Printf(PRINT_ALL, "%s: Load %s[%d]\n", __func__, image->name, img_loaded); + } + + if (type == it_skin && bits == 8) + FloodFillSkin(pic, width, height); + + if (bits == 8) + { + // resize 8bit images only when we forced such logic + if (vk_retexturing->value >= 2) + { + byte *image_converted = malloc(width * height * 4); + scale2x(pic, image_converted, width, height); + image->vk_texture.mipLevels = Vk_Upload8(image_converted, width * 2, height * 2, image->type, &texBuffer, &upload_width, &upload_height); + free(image_converted); + } + else + { + image->vk_texture.mipLevels = Vk_Upload8(pic, width, height, image->type, &texBuffer, &upload_width, &upload_height); + } + } + else + image->vk_texture.mipLevels = Vk_Upload32(pic, width, height, image->type, &texBuffer, &upload_width, &upload_height); + + image->upload_width = upload_width; // after power of 2 and scales + image->upload_height = upload_height; + + QVk_CreateTexture(&image->vk_texture, (unsigned char*)texBuffer, + image->upload_width, image->upload_height, + nolerp ? S_NEAREST : vk_current_sampler, (type == it_sky)); + QVk_DebugSetObjectName((uint64_t)image->vk_texture.resource.image, + VK_OBJECT_TYPE_IMAGE, va("Image: %s", name)); + QVk_DebugSetObjectName((uint64_t)image->vk_texture.imageView, + VK_OBJECT_TYPE_IMAGE_VIEW, va("Image View: %s", name)); + QVk_DebugSetObjectName((uint64_t)image->vk_texture.descriptorSet, + VK_OBJECT_TYPE_DESCRIPTOR_SET, va("Descriptor Set: %s", name)); + QVk_DebugSetObjectName((uint64_t)image->vk_texture.resource.memory, + VK_OBJECT_TYPE_DEVICE_MEMORY, "Memory: game textures"); + + if (texBuffer) + { + free(texBuffer); + } + return image; +} + + +/* +================ +Vk_LoadWal +================ +*/ +static image_t *Vk_LoadWal (char *name, imagetype_t type) +{ + miptex_t *mt; + int width, height, ofs; + image_t *image; + + ri.FS_LoadFile (name, (void **)&mt); + if (!mt) + { + R_Printf(PRINT_ALL, "%s: can't load %s\n", __func__, name); + return r_notexture; + } + + width = LittleLong (mt->width); + height = LittleLong (mt->height); + ofs = LittleLong (mt->offsets[0]); + + image = Vk_LoadPic(name, (byte *)mt + ofs, + width, width, + height, height, + type, 8); + + ri.FS_FreeFile ((void *)mt); + + return image; +} + +static image_t * +Vk_LoadM8(char *origname, imagetype_t type) +{ + m8tex_t *mt; + int width, height, ofs, size; + image_t *image; + char name[256]; + unsigned char *image_buffer = NULL; + + Q_strlcpy(name, origname, sizeof(name)); + + /* Add the extension */ + if (strcmp(COM_FileExtension(name), "m8")) + { + Q_strlcat(name, ".m8", sizeof(name)); + } + + size = ri.FS_LoadFile(name, (void **)&mt); + + if (!mt) + { + R_Printf(PRINT_ALL, "%s: can't load %s\n", __func__, name); + return r_notexture; + } + + if (size < sizeof(m8tex_t)) + { + R_Printf(PRINT_ALL, "%s: can't load %s, small header\n", __func__, name); + ri.FS_FreeFile((void *)mt); + return r_notexture; + } + + if (LittleLong (mt->version) != M8_VERSION) + { + R_Printf(PRINT_ALL, "LoadWal: can't load %s, wrong magic value.\n", name); + ri.FS_FreeFile ((void *)mt); + return r_notexture; + } + + width = LittleLong(mt->width[0]); + height = LittleLong(mt->height[0]); + ofs = LittleLong(mt->offsets[0]); + + if ((ofs <= 0) || (width <= 0) || (height <= 0) || + (((size - ofs) / height) < width)) + { + R_Printf(PRINT_ALL, "%s: can't load %s, small body\n", __func__, name); + ri.FS_FreeFile((void *)mt); + return r_notexture; + } + + image_buffer = malloc (width * height * 4); + for(int i=0; ipalette[value].r; + image_buffer[i * 4 + 1] = mt->palette[value].g; + image_buffer[i * 4 + 2] = mt->palette[value].b; + image_buffer[i * 4 + 3] = value == 255 ? 0 : 255; + } + + image = Vk_LoadPic(name, image_buffer, width, width, height, height, type, 32); + free(image_buffer); + + ri.FS_FreeFile((void *)mt); + + return image; +} + +static image_t* +Vk_LoadHiColorImage(char *name, const char* namewe, const char *ext, imagetype_t type) +{ + image_t *image = NULL; + byte *pic = NULL; + int realwidth = 0, realheight = 0; + int width = 0, height = 0; + + if (strcmp(ext, "pcx") == 0) + { + /* Get size of the original texture */ + GetPCXInfo(name, &realwidth, &realheight); + } + else if (strcmp(ext, "wal") == 0) + { + /* Get size of the original texture */ + GetWalInfo(name, &realwidth, &realheight); + } + else if (strcmp(ext, "m8") == 0) + { + /* Get size of the original texture */ + GetM8Info(name, &realwidth, &realheight); + } + + /* try to load a tga, png or jpg (in that order/priority) */ + if ( LoadSTB(namewe, "tga", &pic, &width, &height) + || LoadSTB(namewe, "png", &pic, &width, &height) + || LoadSTB(namewe, "jpg", &pic, &width, &height) ) + { + if (width >= realwidth && height >= realheight) + { + if (realheight == 0 || realwidth == 0) + { + realheight = height; + realwidth = width; + } + + image = Vk_LoadPic(name, pic, + width, realwidth, + height, realheight, + type, 32); + } + } + + if (pic) + { + free(pic); + } + + return image; +} + +static image_t* +Vk_LoadImage(char *name, const char* namewe, const char *ext, imagetype_t type) +{ + image_t *image = NULL; + + // with retexturing + if (vk_retexturing->value) + { + image = Vk_LoadHiColorImage(name, namewe, ext, type); + } + + if (!image) + { + byte *pic; + int width, height; + + // + // load the pic from disk + // + pic = NULL; + if (!strcmp(ext, "pcx")) + { + byte *palette; + palette = NULL; + + LoadPCX (name, &pic, &palette, &width, &height); + if (!pic) + return NULL; + image = Vk_LoadPic(name, pic, + width, width, + height, height, + type, 8); + + if (palette) + free(palette); + } + else if (!strcmp(ext, "wal")) + { + image = Vk_LoadWal (name, type); + } + else if (!strcmp(ext, "m8")) + { + image = Vk_LoadM8 (name, type); + } + else if (!strcmp(ext, "tga")) + { + if (!LoadSTB (namewe, "tga", &pic, &width, &height)) + return NULL; + if (!pic) + return NULL; + image = Vk_LoadPic(name, pic, + width, width, + height, height, + type, 32); + } + + if (pic) + free(pic); + } + + return image; +} + +/* +=============== +Vk_FindImage + +Finds or loads the given image +=============== +*/ +image_t *Vk_FindImage (char *name, imagetype_t type) +{ + image_t *image; + int i, len; + char *ptr; + char namewe[256]; + const char* ext; + + if (!name) + { + return NULL; + } + + ext = COM_FileExtension(name); + if(!ext[0]) + { + /* file has no extension */ + return NULL; + } + + len = strlen(name); + + /* Remove the extension */ + memset(namewe, 0, 256); + memcpy(namewe, name, len - (strlen(ext) + 1)); + + if (len < 5) + { + return NULL; + } + + /* fix backslashes */ + while ((ptr = strchr(name, '\\'))) + { + *ptr = '/'; + } + + // look for it + for (i=0, image=vktextures ; iname)) + { + image->registration_sequence = registration_sequence; + return image; + } + } + + // + // load the pic from disk + // + return Vk_LoadImage(name, namewe, ext, type); +} + + +/* +=============== +RE_RegisterSkin +=============== +*/ +struct image_s *RE_RegisterSkin (char *name) +{ + return Vk_FindImage (name, it_skin); +} + +qboolean Vk_ImageHasFreeSpace(void) +{ + int i, used; + image_t *image; + + used = 0; + + for (i = 0, image = vktextures; i < numvktextures; i++, image++) + { + if (!image->name[0]) + continue; + if (image->registration_sequence == registration_sequence) + { + used ++; + } + } + + if (image_max < used) + { + image_max = used; + } + + // should same size of free slots as currently used + return (img_loaded + used) < MAX_VKTEXTURES; +} + +/* +================ +Vk_FreeUnusedImages + +Any image that was not touched on this registration sequence +will be freed. +================ +*/ +void Vk_FreeUnusedImages (void) +{ + int i; + image_t *image; + + if (Vk_ImageHasFreeSpace()) + { + // should be enough space for load next images + return; + } + + // never free r_notexture or particle texture + r_notexture->registration_sequence = registration_sequence; + r_particletexture->registration_sequence = registration_sequence; + r_squaretexture->registration_sequence = registration_sequence; + + for (i = 0, image = vktextures; i < numvktextures; i++, image++) + { + if (image->registration_sequence == registration_sequence) + continue; // used this sequence + if (!image->registration_sequence) + continue; // free image_t slot + if (image->type == it_pic) + continue; // don't free pics + + if (vk_validation->value) + { + R_Printf(PRINT_ALL, "%s: Unload %s[%d]\n", __func__, image->name, img_loaded); + } + + // free it + QVk_ReleaseTexture(&image->vk_texture); + memset(image, 0, sizeof(*image)); + + img_loaded --; + if (img_loaded < 0) + { + ri.Sys_Error (ERR_DROP, "%s: Broken unload", __func__); + } + } + + // free all unused blocks + vulkan_memory_free_unused(); +} + + +/* +=============== +Draw_GetPalette +=============== +*/ +static int Draw_GetPalette (void) +{ + int i; + byte *pic, *pal; + int width, height; + + // get the palette + + LoadPCX ("pics/colormap.pcx", &pic, &pal, &width, &height); + if (!pal) + ri.Sys_Error (ERR_FATAL, "Couldn't load pics/colormap.pcx"); + + for (i=0 ; i<256 ; i++) + { + unsigned v; + int r, g, b; + + r = pal[i*3+0]; + g = pal[i*3+1]; + b = pal[i*3+2]; + + v = (255<<24) + (r<<0) + (g<<8) + (b<<16); + d_8to24table[i] = LittleLong(v); + } + + d_8to24table[255] &= LittleLong(0xffffff); // 255 is transparent + + free (pic); + free (pal); + + return 0; +} + + +/* +=============== +Vk_InitImages +=============== +*/ +void Vk_InitImages (void) +{ + int i; + float overbright; + + numvktextures = 0; + img_loaded = 0; + image_max = 0; + registration_sequence = 1; + + // init intensity conversions + intensity = ri.Cvar_Get("vk_intensity", "2", 0); + + if (intensity->value <= 1) + ri.Cvar_Set("vk_intensity", "1"); + + vk_state.inverse_intensity = 1 / intensity->value; + + for (i = 0; i<256; i++) + { + int j; + + j = i * intensity->value; + if (j > 255) + j = 255; + intensitytable[i] = j; + } + + Draw_GetPalette(); + + overbright = vk_overbrightbits->value; + + if(overbright < 0.5) + overbright = 0.5; + + if(overbright > 4.0) + overbright = 4.0; + + for (i=0 ; i<256 ; i++) { + int inf; + + inf = i * overbright; + + if (inf < 0) + inf = 0; + if (inf > 255) + inf = 255; + + overbrightable[i] = inf; + } +} + +/* +=============== +Vk_ShutdownImages +=============== +*/ +void Vk_ShutdownImages (void) +{ + int i; + image_t *image; + + for (i = 0, image = vktextures; iregistration_sequence) + continue; // free image_t slot + + if (vk_validation->value) + { + R_Printf(PRINT_ALL, "%s: Unload %s[%d]\n", __func__, image->name, img_loaded); + } + + QVk_ReleaseTexture(&image->vk_texture); + memset(image, 0, sizeof(*image)); + + img_loaded --; + if (img_loaded < 0) + { + ri.Sys_Error (ERR_DROP, "%s: Broken unload", __func__); + } + } + + QVk_ReleaseTexture(&vk_rawTexture); + + for(i = 0; i < MAX_LIGHTMAPS*2; i++) + QVk_ReleaseTexture(&vk_state.lightmap_textures[i]); +} + diff --git a/src/vk/vk_light.c b/src/vk/vk_light.c new file mode 100644 index 0000000..1a17929 --- /dev/null +++ b/src/vk/vk_light.c @@ -0,0 +1,626 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. +Copyright (C) 2018-2019 Krzysztof Kondrak + +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. + +*/ +// vk_light.c + +#include "header/local.h" + +static int r_dlightframecount; + +#define DLIGHT_CUTOFF 64 + +/* +============================================================================= + +DYNAMIC LIGHTS BLEND RENDERING + +============================================================================= +*/ + +void R_RenderDlight (dlight_t *light) +{ + int i, j; + float rad; + + rad = light->intensity * 0.35; + + struct { + vec3_t verts; + float color[3]; + } lightVerts[18]; + + for (i = 0; i < 3; i++) + lightVerts[0].verts[i] = light->origin[i] - vpn[i] * rad; + + lightVerts[0].color[0] = light->color[0] * 0.2; + lightVerts[0].color[1] = light->color[1] * 0.2; + lightVerts[0].color[2] = light->color[2] * 0.2; + + for (i = 16; i >= 0; i--) + { + float a; + + a = i / 16.0 * M_PI * 2; + for (j = 0; j < 3; j++) + { + lightVerts[i+1].verts[j] = light->origin[j] + vright[j] * cos(a)*rad + + vup[j] * sin(a)*rad; + lightVerts[i+1].color[j] = 0.f; + } + } + + QVk_BindPipeline(&vk_drawDLightPipeline); + + VkBuffer vbo; + VkDeviceSize vboOffset; + uint32_t uboOffset; + VkDescriptorSet uboDescriptorSet; + uint8_t *vertData = QVk_GetVertexBuffer(sizeof(lightVerts), &vbo, &vboOffset); + uint8_t *uboData = QVk_GetUniformBuffer(sizeof(r_viewproj_matrix), &uboOffset, &uboDescriptorSet); + memcpy(vertData, lightVerts, sizeof(lightVerts)); + memcpy(uboData, r_viewproj_matrix, sizeof(r_viewproj_matrix)); + + vkCmdBindVertexBuffers(vk_activeCmdbuffer, 0, 1, &vbo, &vboOffset); + vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vk_drawDLightPipeline.layout, 0, 1, &uboDescriptorSet, 1, &uboOffset); + vkCmdBindIndexBuffer(vk_activeCmdbuffer, QVk_GetTriangleFanIbo(48), 0, VK_INDEX_TYPE_UINT16); + vkCmdDrawIndexed(vk_activeCmdbuffer, 48, 1, 0, 0, 0); +} + +/* +============= +R_RenderDlights +============= +*/ +void R_RenderDlights (void) +{ + int i; + dlight_t *l; + + if (!vk_flashblend->value) + return; + + r_dlightframecount = r_framecount + 1; // because the count hasn't + // advanced yet for this frame + l = r_newrefdef.dlights; + for (i=0 ; icontents != -1) + return; + + splitplane = node->plane; + dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist; + + if (dist > light->intensity-DLIGHT_CUTOFF) + { + R_MarkLights (light, bit, node->children[0]); + return; + } + if (dist < -light->intensity+DLIGHT_CUTOFF) + { + R_MarkLights (light, bit, node->children[1]); + return; + } + + // mark the polygons + surf = r_worldmodel->surfaces + node->firstsurface; + for (i=0 ; inumsurfaces ; i++, surf++) + { + if (surf->dlightframe != r_dlightframecount) + { + surf->dlightbits = 0; + surf->dlightframe = r_dlightframecount; + } + surf->dlightbits |= bit; + } + + R_MarkLights (light, bit, node->children[0]); + R_MarkLights (light, bit, node->children[1]); +} + + +/* +============= +R_PushDlights +============= +*/ +void R_PushDlights (void) +{ + int i; + dlight_t *l; + + if (vk_flashblend->value) + return; + + r_dlightframecount = r_framecount + 1; // because the count hasn't + // advanced yet for this frame + l = r_newrefdef.dlights; + for (i=0 ; inodes ); +} + + +/* +============================================================================= + +LIGHT SAMPLING + +============================================================================= +*/ + +vec3_t pointcolor; +cplane_t *lightplane; // used as shadow plane +vec3_t lightspot; + +static int RecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end) +{ + float front, back, frac; + int side; + cplane_t *plane; + vec3_t mid; + msurface_t *surf; + int s, t, ds, dt; + int i; + mtexinfo_t *tex; + byte *lightmap; + int maps; + int r; + + if (node->contents != -1) + return -1; // didn't hit anything + +// calculate mid point + +// FIXME: optimize for axial + plane = node->plane; + front = DotProduct (start, plane->normal) - plane->dist; + back = DotProduct (end, plane->normal) - plane->dist; + side = front < 0; + + if ( (back < 0) == side) + return RecursiveLightPoint (node->children[side], start, end); + + frac = front / (front-back); + mid[0] = start[0] + (end[0] - start[0])*frac; + mid[1] = start[1] + (end[1] - start[1])*frac; + mid[2] = start[2] + (end[2] - start[2])*frac; + + // go down front side + r = RecursiveLightPoint (node->children[side], start, mid); + if (r >= 0) + return r; // hit something + + // check for impact on this node + VectorCopy (mid, lightspot); + lightplane = plane; + + surf = r_worldmodel->surfaces + node->firstsurface; + for (i=0 ; inumsurfaces ; i++, surf++) + { + vec3_t scale; + + if (surf->flags&(SURF_DRAWTURB|SURF_DRAWSKY)) + continue; // no lightmaps + + tex = surf->texinfo; + + s = DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3]; + t = DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3];; + + if (s < surf->texturemins[0] || + t < surf->texturemins[1]) + continue; + + ds = s - surf->texturemins[0]; + dt = t - surf->texturemins[1]; + + if ( ds > surf->extents[0] || dt > surf->extents[1] ) + continue; + + if (!surf->samples) + return 0; + + ds >>= 4; + dt >>= 4; + + lightmap = surf->samples; + VectorCopy (vec3_origin, pointcolor); + + lightmap += 3*(dt * ((surf->extents[0]>>4)+1) + ds); + + for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + maps++) + { + for (int j=0 ; j<3 ; j++) + scale[j] = r_modulate->value*r_newrefdef.lightstyles[surf->styles[maps]].rgb[j]; + + pointcolor[0] += lightmap[0] * scale[0] * (1.0/255); + pointcolor[1] += lightmap[1] * scale[1] * (1.0/255); + pointcolor[2] += lightmap[2] * scale[2] * (1.0/255); + lightmap += 3*((surf->extents[0]>>4)+1) * + ((surf->extents[1]>>4)+1); + } + + return 1; + } + +// go down back side + return RecursiveLightPoint (node->children[!side], mid, end); +} + +/* +=============== +R_LightPoint +=============== +*/ +void R_LightPoint (vec3_t p, vec3_t color, entity_t *currententity) +{ + vec3_t end; + float r; + int lnum; + dlight_t *dl; + vec3_t dist; + + if (!r_worldmodel->lightdata || !currententity) + { + color[0] = color[1] = color[2] = 1.0; + return; + } + + end[0] = p[0]; + end[1] = p[1]; + end[2] = p[2] - 2048; + + r = RecursiveLightPoint (r_worldmodel->nodes, p, end); + + if (r == -1) + { + VectorCopy (vec3_origin, color); + } + else + { + VectorCopy (pointcolor, color); + } + + // + // add dynamic lights + // + dl = r_newrefdef.dlights; + for (lnum=0 ; lnumorigin, + dl->origin, + dist); + add = dl->intensity - VectorLength(dist); + add *= (1.0/256); + if (add > 0) + { + VectorMA (color, add, dl->color, color); + } + } + + VectorScale (color, r_modulate->value, color); +} + + +//=================================================================== + +static float s_blocklights[34*34*3]; +/* +=============== +R_AddDynamicLights +=============== +*/ +static void R_AddDynamicLights (msurface_t *surf) +{ + int lnum; + int sd, td; + float fdist, frad, fminlight; + vec3_t impact, local; + int s, t; + int i; + int smax, tmax; + mtexinfo_t *tex; + dlight_t *dl; + float *pfBL; + float fsacc, ftacc; + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + tex = surf->texinfo; + + for (lnum=0 ; lnumdlightbits & (1<intensity; + fdist = DotProduct (dl->origin, surf->plane->normal) - + surf->plane->dist; + frad -= fabs(fdist); + // rad is now the highest intensity on the plane + + fminlight = DLIGHT_CUTOFF; // FIXME: make configurable? + if (frad < fminlight) + continue; + fminlight = frad - fminlight; + + for (i=0 ; i<3 ; i++) + { + impact[i] = dl->origin[i] - + surf->plane->normal[i]*fdist; + } + + local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3] - surf->texturemins[0]; + local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3] - surf->texturemins[1]; + + pfBL = s_blocklights; + for (t = 0, ftacc = 0 ; t td) + fdist = sd + (td>>1); + else + fdist = td + (sd>>1); + + if ( fdist < fminlight ) + { + pfBL[0] += ( frad - fdist ) * dl->color[0]; + pfBL[1] += ( frad - fdist ) * dl->color[1]; + pfBL[2] += ( frad - fdist ) * dl->color[2]; + } + } + } + } +} + + +/* +** R_SetCacheState +*/ +void R_SetCacheState( msurface_t *surf ) +{ + int maps; + + for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + maps++) + { + surf->cached_light[maps] = r_newrefdef.lightstyles[surf->styles[maps]].white; + } +} + +/* +=============== +R_BuildLightMap + +Combine and scale multiple lightmaps into the floating format in blocklights +=============== +*/ +void R_BuildLightMap (msurface_t *surf, byte *dest, int stride) +{ + int smax, tmax; + int r, g, b, a, max; + int i, j, size; + byte *lightmap; + float scale[4]; + int nummaps; + float *bl; + + if ( surf->texinfo->flags & (SURF_SKY|SURF_TRANS33|SURF_TRANS66|SURF_WARP) ) + ri.Sys_Error (ERR_DROP, "R_BuildLightMap called for non-lit surface"); + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + size = smax*tmax; + if (size > (sizeof(s_blocklights)>>4) ) + ri.Sys_Error (ERR_DROP, "Bad s_blocklights size"); + + // set to full bright if no light data + if (!surf->samples) + { + for (i=0 ; istyles[nummaps] != 255 ; + nummaps++) + ; + + lightmap = surf->samples; + + // add all the lightmaps + if ( nummaps == 1 ) + { + int maps; + + for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + maps++) + { + bl = s_blocklights; + + for (i=0 ; i<3 ; i++) + scale[i] = r_modulate->value*r_newrefdef.lightstyles[surf->styles[maps]].rgb[i]; + + if ( scale[0] == 1.0F && + scale[1] == 1.0F && + scale[2] == 1.0F ) + { + for (i=0 ; istyles[maps] != 255 ; + maps++) + { + bl = s_blocklights; + + for (i=0 ; i<3 ; i++) + scale[i] = r_modulate->value*r_newrefdef.lightstyles[surf->styles[maps]].rgb[i]; + + if ( scale[0] == 1.0F && + scale[1] == 1.0F && + scale[2] == 1.0F ) + { + for (i=0 ; idlightframe == r_framecount) + R_AddDynamicLights (surf); + +store: + // put into texture format + stride -= (smax<<2); + bl = s_blocklights; + + for (i = 0; i < tmax; i++, dest += stride) + { + for (j = 0; j < smax; j++) + { + + r = Q_ftol(bl[0]); + g = Q_ftol(bl[1]); + b = Q_ftol(bl[2]); + + // catch negative lights + if (r < 0) + r = 0; + if (g < 0) + g = 0; + if (b < 0) + b = 0; + + /* + ** determine the brightest of the three color components + */ + if (r > g) + max = r; + else + max = g; + if (b > max) + max = b; + + /* + ** alpha is ONLY used for the mono lightmap case. For this reason + ** we set it to the brightest of the color components so that + ** things don't get too dim. + */ + a = max; + + /* + ** rescale all the color components if the intensity of the greatest + ** channel exceeds 1.0 + */ + if (max > 255) + { + float t = 255.0F / max; + + r = r * t; + g = g * t; + b = b * t; + a = a * t; + } + + dest[0] = r; + dest[1] = g; + dest[2] = b; + dest[3] = a; + + bl += 3; + dest += 4; + } + } +} + diff --git a/src/vk/vk_mesh.c b/src/vk/vk_mesh.c new file mode 100644 index 0000000..d390db2 --- /dev/null +++ b/src/vk/vk_mesh.c @@ -0,0 +1,999 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. +Copyright (C) 2018-2019 Krzysztof Kondrak + +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. + +*/ +// vk_mesh.c: triangle model functions + +#include "header/local.h" + +/* +============================================================= + + ALIAS MODELS + +============================================================= +*/ + +#define NUMVERTEXNORMALS 162 + +static float r_avertexnormals[NUMVERTEXNORMALS][3] = { +#include "../constants/anorms.h" +}; + +typedef float vec4_t[4]; + +enum { + TRIANGLE_STRIP = 0, + TRIANGLE_FAN = 1 +} pipelineIdx; + +typedef struct { + vec3_t vertex; + float color[4]; + float texCoord[2]; +} modelvert; + +typedef struct { + int vertexCount; + int firstVertex; +} drawinfo_t; + +polyvert_t *verts_buffer = NULL; +lmappolyvert_t *lmappolyverts_buffer = NULL; +static drawinfo_t *drawInfo[2] = {NULL, NULL}; +static modelvert *vertList[2] = {NULL, NULL}; +static vec4_t *s_lerped = NULL; +static vec3_t *shadowverts = NULL; +static int verts_count = 0; + +vec3_t shadevector; +float shadelight[3]; + +// precalculated dot products for quantized angles +#define SHADEDOT_QUANT 16 +static float r_avertexnormal_dots[SHADEDOT_QUANT][256] = { +#include "../constants/anormtab.h" +}; + +float *shadedots = r_avertexnormal_dots[0]; + +extern float r_view_matrix[16]; +extern float r_projection_matrix[16]; +extern float r_viewproj_matrix[16]; + +// correction matrix with "hacked depth" for models with RF_DEPTHHACK flag set +static float r_vulkan_correction_dh[16] = { + 1.f, 0.f, 0.f, 0.f, + 0.f, -1.f, 0.f, 0.f, + 0.f, 0.f, .3f, 0.f, + 0.f, 0.f, .3f, 1.f +}; + +int +Mesh_VertsRealloc(int count) +{ + void *ptr; + + if (verts_count > count) + { + return 0; + } + + verts_count = ROUNDUP(count * 2, 256); + + ptr = realloc(s_lerped, verts_count * sizeof(vec4_t)); + if (!ptr) + { + return -1; + } + s_lerped = ptr; + + ptr = realloc(shadowverts, verts_count * sizeof(vec3_t)); + if (!ptr) + { + return -1; + } + shadowverts = ptr; + + ptr = realloc(verts_buffer, verts_count * sizeof(polyvert_t)); + if (!ptr) + { + return -1; + } + verts_buffer = ptr; + + ptr = realloc(lmappolyverts_buffer, verts_count * sizeof(polyvert_t)); + if (!ptr) + { + return -1; + } + lmappolyverts_buffer = ptr; + + ptr = realloc(vertList[0], verts_count * sizeof(modelvert)); + if (!ptr) + { + return -1; + } + vertList[0] = ptr; + + ptr = realloc(vertList[1], verts_count * sizeof(modelvert)); + if (!ptr) + { + return -1; + } + vertList[1] = ptr; + + ptr = realloc(drawInfo[0], verts_count * sizeof(drawinfo_t)); + if (!ptr) + { + return -1; + } + drawInfo[0] = ptr; + + ptr = realloc(drawInfo[1], verts_count * sizeof(drawinfo_t)); + if (!ptr) + { + return -1; + } + drawInfo[1] = ptr; + + return 0; +} + +/* +=============== +Mesh_Init +=============== +*/ +void Mesh_Init (void) +{ + s_lerped = NULL; + shadowverts = NULL; + verts_buffer = NULL; + lmappolyverts_buffer = NULL; + vertList[0] = NULL; + vertList[1] = NULL; + drawInfo[0] = NULL; + drawInfo[1] = NULL; + + verts_count = 0; + + if (Mesh_VertsRealloc(MAX_VERTS)) + { + ri.Sys_Error(ERR_FATAL, "%s: can't allocate memory", __func__); + } +} + +/* +================ +Mesh_Free +================ +*/ +void Mesh_Free (void) +{ + if (vk_validation->value > 1) + { + R_Printf(PRINT_ALL, "%s: Deallocated %d mesh verts\n", + __func__, verts_count); + } + verts_count = 0; + + if (shadowverts) + { + free(shadowverts); + } + shadowverts = NULL; + + if (s_lerped) + { + free(s_lerped); + } + s_lerped = NULL; + + if (verts_buffer) + { + free(verts_buffer); + } + verts_buffer = NULL; + + if (lmappolyverts_buffer) + { + free(lmappolyverts_buffer); + } + lmappolyverts_buffer = NULL; + + if (vertList[0]) + { + free(vertList[0]); + } + if (vertList[1]) + { + free(vertList[1]); + } + vertList[0] = NULL; + vertList[1] = NULL; + + if (drawInfo[0]) + { + free(drawInfo[0]); + } + if (drawInfo[1]) + { + free(drawInfo[1]); + } + drawInfo[0] = NULL; + drawInfo[1] = NULL; +} + + +static void Vk_LerpVerts( int nverts, dtrivertx_t *v, dtrivertx_t *ov, dtrivertx_t *verts, float *lerp, float move[3], float frontv[3], float backv[3], entity_t *currententity ) +{ + int i; + + //PMM -- added RF_SHELL_DOUBLE, RF_SHELL_HALF_DAM + if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) + { + for (i=0 ; i < nverts; i++, v++, ov++, lerp+=4 ) + { + float *normal = r_avertexnormals[verts[i].lightnormalindex]; + + lerp[0] = move[0] + ov->v[0]*backv[0] + v->v[0]*frontv[0] + normal[0] * POWERSUIT_SCALE; + lerp[1] = move[1] + ov->v[1]*backv[1] + v->v[1]*frontv[1] + normal[1] * POWERSUIT_SCALE; + lerp[2] = move[2] + ov->v[2]*backv[2] + v->v[2]*frontv[2] + normal[2] * POWERSUIT_SCALE; + } + } + else + { + for (i=0 ; i < nverts; i++, v++, ov++, lerp+=4) + { + lerp[0] = move[0] + ov->v[0]*backv[0] + v->v[0]*frontv[0]; + lerp[1] = move[1] + ov->v[1]*backv[1] + v->v[1]*frontv[1]; + lerp[2] = move[2] + ov->v[2]*backv[2] + v->v[2]*frontv[2]; + } + } + +} + +/* +============= +Vk_DrawAliasFrameLerp + +interpolates between two frames and origins +FIXME: batch lerp all vertexes +============= +*/ +static void Vk_DrawAliasFrameLerp (dmdl_t *paliashdr, float backlerp, image_t *skin, float *modelMatrix, int leftHandOffset, int translucentIdx, entity_t *currententity) +{ + daliasframe_t *frame, *oldframe; + dtrivertx_t *v, *ov, *verts; + int *order; + float frontlerp; + float alpha; + vec3_t move, delta, vectors[3]; + vec3_t frontv, backv; + int i; + float *lerp; + + frame = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames + + currententity->frame * paliashdr->framesize); + verts = v = frame->verts; + + oldframe = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames + + currententity->oldframe * paliashdr->framesize); + ov = oldframe->verts; + + order = (int *)((byte *)paliashdr + paliashdr->ofs_glcmds); + + if (currententity->flags & RF_TRANSLUCENT) + alpha = currententity->alpha; + else + alpha = 1.0; + + frontlerp = 1.0 - backlerp; + + // move should be the delta back to the previous frame * backlerp + VectorSubtract (currententity->oldorigin, currententity->origin, delta); + AngleVectors (currententity->angles, vectors[0], vectors[1], vectors[2]); + + move[0] = DotProduct (delta, vectors[0]); // forward + move[1] = -DotProduct (delta, vectors[1]); // left + move[2] = DotProduct (delta, vectors[2]); // up + + VectorAdd (move, oldframe->translate, move); + + for (i=0 ; i<3 ; i++) + { + move[i] = backlerp*move[i] + frontlerp*frame->translate[i]; + } + + for (i=0 ; i<3 ; i++) + { + frontv[i] = frontlerp*frame->scale[i]; + backv[i] = backlerp*oldframe->scale[i]; + } + + if (Mesh_VertsRealloc(paliashdr->num_xyz)) + { + ri.Sys_Error(ERR_FATAL, "%s: can't allocate memory", __func__); + } + + lerp = s_lerped[0]; + + Vk_LerpVerts( paliashdr->num_xyz, v, ov, verts, lerp, move, frontv, backv, currententity ); + + int vertCounts[2] = { 0, 0 }; + int pipeCounters[2] = { 0, 0 }; + VkDeviceSize maxTriangleFanIdxCnt = 0; + + if (Mesh_VertsRealloc(1)) + { + ri.Sys_Error(ERR_FATAL, "%s: can't allocate memory", __func__); + } + + drawInfo[0][0].firstVertex = 0; + drawInfo[1][0].firstVertex = 0; + + struct { + float model[16]; + int textured; + } meshUbo; + + while (1) + { + int count; + + // get the vertex count and primitive type + count = *order++; + if (!count) + break; // done + if (count < 0) + { + count = -count; + pipelineIdx = TRIANGLE_FAN; + } + else + { + pipelineIdx = TRIANGLE_STRIP; + } + + if (Mesh_VertsRealloc(pipeCounters[pipelineIdx])) + { + ri.Sys_Error(ERR_FATAL, "%s: can't allocate memory", __func__); + } + + drawInfo[pipelineIdx][pipeCounters[pipelineIdx]].vertexCount = count; + maxTriangleFanIdxCnt = max(maxTriangleFanIdxCnt, ((count - 2) * 3)); + + if (currententity->flags & (RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE)) + { + meshUbo.textured = 0; + do + { + int vertIdx = vertCounts[pipelineIdx]; + int index_xyz = order[2]; + + if (Mesh_VertsRealloc(vertIdx)) + { + ri.Sys_Error(ERR_FATAL, "%s: can't allocate memory", __func__); + } + + // unused in this case, since texturing is disabled + vertList[pipelineIdx][vertIdx].texCoord[0] = 0.f; + vertList[pipelineIdx][vertIdx].texCoord[1] = 0.f; + + vertList[pipelineIdx][vertIdx].color[0] = shadelight[0]; + vertList[pipelineIdx][vertIdx].color[1] = shadelight[1]; + vertList[pipelineIdx][vertIdx].color[2] = shadelight[2]; + vertList[pipelineIdx][vertIdx].color[3] = alpha; + + if (verts_count < index_xyz) + { + R_Printf(PRINT_ALL, "%s: Model has issues with lerped index\n", __func__); + return; + } + + vertList[pipelineIdx][vertIdx].vertex[0] = s_lerped[index_xyz][0]; + vertList[pipelineIdx][vertIdx].vertex[1] = s_lerped[index_xyz][1]; + vertList[pipelineIdx][vertIdx].vertex[2] = s_lerped[index_xyz][2]; + vertCounts[pipelineIdx]++; + order += 3; + } while (--count); + } + else + { + meshUbo.textured = 1; + do + { + int vertIdx = vertCounts[pipelineIdx]; + int index_xyz = order[2]; + float l; + + if (Mesh_VertsRealloc(vertIdx)) + { + ri.Sys_Error(ERR_FATAL, "%s: can't allocate memory", __func__); + } + + // texture coordinates come from the draw list + vertList[pipelineIdx][vertIdx].texCoord[0] = ((float *)order)[0]; + vertList[pipelineIdx][vertIdx].texCoord[1] = ((float *)order)[1]; + + // normals and vertexes come from the frame list + l = shadedots[verts[index_xyz].lightnormalindex]; + + vertList[pipelineIdx][vertIdx].color[0] = l * shadelight[0]; + vertList[pipelineIdx][vertIdx].color[1] = l * shadelight[1]; + vertList[pipelineIdx][vertIdx].color[2] = l * shadelight[2]; + vertList[pipelineIdx][vertIdx].color[3] = alpha; + + if (verts_count < index_xyz) + { + R_Printf(PRINT_ALL, "%s: Model has issues with lerped index\n", __func__); + return; + } + + vertList[pipelineIdx][vertIdx].vertex[0] = s_lerped[index_xyz][0]; + vertList[pipelineIdx][vertIdx].vertex[1] = s_lerped[index_xyz][1]; + vertList[pipelineIdx][vertIdx].vertex[2] = s_lerped[index_xyz][2]; + vertCounts[pipelineIdx]++; + order += 3; + } while (--count); + } + + if (Mesh_VertsRealloc(pipeCounters[pipelineIdx] + 1)) + { + ri.Sys_Error(ERR_FATAL, "%s: can't allocate memory", __func__); + } + + pipeCounters[pipelineIdx]++; + drawInfo[pipelineIdx][pipeCounters[pipelineIdx]].firstVertex = vertCounts[pipelineIdx]; + } + + uint32_t uboOffset; + VkDescriptorSet uboDescriptorSet; + uint8_t *uboData = QVk_GetUniformBuffer(sizeof(meshUbo), &uboOffset, &uboDescriptorSet); + memcpy(meshUbo.model, modelMatrix, sizeof(float) * 16); + memcpy(uboData, &meshUbo, sizeof(meshUbo)); + + // player configuration screen model is using the UI renderpass + int pidx = (r_newrefdef.rdflags & RDF_NOWORLDMODEL) ? RP_UI : RP_WORLD; + // non-depth write alias models don't occur with RF_WEAPONMODEL set, so no need for additional left-handed pipelines + qvkpipeline_t pipelines[2][2] = { + { vk_drawModelPipelineFan[pidx], vk_drawLefthandModelPipelineFan }, + { vk_drawNoDepthModelPipelineFan, vk_drawLefthandModelPipelineFan } }; + for (int p = 0; p < 2; p++) + { + VkDeviceSize vaoSize = sizeof(modelvert) * vertCounts[p]; + VkBuffer vbo; + VkDeviceSize vboOffset; + uint8_t *vertData = QVk_GetVertexBuffer(vaoSize, &vbo, &vboOffset); + memcpy(vertData, vertList[p], vaoSize); + + QVk_BindPipeline(&pipelines[translucentIdx][leftHandOffset]); + VkDescriptorSet descriptorSets[] = { skin->vk_texture.descriptorSet, uboDescriptorSet }; + vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[translucentIdx][leftHandOffset].layout, 0, 2, descriptorSets, 1, &uboOffset); + vkCmdBindVertexBuffers(vk_activeCmdbuffer, 0, 1, &vbo, &vboOffset); + + if (p == TRIANGLE_STRIP) + { + vkCmdBindIndexBuffer(vk_activeCmdbuffer, QVk_GetTriangleStripIbo(maxTriangleFanIdxCnt), 0, VK_INDEX_TYPE_UINT16); + + for (i = 0; i < pipeCounters[p]; i++) + { + vkCmdDrawIndexed(vk_activeCmdbuffer, (drawInfo[p][i].vertexCount - 2) * 3, 1, 0, drawInfo[p][i].firstVertex, 0); + } + } + else + { + vkCmdBindIndexBuffer(vk_activeCmdbuffer, QVk_GetTriangleFanIbo(maxTriangleFanIdxCnt), 0, VK_INDEX_TYPE_UINT16); + + for (i = 0; i < pipeCounters[p]; i++) + { + vkCmdDrawIndexed(vk_activeCmdbuffer, (drawInfo[p][i].vertexCount - 2) * 3, 1, 0, drawInfo[p][i].firstVertex, 0); + } + } + } +} + + +/* +============= +Vk_DrawAliasShadow +============= +*/ +extern vec3_t lightspot; + +static void Vk_DrawAliasShadow (dmdl_t *paliashdr, int posenum, float *modelMatrix, entity_t *currententity) +{ + int *order; + vec3_t point; + float height, lheight; + + lheight = currententity->origin[2] - lightspot[2]; + + height = 0; + + order = (int *)((byte *)paliashdr + paliashdr->ofs_glcmds); + + height = -lheight + 1.0; + + uint32_t uboOffset; + VkDescriptorSet uboDescriptorSet; + uint8_t *uboData = QVk_GetUniformBuffer(sizeof(float) * 16, &uboOffset, &uboDescriptorSet); + memcpy(uboData, modelMatrix, sizeof(float) * 16); + + while (1) + { + int i; + int count; + + i = 0; + // get the vertex count and primitive type + count = *order++; + if (!count) + break; // done + if (count < 0) + { + count = -count; + pipelineIdx = TRIANGLE_FAN; + } + else + { + pipelineIdx = TRIANGLE_STRIP; + } + + if (Mesh_VertsRealloc(count)) + { + ri.Sys_Error(ERR_FATAL, "%s: can't allocate memory", __func__); + } + + do + { + if (Mesh_VertsRealloc(order[2])) + { + ri.Sys_Error(ERR_FATAL, "%s: can't allocate memory", __func__); + } + + // normals and vertexes come from the frame list + memcpy( point, s_lerped[order[2]], sizeof( point ) ); + + point[0] -= shadevector[0]*(point[2]+lheight); + point[1] -= shadevector[1]*(point[2]+lheight); + point[2] = height; + + shadowverts[i][0] = point[0]; + shadowverts[i][1] = point[1]; + shadowverts[i][2] = point[2]; + + order += 3; + i++; + } while (--count); + + if (i > 0) + { + VkDeviceSize vaoSize = sizeof(vec3_t) * i; + VkBuffer vbo; + VkDeviceSize vboOffset; + uint8_t *vertData = QVk_GetVertexBuffer(vaoSize, &vbo, &vboOffset); + memcpy(vertData, shadowverts, vaoSize); + + QVk_BindPipeline(&vk_shadowsPipelineFan); + vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vk_shadowsPipelineFan.layout, 0, 1, &uboDescriptorSet, 1, &uboOffset); + vkCmdBindVertexBuffers(vk_activeCmdbuffer, 0, 1, &vbo, &vboOffset); + + if (pipelineIdx == TRIANGLE_STRIP) + { + vkCmdBindIndexBuffer(vk_activeCmdbuffer, QVk_GetTriangleStripIbo((i - 2) * 3), 0, VK_INDEX_TYPE_UINT16); + vkCmdDrawIndexed(vk_activeCmdbuffer, (i - 2) * 3, 1, 0, 0, 0); + } + else + { + vkCmdBindIndexBuffer(vk_activeCmdbuffer, QVk_GetTriangleFanIbo((i - 2) * 3), 0, VK_INDEX_TYPE_UINT16); + vkCmdDrawIndexed(vk_activeCmdbuffer, (i - 2) * 3, 1, 0, 0, 0); + } + } + } +} + + +/* +** R_CullAliasModel +*/ +static qboolean R_CullAliasModel( vec3_t bbox[8], entity_t *e, model_t *currentmodel ) +{ + int i; + vec3_t mins, maxs; + dmdl_t *paliashdr; + vec3_t vectors[3]; + vec3_t thismins, oldmins, thismaxs, oldmaxs; + daliasframe_t *pframe, *poldframe; + vec3_t angles; + + paliashdr = (dmdl_t *)currentmodel->extradata; + + if ( ( e->frame >= paliashdr->num_frames ) || ( e->frame < 0 ) ) + { + R_Printf(PRINT_ALL, "%s %s: no such frame %d\n", + __func__, currentmodel->name, e->frame); + e->frame = 0; + } + if ( ( e->oldframe >= paliashdr->num_frames ) || ( e->oldframe < 0 ) ) + { + R_Printf(PRINT_ALL, "%s %s: no such oldframe %d\n", + __func__, currentmodel->name, e->oldframe); + e->oldframe = 0; + } + + pframe = ( daliasframe_t * ) ( ( byte * ) paliashdr + + paliashdr->ofs_frames + + e->frame * paliashdr->framesize); + + poldframe = ( daliasframe_t * ) ( ( byte * ) paliashdr + + paliashdr->ofs_frames + + e->oldframe * paliashdr->framesize); + + /* + ** compute axially aligned mins and maxs + */ + if ( pframe == poldframe ) + { + for ( i = 0; i < 3; i++ ) + { + mins[i] = pframe->translate[i]; + maxs[i] = mins[i] + pframe->scale[i]*255; + } + } + else + { + for ( i = 0; i < 3; i++ ) + { + thismins[i] = pframe->translate[i]; + thismaxs[i] = thismins[i] + pframe->scale[i]*255; + + oldmins[i] = poldframe->translate[i]; + oldmaxs[i] = oldmins[i] + poldframe->scale[i]*255; + + if ( thismins[i] < oldmins[i] ) + mins[i] = thismins[i]; + else + mins[i] = oldmins[i]; + + if ( thismaxs[i] > oldmaxs[i] ) + maxs[i] = thismaxs[i]; + else + maxs[i] = oldmaxs[i]; + } + } + + /* + ** compute a full bounding box + */ + for ( i = 0; i < 8; i++ ) + { + vec3_t tmp; + + if ( i & 1 ) + tmp[0] = mins[0]; + else + tmp[0] = maxs[0]; + + if ( i & 2 ) + tmp[1] = mins[1]; + else + tmp[1] = maxs[1]; + + if ( i & 4 ) + tmp[2] = mins[2]; + else + tmp[2] = maxs[2]; + + VectorCopy( tmp, bbox[i] ); + } + + /* + ** rotate the bounding box + */ + VectorCopy( e->angles, angles ); + angles[YAW] = -angles[YAW]; + AngleVectors( angles, vectors[0], vectors[1], vectors[2] ); + + for ( i = 0; i < 8; i++ ) + { + vec3_t tmp; + + VectorCopy( bbox[i], tmp ); + + bbox[i][0] = DotProduct( vectors[0], tmp ); + bbox[i][1] = -DotProduct( vectors[1], tmp ); + bbox[i][2] = DotProduct( vectors[2], tmp ); + + VectorAdd( e->origin, bbox[i], bbox[i] ); + } + + { + int p, f, aggregatemask = ~0; + + for ( p = 0; p < 8; p++ ) + { + int mask = 0; + + for ( f = 0; f < 4; f++ ) + { + float dp = DotProduct( frustum[f].normal, bbox[p] ); + + if ( ( dp - frustum[f].dist ) < 0 ) + { + mask |= ( 1 << f ); + } + } + + aggregatemask &= mask; + } + + if ( aggregatemask ) + { + return true; + } + + return false; + } +} + +/* +================= +R_DrawAliasModel + +================= +*/ +void R_DrawAliasModel (entity_t *currententity, model_t *currentmodel) +{ + int i; + int leftHandOffset = 0; + dmdl_t *paliashdr; + float an; + vec3_t bbox[8]; + float prev_viewproj[16]; + + if ( !( currententity->flags & RF_WEAPONMODEL ) ) + { + if ( R_CullAliasModel( bbox, currententity, currentmodel ) ) + return; + } + + if ( currententity->flags & RF_WEAPONMODEL ) + { + if ( r_lefthand->value == 2 ) + return; + } + + paliashdr = (dmdl_t *)currentmodel->extradata; + + // + // get lighting information + // + // PMM - rewrote, reordered to handle new shells & mixing + // PMM - 3.20 code .. replaced with original way of doing it to keep mod authors happy + // + if ( currententity->flags & ( RF_SHELL_HALF_DAM | RF_SHELL_GREEN | RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE ) ) + { + VectorClear (shadelight); + if (currententity->flags & RF_SHELL_HALF_DAM) + { + shadelight[0] = 0.56; + shadelight[1] = 0.59; + shadelight[2] = 0.45; + } + if ( currententity->flags & RF_SHELL_DOUBLE ) + { + shadelight[0] = 0.9; + shadelight[1] = 0.7; + } + if ( currententity->flags & RF_SHELL_RED ) + shadelight[0] = 1.0; + if ( currententity->flags & RF_SHELL_GREEN ) + shadelight[1] = 1.0; + if ( currententity->flags & RF_SHELL_BLUE ) + shadelight[2] = 1.0; + } + else if ( currententity->flags & RF_FULLBRIGHT ) + { + for (i=0 ; i<3 ; i++) + shadelight[i] = 1.0; + } + else + { + R_LightPoint (currententity->origin, shadelight, currententity); + + // player lighting hack for communication back to server + // big hack! + if ( currententity->flags & RF_WEAPONMODEL ) + { + // pick the greatest component, which should be the same + // as the mono value returned by software + if (shadelight[0] > shadelight[1]) + { + if (shadelight[0] > shadelight[2]) + r_lightlevel->value = 150*shadelight[0]; + else + r_lightlevel->value = 150*shadelight[2]; + } + else + { + if (shadelight[1] > shadelight[2]) + r_lightlevel->value = 150*shadelight[1]; + else + r_lightlevel->value = 150*shadelight[2]; + } + } + } + + if ( currententity->flags & RF_MINLIGHT ) + { + for (i=0 ; i<3 ; i++) + if (shadelight[i] > 0.1) + break; + if (i == 3) + { + shadelight[0] = 0.1; + shadelight[1] = 0.1; + shadelight[2] = 0.1; + } + } + + if ( currententity->flags & RF_GLOW ) + { // bonus items will pulse with time + float scale; + + scale = 0.1 * sin(r_newrefdef.time*7); + for (i=0 ; i<3 ; i++) + { + float min; + + min = shadelight[i] * 0.8; + shadelight[i] += scale; + if (shadelight[i] < min) + shadelight[i] = min; + } + } + + // ================= + // PGM ir goggles color override + if ( r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE) + { + shadelight[0] = 1.0; + shadelight[1] = 0.0; + shadelight[2] = 0.0; + } + // PGM + // ================= + + shadedots = r_avertexnormal_dots[((int)(currententity->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; + + an = currententity->angles[1]/180*M_PI; + shadevector[0] = cos(-an); + shadevector[1] = sin(-an); + shadevector[2] = 1; + VectorNormalize (shadevector); + + // + // locate the proper data + // + + c_alias_polys += paliashdr->num_tris; + + // + // draw all the triangles + // + if (currententity->flags & RF_DEPTHHACK || r_newrefdef.rdflags & RDF_NOWORLDMODEL) { // hack the depth range to prevent view model from poking into walls + float r_proj_aspect = (float)r_newrefdef.width / r_newrefdef.height; + float r_proj_fovy = r_newrefdef.fov_y; + float dist = (r_farsee->value == 0) ? 4096.0f : 8192.0f; + // use different range for player setup screen so it doesn't collide with the viewmodel + r_vulkan_correction_dh[10] = 0.3f - (r_newrefdef.rdflags & RDF_NOWORLDMODEL) * 0.1f; + r_vulkan_correction_dh[14] = 0.3f - (r_newrefdef.rdflags & RDF_NOWORLDMODEL) * 0.1f; + + memcpy(prev_viewproj, r_viewproj_matrix, sizeof(r_viewproj_matrix)); + if (currententity->flags & RF_WEAPONMODEL && r_gunfov->value < 0) + { + Mat_Perspective(r_projection_matrix, r_vulkan_correction_dh, r_proj_fovy, r_proj_aspect, 4, dist); + } + else + { + Mat_Perspective(r_projection_matrix, r_vulkan_correction_dh, r_gunfov->value, r_proj_aspect, 4, dist); + } + Mat_Mul(r_view_matrix, r_projection_matrix, r_viewproj_matrix); + vkCmdPushConstants(vk_activeCmdbuffer, vk_drawTexQuadPipeline[vk_state.current_renderpass].layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(r_viewproj_matrix), r_viewproj_matrix); + } + + if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) ) + { + Mat_Scale(r_viewproj_matrix, -1.f, 1.f, 1.f); + vkCmdPushConstants(vk_activeCmdbuffer, vk_drawTexQuadPipeline[vk_state.current_renderpass].layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(r_viewproj_matrix), r_viewproj_matrix); + leftHandOffset = 1; + } + + currententity->angles[PITCH] = -currententity->angles[PITCH]; // sigh. + { + float model[16]; + image_t *skin; + Mat_Identity(model); + R_RotateForEntity (currententity, model); + + currententity->angles[PITCH] = -currententity->angles[PITCH]; // sigh. + + // select skin + if (currententity->skin) + skin = currententity->skin; // custom player skin + else + { + if (currententity->skinnum >= MAX_MD2SKINS) + skin = currentmodel->skins[0]; + else + { + skin = currentmodel->skins[currententity->skinnum]; + if (!skin) + skin = currentmodel->skins[0]; + } + } + if (!skin) + skin = r_notexture; // fallback... + + // draw it + if ( (currententity->frame >= paliashdr->num_frames) + || (currententity->frame < 0) ) + { + R_Printf(PRINT_ALL, "%s %s: no such frame %d\n", + __func__, currentmodel->name, currententity->frame); + currententity->frame = 0; + currententity->oldframe = 0; + } + + if ( (currententity->oldframe >= paliashdr->num_frames) + || (currententity->oldframe < 0)) + { + R_Printf(PRINT_ALL, "%s %s: no such oldframe %d\n", + __func__, currentmodel->name, currententity->oldframe); + currententity->frame = 0; + currententity->oldframe = 0; + } + + if ( !r_lerpmodels->value ) + currententity->backlerp = 0; + Vk_DrawAliasFrameLerp (paliashdr, currententity->backlerp, skin, model, leftHandOffset, (currententity->flags & RF_TRANSLUCENT) ? 1 : 0, currententity); + } + + if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) ) + { + Mat_Scale(r_viewproj_matrix, -1.f, 1.f, 1.f); + vkCmdPushConstants(vk_activeCmdbuffer, vk_drawTexQuadPipeline[vk_state.current_renderpass].layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(r_viewproj_matrix), r_viewproj_matrix); + } + + if (currententity->flags & RF_DEPTHHACK || r_newrefdef.rdflags & RDF_NOWORLDMODEL) + { + memcpy(r_viewproj_matrix, prev_viewproj, sizeof(prev_viewproj)); + vkCmdPushConstants(vk_activeCmdbuffer, vk_drawTexQuadPipeline[vk_state.current_renderpass].layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(r_viewproj_matrix), r_viewproj_matrix); + } + + if (vk_shadows->value && !(currententity->flags & (RF_TRANSLUCENT | RF_WEAPONMODEL))) + { + float model[16]; + Mat_Identity(model); + R_RotateForEntity(currententity, model); + Vk_DrawAliasShadow (paliashdr, currententity->frame, model, currententity); + } +} diff --git a/src/vk/vk_model.c b/src/vk/vk_model.c new file mode 100644 index 0000000..01a6577 --- /dev/null +++ b/src/vk/vk_model.c @@ -0,0 +1,1525 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. +Copyright (C) 2018-2019 Krzysztof Kondrak + +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. + +*/ +// vk_model.c -- model loading and caching + +#include "header/local.h" + +YQ2_ALIGNAS_TYPE(int) static byte mod_novis[MAX_MAP_LEAFS/8]; + +#define MAX_MOD_KNOWN 512 +static model_t *models_known; +static int mod_numknown = 0; +static int mod_loaded = 0; +static int mod_max = 0; +static int models_known_max = 0; + +int registration_sequence; + +/* +=============== +Mod_PointInLeaf +=============== +*/ +mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model) +{ + mnode_t *node; + + if (!model || !model->nodes) + ri.Sys_Error (ERR_DROP, "%s: bad model", __func__); + + node = model->nodes; + while (1) + { + cplane_t *plane; + float d; + + if (node->contents != -1) + return (mleaf_t *)node; + plane = node->plane; + d = DotProduct (p,plane->normal) - plane->dist; + if (d > 0) + node = node->children[0]; + else + node = node->children[1]; + } + + return NULL; // never reached +} + + +/* +============== +Mod_ClusterPVS +============== +*/ +byte *Mod_ClusterPVS (int cluster, model_t *model) +{ + if (cluster == -1 || !model->vis) + return mod_novis; + + return Mod_DecompressVis ( (byte *)model->vis + + model->vis->bitofs[cluster][DVIS_PVS], + (model->vis->numclusters+7)>>3); +} + + +//=============================================================================== + +/* +=============== +Mod_Reallocate +=============== +*/ +void Mod_Reallocate (void) +{ + if ((models_known_max >= (mod_max * 4)) && (models_known != NULL)) + { + return; + } + + if (models_known) + { + // Always up if already allocated + models_known_max *= 2; + // free up + Mod_FreeAll(); + Mod_FreeModelsKnown(); + } + + if (models_known_max < (mod_max * 4)) + { + // double is not enough? + models_known_max = ROUNDUP(mod_max * 4, 16); + } + + R_Printf(PRINT_ALL, "Reallocate space for %d models.\n", models_known_max); + + models_known = malloc(models_known_max * sizeof(model_t)); + memset(models_known, 0, models_known_max * sizeof(model_t)); +} + +/* +=============== +Mod_Init +=============== +*/ +void Mod_Init (void) +{ + memset (mod_novis, 0xff, sizeof(mod_novis)); + mod_numknown = 0; + mod_loaded = 0; + mod_max = 0; + models_known_max = MAX_MOD_KNOWN; + models_known = NULL; + + Mod_Reallocate (); +} + +/* +================ +Mod_Free +================ +*/ +static void Mod_Free (model_t *mod) +{ + if (!mod->extradata) + { + // looks as empty model + memset (mod, 0, sizeof(*mod)); + return; + } + + if (vk_validation->value) + { + R_Printf(PRINT_ALL, "%s: Unload %s[%d]\n", __func__, mod->name, mod_loaded); + } + + Hunk_Free (mod->extradata); + memset (mod, 0, sizeof(*mod)); + mod_loaded --; + if (mod_loaded < 0) + { + ri.Sys_Error (ERR_DROP, "%s: Broken unload", __func__); + } +} + +/* +================ +Mod_FreeAll +================ +*/ +void Mod_FreeAll (void) +{ + int i; + + for (i=0 ; ifilelen) + { + loadmodel->lightdata = NULL; + return; + } + loadmodel->lightdata = Hunk_Alloc ( l->filelen); + memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen); +} + + +/* +================= +Mod_LoadVisibility +================= +*/ +static void Mod_LoadVisibility (model_t *loadmodel, byte *mod_base, lump_t *l) +{ + int i; + + if (!l->filelen) + { + loadmodel->vis = NULL; + return; + } + loadmodel->vis = Hunk_Alloc ( l->filelen); + memcpy (loadmodel->vis, mod_base + l->fileofs, l->filelen); + + loadmodel->vis->numclusters = LittleLong (loadmodel->vis->numclusters); + for (i=0 ; ivis->numclusters ; i++) + { + loadmodel->vis->bitofs[i][0] = LittleLong (loadmodel->vis->bitofs[i][0]); + loadmodel->vis->bitofs[i][1] = LittleLong (loadmodel->vis->bitofs[i][1]); + } +} + + +/* +================= +Mod_LoadVertexes +================= +*/ +static void Mod_LoadVertexes (model_t *loadmodel, byte *mod_base, lump_t *l) +{ + dvertex_t *in; + mvertex_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + { + ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", + __func__, loadmodel->name); + } + + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->vertexes = out; + loadmodel->numvertexes = count; + + for ( i=0 ; iposition[0] = LittleFloat (in->point[0]); + out->position[1] = LittleFloat (in->point[1]); + out->position[2] = LittleFloat (in->point[2]); + } +} + +/* +================= +RadiusFromBounds +================= +*/ +static float RadiusFromBounds (vec3_t mins, vec3_t maxs) +{ + int i; + vec3_t corner; + + for (i=0 ; i<3 ; i++) + { + corner[i] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]); + } + + return VectorLength (corner); +} + + +/* +================= +Mod_LoadSubmodels +================= +*/ +static void Mod_LoadSubmodels (model_t *loadmodel, byte *mod_base, lump_t *l) +{ + dmodel_t *in; + model_t *out; + int i, j, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + { + ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", + __func__, loadmodel->name); + } + + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->submodels = out; + loadmodel->numsubmodels = count; + + for ( i=0 ; isubmodels, sizeof(*out)); + } + + Com_sprintf (out->name, sizeof(out->name), "*%d", i); + + for (j=0 ; j<3 ; j++) + { // spread the mins / maxs by a pixel + out->mins[j] = LittleFloat (in->mins[j]) - 1; + out->maxs[j] = LittleFloat (in->maxs[j]) + 1; + out->origin[j] = LittleFloat (in->origin[j]); + } + + out->radius = RadiusFromBounds (out->mins, out->maxs); + out->firstnode = LittleLong (in->headnode); + out->firstmodelsurface = LittleLong (in->firstface); + out->nummodelsurfaces = LittleLong (in->numfaces); + // visleafs + out->numleafs = 0; + // check limits + if (out->firstnode >= loadmodel->numnodes) + { + ri.Sys_Error(ERR_DROP, "%s: Inline model %i has bad firstnode", + __func__, i); + } + } +} + +/* +================= +Mod_LoadEdges +================= +*/ +static void Mod_LoadEdges (model_t *loadmodel, byte *mod_base, lump_t *l) +{ + dedge_t *in; + medge_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + { + ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", + __func__, loadmodel->name); + } + + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( (count + 1) * sizeof(*out)); + + loadmodel->edges = out; + loadmodel->numedges = count; + + for ( i=0 ; iv[0] = (unsigned short)LittleShort(in->v[0]); + out->v[1] = (unsigned short)LittleShort(in->v[1]); + } +} + +/* +================= +Mod_LoadTexinfo +================= +*/ +static void Mod_LoadTexinfo (model_t *loadmodel, byte *mod_base, lump_t *l) +{ + texinfo_t *in; + mtexinfo_t *out, *step; + int i, j, count; + char name[MAX_QPATH]; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + { + ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", + __func__, loadmodel->name); + } + + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->texinfo = out; + loadmodel->numtexinfo = count; + + for ( i=0 ; ivecs[0][j] = LittleFloat (in->vecs[0][j]); + out->vecs[1][j] = LittleFloat (in->vecs[1][j]); + } + + out->flags = LittleLong (in->flags); + next = LittleLong (in->nexttexinfo); + if (next > 0) + out->next = loadmodel->texinfo + next; + else + out->next = NULL; + Com_sprintf (name, sizeof(name), "textures/%s.wal", in->texture); + + out->image = Vk_FindImage (name, it_wall); + if (!out->image || out->image == r_notexture) + { + Com_sprintf (name, sizeof(name), "textures/%s.m8", in->texture); + out->image = Vk_FindImage (name, it_wall); + } + + if (!out->image) + { + R_Printf(PRINT_ALL, "Couldn't load %s\n", name); + out->image = r_notexture; + } + } + + // count animation frames + for (i=0 ; itexinfo[i]; + out->numframes = 1; + for (step = out->next ; step && step != out ; step=step->next) + out->numframes++; + } +} + +/* +================ +CalcSurfaceExtents + +Fills in s->texturemins[] and s->extents[] +================ +*/ +static void CalcSurfaceExtents (model_t *loadmodel, msurface_t *s) +{ + float mins[2], maxs[2], val; + int i; + mtexinfo_t *tex; + int bmins[2], bmaxs[2]; + + mins[0] = mins[1] = 999999; + maxs[0] = maxs[1] = -99999; + + tex = s->texinfo; + + for (i=0 ; inumedges ; i++) + { + int e, j; + mvertex_t *v; + + e = loadmodel->surfedges[s->firstedge+i]; + if (e >= 0) + v = &loadmodel->vertexes[loadmodel->edges[e].v[0]]; + else + v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]]; + + for (j=0 ; j<2 ; j++) + { + val = v->position[0] * tex->vecs[j][0] + + v->position[1] * tex->vecs[j][1] + + v->position[2] * tex->vecs[j][2] + + tex->vecs[j][3]; + if (val < mins[j]) + mins[j] = val; + if (val > maxs[j]) + maxs[j] = val; + } + } + + for (i=0 ; i<2 ; i++) + { + bmins[i] = floor(mins[i]/16); + bmaxs[i] = ceil(maxs[i]/16); + + s->texturemins[i] = bmins[i] * 16; + s->extents[i] = (bmaxs[i] - bmins[i]) * 16; + } +} + +static int calcTexinfoAndFacesSize(const lump_t *fl, byte *mod_base, const lump_t *tl) +{ + dface_t* face_in = (void *)(mod_base + fl->fileofs); + texinfo_t* texinfo_in = (void *)(mod_base + tl->fileofs); + + if (fl->filelen % sizeof(*face_in) || tl->filelen % sizeof(*texinfo_in)) + { + // will error out when actually loading it + return 0; + } + + int ret = 0; + + int face_count = fl->filelen / sizeof(*face_in); + int texinfo_count = tl->filelen / sizeof(*texinfo_in); + + { + // out = Hunk_Alloc(count * sizeof(*out)); + int baseSize = face_count * sizeof(msurface_t); + baseSize = (baseSize + 31) & ~31; + ret += baseSize; + + int ti_size = texinfo_count * sizeof(mtexinfo_t); + ti_size = (ti_size + 31) & ~31; + ret += ti_size; + } + + int numWarpFaces = 0; + + for (int surfnum = 0; surfnum < face_count; surfnum++, face_in++) + { + int numverts = LittleShort(face_in->numedges); + int ti = LittleShort(face_in->texinfo); + if ((ti < 0) || (ti >= texinfo_count)) + { + return 0; // will error out + } + int texFlags = LittleLong(texinfo_in[ti].flags); + + /* set the drawing flags */ + if (texFlags & SURF_WARP) + { + if (numverts > 60) + return 0; // will error out in R_SubdividePolygon() + + // Vk_SubdivideSurface(out, loadmodel); /* cut up polygon for warps */ + // for each (pot. recursive) call to R_SubdividePolygon(): + // sizeof(vkpoly_t) + ((numverts - 4) + 2) * VERTEXSIZE*sizeof(float) + + // this is tricky, how much is allocated depends on the size of the surface + // which we don't know (we'd need the vertices etc to know, but we can't load + // those without allocating...) + // so we just count warped faces and use a generous estimate below + + ++numWarpFaces; + } + else + { + // Vk_BuildPolygonFromSurface(out); + // => poly = Hunk_Alloc(sizeof(vkpoly_t) + (numverts - 4) * VERTEXSIZE*sizeof(float)); + int polySize = sizeof(vkpoly_t) + (numverts - 4) * VERTEXSIZE*sizeof(float); + polySize = (polySize + 31) & ~31; + ret += polySize; + } + } + + // yeah, this is a bit hacky, but it looks like for each warped face + // 256-55000 bytes are allocated (usually on the lower end), + // so just assume 48k per face to be safe + ret += numWarpFaces * 49152; + ret += 1000000; // and 1MB extra just in case + + return ret; +} + +/* +================= +Mod_LoadFaces +================= +*/ +static void Mod_LoadFaces (model_t *loadmodel, byte *mod_base, lump_t *l) +{ + dface_t *in; + msurface_t *out; + int i, count, surfnum; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + { + ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", + __func__, loadmodel->name); + } + + count = l->filelen / sizeof(*in); + out = Hunk_Alloc(count * sizeof(*out)); + + loadmodel->surfaces = out; + loadmodel->numsurfaces = count; + + Vk_BeginBuildingLightmaps(loadmodel); + + for (surfnum = 0; surfnumfirstedge = LittleLong(in->firstedge); + out->numedges = LittleShort(in->numedges); + if (out->numedges < 3) + { + ri.Sys_Error(ERR_DROP, "%s: Surface with %d edges", + __func__, out->numedges); + } + out->flags = 0; + out->polys = NULL; + + planenum = LittleShort(in->planenum); + side = LittleShort(in->side); + if (side) + out->flags |= SURF_PLANEBACK; + + out->plane = loadmodel->planes + planenum; + + ti = LittleShort(in->texinfo); + if (ti < 0 || ti >= loadmodel->numtexinfo) + { + ri.Sys_Error(ERR_DROP, "%s: bad texinfo number", __func__); + } + out->texinfo = loadmodel->texinfo + ti; + + CalcSurfaceExtents(loadmodel, out); + + // lighting info + + for (i = 0; istyles[i] = in->styles[i]; + i = LittleLong(in->lightofs); + if (i == -1) + out->samples = NULL; + else + out->samples = loadmodel->lightdata + i; + + // set the drawing flags + + if (out->texinfo->flags & SURF_WARP) + { + out->flags |= SURF_DRAWTURB; + for (i = 0; i<2; i++) + { + out->extents[i] = 16384; + out->texturemins[i] = -8192; + } + Vk_SubdivideSurface(out, loadmodel); // cut up polygon for warps + } + + if (r_fixsurfsky->value) + { + if (out->texinfo->flags & SURF_SKY) + { + out->flags |= SURF_DRAWSKY; + } + } + + // create lightmaps and polygons + if (!(out->texinfo->flags & (SURF_SKY | SURF_TRANS33 | SURF_TRANS66 | SURF_WARP))) + Vk_CreateSurfaceLightmap(out); + + if (!(out->texinfo->flags & SURF_WARP)) + Vk_BuildPolygonFromSurface(out, loadmodel); + + } + + Vk_EndBuildingLightmaps(); +} + + +/* +================= +Mod_SetParent +================= +*/ +static void Mod_SetParent (mnode_t *node, mnode_t *parent) +{ + node->parent = parent; + if (node->contents != -1) + return; + Mod_SetParent (node->children[0], node); + Mod_SetParent (node->children[1], node); +} + +/* +================= +Mod_LoadNodes +================= +*/ +static void Mod_LoadNodes (model_t *loadmodel, byte *mod_base, lump_t *l) +{ + int i, j, count; + dnode_t *in; + mnode_t *out; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + { + ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", + __func__, loadmodel->name); + } + + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->nodes = out; + loadmodel->numnodes = count; + + for ( i=0 ; iminmaxs[j] = LittleShort (in->mins[j]); + out->minmaxs[3+j] = LittleShort (in->maxs[j]); + } + + p = LittleLong(in->planenum); + out->plane = loadmodel->planes + p; + + out->firstsurface = LittleShort (in->firstface); + out->numsurfaces = LittleShort (in->numfaces); + out->contents = -1; // differentiate from leafs + + for (j=0 ; j<2 ; j++) + { + p = LittleLong (in->children[j]); + if (p >= 0) + out->children[j] = loadmodel->nodes + p; + else + out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p)); + } + } + + Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs +} + +/* +================= +Mod_LoadLeafs +================= +*/ +static void Mod_LoadLeafs (model_t *loadmodel, byte *mod_base, lump_t *l) +{ + dleaf_t *in; + mleaf_t *out; + int i, j, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + { + ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", + __func__, loadmodel->name); + } + + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->leafs = out; + loadmodel->numleafs = count; + + for ( i=0 ; iminmaxs[j] = LittleShort (in->mins[j]); + out->minmaxs[3+j] = LittleShort (in->maxs[j]); + } + + out->contents = LittleLong(in->contents); + out->cluster = LittleShort(in->cluster); + out->area = LittleShort(in->area); + + // make unsigned long from signed short + firstleafface = LittleShort(in->firstleafface) & 0xFFFF; + out->nummarksurfaces = LittleShort(in->numleaffaces) & 0xFFFF; + + out->firstmarksurface = loadmodel->marksurfaces + firstleafface; + if ((firstleafface + out->nummarksurfaces) > loadmodel->nummarksurfaces) + { + ri.Sys_Error(ERR_DROP, "%s: wrong marksurfaces position in %s", + __func__, loadmodel->name); + } + + // gl underwater warp +#if 0 + if (out->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA|CONTENTS_THINWATER) ) + { + for (j=0 ; jnummarksurfaces ; j++) + { + out->firstmarksurface[j]->flags |= SURF_UNDERWATER; + for (poly = out->firstmarksurface[j]->polys ; poly ; poly=poly->next) + poly->flags |= SURF_UNDERWATER; + } + } +#endif + } +} + +/* +================= +Mod_LoadMarksurfaces +================= +*/ +static void Mod_LoadMarksurfaces (model_t *loadmodel, byte *mod_base, lump_t *l) +{ + int i, count; + short *in; + msurface_t **out; + + in = (void *)(mod_base + l->fileofs); + + if (l->filelen % sizeof(*in)) + { + ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", + __func__, loadmodel->name); + } + + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->marksurfaces = out; + loadmodel->nummarksurfaces = count; + + for ( i=0 ; i= loadmodel->numsurfaces) + { + ri.Sys_Error(ERR_DROP, "%s: bad surface number", __func__); + } + out[i] = loadmodel->surfaces + j; + } +} + +/* +================= +Mod_LoadSurfedges +================= +*/ +static void Mod_LoadSurfedges (model_t *loadmodel, byte *mod_base, lump_t *l) +{ + int i, count; + int *in, *out; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + { + ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", + __func__, loadmodel->name); + } + + count = l->filelen / sizeof(*in); + if (count < 1 || count >= MAX_MAP_SURFEDGES) + ri.Sys_Error (ERR_DROP, "%s: bad surfedges count in %s: %i", + __func__, loadmodel->name, count); + + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->surfedges = out; + loadmodel->numsurfedges = count; + + for ( i=0 ; ifileofs); + + if (l->filelen % sizeof(*in)) + { + ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", + __func__, loadmodel->name); + } + + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*2*sizeof(*out)); + + loadmodel->planes = out; + loadmodel->numplanes = count; + + for ( i=0 ; inormal[j] = LittleFloat (in->normal[j]); + if (out->normal[j] < 0) + bits |= 1<dist = LittleFloat (in->dist); + out->type = LittleLong (in->type); + out->signbits = bits; + } +} + + +// calculate the size that Hunk_Alloc(), called by Mod_Load*() from Mod_LoadBrushModel(), +// will use (=> includes its padding), so we'll know how big the hunk needs to be +static int calcLumpHunkSize(const lump_t *l, int inSize, int outSize) +{ + if (l->filelen % inSize) + { + // Mod_Load*() will error out on this because of "funny size" + // don't error out here because in Mod_Load*() it can print the functionname + // (=> tells us what kind of lump) before shutting down the game + return 0; + } + + int count = l->filelen / inSize; + int size = count * outSize; + + // round to cacheline, like Hunk_Alloc() does + size = (size + 31) & ~31; + return size; +} + +/* +================= +Mod_LoadBrushModel +================= +*/ +static void Mod_LoadBrushModel (model_t *loadmodel, void *buffer, int modfilelen) +{ + int i; + dheader_t *header; + byte *mod_base; + + header = (dheader_t *)buffer; + + i = LittleLong(header->version); + + if (i != BSPVERSION) + { + ri.Sys_Error(ERR_DROP, "%s: %s has wrong version number (%i should be %i)", + __func__, loadmodel->name, i, BSPVERSION); + } + + // swap all the lumps + mod_base = (byte *)header; + + for (i = 0; i < sizeof(dheader_t) / 4; i++) + { + ((int *)header)[i] = LittleLong(((int *)header)[i]); + } + + // calculate the needed hunksize from the lumps + int hunkSize = 0; + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_VERTEXES], sizeof(dvertex_t), sizeof(mvertex_t)); + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_EDGES], sizeof(dedge_t), sizeof(medge_t)); + hunkSize += sizeof(medge_t) + 31; // for count+1 in Mod_LoadEdges() + int surfEdgeCount = (header->lumps[LUMP_SURFEDGES].filelen+sizeof(int)-1)/sizeof(int); + if(surfEdgeCount < MAX_MAP_SURFEDGES) // else it errors out later anyway + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_SURFEDGES], sizeof(int), sizeof(int)); + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_LIGHTING], 1, 1); + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_PLANES], sizeof(dplane_t), sizeof(cplane_t)*2); + hunkSize += calcTexinfoAndFacesSize(&header->lumps[LUMP_FACES], mod_base, &header->lumps[LUMP_TEXINFO]); + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_LEAFFACES], sizeof(short), sizeof(msurface_t *)); // yes, out is indeeed a pointer! + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_VISIBILITY], 1, 1); + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_LEAFS], sizeof(dleaf_t), sizeof(mleaf_t)); + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_NODES], sizeof(dnode_t), sizeof(mnode_t)); + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_MODELS], sizeof(dmodel_t), sizeof(model_t)); + + loadmodel->extradata = Hunk_Begin(hunkSize); + loadmodel->type = mod_brush; + loadmodel->numframes = 2; // regular and alternate animation + + // load into heap + Mod_LoadVertexes (loadmodel, mod_base, &header->lumps[LUMP_VERTEXES]); + Mod_LoadEdges (loadmodel, mod_base, &header->lumps[LUMP_EDGES]); + Mod_LoadSurfedges (loadmodel, mod_base, &header->lumps[LUMP_SURFEDGES]); + Mod_LoadLighting (loadmodel, mod_base, &header->lumps[LUMP_LIGHTING]); + Mod_LoadPlanes (loadmodel, mod_base, &header->lumps[LUMP_PLANES]); + Mod_LoadTexinfo (loadmodel, mod_base, &header->lumps[LUMP_TEXINFO]); + Mod_LoadFaces (loadmodel, mod_base, &header->lumps[LUMP_FACES]); + Mod_LoadMarksurfaces (loadmodel, mod_base, &header->lumps[LUMP_LEAFFACES]); + Mod_LoadVisibility (loadmodel, mod_base, &header->lumps[LUMP_VISIBILITY]); + Mod_LoadLeafs (loadmodel, mod_base, &header->lumps[LUMP_LEAFS]); + Mod_LoadNodes (loadmodel, mod_base, &header->lumps[LUMP_NODES]); + Mod_LoadSubmodels (loadmodel, mod_base, &header->lumps[LUMP_MODELS]); +} + +/* +============================================================================== + +ALIAS MODELS + +============================================================================== +*/ + +/* +================= +Mod_LoadAliasModel +================= +*/ +static void Mod_LoadAliasModel (model_t *mod, void *buffer, int modfilelen) +{ + int i, j; + dmdl_t *pinmodel, *pheader; + dstvert_t *pinst, *poutst; + dtriangle_t *pintri, *pouttri; + int *pincmd, *poutcmd; + int version; + int ofs_end; + + pinmodel = (dmdl_t *)buffer; + + version = LittleLong (pinmodel->version); + if (version != ALIAS_VERSION) + { + ri.Sys_Error(ERR_DROP, "%s: %s has wrong version number (%i should be %i)", + __func__, mod->name, version, ALIAS_VERSION); + } + + ofs_end = LittleLong(pinmodel->ofs_end); + if (ofs_end < 0 || ofs_end > modfilelen) + { + ri.Sys_Error(ERR_DROP, "%s: model %s file size(%d) too small, should be %d", + __func__, mod->name, modfilelen, ofs_end); + } + + mod->extradata = Hunk_Begin(modfilelen); + pheader = Hunk_Alloc(ofs_end); + + // byte swap the header fields and sanity check + for (i=0 ; iskinheight > MAX_LBM_HEIGHT) + { + ri.Sys_Error(ERR_DROP, "%s: model %s has a skin taller than %d", + __func__, mod->name, MAX_LBM_HEIGHT); + } + + if (pheader->num_xyz <= 0) + { + ri.Sys_Error(ERR_DROP, "%s: model %s has no vertices", + __func__, mod->name); + } + + if (pheader->num_xyz > MAX_VERTS) + { + ri.Sys_Error(ERR_DROP, "%s: model %s has too many vertices", + __func__, mod->name); + } + + if (pheader->num_st <= 0) + { + ri.Sys_Error(ERR_DROP, "%s: model %s has no st vertices", + __func__, mod->name); + } + + if (pheader->num_tris <= 0) + { + ri.Sys_Error(ERR_DROP, "%s: model %s has no triangles", + __func__, mod->name); + } + + if (pheader->num_frames <= 0) + { + ri.Sys_Error(ERR_DROP, "%s: model %s has no frames", + __func__, mod->name); + } + + // + // load base s and t vertices (not used in gl version) + // + pinst = (dstvert_t *) ((byte *)pinmodel + pheader->ofs_st); + poutst = (dstvert_t *) ((byte *)pheader + pheader->ofs_st); + + for (i=0 ; inum_st ; i++) + { + poutst[i].s = LittleShort (pinst[i].s); + poutst[i].t = LittleShort (pinst[i].t); + } + + // + // load triangle lists + // + pintri = (dtriangle_t *) ((byte *)pinmodel + pheader->ofs_tris); + pouttri = (dtriangle_t *) ((byte *)pheader + pheader->ofs_tris); + + for (i=0 ; inum_tris ; i++) + { + for (j=0 ; j<3 ; j++) + { + pouttri[i].index_xyz[j] = LittleShort (pintri[i].index_xyz[j]); + pouttri[i].index_st[j] = LittleShort (pintri[i].index_st[j]); + } + } + + // + // load the frames + // + for (i=0 ; inum_frames ; i++) + { + daliasframe_t *pinframe, *poutframe; + + pinframe = (daliasframe_t *) ((byte *)pinmodel + + pheader->ofs_frames + i * pheader->framesize); + poutframe = (daliasframe_t *) ((byte *)pheader + + pheader->ofs_frames + i * pheader->framesize); + + memcpy (poutframe->name, pinframe->name, sizeof(poutframe->name)); + for (j=0 ; j<3 ; j++) + { + poutframe->scale[j] = LittleFloat (pinframe->scale[j]); + poutframe->translate[j] = LittleFloat (pinframe->translate[j]); + } + // verts are all 8 bit, so no swapping needed + memcpy (poutframe->verts, pinframe->verts, + pheader->num_xyz*sizeof(dtrivertx_t)); + + } + + mod->type = mod_alias; + + // + // load the glcmds + // + pincmd = (int *) ((byte *)pinmodel + pheader->ofs_glcmds); + poutcmd = (int *) ((byte *)pheader + pheader->ofs_glcmds); + for (i=0; i < pheader->num_glcmds; i++) + { + poutcmd[i] = LittleLong (pincmd[i]); + } + + if (poutcmd[pheader->num_glcmds-1] != 0) + { + R_Printf(PRINT_ALL, "%s: Entity %s has possible last element issues with %d verts.\n", + __func__, + mod->name, + poutcmd[pheader->num_glcmds-1]); + } + + // register all skins + memcpy ((char *)pheader + pheader->ofs_skins, (char *)pinmodel + pheader->ofs_skins, + pheader->num_skins*MAX_SKINNAME); + for (i=0 ; inum_skins ; i++) + { + mod->skins[i] = Vk_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME + , it_skin); + } + + mod->mins[0] = -32; + mod->mins[1] = -32; + mod->mins[2] = -32; + mod->maxs[0] = 32; + mod->maxs[1] = 32; + mod->maxs[2] = 32; +} + +/* +============================================================================== + +SPRITE MODELS + +============================================================================== +*/ + +/* +================= +Mod_LoadSpriteModel +================= +*/ +static void Mod_LoadSpriteModel (model_t *mod, void *buffer, int modfilelen) +{ + dsprite_t *sprin, *sprout; + int i; + + sprin = (dsprite_t *)buffer; + mod->extradata = Hunk_Begin(modfilelen); + sprout = Hunk_Alloc(modfilelen); + + sprout->ident = LittleLong (sprin->ident); + sprout->version = LittleLong (sprin->version); + sprout->numframes = LittleLong (sprin->numframes); + + if (sprout->version != SPRITE_VERSION) + { + ri.Sys_Error(ERR_DROP, "%s: %s has wrong version number (%i should be %i)", + __func__, mod->name, sprout->version, SPRITE_VERSION); + } + + if (sprout->numframes > MAX_MD2SKINS) + { + ri.Sys_Error(ERR_DROP, "%s: %s has too many frames (%i > %i)", + __func__, mod->name, sprout->numframes, MAX_MD2SKINS); + } + + // byte swap everything + for (i=0 ; inumframes ; i++) + { + sprout->frames[i].width = LittleLong (sprin->frames[i].width); + sprout->frames[i].height = LittleLong (sprin->frames[i].height); + sprout->frames[i].origin_x = LittleLong (sprin->frames[i].origin_x); + sprout->frames[i].origin_y = LittleLong (sprin->frames[i].origin_y); + memcpy (sprout->frames[i].name, sprin->frames[i].name, MAX_SKINNAME); + mod->skins[i] = Vk_FindImage (sprout->frames[i].name, + it_sprite); + } + + mod->type = mod_sprite; +} + +//============================================================================= + +/* +================== +Mod_ForName + +Loads in a model for the given name +================== +*/ +static model_t *Mod_ForName (char *name, model_t *parent_model, qboolean crash) +{ + model_t *mod; + unsigned *buf; + int i, modfilelen; + + if (!name[0]) + { + ri.Sys_Error(ERR_DROP, "%s: NULL name", __func__); + } + + // + // inline models are grabbed only from worldmodel + // + if (name[0] == '*' && parent_model) + { + i = atoi(name+1); + if (i < 1 || i >= parent_model->numsubmodels) + ri.Sys_Error (ERR_DROP, "bad inline model number"); + return &parent_model->submodels[i]; + } + + // + // search the currently loaded models + // + for (i=0 , mod=models_known ; iname[0]) + continue; + if (!strcmp (mod->name, name) ) + return mod; + } + + // + // find a free model slot spot + // + for (i=0 , mod=models_known ; iname[0]) + break; // free spot + } + if (i == mod_numknown) + { + if (mod_numknown == models_known_max) + ri.Sys_Error(ERR_DROP, "%s: mod_numknown == models_known_max", __func__); + mod_numknown++; + } + strcpy (mod->name, name); + + // + // load the file + // + modfilelen = ri.FS_LoadFile (mod->name, (void **)&buf); + if (!buf) + { + if (crash) + { + ri.Sys_Error(ERR_DROP, "%s: %s not found", + __func__, mod->name); + } + + if (vk_validation->value) + { + R_Printf(PRINT_ALL, "%s: Can't load %s\n", __func__, mod->name); + } + memset (mod->name, 0, sizeof(mod->name)); + return NULL; + } + + // update count of loaded models + mod_loaded ++; + if (vk_validation->value) + { + R_Printf(PRINT_ALL, "%s: Load %s[%d]\n", __func__, mod->name, mod_loaded); + } + + // + // fill it in + // + + // call the apropriate loader + + switch (LittleLong(*(unsigned *)buf)) + { + case IDALIASHEADER: + Mod_LoadAliasModel(mod, buf, modfilelen); + break; + + case IDSPRITEHEADER: + Mod_LoadSpriteModel(mod, buf, modfilelen); + break; + + case IDBSPHEADER: + Mod_LoadBrushModel(mod, buf, modfilelen); + break; + + default: + ri.Sys_Error(ERR_DROP, "%s: unknown fileid for %s", + __func__, mod->name); + break; + } + + mod->extradatasize = Hunk_End (); + + ri.FS_FreeFile(buf); + + return mod; +} + +/* +===================== +RE_BeginRegistration + +Specifies the model that will be used as the world +===================== +*/ +void +RE_BeginRegistration (char *model) +{ + char fullname[MAX_QPATH]; + cvar_t *flushmap; + + Mod_Reallocate(); + + registration_sequence++; + r_oldviewcluster = -1; // force markleafs + + Com_sprintf (fullname, sizeof(fullname), "maps/%s.bsp", model); + + // explicitly free the old map if different + // this guarantees that models_known[0] is the world map + flushmap = ri.Cvar_Get ("flushmap", "0", 0); + if ( strcmp(models_known[0].name, fullname) || flushmap->value) + Mod_Free (&models_known[0]); + r_worldmodel = Mod_ForName(fullname, NULL, true); + if (r_worldmodel != models_known) + ri.Sys_Error(ERR_DROP, "%s: Loaded a brush model after the world", __func__); + + r_viewcluster = -1; +} + +/* +===================== +RE_RegisterModel + +===================== +*/ +struct model_s *RE_RegisterModel (char *name) +{ + model_t *mod; + + mod = Mod_ForName (name, r_worldmodel, false); + if (mod) + { + int i; + + mod->registration_sequence = registration_sequence; + + // register any images used by the models + if (mod->type == mod_sprite) + { + dsprite_t *sprout; + + sprout = (dsprite_t *)mod->extradata; + for (i=0 ; inumframes ; i++) + mod->skins[i] = Vk_FindImage (sprout->frames[i].name, it_sprite); + } + else if (mod->type == mod_alias) + { + dmdl_t *pheader; + + pheader = (dmdl_t *)mod->extradata; + for (i=0 ; inum_skins ; i++) + mod->skins[i] = Vk_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME, it_skin); +//PGM + mod->numframes = pheader->num_frames; +//PGM + } + else if (mod->type == mod_brush) + { + for (i=0 ; inumtexinfo ; i++) + mod->texinfo[i].image->registration_sequence = registration_sequence; + } + } + return mod; +} + +static qboolean +Mod_HasFreeSpace(void) +{ + int i, used; + model_t *mod; + + used = 0; + + for (i=0, mod=models_known ; iname[0]) + continue; + if (mod->registration_sequence == registration_sequence) + { + used ++; + } + } + + if (mod_max < used) + { + mod_max = used; + } + + // should same size of free slots as currently used + return (mod_loaded + mod_max) < models_known_max; +} + +/* +================ +Mod_Modellist_f +================ +*/ +void Mod_Modellist_f (void) +{ + int i, total, used; + model_t *mod; + qboolean freeup; + + total = 0; + used = 0; + + R_Printf(PRINT_ALL,"Loaded models:\n"); + for (i=0, mod=models_known ; i < mod_numknown ; i++, mod++) + { + char *in_use = ""; + + if (mod->registration_sequence == registration_sequence) + { + in_use = "*"; + used ++; + } + + if (!mod->name[0]) + continue; + R_Printf(PRINT_ALL, "%8i : %s %s\n", + mod->extradatasize, mod->name, in_use); + total += mod->extradatasize; + } + R_Printf(PRINT_ALL, "Total resident: %i in %d models\n", total, mod_loaded); + // update statistics + freeup = Mod_HasFreeSpace(); + R_Printf(PRINT_ALL, "Used %d of %d models%s.\n", used, mod_max, freeup ? ", has free space" : ""); +} + +/* +===================== +RE_EndRegistration + +===================== +*/ +void RE_EndRegistration (void) +{ + int i; + model_t *mod; + + if (Mod_HasFreeSpace() && Vk_ImageHasFreeSpace()) + { + // should be enough space for load next maps + return; + } + + for (i=0, mod=models_known ; iname[0]) + continue; + if (mod->registration_sequence != registration_sequence) + { // don't need this model + Mod_Free (mod); + } + } + + Vk_FreeUnusedImages (); +} diff --git a/src/vk/vk_pipeline.c b/src/vk/vk_pipeline.c new file mode 100644 index 0000000..ee7d3f2 --- /dev/null +++ b/src/vk/vk_pipeline.c @@ -0,0 +1,222 @@ +/* +Copyright (C) 2018-2019 Krzysztof Kondrak + +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. + +*/ + +#include "header/local.h" + +qvkshader_t QVk_CreateShader(const uint32_t *shaderSrc, size_t shaderCodeSize, VkShaderStageFlagBits shaderStage) +{ + qvkshader_t shader; + VkShaderModuleCreateInfo smCreateInfo = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .codeSize = shaderCodeSize, + .pCode = shaderSrc + }; + + VK_VERIFY(vkCreateShaderModule(vk_device.logical, &smCreateInfo, NULL, &shader.module)); + + VkPipelineShaderStageCreateInfo vssCreateInfo = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .stage = shaderStage, + .module = shader.module, + .pName = "main", + .pSpecializationInfo = NULL + }; + + shader.createInfo = vssCreateInfo; + + return shader; +} + +void QVk_CreatePipeline(const VkDescriptorSetLayout *descriptorLayout, const uint32_t descLayoutCount, const VkPipelineVertexInputStateCreateInfo *vertexInputInfo, + qvkpipeline_t *pipeline, const qvkrenderpass_t *renderpass, const qvkshader_t *shaders, uint32_t shaderCount) +{ + VkPipelineShaderStageCreateInfo *ssCreateInfos = (VkPipelineShaderStageCreateInfo *)malloc(shaderCount * sizeof(VkPipelineShaderStageCreateInfo)); + for (int i = 0; i < shaderCount; i++) + { + ssCreateInfos[i] = shaders[i].createInfo; + } + + VkPipelineInputAssemblyStateCreateInfo iaCreateInfo = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .topology = pipeline->topology, + .primitiveRestartEnable = VK_FALSE + }; + + VkViewport viewport = { + .x = 0.f, + .y = 0.f, + .width = (float)vid.width, + .height = (float)vid.height, + .minDepth = 0.f, + .maxDepth = 1.f, + }; + + VkRect2D scissor = { + .offset.x = 0, + .offset.y = 0, + .extent = vk_swapchain.extent + }; + + VkPipelineViewportStateCreateInfo vpCreateInfo = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .viewportCount = 1, + .pViewports = &viewport, + .scissorCount = 1, + .pScissors = &scissor + }; + + VkPipelineRasterizationStateCreateInfo rCreateInfo = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .depthClampEnable = VK_FALSE, + .rasterizerDiscardEnable = VK_FALSE, + .polygonMode = VK_POLYGON_MODE_FILL, + .cullMode = pipeline->cullMode, + .frontFace = VK_FRONT_FACE_CLOCKWISE, + .depthBiasEnable = VK_FALSE, + .depthBiasConstantFactor = 0.f, + .depthBiasClamp = 0.f, + .depthBiasSlopeFactor = 0.f, + .lineWidth = 1.f + }; + + VkPipelineMultisampleStateCreateInfo msCreateInfo = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .rasterizationSamples = renderpass->sampleCount, + .sampleShadingEnable = (vk_sampleshading->value > 0 && vk_device.features.sampleRateShading) ? VK_TRUE : VK_FALSE, + .minSampleShading = (vk_sampleshading->value > 0 && vk_device.features.sampleRateShading) ? 1.f : 0.f, + .pSampleMask = NULL, + .alphaToCoverageEnable = VK_FALSE, + .alphaToOneEnable = VK_FALSE + }; + + VkPipelineDepthStencilStateCreateInfo dCreateInfo = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .depthTestEnable = pipeline->depthTestEnable, + .depthWriteEnable = pipeline->depthTestEnable == VK_TRUE ? pipeline->depthWriteEnable : VK_FALSE, // there should be NO depth writes if depthTestEnable is false but Intel seems to not follow the specs fully... + .depthCompareOp = VK_COMPARE_OP_LESS, + .depthBoundsTestEnable = VK_FALSE, + .stencilTestEnable = VK_FALSE, + .front = { VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_NEVER, 0, 0, 0 }, + .back = { VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_NEVER, 0, 0, 0 }, + .minDepthBounds = 0.f, + .maxDepthBounds = 1.f + }; + + VkPipelineColorBlendStateCreateInfo cbsCreateInfo = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .logicOpEnable = VK_FALSE, + .logicOp = VK_LOGIC_OP_COPY, + .attachmentCount = 1, + .pAttachments = &pipeline->blendOpts, + .blendConstants[0] = 0.f, + .blendConstants[1] = 0.f, + .blendConstants[2] = 0.f, + .blendConstants[3] = 0.f + }; + + VkDynamicState dynamicStates[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; + VkPipelineDynamicStateCreateInfo dsCreateInfo = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .dynamicStateCount = 2, + .pDynamicStates = dynamicStates + }; + + // push constant sizes accomodate for maximum number of uploaded elements (should probably be checked against the hardware's maximum supported value) + VkPushConstantRange pushConstantRange[] = { + { + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, + .offset = 0, + .size = 17 * sizeof(float) + }, + { + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + .offset = 17 * sizeof(float), + .size = 11 * sizeof(float) + }}; + + VkPipelineLayoutCreateInfo plCreateInfo = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .setLayoutCount = descLayoutCount, + .pSetLayouts = descriptorLayout, + // for simplicity assume only two push constant range is passed, + // so it's not the most flexible approach + .pushConstantRangeCount = 2, + .pPushConstantRanges = pushConstantRange + }; + + VK_VERIFY(vkCreatePipelineLayout(vk_device.logical, &plCreateInfo, NULL, &pipeline->layout)); + + // create THE pipeline + VkGraphicsPipelineCreateInfo pCreateInfo = { + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .pNext = NULL, + .flags = pipeline->flags, + .stageCount = shaderCount, + .pStages = ssCreateInfos, + .pVertexInputState = vertexInputInfo, + .pInputAssemblyState = &iaCreateInfo, + .pTessellationState = NULL, + .pViewportState = &vpCreateInfo, + .pRasterizationState = &rCreateInfo, + .pMultisampleState = &msCreateInfo, + .pDepthStencilState = &dCreateInfo, + .pColorBlendState = &cbsCreateInfo, + .pDynamicState = &dsCreateInfo, + .layout = pipeline->layout, + .renderPass = renderpass->rp, + .subpass = 0, + .basePipelineHandle = VK_NULL_HANDLE, + .basePipelineIndex = -1 + }; + + VK_VERIFY(vkCreateGraphicsPipelines(vk_device.logical, VK_NULL_HANDLE, 1, &pCreateInfo, NULL, &pipeline->pl)); + free(ssCreateInfos); +} + +void QVk_DestroyPipeline(qvkpipeline_t *pipeline) +{ + if (pipeline->layout != VK_NULL_HANDLE) + vkDestroyPipelineLayout(vk_device.logical, pipeline->layout, NULL); + if (pipeline->pl != VK_NULL_HANDLE) + vkDestroyPipeline(vk_device.logical, pipeline->pl, NULL); + + pipeline->layout = VK_NULL_HANDLE; + pipeline->pl = VK_NULL_HANDLE; +} diff --git a/src/vk/vk_rmain.c b/src/vk/vk_rmain.c new file mode 100644 index 0000000..046b527 --- /dev/null +++ b/src/vk/vk_rmain.c @@ -0,0 +1,1761 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. +Copyright (C) 2018-2019 Krzysztof Kondrak + +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. + +*/ +// vk_rmain.c + +#include "header/local.h" + +#define REF_VERSION "Yamagi Quake II Vulkan Refresher (based on vkQuake2 v1.4.3)" + +// world rendered and ready to render 2d elements +static qboolean world_rendered; + +viddef_t vid; + +refimport_t ri; + +model_t *r_worldmodel; + +vkconfig_t vk_config; +vkstate_t vk_state; + +image_t *r_notexture; // use for bad textures +image_t *r_particletexture; // little dot for particles +image_t *r_squaretexture; // rectangle for particles + +cplane_t frustum[4]; + +int r_visframecount; // bumped when going to a new PVS +int r_framecount; // used for dlight push checking + +int c_brush_polys, c_alias_polys; + +static float v_blend[4]; // final blending color + +void Vk_Strings_f(void); +void Vk_Mem_f(void); + +// +// view origin +// +vec3_t vup; +vec3_t vpn; +vec3_t vright; +vec3_t r_origin; + +float r_projection_matrix[16]; +float r_view_matrix[16]; +float r_viewproj_matrix[16]; +// correction matrix for perspective in Vulkan +static float r_vulkan_correction[16] = { 1.f, 0.f, 0.f, 0.f, + 0.f, -1.f, 0.f, 0.f, + 0.f, 0.f, .5f, 0.f, + 0.f, 0.f, .5f, 1.f + }; +// +// screen size info +// +refdef_t r_newrefdef; + +int r_viewcluster, r_viewcluster2, r_oldviewcluster, r_oldviewcluster2; + +static cvar_t *r_norefresh; +static cvar_t *r_drawentities; +cvar_t *r_drawworld; +static cvar_t *r_speeds; +static cvar_t *r_fullbright; +cvar_t *r_novis; +static cvar_t *r_nocull; +cvar_t *r_lerpmodels; +cvar_t *r_lefthand; +cvar_t *r_vsync; +static cvar_t *r_mode; +cvar_t *r_gunfov; +cvar_t *r_farsee; +static cvar_t *r_customwidth; +static cvar_t *r_customheight; + +cvar_t *r_lightlevel; // FIXME: This is a HACK to get the client's light level + +cvar_t *vk_overbrightbits; +cvar_t *vk_validation; +cvar_t *vk_picmip; +cvar_t *vk_skymip; +cvar_t *vk_flashblend; +cvar_t *vk_finish; +cvar_t *r_clear; +cvar_t *r_lockpvs; +static cvar_t *vk_polyblend; +cvar_t *r_modulate; +cvar_t *vk_shadows; +cvar_t *vk_pixel_size; +static cvar_t *vk_particle_size; +static cvar_t *vk_particle_att_a; +static cvar_t *vk_particle_att_b; +static cvar_t *vk_particle_att_c; +static cvar_t *vk_particle_min_size; +static cvar_t *vk_particle_max_size; +static cvar_t *vk_custom_particles; +cvar_t *vk_postprocess; +cvar_t *vk_dynamic; +cvar_t *vk_msaa; +cvar_t *vk_showtris; +cvar_t *vk_lightmap; +cvar_t *vk_texturemode; +cvar_t *vk_lmaptexturemode; +cvar_t *vk_aniso; +cvar_t *vk_mip_nearfilter; +cvar_t *vk_sampleshading; +cvar_t *vk_device_idx; +cvar_t *vk_retexturing; +static cvar_t *vk_underwater; +cvar_t *vk_nolerp_list; +cvar_t *r_fixsurfsky; + +cvar_t *vid_fullscreen; +cvar_t *vid_gamma; +static cvar_t *viewsize; + +/* +================= +R_CullBox + +Returns true if the box is completely outside the frustom +================= +*/ +qboolean R_CullBox (vec3_t mins, vec3_t maxs) +{ + int i; + + if (r_nocull->value) + return false; + + for (i=0 ; i<4 ; i++) + if ( BOX_ON_PLANE_SIDE(mins, maxs, &frustum[i]) == 2) + return true; + return false; +} + + +void R_RotateForEntity (entity_t *e, float *mvMatrix) +{ + Mat_Rotate(mvMatrix, -e->angles[2], 1.f, 0.f, 0.f); + Mat_Rotate(mvMatrix, -e->angles[0], 0.f, 1.f, 0.f); + Mat_Rotate(mvMatrix, e->angles[1], 0.f, 0.f, 1.f); + Mat_Translate(mvMatrix, e->origin[0], e->origin[1], e->origin[2]); +} + +/* +============================================================= + + SPRITE MODELS + +============================================================= +*/ + + +/* +================= +R_DrawSpriteModel + +================= +*/ +void R_DrawSpriteModel (entity_t *currententity, model_t *currentmodel) +{ + float alpha = 1.0F; + vec3_t point; + dsprframe_t *frame; + float *up, *right; + dsprite_t *psprite; + + // don't even bother culling, because it's just a single + // polygon without a surface cache + + psprite = (dsprite_t *)currentmodel->extradata; + + currententity->frame %= psprite->numframes; + + frame = &psprite->frames[currententity->frame]; + + // normal sprite + up = vup; + right = vright; + + if (currententity->flags & RF_TRANSLUCENT) + alpha = currententity->alpha; + + vec3_t spriteQuad[4]; + + VectorMA(currententity->origin, -frame->origin_y, up, point); + VectorMA(point, -frame->origin_x, right, spriteQuad[0]); + VectorMA(currententity->origin, frame->height - frame->origin_y, up, point); + VectorMA(point, -frame->origin_x, right, spriteQuad[1]); + VectorMA(currententity->origin, frame->height - frame->origin_y, up, point); + VectorMA(point, frame->width - frame->origin_x, right, spriteQuad[2]); + VectorMA(currententity->origin, -frame->origin_y, up, point); + VectorMA(point, frame->width - frame->origin_x, right, spriteQuad[3]); + + float quadVerts[] = { spriteQuad[0][0], spriteQuad[0][1], spriteQuad[0][2], 0.f, 1.f, + spriteQuad[1][0], spriteQuad[1][1], spriteQuad[1][2], 0.f, 0.f, + spriteQuad[2][0], spriteQuad[2][1], spriteQuad[2][2], 1.f, 0.f, + spriteQuad[0][0], spriteQuad[0][1], spriteQuad[0][2], 0.f, 1.f, + spriteQuad[2][0], spriteQuad[2][1], spriteQuad[2][2], 1.f, 0.f, + spriteQuad[3][0], spriteQuad[3][1], spriteQuad[3][2], 1.f, 1.f }; + + vkCmdPushConstants(vk_activeCmdbuffer, vk_drawSpritePipeline.layout, + VK_SHADER_STAGE_VERTEX_BIT, sizeof(r_viewproj_matrix), sizeof(float), &alpha); + QVk_BindPipeline(&vk_drawSpritePipeline); + + VkBuffer vbo; + VkDeviceSize vboOffset; + uint8_t *vertData = QVk_GetVertexBuffer(sizeof(quadVerts), &vbo, &vboOffset); + memcpy(vertData, quadVerts, sizeof(quadVerts)); + + vkCmdBindVertexBuffers(vk_activeCmdbuffer, 0, 1, &vbo, &vboOffset); + + float gamma = 2.1F - vid_gamma->value; + + vkCmdPushConstants(vk_activeCmdbuffer, vk_drawTexQuadPipeline[vk_state.current_renderpass].layout, + VK_SHADER_STAGE_FRAGMENT_BIT, 17 * sizeof(float), sizeof(gamma), &gamma); + + vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vk_drawSpritePipeline.layout, 0, 1, ¤tmodel->skins[currententity->frame]->vk_texture.descriptorSet, 0, NULL); + vkCmdDraw(vk_activeCmdbuffer, 6, 1, 0, 0); +} + +//================================================================================== + +/* +============= +R_DrawNullModel +============= +*/ +void R_DrawNullModel (entity_t *currententity) +{ + vec3_t shadelight; + int i,j; + + if (currententity->flags & RF_FULLBRIGHT) + shadelight[0] = shadelight[1] = shadelight[2] = 1.0F; + else + R_LightPoint(currententity->origin, shadelight, currententity); + + float model[16]; + Mat_Identity(model); + R_RotateForEntity(currententity, model); + + vec3_t verts[24]; + verts[0][0] = 0.f; + verts[0][1] = 0.f; + verts[0][2] = -16.f; + verts[1][0] = shadelight[0]; + verts[1][1] = shadelight[1]; + verts[1][2] = shadelight[2]; + + for (i = 2, j = 0; i < 12; i+=2, j++) + { + verts[i][0] = 16 * cos(j*M_PI / 2); + verts[i][1] = 16 * sin(j*M_PI / 2); + verts[i][2] = 0.f; + verts[i+1][0] = shadelight[0]; + verts[i+1][1] = shadelight[1]; + verts[i+1][2] = shadelight[2]; + } + + verts[12][0] = 0.f; + verts[12][1] = 0.f; + verts[12][2] = 16.f; + verts[13][0] = shadelight[0]; + verts[13][1] = shadelight[1]; + verts[13][2] = shadelight[2]; + + for (i = 23, j = 4; i > 13; i-=2, j--) + { + verts[i-1][0] = 16 * cos(j*M_PI / 2); + verts[i-1][1] = 16 * sin(j*M_PI / 2); + verts[i-1][2] = 0.f; + verts[i][0] = shadelight[0]; + verts[i][1] = shadelight[1]; + verts[i][2] = shadelight[2]; + } + + VkBuffer vbo; + VkDeviceSize vboOffset; + uint32_t uboOffset; + VkDescriptorSet uboDescriptorSet; + uint8_t *vertData = QVk_GetVertexBuffer(sizeof(verts), &vbo, &vboOffset); + uint8_t *uboData = QVk_GetUniformBuffer(sizeof(model), &uboOffset, &uboDescriptorSet); + memcpy(vertData, verts, sizeof(verts)); + memcpy(uboData, model, sizeof(model)); + + QVk_BindPipeline(&vk_drawNullModelPipeline); + vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vk_drawNullModelPipeline.layout, 0, 1, &uboDescriptorSet, 1, &uboOffset); + vkCmdBindVertexBuffers(vk_activeCmdbuffer, 0, 1, &vbo, &vboOffset); + vkCmdBindIndexBuffer(vk_activeCmdbuffer, QVk_GetTriangleFanIbo(12), 0, VK_INDEX_TYPE_UINT16); + vkCmdDrawIndexed(vk_activeCmdbuffer, 12, 1, 0, 0, 0); + vkCmdDrawIndexed(vk_activeCmdbuffer, 12, 1, 0, 6, 0); +} + +/* +============= +R_DrawEntitiesOnList +============= +*/ +void R_DrawEntitiesOnList (void) +{ + int i; + + if (!r_drawentities->value) + return; + + // draw non-transparent first + for (i = 0; iflags & RF_TRANSLUCENT) + continue; // solid + + if (currententity->flags & RF_BEAM) + { + R_DrawBeam(currententity); + } + else + { + model_t *currentmodel = currententity->model; + if (!currentmodel) + { + R_DrawNullModel(currententity); + continue; + } + switch (currentmodel->type) + { + case mod_alias: + R_DrawAliasModel(currententity, currentmodel); + break; + case mod_brush: + R_DrawBrushModel(currententity, currentmodel); + break; + case mod_sprite: + R_DrawSpriteModel(currententity, currentmodel); + break; + default: + R_Printf(PRINT_ALL, "%s: Bad modeltype %d\n", + __func__, currentmodel->type); + return; + } + } + } + + // draw transparent entities + // we could sort these if it ever becomes a problem... + for (i = 0; iflags & RF_TRANSLUCENT)) + continue; // solid + + if (currententity->flags & RF_BEAM) + { + R_DrawBeam(currententity); + } + else + { + model_t *currentmodel = currententity->model; + + if (!currentmodel) + { + R_DrawNullModel(currententity); + continue; + } + switch (currentmodel->type) + { + case mod_alias: + R_DrawAliasModel(currententity, currentmodel); + break; + case mod_brush: + R_DrawBrushModel(currententity, currentmodel); + break; + case mod_sprite: + R_DrawSpriteModel(currententity, currentmodel); + break; + default: + R_Printf(PRINT_ALL, "%s: Bad modeltype %d\n", + __func__, currentmodel->type); + return; + } + } + } +} + +/* +** Vk_DrawParticles +** +*/ +void Vk_DrawParticles(int num_particles, const particle_t particles[], const unsigned colortable[768]) +{ + typedef struct { + float x,y,z,r,g,b,a,u,v; + } pvertex; + + const particle_t *p; + int i; + vec3_t up, right; + byte color[4]; + pvertex* currentvertex; + + if (!num_particles) + return; + + VectorScale(vup, 1.5, up); + VectorScale(vright, 1.5, right); + + static pvertex visibleParticles[MAX_PARTICLES * 3]; + + if (num_particles > MAX_PARTICLES) + { + num_particles = MAX_PARTICLES; + } + + currentvertex = visibleParticles; + for (p = particles, i = 0; i < num_particles; i++, p++) + { + float scale; + + // hack a scale up to keep particles from disapearing + scale = (p->origin[0] - r_origin[0]) * vpn[0] + + (p->origin[1] - r_origin[1]) * vpn[1] + + (p->origin[2] - r_origin[2]) * vpn[2]; + + if (scale < 20) + scale = 1; + else + scale = 1 + scale * 0.004; + + *(int *)color = colortable[p->color]; + + float r = color[0] / 255.f; + float g = color[1] / 255.f; + float b = color[2] / 255.f; + + currentvertex->x = p->origin[0]; + currentvertex->y = p->origin[1]; + currentvertex->z = p->origin[2]; + currentvertex->r = r; + currentvertex->g = g; + currentvertex->b = b; + currentvertex->a = p->alpha; + currentvertex->u = 0.0625; + currentvertex->v = 0.0625; + currentvertex++; + + currentvertex->x = p->origin[0] + up[0] * scale; + currentvertex->y = p->origin[1] + up[1] * scale; + currentvertex->z = p->origin[2] + up[2] * scale; + currentvertex->r = r; + currentvertex->g = g; + currentvertex->b = b; + currentvertex->a = p->alpha; + currentvertex->u = 1.0625; + currentvertex->v = 0.0625; + currentvertex++; + + currentvertex->x = p->origin[0] + right[0] * scale; + currentvertex->y = p->origin[1] + right[1] * scale; + currentvertex->z = p->origin[2] + right[2] * scale; + currentvertex->r = r; + currentvertex->g = g; + currentvertex->b = b; + currentvertex->a = p->alpha; + currentvertex->u = 0.0625; + currentvertex->v = 1.0625; + currentvertex++; + } + + QVk_BindPipeline(&vk_drawParticlesPipeline); + + VkBuffer vbo; + VkDeviceSize vboOffset; + uint8_t *vertData = QVk_GetVertexBuffer((currentvertex - visibleParticles) * sizeof(pvertex), &vbo, &vboOffset); + memcpy(vertData, &visibleParticles, (currentvertex - visibleParticles) * sizeof(pvertex)); + + float gamma = 2.1F - vid_gamma->value; + + vkCmdPushConstants(vk_activeCmdbuffer, vk_drawTexQuadPipeline[vk_state.current_renderpass].layout, + VK_SHADER_STAGE_FRAGMENT_BIT, 17 * sizeof(float), sizeof(gamma), &gamma); + + if (vk_custom_particles->value == 2) + { + vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + vk_drawParticlesPipeline.layout, 0, 1, + &r_squaretexture->vk_texture.descriptorSet, 0, NULL); + } + else + { + vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + vk_drawParticlesPipeline.layout, 0, 1, + &r_particletexture->vk_texture.descriptorSet, 0, NULL); + } + + vkCmdBindVertexBuffers(vk_activeCmdbuffer, 0, 1, &vbo, &vboOffset); + vkCmdDraw(vk_activeCmdbuffer, (currentvertex - visibleParticles), 1, 0, 0); +} + +/* +=============== +R_DrawParticles +=============== +*/ +void R_DrawParticles (void) +{ + if (vk_custom_particles->value == 1) + { + int i; + unsigned char color[4]; + const particle_t *p; + + if (!r_newrefdef.num_particles) + return; + + typedef struct { + float x, y, z, r, g, b, a; + } ppoint; + + struct { + float particleSize; + float particleScale; + float minPointSize; + float maxPointSize; + float att_a; + float att_b; + float att_c; + } particleUbo; + + // Particle size needs to be scaled down proportionally to vk_pixel_size. + const float divisor = (vk_pixel_size->value < 1.0f ? 1.0f : vk_pixel_size->value); + particleUbo.particleSize = vk_particle_size->value / divisor; + particleUbo.particleScale = vid.width * ri.Cvar_Get("viewsize", "100", CVAR_ARCHIVE)->value / 102400; + particleUbo.minPointSize = vk_particle_min_size->value; + particleUbo.maxPointSize = vk_particle_max_size->value; + particleUbo.att_a = vk_particle_att_a->value; + particleUbo.att_b = vk_particle_att_b->value; + particleUbo.att_c = vk_particle_att_c->value; + + static ppoint visibleParticles[MAX_PARTICLES]; + + for (i = 0, p = r_newrefdef.particles; i < r_newrefdef.num_particles; i++, p++) + { + *(int *)color = d_8to24table[p->color]; + + float r = color[0] / 255.f; + float g = color[1] / 255.f; + float b = color[2] / 255.f; + + visibleParticles[i].x = p->origin[0]; + visibleParticles[i].y = p->origin[1]; + visibleParticles[i].z = p->origin[2]; + visibleParticles[i].r = r; + visibleParticles[i].g = g; + visibleParticles[i].b = b; + visibleParticles[i].a = p->alpha; + } + + QVk_BindPipeline(&vk_drawPointParticlesPipeline); + + VkBuffer vbo; + VkDeviceSize vboOffset; + uint32_t uboOffset; + VkDescriptorSet uboDescriptorSet; + uint8_t *vertData = QVk_GetVertexBuffer(sizeof(ppoint) * r_newrefdef.num_particles, &vbo, &vboOffset); + uint8_t *uboData = QVk_GetUniformBuffer(sizeof(particleUbo), &uboOffset, &uboDescriptorSet); + memcpy(vertData, &visibleParticles, sizeof(ppoint) * r_newrefdef.num_particles); + memcpy(uboData, &particleUbo, sizeof(particleUbo)); + vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vk_drawPointParticlesPipeline.layout, 0, 1, &uboDescriptorSet, 1, &uboOffset); + vkCmdBindVertexBuffers(vk_activeCmdbuffer, 0, 1, &vbo, &vboOffset); + vkCmdDraw(vk_activeCmdbuffer, r_newrefdef.num_particles, 1, 0, 0); + } + else + { + Vk_DrawParticles(r_newrefdef.num_particles, r_newrefdef.particles, d_8to24table); + } +} + +/* +============ +R_PolyBlend +============ +*/ +void R_PolyBlend (void) +{ + if (!vk_polyblend->value) + return; + if (!v_blend[3]) + return; + + float polyTransform[] = { 0.f, 0.f, vid.width, vid.height, v_blend[0], v_blend[1], v_blend[2], v_blend[3] }; + QVk_DrawColorRect(polyTransform, sizeof(polyTransform), RP_WORLD); +} + +//======================================================================= + +static int +SignbitsForPlane (cplane_t *out) +{ + int bits, j; + + // for fast box on planeside test + + bits = 0; + for (j = 0; j<3; j++) + { + if (out->normal[j] < 0) + bits |= 1 << j; + } + return bits; +} + + +static void +R_SetFrustum (float fovx, float fovy) +{ + // rotate VPN right by FOV_X/2 degrees + RotatePointAroundVector(frustum[0].normal, vup, vpn, -(90 - fovx / 2)); + // rotate VPN left by FOV_X/2 degrees + RotatePointAroundVector(frustum[1].normal, vup, vpn, 90 - fovx / 2); + // rotate VPN up by FOV_X/2 degrees + RotatePointAroundVector(frustum[2].normal, vright, vpn, 90 - fovy / 2); + // rotate VPN down by FOV_X/2 degrees + RotatePointAroundVector(frustum[3].normal, vright, vpn, -(90 - fovy / 2)); + + for (int i = 0; i < 4; i++) + { + frustum[i].type = PLANE_ANYZ; + frustum[i].dist = DotProduct(r_origin, frustum[i].normal); + frustum[i].signbits = SignbitsForPlane(&frustum[i]); + } +} + +//======================================================================= + +/* +=============== +R_SetupFrame +=============== +*/ +void R_SetupFrame (void) +{ + int i; + mleaf_t *leaf; + + r_framecount++; + + // build the transformation matrix for the given view angles + VectorCopy(r_newrefdef.vieworg, r_origin); + + AngleVectors(r_newrefdef.viewangles, vpn, vright, vup); + + // current viewcluster + if (!(r_newrefdef.rdflags & RDF_NOWORLDMODEL)) + { + r_oldviewcluster = r_viewcluster; + r_oldviewcluster2 = r_viewcluster2; + leaf = Mod_PointInLeaf(r_origin, r_worldmodel); + r_viewcluster = r_viewcluster2 = leaf->cluster; + + // check above and below so crossing solid water doesn't draw wrong + if (!leaf->contents) + { // look down a bit + vec3_t temp; + + VectorCopy(r_origin, temp); + temp[2] -= 16; + leaf = Mod_PointInLeaf(temp, r_worldmodel); + if (!(leaf->contents & CONTENTS_SOLID) && + (leaf->cluster != r_viewcluster2)) + r_viewcluster2 = leaf->cluster; + } + else + { // look up a bit + vec3_t temp; + + VectorCopy(r_origin, temp); + temp[2] += 16; + leaf = Mod_PointInLeaf(temp, r_worldmodel); + if (!(leaf->contents & CONTENTS_SOLID) && + (leaf->cluster != r_viewcluster2)) + r_viewcluster2 = leaf->cluster; + } + } + + for (i = 0; i < 4; i++) + v_blend[i] = r_newrefdef.blend[i]; + + c_brush_polys = 0; + c_alias_polys = 0; + + // clear out the portion of the screen that the NOWORLDMODEL defines + // unlike OpenGL, draw a rectangle in proper location - it's easier to do in Vulkan + if (r_newrefdef.rdflags & RDF_NOWORLDMODEL) + { + float clearArea[] = { (float)r_newrefdef.x / vid.width, (float)r_newrefdef.y / vid.height, + (float)r_newrefdef.width / vid.width, (float)r_newrefdef.height / vid.height, + .3f, .3f, .3f, 1.f }; + QVk_DrawColorRect(clearArea, sizeof(clearArea), RP_UI); + } +} + +void Mat_Identity(float *matrix) +{ + matrix[0] = 1.f; + matrix[1] = 0.f; + matrix[2] = 0.f; + matrix[3] = 0.f; + matrix[4] = 0.f; + matrix[5] = 1.f; + matrix[6] = 0.f; + matrix[7] = 0.f; + matrix[8] = 0.f; + matrix[9] = 0.f; + matrix[10] = 1.f; + matrix[11] = 0.f; + matrix[12] = 0.f; + matrix[13] = 0.f; + matrix[14] = 0.f; + matrix[15] = 1.f; +} + +void Mat_Mul(float *m1, float *m2, float *res) +{ + float mul[16] = { m1[0] * m2[0] + m1[1] * m2[4] + m1[2] * m2[8] + m1[3] * m2[12], + m1[0] * m2[1] + m1[1] * m2[5] + m1[2] * m2[9] + m1[3] * m2[13], + m1[0] * m2[2] + m1[1] * m2[6] + m1[2] * m2[10] + m1[3] * m2[14], + m1[0] * m2[3] + m1[1] * m2[7] + m1[2] * m2[11] + m1[3] * m2[15], + m1[4] * m2[0] + m1[5] * m2[4] + m1[6] * m2[8] + m1[7] * m2[12], + m1[4] * m2[1] + m1[5] * m2[5] + m1[6] * m2[9] + m1[7] * m2[13], + m1[4] * m2[2] + m1[5] * m2[6] + m1[6] * m2[10] + m1[7] * m2[14], + m1[4] * m2[3] + m1[5] * m2[7] + m1[6] * m2[11] + m1[7] * m2[15], + m1[8] * m2[0] + m1[9] * m2[4] + m1[10] * m2[8] + m1[11] * m2[12], + m1[8] * m2[1] + m1[9] * m2[5] + m1[10] * m2[9] + m1[11] * m2[13], + m1[8] * m2[2] + m1[9] * m2[6] + m1[10] * m2[10] + m1[11] * m2[14], + m1[8] * m2[3] + m1[9] * m2[7] + m1[10] * m2[11] + m1[11] * m2[15], + m1[12] * m2[0] + m1[13] * m2[4] + m1[14] * m2[8] + m1[15] * m2[12], + m1[12] * m2[1] + m1[13] * m2[5] + m1[14] * m2[9] + m1[15] * m2[13], + m1[12] * m2[2] + m1[13] * m2[6] + m1[14] * m2[10] + m1[15] * m2[14], + m1[12] * m2[3] + m1[13] * m2[7] + m1[14] * m2[11] + m1[15] * m2[15] + }; + + memcpy(res, mul, sizeof(float) * 16); +} + +void Mat_Translate(float *matrix, float x, float y, float z) +{ + float t[16] = { 1.f, 0.f, 0.f, 0.f, + 0.f, 1.f, 0.f, 0.f, + 0.f, 0.f, 1.f, 0.f, + x, y, z, 1.f }; + + Mat_Mul(matrix, t, matrix); +} + +void Mat_Rotate(float *matrix, float deg, float x, float y, float z) +{ + double c = cos(deg * M_PI / 180.0); + double s = sin(deg * M_PI / 180.0); + double cd = 1.0 - c; + vec3_t r = { x, y, z }; + VectorNormalize(r); + + float rot[16] = { r[0]*r[0]*cd + c, r[1]*r[0]*cd + r[2]*s, r[0]*r[2]*cd - r[1]*s, 0.f, + r[0]*r[1]*cd - r[2]*s, r[1]*r[1]*cd + c, r[1]*r[2]*cd + r[0]*s, 0.f, + r[0]*r[2]*cd + r[1]*s, r[1]*r[2]*cd - r[0]*s, r[2]*r[2]*cd + c, 0.f, + 0.f, 0.f, 0.f, 1.f + }; + + Mat_Mul(matrix, rot, matrix); +} + +void Mat_Scale(float *matrix, float x, float y, float z) +{ + float s[16] = { x, 0.f, 0.f, 0.f, + 0.f, y, 0.f, 0.f, + 0.f, 0.f, z, 0.f, + 0.f, 0.f, 0.f, 1.f + }; + + Mat_Mul(matrix, s, matrix); +} + +void Mat_Perspective(float *matrix, float *correction_matrix, float fovy, float aspect, + float zNear, float zFar) +{ + float xmin, xmax, ymin, ymax; + + ymax = zNear * tan(fovy * M_PI / 360.0); + ymin = -ymax; + + xmin = ymin * aspect; + xmax = ymax * aspect; + + xmin += -(2 * vk_state.camera_separation) / zNear; + xmax += -(2 * vk_state.camera_separation) / zNear; + + float proj[16]; + memset(proj, 0, sizeof(float) * 16); + proj[0] = 2.f * zNear / (xmax - xmin); + proj[2] = (xmax + xmin) / (xmax - xmin); + proj[5] = 2.f * zNear / (ymax - ymin); + proj[6] = (ymax + ymin) / (ymax - ymin); + proj[10] = -(zFar + zNear) / (zFar - zNear); + proj[11] = -1.f; + proj[14] = -2.f * zFar * zNear / (zFar - zNear); + + // Convert projection matrix to Vulkan coordinate system (https://matthewwellings.com/blog/the-new-vulkan-coordinate-system/) + Mat_Mul(proj, correction_matrix, matrix); +} + +void Mat_Ortho(float *matrix, float left, float right, float bottom, float top, + float zNear, float zFar) +{ + float proj[16]; + memset(proj, 0, sizeof(float) * 16); + proj[0] = 2.f / (right - left); + proj[3] = (right + left) / (right - left); + proj[5] = 2.f / (top - bottom); + proj[7] = (top + bottom) / (top - bottom); + proj[10] = -2.f / (zFar - zNear); + proj[11] = -(zFar + zNear) / (zFar - zNear); + proj[15] = 1.f; + + // Convert projection matrix to Vulkan coordinate system (https://matthewwellings.com/blog/the-new-vulkan-coordinate-system/) + Mat_Mul(proj, r_vulkan_correction, matrix); +} + +/* +============= +R_SetupVulkan +============= +*/ +static void +R_SetupVulkan (void) +{ + float r_proj_aspect; + float r_proj_fovx; + float r_proj_fovy; + int x, x2, y2, y, w, h; + float dist = (r_farsee->value == 0) ? 4096.0f : 8192.0f; + + // + // set up viewport + // + x = floor(r_newrefdef.x * vid.width / vid.width); + x2 = ceil((r_newrefdef.x + r_newrefdef.width) * vid.width / vid.width); + y = floor(vid.height - r_newrefdef.y * vid.height / vid.height); + y2 = ceil(vid.height - (r_newrefdef.y + r_newrefdef.height) * vid.height / vid.height); + + w = x2 - x; + h = y - y2; + + VkViewport viewport = { + .x = x, + .y = vid.height - h - y2, + .width = w, + .height = h, + .minDepth = 0.f, + .maxDepth = 1.f, + }; + + // When rendering the world, reduce viewport size proportionally to vk_pixel_size. + if (vk_state.current_renderpass == RP_WORLD) + { + const float divisor = (vk_pixel_size->value < 1.0f ? 1.0f : vk_pixel_size->value); + viewport.x /= divisor; + viewport.y /= divisor; + viewport.width /= divisor; + viewport.height /= divisor; + } + + vkCmdSetViewport(vk_activeCmdbuffer, 0, 1, &viewport); + + // set up projection matrix + r_proj_fovx = r_newrefdef.fov_x; + r_proj_fovy = r_newrefdef.fov_y; + r_proj_aspect = (float)r_newrefdef.width / r_newrefdef.height; + Mat_Perspective(r_projection_matrix, r_vulkan_correction, r_proj_fovy, r_proj_aspect, 4, dist); + + R_SetFrustum(r_proj_fovx, r_proj_fovy); + + // set up view matrix + Mat_Identity(r_view_matrix); + // put Z going up + Mat_Translate(r_view_matrix, -r_newrefdef.vieworg[0], -r_newrefdef.vieworg[1], -r_newrefdef.vieworg[2]); + Mat_Rotate(r_view_matrix, -r_newrefdef.viewangles[1], 0.f, 0.f, 1.f); + Mat_Rotate(r_view_matrix, -r_newrefdef.viewangles[0], 0.f, 1.f, 0.f); + Mat_Rotate(r_view_matrix, -r_newrefdef.viewangles[2], 1.f, 0.f, 0.f); + Mat_Rotate(r_view_matrix, 90.f, 0.f, 0.f, 1.f); + Mat_Rotate(r_view_matrix, -90.f, 1.f, 0.f, 0.f); + + // precalculate view-projection matrix + Mat_Mul(r_view_matrix, r_projection_matrix, r_viewproj_matrix); + // view-projection matrix will always be stored as the first push constant item, so set no offset + vkCmdPushConstants(vk_activeCmdbuffer, vk_drawTexQuadPipeline[vk_state.current_renderpass].layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(r_viewproj_matrix), r_viewproj_matrix); +} + +static void R_Flash( void ) +{ + R_PolyBlend (); +} + +/* +================ +RE_RenderView + +r_newrefdef must be set before the first call +================ +*/ +static void RE_RenderView (refdef_t *fd) +{ + if (r_norefresh->value) + return; + + r_newrefdef = *fd; + + if (!r_worldmodel && !(r_newrefdef.rdflags & RDF_NOWORLDMODEL)) + ri.Sys_Error(ERR_DROP, "%s: NULL worldmodel", __func__); + + if (r_speeds->value) + { + c_brush_polys = 0; + c_alias_polys = 0; + } + + VkRect2D scissor = { + .offset = { r_newrefdef.x, r_newrefdef.y }, + .extent = { r_newrefdef.width, r_newrefdef.height } + }; + + // When rendering the world, scale down scissor proportionally to vk_pixel_size. + if (vk_state.current_renderpass == RP_WORLD) + { + const float divisor = (vk_pixel_size->value < 1.0f ? 1.0f : vk_pixel_size->value); + scissor.offset.x = (int32_t)floorf(scissor.offset.x / divisor); + scissor.offset.y = (int32_t)floorf(scissor.offset.y / divisor); + scissor.extent.width = (uint32_t)ceilf(scissor.extent.width / divisor); + scissor.extent.height = (uint32_t)ceilf(scissor.extent.height / divisor); + } + + vkCmdSetScissor(vk_activeCmdbuffer, 0, 1, &scissor); + + R_PushDlights(); + + // added for compatibility sake with OpenGL implementation - don't use it! + if (vk_finish->value) + vkDeviceWaitIdle(vk_device.logical); + + R_SetupFrame(); + + R_SetupVulkan(); + + R_MarkLeaves(); // done here so we know if we're in water + + R_DrawWorld(); + + R_DrawEntitiesOnList(); + + R_RenderDlights(); + + R_DrawParticles(); + + R_DrawAlphaSurfaces(); + + R_Flash(); + + if (r_speeds->value) + { + R_Printf(PRINT_ALL, "%4i wpoly %4i epoly %i tex %i lmaps\n", + c_brush_polys, + c_alias_polys, + c_visible_textures, + c_visible_lightmaps); + } +} + +qboolean RE_EndWorldRenderpass(void) +{ + // still some issues? + if (!vk_frameStarted) + { + // we can't start 2d rendering + return false; + } + + // 3d world has alredy rendered and 2d already initialized + if (world_rendered) + { + return true; + } + + world_rendered = true; + + // finish rendering world view to offsceen buffer + vkCmdEndRenderPass(vk_activeCmdbuffer); + + // apply postprocessing effects to offscreen buffer: + // * underwater view warp if the player is submerged in liquid + // * restore world view to the full screen size when vk_pixel_size is >1.0 + QVk_BeginRenderpass(RP_WORLD_WARP); + float underwaterTime; + if (vk_underwater->value) + { + underwaterTime = (r_newrefdef.rdflags & RDF_UNDERWATER) ? r_newrefdef.time : 0.f; + } + else + { + underwaterTime = 0.f; + }; + float pushConsts[] = + { + underwaterTime, + viewsize->value / 100.0f, + vid.width, + vid.height, + vk_viewport.x, + vk_viewport.y, + (vk_pixel_size->value < 1.0f ? 1.0f : vk_pixel_size->value), + r_newrefdef.x, + r_newrefdef.y, + r_newrefdef.width, + r_newrefdef.height, + }; + vkCmdPushConstants(vk_activeCmdbuffer, vk_worldWarpPipeline.layout, + VK_SHADER_STAGE_FRAGMENT_BIT, 17 * sizeof(float), sizeof(pushConsts), pushConsts); + vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vk_worldWarpPipeline.layout, 0, 1, &vk_colorbuffer.descriptorSet, 0, NULL); + QVk_BindPipeline(&vk_worldWarpPipeline); + // Restore full viewport for future steps. + vkCmdSetViewport(vk_activeCmdbuffer, 0u, 1u, &vk_viewport); + vkCmdSetScissor(vk_activeCmdbuffer, 0u, 1u, &vk_scissor); + vkCmdDraw(vk_activeCmdbuffer, 3, 1, 0, 0); + vkCmdEndRenderPass(vk_activeCmdbuffer); + + // start drawing UI + QVk_BeginRenderpass(RP_UI); + + return true; +} + +static void R_SetVulkan2D (const VkViewport* viewport, const VkRect2D* scissor) +{ + // player configuration screen renders a model using the UI renderpass, so skip finishing RP_WORLD twice + if (!(r_newrefdef.rdflags & RDF_NOWORLDMODEL)) + if(!RE_EndWorldRenderpass()) + // buffers is not initialized + return; + + vkCmdSetViewport(vk_activeCmdbuffer, 0, 1, viewport); + vkCmdSetScissor(vk_activeCmdbuffer, 0, 1, scissor); + + // first, blit offscreen color buffer with warped/postprocessed world view + // skip this step if we're in player config screen since it uses RP_UI and draws directly to swapchain + if (!(r_newrefdef.rdflags & RDF_NOWORLDMODEL)) + { + float pushConsts[] = { vk_postprocess->value, (2.1 - vid_gamma->value)}; + vkCmdPushConstants(vk_activeCmdbuffer, vk_postprocessPipeline.layout, + VK_SHADER_STAGE_FRAGMENT_BIT, 17 * sizeof(float), sizeof(pushConsts), pushConsts); + vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vk_postprocessPipeline.layout, 0, 1, &vk_colorbufferWarp.descriptorSet, 0, NULL); + QVk_BindPipeline(&vk_postprocessPipeline); + vkCmdDraw(vk_activeCmdbuffer, 3, 1, 0, 0); + } +} + + +/* +==================== +R_SetLightLevel + +==================== +*/ +static void +R_SetLightLevel (void) +{ + vec3_t shadelight; + + if (r_newrefdef.rdflags & RDF_NOWORLDMODEL) + return; + + // save off light value for server to look at (BIG HACK!) + + R_LightPoint(r_newrefdef.vieworg, shadelight, NULL); + + // pick the greatest component, which should be the same + // as the mono value returned by software + if (shadelight[0] > shadelight[1]) + { + if (shadelight[0] > shadelight[2]) + r_lightlevel->value = 150 * shadelight[0]; + else + r_lightlevel->value = 150 * shadelight[2]; + } + else + { + if (shadelight[1] > shadelight[2]) + r_lightlevel->value = 150 * shadelight[1]; + else + r_lightlevel->value = 150 * shadelight[2]; + } +} + +/* +===================== +RE_RenderFrame + +===================== +*/ +static void +RE_RenderFrame (refdef_t *fd) +{ + if (!vk_frameStarted) + return; + + RE_RenderView( fd ); + R_SetLightLevel (); + R_SetVulkan2D (&vk_viewport, &vk_scissor); +} + + +static void +R_Register( void ) +{ + r_lefthand = ri.Cvar_Get("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE); + r_norefresh = ri.Cvar_Get("r_norefresh", "0", 0); + r_fullbright = ri.Cvar_Get("r_fullbright", "0", 0); + r_drawentities = ri.Cvar_Get("r_drawentities", "1", 0); + r_drawworld = ri.Cvar_Get("r_drawworld", "1", 0); + r_novis = ri.Cvar_Get("r_novis", "0", 0); + r_nocull = ri.Cvar_Get("r_nocull", "0", 0); + r_lerpmodels = ri.Cvar_Get("r_lerpmodels", "1", 0); + r_speeds = ri.Cvar_Get("r_speeds", "0", 0); + r_lightlevel = ri.Cvar_Get("r_lightlevel", "0", 0); + r_mode = ri.Cvar_Get("r_mode", "11", CVAR_ARCHIVE); + r_vsync = ri.Cvar_Get("r_vsync", "0", CVAR_ARCHIVE); + r_gunfov = ri.Cvar_Get("r_gunfov", "80", CVAR_ARCHIVE); + r_farsee = ri.Cvar_Get("r_farsee", "0", CVAR_LATCH | CVAR_ARCHIVE); + r_customwidth = ri.Cvar_Get("r_customwidth", "1024", CVAR_ARCHIVE); + r_customheight = ri.Cvar_Get("r_customheight", "768", CVAR_ARCHIVE); + + vk_overbrightbits = ri.Cvar_Get("vk_overbrightbits", "1.0", CVAR_ARCHIVE); + vk_validation = ri.Cvar_Get("vk_validation", "0", CVAR_ARCHIVE); + vk_picmip = ri.Cvar_Get("vk_picmip", "0", 0); + vk_skymip = ri.Cvar_Get("vk_skymip", "0", 0); + vk_flashblend = ri.Cvar_Get("vk_flashblend", "0", 0); + vk_finish = ri.Cvar_Get("vk_finish", "0", CVAR_ARCHIVE); + r_clear = ri.Cvar_Get("r_clear", "0", CVAR_ARCHIVE); + r_lockpvs = ri.Cvar_Get("r_lockpvs", "0", 0); + vk_polyblend = ri.Cvar_Get("vk_polyblend", "1", 0); + r_modulate = ri.Cvar_Get("r_modulate", "1", CVAR_ARCHIVE); + vk_shadows = ri.Cvar_Get("r_shadows", "0", CVAR_ARCHIVE); + vk_pixel_size = ri.Cvar_Get("vk_pixel_size", "1", CVAR_ARCHIVE); + vk_particle_size = ri.Cvar_Get("vk_particle_size", "40", CVAR_ARCHIVE); + vk_particle_att_a = ri.Cvar_Get("vk_particle_att_a", "0.01", CVAR_ARCHIVE); + vk_particle_att_b = ri.Cvar_Get("vk_particle_att_b", "0.0", CVAR_ARCHIVE); + vk_particle_att_c = ri.Cvar_Get("vk_particle_att_c", "0.01", CVAR_ARCHIVE); + vk_particle_min_size = ri.Cvar_Get("vk_particle_min_size", "2", CVAR_ARCHIVE); + vk_particle_max_size = ri.Cvar_Get("vk_particle_max_size", "40", CVAR_ARCHIVE); + vk_custom_particles = ri.Cvar_Get("vk_custom_particles", "1", CVAR_ARCHIVE); + vk_postprocess = ri.Cvar_Get("vk_postprocess", "1", CVAR_ARCHIVE); + vk_dynamic = ri.Cvar_Get("vk_dynamic", "1", 0); + vk_msaa = ri.Cvar_Get("r_msaa_samples", "0", CVAR_ARCHIVE); + vk_showtris = ri.Cvar_Get("vk_showtris", "0", 0); + vk_lightmap = ri.Cvar_Get("vk_lightmap", "0", 0); + vk_texturemode = ri.Cvar_Get("vk_texturemode", "VK_MIPMAP_LINEAR", CVAR_ARCHIVE); + vk_lmaptexturemode = ri.Cvar_Get("vk_lmaptexturemode", "VK_MIPMAP_LINEAR", CVAR_ARCHIVE); + vk_aniso = ri.Cvar_Get("r_anisotropic", "0", CVAR_ARCHIVE); + vk_mip_nearfilter = ri.Cvar_Get("vk_mip_nearfilter", "0", CVAR_ARCHIVE); + vk_sampleshading = ri.Cvar_Get("vk_sampleshading", "1", CVAR_ARCHIVE); + vk_device_idx = ri.Cvar_Get("vk_device", "-1", CVAR_ARCHIVE); + vk_retexturing = ri.Cvar_Get("r_retexturing", "1", CVAR_ARCHIVE); + vk_underwater = ri.Cvar_Get("vk_underwater", "1", CVAR_ARCHIVE); + /* don't bilerp characters and crosshairs */ + vk_nolerp_list = ri.Cvar_Get("r_nolerp_list", "pics/conchars.pcx pics/ch1.pcx pics/ch2.pcx pics/ch3.pcx", 0); + r_fixsurfsky = ri.Cvar_Get("r_fixsurfsky", "0", CVAR_ARCHIVE); + + // clamp vk_msaa to accepted range so that video menu doesn't crash on us + if (vk_msaa->value < 0) + ri.Cvar_Set("r_msaa_samples", "0"); + + vid_fullscreen = ri.Cvar_Get("vid_fullscreen", "0", CVAR_ARCHIVE); + vid_gamma = ri.Cvar_Get("vid_gamma", "1.0", CVAR_ARCHIVE); + viewsize = ri.Cvar_Get("viewsize", "100", CVAR_ARCHIVE); + + ri.Cmd_AddCommand("vk_strings", Vk_Strings_f); + ri.Cmd_AddCommand("vk_mem", Vk_Mem_f); + ri.Cmd_AddCommand("imagelist", Vk_ImageList_f); + ri.Cmd_AddCommand("screenshot", Vk_ScreenShot_f); + ri.Cmd_AddCommand("modellist", Mod_Modellist_f); +} + +static int +Vkimp_SetMode(int *pwidth, int *pheight, int mode, int fullscreen) +{ + R_Printf(PRINT_ALL, "Setting mode %d:", mode); + + /* mode -1 is not in the vid mode table - so we keep the values in pwidth + and pheight and don't even try to look up the mode info */ + if ((mode >= 0) && !ri.Vid_GetModeInfo(pwidth, pheight, mode)) + { + R_Printf(PRINT_ALL, " invalid mode\n"); + return rserr_invalid_mode; + } + + /* We trying to get resolution from desktop */ + if (mode == -2) + { + if(!ri.GLimp_GetDesktopMode(pwidth, pheight)) + { + R_Printf( PRINT_ALL, " can't detect mode\n" ); + return rserr_invalid_mode; + } + } + + R_Printf(PRINT_ALL, " %dx%d (vid_fullscreen %i)\n", *pwidth, *pheight, fullscreen); + + if (!ri.GLimp_InitGraphics(fullscreen, pwidth, pheight)) + { + return rserr_invalid_mode; + } + + return rserr_ok; +} + +/* +================== +R_SetMode +================== +*/ +qboolean R_SetMode (void) +{ + rserr_t err; + int fullscreen; + + r_mode->modified = false; + r_vsync->modified = false; + + fullscreen = (int)vid_fullscreen->value; + vid_gamma->modified = false; + + vk_msaa->modified = false; + r_clear->modified = false; + vk_validation->modified = false; + vk_mip_nearfilter->modified = false; + vk_sampleshading->modified = false; + vk_device_idx->modified = false; + vk_picmip->modified = false; + vk_overbrightbits->modified = false; + // refresh texture samplers + vk_texturemode->modified = true; + vk_lmaptexturemode->modified = true; + + /* a bit hackish approach to enable custom resolutions: + Glimp_SetMode needs these values set for mode -1 */ + vid.width = r_customwidth->value; + vid.height = r_customheight->value; + + if ((err = Vkimp_SetMode((int*)&vid.width, (int*)&vid.height, r_mode->value, fullscreen)) == rserr_ok) + { + vk_state.prev_mode = r_mode->value; + } + else + { + if (err == rserr_invalid_fullscreen) + { + ri.Cvar_SetValue("vid_fullscreen", 0); + R_Printf(PRINT_ALL, "%s() - fullscreen unavailable in this mode\n", __func__); + if (Vkimp_SetMode((int*)&vid.width, (int*)&vid.height, r_mode->value, false) == rserr_ok) + return true; + } + else if (err == rserr_invalid_mode) + { + ri.Cvar_SetValue("r_mode", vk_state.prev_mode); + r_mode->modified = false; + R_Printf(PRINT_ALL, "%s() - invalid mode\n", __func__); + } + + // try setting it back to something safe + if (Vkimp_SetMode((int*)&vid.width, (int*)&vid.height, vk_state.prev_mode, false) != rserr_ok) + { + R_Printf(PRINT_ALL, "%s() - could not revert to safe mode\n", __func__); + return false; + } + } + return true; +} + +/* +=============== +RE_Init +=============== +*/ +static qboolean RE_Init( void ) +{ + + R_Printf(PRINT_ALL, "Refresh: " REF_VERSION "\n"); + R_Printf(PRINT_ALL, "Client: " YQ2VERSION "\n\n"); + + R_Register(); + + // set our "safe" modes + vk_state.prev_mode = 4; + // set video mode/screen resolution + if (!R_SetMode()) + { + R_Printf(PRINT_ALL, "%s() - could not R_SetMode()\n", __func__); + return false; + } + ri.Vid_MenuInit(); + + // print device information during startup + Vk_Strings_f(); + + R_Printf(PRINT_ALL, "Successfully initialized Vulkan!\n"); + + return true; +} + +/* +** RE_ShutdownContext +** +** This routine does all OS specific shutdown procedures for the Vulkan +** subsystem. +** +*/ +static void RE_ShutdownContext( void ) +{ + // Shutdown Vulkan subsystem + QVk_WaitAndShutdownAll(); +} + +/* +=============== +RE_Shutdown +=============== +*/ +void RE_Shutdown (void) +{ + ri.Cmd_RemoveCommand("vk_strings"); + ri.Cmd_RemoveCommand("vk_mem"); + ri.Cmd_RemoveCommand("imagelist"); + ri.Cmd_RemoveCommand("screenshot"); + ri.Cmd_RemoveCommand( "modellist" ); + + QVk_WaitAndShutdownAll(); +} + +/* +===================== +RE_BeginFrame +===================== +*/ +static void +RE_BeginFrame( float camera_separation ) +{ + // world has not rendered yet + world_rendered = false; + + /* VK hasn't been initialized yet. I'm pretty sure that + we can't get here without having called QVk_Init(), + but better save than sorry. */ + if (!vk_initialized) + { + vk_frameStarted = false; + return; + } + + /* Some GPU drivers set a maximum extent size of 0x0 when + the window is minimized. But a swapchain with an extent + size of 0x0 is invalid. This leads to the following + problem: + + 1. The window is minimized, the extent size changes and + the Vulkan state get's corrupted. QVk_EndFrame() + above or QVk_BeginFrame() below detect the Vulkan + state as corrupted, set vk_frameStated to false and + request a restart by setting vk_restartNeeded to + true. + 2. RE_EndFrame() triggers the restart. QVk_Shutdown() + is successfull, but QVk_Init() can't create a valid + swapchains and errors out. An incomplete internal + renderer state is left behind. The only way out is + to trigger a full render restart. + 3. The full renderer restart would lead to a restart + loop: Restart -> QVk_Init() fails -> restart -> ... + The only alternative is not to restart. Instead the + renderer could error out, that would print an error + message and quit the client. + + Work around this by not starting the frame or restarting + the renderer, as long as the maximum extent size is 0x0. + This is part 1 (the state corruption war detect in the + last frame), part 2 (the state corruption was detected in + the current frame) is in RE_EndFrame(). */ + if (vk_restartNeeded) + { + if (!QVk_CheckExtent()) + { + vk_frameStarted = false; + return; + } + } + + // if ri.Sys_Error() had been issued mid-frame, we might end up here without properly submitting the image, so call QVk_EndFrame to be safe + if (QVk_EndFrame(true) != VK_SUCCESS) + vk_restartNeeded = true; + + /* + ** change modes if necessary + */ + if (r_mode->modified || vk_msaa->modified || r_clear->modified || vk_picmip->modified || + vk_validation->modified || vk_texturemode->modified || vk_lmaptexturemode->modified || + vk_aniso->modified || vk_mip_nearfilter->modified || vk_sampleshading->modified || + r_vsync->modified || vk_device_idx->modified || vk_overbrightbits->modified) + { + if (vk_texturemode->modified || vk_lmaptexturemode->modified || vk_aniso->modified) + { + if (vk_texturemode->modified || vk_aniso->modified) + { + Vk_TextureMode(vk_texturemode->string); + vk_texturemode->modified = false; + } + if (vk_lmaptexturemode->modified || vk_aniso->modified) + { + Vk_LmapTextureMode(vk_lmaptexturemode->string); + vk_lmaptexturemode->modified = false; + } + + vk_aniso->modified = false; + } + } + + if (QVk_BeginFrame(&vk_viewport, &vk_scissor) != VK_SUCCESS) + vk_restartNeeded = true; + else + QVk_BeginRenderpass(RP_WORLD); +} + +/* +===================== +RE_EndFrame +===================== +*/ +static void +RE_EndFrame( void ) +{ + if (QVk_EndFrame(false) != VK_SUCCESS) + vk_restartNeeded = true; + + // world has not rendered yet + world_rendered = false; + + /* Part two of the 'maximum extent size may be 0x0' + * work around. See the explanation in RE_BeginFrame() + * for details. */ + if (vk_restartNeeded) + { + if (QVk_CheckExtent()) + { + QVk_Restart(); + vk_restartNeeded = false; + } + } +} + +/* +============= +RE_SetPalette +============= +*/ +unsigned r_rawpalette[256]; + +static void +RE_SetPalette (const unsigned char *palette) +{ + int i; + + byte *rp = (byte *)r_rawpalette; + + if (palette) + { + for (i = 0; i < 256; i++) + { + rp[i * 4 + 0] = palette[i * 3 + 0]; + rp[i * 4 + 1] = palette[i * 3 + 1]; + rp[i * 4 + 2] = palette[i * 3 + 2]; + rp[i * 4 + 3] = 0xff; + } + } + else + { + for (i = 0; i < 256; i++) + { + rp[i * 4 + 0] = d_8to24table[i] & 0xff; + rp[i * 4 + 1] = (d_8to24table[i] >> 8) & 0xff; + rp[i * 4 + 2] = (d_8to24table[i] >> 16) & 0xff; + rp[i * 4 + 3] = 0xff; + } + } +} + +/* +** R_DrawBeam +*/ +void R_DrawBeam( entity_t *currententity ) +{ +#define NUM_BEAM_SEGS 6 + + int i; + float r, g, b; + + vec3_t perpvec; + vec3_t direction, normalized_direction; + vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS]; + vec3_t oldorigin, origin; + + oldorigin[0] = currententity->oldorigin[0]; + oldorigin[1] = currententity->oldorigin[1]; + oldorigin[2] = currententity->oldorigin[2]; + + origin[0] = currententity->origin[0]; + origin[1] = currententity->origin[1]; + origin[2] = currententity->origin[2]; + + normalized_direction[0] = direction[0] = oldorigin[0] - origin[0]; + normalized_direction[1] = direction[1] = oldorigin[1] - origin[1]; + normalized_direction[2] = direction[2] = oldorigin[2] - origin[2]; + + if (VectorNormalize(normalized_direction) == 0) + return; + + PerpendicularVector(perpvec, normalized_direction); + VectorScale(perpvec, currententity->frame / 2, perpvec); + + for (i = 0; i < 6; i++) + { + RotatePointAroundVector(start_points[i], normalized_direction, perpvec, (360.0 / NUM_BEAM_SEGS)*i); + VectorAdd(start_points[i], origin, start_points[i]); + VectorAdd(start_points[i], direction, end_points[i]); + } + + r = (d_8to24table[currententity->skinnum & 0xFF]) & 0xFF; + g = (d_8to24table[currententity->skinnum & 0xFF] >> 8) & 0xFF; + b = (d_8to24table[currententity->skinnum & 0xFF] >> 16) & 0xFF; + + r *= 1 / 255.0F; + g *= 1 / 255.0F; + b *= 1 / 255.0F; + + float color[4] = { r, g, b, currententity->alpha }; + + struct { + float v[3]; + } beamvertex[NUM_BEAM_SEGS*4]; + + for (i = 0; i < NUM_BEAM_SEGS; i++) + { + int idx = i * 4; + beamvertex[idx].v[0] = start_points[i][0]; + beamvertex[idx].v[1] = start_points[i][1]; + beamvertex[idx].v[2] = start_points[i][2]; + + beamvertex[idx + 1].v[0] = end_points[i][0]; + beamvertex[idx + 1].v[1] = end_points[i][1]; + beamvertex[idx + 1].v[2] = end_points[i][2]; + + beamvertex[idx + 2].v[0] = start_points[(i + 1) % NUM_BEAM_SEGS][0]; + beamvertex[idx + 2].v[1] = start_points[(i + 1) % NUM_BEAM_SEGS][1]; + beamvertex[idx + 2].v[2] = start_points[(i + 1) % NUM_BEAM_SEGS][2]; + + beamvertex[idx + 3].v[0] = end_points[(i + 1) % NUM_BEAM_SEGS][0]; + beamvertex[idx + 3].v[1] = end_points[(i + 1) % NUM_BEAM_SEGS][1]; + beamvertex[idx + 3].v[2] = end_points[(i + 1) % NUM_BEAM_SEGS][2]; + } + + QVk_BindPipeline(&vk_drawBeamPipeline); + + VkBuffer vbo; + VkDeviceSize vboOffset; + uint32_t uboOffset; + VkDescriptorSet uboDescriptorSet; + uint8_t *vertData = QVk_GetVertexBuffer(sizeof(beamvertex), &vbo, &vboOffset); + uint8_t *uboData = QVk_GetUniformBuffer(sizeof(color), &uboOffset, &uboDescriptorSet); + memcpy(vertData, beamvertex, sizeof(beamvertex)); + memcpy(uboData, color, sizeof(color)); + + vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vk_drawBeamPipeline.layout, 0, 1, &uboDescriptorSet, 1, &uboOffset); + vkCmdBindVertexBuffers(vk_activeCmdbuffer, 0, 1, &vbo, &vboOffset); + vkCmdDraw(vk_activeCmdbuffer, NUM_BEAM_SEGS * 4, 1, 0, 0); +} + +//=================================================================== + +static int +RE_InitContext(void *win) +{ + char title[40] = {0}; + + SDL_Window *window = (SDL_Window *)win; + + if(window == NULL) + { + R_Printf(PRINT_ALL, "%s() must not be called with NULL argument!", __func__); + return false; + } + + /* Window title - set here so we can display renderer name in it */ + snprintf(title, sizeof(title), "Yamagi Quake II %s - Vulkan Render", YQ2VERSION); + SDL_SetWindowTitle(window, title); + + // window is ready, initialize Vulkan now + QVk_SetWindow(window); + if (!QVk_Init()) + { + R_Printf(PRINT_ALL, "%s() - could not initialize Vulkan!\n", __func__); + return false; + } + + QVk_PostInit(); + + return true; +} + +qboolean Vkimp_CreateSurface(SDL_Window *window) +{ + if (!SDL_Vulkan_CreateSurface(window, vk_instance, &vk_surface)) + { + R_Printf(PRINT_ALL, "%s() SDL_Vulkan_CreateSurface failed: %s", + __func__, SDL_GetError()); + return false; + } + return true; +} + +static qboolean +RE_IsVsyncActive(void) +{ + if (r_vsync->value) + { + return true; + } + else + { + return false; + } +} + +static int RE_PrepareForWindow(void) +{ + if (SDL_Vulkan_LoadLibrary(NULL)) + { + R_Printf(PRINT_ALL, "%s() Loader import failed: %s", __func__, SDL_GetError()); + } + + volkInitializeCustom(SDL_Vulkan_GetVkGetInstanceProcAddr()); + + return SDL_WINDOW_VULKAN; +} + +/* +=============== +GetRefAPI +=============== +*/ +Q2_DLL_EXPORTED refexport_t +GetRefAPI(refimport_t imp) +{ + refexport_t refexport = {0}; + + ri = imp; + + refexport.api_version = API_VERSION; + + refexport.BeginRegistration = RE_BeginRegistration; + refexport.RegisterModel = RE_RegisterModel; + refexport.RegisterSkin = RE_RegisterSkin; + refexport.DrawFindPic = RE_Draw_FindPic; + refexport.SetSky = RE_SetSky; + refexport.EndRegistration = RE_EndRegistration; + + refexport.RenderFrame = RE_RenderFrame; + + refexport.DrawGetPicSize = RE_Draw_GetPicSize; + refexport.DrawPicScaled = RE_Draw_PicScaled; + refexport.DrawStretchPic = RE_Draw_StretchPic; + refexport.DrawCharScaled = RE_Draw_CharScaled; + refexport.DrawTileClear = RE_Draw_TileClear; + refexport.DrawFill = RE_Draw_Fill; + refexport.DrawFadeScreen= RE_Draw_FadeScreen; + + refexport.DrawStretchRaw = RE_Draw_StretchRaw; + + refexport.Init = RE_Init; + refexport.IsVSyncActive = RE_IsVsyncActive; + refexport.Shutdown = RE_Shutdown; + refexport.InitContext = RE_InitContext; + refexport.ShutdownContext = RE_ShutdownContext; + refexport.PrepareForWindow = RE_PrepareForWindow; + + refexport.SetPalette = RE_SetPalette; + refexport.BeginFrame = RE_BeginFrame; + refexport.EndWorldRenderpass = RE_EndWorldRenderpass; + refexport.EndFrame = RE_EndFrame; + + // Tell the client that we're unsing the + // new renderer restart API. + ri.Vid_RequestRestart(RESTART_NO); + + Swap_Init (); + + return refexport; +} + +// this is only here so the functions in q_shared.c and q_shwin.c can link +void R_Printf(int level, const char* msg, ...) +{ + va_list argptr; + va_start(argptr, msg); + ri.Com_VPrintf(level, msg, argptr); + va_end(argptr); +} + +void +Sys_Error (char *error, ...) +{ + va_list argptr; + char text[4096]; // MAXPRINTMSG == 4096 + + va_start(argptr, error); + vsnprintf(text, sizeof(text), error, argptr); + va_end(argptr); + + ri.Sys_Error (ERR_FATAL, "%s", text); +} + +void +Com_Printf (char *msg, ...) +{ + va_list argptr; + va_start(argptr, msg); + ri.Com_VPrintf(PRINT_ALL, msg, argptr); + va_end(argptr); +} diff --git a/src/vk/vk_rmisc.c b/src/vk/vk_rmisc.c new file mode 100644 index 0000000..b9cbf4c --- /dev/null +++ b/src/vk/vk_rmisc.c @@ -0,0 +1,325 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. +Copyright (C) 2018-2019 Krzysztof Kondrak + +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. +*/ + +// vk_misc.c + +#include "header/local.h" + +/* +================== +RE_InitParticleTexture +================== +*/ +static byte dottexture[8][8] = +{ + {0,0,0,0,0,0,0,0}, + {0,0,1,1,0,0,0,0}, + {0,1,1,1,1,0,0,0}, + {0,1,1,1,1,0,0,0}, + {0,0,1,1,0,0,0,0}, + {0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0}, +}; + +void RE_InitParticleTexture (void) +{ + int x,y,i; + byte data[8][8][4]; + + // + // particle texture + // + for (x=0 ; x<8 ; x++) + { + for (y=0 ; y<8 ; y++) + { + data[y][x][0] = 255; + data[y][x][1] = 255; + data[y][x][2] = 255; + data[y][x][3] = dottexture[x][y]*255; + } + } + r_particletexture = Vk_LoadPic("***particle***", (byte *)data, + 8, 8, 8, 8, it_sprite, 32); + + // + // particle texture + // + for (x=0 ; x<8 ; x++) + { + for (y=0 ; y<8 ; y++) + { + for (i=0 ; i<4 ; i++) + { + data[y][x][i] = ((y < 4) && (x < 4)) ? 255 : 0; + } + } + } + r_squaretexture = Vk_LoadPic("***square***", (byte *)data, + 8, 8, 8, 8, it_sprite, 32); + + // + // also use this for bad textures, but without alpha + // + for (x=0 ; x<8 ; x++) + { + for (y=0 ; y<8 ; y++) + { + data[y][x][0] = dottexture[x&3][y&3]*255; + data[y][x][1] = 0; + data[y][x][2] = 0; + data[y][x][3] = 255; + } + } + r_notexture = Vk_LoadPic("***r_notexture***", (byte *)data, + 8, 8, 8, 8, it_wall, 32); +} + + +/* +============================================================================== + + SCREEN SHOTS + +============================================================================== +*/ + +/* +================== +Vk_ScreenShot_f +================== +*/ +void Vk_ScreenShot_f (void) +{ + byte *buffer; + int i; + size_t buffSize = vid.width * vid.height * 4; + + if (!vk_device.screenshotSupported) + { + R_Printf(PRINT_ALL, "%s: Screenshots are not supported by this GPU.\n", __func__); + return; + } + + buffer = malloc(buffSize); + + VkExtent2D extent = { + .width = (uint32_t)(vid.width), + .height = (uint32_t)(vid.height), + }; + VkOffset2D offset = { + .x = (int32_t)((vk_swapchain.extent.width - extent.width) / 2u), + .y = (int32_t)((vk_swapchain.extent.height - extent.height) / 2u), + }; + + QVk_ReadPixels(buffer, &offset, &extent); + + // swap rgb to bgr + if (vk_swapchain.format == VK_FORMAT_R8G8B8A8_UNORM || + vk_swapchain.format == VK_FORMAT_R8G8B8A8_SRGB) + { + for (i = 0; i < buffSize; i += 4) + { + buffer[i + 3] = 255; + } + } + else + { + for (i = 0; i < buffSize; i += 4) + { + int temp; + + temp = buffer[i]; + buffer[i] = buffer[i + 2]; + buffer[i + 2] = temp; + buffer[i + 3] = 255; // alpha component + } + } + + ri.Vid_WriteScreenshot(vid.width, vid.height, 4, buffer); + + free(buffer); +} + +/* +** Vk_Strings_f +*/ +void Vk_Strings_f(void) +{ + int i = 0; + + uint32_t numDevices = 0; + int usedDevice = 0; + VkPhysicalDevice *physicalDevices; + VkPhysicalDeviceProperties deviceProperties; + int preferredDevice = (int)vk_device_idx->value; + int msaa = (int)vk_msaa->value; + uint32_t driverMajor = VK_VERSION_MAJOR(vk_device.properties.driverVersion); + uint32_t driverMinor = VK_VERSION_MINOR(vk_device.properties.driverVersion); + uint32_t driverPatch = VK_VERSION_PATCH(vk_device.properties.driverVersion); + + // NVIDIA driver version decoding scheme + if (vk_device.properties.vendorID == 0x10DE) + { + driverMajor = ((uint32_t)(vk_device.properties.driverVersion) >> 22) & 0x3ff; + driverMinor = ((uint32_t)(vk_device.properties.driverVersion) >> 14) & 0x0ff; + + uint32_t secondary = ((uint32_t)(vk_device.properties.driverVersion) >> 6) & 0x0ff; + uint32_t tertiary = vk_device.properties.driverVersion & 0x03f; + + driverPatch = (secondary << 8) | tertiary; + } + + VK_VERIFY(vkEnumeratePhysicalDevices(vk_instance, &numDevices, NULL)); + if (!numDevices) + { + return; + } + physicalDevices = malloc(sizeof(VkPhysicalDevice) * numDevices); + if (!physicalDevices) + { + return; + } + VK_VERIFY(vkEnumeratePhysicalDevices(vk_instance, &numDevices, physicalDevices)); + + if (preferredDevice >= numDevices) + { + preferredDevice = -1; + } + + R_Printf(PRINT_ALL, "------------------------------------\n"); + R_Printf(PRINT_ALL, "Vulkan API: %d.%d\n", VK_VERSION_MAJOR(vk_config.vk_version), + VK_VERSION_MINOR(vk_config.vk_version)); + R_Printf(PRINT_ALL, "Header version: %d\n", VK_HEADER_VERSION); + R_Printf(PRINT_ALL, "Devices found:\n"); + for (i = 0; i < numDevices; ++i) + { + qboolean isPreferred = false; + + vkGetPhysicalDeviceProperties(physicalDevices[i], &deviceProperties); + isPreferred = (preferredDevice == i) || ( + preferredDevice < 0 && + deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU + ); + if (isPreferred) { + usedDevice = i; + } + R_Printf(PRINT_ALL, "%s#%d: %s\n", + isPreferred && numDevices > 1 ? "* " : " ", + i, deviceProperties.deviceName); + } + free(physicalDevices); + + R_Printf(PRINT_ALL, "Using device #%d:\n", usedDevice); + R_Printf(PRINT_ALL, " deviceName: %s\n", vk_device.properties.deviceName); + R_Printf(PRINT_ALL, " resolution: %dx%d", vid.width, vid.height); + if (msaa > 0) + { + R_Printf(PRINT_ALL, " (MSAAx%d)\n", msaa); + } + else + { + R_Printf(PRINT_ALL, "\n"); + } +#ifndef __linux__ + // Intel on Windows and MacOS (Linux uses semver for Mesa drivers) + if (vk_device.properties.vendorID == 0x8086) + { + R_Printf(PRINT_ALL, " driverVersion: %d (0x%X)\n", + vk_device.properties.driverVersion, + vk_device.properties.driverVersion); + } + else +#endif + { + R_Printf(PRINT_ALL, " driverVersion: %d.%d.%d (0x%X)\n", + driverMajor, driverMinor, driverPatch, + vk_device.properties.driverVersion); + } + + R_Printf(PRINT_ALL, " apiVersion: %d.%d.%d\n", + VK_VERSION_MAJOR(vk_device.properties.apiVersion), + VK_VERSION_MINOR(vk_device.properties.apiVersion), + VK_VERSION_PATCH(vk_device.properties.apiVersion)); + R_Printf(PRINT_ALL, " deviceID: %d\n", vk_device.properties.deviceID); + R_Printf(PRINT_ALL, " vendorID: 0x%X (%s)\n", + vk_device.properties.vendorID, vk_config.vendor_name); + R_Printf(PRINT_ALL, " deviceType: %s\n", vk_config.device_type); + R_Printf(PRINT_ALL, " gfx/present/transfer: %d/%d/%d\n", + vk_device.gfxFamilyIndex, + vk_device.presentFamilyIndex, + vk_device.transferFamilyIndex); + R_Printf(PRINT_ALL, "Present mode: %s\n", vk_config.present_mode); + R_Printf(PRINT_ALL, "Swapchain image format: %d\n", vk_swapchain.format); + + R_Printf(PRINT_ALL, "Supported present modes: "); + i = 0; + while(vk_config.supported_present_modes[i]) + { + R_Printf(PRINT_ALL, "%s ", vk_config.supported_present_modes[i++]); + } + R_Printf(PRINT_ALL, "\n"); + + R_Printf(PRINT_ALL, "Enabled extensions: "); + i = 0; + while(vk_config.extensions[i]) + { + R_Printf(PRINT_ALL, "%s ", vk_config.extensions[i++]); + } + R_Printf(PRINT_ALL, "\n"); + + R_Printf(PRINT_ALL, "Enabled layers: "); + i = 0; + while(vk_config.layers[i]) + { + R_Printf(PRINT_ALL, "%s ", vk_config.layers[i++]); + } + R_Printf(PRINT_ALL, "\n"); +} + +/* +** Vk_Mem_f +*/ +void Vk_Mem_f(void) +{ + R_Printf(PRINT_ALL, "\nDynamic buffer stats: \n"); + R_Printf(PRINT_ALL, "Vertex : %u/%ukB (%.1f%% max: %ukB)\n", + vk_config.vertex_buffer_usage / 1024, + vk_config.vertex_buffer_size / 1024, + 100.f * vk_config.vertex_buffer_usage / vk_config.vertex_buffer_size, + vk_config.vertex_buffer_max_usage / 1024); + + R_Printf(PRINT_ALL, "Index : %u/%uB (%.1f%% max: %uB)\n", + vk_config.index_buffer_usage, + vk_config.index_buffer_size, + 100.f * vk_config.index_buffer_usage / vk_config.index_buffer_size, + vk_config.index_buffer_max_usage); + R_Printf(PRINT_ALL, "Uniform: %u/%ukB (%.1f%% max: %ukB)\n", + vk_config.uniform_buffer_usage / 1024, + vk_config.uniform_buffer_size / 1024, + 100.f * vk_config.uniform_buffer_usage / vk_config.uniform_buffer_size, + vk_config.uniform_buffer_max_usage / 1024); + R_Printf(PRINT_ALL, "Triangle index: %u/%u (%.1f%% max: %u)\n", + vk_config.triangle_index_usage, + vk_config.triangle_index_count, + 100.f * vk_config.triangle_index_usage / vk_config.triangle_index_count, + vk_config.triangle_index_max_usage); +} diff --git a/src/vk/vk_rsurf.c b/src/vk/vk_rsurf.c new file mode 100644 index 0000000..97b5679 --- /dev/null +++ b/src/vk/vk_rsurf.c @@ -0,0 +1,1324 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. +Copyright (C) 2018-2019 Krzysztof Kondrak + +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. +*/ + +// vk_rsurf.c: surface-related refresh code +#include + +#include "header/local.h" + +static vec3_t modelorg; // relative to viewpoint + +msurface_t *r_alpha_surfaces; + +#define DYNAMIC_LIGHT_WIDTH 128 +#define DYNAMIC_LIGHT_HEIGHT 128 + +#define LIGHTMAP_BYTES 4 + +#define BLOCK_WIDTH 128 +#define BLOCK_HEIGHT 128 + +int c_visible_lightmaps; +int c_visible_textures; + +typedef struct +{ + int current_lightmap_texture; + + msurface_t *lightmap_surfaces[MAX_LIGHTMAPS]; + + int allocated[BLOCK_WIDTH]; + + // the lightmap texture data needs to be kept in + // main memory so texsubimage can update properly + byte lightmap_buffer[4*BLOCK_WIDTH*BLOCK_HEIGHT]; +} vklightmapstate_t; + +static vklightmapstate_t vk_lms; + + +static void LM_InitBlock( void ); +static void LM_UploadBlock( qboolean dynamic ); +static qboolean LM_AllocBlock (int w, int h, int *x, int *y); + +extern void R_SetCacheState( msurface_t *surf ); +extern void R_BuildLightMap (msurface_t *surf, byte *dest, int stride); + +/* +============================================================= + + BRUSH MODELS + +============================================================= +*/ + +/* +=============== +R_TextureAnimation + +Returns the proper texture for a given time and base texture +=============== +*/ +static image_t *R_TextureAnimation (mtexinfo_t *tex, entity_t *currententity) +{ + int c; + + if (!tex->next) + return tex->image; + + c = currententity->frame % tex->numframes; + while (c) + { + tex = tex->next; + c--; + } + + return tex->image; +} + +/* +================ +DrawVkPoly +================ +*/ +static void DrawVkPoly (vkpoly_t *p, image_t *texture, float *color) +{ + int i; + float *v; + + if (Mesh_VertsRealloc(p->numverts)) + { + ri.Sys_Error(ERR_FATAL, "%s: can't allocate memory", __func__); + } + + v = p->verts[0]; + for (i = 0; i < p->numverts; i++, v += VERTEXSIZE) + { + verts_buffer[i].vertex[0] = v[0]; + verts_buffer[i].vertex[1] = v[1]; + verts_buffer[i].vertex[2] = v[2]; + verts_buffer[i].texCoord[0] = v[3]; + verts_buffer[i].texCoord[1] = v[4]; + } + + QVk_BindPipeline(&vk_drawPolyPipeline); + + VkBuffer vbo; + VkDeviceSize vboOffset; + uint32_t uboOffset; + VkDescriptorSet uboDescriptorSet; + uint8_t *vertData = QVk_GetVertexBuffer(sizeof(polyvert_t) * p->numverts, &vbo, &vboOffset); + uint8_t *uboData = QVk_GetUniformBuffer(sizeof(float) * 4, &uboOffset, &uboDescriptorSet); + memcpy(vertData, verts_buffer, sizeof(polyvert_t) * p->numverts); + memcpy(uboData, color, sizeof(float) * 4); + + VkDescriptorSet descriptorSets[] = { texture->vk_texture.descriptorSet, uboDescriptorSet }; + + float gamma = 2.1F - vid_gamma->value; + + vkCmdPushConstants(vk_activeCmdbuffer, vk_drawTexQuadPipeline[vk_state.current_renderpass].layout, + VK_SHADER_STAGE_FRAGMENT_BIT, 17 * sizeof(float), sizeof(gamma), &gamma); + + vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vk_drawPolyPipeline.layout, 0, 2, descriptorSets, 1, &uboOffset); + vkCmdBindVertexBuffers(vk_activeCmdbuffer, 0, 1, &vbo, &vboOffset); + vkCmdBindIndexBuffer(vk_activeCmdbuffer, QVk_GetTriangleFanIbo((p->numverts - 2) * 3), 0, VK_INDEX_TYPE_UINT16); + vkCmdDrawIndexed(vk_activeCmdbuffer, (p->numverts - 2) * 3, 1, 0, 0, 0); +} + +//============ +//PGM +/* +================ +DrawVkFlowingPoly -- version of DrawVkPoly that handles scrolling texture +================ +*/ +static void DrawVkFlowingPoly (msurface_t *fa, image_t *texture, float *color) +{ + int i; + float *v; + vkpoly_t *p; + float scroll; + + p = fa->polys; + + scroll = -64 * ((r_newrefdef.time / 40.0) - (int)(r_newrefdef.time / 40.0)); + if (scroll == 0.0) + scroll = -64.0; + + if (Mesh_VertsRealloc(p->numverts)) + { + ri.Sys_Error(ERR_FATAL, "%s: can't allocate memory", __func__); + } + + v = p->verts[0]; + for (i = 0; i < p->numverts; i++, v += VERTEXSIZE) + { + verts_buffer[i].vertex[0] = v[0]; + verts_buffer[i].vertex[1] = v[1]; + verts_buffer[i].vertex[2] = v[2]; + verts_buffer[i].texCoord[0] = v[3] + scroll; + verts_buffer[i].texCoord[1] = v[4]; + } + + QVk_BindPipeline(&vk_drawPolyPipeline); + + VkBuffer vbo; + VkDeviceSize vboOffset; + uint32_t uboOffset; + VkDescriptorSet uboDescriptorSet; + uint8_t *vertData = QVk_GetVertexBuffer(sizeof(polyvert_t) * p->numverts, &vbo, &vboOffset); + uint8_t *uboData = QVk_GetUniformBuffer(sizeof(float) * 4, &uboOffset, &uboDescriptorSet); + memcpy(vertData, verts_buffer, sizeof(polyvert_t) * p->numverts); + memcpy(uboData, color, sizeof(float) * 4); + + VkDescriptorSet descriptorSets[] = { texture->vk_texture.descriptorSet, uboDescriptorSet }; + + float gamma = 2.1F - vid_gamma->value; + + vkCmdPushConstants(vk_activeCmdbuffer, vk_drawTexQuadPipeline[vk_state.current_renderpass].layout, + VK_SHADER_STAGE_FRAGMENT_BIT, 17 * sizeof(float), sizeof(gamma), &gamma); + + vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vk_drawPolyPipeline.layout, 0, 2, descriptorSets, 1, &uboOffset); + vkCmdBindVertexBuffers(vk_activeCmdbuffer, 0, 1, &vbo, &vboOffset); + vkCmdBindIndexBuffer(vk_activeCmdbuffer, QVk_GetTriangleFanIbo((p->numverts - 2) * 3), 0, VK_INDEX_TYPE_UINT16); + vkCmdDrawIndexed(vk_activeCmdbuffer, (p->numverts - 2) * 3, 1, 0, 0, 0); +} +//PGM +//============ + +/* +** R_DrawTriangleOutlines +*/ +static void R_DrawTriangleOutlines (void) +{ + int i, j, k; + vkpoly_t *p; + + if (!vk_showtris->value) + return; + + VkBuffer vbo; + VkDeviceSize vboOffset; + float color[3] = { 1.f, 1.f, 1.f }; + struct { + vec3_t v; + float color[3]; + } triVert[4]; + + QVk_BindPipeline(&vk_showTrisPipeline); + uint32_t uboOffset; + VkDescriptorSet uboDescriptorSet; + uint8_t *uboData = QVk_GetUniformBuffer(sizeof(r_viewproj_matrix), &uboOffset, &uboDescriptorSet); + memcpy(uboData, r_viewproj_matrix, sizeof(r_viewproj_matrix)); + vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vk_showTrisPipeline.layout, 0, 1, &uboDescriptorSet, 1, &uboOffset); + + for (i = 0; i < MAX_LIGHTMAPS; i++) + { + msurface_t *surf; + + for (surf = vk_lms.lightmap_surfaces[i]; surf != 0; surf = surf->lightmapchain) + { + p = surf->polys; + for (; p; p = p->chain) + { + for (j = 2, k = 0; j < p->numverts; j++, k++) + { + triVert[0].v[0] = p->verts[0][0]; + triVert[0].v[1] = p->verts[0][1]; + triVert[0].v[2] = p->verts[0][2]; + memcpy(triVert[0].color, color, sizeof(color)); + + triVert[1].v[0] = p->verts[j - 1][0]; + triVert[1].v[1] = p->verts[j - 1][1]; + triVert[1].v[2] = p->verts[j - 1][2]; + memcpy(triVert[1].color, color, sizeof(color)); + + triVert[2].v[0] = p->verts[j][0]; + triVert[2].v[1] = p->verts[j][1]; + triVert[2].v[2] = p->verts[j][2]; + memcpy(triVert[2].color, color, sizeof(color)); + + triVert[3].v[0] = p->verts[0][0]; + triVert[3].v[1] = p->verts[0][1]; + triVert[3].v[2] = p->verts[0][2]; + memcpy(triVert[3].color, color, sizeof(color)); + + uint8_t *vertData = QVk_GetVertexBuffer(sizeof(triVert), &vbo, &vboOffset); + memcpy(vertData, triVert, sizeof(triVert)); + + vkCmdBindVertexBuffers(vk_activeCmdbuffer, 0, 1, &vbo, &vboOffset); + vkCmdDraw(vk_activeCmdbuffer, 4, 1, 0, 0); + } + } + } + } +} + +/* +================ +R_RenderBrushPoly +================ +*/ +static void R_RenderBrushPoly (msurface_t *fa, float *modelMatrix, float alpha, entity_t *currententity) +{ + int maps; + image_t *image; + qboolean is_dynamic = false; + float color[4] = { 1.f, 1.f, 1.f, alpha }; + c_brush_polys++; + + image = R_TextureAnimation(fa->texinfo, currententity); + + if (fa->flags & SURF_DRAWTURB) + { + color[0] = color[1] = color[2] = vk_state.inverse_intensity; + color[3] = 1.f; + // warp texture, no lightmaps + EmitWaterPolys(fa, image, modelMatrix, color, alpha == 1.f); + return; + } + + //====== + //PGM + if (fa->texinfo->flags & SURF_FLOWING) + DrawVkFlowingPoly(fa, image, color); + else + DrawVkPoly(fa->polys, image, color); + //PGM + //====== + + /* + ** check for lightmap modification + */ + for (maps = 0; maps < MAXLIGHTMAPS && fa->styles[maps] != 255; maps++) + { + if (r_newrefdef.lightstyles[fa->styles[maps]].white != fa->cached_light[maps]) + goto dynamic; + } + + // dynamic this frame or dynamic previously + if (fa->dlightframe == r_framecount) + { + dynamic: + if (vk_dynamic->value) + { + if (!(fa->texinfo->flags & (SURF_SKY | SURF_TRANS33 | SURF_TRANS66 | SURF_WARP))) + { + is_dynamic = true; + } + } + } + + if (is_dynamic) + { + if ((fa->styles[maps] >= 32 || fa->styles[maps] == 0) && (fa->dlightframe != r_framecount)) + { + unsigned temp[34 * 34]; + int smax, tmax; + + smax = (fa->extents[0] >> 4) + 1; + tmax = (fa->extents[1] >> 4) + 1; + + R_BuildLightMap(fa, (void *)temp, smax * 4); + R_SetCacheState(fa); + + QVk_UpdateTextureData(&vk_state.lightmap_textures[fa->lightmaptexturenum], (unsigned char*)temp, fa->light_s, fa->light_t, smax, tmax); + + fa->lightmapchain = vk_lms.lightmap_surfaces[fa->lightmaptexturenum]; + vk_lms.lightmap_surfaces[fa->lightmaptexturenum] = fa; + } + else + { + fa->lightmapchain = vk_lms.lightmap_surfaces[0]; + vk_lms.lightmap_surfaces[0] = fa; + } + } + else + { + fa->lightmapchain = vk_lms.lightmap_surfaces[fa->lightmaptexturenum]; + vk_lms.lightmap_surfaces[fa->lightmaptexturenum] = fa; + } +} + + +/* +================ +R_DrawAlphaSurfaces + +Draw water surfaces and windows. +The BSP tree is waled front to back, so unwinding the chain +of alpha_surfaces will draw back to front, giving proper ordering. +================ +*/ +void R_DrawAlphaSurfaces (void) +{ + msurface_t *s; + float intens; + + // the textures are prescaled up for a better lighting range, + // so scale it back down + intens = vk_state.inverse_intensity; + float color[4] = { intens, intens, intens, 1.f }; + + for (s = r_alpha_surfaces; s; s = s->texturechain) + { + c_brush_polys++; + if (s->texinfo->flags & SURF_TRANS33) + color[3] = 0.33f; + else if (s->texinfo->flags & SURF_TRANS66) + color[3] = 0.66f; + + if (s->flags & SURF_DRAWTURB) + EmitWaterPolys(s, s->texinfo->image, NULL, color, false); + else if (s->texinfo->flags & SURF_FLOWING) // PGM 9/16/98 + DrawVkFlowingPoly(s, s->texinfo->image, color); // PGM + else + DrawVkPoly(s->polys, s->texinfo->image, color); + } + + r_alpha_surfaces = NULL; +} + +/* +================ +DrawTextureChains + +Draw world surfaces (mostly solid with alpha == 1.f) +================ +*/ +static void DrawTextureChains (entity_t *currententity) +{ + int i; + msurface_t *s; + image_t *image; + + c_visible_textures = 0; + + for (i = 0, image = vktextures; i < numvktextures; i++, image++) + { + if (!image->registration_sequence) + continue; + if (!image->texturechain) + continue; + c_visible_textures++; + + for (s = image->texturechain; s; s = s->texturechain) + { + if (!(s->flags & SURF_DRAWTURB)) + R_RenderBrushPoly(s, NULL, 1.f, currententity); + } + } + + for (i = 0, image = vktextures; i < numvktextures; i++, image++) + { + if (!image->registration_sequence) + continue; + s = image->texturechain; + if (!s) + continue; + + for (; s; s = s->texturechain) + { + if (s->flags & SURF_DRAWTURB) + R_RenderBrushPoly(s, NULL, 1.f, currententity); + } + + image->texturechain = NULL; + } +} + + +static void Vk_RenderLightmappedPoly( msurface_t *surf, float *modelMatrix, float alpha, entity_t *currententity ) +{ + int i, nv = surf->polys->numverts; + int map; + float *v; + image_t *image = R_TextureAnimation(surf->texinfo, currententity); + qboolean is_dynamic = false; + unsigned lmtex = surf->lightmaptexturenum; + vkpoly_t *p; + + struct { + float model[16]; + float viewLightmaps; + } lmapPolyUbo; + + lmapPolyUbo.viewLightmaps = vk_lightmap->value ? 1.f : 0.f; + + if (modelMatrix) + { + memcpy(lmapPolyUbo.model, modelMatrix, sizeof(float) * 16); + } + else + { + Mat_Identity(lmapPolyUbo.model); + } + + QVk_BindPipeline(&vk_drawPolyLmapPipeline); + + uint32_t uboOffset; + VkDescriptorSet uboDescriptorSet; + uint8_t *uboData = QVk_GetUniformBuffer(sizeof(lmapPolyUbo), &uboOffset, &uboDescriptorSet); + memcpy(uboData, &lmapPolyUbo, sizeof(lmapPolyUbo)); + + for (map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255; map++) + { + if (r_newrefdef.lightstyles[surf->styles[map]].white != surf->cached_light[map]) + goto dynamic; + } + + // dynamic this frame or dynamic previously + if (surf->dlightframe == r_framecount) + { + dynamic: + if (vk_dynamic->value) + { + if (!(surf->texinfo->flags & (SURF_SKY | SURF_TRANS33 | SURF_TRANS66 | SURF_WARP))) + { + is_dynamic = true; + } + } + } + + if (Mesh_VertsRealloc(nv)) + { + ri.Sys_Error(ERR_FATAL, "%s: can't allocate memory", __func__); + } + + if (is_dynamic) + { + unsigned temp[128 * 128]; + int smax, tmax; + + if ((surf->styles[map] >= 32 || surf->styles[map] == 0) && (surf->dlightframe != r_framecount)) + { + smax = (surf->extents[0] >> 4) + 1; + tmax = (surf->extents[1] >> 4) + 1; + + R_BuildLightMap(surf, (void *)temp, smax * 4); + R_SetCacheState(surf); + + lmtex = surf->lightmaptexturenum; + QVk_UpdateTextureData(&vk_state.lightmap_textures[surf->lightmaptexturenum], (unsigned char *)temp, surf->light_s, surf->light_t, smax, tmax); + } + else + { + smax = (surf->extents[0] >> 4) + 1; + tmax = (surf->extents[1] >> 4) + 1; + + R_BuildLightMap(surf, (void *)temp, smax * 4); + + lmtex = surf->lightmaptexturenum + DYNLIGHTMAP_OFFSET; + QVk_UpdateTextureData(&vk_state.lightmap_textures[lmtex], (unsigned char *)temp, surf->light_s, surf->light_t, smax, tmax); + } + + c_brush_polys++; + + //========== + //PGM + if (surf->texinfo->flags & SURF_FLOWING) + { + float scroll; + + scroll = -64 * ((r_newrefdef.time / 40.0) - (int)(r_newrefdef.time / 40.0)); + if (scroll == 0.0) + scroll = -64.0; + + VkBuffer vbo; + VkDeviceSize vboOffset; + VkDescriptorSet descriptorSets[] = { image->vk_texture.descriptorSet, uboDescriptorSet, vk_state.lightmap_textures[lmtex].descriptorSet }; + vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vk_drawPolyLmapPipeline.layout, 0, 3, descriptorSets, 1, &uboOffset); + + for (p = surf->polys; p; p = p->chain) + { + v = p->verts[0]; + for (i = 0; i < nv; i++, v += VERTEXSIZE) + { + lmappolyverts_buffer[i].vertex[0] = v[0]; + lmappolyverts_buffer[i].vertex[1] = v[1]; + lmappolyverts_buffer[i].vertex[2] = v[2]; + lmappolyverts_buffer[i].texCoord[0] = v[3] + scroll; + lmappolyverts_buffer[i].texCoord[1] = v[4]; + lmappolyverts_buffer[i].texCoordLmap[0] = v[5]; + lmappolyverts_buffer[i].texCoordLmap[1] = v[6]; + } + + uint8_t *vertData = QVk_GetVertexBuffer(sizeof(lmappolyvert_t) * nv, &vbo, &vboOffset); + memcpy(vertData, lmappolyverts_buffer, sizeof(lmappolyvert_t) * nv); + + vkCmdBindVertexBuffers(vk_activeCmdbuffer, 0, 1, &vbo, &vboOffset); + vkCmdBindIndexBuffer(vk_activeCmdbuffer, QVk_GetTriangleFanIbo((nv - 2) * 3), 0, VK_INDEX_TYPE_UINT16); + vkCmdDrawIndexed(vk_activeCmdbuffer, (nv - 2) * 3, 1, 0, 0, 0); + } + } + else + { + VkBuffer vbo; + VkDeviceSize vboOffset; + VkDescriptorSet descriptorSets[] = { image->vk_texture.descriptorSet, uboDescriptorSet, vk_state.lightmap_textures[lmtex].descriptorSet }; + vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vk_drawPolyLmapPipeline.layout, 0, 3, descriptorSets, 1, &uboOffset); + + for (p = surf->polys; p; p = p->chain) + { + v = p->verts[0]; + for (i = 0; i < nv; i++, v += VERTEXSIZE) + { + lmappolyverts_buffer[i].vertex[0] = v[0]; + lmappolyverts_buffer[i].vertex[1] = v[1]; + lmappolyverts_buffer[i].vertex[2] = v[2]; + lmappolyverts_buffer[i].texCoord[0] = v[3]; + lmappolyverts_buffer[i].texCoord[1] = v[4]; + lmappolyverts_buffer[i].texCoordLmap[0] = v[5]; + lmappolyverts_buffer[i].texCoordLmap[1] = v[6]; + } + + uint8_t *vertData = QVk_GetVertexBuffer(sizeof(lmappolyvert_t) * nv, &vbo, &vboOffset); + memcpy(vertData, lmappolyverts_buffer, sizeof(lmappolyvert_t) * nv); + + vkCmdBindVertexBuffers(vk_activeCmdbuffer, 0, 1, &vbo, &vboOffset); + vkCmdBindIndexBuffer(vk_activeCmdbuffer, QVk_GetTriangleFanIbo((nv - 2) * 3), 0, VK_INDEX_TYPE_UINT16); + vkCmdDrawIndexed(vk_activeCmdbuffer, (nv - 2) * 3, 1, 0, 0, 0); + } + } + //PGM + //========== + } + else + { + c_brush_polys++; + + //========== + //PGM + if (surf->texinfo->flags & SURF_FLOWING) + { + float scroll; + + scroll = -64 * ((r_newrefdef.time / 40.0) - (int)(r_newrefdef.time / 40.0)); + if (scroll == 0.0) + scroll = -64.0; + + for (p = surf->polys; p; p = p->chain) + { + v = p->verts[0]; + for (i = 0; i < nv; i++, v += VERTEXSIZE) + { + lmappolyverts_buffer[i].vertex[0] = v[0]; + lmappolyverts_buffer[i].vertex[1] = v[1]; + lmappolyverts_buffer[i].vertex[2] = v[2]; + lmappolyverts_buffer[i].texCoord[0] = v[3] + scroll; + lmappolyverts_buffer[i].texCoord[1] = v[4]; + lmappolyverts_buffer[i].texCoordLmap[0] = v[5]; + lmappolyverts_buffer[i].texCoordLmap[1] = v[6]; + } + VkBuffer vbo; + VkDeviceSize vboOffset; + uint8_t *vertData = QVk_GetVertexBuffer(sizeof(lmappolyvert_t) * nv, &vbo, &vboOffset); + memcpy(vertData, lmappolyverts_buffer, sizeof(lmappolyvert_t) * nv); + + VkDescriptorSet descriptorSets[] = { image->vk_texture.descriptorSet, uboDescriptorSet, vk_state.lightmap_textures[lmtex].descriptorSet }; + vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vk_drawPolyLmapPipeline.layout, 0, 3, descriptorSets, 1, &uboOffset); + vkCmdBindVertexBuffers(vk_activeCmdbuffer, 0, 1, &vbo, &vboOffset); + vkCmdBindIndexBuffer(vk_activeCmdbuffer, QVk_GetTriangleFanIbo((nv - 2) * 3), 0, VK_INDEX_TYPE_UINT16); + vkCmdDrawIndexed(vk_activeCmdbuffer, (nv - 2) * 3, 1, 0, 0, 0); + } + } + else + { + //PGM + //========== + for (p = surf->polys; p; p = p->chain) + { + v = p->verts[0]; + for (i = 0; i < nv; i++, v += VERTEXSIZE) + { + lmappolyverts_buffer[i].vertex[0] = v[0]; + lmappolyverts_buffer[i].vertex[1] = v[1]; + lmappolyverts_buffer[i].vertex[2] = v[2]; + lmappolyverts_buffer[i].texCoord[0] = v[3]; + lmappolyverts_buffer[i].texCoord[1] = v[4]; + lmappolyverts_buffer[i].texCoordLmap[0] = v[5]; + lmappolyverts_buffer[i].texCoordLmap[1] = v[6]; + } + VkBuffer vbo; + VkDeviceSize vboOffset; + uint8_t *vertData = QVk_GetVertexBuffer(sizeof(lmappolyvert_t) * nv, &vbo, &vboOffset); + memcpy(vertData, lmappolyverts_buffer, sizeof(lmappolyvert_t) * nv); + + VkDescriptorSet descriptorSets[] = { image->vk_texture.descriptorSet, uboDescriptorSet, vk_state.lightmap_textures[lmtex].descriptorSet }; + vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vk_drawPolyLmapPipeline.layout, 0, 3, descriptorSets, 1, &uboOffset); + vkCmdBindVertexBuffers(vk_activeCmdbuffer, 0, 1, &vbo, &vboOffset); + vkCmdBindIndexBuffer(vk_activeCmdbuffer, QVk_GetTriangleFanIbo((nv - 2) * 3), 0, VK_INDEX_TYPE_UINT16); + vkCmdDrawIndexed(vk_activeCmdbuffer, (nv - 2) * 3, 1, 0, 0, 0); + } + //========== + //PGM + } + //PGM + //========== + } +} + +/* +================= +R_DrawInlineBModel +================= +*/ +static void R_DrawInlineBModel (entity_t *currententity, model_t *currentmodel, float *modelMatrix) +{ + int i; + msurface_t *psurf; + float alpha = 1.f; + + // calculate dynamic lighting for bmodel + if (!vk_flashblend->value) + { + dlight_t *lt; + int k; + + lt = r_newrefdef.dlights; + for (k = 0; knodes + currentmodel->firstnode); + } + } + + psurf = ¤tmodel->surfaces[currentmodel->firstmodelsurface]; + + if (currententity->flags & RF_TRANSLUCENT) + { + alpha = .25f; + } + + // + // draw texture + // + for (i = 0; inummodelsurfaces; i++, psurf++) + { + float dot; + cplane_t *pplane; + + // find which side of the node we are on + pplane = psurf->plane; + + dot = DotProduct(modelorg, pplane->normal) - pplane->dist; + + // draw the polygon + if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || + (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) + { + if (psurf->texinfo->flags & (SURF_TRANS33 | SURF_TRANS66)) + { // add to the translucent chain + psurf->texturechain = r_alpha_surfaces; + r_alpha_surfaces = psurf; + } + else if (!(psurf->flags & SURF_DRAWTURB) && !vk_showtris->value) + { + Vk_RenderLightmappedPoly(psurf, modelMatrix, alpha, currententity); + } + else + { + R_RenderBrushPoly(psurf, modelMatrix, alpha, currententity); + } + } + } +} + +/* +================= +R_DrawBrushModel +================= +*/ +void R_DrawBrushModel (entity_t *currententity, model_t *currentmodel) +{ + vec3_t mins, maxs; + qboolean rotated; + + if (currentmodel->nummodelsurfaces == 0) + return; + + if (currententity->angles[0] || currententity->angles[1] || currententity->angles[2]) + { + int i; + + rotated = true; + for (i = 0; i<3; i++) + { + mins[i] = currententity->origin[i] - currentmodel->radius; + maxs[i] = currententity->origin[i] + currentmodel->radius; + } + } + else + { + rotated = false; + VectorAdd(currententity->origin, currentmodel->mins, mins); + VectorAdd(currententity->origin, currentmodel->maxs, maxs); + } + + if (R_CullBox(mins, maxs)) + return; + + memset(vk_lms.lightmap_surfaces, 0, sizeof(vk_lms.lightmap_surfaces)); + + VectorSubtract(r_newrefdef.vieworg, currententity->origin, modelorg); + if (rotated) + { + vec3_t temp; + vec3_t forward, right, up; + + VectorCopy(modelorg, temp); + AngleVectors(currententity->angles, forward, right, up); + modelorg[0] = DotProduct(temp, forward); + modelorg[1] = -DotProduct(temp, right); + modelorg[2] = DotProduct(temp, up); + } + + currententity->angles[0] = -currententity->angles[0]; // stupid quake bug + currententity->angles[2] = -currententity->angles[2]; // stupid quake bug + float model[16]; + Mat_Identity(model); + R_RotateForEntity(currententity, model); + currententity->angles[0] = -currententity->angles[0]; // stupid quake bug + currententity->angles[2] = -currententity->angles[2]; // stupid quake bug + + R_DrawInlineBModel(currententity, currentmodel, model); +} + +/* +============================================================= + + WORLD MODEL + +============================================================= +*/ + +/* +================ +R_RecursiveWorldNode +================ +*/ +static void R_RecursiveWorldNode (mnode_t *node, entity_t *currententity) +{ + int c, side, sidebit; + cplane_t *plane; + msurface_t *surf; + mleaf_t *pleaf; + float dot; + image_t *image; + + if (node->contents == CONTENTS_SOLID) + return; // solid + + if (node->visframe != r_visframecount) + return; + if (R_CullBox (node->minmaxs, node->minmaxs+3)) + return; + + // if a leaf node, draw stuff + if (node->contents != -1) + { + msurface_t **mark; + + pleaf = (mleaf_t *)node; + + // check for door connected areas + if (r_newrefdef.areabits) + { + if (! (r_newrefdef.areabits[pleaf->area>>3] & (1<<(pleaf->area&7)) ) ) + return; // not visible + } + + mark = pleaf->firstmarksurface; + c = pleaf->nummarksurfaces; + + if (c) + { + do + { + (*mark)->visframe = r_framecount; + mark++; + } while (--c); + } + + return; + } + + // node is just a decision point, so go down the apropriate sides + // find which side of the node we are on + plane = node->plane; + + switch (plane->type) + { + case PLANE_X: + dot = modelorg[0] - plane->dist; + break; + case PLANE_Y: + dot = modelorg[1] - plane->dist; + break; + case PLANE_Z: + dot = modelorg[2] - plane->dist; + break; + default: + dot = DotProduct (modelorg, plane->normal) - plane->dist; + break; + } + + if (dot >= 0) + { + side = 0; + sidebit = 0; + } + else + { + side = 1; + sidebit = SURF_PLANEBACK; + } + + // recurse down the children, front side first + R_RecursiveWorldNode (node->children[side], currententity); + + // draw stuff + for ( c = node->numsurfaces, surf = r_worldmodel->surfaces + node->firstsurface; c ; c--, surf++) + { + if (surf->visframe != r_framecount) + continue; + + if ( (surf->flags & SURF_PLANEBACK) != sidebit ) + continue; // wrong side + + if (surf->texinfo->flags & SURF_SKY) + { // just adds to visible sky bounds + R_AddSkySurface (surf); + } + else if (surf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66)) + { // add to the translucent chain + surf->texturechain = r_alpha_surfaces; + r_alpha_surfaces = surf; + } + else + { + if (!(surf->flags & SURF_DRAWTURB) && !vk_showtris->value) + { + Vk_RenderLightmappedPoly(surf, NULL, 1.f, currententity); + } + else + { + // the polygon is visible, so add it to the texture + // sorted chain + // FIXME: this is a hack for animation + image = R_TextureAnimation(surf->texinfo, currententity); + surf->texturechain = image->texturechain; + image->texturechain = surf; + } + } + } + + // recurse down the back side + R_RecursiveWorldNode (node->children[!side], currententity); +} + + +/* +============= +R_DrawWorld +============= +*/ +void R_DrawWorld (void) +{ + entity_t ent; + + if (!r_drawworld->value) + return; + + if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) + return; + + VectorCopy (r_newrefdef.vieworg, modelorg); + + // auto cycle the world frame for texture animation + memset (&ent, 0, sizeof(ent)); + ent.frame = (int)(r_newrefdef.time*2); + + memset (vk_lms.lightmap_surfaces, 0, sizeof(vk_lms.lightmap_surfaces)); + R_ClearSkyBox (); + + R_RecursiveWorldNode (r_worldmodel->nodes, &ent); + + /* + ** theoretically nothing should happen in the next two functions + ** if multitexture is enabled - in practice, this code renders non-transparent liquids! + */ + DrawTextureChains (&ent); + + R_DrawSkyBox (); + + R_DrawTriangleOutlines (); +} + + +/* +=============== +R_MarkLeaves + +Mark the leaves and nodes that are in the PVS for the current +cluster +=============== +*/ +void R_MarkLeaves (void) +{ + byte *vis; + byte fatvis[MAX_MAP_LEAFS/8]; + mnode_t *node; + int i; + mleaf_t *leaf; + + if (r_oldviewcluster == r_viewcluster && r_oldviewcluster2 == r_viewcluster2 && !r_novis->value && r_viewcluster != -1) + return; + + // development aid to let you run around and see exactly where + // the pvs ends + if (r_lockpvs->value) + return; + + r_visframecount++; + r_oldviewcluster = r_viewcluster; + r_oldviewcluster2 = r_viewcluster2; + + if (r_novis->value || r_viewcluster == -1 || !r_worldmodel->vis) + { + // mark everything + for (i=0 ; inumleafs ; i++) + r_worldmodel->leafs[i].visframe = r_visframecount; + for (i=0 ; inumnodes ; i++) + r_worldmodel->nodes[i].visframe = r_visframecount; + return; + } + + vis = Mod_ClusterPVS (r_viewcluster, r_worldmodel); + // may have to combine two clusters because of solid water boundaries + if (r_viewcluster2 != r_viewcluster) + { + int c; + + memcpy (fatvis, vis, (r_worldmodel->numleafs+7)/8); + vis = Mod_ClusterPVS (r_viewcluster2, r_worldmodel); + c = (r_worldmodel->numleafs+31)/32; + for (i=0 ; ileafs ; inumleafs ; i++, leaf++) + { + int cluster; + + cluster = leaf->cluster; + if (cluster == -1) + continue; + if (vis[cluster>>3] & (1<<(cluster&7))) + { + node = (mnode_t *)leaf; + do + { + if (node->visframe == r_visframecount) + break; + node->visframe = r_visframecount; + node = node->parent; + } while (node); + } + } +} + + + +/* +============================================================================= + + LIGHTMAP ALLOCATION + +============================================================================= +*/ + +static void LM_InitBlock( void ) +{ + memset( vk_lms.allocated, 0, sizeof( vk_lms.allocated ) ); +} + +static void LM_UploadBlock( qboolean dynamic ) +{ + int texture; + + if ( dynamic ) + { + texture = 0; + } + else + { + texture = vk_lms.current_lightmap_texture; + } + + if ( dynamic ) + { + int i; + int height = 0; + + for ( i = 0; i < BLOCK_WIDTH; i++ ) + { + if ( vk_lms.allocated[i] > height ) + height = vk_lms.allocated[i]; + } + QVk_UpdateTextureData(&vk_state.lightmap_textures[texture], vk_lms.lightmap_buffer, 0, 0, BLOCK_WIDTH, height); + } + else + { + if (vk_state.lightmap_textures[texture].resource.image != VK_NULL_HANDLE) + QVk_UpdateTextureData(&vk_state.lightmap_textures[texture], vk_lms.lightmap_buffer, 0, 0, BLOCK_WIDTH, BLOCK_HEIGHT); + else + { + QVVKTEXTURE_CLEAR(vk_state.lightmap_textures[texture]); + QVk_CreateTexture(&vk_state.lightmap_textures[texture], vk_lms.lightmap_buffer, + BLOCK_WIDTH, BLOCK_HEIGHT, vk_current_lmap_sampler, false); + QVk_DebugSetObjectName((uint64_t)vk_state.lightmap_textures[texture].resource.image, + VK_OBJECT_TYPE_IMAGE, va("Image: dynamic lightmap #%d", texture)); + QVk_DebugSetObjectName((uint64_t)vk_state.lightmap_textures[texture].imageView, + VK_OBJECT_TYPE_IMAGE_VIEW, va("Image View: dynamic lightmap #%d", texture)); + QVk_DebugSetObjectName((uint64_t)vk_state.lightmap_textures[texture].descriptorSet, + VK_OBJECT_TYPE_DESCRIPTOR_SET, va("Descriptor Set: dynamic lightmap #%d", texture)); + QVk_DebugSetObjectName((uint64_t)vk_state.lightmap_textures[texture].resource.memory, + VK_OBJECT_TYPE_DEVICE_MEMORY, va("Memory: dynamic lightmap #%d", texture)); + } + if ( ++vk_lms.current_lightmap_texture == MAX_LIGHTMAPS ) + ri.Sys_Error( ERR_DROP, "%s() - MAX_LIGHTMAPS exceeded\n", __func__); + } +} + +// returns a texture number and the position inside it +static qboolean LM_AllocBlock (int w, int h, int *x, int *y) +{ + int i, best; + + best = BLOCK_HEIGHT; + + for (i=0 ; i= best) + break; + if (vk_lms.allocated[i+j] > best2) + best2 = vk_lms.allocated[i+j]; + } + if (j == w) + { // this is a valid spot + *x = i; + *y = best = best2; + } + } + + if (best + h > BLOCK_HEIGHT) + return false; + + for (i=0 ; iedges; + lnumverts = fa->numedges; + + VectorClear (total); + // + // draw texture + // + poly = Hunk_Alloc (sizeof(vkpoly_t) + (lnumverts-4) * VERTEXSIZE*sizeof(float)); + poly->next = fa->polys; + poly->flags = fa->flags; + fa->polys = poly; + poly->numverts = lnumverts; + + for (i=0 ; isurfedges[fa->firstedge + i]; + + if (lindex > 0) + { + r_pedge = &pedges[lindex]; + vec = currentmodel->vertexes[r_pedge->v[0]].position; + } + else + { + r_pedge = &pedges[-lindex]; + vec = currentmodel->vertexes[r_pedge->v[1]].position; + } + s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3]; + s /= fa->texinfo->image->width; + + t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3]; + t /= fa->texinfo->image->height; + + VectorAdd (total, vec, total); + VectorCopy (vec, poly->verts[i]); + poly->verts[i][3] = s; + poly->verts[i][4] = t; + + // + // lightmap texture coordinates + // + s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3]; + s -= fa->texturemins[0]; + s += fa->light_s*16; + s += 8; + s /= BLOCK_WIDTH*16; //fa->texinfo->texture->width; + + t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3]; + t -= fa->texturemins[1]; + t += fa->light_t*16; + t += 8; + t /= BLOCK_HEIGHT*16; //fa->texinfo->texture->height; + + poly->verts[i][5] = s; + poly->verts[i][6] = t; + } + + poly->numverts = lnumverts; + +} + +/* +======================== +Vk_CreateSurfaceLightmap +======================== +*/ +void Vk_CreateSurfaceLightmap (msurface_t *surf) +{ + int smax, tmax; + byte *base; + + if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB)) + return; + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + + if ( !LM_AllocBlock( smax, tmax, &surf->light_s, &surf->light_t ) ) + { + LM_UploadBlock( false ); + LM_InitBlock(); + if ( !LM_AllocBlock( smax, tmax, &surf->light_s, &surf->light_t ) ) + { + ri.Sys_Error( ERR_FATAL, "%s: Consecutive calls to LM_AllocBlock(%d,%d) failed\n", __func__, smax, tmax ); + } + } + + surf->lightmaptexturenum = vk_lms.current_lightmap_texture; + + base = vk_lms.lightmap_buffer; + base += (surf->light_t * BLOCK_WIDTH + surf->light_s) * LIGHTMAP_BYTES; + + R_SetCacheState( surf ); + R_BuildLightMap (surf, base, BLOCK_WIDTH*LIGHTMAP_BYTES); +} + + +/* +================== +Vk_BeginBuildingLightmaps + +================== +*/ +void Vk_BeginBuildingLightmaps (model_t *m) +{ + static lightstyle_t lightstyles[MAX_LIGHTSTYLES]; + int i; + + memset(vk_lms.allocated, 0, sizeof(vk_lms.allocated)); + + r_framecount = 1; // no dlightcache + + /* + ** setup the base lightstyles so the lightmaps won't have to be regenerated + ** the first time they're seen + */ + for (i = 0; i < MAX_LIGHTSTYLES; i++) + { + lightstyles[i].rgb[0] = 1; + lightstyles[i].rgb[1] = 1; + lightstyles[i].rgb[2] = 1; + lightstyles[i].white = 3; + } + r_newrefdef.lightstyles = lightstyles; + + vk_lms.current_lightmap_texture = 0; + + /* + ** initialize the dynamic lightmap textures + */ + if (vk_state.lightmap_textures[DYNLIGHTMAP_OFFSET].resource.image == VK_NULL_HANDLE) + { + for (i = DYNLIGHTMAP_OFFSET; i < MAX_LIGHTMAPS*2; i++) + { + unsigned dummy[BLOCK_WIDTH * BLOCK_HEIGHT]; + + QVVKTEXTURE_CLEAR(vk_state.lightmap_textures[i]); + QVk_CreateTexture(&vk_state.lightmap_textures[i], (unsigned char*)dummy, + BLOCK_WIDTH, BLOCK_HEIGHT, vk_current_lmap_sampler, false); + QVk_DebugSetObjectName((uint64_t)vk_state.lightmap_textures[i].resource.image, + VK_OBJECT_TYPE_IMAGE, va("Image: dynamic lightmap #%d", i)); + QVk_DebugSetObjectName((uint64_t)vk_state.lightmap_textures[i].imageView, + VK_OBJECT_TYPE_IMAGE_VIEW, va("Image View: dynamic lightmap #%d", i)); + QVk_DebugSetObjectName((uint64_t)vk_state.lightmap_textures[i].descriptorSet, + VK_OBJECT_TYPE_DESCRIPTOR_SET, va("Descriptor Set: dynamic lightmap #%d", i)); + QVk_DebugSetObjectName((uint64_t)vk_state.lightmap_textures[i].resource.memory, + VK_OBJECT_TYPE_DEVICE_MEMORY, va("Memory: dynamic lightmap #%d", i)); + } + } +} + +/* +======================= +Vk_EndBuildingLightmaps +======================= +*/ +void Vk_EndBuildingLightmaps (void) +{ + LM_UploadBlock( false ); +} + diff --git a/src/vk/vk_shaders.c b/src/vk/vk_shaders.c new file mode 100644 index 0000000..4de4b53 --- /dev/null +++ b/src/vk/vk_shaders.c @@ -0,0 +1,85 @@ +/* +Copyright (C) 2018-2019 Krzysztof Kondrak + +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. + +*/ + +#include "header/shaders.h" + +// ingame shaders stored as uint32_t arrays (autogenerated by glslangValidator) +#include "spirv/basic_vert.c" +#include "spirv/basic_frag.c" +#include "spirv/basic_color_quad_vert.c" +#include "spirv/basic_color_quad_frag.c" +#include "spirv/model_vert.c" +#include "spirv/model_frag.c" +#include "spirv/nullmodel_vert.c" +#include "spirv/particle_vert.c" +#include "spirv/point_particle_vert.c" +#include "spirv/point_particle_frag.c" +#include "spirv/sprite_vert.c" +#include "spirv/beam_vert.c" +#include "spirv/skybox_vert.c" +#include "spirv/d_light_vert.c" +#include "spirv/polygon_vert.c" +#include "spirv/polygon_lmap_vert.c" +#include "spirv/polygon_lmap_frag.c" +#include "spirv/polygon_warp_vert.c" +#include "spirv/shadows_vert.c" +#include "spirv/postprocess_vert.c" +#include "spirv/postprocess_frag.c" +#include "spirv/world_warp_vert.c" +#include "spirv/world_warp_frag.c" + +const size_t basic_vert_size = sizeof(basic_vert_spv); +const size_t basic_frag_size = sizeof(basic_frag_spv); + +const size_t basic_color_quad_vert_size = sizeof(basic_color_quad_vert_spv); +const size_t basic_color_quad_frag_size = sizeof(basic_color_quad_frag_spv); + +const size_t model_vert_size = sizeof(model_vert_spv); +const size_t model_frag_size = sizeof(model_frag_spv); + +const size_t nullmodel_vert_size = sizeof(nullmodel_vert_spv); + +const size_t particle_vert_size = sizeof(particle_vert_spv); + +const size_t point_particle_vert_size = sizeof(point_particle_vert_spv); +const size_t point_particle_frag_size = sizeof(point_particle_frag_spv); + +const size_t sprite_vert_size = sizeof(sprite_vert_spv); + +const size_t beam_vert_size = sizeof(beam_vert_spv); + +const size_t skybox_vert_size = sizeof(skybox_vert_spv); + +const size_t d_light_vert_size = sizeof(d_light_vert_spv); + +const size_t polygon_vert_size = sizeof(polygon_vert_spv); + +const size_t polygon_lmap_vert_size = sizeof(polygon_lmap_vert_spv); +const size_t polygon_lmap_frag_size = sizeof(polygon_lmap_frag_spv); + +const size_t polygon_warp_vert_size = sizeof(polygon_warp_vert_spv); + +const size_t shadows_vert_size = sizeof(shadows_vert_spv); + +const size_t postprocess_vert_size = sizeof(postprocess_vert_spv); +const size_t postprocess_frag_size = sizeof(postprocess_frag_spv); + +const size_t world_warp_vert_size = sizeof(world_warp_vert_spv); +const size_t world_warp_frag_size = sizeof(world_warp_frag_spv); diff --git a/src/vk/vk_swapchain.c b/src/vk/vk_swapchain.c new file mode 100644 index 0000000..2ee91de --- /dev/null +++ b/src/vk/vk_swapchain.c @@ -0,0 +1,250 @@ +/* +Copyright (C) 2018-2019 Krzysztof Kondrak + +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. + +*/ + +#include "header/local.h" + +// internal helper +static const char *presentModeString(VkPresentModeKHR presentMode) +{ +#define PMSTR(r) case VK_ ##r: return "VK_"#r + switch (presentMode) + { + PMSTR(PRESENT_MODE_IMMEDIATE_KHR); + PMSTR(PRESENT_MODE_MAILBOX_KHR); + PMSTR(PRESENT_MODE_FIFO_KHR); + PMSTR(PRESENT_MODE_FIFO_RELAXED_KHR); + default: return ""; + } +#undef PMSTR + return "UNKNOWN PRESENT MODE"; +} + +// internal helper +static VkSurfaceFormatKHR getSwapSurfaceFormat(const VkSurfaceFormatKHR *surfaceFormats, uint32_t formatCount) +{ + VkSurfaceFormatKHR swapSurfaceFormat; + memset(&swapSurfaceFormat, 0, sizeof(swapSurfaceFormat)); + if (!surfaceFormats || !formatCount) + { + return swapSurfaceFormat; + } + + for (size_t i = 0; i < formatCount; ++i) + { + if (surfaceFormats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR && + surfaceFormats[i].format == VK_FORMAT_B8G8R8A8_UNORM) + { + swapSurfaceFormat.colorSpace = surfaceFormats[i].colorSpace; + swapSurfaceFormat.format = surfaceFormats[i].format; + return swapSurfaceFormat; + } + } + // no preferred format, so get the first one from list + swapSurfaceFormat.colorSpace = surfaceFormats[0].colorSpace; + swapSurfaceFormat.format = surfaceFormats[0].format; + + return swapSurfaceFormat; +} + +// internal helper +// look to https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPresentModeKHR.html for more information +static VkPresentModeKHR getSwapPresentMode(const VkPresentModeKHR *presentModes, uint32_t presentModesCount, VkPresentModeKHR desiredMode) +{ + // PRESENT_MODE_FIFO_KHR is guaranteed to exist due to spec requirements + VkPresentModeKHR usedPresentMode = VK_PRESENT_MODE_FIFO_KHR; + + if (!presentModes) + { + return usedPresentMode; + } + + // check if the desired present mode is supported + for (uint32_t i = 0; i < presentModesCount; ++i) + { + // mode supported, nothing to do here + if (presentModes[i] == desiredMode) + { + vk_config.present_mode = presentModeString(desiredMode); + R_Printf(PRINT_ALL, "...using present mode: %s\n", vk_config.present_mode); + return desiredMode; + } + } + + // preferred present mode not found - choose the next best thing + for (uint32_t i = 0; i < presentModesCount; ++i) + { + // always prefer mailbox for triple buffering with whole image replace + if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) + { + usedPresentMode = presentModes[i]; + break; + } + // prefer immediate update with tearing + else if (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) + { + usedPresentMode = presentModes[i]; + } + } + + vk_config.present_mode = presentModeString(usedPresentMode); + R_Printf(PRINT_ALL, "...present mode %s not supported, using present mode: %s\n", presentModeString(desiredMode), vk_config.present_mode); + return usedPresentMode; +} + +// internal helper +static VkCompositeAlphaFlagBitsKHR getSupportedCompositeAlpha(VkCompositeAlphaFlagsKHR supportedFlags) +{ + VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[] = { + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR + }; + + for (int i = 0; i < 4; ++i) + { + if (supportedFlags & compositeAlphaFlags[i]) + return compositeAlphaFlags[i]; + } + + return VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; +} + +qboolean QVk_CheckExtent(void) +{ + VkSurfaceCapabilitiesKHR surfaceCaps; + VK_VERIFY(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_device.physical, vk_surface, &surfaceCaps)); + + if (surfaceCaps.currentExtent.width == 0 || surfaceCaps.currentExtent.height == 0) + { + return false; + } + + return true; +} + +VkResult QVk_CreateSwapchain() +{ + VkSurfaceCapabilitiesKHR surfaceCaps; + VkSurfaceFormatKHR *surfaceFormats = NULL; + VkPresentModeKHR *presentModes = NULL; + uint32_t formatCount, presentModesCount; + VK_VERIFY(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_device.physical, vk_surface, &surfaceCaps)); + VK_VERIFY(vkGetPhysicalDeviceSurfaceFormatsKHR(vk_device.physical, vk_surface, &formatCount, NULL)); + VK_VERIFY(vkGetPhysicalDeviceSurfacePresentModesKHR(vk_device.physical, vk_surface, &presentModesCount, NULL)); + + if (formatCount > 0) + { + surfaceFormats = (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR)); + VK_VERIFY(vkGetPhysicalDeviceSurfaceFormatsKHR(vk_device.physical, vk_surface, &formatCount, surfaceFormats)); + } + + if (presentModesCount > 0) + { + presentModes = (VkPresentModeKHR *)malloc(presentModesCount * sizeof(VkPresentModeKHR)); + VK_VERIFY(vkGetPhysicalDeviceSurfacePresentModesKHR(vk_device.physical, vk_surface, &presentModesCount, presentModes)); + + R_Printf(PRINT_ALL, "Supported present modes: "); + for (int i = 0; i < presentModesCount; i++) + { + R_Printf(PRINT_ALL, "%s ", presentModeString(presentModes[i])); + vk_config.supported_present_modes[i] = presentModeString(presentModes[i]); + } + R_Printf(PRINT_ALL, "\n"); + } + + VkSurfaceFormatKHR swapSurfaceFormat = getSwapSurfaceFormat(surfaceFormats, formatCount); + VkPresentModeKHR swapPresentMode = getSwapPresentMode(presentModes, presentModesCount, r_vsync->value > 0 ? VK_PRESENT_MODE_FIFO_KHR : VK_PRESENT_MODE_MAILBOX_KHR); + free(surfaceFormats); + free(presentModes); + + VkExtent2D extent = surfaceCaps.currentExtent; + if(extent.width == UINT32_MAX || extent.height == UINT32_MAX) + { + extent.width = max(surfaceCaps.minImageExtent.width, min(surfaceCaps.maxImageExtent.width, vid.width)); + extent.height = max(surfaceCaps.minImageExtent.height, min(surfaceCaps.maxImageExtent.height, vid.height)); + } + + // request at least 2 images - this fixes fullscreen crashes on AMD when launching the game in fullscreen + uint32_t imageCount = max(2, surfaceCaps.minImageCount); + if (swapPresentMode != VK_PRESENT_MODE_FIFO_KHR) + imageCount = max(3, surfaceCaps.minImageCount); + + if (surfaceCaps.maxImageCount > 0) + imageCount = min(imageCount, surfaceCaps.maxImageCount); + + VkImageUsageFlags imgUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + + // TRANSFER_SRC_BIT is required for taking screenshots + if (surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) + { + imgUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + vk_device.screenshotSupported = true; + } + + VkSwapchainKHR oldSwapchain = vk_swapchain.sc; + VkSwapchainCreateInfoKHR scCreateInfo = { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + .pNext = NULL, + .flags = 0, + .surface = vk_surface, + .minImageCount = imageCount, + .imageFormat = swapSurfaceFormat.format, + .imageColorSpace = swapSurfaceFormat.colorSpace, + .imageExtent = extent, + .imageArrayLayers = 1, + .imageUsage = imgUsage, + .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = NULL, + .preTransform = (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : surfaceCaps.currentTransform, + .compositeAlpha = getSupportedCompositeAlpha(surfaceCaps.supportedCompositeAlpha), + .presentMode = swapPresentMode, + .clipped = VK_TRUE, + .oldSwapchain = oldSwapchain + }; + + uint32_t queueFamilyIndices[] = { (uint32_t)vk_device.gfxFamilyIndex, (uint32_t)vk_device.presentFamilyIndex }; + if (vk_device.presentFamilyIndex != vk_device.gfxFamilyIndex) + { + scCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + scCreateInfo.queueFamilyIndexCount = 2; + scCreateInfo.pQueueFamilyIndices = queueFamilyIndices; + } + + vk_swapchain.format = swapSurfaceFormat.format; + vk_swapchain.extent = extent; + R_Printf(PRINT_ALL, "...trying swapchain extent: %dx%d\n", vk_swapchain.extent.width, vk_swapchain.extent.height); + R_Printf(PRINT_ALL, "...trying swapchain image format: %d\n", vk_swapchain.format); + + VkResult res = vkCreateSwapchainKHR(vk_device.logical, &scCreateInfo, NULL, &vk_swapchain.sc); + if (res != VK_SUCCESS) + return res; + + VK_VERIFY(vkGetSwapchainImagesKHR(vk_device.logical, vk_swapchain.sc, &imageCount, NULL)); + vk_swapchain.images = (VkImage *)malloc(imageCount * sizeof(VkImage)); + vk_swapchain.imageCount = imageCount; + res = vkGetSwapchainImagesKHR(vk_device.logical, vk_swapchain.sc, &imageCount, vk_swapchain.images); + + if (oldSwapchain != VK_NULL_HANDLE) + vkDestroySwapchainKHR(vk_device.logical, oldSwapchain, NULL); + + return res; +} diff --git a/src/vk/vk_util.c b/src/vk/vk_util.c new file mode 100644 index 0000000..3126bf5 --- /dev/null +++ b/src/vk/vk_util.c @@ -0,0 +1,620 @@ +/* +Copyright (C) 2018 Christoph Schied +Copyright (C) 2020 Denis Pauk + +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. +*/ + +#include "header/util.h" +#include "header/local.h" + +#include + +static uint32_t +get_memory_type(uint32_t mem_req_type_bits, VkMemoryPropertyFlags mem_prop) +{ + for(uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; i++) { + if(mem_req_type_bits & (1 << i)) { + if((vk_device.mem_properties.memoryTypes[i].propertyFlags & mem_prop) == mem_prop) + return i; + } + } + return -1; +} + +typedef struct MemoryResource_s { + // type of memory + uint32_t memory_type; + // offset step + VkDeviceSize alignment; + // id memory used + VkBool32 used; + // suballocate + VkBool32 suballocate; + // shared memory used for image + VkDeviceMemory memory; + // image size + VkDeviceSize size; + // posision in shared memory + VkDeviceSize offset; +} MemoryResource_t; + +// 1MB buffers / 512 x 512 * RGBA +#define MEMORY_THRESHOLD (512 * 512 * 4) + +static VkDeviceSize memory_block_threshold; +static MemoryResource_t *used_memory; +static VkDeviceSize used_memory_size; + +void +vulkan_memory_init(void) +{ + memory_block_threshold = MEMORY_THRESHOLD; + used_memory_size = 1024; // Size of buffers history + used_memory = malloc(used_memory_size * sizeof(MemoryResource_t)); + memset(used_memory, 0, used_memory_size * sizeof(MemoryResource_t)); +} + +static void +memory_type_print(VkMemoryPropertyFlags mem_prop) +{ +#define MPSTR(r, prop) \ + if((prop & VK_ ##r) != 0) \ + { R_Printf(PRINT_ALL, " %s", "VK_"#r); }; + + MPSTR(MEMORY_PROPERTY_DEVICE_LOCAL_BIT, mem_prop); + MPSTR(MEMORY_PROPERTY_HOST_VISIBLE_BIT, mem_prop); + MPSTR(MEMORY_PROPERTY_HOST_COHERENT_BIT, mem_prop); + MPSTR(MEMORY_PROPERTY_HOST_CACHED_BIT, mem_prop); + MPSTR(MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, mem_prop); + MPSTR(MEMORY_PROPERTY_PROTECTED_BIT, mem_prop); + MPSTR(MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD, mem_prop); + MPSTR(MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD, mem_prop); + +#undef PMSTR +} + +void +vulkan_memory_types_show(void) +{ + R_Printf(PRINT_ALL, "\nMemory blocks:"); + + for(uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; i++) + { + if (vk_device.mem_properties.memoryTypes[i].propertyFlags) + { + R_Printf(PRINT_ALL, "\n #%d:", i); + memory_type_print(vk_device.mem_properties.memoryTypes[i].propertyFlags); + } + } + R_Printf(PRINT_ALL, "\n"); +} + +static VkBool32 +vulkan_memory_is_used(int start_pos, int end_pos, VkDeviceMemory memory) +{ + int pos; + + for (pos = start_pos; pos < end_pos; pos++) + { + if (used_memory[pos].memory == memory && used_memory[pos].used) + return VK_TRUE; + } + + return VK_FALSE; +} + +void +vulkan_memory_free_unused(void) +{ + int pos_global; + + for (pos_global = 0; pos_global < used_memory_size; pos_global ++) + { + VkDeviceMemory memory = used_memory[pos_global].memory; + if (memory != VK_NULL_HANDLE && !used_memory[pos_global].used) + { + int pos_local; + + // is used somewhere else after + if (vulkan_memory_is_used(pos_global, used_memory_size, memory)) + continue; + + // is used somewhere else before + if (vulkan_memory_is_used(0, pos_global, memory)) + continue; + + // free current memory block + vkFreeMemory(vk_device.logical, memory, NULL); + memset(&used_memory[pos_global], 0, sizeof(MemoryResource_t)); + + // cleanup same block + for (pos_local = pos_global + 1; pos_local < used_memory_size; pos_local++) + { + if (used_memory[pos_local].memory == memory) + { + memset(&used_memory[pos_local], 0, sizeof(MemoryResource_t)); + } + } + + } + } +} + +void +vulkan_memory_delete(void) +{ + int pos_global; + for (pos_global = 0; pos_global < used_memory_size; pos_global ++) + { + VkDeviceMemory memory = used_memory[pos_global].memory; + if (memory != VK_NULL_HANDLE) + { + int pos_local; + + // free current memory block + vkFreeMemory(vk_device.logical, memory, NULL); + memset(&used_memory[pos_global], 0, sizeof(MemoryResource_t)); + + // cleanup same block + for (pos_local = pos_global + 1; pos_local < used_memory_size; pos_local++) + { + if (used_memory[pos_local].memory == memory) + { + memset(&used_memory[pos_local], 0, sizeof(MemoryResource_t)); + } + } + } + } + free(used_memory); +} + +static VkResult +memory_block_min(VkDeviceSize size, + uint32_t memory_type, + VkDeviceSize alignment, + VkBool32 suballocate, + int* block_pos) +{ + int pos; + VkDeviceSize min_size = memory_block_threshold; + VkResult result = VK_ERROR_OUT_OF_DEVICE_MEMORY; + + // update max_size + if (min_size < size) + { + *block_pos = -1; + return result; + } + + // search minimal posible size + for (pos = 0; pos < used_memory_size; pos ++) + { + if (used_memory[pos].memory_type == memory_type && + used_memory[pos].suballocate == suballocate && + used_memory[pos].alignment == alignment && + used_memory[pos].memory != VK_NULL_HANDLE && + used_memory[pos].used == VK_FALSE && + used_memory[pos].size < min_size && + used_memory[pos].size >= size) + { + // save minimal size + min_size = used_memory[pos].size; + *block_pos = pos; + result = VK_SUCCESS; + } + } + + return result; +} + +static VkResult +memory_block_empty(int *block_pos) +{ + int pos; + MemoryResource_t *memory; + + // search empty memory + for (pos = *block_pos; pos < used_memory_size; pos ++) + { + if (used_memory[pos].memory == VK_NULL_HANDLE) + { + *block_pos = pos; + return VK_SUCCESS; + } + } + + memory = realloc(used_memory, (used_memory_size * 2) * sizeof(MemoryResource_t)); + if (!memory) + return VK_ERROR_OUT_OF_DEVICE_MEMORY; + + // use previous end + *block_pos = used_memory_size; + + // update old struct + memset(memory + used_memory_size, 0, used_memory_size * sizeof(MemoryResource_t)); + used_memory_size *= 2; + used_memory = memory; + + return VK_SUCCESS; +} + +static VkResult +memory_block_allocate(VkDeviceSize size, + uint32_t memory_type, + VkDeviceSize alignment, + VkBool32 suballocate, + int *block_pos) +{ + int pos = 0; + if (memory_block_empty(&pos) == VK_SUCCESS) + { + VkResult result; + VkDeviceMemory memory; + + if (size < MEMORY_THRESHOLD) + size = MEMORY_THRESHOLD; + + // allocate only aligned + size = ROUNDUP(size, alignment); + + // Need to split only buffers with suballocate support + if (suballocate) + { + // requested bigger then usual + if (size > memory_block_threshold) + { + size *= 2; + // up threshold for next allocations + memory_block_threshold = size; + } + // allcate bigger memory for reuse + else if (size < memory_block_threshold) + { + size = memory_block_threshold; + } + } + + VkMemoryAllocateInfo mem_alloc_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .allocationSize = size, + .memoryTypeIndex = memory_type + }; + + result = vkAllocateMemory(vk_device.logical, &mem_alloc_info, NULL, &memory); + if (result == VK_SUCCESS) + { + used_memory[pos].memory = memory; + used_memory[pos].memory_type = memory_type; + used_memory[pos].alignment = alignment; + used_memory[pos].offset = 0; + used_memory[pos].size = size; + used_memory[pos].suballocate = suballocate; + used_memory[pos].used = VK_FALSE; + *block_pos = pos; + } + return result; + } + + return VK_ERROR_OUT_OF_DEVICE_MEMORY; +} + +static VkResult +memory_create(VkDeviceSize size, + uint32_t memory_type, + VkBool32 suballocate, + VkDeviceSize alignment, + VkDeviceMemory *memory, + VkDeviceSize *offset) +{ + int pos = -1; + VkResult result; + result = memory_block_min(size, memory_type, alignment, suballocate, &pos); + + if (result != VK_SUCCESS) + { + result = memory_block_allocate(size, memory_type, alignment, suballocate, &pos); + } + if (result == VK_SUCCESS) + { + // check size of block, + // new block should be at least same size as current + // and beger than double minimal offset + // and marked as not for mmap + if (used_memory[pos].size > (size * 2) && + (used_memory[pos].size > (used_memory[pos].alignment * 2)) && + used_memory[pos].suballocate) + { + // search from next slot + int new_pos = pos + 1; + result = memory_block_empty(&new_pos); + if (result == VK_SUCCESS) + { + VkDeviceSize new_size = ROUNDUP(size, used_memory[pos].alignment); + + // split to several blocks + memcpy(&used_memory[new_pos], &used_memory[pos], sizeof(MemoryResource_t)); + used_memory[new_pos].offset = used_memory[pos].offset + new_size; + used_memory[new_pos].size = used_memory[pos].size - new_size; + + // save new size to block, it can be bigger than required + used_memory[pos].size = used_memory[new_pos].offset - used_memory[pos].offset; + assert(used_memory[pos].size > 0); + } + } + + used_memory[pos].used = VK_TRUE; + *offset = used_memory[pos].offset; + *memory = used_memory[pos].memory; + return result; + } + + return VK_ERROR_OUT_OF_DEVICE_MEMORY; +} + +static void +memory_destroy(VkDeviceMemory memory, VkDeviceSize offset) +{ + int pos; + for (pos = 0; pos < used_memory_size; pos ++) + { + if (used_memory[pos].memory == memory && used_memory[pos].offset == offset) + { + used_memory[pos].used = VK_FALSE; + return; + } + } + // looks as no such memory registered + vkFreeMemory(vk_device.logical, memory, NULL); +} + +static VkResult +memory_create_by_property(VkMemoryRequirements* mem_reqs, + VkMemoryPropertyFlags mem_properties, + VkMemoryPropertyFlags mem_preferences, + VkDeviceMemory *memory, + VkDeviceSize *offset) +{ + uint32_t memory_index; + VkMemoryPropertyFlags host_visible; + + memory_index = get_memory_type(mem_reqs->memoryTypeBits, + mem_properties | mem_preferences); + // prefered memory allocation + if (memory_index == -1) + { + memory_index = get_memory_type(mem_reqs->memoryTypeBits, + mem_properties); + } + // strictly required + if (memory_index == -1) + { + R_Printf(PRINT_ALL, "%s:%d: Have not found required memory type.\n", + __func__, __LINE__); + return VK_ERROR_OUT_OF_DEVICE_MEMORY; + } + + host_visible = mem_properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + + return memory_create(mem_reqs->size, memory_index, + // suballocate allowed + host_visible != VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + mem_reqs->alignment, memory, offset); +} + +VkResult +buffer_create(BufferResource_t *buf, + VkBufferCreateInfo buf_create_info, + VkMemoryPropertyFlags mem_properties, + VkMemoryPropertyFlags mem_preferences) +{ + assert(buf_create_info.size > 0); + assert(buf); + VkResult result = VK_SUCCESS; + + buf->size = buf_create_info.size; + buf->is_mapped = VK_FALSE; + + result = vkCreateBuffer(vk_device.logical, &buf_create_info, NULL, &buf->buffer); + if(result != VK_SUCCESS) { + R_Printf(PRINT_ALL, "%s:%d: VkResult verification: %s\n", + __func__, __LINE__, QVk_GetError(result)); + goto fail_buffer; + } + assert(buf->buffer != VK_NULL_HANDLE); + + VkMemoryRequirements mem_reqs; + vkGetBufferMemoryRequirements(vk_device.logical, buf->buffer, &mem_reqs); + + result = memory_create_by_property(&mem_reqs, mem_properties, mem_preferences, + &buf->memory, &buf->offset); + if(result != VK_SUCCESS) { + R_Printf(PRINT_ALL, "%s:%d: VkResult verification: %s\n", + __func__, __LINE__, QVk_GetError(result)); + goto fail_mem_alloc; + } + + assert(buf->memory != VK_NULL_HANDLE); + + result = vkBindBufferMemory(vk_device.logical, buf->buffer, buf->memory, buf->offset); + if(result != VK_SUCCESS) { + R_Printf(PRINT_ALL, "%s:%d: VkResult verification: %s\n", + __func__, __LINE__, QVk_GetError(result)); + goto fail_bind_buf_memory; + } + + return VK_SUCCESS; + +fail_bind_buf_memory: + memory_destroy(buf->memory, buf->offset); +fail_mem_alloc: + vkDestroyBuffer(vk_device.logical, buf->buffer, NULL); +fail_buffer: + buf->buffer = VK_NULL_HANDLE; + buf->memory = VK_NULL_HANDLE; + buf->size = 0; + return result; +} + +VkResult +image_create(ImageResource_t *img, + VkImageCreateInfo img_create_info, + VkMemoryPropertyFlags mem_properties, + VkMemoryPropertyFlags mem_preferences) +{ + assert(img); + VkResult result = VK_SUCCESS; + + result = vkCreateImage(vk_device.logical, &img_create_info, NULL, &img->image); + if(result != VK_SUCCESS) { + R_Printf(PRINT_ALL, "%s:%d: VkResult verification: %s\n", + __func__, __LINE__, QVk_GetError(result)); + goto fail_buffer; + } + assert(img->image != VK_NULL_HANDLE); + + VkMemoryRequirements mem_reqs; + vkGetImageMemoryRequirements(vk_device.logical, img->image, &mem_reqs); + img->size = mem_reqs.size; + + result = memory_create_by_property(&mem_reqs, mem_properties, mem_preferences, + &img->memory, &img->offset); + if(result != VK_SUCCESS) { + R_Printf(PRINT_ALL, "%s:%d: VkResult verification: %s\n", + __func__, __LINE__, QVk_GetError(result)); + goto fail_mem_alloc; + } + + assert(img->memory != VK_NULL_HANDLE); + + result = vkBindImageMemory(vk_device.logical, img->image, img->memory, img->offset); + if(result != VK_SUCCESS) { + R_Printf(PRINT_ALL, "%s:%d: VkResult verification: %s\n", + __func__, __LINE__, QVk_GetError(result)); + goto fail_bind_buf_memory; + } + + return VK_SUCCESS; + +fail_bind_buf_memory: + memory_destroy(img->memory, img->offset); +fail_mem_alloc: + vkDestroyImage(vk_device.logical, img->image, NULL); +fail_buffer: + img->image = VK_NULL_HANDLE; + img->memory = VK_NULL_HANDLE; + img->size = 0; + return result; +} + +VkResult +buffer_destroy(BufferResource_t *buf) +{ + assert(!buf->is_mapped); + + // buffer should be destroed before bound memory + if(buf->buffer != VK_NULL_HANDLE) + { + vkDestroyBuffer(vk_device.logical, buf->buffer, NULL); + buf->buffer = VK_NULL_HANDLE; + } + + // buffer desroed, we can free up memory + if(buf->memory != VK_NULL_HANDLE) + { + memory_destroy(buf->memory, buf->offset); + buf->memory = VK_NULL_HANDLE; + } + + memset(buf, 0, sizeof(BufferResource_t)); + + return VK_SUCCESS; +} + +VkResult +image_destroy(ImageResource_t *img) +{ + // image should be destroed before bound memory + if(img->image != VK_NULL_HANDLE) + { + vkDestroyImage(vk_device.logical, img->image, NULL); + img->image = VK_NULL_HANDLE; + } + + // image destroed, we can free up memory + if(img->memory != VK_NULL_HANDLE) + { + memory_destroy(img->memory, img->offset); + img->memory = VK_NULL_HANDLE; + } + + memset(img, 0, sizeof(ImageResource_t)); + + return VK_SUCCESS; +} + +VkResult +buffer_flush(BufferResource_t *buf) +{ + VkResult result = VK_SUCCESS; + + VkMappedMemoryRange ranges[1] = {{ + .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + .memory = buf->memory, + .offset = buf->offset, + .size = buf->size + }}; + result = vkFlushMappedMemoryRanges(vk_device.logical, 1, ranges); + return result; +} + +VkResult +buffer_invalidate(BufferResource_t *buf) +{ + VkResult result = VK_SUCCESS; + + VkMappedMemoryRange ranges[1] = {{ + .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + .memory = buf->memory, + .offset = buf->offset, + .size = buf->size + }}; + result = vkInvalidateMappedMemoryRanges(vk_device.logical, 1, ranges); + return result; + +} + +void * +buffer_map(BufferResource_t *buf) +{ + assert(buf->memory); + assert(!buf->is_mapped); + buf->is_mapped = VK_TRUE; + void *ret = NULL; + assert(buf->memory != VK_NULL_HANDLE); + assert(buf->size > 0); + VK_VERIFY(vkMapMemory(vk_device.logical, buf->memory, + buf->offset/*offset*/, buf->size, 0 /*flags*/, &ret)); + return ret; +} + +void +buffer_unmap(BufferResource_t *buf) +{ + assert(buf->memory); + assert(buf->is_mapped); + buf->is_mapped = VK_FALSE; + vkUnmapMemory(vk_device.logical, buf->memory); +} diff --git a/src/vk/vk_validation.c b/src/vk/vk_validation.c new file mode 100644 index 0000000..2710ba8 --- /dev/null +++ b/src/vk/vk_validation.c @@ -0,0 +1,99 @@ +/* +Copyright (C) 2018-2019 Krzysztof Kondrak + +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. + +*/ + +#include "header/local.h" + +static VkDebugUtilsMessengerEXT validationMessenger = VK_NULL_HANDLE; + +// layer message to string +static const char* msgToString(VkDebugUtilsMessageTypeFlagsEXT type) +{ + int g = (type & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) != 0 ? 1 : 0; + int p = (type & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) != 0 ? 1 : 0; + int v = (type & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) != 0 ? 1 : 0; + + if (g) return ""; + if (p && !v) return "(performance)"; + if (p && v) return "(performance and validation)"; + if (v) return "(validation)"; + + return "?"; +} + +// validation layer callback function (VK_EXT_debug_utils) +static VKAPI_ATTR VkBool32 VKAPI_CALL debugUtilsCallback(VkDebugUtilsMessageSeverityFlagBitsEXT msgSeverity, + VkDebugUtilsMessageTypeFlagsEXT msgType, + const VkDebugUtilsMessengerCallbackDataEXT *callbackData, + void* userData) +{ + switch (msgSeverity) + { + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: + R_Printf(PRINT_ALL, "VK_INFO: %s %s\n", callbackData->pMessage, msgToString(msgType)); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: + R_Printf(PRINT_ALL, "VK_VERBOSE: %s %s\n", callbackData->pMessage, msgToString(msgType)); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: + R_Printf(PRINT_ALL, "VK_WARNING: %s %s\n", callbackData->pMessage, msgToString(msgType)); + break; + default: + R_Printf(PRINT_ALL, "VK_ERROR: %s %s\n", callbackData->pMessage, msgToString(msgType)); + assert(!"Vulkan error occured!"); + } + return VK_FALSE; +} + +void QVk_CreateValidationLayers() +{ + VkDebugUtilsMessengerCreateInfoEXT callbackInfo = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .pNext = NULL, + .flags = 0, + .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, + .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, + .pfnUserCallback = debugUtilsCallback, + .pUserData = NULL + }; + + if(vk_validation->value) + { + callbackInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT; + } + + if (qvkCreateDebugUtilsMessengerEXT) + { + VK_VERIFY(qvkCreateDebugUtilsMessengerEXT(vk_instance, &callbackInfo, NULL, &validationMessenger)); + R_Printf(PRINT_ALL, "...Vulkan validation layers enabled\n"); + } +} + +void QVk_DestroyValidationLayers() +{ + if( validationMessenger != VK_NULL_HANDLE && qvkDestroyDebugUtilsMessengerEXT) + { + qvkDestroyDebugUtilsMessengerEXT( vk_instance, validationMessenger, NULL ); + validationMessenger = VK_NULL_HANDLE; + } +} diff --git a/src/vk/vk_warp.c b/src/vk/vk_warp.c new file mode 100644 index 0000000..208f99a --- /dev/null +++ b/src/vk/vk_warp.c @@ -0,0 +1,732 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. +Copyright (C) 2018-2019 Krzysztof Kondrak + +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. + +*/ +// vk_warp.c -- sky and water polygons +#include "header/local.h" + +static char skyname[MAX_QPATH]; +static float skyrotate; +static vec3_t skyaxis; +static image_t *sky_images[6]; + +static msurface_t *warpface; + +#define SUBDIVIDE_SIZE 64 + +static void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs) +{ + int i, j; + float *v; + + mins[0] = mins[1] = mins[2] = 9999; + maxs[0] = maxs[1] = maxs[2] = -9999; + v = verts; + for (i=0 ; i maxs[j]) + maxs[j] = *v; + } +} + +static void SubdividePolygon (int numverts, float *verts) +{ + int i, j, k; + vec3_t mins, maxs; + float *v; + vec3_t front[64], back[64]; + int f, b; + float dist[64]; + float frac; + vkpoly_t *poly; + vec3_t total; + float total_s, total_t; + + if (numverts > 60) + ri.Sys_Error (ERR_DROP, "%s: numverts = %i", __func__, numverts); + + BoundPoly (numverts, verts, mins, maxs); + + for (i=0 ; i<3 ; i++) + { + float m; + + m = (mins[i] + maxs[i]) * 0.5; + m = SUBDIVIDE_SIZE * floor (m/SUBDIVIDE_SIZE + 0.5); + if (maxs[i] - m < 8) + continue; + if (m - mins[i] < 8) + continue; + + // cut it + v = verts + i; + for (j=0 ; j= 0) + { + VectorCopy (v, front[f]); + f++; + } + if (dist[j] <= 0) + { + VectorCopy (v, back[b]); + b++; + } + if (dist[j] == 0 || dist[j+1] == 0) + continue; + if ( (dist[j] > 0) != (dist[j+1] > 0) ) + { + // clip point + frac = dist[j] / (dist[j] - dist[j+1]); + for (k=0 ; k<3 ; k++) + front[f][k] = back[b][k] = v[k] + frac*(v[3+k] - v[k]); + f++; + b++; + } + } + + SubdividePolygon (f, front[0]); + SubdividePolygon (b, back[0]); + return; + } + + // add a point in the center to help keep warp valid + poly = Hunk_Alloc (sizeof(vkpoly_t) + ((numverts-4)+2) * VERTEXSIZE*sizeof(float)); + poly->next = warpface->polys; + warpface->polys = poly; + poly->numverts = numverts+2; + VectorClear (total); + total_s = 0; + total_t = 0; + for (i=0 ; iverts[i+1]); + s = DotProduct (verts, warpface->texinfo->vecs[0]); + t = DotProduct (verts, warpface->texinfo->vecs[1]); + + total_s += s; + total_t += t; + VectorAdd (total, verts, total); + + poly->verts[i+1][3] = s; + poly->verts[i+1][4] = t; + } + + VectorScale (total, (1.0/numverts), poly->verts[0]); + poly->verts[0][3] = total_s/numverts; + poly->verts[0][4] = total_t/numverts; + + // copy first vertex to last + memcpy (poly->verts[i+1], poly->verts[1], sizeof(poly->verts[0])); +} + +/* +================ +Vk_SubdivideSurface + +Breaks a polygon up along axial 64 unit +boundaries so that turbulent and sky warps +can be done reasonably. +================ +*/ +void Vk_SubdivideSurface (msurface_t *fa, model_t *loadmodel) +{ + vec3_t verts[64]; + int numverts; + int i; + float *vec; + + warpface = fa; + + // + // convert edges back to a normal polygon + // + numverts = 0; + for (i=0 ; inumedges ; i++) + { + int lindex; + + lindex = loadmodel->surfedges[fa->firstedge + i]; + + if (lindex > 0) + vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position; + else + vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position; + VectorCopy (vec, verts[numverts]); + numverts++; + } + + SubdividePolygon (numverts, verts[0]); +} + +//========================================================= + +/* +============= +EmitWaterPolys + +Does a water warp on the pre-fragmented vkpoly_t chain +============= +*/ +void +EmitWaterPolys (msurface_t *fa, image_t *texture, float *modelMatrix, + float *color, qboolean solid_surface) +{ + vkpoly_t *p, *bp; + float *v; + int i; + + struct { + float model[16]; + float color[4]; + float time; + float scroll; + } polyUbo; + + polyUbo.color[0] = color[0]; + polyUbo.color[1] = color[1]; + polyUbo.color[2] = color[2]; + polyUbo.color[3] = color[3]; + polyUbo.time = r_newrefdef.time; + + if (fa->texinfo->flags & SURF_FLOWING) + polyUbo.scroll = (-64 * ((r_newrefdef.time*0.5) - (int)(r_newrefdef.time*0.5))) / 64.f; + else + polyUbo.scroll = 0; + + if (modelMatrix) + { + memcpy(polyUbo.model, modelMatrix, sizeof(float) * 16); + } + else + { + Mat_Identity(polyUbo.model); + } + + if (solid_surface) + { + // Solid surface + QVk_BindPipeline(&vk_drawPolySolidWarpPipeline); + } + else + { + // Blend surface + QVk_BindPipeline(&vk_drawPolyWarpPipeline); + } + + uint32_t uboOffset; + VkDescriptorSet uboDescriptorSet; + uint8_t *uboData = QVk_GetUniformBuffer(sizeof(polyUbo), &uboOffset, &uboDescriptorSet); + memcpy(uboData, &polyUbo, sizeof(polyUbo)); + + VkBuffer vbo; + VkDeviceSize vboOffset; + VkDescriptorSet descriptorSets[] = { texture->vk_texture.descriptorSet, uboDescriptorSet }; + + float gamma = 2.1F - vid_gamma->value; + + vkCmdPushConstants(vk_activeCmdbuffer, vk_drawTexQuadPipeline[vk_state.current_renderpass].layout, + VK_SHADER_STAGE_FRAGMENT_BIT, 17 * sizeof(float), sizeof(gamma), &gamma); + + if (solid_surface) + { + // Solid surface + vkCmdBindDescriptorSets( + vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + vk_drawPolySolidWarpPipeline.layout, 0, 2, + descriptorSets, 1, &uboOffset); + } + else + { + // Blend surface + vkCmdBindDescriptorSets( + vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + vk_drawPolyWarpPipeline.layout, 0, 2, + descriptorSets, 1, &uboOffset); + } + + for (bp = fa->polys; bp; bp = bp->next) + { + p = bp; + + if (Mesh_VertsRealloc(p->numverts)) + { + ri.Sys_Error(ERR_FATAL, "%s: can't allocate memory", __func__); + } + + for (i = 0, v = p->verts[0]; i < p->numverts; i++, v += VERTEXSIZE) + { + verts_buffer[i].vertex[0] = v[0]; + verts_buffer[i].vertex[1] = v[1]; + verts_buffer[i].vertex[2] = v[2]; + verts_buffer[i].texCoord[0] = v[3] / 64.f; + verts_buffer[i].texCoord[1] = v[4] / 64.f; + } + + uint8_t *vertData = QVk_GetVertexBuffer(sizeof(polyvert_t) * p->numverts, &vbo, &vboOffset); + memcpy(vertData, verts_buffer, sizeof(polyvert_t) * p->numverts); + + vkCmdBindVertexBuffers(vk_activeCmdbuffer, 0, 1, &vbo, &vboOffset); + vkCmdBindIndexBuffer(vk_activeCmdbuffer, QVk_GetTriangleFanIbo((p->numverts - 2) * 3), 0, VK_INDEX_TYPE_UINT16); + vkCmdDrawIndexed(vk_activeCmdbuffer, (p->numverts - 2) * 3, 1, 0, 0, 0); + } +} + + +//=================================================================== + + +static vec3_t skyclip[6] = { + {1,1,0}, + {1,-1,0}, + {0,-1,1}, + {0,1,1}, + {1,0,1}, + {-1,0,1} +}; + +// 1 = s, 2 = t, 3 = 2048 +static int st_to_vec[6][3] = +{ + {3,-1,2}, + {-3,1,2}, + + {1,3,2}, + {-1,-3,2}, + + {-2,-1,3}, // 0 degrees yaw, look straight up + {2,-1,-3} // look straight down + +// {-1,2,3}, +// {1,2,-3} +}; + +// s = [0]/[2], t = [1]/[2] +static int vec_to_st[6][3] = +{ + {-2,3,1}, + {2,3,-1}, + + {1,3,2}, + {-1,3,-2}, + + {-2,-1,3}, + {-2,1,-3} + +// {-1,2,3}, +// {1,2,-3} +}; + +static float skymins[2][6], skymaxs[2][6]; +static float sky_min, sky_max; + +static void DrawSkyPolygon (int nump, vec3_t vecs) +{ + int i; + vec3_t v, av; + float s, t, dv; + int axis; + float *vp; + + // decide which face it maps to + VectorCopy (vec3_origin, v); + for (i=0, vp=vecs ; i av[1] && av[0] > av[2]) + { + if (v[0] < 0) + axis = 1; + else + axis = 0; + } + else if (av[1] > av[2] && av[1] > av[0]) + { + if (v[1] < 0) + axis = 3; + else + axis = 2; + } + else + { + if (v[2] < 0) + axis = 5; + else + axis = 4; + } + + // project new texture coords + for (i=0 ; i 0) + dv = vecs[j - 1]; + else + dv = -vecs[-j - 1]; + if (dv < 0.001) + continue; // don't divide by zero + j = vec_to_st[axis][0]; + if (j < 0) + s = -vecs[-j -1] / dv; + else + s = vecs[j-1] / dv; + j = vec_to_st[axis][1]; + if (j < 0) + t = -vecs[-j -1] / dv; + else + t = vecs[j-1] / dv; + + if (s < skymins[0][axis]) + skymins[0][axis] = s; + if (t < skymins[1][axis]) + skymins[1][axis] = t; + if (s > skymaxs[0][axis]) + skymaxs[0][axis] = s; + if (t > skymaxs[1][axis]) + skymaxs[1][axis] = t; + } +} + +#define ON_EPSILON 0.1 // point on plane side epsilon +#define MAX_CLIP_VERTS 64 +static void ClipSkyPolygon (int nump, vec3_t vecs, int stage) +{ + float *norm; + float *v; + qboolean front, back; + float d, e; + float dists[MAX_CLIP_VERTS]; + int sides[MAX_CLIP_VERTS]; + vec3_t newv[2][MAX_CLIP_VERTS]; + int newc[2]; + int i, j; + + if (nump > MAX_CLIP_VERTS-2) + ri.Sys_Error (ERR_DROP, "%s: MAX_CLIP_VERTS", __func__); + if (stage == 6) + { // fully clipped, so draw it + DrawSkyPolygon (nump, vecs); + return; + } + + front = back = false; + norm = skyclip[stage]; + for (i=0, v = vecs ; i ON_EPSILON) + { + front = true; + sides[i] = SIDE_FRONT; + } + else if (d < -ON_EPSILON) + { + back = true; + sides[i] = SIDE_BACK; + } + else + sides[i] = SIDE_ON; + dists[i] = d; + } + + if (!front || !back) + { // not clipped + ClipSkyPolygon (nump, vecs, stage+1); + return; + } + + // clip it + sides[i] = sides[0]; + dists[i] = dists[0]; + VectorCopy (vecs, (vecs+(i*3)) ); + newc[0] = newc[1] = 0; + + for (i=0, v = vecs ; ipolys ; p ; p=p->next) + { + for (i=0 ; inumverts ; i++) + { + VectorSubtract (p->verts[i], r_origin, verts[i]); + } + ClipSkyPolygon (p->numverts, verts[0], 0); + } +} + + +/* +============== +R_ClearSkyBox +============== +*/ +void R_ClearSkyBox (void) +{ + int i; + + for (i=0 ; i<6 ; i++) + { + skymins[0][i] = skymins[1][i] = 9999; + skymaxs[0][i] = skymaxs[1][i] = -9999; + } +} + + +static void MakeSkyVec (float s, float t, int axis, float *vertexData) +{ + vec3_t v, b; + int j; + + float dist = (r_farsee->value == 0) ? 2300.0f : 4096.0f; + + b[0] = s * dist; + b[1] = t * dist; + b[2] = dist; + + for (j = 0; j<3; j++) + { + int k; + + k = st_to_vec[axis][j]; + if (k < 0) + v[j] = -b[-k - 1]; + else + v[j] = b[k - 1]; + } + + // avoid bilerp seam + s = (s + 1)*0.5; + t = (t + 1)*0.5; + + if (s < sky_min) + s = sky_min; + else if (s > sky_max) + s = sky_max; + if (t < sky_min) + t = sky_min; + else if (t > sky_max) + t = sky_max; + + t = 1.0 - t; + + vertexData[0] = v[0]; + vertexData[1] = v[1]; + vertexData[2] = v[2]; + vertexData[3] = s; + vertexData[4] = t; +} + +/* +============== +R_DrawSkyBox +============== +*/ +static int skytexorder[6] = {0,2,1,3,4,5}; +void R_DrawSkyBox (void) +{ + int i; + + if (skyrotate) + { // check for no sky at all + for (i = 0; i<6; i++) + if (skymins[0][i] < skymaxs[0][i] + && skymins[1][i] < skymaxs[1][i]) + break; + if (i == 6) + return; // nothing visible + } + + float model[16]; + Mat_Identity(model); + Mat_Rotate(model, r_newrefdef.time * skyrotate, skyaxis[0], skyaxis[1], skyaxis[2]); + Mat_Translate(model, r_origin[0], r_origin[1], r_origin[2]); + + struct { + float data[5]; + } skyVerts[4]; + + QVk_BindPipeline(&vk_drawSkyboxPipeline); + uint32_t uboOffset; + VkDescriptorSet uboDescriptorSet; + uint8_t *uboData = QVk_GetUniformBuffer(sizeof(model), &uboOffset, &uboDescriptorSet); + memcpy(uboData, model, sizeof(model)); + + for (i = 0; i<6; i++) + { + if (skyrotate) + { // hack, forces full sky to draw when rotating + skymins[0][i] = -1; + skymins[1][i] = -1; + skymaxs[0][i] = 1; + skymaxs[1][i] = 1; + } + + if (skymins[0][i] >= skymaxs[0][i] + || skymins[1][i] >= skymaxs[1][i]) + continue; + + MakeSkyVec(skymins[0][i], skymins[1][i], i, skyVerts[0].data); + MakeSkyVec(skymins[0][i], skymaxs[1][i], i, skyVerts[1].data); + MakeSkyVec(skymaxs[0][i], skymaxs[1][i], i, skyVerts[2].data); + MakeSkyVec(skymaxs[0][i], skymins[1][i], i, skyVerts[3].data); + + float verts[] = { + skyVerts[0].data[0], skyVerts[0].data[1], skyVerts[0].data[2], skyVerts[0].data[3], skyVerts[0].data[4], + skyVerts[1].data[0], skyVerts[1].data[1], skyVerts[1].data[2], skyVerts[1].data[3], skyVerts[1].data[4], + skyVerts[2].data[0], skyVerts[2].data[1], skyVerts[2].data[2], skyVerts[2].data[3], skyVerts[2].data[4], + skyVerts[0].data[0], skyVerts[0].data[1], skyVerts[0].data[2], skyVerts[0].data[3], skyVerts[0].data[4], + skyVerts[2].data[0], skyVerts[2].data[1], skyVerts[2].data[2], skyVerts[2].data[3], skyVerts[2].data[4], + skyVerts[3].data[0], skyVerts[3].data[1], skyVerts[3].data[2], skyVerts[3].data[3], skyVerts[3].data[4] + }; + + VkBuffer vbo; + VkDeviceSize vboOffset; + uint8_t *vertData = QVk_GetVertexBuffer(sizeof(verts), &vbo, &vboOffset); + memcpy(vertData, verts, sizeof(verts)); + + VkDescriptorSet descriptorSets[] = { sky_images[skytexorder[i]]->vk_texture.descriptorSet, uboDescriptorSet }; + + float gamma = 2.1F - vid_gamma->value; + + vkCmdPushConstants(vk_activeCmdbuffer, vk_drawTexQuadPipeline[vk_state.current_renderpass].layout, + VK_SHADER_STAGE_FRAGMENT_BIT, 17 * sizeof(float), sizeof(gamma), &gamma); + + vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + vk_drawSkyboxPipeline.layout, 0, 2, descriptorSets, 1, &uboOffset); + vkCmdBindVertexBuffers(vk_activeCmdbuffer, 0, 1, &vbo, &vboOffset); + vkCmdDraw(vk_activeCmdbuffer, 6, 1, 0, 0); + } +} + + +/* +============ +RE_SetSky +============ +*/ +// 3dstudio environment map names +static char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"}; +void RE_SetSky (char *name, float rotate, vec3_t axis) +{ + int i; + char pathname[MAX_QPATH]; + + strncpy(skyname, name, sizeof(skyname) - 1); + skyrotate = rotate; + VectorCopy(axis, skyaxis); + + for (i = 0; i<6; i++) + { + // chop down rotating skies for less memory + if (vk_skymip->value || skyrotate) + vk_picmip->value++; + + Com_sprintf(pathname, sizeof(pathname), "env/%s%s.tga", skyname, suf[i]); + + sky_images[i] = Vk_FindImage(pathname, it_sky); + if (!sky_images[i]) { + Com_sprintf(pathname, sizeof(pathname), "pics/Skies/%s%s.m8", skyname, suf[i]); + sky_images[i] = Vk_FindImage(pathname, it_sky); + } + + if (!sky_images[i]) + sky_images[i] = r_notexture; + + if (vk_skymip->value || skyrotate) + { // take less memory + vk_picmip->value--; + sky_min = 1.0 / 256; + sky_max = 255.0 / 256; + } + else + { + sky_min = 1.0 / 512; + sky_max = 511.0 / 512; + } + } +} diff --git a/src/vk/volk/volk.c b/src/vk/volk/volk.c new file mode 100644 index 0000000..3926871 --- /dev/null +++ b/src/vk/volk/volk.c @@ -0,0 +1,1905 @@ +/* This file is part of volk library; see volk.h for version/license details */ +/* clang-format off */ +#include "volk.h" + +#ifdef _WIN32 + typedef const char* LPCSTR; + typedef struct HINSTANCE__* HINSTANCE; + typedef HINSTANCE HMODULE; + #ifdef _WIN64 + typedef __int64 (__stdcall* FARPROC)(void); + #else + typedef int (__stdcall* FARPROC)(void); + #endif +#else +# include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 +__declspec(dllimport) HMODULE __stdcall LoadLibraryA(LPCSTR); +__declspec(dllimport) FARPROC __stdcall GetProcAddress(HMODULE, LPCSTR); +#endif + +static VkInstance loadedInstance = VK_NULL_HANDLE; +static VkDevice loadedDevice = VK_NULL_HANDLE; + +static void volkGenLoadLoader(void* context, PFN_vkVoidFunction (*load)(void*, const char*)); +static void volkGenLoadInstance(void* context, PFN_vkVoidFunction (*load)(void*, const char*)); +static void volkGenLoadDevice(void* context, PFN_vkVoidFunction (*load)(void*, const char*)); +static void volkGenLoadDeviceTable(struct VolkDeviceTable* table, void* context, PFN_vkVoidFunction (*load)(void*, const char*)); + +static PFN_vkVoidFunction vkGetInstanceProcAddrStub(void* context, const char* name) +{ + return vkGetInstanceProcAddr((VkInstance)context, name); +} + +static PFN_vkVoidFunction vkGetDeviceProcAddrStub(void* context, const char* name) +{ + return vkGetDeviceProcAddr((VkDevice)context, name); +} + +VkResult volkInitialize(void) +{ +#if defined(_WIN32) + HMODULE module = LoadLibraryA("vulkan-1.dll"); + if (!module) + return VK_ERROR_INITIALIZATION_FAILED; + + // note: function pointer is cast through void function pointer to silence cast-function-type warning on gcc8 + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)(void(*)(void))GetProcAddress(module, "vkGetInstanceProcAddr"); +#elif defined(__APPLE__) + void* module = dlopen("libvulkan.dylib", RTLD_NOW | RTLD_LOCAL); + if (!module) + module = dlopen("libvulkan.1.dylib", RTLD_NOW | RTLD_LOCAL); + if (!module) + module = dlopen("libMoltenVK.dylib", RTLD_NOW | RTLD_LOCAL); + if (!module) + return VK_ERROR_INITIALIZATION_FAILED; + + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym(module, "vkGetInstanceProcAddr"); +#else + void* module = dlopen("libvulkan.so.1", RTLD_NOW | RTLD_LOCAL); + if (!module) + module = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL); + if (!module) + return VK_ERROR_INITIALIZATION_FAILED; + + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym(module, "vkGetInstanceProcAddr"); +#endif + + volkGenLoadLoader(NULL, vkGetInstanceProcAddrStub); + + return VK_SUCCESS; +} + +void volkInitializeCustom(PFN_vkGetInstanceProcAddr handler) +{ + vkGetInstanceProcAddr = handler; + + volkGenLoadLoader(NULL, vkGetInstanceProcAddrStub); +} + +uint32_t volkGetInstanceVersion(void) +{ +#if defined(VK_VERSION_1_1) + uint32_t apiVersion = 0; + if (vkEnumerateInstanceVersion && vkEnumerateInstanceVersion(&apiVersion) == VK_SUCCESS) + return apiVersion; +#endif + + if (vkCreateInstance) + return VK_API_VERSION_1_0; + + return 0; +} + +void volkLoadInstance(VkInstance instance) +{ + loadedInstance = instance; + volkGenLoadInstance(instance, vkGetInstanceProcAddrStub); + volkGenLoadDevice(instance, vkGetInstanceProcAddrStub); +} + +void volkLoadInstanceOnly(VkInstance instance) +{ + loadedInstance = instance; + volkGenLoadInstance(instance, vkGetInstanceProcAddrStub); +} + +VkInstance volkGetLoadedInstance() +{ + return loadedInstance; +} + +void volkLoadDevice(VkDevice device) +{ + loadedDevice = device; + volkGenLoadDevice(device, vkGetDeviceProcAddrStub); +} + +VkDevice volkGetLoadedDevice() +{ + return loadedDevice; +} + +void volkLoadDeviceTable(struct VolkDeviceTable* table, VkDevice device) +{ + volkGenLoadDeviceTable(table, device, vkGetDeviceProcAddrStub); +} + +static void volkGenLoadLoader(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) +{ + /* VOLK_GENERATE_LOAD_LOADER */ +#if defined(VK_VERSION_1_0) + vkCreateInstance = (PFN_vkCreateInstance)load(context, "vkCreateInstance"); + vkEnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)load(context, "vkEnumerateInstanceExtensionProperties"); + vkEnumerateInstanceLayerProperties = (PFN_vkEnumerateInstanceLayerProperties)load(context, "vkEnumerateInstanceLayerProperties"); +#endif /* defined(VK_VERSION_1_0) */ +#if defined(VK_VERSION_1_1) + vkEnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion)load(context, "vkEnumerateInstanceVersion"); +#endif /* defined(VK_VERSION_1_1) */ + /* VOLK_GENERATE_LOAD_LOADER */ +} + +static void volkGenLoadInstance(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) +{ + /* VOLK_GENERATE_LOAD_INSTANCE */ +#if defined(VK_VERSION_1_0) + vkCreateDevice = (PFN_vkCreateDevice)load(context, "vkCreateDevice"); + vkDestroyInstance = (PFN_vkDestroyInstance)load(context, "vkDestroyInstance"); + vkEnumerateDeviceExtensionProperties = (PFN_vkEnumerateDeviceExtensionProperties)load(context, "vkEnumerateDeviceExtensionProperties"); + vkEnumerateDeviceLayerProperties = (PFN_vkEnumerateDeviceLayerProperties)load(context, "vkEnumerateDeviceLayerProperties"); + vkEnumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices)load(context, "vkEnumeratePhysicalDevices"); + vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)load(context, "vkGetDeviceProcAddr"); + vkGetPhysicalDeviceFeatures = (PFN_vkGetPhysicalDeviceFeatures)load(context, "vkGetPhysicalDeviceFeatures"); + vkGetPhysicalDeviceFormatProperties = (PFN_vkGetPhysicalDeviceFormatProperties)load(context, "vkGetPhysicalDeviceFormatProperties"); + vkGetPhysicalDeviceImageFormatProperties = (PFN_vkGetPhysicalDeviceImageFormatProperties)load(context, "vkGetPhysicalDeviceImageFormatProperties"); + vkGetPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties)load(context, "vkGetPhysicalDeviceMemoryProperties"); + vkGetPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties)load(context, "vkGetPhysicalDeviceProperties"); + vkGetPhysicalDeviceQueueFamilyProperties = (PFN_vkGetPhysicalDeviceQueueFamilyProperties)load(context, "vkGetPhysicalDeviceQueueFamilyProperties"); + vkGetPhysicalDeviceSparseImageFormatProperties = (PFN_vkGetPhysicalDeviceSparseImageFormatProperties)load(context, "vkGetPhysicalDeviceSparseImageFormatProperties"); +#endif /* defined(VK_VERSION_1_0) */ +#if defined(VK_VERSION_1_1) + vkEnumeratePhysicalDeviceGroups = (PFN_vkEnumeratePhysicalDeviceGroups)load(context, "vkEnumeratePhysicalDeviceGroups"); + vkGetPhysicalDeviceExternalBufferProperties = (PFN_vkGetPhysicalDeviceExternalBufferProperties)load(context, "vkGetPhysicalDeviceExternalBufferProperties"); + vkGetPhysicalDeviceExternalFenceProperties = (PFN_vkGetPhysicalDeviceExternalFenceProperties)load(context, "vkGetPhysicalDeviceExternalFenceProperties"); + vkGetPhysicalDeviceExternalSemaphoreProperties = (PFN_vkGetPhysicalDeviceExternalSemaphoreProperties)load(context, "vkGetPhysicalDeviceExternalSemaphoreProperties"); + vkGetPhysicalDeviceFeatures2 = (PFN_vkGetPhysicalDeviceFeatures2)load(context, "vkGetPhysicalDeviceFeatures2"); + vkGetPhysicalDeviceFormatProperties2 = (PFN_vkGetPhysicalDeviceFormatProperties2)load(context, "vkGetPhysicalDeviceFormatProperties2"); + vkGetPhysicalDeviceImageFormatProperties2 = (PFN_vkGetPhysicalDeviceImageFormatProperties2)load(context, "vkGetPhysicalDeviceImageFormatProperties2"); + vkGetPhysicalDeviceMemoryProperties2 = (PFN_vkGetPhysicalDeviceMemoryProperties2)load(context, "vkGetPhysicalDeviceMemoryProperties2"); + vkGetPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2)load(context, "vkGetPhysicalDeviceProperties2"); + vkGetPhysicalDeviceQueueFamilyProperties2 = (PFN_vkGetPhysicalDeviceQueueFamilyProperties2)load(context, "vkGetPhysicalDeviceQueueFamilyProperties2"); + vkGetPhysicalDeviceSparseImageFormatProperties2 = (PFN_vkGetPhysicalDeviceSparseImageFormatProperties2)load(context, "vkGetPhysicalDeviceSparseImageFormatProperties2"); +#endif /* defined(VK_VERSION_1_1) */ +#if defined(VK_EXT_acquire_xlib_display) + vkAcquireXlibDisplayEXT = (PFN_vkAcquireXlibDisplayEXT)load(context, "vkAcquireXlibDisplayEXT"); + vkGetRandROutputDisplayEXT = (PFN_vkGetRandROutputDisplayEXT)load(context, "vkGetRandROutputDisplayEXT"); +#endif /* defined(VK_EXT_acquire_xlib_display) */ +#if defined(VK_EXT_calibrated_timestamps) + vkGetPhysicalDeviceCalibrateableTimeDomainsEXT = (PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)load(context, "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT"); +#endif /* defined(VK_EXT_calibrated_timestamps) */ +#if defined(VK_EXT_debug_report) + vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)load(context, "vkCreateDebugReportCallbackEXT"); + vkDebugReportMessageEXT = (PFN_vkDebugReportMessageEXT)load(context, "vkDebugReportMessageEXT"); + vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)load(context, "vkDestroyDebugReportCallbackEXT"); +#endif /* defined(VK_EXT_debug_report) */ +#if defined(VK_EXT_debug_utils) + vkCmdBeginDebugUtilsLabelEXT = (PFN_vkCmdBeginDebugUtilsLabelEXT)load(context, "vkCmdBeginDebugUtilsLabelEXT"); + vkCmdEndDebugUtilsLabelEXT = (PFN_vkCmdEndDebugUtilsLabelEXT)load(context, "vkCmdEndDebugUtilsLabelEXT"); + vkCmdInsertDebugUtilsLabelEXT = (PFN_vkCmdInsertDebugUtilsLabelEXT)load(context, "vkCmdInsertDebugUtilsLabelEXT"); + vkCreateDebugUtilsMessengerEXT = (PFN_vkCreateDebugUtilsMessengerEXT)load(context, "vkCreateDebugUtilsMessengerEXT"); + vkDestroyDebugUtilsMessengerEXT = (PFN_vkDestroyDebugUtilsMessengerEXT)load(context, "vkDestroyDebugUtilsMessengerEXT"); + vkQueueBeginDebugUtilsLabelEXT = (PFN_vkQueueBeginDebugUtilsLabelEXT)load(context, "vkQueueBeginDebugUtilsLabelEXT"); + vkQueueEndDebugUtilsLabelEXT = (PFN_vkQueueEndDebugUtilsLabelEXT)load(context, "vkQueueEndDebugUtilsLabelEXT"); + vkQueueInsertDebugUtilsLabelEXT = (PFN_vkQueueInsertDebugUtilsLabelEXT)load(context, "vkQueueInsertDebugUtilsLabelEXT"); + vkSetDebugUtilsObjectNameEXT = (PFN_vkSetDebugUtilsObjectNameEXT)load(context, "vkSetDebugUtilsObjectNameEXT"); + vkSetDebugUtilsObjectTagEXT = (PFN_vkSetDebugUtilsObjectTagEXT)load(context, "vkSetDebugUtilsObjectTagEXT"); + vkSubmitDebugUtilsMessageEXT = (PFN_vkSubmitDebugUtilsMessageEXT)load(context, "vkSubmitDebugUtilsMessageEXT"); +#endif /* defined(VK_EXT_debug_utils) */ +#if defined(VK_EXT_direct_mode_display) + vkReleaseDisplayEXT = (PFN_vkReleaseDisplayEXT)load(context, "vkReleaseDisplayEXT"); +#endif /* defined(VK_EXT_direct_mode_display) */ +#if defined(VK_EXT_directfb_surface) + vkCreateDirectFBSurfaceEXT = (PFN_vkCreateDirectFBSurfaceEXT)load(context, "vkCreateDirectFBSurfaceEXT"); + vkGetPhysicalDeviceDirectFBPresentationSupportEXT = (PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT)load(context, "vkGetPhysicalDeviceDirectFBPresentationSupportEXT"); +#endif /* defined(VK_EXT_directfb_surface) */ +#if defined(VK_EXT_display_surface_counter) + vkGetPhysicalDeviceSurfaceCapabilities2EXT = (PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT)load(context, "vkGetPhysicalDeviceSurfaceCapabilities2EXT"); +#endif /* defined(VK_EXT_display_surface_counter) */ +#if defined(VK_EXT_full_screen_exclusive) + vkGetPhysicalDeviceSurfacePresentModes2EXT = (PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT)load(context, "vkGetPhysicalDeviceSurfacePresentModes2EXT"); +#endif /* defined(VK_EXT_full_screen_exclusive) */ +#if defined(VK_EXT_headless_surface) + vkCreateHeadlessSurfaceEXT = (PFN_vkCreateHeadlessSurfaceEXT)load(context, "vkCreateHeadlessSurfaceEXT"); +#endif /* defined(VK_EXT_headless_surface) */ +#if defined(VK_EXT_metal_surface) + vkCreateMetalSurfaceEXT = (PFN_vkCreateMetalSurfaceEXT)load(context, "vkCreateMetalSurfaceEXT"); +#endif /* defined(VK_EXT_metal_surface) */ +#if defined(VK_EXT_sample_locations) + vkGetPhysicalDeviceMultisamplePropertiesEXT = (PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT)load(context, "vkGetPhysicalDeviceMultisamplePropertiesEXT"); +#endif /* defined(VK_EXT_sample_locations) */ +#if defined(VK_EXT_tooling_info) + vkGetPhysicalDeviceToolPropertiesEXT = (PFN_vkGetPhysicalDeviceToolPropertiesEXT)load(context, "vkGetPhysicalDeviceToolPropertiesEXT"); +#endif /* defined(VK_EXT_tooling_info) */ +#if defined(VK_FUCHSIA_imagepipe_surface) + vkCreateImagePipeSurfaceFUCHSIA = (PFN_vkCreateImagePipeSurfaceFUCHSIA)load(context, "vkCreateImagePipeSurfaceFUCHSIA"); +#endif /* defined(VK_FUCHSIA_imagepipe_surface) */ +#if defined(VK_GGP_stream_descriptor_surface) + vkCreateStreamDescriptorSurfaceGGP = (PFN_vkCreateStreamDescriptorSurfaceGGP)load(context, "vkCreateStreamDescriptorSurfaceGGP"); +#endif /* defined(VK_GGP_stream_descriptor_surface) */ +#if defined(VK_KHR_android_surface) + vkCreateAndroidSurfaceKHR = (PFN_vkCreateAndroidSurfaceKHR)load(context, "vkCreateAndroidSurfaceKHR"); +#endif /* defined(VK_KHR_android_surface) */ +#if defined(VK_KHR_device_group_creation) + vkEnumeratePhysicalDeviceGroupsKHR = (PFN_vkEnumeratePhysicalDeviceGroupsKHR)load(context, "vkEnumeratePhysicalDeviceGroupsKHR"); +#endif /* defined(VK_KHR_device_group_creation) */ +#if defined(VK_KHR_display) + vkCreateDisplayModeKHR = (PFN_vkCreateDisplayModeKHR)load(context, "vkCreateDisplayModeKHR"); + vkCreateDisplayPlaneSurfaceKHR = (PFN_vkCreateDisplayPlaneSurfaceKHR)load(context, "vkCreateDisplayPlaneSurfaceKHR"); + vkGetDisplayModePropertiesKHR = (PFN_vkGetDisplayModePropertiesKHR)load(context, "vkGetDisplayModePropertiesKHR"); + vkGetDisplayPlaneCapabilitiesKHR = (PFN_vkGetDisplayPlaneCapabilitiesKHR)load(context, "vkGetDisplayPlaneCapabilitiesKHR"); + vkGetDisplayPlaneSupportedDisplaysKHR = (PFN_vkGetDisplayPlaneSupportedDisplaysKHR)load(context, "vkGetDisplayPlaneSupportedDisplaysKHR"); + vkGetPhysicalDeviceDisplayPlanePropertiesKHR = (PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)load(context, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR"); + vkGetPhysicalDeviceDisplayPropertiesKHR = (PFN_vkGetPhysicalDeviceDisplayPropertiesKHR)load(context, "vkGetPhysicalDeviceDisplayPropertiesKHR"); +#endif /* defined(VK_KHR_display) */ +#if defined(VK_KHR_external_fence_capabilities) + vkGetPhysicalDeviceExternalFencePropertiesKHR = (PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR)load(context, "vkGetPhysicalDeviceExternalFencePropertiesKHR"); +#endif /* defined(VK_KHR_external_fence_capabilities) */ +#if defined(VK_KHR_external_memory_capabilities) + vkGetPhysicalDeviceExternalBufferPropertiesKHR = (PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR)load(context, "vkGetPhysicalDeviceExternalBufferPropertiesKHR"); +#endif /* defined(VK_KHR_external_memory_capabilities) */ +#if defined(VK_KHR_external_semaphore_capabilities) + vkGetPhysicalDeviceExternalSemaphorePropertiesKHR = (PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR)load(context, "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR"); +#endif /* defined(VK_KHR_external_semaphore_capabilities) */ +#if defined(VK_KHR_get_display_properties2) + vkGetDisplayModeProperties2KHR = (PFN_vkGetDisplayModeProperties2KHR)load(context, "vkGetDisplayModeProperties2KHR"); + vkGetDisplayPlaneCapabilities2KHR = (PFN_vkGetDisplayPlaneCapabilities2KHR)load(context, "vkGetDisplayPlaneCapabilities2KHR"); + vkGetPhysicalDeviceDisplayPlaneProperties2KHR = (PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR)load(context, "vkGetPhysicalDeviceDisplayPlaneProperties2KHR"); + vkGetPhysicalDeviceDisplayProperties2KHR = (PFN_vkGetPhysicalDeviceDisplayProperties2KHR)load(context, "vkGetPhysicalDeviceDisplayProperties2KHR"); +#endif /* defined(VK_KHR_get_display_properties2) */ +#if defined(VK_KHR_get_physical_device_properties2) + vkGetPhysicalDeviceFeatures2KHR = (PFN_vkGetPhysicalDeviceFeatures2KHR)load(context, "vkGetPhysicalDeviceFeatures2KHR"); + vkGetPhysicalDeviceFormatProperties2KHR = (PFN_vkGetPhysicalDeviceFormatProperties2KHR)load(context, "vkGetPhysicalDeviceFormatProperties2KHR"); + vkGetPhysicalDeviceImageFormatProperties2KHR = (PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)load(context, "vkGetPhysicalDeviceImageFormatProperties2KHR"); + vkGetPhysicalDeviceMemoryProperties2KHR = (PFN_vkGetPhysicalDeviceMemoryProperties2KHR)load(context, "vkGetPhysicalDeviceMemoryProperties2KHR"); + vkGetPhysicalDeviceProperties2KHR = (PFN_vkGetPhysicalDeviceProperties2KHR)load(context, "vkGetPhysicalDeviceProperties2KHR"); + vkGetPhysicalDeviceQueueFamilyProperties2KHR = (PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)load(context, "vkGetPhysicalDeviceQueueFamilyProperties2KHR"); + vkGetPhysicalDeviceSparseImageFormatProperties2KHR = (PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)load(context, "vkGetPhysicalDeviceSparseImageFormatProperties2KHR"); +#endif /* defined(VK_KHR_get_physical_device_properties2) */ +#if defined(VK_KHR_get_surface_capabilities2) + vkGetPhysicalDeviceSurfaceCapabilities2KHR = (PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR)load(context, "vkGetPhysicalDeviceSurfaceCapabilities2KHR"); + vkGetPhysicalDeviceSurfaceFormats2KHR = (PFN_vkGetPhysicalDeviceSurfaceFormats2KHR)load(context, "vkGetPhysicalDeviceSurfaceFormats2KHR"); +#endif /* defined(VK_KHR_get_surface_capabilities2) */ +#if defined(VK_KHR_performance_query) + vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR = (PFN_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR)load(context, "vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR"); + vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR = (PFN_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR)load(context, "vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR"); +#endif /* defined(VK_KHR_performance_query) */ +#if defined(VK_KHR_surface) + vkDestroySurfaceKHR = (PFN_vkDestroySurfaceKHR)load(context, "vkDestroySurfaceKHR"); + vkGetPhysicalDeviceSurfaceCapabilitiesKHR = (PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)load(context, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"); + vkGetPhysicalDeviceSurfaceFormatsKHR = (PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)load(context, "vkGetPhysicalDeviceSurfaceFormatsKHR"); + vkGetPhysicalDeviceSurfacePresentModesKHR = (PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)load(context, "vkGetPhysicalDeviceSurfacePresentModesKHR"); + vkGetPhysicalDeviceSurfaceSupportKHR = (PFN_vkGetPhysicalDeviceSurfaceSupportKHR)load(context, "vkGetPhysicalDeviceSurfaceSupportKHR"); +#endif /* defined(VK_KHR_surface) */ +#if defined(VK_KHR_wayland_surface) + vkCreateWaylandSurfaceKHR = (PFN_vkCreateWaylandSurfaceKHR)load(context, "vkCreateWaylandSurfaceKHR"); + vkGetPhysicalDeviceWaylandPresentationSupportKHR = (PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)load(context, "vkGetPhysicalDeviceWaylandPresentationSupportKHR"); +#endif /* defined(VK_KHR_wayland_surface) */ +#if defined(VK_KHR_win32_surface) + vkCreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR)load(context, "vkCreateWin32SurfaceKHR"); + vkGetPhysicalDeviceWin32PresentationSupportKHR = (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)load(context, "vkGetPhysicalDeviceWin32PresentationSupportKHR"); +#endif /* defined(VK_KHR_win32_surface) */ +#if defined(VK_KHR_xcb_surface) + vkCreateXcbSurfaceKHR = (PFN_vkCreateXcbSurfaceKHR)load(context, "vkCreateXcbSurfaceKHR"); + vkGetPhysicalDeviceXcbPresentationSupportKHR = (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)load(context, "vkGetPhysicalDeviceXcbPresentationSupportKHR"); +#endif /* defined(VK_KHR_xcb_surface) */ +#if defined(VK_KHR_xlib_surface) + vkCreateXlibSurfaceKHR = (PFN_vkCreateXlibSurfaceKHR)load(context, "vkCreateXlibSurfaceKHR"); + vkGetPhysicalDeviceXlibPresentationSupportKHR = (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)load(context, "vkGetPhysicalDeviceXlibPresentationSupportKHR"); +#endif /* defined(VK_KHR_xlib_surface) */ +#if defined(VK_MVK_ios_surface) + vkCreateIOSSurfaceMVK = (PFN_vkCreateIOSSurfaceMVK)load(context, "vkCreateIOSSurfaceMVK"); +#endif /* defined(VK_MVK_ios_surface) */ +#if defined(VK_MVK_macos_surface) + vkCreateMacOSSurfaceMVK = (PFN_vkCreateMacOSSurfaceMVK)load(context, "vkCreateMacOSSurfaceMVK"); +#endif /* defined(VK_MVK_macos_surface) */ +#if defined(VK_NN_vi_surface) + vkCreateViSurfaceNN = (PFN_vkCreateViSurfaceNN)load(context, "vkCreateViSurfaceNN"); +#endif /* defined(VK_NN_vi_surface) */ +#if defined(VK_NV_cooperative_matrix) + vkGetPhysicalDeviceCooperativeMatrixPropertiesNV = (PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV)load(context, "vkGetPhysicalDeviceCooperativeMatrixPropertiesNV"); +#endif /* defined(VK_NV_cooperative_matrix) */ +#if defined(VK_NV_coverage_reduction_mode) + vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV = (PFN_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV)load(context, "vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV"); +#endif /* defined(VK_NV_coverage_reduction_mode) */ +#if defined(VK_NV_external_memory_capabilities) + vkGetPhysicalDeviceExternalImageFormatPropertiesNV = (PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV)load(context, "vkGetPhysicalDeviceExternalImageFormatPropertiesNV"); +#endif /* defined(VK_NV_external_memory_capabilities) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) + vkGetPhysicalDevicePresentRectanglesKHR = (PFN_vkGetPhysicalDevicePresentRectanglesKHR)load(context, "vkGetPhysicalDevicePresentRectanglesKHR"); +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ + /* VOLK_GENERATE_LOAD_INSTANCE */ +} + +static void volkGenLoadDevice(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) +{ + /* VOLK_GENERATE_LOAD_DEVICE */ +#if defined(VK_VERSION_1_0) + vkAllocateCommandBuffers = (PFN_vkAllocateCommandBuffers)load(context, "vkAllocateCommandBuffers"); + vkAllocateDescriptorSets = (PFN_vkAllocateDescriptorSets)load(context, "vkAllocateDescriptorSets"); + vkAllocateMemory = (PFN_vkAllocateMemory)load(context, "vkAllocateMemory"); + vkBeginCommandBuffer = (PFN_vkBeginCommandBuffer)load(context, "vkBeginCommandBuffer"); + vkBindBufferMemory = (PFN_vkBindBufferMemory)load(context, "vkBindBufferMemory"); + vkBindImageMemory = (PFN_vkBindImageMemory)load(context, "vkBindImageMemory"); + vkCmdBeginQuery = (PFN_vkCmdBeginQuery)load(context, "vkCmdBeginQuery"); + vkCmdBeginRenderPass = (PFN_vkCmdBeginRenderPass)load(context, "vkCmdBeginRenderPass"); + vkCmdBindDescriptorSets = (PFN_vkCmdBindDescriptorSets)load(context, "vkCmdBindDescriptorSets"); + vkCmdBindIndexBuffer = (PFN_vkCmdBindIndexBuffer)load(context, "vkCmdBindIndexBuffer"); + vkCmdBindPipeline = (PFN_vkCmdBindPipeline)load(context, "vkCmdBindPipeline"); + vkCmdBindVertexBuffers = (PFN_vkCmdBindVertexBuffers)load(context, "vkCmdBindVertexBuffers"); + vkCmdBlitImage = (PFN_vkCmdBlitImage)load(context, "vkCmdBlitImage"); + vkCmdClearAttachments = (PFN_vkCmdClearAttachments)load(context, "vkCmdClearAttachments"); + vkCmdClearColorImage = (PFN_vkCmdClearColorImage)load(context, "vkCmdClearColorImage"); + vkCmdClearDepthStencilImage = (PFN_vkCmdClearDepthStencilImage)load(context, "vkCmdClearDepthStencilImage"); + vkCmdCopyBuffer = (PFN_vkCmdCopyBuffer)load(context, "vkCmdCopyBuffer"); + vkCmdCopyBufferToImage = (PFN_vkCmdCopyBufferToImage)load(context, "vkCmdCopyBufferToImage"); + vkCmdCopyImage = (PFN_vkCmdCopyImage)load(context, "vkCmdCopyImage"); + vkCmdCopyImageToBuffer = (PFN_vkCmdCopyImageToBuffer)load(context, "vkCmdCopyImageToBuffer"); + vkCmdCopyQueryPoolResults = (PFN_vkCmdCopyQueryPoolResults)load(context, "vkCmdCopyQueryPoolResults"); + vkCmdDispatch = (PFN_vkCmdDispatch)load(context, "vkCmdDispatch"); + vkCmdDispatchIndirect = (PFN_vkCmdDispatchIndirect)load(context, "vkCmdDispatchIndirect"); + vkCmdDraw = (PFN_vkCmdDraw)load(context, "vkCmdDraw"); + vkCmdDrawIndexed = (PFN_vkCmdDrawIndexed)load(context, "vkCmdDrawIndexed"); + vkCmdDrawIndexedIndirect = (PFN_vkCmdDrawIndexedIndirect)load(context, "vkCmdDrawIndexedIndirect"); + vkCmdDrawIndirect = (PFN_vkCmdDrawIndirect)load(context, "vkCmdDrawIndirect"); + vkCmdEndQuery = (PFN_vkCmdEndQuery)load(context, "vkCmdEndQuery"); + vkCmdEndRenderPass = (PFN_vkCmdEndRenderPass)load(context, "vkCmdEndRenderPass"); + vkCmdExecuteCommands = (PFN_vkCmdExecuteCommands)load(context, "vkCmdExecuteCommands"); + vkCmdFillBuffer = (PFN_vkCmdFillBuffer)load(context, "vkCmdFillBuffer"); + vkCmdNextSubpass = (PFN_vkCmdNextSubpass)load(context, "vkCmdNextSubpass"); + vkCmdPipelineBarrier = (PFN_vkCmdPipelineBarrier)load(context, "vkCmdPipelineBarrier"); + vkCmdPushConstants = (PFN_vkCmdPushConstants)load(context, "vkCmdPushConstants"); + vkCmdResetEvent = (PFN_vkCmdResetEvent)load(context, "vkCmdResetEvent"); + vkCmdResetQueryPool = (PFN_vkCmdResetQueryPool)load(context, "vkCmdResetQueryPool"); + vkCmdResolveImage = (PFN_vkCmdResolveImage)load(context, "vkCmdResolveImage"); + vkCmdSetBlendConstants = (PFN_vkCmdSetBlendConstants)load(context, "vkCmdSetBlendConstants"); + vkCmdSetDepthBias = (PFN_vkCmdSetDepthBias)load(context, "vkCmdSetDepthBias"); + vkCmdSetDepthBounds = (PFN_vkCmdSetDepthBounds)load(context, "vkCmdSetDepthBounds"); + vkCmdSetEvent = (PFN_vkCmdSetEvent)load(context, "vkCmdSetEvent"); + vkCmdSetLineWidth = (PFN_vkCmdSetLineWidth)load(context, "vkCmdSetLineWidth"); + vkCmdSetScissor = (PFN_vkCmdSetScissor)load(context, "vkCmdSetScissor"); + vkCmdSetStencilCompareMask = (PFN_vkCmdSetStencilCompareMask)load(context, "vkCmdSetStencilCompareMask"); + vkCmdSetStencilReference = (PFN_vkCmdSetStencilReference)load(context, "vkCmdSetStencilReference"); + vkCmdSetStencilWriteMask = (PFN_vkCmdSetStencilWriteMask)load(context, "vkCmdSetStencilWriteMask"); + vkCmdSetViewport = (PFN_vkCmdSetViewport)load(context, "vkCmdSetViewport"); + vkCmdUpdateBuffer = (PFN_vkCmdUpdateBuffer)load(context, "vkCmdUpdateBuffer"); + vkCmdWaitEvents = (PFN_vkCmdWaitEvents)load(context, "vkCmdWaitEvents"); + vkCmdWriteTimestamp = (PFN_vkCmdWriteTimestamp)load(context, "vkCmdWriteTimestamp"); + vkCreateBuffer = (PFN_vkCreateBuffer)load(context, "vkCreateBuffer"); + vkCreateBufferView = (PFN_vkCreateBufferView)load(context, "vkCreateBufferView"); + vkCreateCommandPool = (PFN_vkCreateCommandPool)load(context, "vkCreateCommandPool"); + vkCreateComputePipelines = (PFN_vkCreateComputePipelines)load(context, "vkCreateComputePipelines"); + vkCreateDescriptorPool = (PFN_vkCreateDescriptorPool)load(context, "vkCreateDescriptorPool"); + vkCreateDescriptorSetLayout = (PFN_vkCreateDescriptorSetLayout)load(context, "vkCreateDescriptorSetLayout"); + vkCreateEvent = (PFN_vkCreateEvent)load(context, "vkCreateEvent"); + vkCreateFence = (PFN_vkCreateFence)load(context, "vkCreateFence"); + vkCreateFramebuffer = (PFN_vkCreateFramebuffer)load(context, "vkCreateFramebuffer"); + vkCreateGraphicsPipelines = (PFN_vkCreateGraphicsPipelines)load(context, "vkCreateGraphicsPipelines"); + vkCreateImage = (PFN_vkCreateImage)load(context, "vkCreateImage"); + vkCreateImageView = (PFN_vkCreateImageView)load(context, "vkCreateImageView"); + vkCreatePipelineCache = (PFN_vkCreatePipelineCache)load(context, "vkCreatePipelineCache"); + vkCreatePipelineLayout = (PFN_vkCreatePipelineLayout)load(context, "vkCreatePipelineLayout"); + vkCreateQueryPool = (PFN_vkCreateQueryPool)load(context, "vkCreateQueryPool"); + vkCreateRenderPass = (PFN_vkCreateRenderPass)load(context, "vkCreateRenderPass"); + vkCreateSampler = (PFN_vkCreateSampler)load(context, "vkCreateSampler"); + vkCreateSemaphore = (PFN_vkCreateSemaphore)load(context, "vkCreateSemaphore"); + vkCreateShaderModule = (PFN_vkCreateShaderModule)load(context, "vkCreateShaderModule"); + vkDestroyBuffer = (PFN_vkDestroyBuffer)load(context, "vkDestroyBuffer"); + vkDestroyBufferView = (PFN_vkDestroyBufferView)load(context, "vkDestroyBufferView"); + vkDestroyCommandPool = (PFN_vkDestroyCommandPool)load(context, "vkDestroyCommandPool"); + vkDestroyDescriptorPool = (PFN_vkDestroyDescriptorPool)load(context, "vkDestroyDescriptorPool"); + vkDestroyDescriptorSetLayout = (PFN_vkDestroyDescriptorSetLayout)load(context, "vkDestroyDescriptorSetLayout"); + vkDestroyDevice = (PFN_vkDestroyDevice)load(context, "vkDestroyDevice"); + vkDestroyEvent = (PFN_vkDestroyEvent)load(context, "vkDestroyEvent"); + vkDestroyFence = (PFN_vkDestroyFence)load(context, "vkDestroyFence"); + vkDestroyFramebuffer = (PFN_vkDestroyFramebuffer)load(context, "vkDestroyFramebuffer"); + vkDestroyImage = (PFN_vkDestroyImage)load(context, "vkDestroyImage"); + vkDestroyImageView = (PFN_vkDestroyImageView)load(context, "vkDestroyImageView"); + vkDestroyPipeline = (PFN_vkDestroyPipeline)load(context, "vkDestroyPipeline"); + vkDestroyPipelineCache = (PFN_vkDestroyPipelineCache)load(context, "vkDestroyPipelineCache"); + vkDestroyPipelineLayout = (PFN_vkDestroyPipelineLayout)load(context, "vkDestroyPipelineLayout"); + vkDestroyQueryPool = (PFN_vkDestroyQueryPool)load(context, "vkDestroyQueryPool"); + vkDestroyRenderPass = (PFN_vkDestroyRenderPass)load(context, "vkDestroyRenderPass"); + vkDestroySampler = (PFN_vkDestroySampler)load(context, "vkDestroySampler"); + vkDestroySemaphore = (PFN_vkDestroySemaphore)load(context, "vkDestroySemaphore"); + vkDestroyShaderModule = (PFN_vkDestroyShaderModule)load(context, "vkDestroyShaderModule"); + vkDeviceWaitIdle = (PFN_vkDeviceWaitIdle)load(context, "vkDeviceWaitIdle"); + vkEndCommandBuffer = (PFN_vkEndCommandBuffer)load(context, "vkEndCommandBuffer"); + vkFlushMappedMemoryRanges = (PFN_vkFlushMappedMemoryRanges)load(context, "vkFlushMappedMemoryRanges"); + vkFreeCommandBuffers = (PFN_vkFreeCommandBuffers)load(context, "vkFreeCommandBuffers"); + vkFreeDescriptorSets = (PFN_vkFreeDescriptorSets)load(context, "vkFreeDescriptorSets"); + vkFreeMemory = (PFN_vkFreeMemory)load(context, "vkFreeMemory"); + vkGetBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements)load(context, "vkGetBufferMemoryRequirements"); + vkGetDeviceMemoryCommitment = (PFN_vkGetDeviceMemoryCommitment)load(context, "vkGetDeviceMemoryCommitment"); + vkGetDeviceQueue = (PFN_vkGetDeviceQueue)load(context, "vkGetDeviceQueue"); + vkGetEventStatus = (PFN_vkGetEventStatus)load(context, "vkGetEventStatus"); + vkGetFenceStatus = (PFN_vkGetFenceStatus)load(context, "vkGetFenceStatus"); + vkGetImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements)load(context, "vkGetImageMemoryRequirements"); + vkGetImageSparseMemoryRequirements = (PFN_vkGetImageSparseMemoryRequirements)load(context, "vkGetImageSparseMemoryRequirements"); + vkGetImageSubresourceLayout = (PFN_vkGetImageSubresourceLayout)load(context, "vkGetImageSubresourceLayout"); + vkGetPipelineCacheData = (PFN_vkGetPipelineCacheData)load(context, "vkGetPipelineCacheData"); + vkGetQueryPoolResults = (PFN_vkGetQueryPoolResults)load(context, "vkGetQueryPoolResults"); + vkGetRenderAreaGranularity = (PFN_vkGetRenderAreaGranularity)load(context, "vkGetRenderAreaGranularity"); + vkInvalidateMappedMemoryRanges = (PFN_vkInvalidateMappedMemoryRanges)load(context, "vkInvalidateMappedMemoryRanges"); + vkMapMemory = (PFN_vkMapMemory)load(context, "vkMapMemory"); + vkMergePipelineCaches = (PFN_vkMergePipelineCaches)load(context, "vkMergePipelineCaches"); + vkQueueBindSparse = (PFN_vkQueueBindSparse)load(context, "vkQueueBindSparse"); + vkQueueSubmit = (PFN_vkQueueSubmit)load(context, "vkQueueSubmit"); + vkQueueWaitIdle = (PFN_vkQueueWaitIdle)load(context, "vkQueueWaitIdle"); + vkResetCommandBuffer = (PFN_vkResetCommandBuffer)load(context, "vkResetCommandBuffer"); + vkResetCommandPool = (PFN_vkResetCommandPool)load(context, "vkResetCommandPool"); + vkResetDescriptorPool = (PFN_vkResetDescriptorPool)load(context, "vkResetDescriptorPool"); + vkResetEvent = (PFN_vkResetEvent)load(context, "vkResetEvent"); + vkResetFences = (PFN_vkResetFences)load(context, "vkResetFences"); + vkSetEvent = (PFN_vkSetEvent)load(context, "vkSetEvent"); + vkUnmapMemory = (PFN_vkUnmapMemory)load(context, "vkUnmapMemory"); + vkUpdateDescriptorSets = (PFN_vkUpdateDescriptorSets)load(context, "vkUpdateDescriptorSets"); + vkWaitForFences = (PFN_vkWaitForFences)load(context, "vkWaitForFences"); +#endif /* defined(VK_VERSION_1_0) */ +#if defined(VK_VERSION_1_1) + vkBindBufferMemory2 = (PFN_vkBindBufferMemory2)load(context, "vkBindBufferMemory2"); + vkBindImageMemory2 = (PFN_vkBindImageMemory2)load(context, "vkBindImageMemory2"); + vkCmdDispatchBase = (PFN_vkCmdDispatchBase)load(context, "vkCmdDispatchBase"); + vkCmdSetDeviceMask = (PFN_vkCmdSetDeviceMask)load(context, "vkCmdSetDeviceMask"); + vkCreateDescriptorUpdateTemplate = (PFN_vkCreateDescriptorUpdateTemplate)load(context, "vkCreateDescriptorUpdateTemplate"); + vkCreateSamplerYcbcrConversion = (PFN_vkCreateSamplerYcbcrConversion)load(context, "vkCreateSamplerYcbcrConversion"); + vkDestroyDescriptorUpdateTemplate = (PFN_vkDestroyDescriptorUpdateTemplate)load(context, "vkDestroyDescriptorUpdateTemplate"); + vkDestroySamplerYcbcrConversion = (PFN_vkDestroySamplerYcbcrConversion)load(context, "vkDestroySamplerYcbcrConversion"); + vkGetBufferMemoryRequirements2 = (PFN_vkGetBufferMemoryRequirements2)load(context, "vkGetBufferMemoryRequirements2"); + vkGetDescriptorSetLayoutSupport = (PFN_vkGetDescriptorSetLayoutSupport)load(context, "vkGetDescriptorSetLayoutSupport"); + vkGetDeviceGroupPeerMemoryFeatures = (PFN_vkGetDeviceGroupPeerMemoryFeatures)load(context, "vkGetDeviceGroupPeerMemoryFeatures"); + vkGetDeviceQueue2 = (PFN_vkGetDeviceQueue2)load(context, "vkGetDeviceQueue2"); + vkGetImageMemoryRequirements2 = (PFN_vkGetImageMemoryRequirements2)load(context, "vkGetImageMemoryRequirements2"); + vkGetImageSparseMemoryRequirements2 = (PFN_vkGetImageSparseMemoryRequirements2)load(context, "vkGetImageSparseMemoryRequirements2"); + vkTrimCommandPool = (PFN_vkTrimCommandPool)load(context, "vkTrimCommandPool"); + vkUpdateDescriptorSetWithTemplate = (PFN_vkUpdateDescriptorSetWithTemplate)load(context, "vkUpdateDescriptorSetWithTemplate"); +#endif /* defined(VK_VERSION_1_1) */ +#if defined(VK_VERSION_1_2) + vkCmdBeginRenderPass2 = (PFN_vkCmdBeginRenderPass2)load(context, "vkCmdBeginRenderPass2"); + vkCmdDrawIndexedIndirectCount = (PFN_vkCmdDrawIndexedIndirectCount)load(context, "vkCmdDrawIndexedIndirectCount"); + vkCmdDrawIndirectCount = (PFN_vkCmdDrawIndirectCount)load(context, "vkCmdDrawIndirectCount"); + vkCmdEndRenderPass2 = (PFN_vkCmdEndRenderPass2)load(context, "vkCmdEndRenderPass2"); + vkCmdNextSubpass2 = (PFN_vkCmdNextSubpass2)load(context, "vkCmdNextSubpass2"); + vkCreateRenderPass2 = (PFN_vkCreateRenderPass2)load(context, "vkCreateRenderPass2"); + vkGetBufferDeviceAddress = (PFN_vkGetBufferDeviceAddress)load(context, "vkGetBufferDeviceAddress"); + vkGetBufferOpaqueCaptureAddress = (PFN_vkGetBufferOpaqueCaptureAddress)load(context, "vkGetBufferOpaqueCaptureAddress"); + vkGetDeviceMemoryOpaqueCaptureAddress = (PFN_vkGetDeviceMemoryOpaqueCaptureAddress)load(context, "vkGetDeviceMemoryOpaqueCaptureAddress"); + vkGetSemaphoreCounterValue = (PFN_vkGetSemaphoreCounterValue)load(context, "vkGetSemaphoreCounterValue"); + vkResetQueryPool = (PFN_vkResetQueryPool)load(context, "vkResetQueryPool"); + vkSignalSemaphore = (PFN_vkSignalSemaphore)load(context, "vkSignalSemaphore"); + vkWaitSemaphores = (PFN_vkWaitSemaphores)load(context, "vkWaitSemaphores"); +#endif /* defined(VK_VERSION_1_2) */ +#if defined(VK_AMD_buffer_marker) + vkCmdWriteBufferMarkerAMD = (PFN_vkCmdWriteBufferMarkerAMD)load(context, "vkCmdWriteBufferMarkerAMD"); +#endif /* defined(VK_AMD_buffer_marker) */ +#if defined(VK_AMD_display_native_hdr) + vkSetLocalDimmingAMD = (PFN_vkSetLocalDimmingAMD)load(context, "vkSetLocalDimmingAMD"); +#endif /* defined(VK_AMD_display_native_hdr) */ +#if defined(VK_AMD_draw_indirect_count) + vkCmdDrawIndexedIndirectCountAMD = (PFN_vkCmdDrawIndexedIndirectCountAMD)load(context, "vkCmdDrawIndexedIndirectCountAMD"); + vkCmdDrawIndirectCountAMD = (PFN_vkCmdDrawIndirectCountAMD)load(context, "vkCmdDrawIndirectCountAMD"); +#endif /* defined(VK_AMD_draw_indirect_count) */ +#if defined(VK_AMD_shader_info) + vkGetShaderInfoAMD = (PFN_vkGetShaderInfoAMD)load(context, "vkGetShaderInfoAMD"); +#endif /* defined(VK_AMD_shader_info) */ +#if defined(VK_ANDROID_external_memory_android_hardware_buffer) + vkGetAndroidHardwareBufferPropertiesANDROID = (PFN_vkGetAndroidHardwareBufferPropertiesANDROID)load(context, "vkGetAndroidHardwareBufferPropertiesANDROID"); + vkGetMemoryAndroidHardwareBufferANDROID = (PFN_vkGetMemoryAndroidHardwareBufferANDROID)load(context, "vkGetMemoryAndroidHardwareBufferANDROID"); +#endif /* defined(VK_ANDROID_external_memory_android_hardware_buffer) */ +#if defined(VK_EXT_buffer_device_address) + vkGetBufferDeviceAddressEXT = (PFN_vkGetBufferDeviceAddressEXT)load(context, "vkGetBufferDeviceAddressEXT"); +#endif /* defined(VK_EXT_buffer_device_address) */ +#if defined(VK_EXT_calibrated_timestamps) + vkGetCalibratedTimestampsEXT = (PFN_vkGetCalibratedTimestampsEXT)load(context, "vkGetCalibratedTimestampsEXT"); +#endif /* defined(VK_EXT_calibrated_timestamps) */ +#if defined(VK_EXT_conditional_rendering) + vkCmdBeginConditionalRenderingEXT = (PFN_vkCmdBeginConditionalRenderingEXT)load(context, "vkCmdBeginConditionalRenderingEXT"); + vkCmdEndConditionalRenderingEXT = (PFN_vkCmdEndConditionalRenderingEXT)load(context, "vkCmdEndConditionalRenderingEXT"); +#endif /* defined(VK_EXT_conditional_rendering) */ +#if defined(VK_EXT_debug_marker) + vkCmdDebugMarkerBeginEXT = (PFN_vkCmdDebugMarkerBeginEXT)load(context, "vkCmdDebugMarkerBeginEXT"); + vkCmdDebugMarkerEndEXT = (PFN_vkCmdDebugMarkerEndEXT)load(context, "vkCmdDebugMarkerEndEXT"); + vkCmdDebugMarkerInsertEXT = (PFN_vkCmdDebugMarkerInsertEXT)load(context, "vkCmdDebugMarkerInsertEXT"); + vkDebugMarkerSetObjectNameEXT = (PFN_vkDebugMarkerSetObjectNameEXT)load(context, "vkDebugMarkerSetObjectNameEXT"); + vkDebugMarkerSetObjectTagEXT = (PFN_vkDebugMarkerSetObjectTagEXT)load(context, "vkDebugMarkerSetObjectTagEXT"); +#endif /* defined(VK_EXT_debug_marker) */ +#if defined(VK_EXT_discard_rectangles) + vkCmdSetDiscardRectangleEXT = (PFN_vkCmdSetDiscardRectangleEXT)load(context, "vkCmdSetDiscardRectangleEXT"); +#endif /* defined(VK_EXT_discard_rectangles) */ +#if defined(VK_EXT_display_control) + vkDisplayPowerControlEXT = (PFN_vkDisplayPowerControlEXT)load(context, "vkDisplayPowerControlEXT"); + vkGetSwapchainCounterEXT = (PFN_vkGetSwapchainCounterEXT)load(context, "vkGetSwapchainCounterEXT"); + vkRegisterDeviceEventEXT = (PFN_vkRegisterDeviceEventEXT)load(context, "vkRegisterDeviceEventEXT"); + vkRegisterDisplayEventEXT = (PFN_vkRegisterDisplayEventEXT)load(context, "vkRegisterDisplayEventEXT"); +#endif /* defined(VK_EXT_display_control) */ +#if defined(VK_EXT_extended_dynamic_state) + vkCmdBindVertexBuffers2EXT = (PFN_vkCmdBindVertexBuffers2EXT)load(context, "vkCmdBindVertexBuffers2EXT"); + vkCmdSetCullModeEXT = (PFN_vkCmdSetCullModeEXT)load(context, "vkCmdSetCullModeEXT"); + vkCmdSetDepthBoundsTestEnableEXT = (PFN_vkCmdSetDepthBoundsTestEnableEXT)load(context, "vkCmdSetDepthBoundsTestEnableEXT"); + vkCmdSetDepthCompareOpEXT = (PFN_vkCmdSetDepthCompareOpEXT)load(context, "vkCmdSetDepthCompareOpEXT"); + vkCmdSetDepthTestEnableEXT = (PFN_vkCmdSetDepthTestEnableEXT)load(context, "vkCmdSetDepthTestEnableEXT"); + vkCmdSetDepthWriteEnableEXT = (PFN_vkCmdSetDepthWriteEnableEXT)load(context, "vkCmdSetDepthWriteEnableEXT"); + vkCmdSetFrontFaceEXT = (PFN_vkCmdSetFrontFaceEXT)load(context, "vkCmdSetFrontFaceEXT"); + vkCmdSetPrimitiveTopologyEXT = (PFN_vkCmdSetPrimitiveTopologyEXT)load(context, "vkCmdSetPrimitiveTopologyEXT"); + vkCmdSetScissorWithCountEXT = (PFN_vkCmdSetScissorWithCountEXT)load(context, "vkCmdSetScissorWithCountEXT"); + vkCmdSetStencilOpEXT = (PFN_vkCmdSetStencilOpEXT)load(context, "vkCmdSetStencilOpEXT"); + vkCmdSetStencilTestEnableEXT = (PFN_vkCmdSetStencilTestEnableEXT)load(context, "vkCmdSetStencilTestEnableEXT"); + vkCmdSetViewportWithCountEXT = (PFN_vkCmdSetViewportWithCountEXT)load(context, "vkCmdSetViewportWithCountEXT"); +#endif /* defined(VK_EXT_extended_dynamic_state) */ +#if defined(VK_EXT_external_memory_host) + vkGetMemoryHostPointerPropertiesEXT = (PFN_vkGetMemoryHostPointerPropertiesEXT)load(context, "vkGetMemoryHostPointerPropertiesEXT"); +#endif /* defined(VK_EXT_external_memory_host) */ +#if defined(VK_EXT_full_screen_exclusive) + vkAcquireFullScreenExclusiveModeEXT = (PFN_vkAcquireFullScreenExclusiveModeEXT)load(context, "vkAcquireFullScreenExclusiveModeEXT"); + vkReleaseFullScreenExclusiveModeEXT = (PFN_vkReleaseFullScreenExclusiveModeEXT)load(context, "vkReleaseFullScreenExclusiveModeEXT"); +#endif /* defined(VK_EXT_full_screen_exclusive) */ +#if defined(VK_EXT_hdr_metadata) + vkSetHdrMetadataEXT = (PFN_vkSetHdrMetadataEXT)load(context, "vkSetHdrMetadataEXT"); +#endif /* defined(VK_EXT_hdr_metadata) */ +#if defined(VK_EXT_host_query_reset) + vkResetQueryPoolEXT = (PFN_vkResetQueryPoolEXT)load(context, "vkResetQueryPoolEXT"); +#endif /* defined(VK_EXT_host_query_reset) */ +#if defined(VK_EXT_image_drm_format_modifier) + vkGetImageDrmFormatModifierPropertiesEXT = (PFN_vkGetImageDrmFormatModifierPropertiesEXT)load(context, "vkGetImageDrmFormatModifierPropertiesEXT"); +#endif /* defined(VK_EXT_image_drm_format_modifier) */ +#if defined(VK_EXT_line_rasterization) + vkCmdSetLineStippleEXT = (PFN_vkCmdSetLineStippleEXT)load(context, "vkCmdSetLineStippleEXT"); +#endif /* defined(VK_EXT_line_rasterization) */ +#if defined(VK_EXT_private_data) + vkCreatePrivateDataSlotEXT = (PFN_vkCreatePrivateDataSlotEXT)load(context, "vkCreatePrivateDataSlotEXT"); + vkDestroyPrivateDataSlotEXT = (PFN_vkDestroyPrivateDataSlotEXT)load(context, "vkDestroyPrivateDataSlotEXT"); + vkGetPrivateDataEXT = (PFN_vkGetPrivateDataEXT)load(context, "vkGetPrivateDataEXT"); + vkSetPrivateDataEXT = (PFN_vkSetPrivateDataEXT)load(context, "vkSetPrivateDataEXT"); +#endif /* defined(VK_EXT_private_data) */ +#if defined(VK_EXT_sample_locations) + vkCmdSetSampleLocationsEXT = (PFN_vkCmdSetSampleLocationsEXT)load(context, "vkCmdSetSampleLocationsEXT"); +#endif /* defined(VK_EXT_sample_locations) */ +#if defined(VK_EXT_transform_feedback) + vkCmdBeginQueryIndexedEXT = (PFN_vkCmdBeginQueryIndexedEXT)load(context, "vkCmdBeginQueryIndexedEXT"); + vkCmdBeginTransformFeedbackEXT = (PFN_vkCmdBeginTransformFeedbackEXT)load(context, "vkCmdBeginTransformFeedbackEXT"); + vkCmdBindTransformFeedbackBuffersEXT = (PFN_vkCmdBindTransformFeedbackBuffersEXT)load(context, "vkCmdBindTransformFeedbackBuffersEXT"); + vkCmdDrawIndirectByteCountEXT = (PFN_vkCmdDrawIndirectByteCountEXT)load(context, "vkCmdDrawIndirectByteCountEXT"); + vkCmdEndQueryIndexedEXT = (PFN_vkCmdEndQueryIndexedEXT)load(context, "vkCmdEndQueryIndexedEXT"); + vkCmdEndTransformFeedbackEXT = (PFN_vkCmdEndTransformFeedbackEXT)load(context, "vkCmdEndTransformFeedbackEXT"); +#endif /* defined(VK_EXT_transform_feedback) */ +#if defined(VK_EXT_validation_cache) + vkCreateValidationCacheEXT = (PFN_vkCreateValidationCacheEXT)load(context, "vkCreateValidationCacheEXT"); + vkDestroyValidationCacheEXT = (PFN_vkDestroyValidationCacheEXT)load(context, "vkDestroyValidationCacheEXT"); + vkGetValidationCacheDataEXT = (PFN_vkGetValidationCacheDataEXT)load(context, "vkGetValidationCacheDataEXT"); + vkMergeValidationCachesEXT = (PFN_vkMergeValidationCachesEXT)load(context, "vkMergeValidationCachesEXT"); +#endif /* defined(VK_EXT_validation_cache) */ +#if defined(VK_GOOGLE_display_timing) + vkGetPastPresentationTimingGOOGLE = (PFN_vkGetPastPresentationTimingGOOGLE)load(context, "vkGetPastPresentationTimingGOOGLE"); + vkGetRefreshCycleDurationGOOGLE = (PFN_vkGetRefreshCycleDurationGOOGLE)load(context, "vkGetRefreshCycleDurationGOOGLE"); +#endif /* defined(VK_GOOGLE_display_timing) */ +#if defined(VK_INTEL_performance_query) + vkAcquirePerformanceConfigurationINTEL = (PFN_vkAcquirePerformanceConfigurationINTEL)load(context, "vkAcquirePerformanceConfigurationINTEL"); + vkCmdSetPerformanceMarkerINTEL = (PFN_vkCmdSetPerformanceMarkerINTEL)load(context, "vkCmdSetPerformanceMarkerINTEL"); + vkCmdSetPerformanceOverrideINTEL = (PFN_vkCmdSetPerformanceOverrideINTEL)load(context, "vkCmdSetPerformanceOverrideINTEL"); + vkCmdSetPerformanceStreamMarkerINTEL = (PFN_vkCmdSetPerformanceStreamMarkerINTEL)load(context, "vkCmdSetPerformanceStreamMarkerINTEL"); + vkGetPerformanceParameterINTEL = (PFN_vkGetPerformanceParameterINTEL)load(context, "vkGetPerformanceParameterINTEL"); + vkInitializePerformanceApiINTEL = (PFN_vkInitializePerformanceApiINTEL)load(context, "vkInitializePerformanceApiINTEL"); + vkQueueSetPerformanceConfigurationINTEL = (PFN_vkQueueSetPerformanceConfigurationINTEL)load(context, "vkQueueSetPerformanceConfigurationINTEL"); + vkReleasePerformanceConfigurationINTEL = (PFN_vkReleasePerformanceConfigurationINTEL)load(context, "vkReleasePerformanceConfigurationINTEL"); + vkUninitializePerformanceApiINTEL = (PFN_vkUninitializePerformanceApiINTEL)load(context, "vkUninitializePerformanceApiINTEL"); +#endif /* defined(VK_INTEL_performance_query) */ +#if defined(VK_KHR_bind_memory2) + vkBindBufferMemory2KHR = (PFN_vkBindBufferMemory2KHR)load(context, "vkBindBufferMemory2KHR"); + vkBindImageMemory2KHR = (PFN_vkBindImageMemory2KHR)load(context, "vkBindImageMemory2KHR"); +#endif /* defined(VK_KHR_bind_memory2) */ +#if defined(VK_KHR_buffer_device_address) + vkGetBufferDeviceAddressKHR = (PFN_vkGetBufferDeviceAddressKHR)load(context, "vkGetBufferDeviceAddressKHR"); + vkGetBufferOpaqueCaptureAddressKHR = (PFN_vkGetBufferOpaqueCaptureAddressKHR)load(context, "vkGetBufferOpaqueCaptureAddressKHR"); + vkGetDeviceMemoryOpaqueCaptureAddressKHR = (PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR)load(context, "vkGetDeviceMemoryOpaqueCaptureAddressKHR"); +#endif /* defined(VK_KHR_buffer_device_address) */ +#if defined(VK_KHR_create_renderpass2) + vkCmdBeginRenderPass2KHR = (PFN_vkCmdBeginRenderPass2KHR)load(context, "vkCmdBeginRenderPass2KHR"); + vkCmdEndRenderPass2KHR = (PFN_vkCmdEndRenderPass2KHR)load(context, "vkCmdEndRenderPass2KHR"); + vkCmdNextSubpass2KHR = (PFN_vkCmdNextSubpass2KHR)load(context, "vkCmdNextSubpass2KHR"); + vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)load(context, "vkCreateRenderPass2KHR"); +#endif /* defined(VK_KHR_create_renderpass2) */ +#if defined(VK_KHR_deferred_host_operations) + vkCreateDeferredOperationKHR = (PFN_vkCreateDeferredOperationKHR)load(context, "vkCreateDeferredOperationKHR"); + vkDeferredOperationJoinKHR = (PFN_vkDeferredOperationJoinKHR)load(context, "vkDeferredOperationJoinKHR"); + vkDestroyDeferredOperationKHR = (PFN_vkDestroyDeferredOperationKHR)load(context, "vkDestroyDeferredOperationKHR"); + vkGetDeferredOperationMaxConcurrencyKHR = (PFN_vkGetDeferredOperationMaxConcurrencyKHR)load(context, "vkGetDeferredOperationMaxConcurrencyKHR"); + vkGetDeferredOperationResultKHR = (PFN_vkGetDeferredOperationResultKHR)load(context, "vkGetDeferredOperationResultKHR"); +#endif /* defined(VK_KHR_deferred_host_operations) */ +#if defined(VK_KHR_descriptor_update_template) + vkCreateDescriptorUpdateTemplateKHR = (PFN_vkCreateDescriptorUpdateTemplateKHR)load(context, "vkCreateDescriptorUpdateTemplateKHR"); + vkDestroyDescriptorUpdateTemplateKHR = (PFN_vkDestroyDescriptorUpdateTemplateKHR)load(context, "vkDestroyDescriptorUpdateTemplateKHR"); + vkUpdateDescriptorSetWithTemplateKHR = (PFN_vkUpdateDescriptorSetWithTemplateKHR)load(context, "vkUpdateDescriptorSetWithTemplateKHR"); +#endif /* defined(VK_KHR_descriptor_update_template) */ +#if defined(VK_KHR_device_group) + vkCmdDispatchBaseKHR = (PFN_vkCmdDispatchBaseKHR)load(context, "vkCmdDispatchBaseKHR"); + vkCmdSetDeviceMaskKHR = (PFN_vkCmdSetDeviceMaskKHR)load(context, "vkCmdSetDeviceMaskKHR"); + vkGetDeviceGroupPeerMemoryFeaturesKHR = (PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR)load(context, "vkGetDeviceGroupPeerMemoryFeaturesKHR"); +#endif /* defined(VK_KHR_device_group) */ +#if defined(VK_KHR_display_swapchain) + vkCreateSharedSwapchainsKHR = (PFN_vkCreateSharedSwapchainsKHR)load(context, "vkCreateSharedSwapchainsKHR"); +#endif /* defined(VK_KHR_display_swapchain) */ +#if defined(VK_KHR_draw_indirect_count) + vkCmdDrawIndexedIndirectCountKHR = (PFN_vkCmdDrawIndexedIndirectCountKHR)load(context, "vkCmdDrawIndexedIndirectCountKHR"); + vkCmdDrawIndirectCountKHR = (PFN_vkCmdDrawIndirectCountKHR)load(context, "vkCmdDrawIndirectCountKHR"); +#endif /* defined(VK_KHR_draw_indirect_count) */ +#if defined(VK_KHR_external_fence_fd) + vkGetFenceFdKHR = (PFN_vkGetFenceFdKHR)load(context, "vkGetFenceFdKHR"); + vkImportFenceFdKHR = (PFN_vkImportFenceFdKHR)load(context, "vkImportFenceFdKHR"); +#endif /* defined(VK_KHR_external_fence_fd) */ +#if defined(VK_KHR_external_fence_win32) + vkGetFenceWin32HandleKHR = (PFN_vkGetFenceWin32HandleKHR)load(context, "vkGetFenceWin32HandleKHR"); + vkImportFenceWin32HandleKHR = (PFN_vkImportFenceWin32HandleKHR)load(context, "vkImportFenceWin32HandleKHR"); +#endif /* defined(VK_KHR_external_fence_win32) */ +#if defined(VK_KHR_external_memory_fd) + vkGetMemoryFdKHR = (PFN_vkGetMemoryFdKHR)load(context, "vkGetMemoryFdKHR"); + vkGetMemoryFdPropertiesKHR = (PFN_vkGetMemoryFdPropertiesKHR)load(context, "vkGetMemoryFdPropertiesKHR"); +#endif /* defined(VK_KHR_external_memory_fd) */ +#if defined(VK_KHR_external_memory_win32) + vkGetMemoryWin32HandleKHR = (PFN_vkGetMemoryWin32HandleKHR)load(context, "vkGetMemoryWin32HandleKHR"); + vkGetMemoryWin32HandlePropertiesKHR = (PFN_vkGetMemoryWin32HandlePropertiesKHR)load(context, "vkGetMemoryWin32HandlePropertiesKHR"); +#endif /* defined(VK_KHR_external_memory_win32) */ +#if defined(VK_KHR_external_semaphore_fd) + vkGetSemaphoreFdKHR = (PFN_vkGetSemaphoreFdKHR)load(context, "vkGetSemaphoreFdKHR"); + vkImportSemaphoreFdKHR = (PFN_vkImportSemaphoreFdKHR)load(context, "vkImportSemaphoreFdKHR"); +#endif /* defined(VK_KHR_external_semaphore_fd) */ +#if defined(VK_KHR_external_semaphore_win32) + vkGetSemaphoreWin32HandleKHR = (PFN_vkGetSemaphoreWin32HandleKHR)load(context, "vkGetSemaphoreWin32HandleKHR"); + vkImportSemaphoreWin32HandleKHR = (PFN_vkImportSemaphoreWin32HandleKHR)load(context, "vkImportSemaphoreWin32HandleKHR"); +#endif /* defined(VK_KHR_external_semaphore_win32) */ +#if defined(VK_KHR_get_memory_requirements2) + vkGetBufferMemoryRequirements2KHR = (PFN_vkGetBufferMemoryRequirements2KHR)load(context, "vkGetBufferMemoryRequirements2KHR"); + vkGetImageMemoryRequirements2KHR = (PFN_vkGetImageMemoryRequirements2KHR)load(context, "vkGetImageMemoryRequirements2KHR"); + vkGetImageSparseMemoryRequirements2KHR = (PFN_vkGetImageSparseMemoryRequirements2KHR)load(context, "vkGetImageSparseMemoryRequirements2KHR"); +#endif /* defined(VK_KHR_get_memory_requirements2) */ +#if defined(VK_KHR_maintenance1) + vkTrimCommandPoolKHR = (PFN_vkTrimCommandPoolKHR)load(context, "vkTrimCommandPoolKHR"); +#endif /* defined(VK_KHR_maintenance1) */ +#if defined(VK_KHR_maintenance3) + vkGetDescriptorSetLayoutSupportKHR = (PFN_vkGetDescriptorSetLayoutSupportKHR)load(context, "vkGetDescriptorSetLayoutSupportKHR"); +#endif /* defined(VK_KHR_maintenance3) */ +#if defined(VK_KHR_performance_query) + vkAcquireProfilingLockKHR = (PFN_vkAcquireProfilingLockKHR)load(context, "vkAcquireProfilingLockKHR"); + vkReleaseProfilingLockKHR = (PFN_vkReleaseProfilingLockKHR)load(context, "vkReleaseProfilingLockKHR"); +#endif /* defined(VK_KHR_performance_query) */ +#if defined(VK_KHR_pipeline_executable_properties) + vkGetPipelineExecutableInternalRepresentationsKHR = (PFN_vkGetPipelineExecutableInternalRepresentationsKHR)load(context, "vkGetPipelineExecutableInternalRepresentationsKHR"); + vkGetPipelineExecutablePropertiesKHR = (PFN_vkGetPipelineExecutablePropertiesKHR)load(context, "vkGetPipelineExecutablePropertiesKHR"); + vkGetPipelineExecutableStatisticsKHR = (PFN_vkGetPipelineExecutableStatisticsKHR)load(context, "vkGetPipelineExecutableStatisticsKHR"); +#endif /* defined(VK_KHR_pipeline_executable_properties) */ +#if defined(VK_KHR_push_descriptor) + vkCmdPushDescriptorSetKHR = (PFN_vkCmdPushDescriptorSetKHR)load(context, "vkCmdPushDescriptorSetKHR"); +#endif /* defined(VK_KHR_push_descriptor) */ +#if defined(VK_KHR_ray_tracing) + vkBindAccelerationStructureMemoryKHR = (PFN_vkBindAccelerationStructureMemoryKHR)load(context, "vkBindAccelerationStructureMemoryKHR"); + vkBuildAccelerationStructureKHR = (PFN_vkBuildAccelerationStructureKHR)load(context, "vkBuildAccelerationStructureKHR"); + vkCmdBuildAccelerationStructureIndirectKHR = (PFN_vkCmdBuildAccelerationStructureIndirectKHR)load(context, "vkCmdBuildAccelerationStructureIndirectKHR"); + vkCmdBuildAccelerationStructureKHR = (PFN_vkCmdBuildAccelerationStructureKHR)load(context, "vkCmdBuildAccelerationStructureKHR"); + vkCmdCopyAccelerationStructureKHR = (PFN_vkCmdCopyAccelerationStructureKHR)load(context, "vkCmdCopyAccelerationStructureKHR"); + vkCmdCopyAccelerationStructureToMemoryKHR = (PFN_vkCmdCopyAccelerationStructureToMemoryKHR)load(context, "vkCmdCopyAccelerationStructureToMemoryKHR"); + vkCmdCopyMemoryToAccelerationStructureKHR = (PFN_vkCmdCopyMemoryToAccelerationStructureKHR)load(context, "vkCmdCopyMemoryToAccelerationStructureKHR"); + vkCmdTraceRaysIndirectKHR = (PFN_vkCmdTraceRaysIndirectKHR)load(context, "vkCmdTraceRaysIndirectKHR"); + vkCmdTraceRaysKHR = (PFN_vkCmdTraceRaysKHR)load(context, "vkCmdTraceRaysKHR"); + vkCmdWriteAccelerationStructuresPropertiesKHR = (PFN_vkCmdWriteAccelerationStructuresPropertiesKHR)load(context, "vkCmdWriteAccelerationStructuresPropertiesKHR"); + vkCopyAccelerationStructureKHR = (PFN_vkCopyAccelerationStructureKHR)load(context, "vkCopyAccelerationStructureKHR"); + vkCopyAccelerationStructureToMemoryKHR = (PFN_vkCopyAccelerationStructureToMemoryKHR)load(context, "vkCopyAccelerationStructureToMemoryKHR"); + vkCopyMemoryToAccelerationStructureKHR = (PFN_vkCopyMemoryToAccelerationStructureKHR)load(context, "vkCopyMemoryToAccelerationStructureKHR"); + vkCreateAccelerationStructureKHR = (PFN_vkCreateAccelerationStructureKHR)load(context, "vkCreateAccelerationStructureKHR"); + vkCreateRayTracingPipelinesKHR = (PFN_vkCreateRayTracingPipelinesKHR)load(context, "vkCreateRayTracingPipelinesKHR"); + vkDestroyAccelerationStructureKHR = (PFN_vkDestroyAccelerationStructureKHR)load(context, "vkDestroyAccelerationStructureKHR"); + vkGetAccelerationStructureDeviceAddressKHR = (PFN_vkGetAccelerationStructureDeviceAddressKHR)load(context, "vkGetAccelerationStructureDeviceAddressKHR"); + vkGetAccelerationStructureMemoryRequirementsKHR = (PFN_vkGetAccelerationStructureMemoryRequirementsKHR)load(context, "vkGetAccelerationStructureMemoryRequirementsKHR"); + vkGetDeviceAccelerationStructureCompatibilityKHR = (PFN_vkGetDeviceAccelerationStructureCompatibilityKHR)load(context, "vkGetDeviceAccelerationStructureCompatibilityKHR"); + vkGetRayTracingCaptureReplayShaderGroupHandlesKHR = (PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR)load(context, "vkGetRayTracingCaptureReplayShaderGroupHandlesKHR"); + vkGetRayTracingShaderGroupHandlesKHR = (PFN_vkGetRayTracingShaderGroupHandlesKHR)load(context, "vkGetRayTracingShaderGroupHandlesKHR"); + vkWriteAccelerationStructuresPropertiesKHR = (PFN_vkWriteAccelerationStructuresPropertiesKHR)load(context, "vkWriteAccelerationStructuresPropertiesKHR"); +#endif /* defined(VK_KHR_ray_tracing) */ +#if defined(VK_KHR_sampler_ycbcr_conversion) + vkCreateSamplerYcbcrConversionKHR = (PFN_vkCreateSamplerYcbcrConversionKHR)load(context, "vkCreateSamplerYcbcrConversionKHR"); + vkDestroySamplerYcbcrConversionKHR = (PFN_vkDestroySamplerYcbcrConversionKHR)load(context, "vkDestroySamplerYcbcrConversionKHR"); +#endif /* defined(VK_KHR_sampler_ycbcr_conversion) */ +#if defined(VK_KHR_shared_presentable_image) + vkGetSwapchainStatusKHR = (PFN_vkGetSwapchainStatusKHR)load(context, "vkGetSwapchainStatusKHR"); +#endif /* defined(VK_KHR_shared_presentable_image) */ +#if defined(VK_KHR_swapchain) + vkAcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)load(context, "vkAcquireNextImageKHR"); + vkCreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)load(context, "vkCreateSwapchainKHR"); + vkDestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)load(context, "vkDestroySwapchainKHR"); + vkGetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)load(context, "vkGetSwapchainImagesKHR"); + vkQueuePresentKHR = (PFN_vkQueuePresentKHR)load(context, "vkQueuePresentKHR"); +#endif /* defined(VK_KHR_swapchain) */ +#if defined(VK_KHR_timeline_semaphore) + vkGetSemaphoreCounterValueKHR = (PFN_vkGetSemaphoreCounterValueKHR)load(context, "vkGetSemaphoreCounterValueKHR"); + vkSignalSemaphoreKHR = (PFN_vkSignalSemaphoreKHR)load(context, "vkSignalSemaphoreKHR"); + vkWaitSemaphoresKHR = (PFN_vkWaitSemaphoresKHR)load(context, "vkWaitSemaphoresKHR"); +#endif /* defined(VK_KHR_timeline_semaphore) */ +#if defined(VK_NVX_image_view_handle) + vkGetImageViewAddressNVX = (PFN_vkGetImageViewAddressNVX)load(context, "vkGetImageViewAddressNVX"); + vkGetImageViewHandleNVX = (PFN_vkGetImageViewHandleNVX)load(context, "vkGetImageViewHandleNVX"); +#endif /* defined(VK_NVX_image_view_handle) */ +#if defined(VK_NV_clip_space_w_scaling) + vkCmdSetViewportWScalingNV = (PFN_vkCmdSetViewportWScalingNV)load(context, "vkCmdSetViewportWScalingNV"); +#endif /* defined(VK_NV_clip_space_w_scaling) */ +#if defined(VK_NV_device_diagnostic_checkpoints) + vkCmdSetCheckpointNV = (PFN_vkCmdSetCheckpointNV)load(context, "vkCmdSetCheckpointNV"); + vkGetQueueCheckpointDataNV = (PFN_vkGetQueueCheckpointDataNV)load(context, "vkGetQueueCheckpointDataNV"); +#endif /* defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_NV_device_generated_commands) + vkCmdBindPipelineShaderGroupNV = (PFN_vkCmdBindPipelineShaderGroupNV)load(context, "vkCmdBindPipelineShaderGroupNV"); + vkCmdExecuteGeneratedCommandsNV = (PFN_vkCmdExecuteGeneratedCommandsNV)load(context, "vkCmdExecuteGeneratedCommandsNV"); + vkCmdPreprocessGeneratedCommandsNV = (PFN_vkCmdPreprocessGeneratedCommandsNV)load(context, "vkCmdPreprocessGeneratedCommandsNV"); + vkCreateIndirectCommandsLayoutNV = (PFN_vkCreateIndirectCommandsLayoutNV)load(context, "vkCreateIndirectCommandsLayoutNV"); + vkDestroyIndirectCommandsLayoutNV = (PFN_vkDestroyIndirectCommandsLayoutNV)load(context, "vkDestroyIndirectCommandsLayoutNV"); + vkGetGeneratedCommandsMemoryRequirementsNV = (PFN_vkGetGeneratedCommandsMemoryRequirementsNV)load(context, "vkGetGeneratedCommandsMemoryRequirementsNV"); +#endif /* defined(VK_NV_device_generated_commands) */ +#if defined(VK_NV_external_memory_win32) + vkGetMemoryWin32HandleNV = (PFN_vkGetMemoryWin32HandleNV)load(context, "vkGetMemoryWin32HandleNV"); +#endif /* defined(VK_NV_external_memory_win32) */ +#if defined(VK_NV_mesh_shader) + vkCmdDrawMeshTasksIndirectCountNV = (PFN_vkCmdDrawMeshTasksIndirectCountNV)load(context, "vkCmdDrawMeshTasksIndirectCountNV"); + vkCmdDrawMeshTasksIndirectNV = (PFN_vkCmdDrawMeshTasksIndirectNV)load(context, "vkCmdDrawMeshTasksIndirectNV"); + vkCmdDrawMeshTasksNV = (PFN_vkCmdDrawMeshTasksNV)load(context, "vkCmdDrawMeshTasksNV"); +#endif /* defined(VK_NV_mesh_shader) */ +#if defined(VK_NV_ray_tracing) + vkBindAccelerationStructureMemoryNV = (PFN_vkBindAccelerationStructureMemoryNV)load(context, "vkBindAccelerationStructureMemoryNV"); + vkCmdBuildAccelerationStructureNV = (PFN_vkCmdBuildAccelerationStructureNV)load(context, "vkCmdBuildAccelerationStructureNV"); + vkCmdCopyAccelerationStructureNV = (PFN_vkCmdCopyAccelerationStructureNV)load(context, "vkCmdCopyAccelerationStructureNV"); + vkCmdTraceRaysNV = (PFN_vkCmdTraceRaysNV)load(context, "vkCmdTraceRaysNV"); + vkCmdWriteAccelerationStructuresPropertiesNV = (PFN_vkCmdWriteAccelerationStructuresPropertiesNV)load(context, "vkCmdWriteAccelerationStructuresPropertiesNV"); + vkCompileDeferredNV = (PFN_vkCompileDeferredNV)load(context, "vkCompileDeferredNV"); + vkCreateAccelerationStructureNV = (PFN_vkCreateAccelerationStructureNV)load(context, "vkCreateAccelerationStructureNV"); + vkCreateRayTracingPipelinesNV = (PFN_vkCreateRayTracingPipelinesNV)load(context, "vkCreateRayTracingPipelinesNV"); + vkDestroyAccelerationStructureNV = (PFN_vkDestroyAccelerationStructureNV)load(context, "vkDestroyAccelerationStructureNV"); + vkGetAccelerationStructureHandleNV = (PFN_vkGetAccelerationStructureHandleNV)load(context, "vkGetAccelerationStructureHandleNV"); + vkGetAccelerationStructureMemoryRequirementsNV = (PFN_vkGetAccelerationStructureMemoryRequirementsNV)load(context, "vkGetAccelerationStructureMemoryRequirementsNV"); + vkGetRayTracingShaderGroupHandlesNV = (PFN_vkGetRayTracingShaderGroupHandlesNV)load(context, "vkGetRayTracingShaderGroupHandlesNV"); +#endif /* defined(VK_NV_ray_tracing) */ +#if defined(VK_NV_scissor_exclusive) + vkCmdSetExclusiveScissorNV = (PFN_vkCmdSetExclusiveScissorNV)load(context, "vkCmdSetExclusiveScissorNV"); +#endif /* defined(VK_NV_scissor_exclusive) */ +#if defined(VK_NV_shading_rate_image) + vkCmdBindShadingRateImageNV = (PFN_vkCmdBindShadingRateImageNV)load(context, "vkCmdBindShadingRateImageNV"); + vkCmdSetCoarseSampleOrderNV = (PFN_vkCmdSetCoarseSampleOrderNV)load(context, "vkCmdSetCoarseSampleOrderNV"); + vkCmdSetViewportShadingRatePaletteNV = (PFN_vkCmdSetViewportShadingRatePaletteNV)load(context, "vkCmdSetViewportShadingRatePaletteNV"); +#endif /* defined(VK_NV_shading_rate_image) */ +#if (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) + vkGetDeviceGroupSurfacePresentModes2EXT = (PFN_vkGetDeviceGroupSurfacePresentModes2EXT)load(context, "vkGetDeviceGroupSurfacePresentModes2EXT"); +#endif /* (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) + vkCmdPushDescriptorSetWithTemplateKHR = (PFN_vkCmdPushDescriptorSetWithTemplateKHR)load(context, "vkCmdPushDescriptorSetWithTemplateKHR"); +#endif /* (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) + vkGetDeviceGroupPresentCapabilitiesKHR = (PFN_vkGetDeviceGroupPresentCapabilitiesKHR)load(context, "vkGetDeviceGroupPresentCapabilitiesKHR"); + vkGetDeviceGroupSurfacePresentModesKHR = (PFN_vkGetDeviceGroupSurfacePresentModesKHR)load(context, "vkGetDeviceGroupSurfacePresentModesKHR"); +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) + vkAcquireNextImage2KHR = (PFN_vkAcquireNextImage2KHR)load(context, "vkAcquireNextImage2KHR"); +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ + /* VOLK_GENERATE_LOAD_DEVICE */ +} + +static void volkGenLoadDeviceTable(struct VolkDeviceTable* table, void* context, PFN_vkVoidFunction (*load)(void*, const char*)) +{ + /* VOLK_GENERATE_LOAD_DEVICE_TABLE */ +#if defined(VK_VERSION_1_0) + table->vkAllocateCommandBuffers = (PFN_vkAllocateCommandBuffers)load(context, "vkAllocateCommandBuffers"); + table->vkAllocateDescriptorSets = (PFN_vkAllocateDescriptorSets)load(context, "vkAllocateDescriptorSets"); + table->vkAllocateMemory = (PFN_vkAllocateMemory)load(context, "vkAllocateMemory"); + table->vkBeginCommandBuffer = (PFN_vkBeginCommandBuffer)load(context, "vkBeginCommandBuffer"); + table->vkBindBufferMemory = (PFN_vkBindBufferMemory)load(context, "vkBindBufferMemory"); + table->vkBindImageMemory = (PFN_vkBindImageMemory)load(context, "vkBindImageMemory"); + table->vkCmdBeginQuery = (PFN_vkCmdBeginQuery)load(context, "vkCmdBeginQuery"); + table->vkCmdBeginRenderPass = (PFN_vkCmdBeginRenderPass)load(context, "vkCmdBeginRenderPass"); + table->vkCmdBindDescriptorSets = (PFN_vkCmdBindDescriptorSets)load(context, "vkCmdBindDescriptorSets"); + table->vkCmdBindIndexBuffer = (PFN_vkCmdBindIndexBuffer)load(context, "vkCmdBindIndexBuffer"); + table->vkCmdBindPipeline = (PFN_vkCmdBindPipeline)load(context, "vkCmdBindPipeline"); + table->vkCmdBindVertexBuffers = (PFN_vkCmdBindVertexBuffers)load(context, "vkCmdBindVertexBuffers"); + table->vkCmdBlitImage = (PFN_vkCmdBlitImage)load(context, "vkCmdBlitImage"); + table->vkCmdClearAttachments = (PFN_vkCmdClearAttachments)load(context, "vkCmdClearAttachments"); + table->vkCmdClearColorImage = (PFN_vkCmdClearColorImage)load(context, "vkCmdClearColorImage"); + table->vkCmdClearDepthStencilImage = (PFN_vkCmdClearDepthStencilImage)load(context, "vkCmdClearDepthStencilImage"); + table->vkCmdCopyBuffer = (PFN_vkCmdCopyBuffer)load(context, "vkCmdCopyBuffer"); + table->vkCmdCopyBufferToImage = (PFN_vkCmdCopyBufferToImage)load(context, "vkCmdCopyBufferToImage"); + table->vkCmdCopyImage = (PFN_vkCmdCopyImage)load(context, "vkCmdCopyImage"); + table->vkCmdCopyImageToBuffer = (PFN_vkCmdCopyImageToBuffer)load(context, "vkCmdCopyImageToBuffer"); + table->vkCmdCopyQueryPoolResults = (PFN_vkCmdCopyQueryPoolResults)load(context, "vkCmdCopyQueryPoolResults"); + table->vkCmdDispatch = (PFN_vkCmdDispatch)load(context, "vkCmdDispatch"); + table->vkCmdDispatchIndirect = (PFN_vkCmdDispatchIndirect)load(context, "vkCmdDispatchIndirect"); + table->vkCmdDraw = (PFN_vkCmdDraw)load(context, "vkCmdDraw"); + table->vkCmdDrawIndexed = (PFN_vkCmdDrawIndexed)load(context, "vkCmdDrawIndexed"); + table->vkCmdDrawIndexedIndirect = (PFN_vkCmdDrawIndexedIndirect)load(context, "vkCmdDrawIndexedIndirect"); + table->vkCmdDrawIndirect = (PFN_vkCmdDrawIndirect)load(context, "vkCmdDrawIndirect"); + table->vkCmdEndQuery = (PFN_vkCmdEndQuery)load(context, "vkCmdEndQuery"); + table->vkCmdEndRenderPass = (PFN_vkCmdEndRenderPass)load(context, "vkCmdEndRenderPass"); + table->vkCmdExecuteCommands = (PFN_vkCmdExecuteCommands)load(context, "vkCmdExecuteCommands"); + table->vkCmdFillBuffer = (PFN_vkCmdFillBuffer)load(context, "vkCmdFillBuffer"); + table->vkCmdNextSubpass = (PFN_vkCmdNextSubpass)load(context, "vkCmdNextSubpass"); + table->vkCmdPipelineBarrier = (PFN_vkCmdPipelineBarrier)load(context, "vkCmdPipelineBarrier"); + table->vkCmdPushConstants = (PFN_vkCmdPushConstants)load(context, "vkCmdPushConstants"); + table->vkCmdResetEvent = (PFN_vkCmdResetEvent)load(context, "vkCmdResetEvent"); + table->vkCmdResetQueryPool = (PFN_vkCmdResetQueryPool)load(context, "vkCmdResetQueryPool"); + table->vkCmdResolveImage = (PFN_vkCmdResolveImage)load(context, "vkCmdResolveImage"); + table->vkCmdSetBlendConstants = (PFN_vkCmdSetBlendConstants)load(context, "vkCmdSetBlendConstants"); + table->vkCmdSetDepthBias = (PFN_vkCmdSetDepthBias)load(context, "vkCmdSetDepthBias"); + table->vkCmdSetDepthBounds = (PFN_vkCmdSetDepthBounds)load(context, "vkCmdSetDepthBounds"); + table->vkCmdSetEvent = (PFN_vkCmdSetEvent)load(context, "vkCmdSetEvent"); + table->vkCmdSetLineWidth = (PFN_vkCmdSetLineWidth)load(context, "vkCmdSetLineWidth"); + table->vkCmdSetScissor = (PFN_vkCmdSetScissor)load(context, "vkCmdSetScissor"); + table->vkCmdSetStencilCompareMask = (PFN_vkCmdSetStencilCompareMask)load(context, "vkCmdSetStencilCompareMask"); + table->vkCmdSetStencilReference = (PFN_vkCmdSetStencilReference)load(context, "vkCmdSetStencilReference"); + table->vkCmdSetStencilWriteMask = (PFN_vkCmdSetStencilWriteMask)load(context, "vkCmdSetStencilWriteMask"); + table->vkCmdSetViewport = (PFN_vkCmdSetViewport)load(context, "vkCmdSetViewport"); + table->vkCmdUpdateBuffer = (PFN_vkCmdUpdateBuffer)load(context, "vkCmdUpdateBuffer"); + table->vkCmdWaitEvents = (PFN_vkCmdWaitEvents)load(context, "vkCmdWaitEvents"); + table->vkCmdWriteTimestamp = (PFN_vkCmdWriteTimestamp)load(context, "vkCmdWriteTimestamp"); + table->vkCreateBuffer = (PFN_vkCreateBuffer)load(context, "vkCreateBuffer"); + table->vkCreateBufferView = (PFN_vkCreateBufferView)load(context, "vkCreateBufferView"); + table->vkCreateCommandPool = (PFN_vkCreateCommandPool)load(context, "vkCreateCommandPool"); + table->vkCreateComputePipelines = (PFN_vkCreateComputePipelines)load(context, "vkCreateComputePipelines"); + table->vkCreateDescriptorPool = (PFN_vkCreateDescriptorPool)load(context, "vkCreateDescriptorPool"); + table->vkCreateDescriptorSetLayout = (PFN_vkCreateDescriptorSetLayout)load(context, "vkCreateDescriptorSetLayout"); + table->vkCreateEvent = (PFN_vkCreateEvent)load(context, "vkCreateEvent"); + table->vkCreateFence = (PFN_vkCreateFence)load(context, "vkCreateFence"); + table->vkCreateFramebuffer = (PFN_vkCreateFramebuffer)load(context, "vkCreateFramebuffer"); + table->vkCreateGraphicsPipelines = (PFN_vkCreateGraphicsPipelines)load(context, "vkCreateGraphicsPipelines"); + table->vkCreateImage = (PFN_vkCreateImage)load(context, "vkCreateImage"); + table->vkCreateImageView = (PFN_vkCreateImageView)load(context, "vkCreateImageView"); + table->vkCreatePipelineCache = (PFN_vkCreatePipelineCache)load(context, "vkCreatePipelineCache"); + table->vkCreatePipelineLayout = (PFN_vkCreatePipelineLayout)load(context, "vkCreatePipelineLayout"); + table->vkCreateQueryPool = (PFN_vkCreateQueryPool)load(context, "vkCreateQueryPool"); + table->vkCreateRenderPass = (PFN_vkCreateRenderPass)load(context, "vkCreateRenderPass"); + table->vkCreateSampler = (PFN_vkCreateSampler)load(context, "vkCreateSampler"); + table->vkCreateSemaphore = (PFN_vkCreateSemaphore)load(context, "vkCreateSemaphore"); + table->vkCreateShaderModule = (PFN_vkCreateShaderModule)load(context, "vkCreateShaderModule"); + table->vkDestroyBuffer = (PFN_vkDestroyBuffer)load(context, "vkDestroyBuffer"); + table->vkDestroyBufferView = (PFN_vkDestroyBufferView)load(context, "vkDestroyBufferView"); + table->vkDestroyCommandPool = (PFN_vkDestroyCommandPool)load(context, "vkDestroyCommandPool"); + table->vkDestroyDescriptorPool = (PFN_vkDestroyDescriptorPool)load(context, "vkDestroyDescriptorPool"); + table->vkDestroyDescriptorSetLayout = (PFN_vkDestroyDescriptorSetLayout)load(context, "vkDestroyDescriptorSetLayout"); + table->vkDestroyDevice = (PFN_vkDestroyDevice)load(context, "vkDestroyDevice"); + table->vkDestroyEvent = (PFN_vkDestroyEvent)load(context, "vkDestroyEvent"); + table->vkDestroyFence = (PFN_vkDestroyFence)load(context, "vkDestroyFence"); + table->vkDestroyFramebuffer = (PFN_vkDestroyFramebuffer)load(context, "vkDestroyFramebuffer"); + table->vkDestroyImage = (PFN_vkDestroyImage)load(context, "vkDestroyImage"); + table->vkDestroyImageView = (PFN_vkDestroyImageView)load(context, "vkDestroyImageView"); + table->vkDestroyPipeline = (PFN_vkDestroyPipeline)load(context, "vkDestroyPipeline"); + table->vkDestroyPipelineCache = (PFN_vkDestroyPipelineCache)load(context, "vkDestroyPipelineCache"); + table->vkDestroyPipelineLayout = (PFN_vkDestroyPipelineLayout)load(context, "vkDestroyPipelineLayout"); + table->vkDestroyQueryPool = (PFN_vkDestroyQueryPool)load(context, "vkDestroyQueryPool"); + table->vkDestroyRenderPass = (PFN_vkDestroyRenderPass)load(context, "vkDestroyRenderPass"); + table->vkDestroySampler = (PFN_vkDestroySampler)load(context, "vkDestroySampler"); + table->vkDestroySemaphore = (PFN_vkDestroySemaphore)load(context, "vkDestroySemaphore"); + table->vkDestroyShaderModule = (PFN_vkDestroyShaderModule)load(context, "vkDestroyShaderModule"); + table->vkDeviceWaitIdle = (PFN_vkDeviceWaitIdle)load(context, "vkDeviceWaitIdle"); + table->vkEndCommandBuffer = (PFN_vkEndCommandBuffer)load(context, "vkEndCommandBuffer"); + table->vkFlushMappedMemoryRanges = (PFN_vkFlushMappedMemoryRanges)load(context, "vkFlushMappedMemoryRanges"); + table->vkFreeCommandBuffers = (PFN_vkFreeCommandBuffers)load(context, "vkFreeCommandBuffers"); + table->vkFreeDescriptorSets = (PFN_vkFreeDescriptorSets)load(context, "vkFreeDescriptorSets"); + table->vkFreeMemory = (PFN_vkFreeMemory)load(context, "vkFreeMemory"); + table->vkGetBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements)load(context, "vkGetBufferMemoryRequirements"); + table->vkGetDeviceMemoryCommitment = (PFN_vkGetDeviceMemoryCommitment)load(context, "vkGetDeviceMemoryCommitment"); + table->vkGetDeviceQueue = (PFN_vkGetDeviceQueue)load(context, "vkGetDeviceQueue"); + table->vkGetEventStatus = (PFN_vkGetEventStatus)load(context, "vkGetEventStatus"); + table->vkGetFenceStatus = (PFN_vkGetFenceStatus)load(context, "vkGetFenceStatus"); + table->vkGetImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements)load(context, "vkGetImageMemoryRequirements"); + table->vkGetImageSparseMemoryRequirements = (PFN_vkGetImageSparseMemoryRequirements)load(context, "vkGetImageSparseMemoryRequirements"); + table->vkGetImageSubresourceLayout = (PFN_vkGetImageSubresourceLayout)load(context, "vkGetImageSubresourceLayout"); + table->vkGetPipelineCacheData = (PFN_vkGetPipelineCacheData)load(context, "vkGetPipelineCacheData"); + table->vkGetQueryPoolResults = (PFN_vkGetQueryPoolResults)load(context, "vkGetQueryPoolResults"); + table->vkGetRenderAreaGranularity = (PFN_vkGetRenderAreaGranularity)load(context, "vkGetRenderAreaGranularity"); + table->vkInvalidateMappedMemoryRanges = (PFN_vkInvalidateMappedMemoryRanges)load(context, "vkInvalidateMappedMemoryRanges"); + table->vkMapMemory = (PFN_vkMapMemory)load(context, "vkMapMemory"); + table->vkMergePipelineCaches = (PFN_vkMergePipelineCaches)load(context, "vkMergePipelineCaches"); + table->vkQueueBindSparse = (PFN_vkQueueBindSparse)load(context, "vkQueueBindSparse"); + table->vkQueueSubmit = (PFN_vkQueueSubmit)load(context, "vkQueueSubmit"); + table->vkQueueWaitIdle = (PFN_vkQueueWaitIdle)load(context, "vkQueueWaitIdle"); + table->vkResetCommandBuffer = (PFN_vkResetCommandBuffer)load(context, "vkResetCommandBuffer"); + table->vkResetCommandPool = (PFN_vkResetCommandPool)load(context, "vkResetCommandPool"); + table->vkResetDescriptorPool = (PFN_vkResetDescriptorPool)load(context, "vkResetDescriptorPool"); + table->vkResetEvent = (PFN_vkResetEvent)load(context, "vkResetEvent"); + table->vkResetFences = (PFN_vkResetFences)load(context, "vkResetFences"); + table->vkSetEvent = (PFN_vkSetEvent)load(context, "vkSetEvent"); + table->vkUnmapMemory = (PFN_vkUnmapMemory)load(context, "vkUnmapMemory"); + table->vkUpdateDescriptorSets = (PFN_vkUpdateDescriptorSets)load(context, "vkUpdateDescriptorSets"); + table->vkWaitForFences = (PFN_vkWaitForFences)load(context, "vkWaitForFences"); +#endif /* defined(VK_VERSION_1_0) */ +#if defined(VK_VERSION_1_1) + table->vkBindBufferMemory2 = (PFN_vkBindBufferMemory2)load(context, "vkBindBufferMemory2"); + table->vkBindImageMemory2 = (PFN_vkBindImageMemory2)load(context, "vkBindImageMemory2"); + table->vkCmdDispatchBase = (PFN_vkCmdDispatchBase)load(context, "vkCmdDispatchBase"); + table->vkCmdSetDeviceMask = (PFN_vkCmdSetDeviceMask)load(context, "vkCmdSetDeviceMask"); + table->vkCreateDescriptorUpdateTemplate = (PFN_vkCreateDescriptorUpdateTemplate)load(context, "vkCreateDescriptorUpdateTemplate"); + table->vkCreateSamplerYcbcrConversion = (PFN_vkCreateSamplerYcbcrConversion)load(context, "vkCreateSamplerYcbcrConversion"); + table->vkDestroyDescriptorUpdateTemplate = (PFN_vkDestroyDescriptorUpdateTemplate)load(context, "vkDestroyDescriptorUpdateTemplate"); + table->vkDestroySamplerYcbcrConversion = (PFN_vkDestroySamplerYcbcrConversion)load(context, "vkDestroySamplerYcbcrConversion"); + table->vkGetBufferMemoryRequirements2 = (PFN_vkGetBufferMemoryRequirements2)load(context, "vkGetBufferMemoryRequirements2"); + table->vkGetDescriptorSetLayoutSupport = (PFN_vkGetDescriptorSetLayoutSupport)load(context, "vkGetDescriptorSetLayoutSupport"); + table->vkGetDeviceGroupPeerMemoryFeatures = (PFN_vkGetDeviceGroupPeerMemoryFeatures)load(context, "vkGetDeviceGroupPeerMemoryFeatures"); + table->vkGetDeviceQueue2 = (PFN_vkGetDeviceQueue2)load(context, "vkGetDeviceQueue2"); + table->vkGetImageMemoryRequirements2 = (PFN_vkGetImageMemoryRequirements2)load(context, "vkGetImageMemoryRequirements2"); + table->vkGetImageSparseMemoryRequirements2 = (PFN_vkGetImageSparseMemoryRequirements2)load(context, "vkGetImageSparseMemoryRequirements2"); + table->vkTrimCommandPool = (PFN_vkTrimCommandPool)load(context, "vkTrimCommandPool"); + table->vkUpdateDescriptorSetWithTemplate = (PFN_vkUpdateDescriptorSetWithTemplate)load(context, "vkUpdateDescriptorSetWithTemplate"); +#endif /* defined(VK_VERSION_1_1) */ +#if defined(VK_VERSION_1_2) + table->vkCmdBeginRenderPass2 = (PFN_vkCmdBeginRenderPass2)load(context, "vkCmdBeginRenderPass2"); + table->vkCmdDrawIndexedIndirectCount = (PFN_vkCmdDrawIndexedIndirectCount)load(context, "vkCmdDrawIndexedIndirectCount"); + table->vkCmdDrawIndirectCount = (PFN_vkCmdDrawIndirectCount)load(context, "vkCmdDrawIndirectCount"); + table->vkCmdEndRenderPass2 = (PFN_vkCmdEndRenderPass2)load(context, "vkCmdEndRenderPass2"); + table->vkCmdNextSubpass2 = (PFN_vkCmdNextSubpass2)load(context, "vkCmdNextSubpass2"); + table->vkCreateRenderPass2 = (PFN_vkCreateRenderPass2)load(context, "vkCreateRenderPass2"); + table->vkGetBufferDeviceAddress = (PFN_vkGetBufferDeviceAddress)load(context, "vkGetBufferDeviceAddress"); + table->vkGetBufferOpaqueCaptureAddress = (PFN_vkGetBufferOpaqueCaptureAddress)load(context, "vkGetBufferOpaqueCaptureAddress"); + table->vkGetDeviceMemoryOpaqueCaptureAddress = (PFN_vkGetDeviceMemoryOpaqueCaptureAddress)load(context, "vkGetDeviceMemoryOpaqueCaptureAddress"); + table->vkGetSemaphoreCounterValue = (PFN_vkGetSemaphoreCounterValue)load(context, "vkGetSemaphoreCounterValue"); + table->vkResetQueryPool = (PFN_vkResetQueryPool)load(context, "vkResetQueryPool"); + table->vkSignalSemaphore = (PFN_vkSignalSemaphore)load(context, "vkSignalSemaphore"); + table->vkWaitSemaphores = (PFN_vkWaitSemaphores)load(context, "vkWaitSemaphores"); +#endif /* defined(VK_VERSION_1_2) */ +#if defined(VK_AMD_buffer_marker) + table->vkCmdWriteBufferMarkerAMD = (PFN_vkCmdWriteBufferMarkerAMD)load(context, "vkCmdWriteBufferMarkerAMD"); +#endif /* defined(VK_AMD_buffer_marker) */ +#if defined(VK_AMD_display_native_hdr) + table->vkSetLocalDimmingAMD = (PFN_vkSetLocalDimmingAMD)load(context, "vkSetLocalDimmingAMD"); +#endif /* defined(VK_AMD_display_native_hdr) */ +#if defined(VK_AMD_draw_indirect_count) + table->vkCmdDrawIndexedIndirectCountAMD = (PFN_vkCmdDrawIndexedIndirectCountAMD)load(context, "vkCmdDrawIndexedIndirectCountAMD"); + table->vkCmdDrawIndirectCountAMD = (PFN_vkCmdDrawIndirectCountAMD)load(context, "vkCmdDrawIndirectCountAMD"); +#endif /* defined(VK_AMD_draw_indirect_count) */ +#if defined(VK_AMD_shader_info) + table->vkGetShaderInfoAMD = (PFN_vkGetShaderInfoAMD)load(context, "vkGetShaderInfoAMD"); +#endif /* defined(VK_AMD_shader_info) */ +#if defined(VK_ANDROID_external_memory_android_hardware_buffer) + table->vkGetAndroidHardwareBufferPropertiesANDROID = (PFN_vkGetAndroidHardwareBufferPropertiesANDROID)load(context, "vkGetAndroidHardwareBufferPropertiesANDROID"); + table->vkGetMemoryAndroidHardwareBufferANDROID = (PFN_vkGetMemoryAndroidHardwareBufferANDROID)load(context, "vkGetMemoryAndroidHardwareBufferANDROID"); +#endif /* defined(VK_ANDROID_external_memory_android_hardware_buffer) */ +#if defined(VK_EXT_buffer_device_address) + table->vkGetBufferDeviceAddressEXT = (PFN_vkGetBufferDeviceAddressEXT)load(context, "vkGetBufferDeviceAddressEXT"); +#endif /* defined(VK_EXT_buffer_device_address) */ +#if defined(VK_EXT_calibrated_timestamps) + table->vkGetCalibratedTimestampsEXT = (PFN_vkGetCalibratedTimestampsEXT)load(context, "vkGetCalibratedTimestampsEXT"); +#endif /* defined(VK_EXT_calibrated_timestamps) */ +#if defined(VK_EXT_conditional_rendering) + table->vkCmdBeginConditionalRenderingEXT = (PFN_vkCmdBeginConditionalRenderingEXT)load(context, "vkCmdBeginConditionalRenderingEXT"); + table->vkCmdEndConditionalRenderingEXT = (PFN_vkCmdEndConditionalRenderingEXT)load(context, "vkCmdEndConditionalRenderingEXT"); +#endif /* defined(VK_EXT_conditional_rendering) */ +#if defined(VK_EXT_debug_marker) + table->vkCmdDebugMarkerBeginEXT = (PFN_vkCmdDebugMarkerBeginEXT)load(context, "vkCmdDebugMarkerBeginEXT"); + table->vkCmdDebugMarkerEndEXT = (PFN_vkCmdDebugMarkerEndEXT)load(context, "vkCmdDebugMarkerEndEXT"); + table->vkCmdDebugMarkerInsertEXT = (PFN_vkCmdDebugMarkerInsertEXT)load(context, "vkCmdDebugMarkerInsertEXT"); + table->vkDebugMarkerSetObjectNameEXT = (PFN_vkDebugMarkerSetObjectNameEXT)load(context, "vkDebugMarkerSetObjectNameEXT"); + table->vkDebugMarkerSetObjectTagEXT = (PFN_vkDebugMarkerSetObjectTagEXT)load(context, "vkDebugMarkerSetObjectTagEXT"); +#endif /* defined(VK_EXT_debug_marker) */ +#if defined(VK_EXT_discard_rectangles) + table->vkCmdSetDiscardRectangleEXT = (PFN_vkCmdSetDiscardRectangleEXT)load(context, "vkCmdSetDiscardRectangleEXT"); +#endif /* defined(VK_EXT_discard_rectangles) */ +#if defined(VK_EXT_display_control) + table->vkDisplayPowerControlEXT = (PFN_vkDisplayPowerControlEXT)load(context, "vkDisplayPowerControlEXT"); + table->vkGetSwapchainCounterEXT = (PFN_vkGetSwapchainCounterEXT)load(context, "vkGetSwapchainCounterEXT"); + table->vkRegisterDeviceEventEXT = (PFN_vkRegisterDeviceEventEXT)load(context, "vkRegisterDeviceEventEXT"); + table->vkRegisterDisplayEventEXT = (PFN_vkRegisterDisplayEventEXT)load(context, "vkRegisterDisplayEventEXT"); +#endif /* defined(VK_EXT_display_control) */ +#if defined(VK_EXT_extended_dynamic_state) + table->vkCmdBindVertexBuffers2EXT = (PFN_vkCmdBindVertexBuffers2EXT)load(context, "vkCmdBindVertexBuffers2EXT"); + table->vkCmdSetCullModeEXT = (PFN_vkCmdSetCullModeEXT)load(context, "vkCmdSetCullModeEXT"); + table->vkCmdSetDepthBoundsTestEnableEXT = (PFN_vkCmdSetDepthBoundsTestEnableEXT)load(context, "vkCmdSetDepthBoundsTestEnableEXT"); + table->vkCmdSetDepthCompareOpEXT = (PFN_vkCmdSetDepthCompareOpEXT)load(context, "vkCmdSetDepthCompareOpEXT"); + table->vkCmdSetDepthTestEnableEXT = (PFN_vkCmdSetDepthTestEnableEXT)load(context, "vkCmdSetDepthTestEnableEXT"); + table->vkCmdSetDepthWriteEnableEXT = (PFN_vkCmdSetDepthWriteEnableEXT)load(context, "vkCmdSetDepthWriteEnableEXT"); + table->vkCmdSetFrontFaceEXT = (PFN_vkCmdSetFrontFaceEXT)load(context, "vkCmdSetFrontFaceEXT"); + table->vkCmdSetPrimitiveTopologyEXT = (PFN_vkCmdSetPrimitiveTopologyEXT)load(context, "vkCmdSetPrimitiveTopologyEXT"); + table->vkCmdSetScissorWithCountEXT = (PFN_vkCmdSetScissorWithCountEXT)load(context, "vkCmdSetScissorWithCountEXT"); + table->vkCmdSetStencilOpEXT = (PFN_vkCmdSetStencilOpEXT)load(context, "vkCmdSetStencilOpEXT"); + table->vkCmdSetStencilTestEnableEXT = (PFN_vkCmdSetStencilTestEnableEXT)load(context, "vkCmdSetStencilTestEnableEXT"); + table->vkCmdSetViewportWithCountEXT = (PFN_vkCmdSetViewportWithCountEXT)load(context, "vkCmdSetViewportWithCountEXT"); +#endif /* defined(VK_EXT_extended_dynamic_state) */ +#if defined(VK_EXT_external_memory_host) + table->vkGetMemoryHostPointerPropertiesEXT = (PFN_vkGetMemoryHostPointerPropertiesEXT)load(context, "vkGetMemoryHostPointerPropertiesEXT"); +#endif /* defined(VK_EXT_external_memory_host) */ +#if defined(VK_EXT_full_screen_exclusive) + table->vkAcquireFullScreenExclusiveModeEXT = (PFN_vkAcquireFullScreenExclusiveModeEXT)load(context, "vkAcquireFullScreenExclusiveModeEXT"); + table->vkReleaseFullScreenExclusiveModeEXT = (PFN_vkReleaseFullScreenExclusiveModeEXT)load(context, "vkReleaseFullScreenExclusiveModeEXT"); +#endif /* defined(VK_EXT_full_screen_exclusive) */ +#if defined(VK_EXT_hdr_metadata) + table->vkSetHdrMetadataEXT = (PFN_vkSetHdrMetadataEXT)load(context, "vkSetHdrMetadataEXT"); +#endif /* defined(VK_EXT_hdr_metadata) */ +#if defined(VK_EXT_host_query_reset) + table->vkResetQueryPoolEXT = (PFN_vkResetQueryPoolEXT)load(context, "vkResetQueryPoolEXT"); +#endif /* defined(VK_EXT_host_query_reset) */ +#if defined(VK_EXT_image_drm_format_modifier) + table->vkGetImageDrmFormatModifierPropertiesEXT = (PFN_vkGetImageDrmFormatModifierPropertiesEXT)load(context, "vkGetImageDrmFormatModifierPropertiesEXT"); +#endif /* defined(VK_EXT_image_drm_format_modifier) */ +#if defined(VK_EXT_line_rasterization) + table->vkCmdSetLineStippleEXT = (PFN_vkCmdSetLineStippleEXT)load(context, "vkCmdSetLineStippleEXT"); +#endif /* defined(VK_EXT_line_rasterization) */ +#if defined(VK_EXT_private_data) + table->vkCreatePrivateDataSlotEXT = (PFN_vkCreatePrivateDataSlotEXT)load(context, "vkCreatePrivateDataSlotEXT"); + table->vkDestroyPrivateDataSlotEXT = (PFN_vkDestroyPrivateDataSlotEXT)load(context, "vkDestroyPrivateDataSlotEXT"); + table->vkGetPrivateDataEXT = (PFN_vkGetPrivateDataEXT)load(context, "vkGetPrivateDataEXT"); + table->vkSetPrivateDataEXT = (PFN_vkSetPrivateDataEXT)load(context, "vkSetPrivateDataEXT"); +#endif /* defined(VK_EXT_private_data) */ +#if defined(VK_EXT_sample_locations) + table->vkCmdSetSampleLocationsEXT = (PFN_vkCmdSetSampleLocationsEXT)load(context, "vkCmdSetSampleLocationsEXT"); +#endif /* defined(VK_EXT_sample_locations) */ +#if defined(VK_EXT_transform_feedback) + table->vkCmdBeginQueryIndexedEXT = (PFN_vkCmdBeginQueryIndexedEXT)load(context, "vkCmdBeginQueryIndexedEXT"); + table->vkCmdBeginTransformFeedbackEXT = (PFN_vkCmdBeginTransformFeedbackEXT)load(context, "vkCmdBeginTransformFeedbackEXT"); + table->vkCmdBindTransformFeedbackBuffersEXT = (PFN_vkCmdBindTransformFeedbackBuffersEXT)load(context, "vkCmdBindTransformFeedbackBuffersEXT"); + table->vkCmdDrawIndirectByteCountEXT = (PFN_vkCmdDrawIndirectByteCountEXT)load(context, "vkCmdDrawIndirectByteCountEXT"); + table->vkCmdEndQueryIndexedEXT = (PFN_vkCmdEndQueryIndexedEXT)load(context, "vkCmdEndQueryIndexedEXT"); + table->vkCmdEndTransformFeedbackEXT = (PFN_vkCmdEndTransformFeedbackEXT)load(context, "vkCmdEndTransformFeedbackEXT"); +#endif /* defined(VK_EXT_transform_feedback) */ +#if defined(VK_EXT_validation_cache) + table->vkCreateValidationCacheEXT = (PFN_vkCreateValidationCacheEXT)load(context, "vkCreateValidationCacheEXT"); + table->vkDestroyValidationCacheEXT = (PFN_vkDestroyValidationCacheEXT)load(context, "vkDestroyValidationCacheEXT"); + table->vkGetValidationCacheDataEXT = (PFN_vkGetValidationCacheDataEXT)load(context, "vkGetValidationCacheDataEXT"); + table->vkMergeValidationCachesEXT = (PFN_vkMergeValidationCachesEXT)load(context, "vkMergeValidationCachesEXT"); +#endif /* defined(VK_EXT_validation_cache) */ +#if defined(VK_GOOGLE_display_timing) + table->vkGetPastPresentationTimingGOOGLE = (PFN_vkGetPastPresentationTimingGOOGLE)load(context, "vkGetPastPresentationTimingGOOGLE"); + table->vkGetRefreshCycleDurationGOOGLE = (PFN_vkGetRefreshCycleDurationGOOGLE)load(context, "vkGetRefreshCycleDurationGOOGLE"); +#endif /* defined(VK_GOOGLE_display_timing) */ +#if defined(VK_INTEL_performance_query) + table->vkAcquirePerformanceConfigurationINTEL = (PFN_vkAcquirePerformanceConfigurationINTEL)load(context, "vkAcquirePerformanceConfigurationINTEL"); + table->vkCmdSetPerformanceMarkerINTEL = (PFN_vkCmdSetPerformanceMarkerINTEL)load(context, "vkCmdSetPerformanceMarkerINTEL"); + table->vkCmdSetPerformanceOverrideINTEL = (PFN_vkCmdSetPerformanceOverrideINTEL)load(context, "vkCmdSetPerformanceOverrideINTEL"); + table->vkCmdSetPerformanceStreamMarkerINTEL = (PFN_vkCmdSetPerformanceStreamMarkerINTEL)load(context, "vkCmdSetPerformanceStreamMarkerINTEL"); + table->vkGetPerformanceParameterINTEL = (PFN_vkGetPerformanceParameterINTEL)load(context, "vkGetPerformanceParameterINTEL"); + table->vkInitializePerformanceApiINTEL = (PFN_vkInitializePerformanceApiINTEL)load(context, "vkInitializePerformanceApiINTEL"); + table->vkQueueSetPerformanceConfigurationINTEL = (PFN_vkQueueSetPerformanceConfigurationINTEL)load(context, "vkQueueSetPerformanceConfigurationINTEL"); + table->vkReleasePerformanceConfigurationINTEL = (PFN_vkReleasePerformanceConfigurationINTEL)load(context, "vkReleasePerformanceConfigurationINTEL"); + table->vkUninitializePerformanceApiINTEL = (PFN_vkUninitializePerformanceApiINTEL)load(context, "vkUninitializePerformanceApiINTEL"); +#endif /* defined(VK_INTEL_performance_query) */ +#if defined(VK_KHR_bind_memory2) + table->vkBindBufferMemory2KHR = (PFN_vkBindBufferMemory2KHR)load(context, "vkBindBufferMemory2KHR"); + table->vkBindImageMemory2KHR = (PFN_vkBindImageMemory2KHR)load(context, "vkBindImageMemory2KHR"); +#endif /* defined(VK_KHR_bind_memory2) */ +#if defined(VK_KHR_buffer_device_address) + table->vkGetBufferDeviceAddressKHR = (PFN_vkGetBufferDeviceAddressKHR)load(context, "vkGetBufferDeviceAddressKHR"); + table->vkGetBufferOpaqueCaptureAddressKHR = (PFN_vkGetBufferOpaqueCaptureAddressKHR)load(context, "vkGetBufferOpaqueCaptureAddressKHR"); + table->vkGetDeviceMemoryOpaqueCaptureAddressKHR = (PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR)load(context, "vkGetDeviceMemoryOpaqueCaptureAddressKHR"); +#endif /* defined(VK_KHR_buffer_device_address) */ +#if defined(VK_KHR_create_renderpass2) + table->vkCmdBeginRenderPass2KHR = (PFN_vkCmdBeginRenderPass2KHR)load(context, "vkCmdBeginRenderPass2KHR"); + table->vkCmdEndRenderPass2KHR = (PFN_vkCmdEndRenderPass2KHR)load(context, "vkCmdEndRenderPass2KHR"); + table->vkCmdNextSubpass2KHR = (PFN_vkCmdNextSubpass2KHR)load(context, "vkCmdNextSubpass2KHR"); + table->vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)load(context, "vkCreateRenderPass2KHR"); +#endif /* defined(VK_KHR_create_renderpass2) */ +#if defined(VK_KHR_deferred_host_operations) + table->vkCreateDeferredOperationKHR = (PFN_vkCreateDeferredOperationKHR)load(context, "vkCreateDeferredOperationKHR"); + table->vkDeferredOperationJoinKHR = (PFN_vkDeferredOperationJoinKHR)load(context, "vkDeferredOperationJoinKHR"); + table->vkDestroyDeferredOperationKHR = (PFN_vkDestroyDeferredOperationKHR)load(context, "vkDestroyDeferredOperationKHR"); + table->vkGetDeferredOperationMaxConcurrencyKHR = (PFN_vkGetDeferredOperationMaxConcurrencyKHR)load(context, "vkGetDeferredOperationMaxConcurrencyKHR"); + table->vkGetDeferredOperationResultKHR = (PFN_vkGetDeferredOperationResultKHR)load(context, "vkGetDeferredOperationResultKHR"); +#endif /* defined(VK_KHR_deferred_host_operations) */ +#if defined(VK_KHR_descriptor_update_template) + table->vkCreateDescriptorUpdateTemplateKHR = (PFN_vkCreateDescriptorUpdateTemplateKHR)load(context, "vkCreateDescriptorUpdateTemplateKHR"); + table->vkDestroyDescriptorUpdateTemplateKHR = (PFN_vkDestroyDescriptorUpdateTemplateKHR)load(context, "vkDestroyDescriptorUpdateTemplateKHR"); + table->vkUpdateDescriptorSetWithTemplateKHR = (PFN_vkUpdateDescriptorSetWithTemplateKHR)load(context, "vkUpdateDescriptorSetWithTemplateKHR"); +#endif /* defined(VK_KHR_descriptor_update_template) */ +#if defined(VK_KHR_device_group) + table->vkCmdDispatchBaseKHR = (PFN_vkCmdDispatchBaseKHR)load(context, "vkCmdDispatchBaseKHR"); + table->vkCmdSetDeviceMaskKHR = (PFN_vkCmdSetDeviceMaskKHR)load(context, "vkCmdSetDeviceMaskKHR"); + table->vkGetDeviceGroupPeerMemoryFeaturesKHR = (PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR)load(context, "vkGetDeviceGroupPeerMemoryFeaturesKHR"); +#endif /* defined(VK_KHR_device_group) */ +#if defined(VK_KHR_display_swapchain) + table->vkCreateSharedSwapchainsKHR = (PFN_vkCreateSharedSwapchainsKHR)load(context, "vkCreateSharedSwapchainsKHR"); +#endif /* defined(VK_KHR_display_swapchain) */ +#if defined(VK_KHR_draw_indirect_count) + table->vkCmdDrawIndexedIndirectCountKHR = (PFN_vkCmdDrawIndexedIndirectCountKHR)load(context, "vkCmdDrawIndexedIndirectCountKHR"); + table->vkCmdDrawIndirectCountKHR = (PFN_vkCmdDrawIndirectCountKHR)load(context, "vkCmdDrawIndirectCountKHR"); +#endif /* defined(VK_KHR_draw_indirect_count) */ +#if defined(VK_KHR_external_fence_fd) + table->vkGetFenceFdKHR = (PFN_vkGetFenceFdKHR)load(context, "vkGetFenceFdKHR"); + table->vkImportFenceFdKHR = (PFN_vkImportFenceFdKHR)load(context, "vkImportFenceFdKHR"); +#endif /* defined(VK_KHR_external_fence_fd) */ +#if defined(VK_KHR_external_fence_win32) + table->vkGetFenceWin32HandleKHR = (PFN_vkGetFenceWin32HandleKHR)load(context, "vkGetFenceWin32HandleKHR"); + table->vkImportFenceWin32HandleKHR = (PFN_vkImportFenceWin32HandleKHR)load(context, "vkImportFenceWin32HandleKHR"); +#endif /* defined(VK_KHR_external_fence_win32) */ +#if defined(VK_KHR_external_memory_fd) + table->vkGetMemoryFdKHR = (PFN_vkGetMemoryFdKHR)load(context, "vkGetMemoryFdKHR"); + table->vkGetMemoryFdPropertiesKHR = (PFN_vkGetMemoryFdPropertiesKHR)load(context, "vkGetMemoryFdPropertiesKHR"); +#endif /* defined(VK_KHR_external_memory_fd) */ +#if defined(VK_KHR_external_memory_win32) + table->vkGetMemoryWin32HandleKHR = (PFN_vkGetMemoryWin32HandleKHR)load(context, "vkGetMemoryWin32HandleKHR"); + table->vkGetMemoryWin32HandlePropertiesKHR = (PFN_vkGetMemoryWin32HandlePropertiesKHR)load(context, "vkGetMemoryWin32HandlePropertiesKHR"); +#endif /* defined(VK_KHR_external_memory_win32) */ +#if defined(VK_KHR_external_semaphore_fd) + table->vkGetSemaphoreFdKHR = (PFN_vkGetSemaphoreFdKHR)load(context, "vkGetSemaphoreFdKHR"); + table->vkImportSemaphoreFdKHR = (PFN_vkImportSemaphoreFdKHR)load(context, "vkImportSemaphoreFdKHR"); +#endif /* defined(VK_KHR_external_semaphore_fd) */ +#if defined(VK_KHR_external_semaphore_win32) + table->vkGetSemaphoreWin32HandleKHR = (PFN_vkGetSemaphoreWin32HandleKHR)load(context, "vkGetSemaphoreWin32HandleKHR"); + table->vkImportSemaphoreWin32HandleKHR = (PFN_vkImportSemaphoreWin32HandleKHR)load(context, "vkImportSemaphoreWin32HandleKHR"); +#endif /* defined(VK_KHR_external_semaphore_win32) */ +#if defined(VK_KHR_get_memory_requirements2) + table->vkGetBufferMemoryRequirements2KHR = (PFN_vkGetBufferMemoryRequirements2KHR)load(context, "vkGetBufferMemoryRequirements2KHR"); + table->vkGetImageMemoryRequirements2KHR = (PFN_vkGetImageMemoryRequirements2KHR)load(context, "vkGetImageMemoryRequirements2KHR"); + table->vkGetImageSparseMemoryRequirements2KHR = (PFN_vkGetImageSparseMemoryRequirements2KHR)load(context, "vkGetImageSparseMemoryRequirements2KHR"); +#endif /* defined(VK_KHR_get_memory_requirements2) */ +#if defined(VK_KHR_maintenance1) + table->vkTrimCommandPoolKHR = (PFN_vkTrimCommandPoolKHR)load(context, "vkTrimCommandPoolKHR"); +#endif /* defined(VK_KHR_maintenance1) */ +#if defined(VK_KHR_maintenance3) + table->vkGetDescriptorSetLayoutSupportKHR = (PFN_vkGetDescriptorSetLayoutSupportKHR)load(context, "vkGetDescriptorSetLayoutSupportKHR"); +#endif /* defined(VK_KHR_maintenance3) */ +#if defined(VK_KHR_performance_query) + table->vkAcquireProfilingLockKHR = (PFN_vkAcquireProfilingLockKHR)load(context, "vkAcquireProfilingLockKHR"); + table->vkReleaseProfilingLockKHR = (PFN_vkReleaseProfilingLockKHR)load(context, "vkReleaseProfilingLockKHR"); +#endif /* defined(VK_KHR_performance_query) */ +#if defined(VK_KHR_pipeline_executable_properties) + table->vkGetPipelineExecutableInternalRepresentationsKHR = (PFN_vkGetPipelineExecutableInternalRepresentationsKHR)load(context, "vkGetPipelineExecutableInternalRepresentationsKHR"); + table->vkGetPipelineExecutablePropertiesKHR = (PFN_vkGetPipelineExecutablePropertiesKHR)load(context, "vkGetPipelineExecutablePropertiesKHR"); + table->vkGetPipelineExecutableStatisticsKHR = (PFN_vkGetPipelineExecutableStatisticsKHR)load(context, "vkGetPipelineExecutableStatisticsKHR"); +#endif /* defined(VK_KHR_pipeline_executable_properties) */ +#if defined(VK_KHR_push_descriptor) + table->vkCmdPushDescriptorSetKHR = (PFN_vkCmdPushDescriptorSetKHR)load(context, "vkCmdPushDescriptorSetKHR"); +#endif /* defined(VK_KHR_push_descriptor) */ +#if defined(VK_KHR_ray_tracing) + table->vkBindAccelerationStructureMemoryKHR = (PFN_vkBindAccelerationStructureMemoryKHR)load(context, "vkBindAccelerationStructureMemoryKHR"); + table->vkBuildAccelerationStructureKHR = (PFN_vkBuildAccelerationStructureKHR)load(context, "vkBuildAccelerationStructureKHR"); + table->vkCmdBuildAccelerationStructureIndirectKHR = (PFN_vkCmdBuildAccelerationStructureIndirectKHR)load(context, "vkCmdBuildAccelerationStructureIndirectKHR"); + table->vkCmdBuildAccelerationStructureKHR = (PFN_vkCmdBuildAccelerationStructureKHR)load(context, "vkCmdBuildAccelerationStructureKHR"); + table->vkCmdCopyAccelerationStructureKHR = (PFN_vkCmdCopyAccelerationStructureKHR)load(context, "vkCmdCopyAccelerationStructureKHR"); + table->vkCmdCopyAccelerationStructureToMemoryKHR = (PFN_vkCmdCopyAccelerationStructureToMemoryKHR)load(context, "vkCmdCopyAccelerationStructureToMemoryKHR"); + table->vkCmdCopyMemoryToAccelerationStructureKHR = (PFN_vkCmdCopyMemoryToAccelerationStructureKHR)load(context, "vkCmdCopyMemoryToAccelerationStructureKHR"); + table->vkCmdTraceRaysIndirectKHR = (PFN_vkCmdTraceRaysIndirectKHR)load(context, "vkCmdTraceRaysIndirectKHR"); + table->vkCmdTraceRaysKHR = (PFN_vkCmdTraceRaysKHR)load(context, "vkCmdTraceRaysKHR"); + table->vkCmdWriteAccelerationStructuresPropertiesKHR = (PFN_vkCmdWriteAccelerationStructuresPropertiesKHR)load(context, "vkCmdWriteAccelerationStructuresPropertiesKHR"); + table->vkCopyAccelerationStructureKHR = (PFN_vkCopyAccelerationStructureKHR)load(context, "vkCopyAccelerationStructureKHR"); + table->vkCopyAccelerationStructureToMemoryKHR = (PFN_vkCopyAccelerationStructureToMemoryKHR)load(context, "vkCopyAccelerationStructureToMemoryKHR"); + table->vkCopyMemoryToAccelerationStructureKHR = (PFN_vkCopyMemoryToAccelerationStructureKHR)load(context, "vkCopyMemoryToAccelerationStructureKHR"); + table->vkCreateAccelerationStructureKHR = (PFN_vkCreateAccelerationStructureKHR)load(context, "vkCreateAccelerationStructureKHR"); + table->vkCreateRayTracingPipelinesKHR = (PFN_vkCreateRayTracingPipelinesKHR)load(context, "vkCreateRayTracingPipelinesKHR"); + table->vkDestroyAccelerationStructureKHR = (PFN_vkDestroyAccelerationStructureKHR)load(context, "vkDestroyAccelerationStructureKHR"); + table->vkGetAccelerationStructureDeviceAddressKHR = (PFN_vkGetAccelerationStructureDeviceAddressKHR)load(context, "vkGetAccelerationStructureDeviceAddressKHR"); + table->vkGetAccelerationStructureMemoryRequirementsKHR = (PFN_vkGetAccelerationStructureMemoryRequirementsKHR)load(context, "vkGetAccelerationStructureMemoryRequirementsKHR"); + table->vkGetDeviceAccelerationStructureCompatibilityKHR = (PFN_vkGetDeviceAccelerationStructureCompatibilityKHR)load(context, "vkGetDeviceAccelerationStructureCompatibilityKHR"); + table->vkGetRayTracingCaptureReplayShaderGroupHandlesKHR = (PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR)load(context, "vkGetRayTracingCaptureReplayShaderGroupHandlesKHR"); + table->vkGetRayTracingShaderGroupHandlesKHR = (PFN_vkGetRayTracingShaderGroupHandlesKHR)load(context, "vkGetRayTracingShaderGroupHandlesKHR"); + table->vkWriteAccelerationStructuresPropertiesKHR = (PFN_vkWriteAccelerationStructuresPropertiesKHR)load(context, "vkWriteAccelerationStructuresPropertiesKHR"); +#endif /* defined(VK_KHR_ray_tracing) */ +#if defined(VK_KHR_sampler_ycbcr_conversion) + table->vkCreateSamplerYcbcrConversionKHR = (PFN_vkCreateSamplerYcbcrConversionKHR)load(context, "vkCreateSamplerYcbcrConversionKHR"); + table->vkDestroySamplerYcbcrConversionKHR = (PFN_vkDestroySamplerYcbcrConversionKHR)load(context, "vkDestroySamplerYcbcrConversionKHR"); +#endif /* defined(VK_KHR_sampler_ycbcr_conversion) */ +#if defined(VK_KHR_shared_presentable_image) + table->vkGetSwapchainStatusKHR = (PFN_vkGetSwapchainStatusKHR)load(context, "vkGetSwapchainStatusKHR"); +#endif /* defined(VK_KHR_shared_presentable_image) */ +#if defined(VK_KHR_swapchain) + table->vkAcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)load(context, "vkAcquireNextImageKHR"); + table->vkCreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)load(context, "vkCreateSwapchainKHR"); + table->vkDestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)load(context, "vkDestroySwapchainKHR"); + table->vkGetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)load(context, "vkGetSwapchainImagesKHR"); + table->vkQueuePresentKHR = (PFN_vkQueuePresentKHR)load(context, "vkQueuePresentKHR"); +#endif /* defined(VK_KHR_swapchain) */ +#if defined(VK_KHR_timeline_semaphore) + table->vkGetSemaphoreCounterValueKHR = (PFN_vkGetSemaphoreCounterValueKHR)load(context, "vkGetSemaphoreCounterValueKHR"); + table->vkSignalSemaphoreKHR = (PFN_vkSignalSemaphoreKHR)load(context, "vkSignalSemaphoreKHR"); + table->vkWaitSemaphoresKHR = (PFN_vkWaitSemaphoresKHR)load(context, "vkWaitSemaphoresKHR"); +#endif /* defined(VK_KHR_timeline_semaphore) */ +#if defined(VK_NVX_image_view_handle) + table->vkGetImageViewAddressNVX = (PFN_vkGetImageViewAddressNVX)load(context, "vkGetImageViewAddressNVX"); + table->vkGetImageViewHandleNVX = (PFN_vkGetImageViewHandleNVX)load(context, "vkGetImageViewHandleNVX"); +#endif /* defined(VK_NVX_image_view_handle) */ +#if defined(VK_NV_clip_space_w_scaling) + table->vkCmdSetViewportWScalingNV = (PFN_vkCmdSetViewportWScalingNV)load(context, "vkCmdSetViewportWScalingNV"); +#endif /* defined(VK_NV_clip_space_w_scaling) */ +#if defined(VK_NV_device_diagnostic_checkpoints) + table->vkCmdSetCheckpointNV = (PFN_vkCmdSetCheckpointNV)load(context, "vkCmdSetCheckpointNV"); + table->vkGetQueueCheckpointDataNV = (PFN_vkGetQueueCheckpointDataNV)load(context, "vkGetQueueCheckpointDataNV"); +#endif /* defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_NV_device_generated_commands) + table->vkCmdBindPipelineShaderGroupNV = (PFN_vkCmdBindPipelineShaderGroupNV)load(context, "vkCmdBindPipelineShaderGroupNV"); + table->vkCmdExecuteGeneratedCommandsNV = (PFN_vkCmdExecuteGeneratedCommandsNV)load(context, "vkCmdExecuteGeneratedCommandsNV"); + table->vkCmdPreprocessGeneratedCommandsNV = (PFN_vkCmdPreprocessGeneratedCommandsNV)load(context, "vkCmdPreprocessGeneratedCommandsNV"); + table->vkCreateIndirectCommandsLayoutNV = (PFN_vkCreateIndirectCommandsLayoutNV)load(context, "vkCreateIndirectCommandsLayoutNV"); + table->vkDestroyIndirectCommandsLayoutNV = (PFN_vkDestroyIndirectCommandsLayoutNV)load(context, "vkDestroyIndirectCommandsLayoutNV"); + table->vkGetGeneratedCommandsMemoryRequirementsNV = (PFN_vkGetGeneratedCommandsMemoryRequirementsNV)load(context, "vkGetGeneratedCommandsMemoryRequirementsNV"); +#endif /* defined(VK_NV_device_generated_commands) */ +#if defined(VK_NV_external_memory_win32) + table->vkGetMemoryWin32HandleNV = (PFN_vkGetMemoryWin32HandleNV)load(context, "vkGetMemoryWin32HandleNV"); +#endif /* defined(VK_NV_external_memory_win32) */ +#if defined(VK_NV_mesh_shader) + table->vkCmdDrawMeshTasksIndirectCountNV = (PFN_vkCmdDrawMeshTasksIndirectCountNV)load(context, "vkCmdDrawMeshTasksIndirectCountNV"); + table->vkCmdDrawMeshTasksIndirectNV = (PFN_vkCmdDrawMeshTasksIndirectNV)load(context, "vkCmdDrawMeshTasksIndirectNV"); + table->vkCmdDrawMeshTasksNV = (PFN_vkCmdDrawMeshTasksNV)load(context, "vkCmdDrawMeshTasksNV"); +#endif /* defined(VK_NV_mesh_shader) */ +#if defined(VK_NV_ray_tracing) + table->vkBindAccelerationStructureMemoryNV = (PFN_vkBindAccelerationStructureMemoryNV)load(context, "vkBindAccelerationStructureMemoryNV"); + table->vkCmdBuildAccelerationStructureNV = (PFN_vkCmdBuildAccelerationStructureNV)load(context, "vkCmdBuildAccelerationStructureNV"); + table->vkCmdCopyAccelerationStructureNV = (PFN_vkCmdCopyAccelerationStructureNV)load(context, "vkCmdCopyAccelerationStructureNV"); + table->vkCmdTraceRaysNV = (PFN_vkCmdTraceRaysNV)load(context, "vkCmdTraceRaysNV"); + table->vkCmdWriteAccelerationStructuresPropertiesNV = (PFN_vkCmdWriteAccelerationStructuresPropertiesNV)load(context, "vkCmdWriteAccelerationStructuresPropertiesNV"); + table->vkCompileDeferredNV = (PFN_vkCompileDeferredNV)load(context, "vkCompileDeferredNV"); + table->vkCreateAccelerationStructureNV = (PFN_vkCreateAccelerationStructureNV)load(context, "vkCreateAccelerationStructureNV"); + table->vkCreateRayTracingPipelinesNV = (PFN_vkCreateRayTracingPipelinesNV)load(context, "vkCreateRayTracingPipelinesNV"); + table->vkDestroyAccelerationStructureNV = (PFN_vkDestroyAccelerationStructureNV)load(context, "vkDestroyAccelerationStructureNV"); + table->vkGetAccelerationStructureHandleNV = (PFN_vkGetAccelerationStructureHandleNV)load(context, "vkGetAccelerationStructureHandleNV"); + table->vkGetAccelerationStructureMemoryRequirementsNV = (PFN_vkGetAccelerationStructureMemoryRequirementsNV)load(context, "vkGetAccelerationStructureMemoryRequirementsNV"); + table->vkGetRayTracingShaderGroupHandlesNV = (PFN_vkGetRayTracingShaderGroupHandlesNV)load(context, "vkGetRayTracingShaderGroupHandlesNV"); +#endif /* defined(VK_NV_ray_tracing) */ +#if defined(VK_NV_scissor_exclusive) + table->vkCmdSetExclusiveScissorNV = (PFN_vkCmdSetExclusiveScissorNV)load(context, "vkCmdSetExclusiveScissorNV"); +#endif /* defined(VK_NV_scissor_exclusive) */ +#if defined(VK_NV_shading_rate_image) + table->vkCmdBindShadingRateImageNV = (PFN_vkCmdBindShadingRateImageNV)load(context, "vkCmdBindShadingRateImageNV"); + table->vkCmdSetCoarseSampleOrderNV = (PFN_vkCmdSetCoarseSampleOrderNV)load(context, "vkCmdSetCoarseSampleOrderNV"); + table->vkCmdSetViewportShadingRatePaletteNV = (PFN_vkCmdSetViewportShadingRatePaletteNV)load(context, "vkCmdSetViewportShadingRatePaletteNV"); +#endif /* defined(VK_NV_shading_rate_image) */ +#if (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) + table->vkGetDeviceGroupSurfacePresentModes2EXT = (PFN_vkGetDeviceGroupSurfacePresentModes2EXT)load(context, "vkGetDeviceGroupSurfacePresentModes2EXT"); +#endif /* (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) + table->vkCmdPushDescriptorSetWithTemplateKHR = (PFN_vkCmdPushDescriptorSetWithTemplateKHR)load(context, "vkCmdPushDescriptorSetWithTemplateKHR"); +#endif /* (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) + table->vkGetDeviceGroupPresentCapabilitiesKHR = (PFN_vkGetDeviceGroupPresentCapabilitiesKHR)load(context, "vkGetDeviceGroupPresentCapabilitiesKHR"); + table->vkGetDeviceGroupSurfacePresentModesKHR = (PFN_vkGetDeviceGroupSurfacePresentModesKHR)load(context, "vkGetDeviceGroupSurfacePresentModesKHR"); +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) + table->vkAcquireNextImage2KHR = (PFN_vkAcquireNextImage2KHR)load(context, "vkAcquireNextImage2KHR"); +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ + /* VOLK_GENERATE_LOAD_DEVICE_TABLE */ +} + +#ifdef __GNUC__ +#ifdef VOLK_DEFAULT_VISIBILITY +# pragma GCC visibility push(default) +#else +# pragma GCC visibility push(hidden) +#endif +#endif + +/* VOLK_GENERATE_PROTOTYPES_C */ +#if defined(VK_VERSION_1_0) +PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; +PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets; +PFN_vkAllocateMemory vkAllocateMemory; +PFN_vkBeginCommandBuffer vkBeginCommandBuffer; +PFN_vkBindBufferMemory vkBindBufferMemory; +PFN_vkBindImageMemory vkBindImageMemory; +PFN_vkCmdBeginQuery vkCmdBeginQuery; +PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; +PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets; +PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; +PFN_vkCmdBindPipeline vkCmdBindPipeline; +PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers; +PFN_vkCmdBlitImage vkCmdBlitImage; +PFN_vkCmdClearAttachments vkCmdClearAttachments; +PFN_vkCmdClearColorImage vkCmdClearColorImage; +PFN_vkCmdClearDepthStencilImage vkCmdClearDepthStencilImage; +PFN_vkCmdCopyBuffer vkCmdCopyBuffer; +PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage; +PFN_vkCmdCopyImage vkCmdCopyImage; +PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer; +PFN_vkCmdCopyQueryPoolResults vkCmdCopyQueryPoolResults; +PFN_vkCmdDispatch vkCmdDispatch; +PFN_vkCmdDispatchIndirect vkCmdDispatchIndirect; +PFN_vkCmdDraw vkCmdDraw; +PFN_vkCmdDrawIndexed vkCmdDrawIndexed; +PFN_vkCmdDrawIndexedIndirect vkCmdDrawIndexedIndirect; +PFN_vkCmdDrawIndirect vkCmdDrawIndirect; +PFN_vkCmdEndQuery vkCmdEndQuery; +PFN_vkCmdEndRenderPass vkCmdEndRenderPass; +PFN_vkCmdExecuteCommands vkCmdExecuteCommands; +PFN_vkCmdFillBuffer vkCmdFillBuffer; +PFN_vkCmdNextSubpass vkCmdNextSubpass; +PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; +PFN_vkCmdPushConstants vkCmdPushConstants; +PFN_vkCmdResetEvent vkCmdResetEvent; +PFN_vkCmdResetQueryPool vkCmdResetQueryPool; +PFN_vkCmdResolveImage vkCmdResolveImage; +PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants; +PFN_vkCmdSetDepthBias vkCmdSetDepthBias; +PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds; +PFN_vkCmdSetEvent vkCmdSetEvent; +PFN_vkCmdSetLineWidth vkCmdSetLineWidth; +PFN_vkCmdSetScissor vkCmdSetScissor; +PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask; +PFN_vkCmdSetStencilReference vkCmdSetStencilReference; +PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask; +PFN_vkCmdSetViewport vkCmdSetViewport; +PFN_vkCmdUpdateBuffer vkCmdUpdateBuffer; +PFN_vkCmdWaitEvents vkCmdWaitEvents; +PFN_vkCmdWriteTimestamp vkCmdWriteTimestamp; +PFN_vkCreateBuffer vkCreateBuffer; +PFN_vkCreateBufferView vkCreateBufferView; +PFN_vkCreateCommandPool vkCreateCommandPool; +PFN_vkCreateComputePipelines vkCreateComputePipelines; +PFN_vkCreateDescriptorPool vkCreateDescriptorPool; +PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout; +PFN_vkCreateDevice vkCreateDevice; +PFN_vkCreateEvent vkCreateEvent; +PFN_vkCreateFence vkCreateFence; +PFN_vkCreateFramebuffer vkCreateFramebuffer; +PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines; +PFN_vkCreateImage vkCreateImage; +PFN_vkCreateImageView vkCreateImageView; +PFN_vkCreateInstance vkCreateInstance; +PFN_vkCreatePipelineCache vkCreatePipelineCache; +PFN_vkCreatePipelineLayout vkCreatePipelineLayout; +PFN_vkCreateQueryPool vkCreateQueryPool; +PFN_vkCreateRenderPass vkCreateRenderPass; +PFN_vkCreateSampler vkCreateSampler; +PFN_vkCreateSemaphore vkCreateSemaphore; +PFN_vkCreateShaderModule vkCreateShaderModule; +PFN_vkDestroyBuffer vkDestroyBuffer; +PFN_vkDestroyBufferView vkDestroyBufferView; +PFN_vkDestroyCommandPool vkDestroyCommandPool; +PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool; +PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout; +PFN_vkDestroyDevice vkDestroyDevice; +PFN_vkDestroyEvent vkDestroyEvent; +PFN_vkDestroyFence vkDestroyFence; +PFN_vkDestroyFramebuffer vkDestroyFramebuffer; +PFN_vkDestroyImage vkDestroyImage; +PFN_vkDestroyImageView vkDestroyImageView; +PFN_vkDestroyInstance vkDestroyInstance; +PFN_vkDestroyPipeline vkDestroyPipeline; +PFN_vkDestroyPipelineCache vkDestroyPipelineCache; +PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout; +PFN_vkDestroyQueryPool vkDestroyQueryPool; +PFN_vkDestroyRenderPass vkDestroyRenderPass; +PFN_vkDestroySampler vkDestroySampler; +PFN_vkDestroySemaphore vkDestroySemaphore; +PFN_vkDestroyShaderModule vkDestroyShaderModule; +PFN_vkDeviceWaitIdle vkDeviceWaitIdle; +PFN_vkEndCommandBuffer vkEndCommandBuffer; +PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties; +PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties; +PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties; +PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties; +PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices; +PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges; +PFN_vkFreeCommandBuffers vkFreeCommandBuffers; +PFN_vkFreeDescriptorSets vkFreeDescriptorSets; +PFN_vkFreeMemory vkFreeMemory; +PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; +PFN_vkGetDeviceMemoryCommitment vkGetDeviceMemoryCommitment; +PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; +PFN_vkGetDeviceQueue vkGetDeviceQueue; +PFN_vkGetEventStatus vkGetEventStatus; +PFN_vkGetFenceStatus vkGetFenceStatus; +PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; +PFN_vkGetImageSparseMemoryRequirements vkGetImageSparseMemoryRequirements; +PFN_vkGetImageSubresourceLayout vkGetImageSubresourceLayout; +PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; +PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures; +PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties; +PFN_vkGetPhysicalDeviceImageFormatProperties vkGetPhysicalDeviceImageFormatProperties; +PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; +PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; +PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties; +PFN_vkGetPhysicalDeviceSparseImageFormatProperties vkGetPhysicalDeviceSparseImageFormatProperties; +PFN_vkGetPipelineCacheData vkGetPipelineCacheData; +PFN_vkGetQueryPoolResults vkGetQueryPoolResults; +PFN_vkGetRenderAreaGranularity vkGetRenderAreaGranularity; +PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges; +PFN_vkMapMemory vkMapMemory; +PFN_vkMergePipelineCaches vkMergePipelineCaches; +PFN_vkQueueBindSparse vkQueueBindSparse; +PFN_vkQueueSubmit vkQueueSubmit; +PFN_vkQueueWaitIdle vkQueueWaitIdle; +PFN_vkResetCommandBuffer vkResetCommandBuffer; +PFN_vkResetCommandPool vkResetCommandPool; +PFN_vkResetDescriptorPool vkResetDescriptorPool; +PFN_vkResetEvent vkResetEvent; +PFN_vkResetFences vkResetFences; +PFN_vkSetEvent vkSetEvent; +PFN_vkUnmapMemory vkUnmapMemory; +PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; +PFN_vkWaitForFences vkWaitForFences; +#endif /* defined(VK_VERSION_1_0) */ +#if defined(VK_VERSION_1_1) +PFN_vkBindBufferMemory2 vkBindBufferMemory2; +PFN_vkBindImageMemory2 vkBindImageMemory2; +PFN_vkCmdDispatchBase vkCmdDispatchBase; +PFN_vkCmdSetDeviceMask vkCmdSetDeviceMask; +PFN_vkCreateDescriptorUpdateTemplate vkCreateDescriptorUpdateTemplate; +PFN_vkCreateSamplerYcbcrConversion vkCreateSamplerYcbcrConversion; +PFN_vkDestroyDescriptorUpdateTemplate vkDestroyDescriptorUpdateTemplate; +PFN_vkDestroySamplerYcbcrConversion vkDestroySamplerYcbcrConversion; +PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion; +PFN_vkEnumeratePhysicalDeviceGroups vkEnumeratePhysicalDeviceGroups; +PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2; +PFN_vkGetDescriptorSetLayoutSupport vkGetDescriptorSetLayoutSupport; +PFN_vkGetDeviceGroupPeerMemoryFeatures vkGetDeviceGroupPeerMemoryFeatures; +PFN_vkGetDeviceQueue2 vkGetDeviceQueue2; +PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2; +PFN_vkGetImageSparseMemoryRequirements2 vkGetImageSparseMemoryRequirements2; +PFN_vkGetPhysicalDeviceExternalBufferProperties vkGetPhysicalDeviceExternalBufferProperties; +PFN_vkGetPhysicalDeviceExternalFenceProperties vkGetPhysicalDeviceExternalFenceProperties; +PFN_vkGetPhysicalDeviceExternalSemaphoreProperties vkGetPhysicalDeviceExternalSemaphoreProperties; +PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2; +PFN_vkGetPhysicalDeviceFormatProperties2 vkGetPhysicalDeviceFormatProperties2; +PFN_vkGetPhysicalDeviceImageFormatProperties2 vkGetPhysicalDeviceImageFormatProperties2; +PFN_vkGetPhysicalDeviceMemoryProperties2 vkGetPhysicalDeviceMemoryProperties2; +PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2; +PFN_vkGetPhysicalDeviceQueueFamilyProperties2 vkGetPhysicalDeviceQueueFamilyProperties2; +PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 vkGetPhysicalDeviceSparseImageFormatProperties2; +PFN_vkTrimCommandPool vkTrimCommandPool; +PFN_vkUpdateDescriptorSetWithTemplate vkUpdateDescriptorSetWithTemplate; +#endif /* defined(VK_VERSION_1_1) */ +#if defined(VK_VERSION_1_2) +PFN_vkCmdBeginRenderPass2 vkCmdBeginRenderPass2; +PFN_vkCmdDrawIndexedIndirectCount vkCmdDrawIndexedIndirectCount; +PFN_vkCmdDrawIndirectCount vkCmdDrawIndirectCount; +PFN_vkCmdEndRenderPass2 vkCmdEndRenderPass2; +PFN_vkCmdNextSubpass2 vkCmdNextSubpass2; +PFN_vkCreateRenderPass2 vkCreateRenderPass2; +PFN_vkGetBufferDeviceAddress vkGetBufferDeviceAddress; +PFN_vkGetBufferOpaqueCaptureAddress vkGetBufferOpaqueCaptureAddress; +PFN_vkGetDeviceMemoryOpaqueCaptureAddress vkGetDeviceMemoryOpaqueCaptureAddress; +PFN_vkGetSemaphoreCounterValue vkGetSemaphoreCounterValue; +PFN_vkResetQueryPool vkResetQueryPool; +PFN_vkSignalSemaphore vkSignalSemaphore; +PFN_vkWaitSemaphores vkWaitSemaphores; +#endif /* defined(VK_VERSION_1_2) */ +#if defined(VK_AMD_buffer_marker) +PFN_vkCmdWriteBufferMarkerAMD vkCmdWriteBufferMarkerAMD; +#endif /* defined(VK_AMD_buffer_marker) */ +#if defined(VK_AMD_display_native_hdr) +PFN_vkSetLocalDimmingAMD vkSetLocalDimmingAMD; +#endif /* defined(VK_AMD_display_native_hdr) */ +#if defined(VK_AMD_draw_indirect_count) +PFN_vkCmdDrawIndexedIndirectCountAMD vkCmdDrawIndexedIndirectCountAMD; +PFN_vkCmdDrawIndirectCountAMD vkCmdDrawIndirectCountAMD; +#endif /* defined(VK_AMD_draw_indirect_count) */ +#if defined(VK_AMD_shader_info) +PFN_vkGetShaderInfoAMD vkGetShaderInfoAMD; +#endif /* defined(VK_AMD_shader_info) */ +#if defined(VK_ANDROID_external_memory_android_hardware_buffer) +PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID; +PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID; +#endif /* defined(VK_ANDROID_external_memory_android_hardware_buffer) */ +#if defined(VK_EXT_acquire_xlib_display) +PFN_vkAcquireXlibDisplayEXT vkAcquireXlibDisplayEXT; +PFN_vkGetRandROutputDisplayEXT vkGetRandROutputDisplayEXT; +#endif /* defined(VK_EXT_acquire_xlib_display) */ +#if defined(VK_EXT_buffer_device_address) +PFN_vkGetBufferDeviceAddressEXT vkGetBufferDeviceAddressEXT; +#endif /* defined(VK_EXT_buffer_device_address) */ +#if defined(VK_EXT_calibrated_timestamps) +PFN_vkGetCalibratedTimestampsEXT vkGetCalibratedTimestampsEXT; +PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT vkGetPhysicalDeviceCalibrateableTimeDomainsEXT; +#endif /* defined(VK_EXT_calibrated_timestamps) */ +#if defined(VK_EXT_conditional_rendering) +PFN_vkCmdBeginConditionalRenderingEXT vkCmdBeginConditionalRenderingEXT; +PFN_vkCmdEndConditionalRenderingEXT vkCmdEndConditionalRenderingEXT; +#endif /* defined(VK_EXT_conditional_rendering) */ +#if defined(VK_EXT_debug_marker) +PFN_vkCmdDebugMarkerBeginEXT vkCmdDebugMarkerBeginEXT; +PFN_vkCmdDebugMarkerEndEXT vkCmdDebugMarkerEndEXT; +PFN_vkCmdDebugMarkerInsertEXT vkCmdDebugMarkerInsertEXT; +PFN_vkDebugMarkerSetObjectNameEXT vkDebugMarkerSetObjectNameEXT; +PFN_vkDebugMarkerSetObjectTagEXT vkDebugMarkerSetObjectTagEXT; +#endif /* defined(VK_EXT_debug_marker) */ +#if defined(VK_EXT_debug_report) +PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT; +PFN_vkDebugReportMessageEXT vkDebugReportMessageEXT; +PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; +#endif /* defined(VK_EXT_debug_report) */ +#if defined(VK_EXT_debug_utils) +PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT; +PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT; +PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT; +PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT; +PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT; +PFN_vkQueueBeginDebugUtilsLabelEXT vkQueueBeginDebugUtilsLabelEXT; +PFN_vkQueueEndDebugUtilsLabelEXT vkQueueEndDebugUtilsLabelEXT; +PFN_vkQueueInsertDebugUtilsLabelEXT vkQueueInsertDebugUtilsLabelEXT; +PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT; +PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT; +PFN_vkSubmitDebugUtilsMessageEXT vkSubmitDebugUtilsMessageEXT; +#endif /* defined(VK_EXT_debug_utils) */ +#if defined(VK_EXT_direct_mode_display) +PFN_vkReleaseDisplayEXT vkReleaseDisplayEXT; +#endif /* defined(VK_EXT_direct_mode_display) */ +#if defined(VK_EXT_directfb_surface) +PFN_vkCreateDirectFBSurfaceEXT vkCreateDirectFBSurfaceEXT; +PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT vkGetPhysicalDeviceDirectFBPresentationSupportEXT; +#endif /* defined(VK_EXT_directfb_surface) */ +#if defined(VK_EXT_discard_rectangles) +PFN_vkCmdSetDiscardRectangleEXT vkCmdSetDiscardRectangleEXT; +#endif /* defined(VK_EXT_discard_rectangles) */ +#if defined(VK_EXT_display_control) +PFN_vkDisplayPowerControlEXT vkDisplayPowerControlEXT; +PFN_vkGetSwapchainCounterEXT vkGetSwapchainCounterEXT; +PFN_vkRegisterDeviceEventEXT vkRegisterDeviceEventEXT; +PFN_vkRegisterDisplayEventEXT vkRegisterDisplayEventEXT; +#endif /* defined(VK_EXT_display_control) */ +#if defined(VK_EXT_display_surface_counter) +PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT vkGetPhysicalDeviceSurfaceCapabilities2EXT; +#endif /* defined(VK_EXT_display_surface_counter) */ +#if defined(VK_EXT_extended_dynamic_state) +PFN_vkCmdBindVertexBuffers2EXT vkCmdBindVertexBuffers2EXT; +PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT; +PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT; +PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT; +PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT; +PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT; +PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT; +PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT; +PFN_vkCmdSetScissorWithCountEXT vkCmdSetScissorWithCountEXT; +PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT; +PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT; +PFN_vkCmdSetViewportWithCountEXT vkCmdSetViewportWithCountEXT; +#endif /* defined(VK_EXT_extended_dynamic_state) */ +#if defined(VK_EXT_external_memory_host) +PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT; +#endif /* defined(VK_EXT_external_memory_host) */ +#if defined(VK_EXT_full_screen_exclusive) +PFN_vkAcquireFullScreenExclusiveModeEXT vkAcquireFullScreenExclusiveModeEXT; +PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT vkGetPhysicalDeviceSurfacePresentModes2EXT; +PFN_vkReleaseFullScreenExclusiveModeEXT vkReleaseFullScreenExclusiveModeEXT; +#endif /* defined(VK_EXT_full_screen_exclusive) */ +#if defined(VK_EXT_hdr_metadata) +PFN_vkSetHdrMetadataEXT vkSetHdrMetadataEXT; +#endif /* defined(VK_EXT_hdr_metadata) */ +#if defined(VK_EXT_headless_surface) +PFN_vkCreateHeadlessSurfaceEXT vkCreateHeadlessSurfaceEXT; +#endif /* defined(VK_EXT_headless_surface) */ +#if defined(VK_EXT_host_query_reset) +PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT; +#endif /* defined(VK_EXT_host_query_reset) */ +#if defined(VK_EXT_image_drm_format_modifier) +PFN_vkGetImageDrmFormatModifierPropertiesEXT vkGetImageDrmFormatModifierPropertiesEXT; +#endif /* defined(VK_EXT_image_drm_format_modifier) */ +#if defined(VK_EXT_line_rasterization) +PFN_vkCmdSetLineStippleEXT vkCmdSetLineStippleEXT; +#endif /* defined(VK_EXT_line_rasterization) */ +#if defined(VK_EXT_metal_surface) +PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT; +#endif /* defined(VK_EXT_metal_surface) */ +#if defined(VK_EXT_private_data) +PFN_vkCreatePrivateDataSlotEXT vkCreatePrivateDataSlotEXT; +PFN_vkDestroyPrivateDataSlotEXT vkDestroyPrivateDataSlotEXT; +PFN_vkGetPrivateDataEXT vkGetPrivateDataEXT; +PFN_vkSetPrivateDataEXT vkSetPrivateDataEXT; +#endif /* defined(VK_EXT_private_data) */ +#if defined(VK_EXT_sample_locations) +PFN_vkCmdSetSampleLocationsEXT vkCmdSetSampleLocationsEXT; +PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT vkGetPhysicalDeviceMultisamplePropertiesEXT; +#endif /* defined(VK_EXT_sample_locations) */ +#if defined(VK_EXT_tooling_info) +PFN_vkGetPhysicalDeviceToolPropertiesEXT vkGetPhysicalDeviceToolPropertiesEXT; +#endif /* defined(VK_EXT_tooling_info) */ +#if defined(VK_EXT_transform_feedback) +PFN_vkCmdBeginQueryIndexedEXT vkCmdBeginQueryIndexedEXT; +PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT; +PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT; +PFN_vkCmdDrawIndirectByteCountEXT vkCmdDrawIndirectByteCountEXT; +PFN_vkCmdEndQueryIndexedEXT vkCmdEndQueryIndexedEXT; +PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT; +#endif /* defined(VK_EXT_transform_feedback) */ +#if defined(VK_EXT_validation_cache) +PFN_vkCreateValidationCacheEXT vkCreateValidationCacheEXT; +PFN_vkDestroyValidationCacheEXT vkDestroyValidationCacheEXT; +PFN_vkGetValidationCacheDataEXT vkGetValidationCacheDataEXT; +PFN_vkMergeValidationCachesEXT vkMergeValidationCachesEXT; +#endif /* defined(VK_EXT_validation_cache) */ +#if defined(VK_FUCHSIA_imagepipe_surface) +PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA; +#endif /* defined(VK_FUCHSIA_imagepipe_surface) */ +#if defined(VK_GGP_stream_descriptor_surface) +PFN_vkCreateStreamDescriptorSurfaceGGP vkCreateStreamDescriptorSurfaceGGP; +#endif /* defined(VK_GGP_stream_descriptor_surface) */ +#if defined(VK_GOOGLE_display_timing) +PFN_vkGetPastPresentationTimingGOOGLE vkGetPastPresentationTimingGOOGLE; +PFN_vkGetRefreshCycleDurationGOOGLE vkGetRefreshCycleDurationGOOGLE; +#endif /* defined(VK_GOOGLE_display_timing) */ +#if defined(VK_INTEL_performance_query) +PFN_vkAcquirePerformanceConfigurationINTEL vkAcquirePerformanceConfigurationINTEL; +PFN_vkCmdSetPerformanceMarkerINTEL vkCmdSetPerformanceMarkerINTEL; +PFN_vkCmdSetPerformanceOverrideINTEL vkCmdSetPerformanceOverrideINTEL; +PFN_vkCmdSetPerformanceStreamMarkerINTEL vkCmdSetPerformanceStreamMarkerINTEL; +PFN_vkGetPerformanceParameterINTEL vkGetPerformanceParameterINTEL; +PFN_vkInitializePerformanceApiINTEL vkInitializePerformanceApiINTEL; +PFN_vkQueueSetPerformanceConfigurationINTEL vkQueueSetPerformanceConfigurationINTEL; +PFN_vkReleasePerformanceConfigurationINTEL vkReleasePerformanceConfigurationINTEL; +PFN_vkUninitializePerformanceApiINTEL vkUninitializePerformanceApiINTEL; +#endif /* defined(VK_INTEL_performance_query) */ +#if defined(VK_KHR_android_surface) +PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; +#endif /* defined(VK_KHR_android_surface) */ +#if defined(VK_KHR_bind_memory2) +PFN_vkBindBufferMemory2KHR vkBindBufferMemory2KHR; +PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR; +#endif /* defined(VK_KHR_bind_memory2) */ +#if defined(VK_KHR_buffer_device_address) +PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR; +PFN_vkGetBufferOpaqueCaptureAddressKHR vkGetBufferOpaqueCaptureAddressKHR; +PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR vkGetDeviceMemoryOpaqueCaptureAddressKHR; +#endif /* defined(VK_KHR_buffer_device_address) */ +#if defined(VK_KHR_create_renderpass2) +PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR; +PFN_vkCmdEndRenderPass2KHR vkCmdEndRenderPass2KHR; +PFN_vkCmdNextSubpass2KHR vkCmdNextSubpass2KHR; +PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; +#endif /* defined(VK_KHR_create_renderpass2) */ +#if defined(VK_KHR_deferred_host_operations) +PFN_vkCreateDeferredOperationKHR vkCreateDeferredOperationKHR; +PFN_vkDeferredOperationJoinKHR vkDeferredOperationJoinKHR; +PFN_vkDestroyDeferredOperationKHR vkDestroyDeferredOperationKHR; +PFN_vkGetDeferredOperationMaxConcurrencyKHR vkGetDeferredOperationMaxConcurrencyKHR; +PFN_vkGetDeferredOperationResultKHR vkGetDeferredOperationResultKHR; +#endif /* defined(VK_KHR_deferred_host_operations) */ +#if defined(VK_KHR_descriptor_update_template) +PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; +PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; +PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; +#endif /* defined(VK_KHR_descriptor_update_template) */ +#if defined(VK_KHR_device_group) +PFN_vkCmdDispatchBaseKHR vkCmdDispatchBaseKHR; +PFN_vkCmdSetDeviceMaskKHR vkCmdSetDeviceMaskKHR; +PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR vkGetDeviceGroupPeerMemoryFeaturesKHR; +#endif /* defined(VK_KHR_device_group) */ +#if defined(VK_KHR_device_group_creation) +PFN_vkEnumeratePhysicalDeviceGroupsKHR vkEnumeratePhysicalDeviceGroupsKHR; +#endif /* defined(VK_KHR_device_group_creation) */ +#if defined(VK_KHR_display) +PFN_vkCreateDisplayModeKHR vkCreateDisplayModeKHR; +PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR; +PFN_vkGetDisplayModePropertiesKHR vkGetDisplayModePropertiesKHR; +PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR; +PFN_vkGetDisplayPlaneSupportedDisplaysKHR vkGetDisplayPlaneSupportedDisplaysKHR; +PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vkGetPhysicalDeviceDisplayPlanePropertiesKHR; +PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vkGetPhysicalDeviceDisplayPropertiesKHR; +#endif /* defined(VK_KHR_display) */ +#if defined(VK_KHR_display_swapchain) +PFN_vkCreateSharedSwapchainsKHR vkCreateSharedSwapchainsKHR; +#endif /* defined(VK_KHR_display_swapchain) */ +#if defined(VK_KHR_draw_indirect_count) +PFN_vkCmdDrawIndexedIndirectCountKHR vkCmdDrawIndexedIndirectCountKHR; +PFN_vkCmdDrawIndirectCountKHR vkCmdDrawIndirectCountKHR; +#endif /* defined(VK_KHR_draw_indirect_count) */ +#if defined(VK_KHR_external_fence_capabilities) +PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR vkGetPhysicalDeviceExternalFencePropertiesKHR; +#endif /* defined(VK_KHR_external_fence_capabilities) */ +#if defined(VK_KHR_external_fence_fd) +PFN_vkGetFenceFdKHR vkGetFenceFdKHR; +PFN_vkImportFenceFdKHR vkImportFenceFdKHR; +#endif /* defined(VK_KHR_external_fence_fd) */ +#if defined(VK_KHR_external_fence_win32) +PFN_vkGetFenceWin32HandleKHR vkGetFenceWin32HandleKHR; +PFN_vkImportFenceWin32HandleKHR vkImportFenceWin32HandleKHR; +#endif /* defined(VK_KHR_external_fence_win32) */ +#if defined(VK_KHR_external_memory_capabilities) +PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR vkGetPhysicalDeviceExternalBufferPropertiesKHR; +#endif /* defined(VK_KHR_external_memory_capabilities) */ +#if defined(VK_KHR_external_memory_fd) +PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR; +PFN_vkGetMemoryFdPropertiesKHR vkGetMemoryFdPropertiesKHR; +#endif /* defined(VK_KHR_external_memory_fd) */ +#if defined(VK_KHR_external_memory_win32) +PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32HandleKHR; +PFN_vkGetMemoryWin32HandlePropertiesKHR vkGetMemoryWin32HandlePropertiesKHR; +#endif /* defined(VK_KHR_external_memory_win32) */ +#if defined(VK_KHR_external_semaphore_capabilities) +PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR vkGetPhysicalDeviceExternalSemaphorePropertiesKHR; +#endif /* defined(VK_KHR_external_semaphore_capabilities) */ +#if defined(VK_KHR_external_semaphore_fd) +PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR; +PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR; +#endif /* defined(VK_KHR_external_semaphore_fd) */ +#if defined(VK_KHR_external_semaphore_win32) +PFN_vkGetSemaphoreWin32HandleKHR vkGetSemaphoreWin32HandleKHR; +PFN_vkImportSemaphoreWin32HandleKHR vkImportSemaphoreWin32HandleKHR; +#endif /* defined(VK_KHR_external_semaphore_win32) */ +#if defined(VK_KHR_get_display_properties2) +PFN_vkGetDisplayModeProperties2KHR vkGetDisplayModeProperties2KHR; +PFN_vkGetDisplayPlaneCapabilities2KHR vkGetDisplayPlaneCapabilities2KHR; +PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR vkGetPhysicalDeviceDisplayPlaneProperties2KHR; +PFN_vkGetPhysicalDeviceDisplayProperties2KHR vkGetPhysicalDeviceDisplayProperties2KHR; +#endif /* defined(VK_KHR_get_display_properties2) */ +#if defined(VK_KHR_get_memory_requirements2) +PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; +PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; +PFN_vkGetImageSparseMemoryRequirements2KHR vkGetImageSparseMemoryRequirements2KHR; +#endif /* defined(VK_KHR_get_memory_requirements2) */ +#if defined(VK_KHR_get_physical_device_properties2) +PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; +PFN_vkGetPhysicalDeviceFormatProperties2KHR vkGetPhysicalDeviceFormatProperties2KHR; +PFN_vkGetPhysicalDeviceImageFormatProperties2KHR vkGetPhysicalDeviceImageFormatProperties2KHR; +PFN_vkGetPhysicalDeviceMemoryProperties2KHR vkGetPhysicalDeviceMemoryProperties2KHR; +PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; +PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR vkGetPhysicalDeviceQueueFamilyProperties2KHR; +PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR vkGetPhysicalDeviceSparseImageFormatProperties2KHR; +#endif /* defined(VK_KHR_get_physical_device_properties2) */ +#if defined(VK_KHR_get_surface_capabilities2) +PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR; +PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR; +#endif /* defined(VK_KHR_get_surface_capabilities2) */ +#if defined(VK_KHR_maintenance1) +PFN_vkTrimCommandPoolKHR vkTrimCommandPoolKHR; +#endif /* defined(VK_KHR_maintenance1) */ +#if defined(VK_KHR_maintenance3) +PFN_vkGetDescriptorSetLayoutSupportKHR vkGetDescriptorSetLayoutSupportKHR; +#endif /* defined(VK_KHR_maintenance3) */ +#if defined(VK_KHR_performance_query) +PFN_vkAcquireProfilingLockKHR vkAcquireProfilingLockKHR; +PFN_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR; +PFN_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR; +PFN_vkReleaseProfilingLockKHR vkReleaseProfilingLockKHR; +#endif /* defined(VK_KHR_performance_query) */ +#if defined(VK_KHR_pipeline_executable_properties) +PFN_vkGetPipelineExecutableInternalRepresentationsKHR vkGetPipelineExecutableInternalRepresentationsKHR; +PFN_vkGetPipelineExecutablePropertiesKHR vkGetPipelineExecutablePropertiesKHR; +PFN_vkGetPipelineExecutableStatisticsKHR vkGetPipelineExecutableStatisticsKHR; +#endif /* defined(VK_KHR_pipeline_executable_properties) */ +#if defined(VK_KHR_push_descriptor) +PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR; +#endif /* defined(VK_KHR_push_descriptor) */ +#if defined(VK_KHR_ray_tracing) +PFN_vkBindAccelerationStructureMemoryKHR vkBindAccelerationStructureMemoryKHR; +PFN_vkBuildAccelerationStructureKHR vkBuildAccelerationStructureKHR; +PFN_vkCmdBuildAccelerationStructureIndirectKHR vkCmdBuildAccelerationStructureIndirectKHR; +PFN_vkCmdBuildAccelerationStructureKHR vkCmdBuildAccelerationStructureKHR; +PFN_vkCmdCopyAccelerationStructureKHR vkCmdCopyAccelerationStructureKHR; +PFN_vkCmdCopyAccelerationStructureToMemoryKHR vkCmdCopyAccelerationStructureToMemoryKHR; +PFN_vkCmdCopyMemoryToAccelerationStructureKHR vkCmdCopyMemoryToAccelerationStructureKHR; +PFN_vkCmdTraceRaysIndirectKHR vkCmdTraceRaysIndirectKHR; +PFN_vkCmdTraceRaysKHR vkCmdTraceRaysKHR; +PFN_vkCmdWriteAccelerationStructuresPropertiesKHR vkCmdWriteAccelerationStructuresPropertiesKHR; +PFN_vkCopyAccelerationStructureKHR vkCopyAccelerationStructureKHR; +PFN_vkCopyAccelerationStructureToMemoryKHR vkCopyAccelerationStructureToMemoryKHR; +PFN_vkCopyMemoryToAccelerationStructureKHR vkCopyMemoryToAccelerationStructureKHR; +PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructureKHR; +PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelinesKHR; +PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructureKHR; +PFN_vkGetAccelerationStructureDeviceAddressKHR vkGetAccelerationStructureDeviceAddressKHR; +PFN_vkGetAccelerationStructureMemoryRequirementsKHR vkGetAccelerationStructureMemoryRequirementsKHR; +PFN_vkGetDeviceAccelerationStructureCompatibilityKHR vkGetDeviceAccelerationStructureCompatibilityKHR; +PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR vkGetRayTracingCaptureReplayShaderGroupHandlesKHR; +PFN_vkGetRayTracingShaderGroupHandlesKHR vkGetRayTracingShaderGroupHandlesKHR; +PFN_vkWriteAccelerationStructuresPropertiesKHR vkWriteAccelerationStructuresPropertiesKHR; +#endif /* defined(VK_KHR_ray_tracing) */ +#if defined(VK_KHR_sampler_ycbcr_conversion) +PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR; +PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR; +#endif /* defined(VK_KHR_sampler_ycbcr_conversion) */ +#if defined(VK_KHR_shared_presentable_image) +PFN_vkGetSwapchainStatusKHR vkGetSwapchainStatusKHR; +#endif /* defined(VK_KHR_shared_presentable_image) */ +#if defined(VK_KHR_surface) +PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; +PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; +PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; +PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; +PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; +#endif /* defined(VK_KHR_surface) */ +#if defined(VK_KHR_swapchain) +PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; +PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; +PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; +PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; +PFN_vkQueuePresentKHR vkQueuePresentKHR; +#endif /* defined(VK_KHR_swapchain) */ +#if defined(VK_KHR_timeline_semaphore) +PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR; +PFN_vkSignalSemaphoreKHR vkSignalSemaphoreKHR; +PFN_vkWaitSemaphoresKHR vkWaitSemaphoresKHR; +#endif /* defined(VK_KHR_timeline_semaphore) */ +#if defined(VK_KHR_wayland_surface) +PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR; +PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR; +#endif /* defined(VK_KHR_wayland_surface) */ +#if defined(VK_KHR_win32_surface) +PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR; +PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR; +#endif /* defined(VK_KHR_win32_surface) */ +#if defined(VK_KHR_xcb_surface) +PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR; +PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR; +#endif /* defined(VK_KHR_xcb_surface) */ +#if defined(VK_KHR_xlib_surface) +PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR; +PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR; +#endif /* defined(VK_KHR_xlib_surface) */ +#if defined(VK_MVK_ios_surface) +PFN_vkCreateIOSSurfaceMVK vkCreateIOSSurfaceMVK; +#endif /* defined(VK_MVK_ios_surface) */ +#if defined(VK_MVK_macos_surface) +PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK; +#endif /* defined(VK_MVK_macos_surface) */ +#if defined(VK_NN_vi_surface) +PFN_vkCreateViSurfaceNN vkCreateViSurfaceNN; +#endif /* defined(VK_NN_vi_surface) */ +#if defined(VK_NVX_image_view_handle) +PFN_vkGetImageViewAddressNVX vkGetImageViewAddressNVX; +PFN_vkGetImageViewHandleNVX vkGetImageViewHandleNVX; +#endif /* defined(VK_NVX_image_view_handle) */ +#if defined(VK_NV_clip_space_w_scaling) +PFN_vkCmdSetViewportWScalingNV vkCmdSetViewportWScalingNV; +#endif /* defined(VK_NV_clip_space_w_scaling) */ +#if defined(VK_NV_cooperative_matrix) +PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV vkGetPhysicalDeviceCooperativeMatrixPropertiesNV; +#endif /* defined(VK_NV_cooperative_matrix) */ +#if defined(VK_NV_coverage_reduction_mode) +PFN_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV; +#endif /* defined(VK_NV_coverage_reduction_mode) */ +#if defined(VK_NV_device_diagnostic_checkpoints) +PFN_vkCmdSetCheckpointNV vkCmdSetCheckpointNV; +PFN_vkGetQueueCheckpointDataNV vkGetQueueCheckpointDataNV; +#endif /* defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_NV_device_generated_commands) +PFN_vkCmdBindPipelineShaderGroupNV vkCmdBindPipelineShaderGroupNV; +PFN_vkCmdExecuteGeneratedCommandsNV vkCmdExecuteGeneratedCommandsNV; +PFN_vkCmdPreprocessGeneratedCommandsNV vkCmdPreprocessGeneratedCommandsNV; +PFN_vkCreateIndirectCommandsLayoutNV vkCreateIndirectCommandsLayoutNV; +PFN_vkDestroyIndirectCommandsLayoutNV vkDestroyIndirectCommandsLayoutNV; +PFN_vkGetGeneratedCommandsMemoryRequirementsNV vkGetGeneratedCommandsMemoryRequirementsNV; +#endif /* defined(VK_NV_device_generated_commands) */ +#if defined(VK_NV_external_memory_capabilities) +PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV vkGetPhysicalDeviceExternalImageFormatPropertiesNV; +#endif /* defined(VK_NV_external_memory_capabilities) */ +#if defined(VK_NV_external_memory_win32) +PFN_vkGetMemoryWin32HandleNV vkGetMemoryWin32HandleNV; +#endif /* defined(VK_NV_external_memory_win32) */ +#if defined(VK_NV_mesh_shader) +PFN_vkCmdDrawMeshTasksIndirectCountNV vkCmdDrawMeshTasksIndirectCountNV; +PFN_vkCmdDrawMeshTasksIndirectNV vkCmdDrawMeshTasksIndirectNV; +PFN_vkCmdDrawMeshTasksNV vkCmdDrawMeshTasksNV; +#endif /* defined(VK_NV_mesh_shader) */ +#if defined(VK_NV_ray_tracing) +PFN_vkBindAccelerationStructureMemoryNV vkBindAccelerationStructureMemoryNV; +PFN_vkCmdBuildAccelerationStructureNV vkCmdBuildAccelerationStructureNV; +PFN_vkCmdCopyAccelerationStructureNV vkCmdCopyAccelerationStructureNV; +PFN_vkCmdTraceRaysNV vkCmdTraceRaysNV; +PFN_vkCmdWriteAccelerationStructuresPropertiesNV vkCmdWriteAccelerationStructuresPropertiesNV; +PFN_vkCompileDeferredNV vkCompileDeferredNV; +PFN_vkCreateAccelerationStructureNV vkCreateAccelerationStructureNV; +PFN_vkCreateRayTracingPipelinesNV vkCreateRayTracingPipelinesNV; +PFN_vkDestroyAccelerationStructureNV vkDestroyAccelerationStructureNV; +PFN_vkGetAccelerationStructureHandleNV vkGetAccelerationStructureHandleNV; +PFN_vkGetAccelerationStructureMemoryRequirementsNV vkGetAccelerationStructureMemoryRequirementsNV; +PFN_vkGetRayTracingShaderGroupHandlesNV vkGetRayTracingShaderGroupHandlesNV; +#endif /* defined(VK_NV_ray_tracing) */ +#if defined(VK_NV_scissor_exclusive) +PFN_vkCmdSetExclusiveScissorNV vkCmdSetExclusiveScissorNV; +#endif /* defined(VK_NV_scissor_exclusive) */ +#if defined(VK_NV_shading_rate_image) +PFN_vkCmdBindShadingRateImageNV vkCmdBindShadingRateImageNV; +PFN_vkCmdSetCoarseSampleOrderNV vkCmdSetCoarseSampleOrderNV; +PFN_vkCmdSetViewportShadingRatePaletteNV vkCmdSetViewportShadingRatePaletteNV; +#endif /* defined(VK_NV_shading_rate_image) */ +#if (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) +PFN_vkGetDeviceGroupSurfacePresentModes2EXT vkGetDeviceGroupSurfacePresentModes2EXT; +#endif /* (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) +PFN_vkCmdPushDescriptorSetWithTemplateKHR vkCmdPushDescriptorSetWithTemplateKHR; +#endif /* (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) +PFN_vkGetDeviceGroupPresentCapabilitiesKHR vkGetDeviceGroupPresentCapabilitiesKHR; +PFN_vkGetDeviceGroupSurfacePresentModesKHR vkGetDeviceGroupSurfacePresentModesKHR; +PFN_vkGetPhysicalDevicePresentRectanglesKHR vkGetPhysicalDevicePresentRectanglesKHR; +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) +PFN_vkAcquireNextImage2KHR vkAcquireNextImage2KHR; +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ +/* VOLK_GENERATE_PROTOTYPES_C */ + +#ifdef __GNUC__ +# pragma GCC visibility pop +#endif + +#ifdef __cplusplus +} +#endif +/* clang-format on */ diff --git a/src/vk/volk/volk.h b/src/vk/volk/volk.h new file mode 100644 index 0000000..f05de67 --- /dev/null +++ b/src/vk/volk/volk.h @@ -0,0 +1,1257 @@ +/** + * volk + * + * Copyright (C) 2018-2019, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) + * Report bugs and download new versions at https://github.com/zeux/volk + * + * This library is distributed under the MIT License. See notice at the end of this file. + */ +/* clang-format off */ +#ifndef VOLK_H_ +#define VOLK_H_ + +#if defined(VULKAN_H_) && !defined(VK_NO_PROTOTYPES) +# error To use volk, you need to define VK_NO_PROTOTYPES before including vulkan.h +#endif + +/* VOLK_GENERATE_VERSION_DEFINE */ +#define VOLK_HEADER_VERSION 153 +/* VOLK_GENERATE_VERSION_DEFINE */ + +#ifndef VK_NO_PROTOTYPES +# define VK_NO_PROTOTYPES +#endif + +#ifndef VULKAN_H_ +# ifdef VOLK_VULKAN_H_PATH +# include VOLK_VULKAN_H_PATH +# elif defined(VK_USE_PLATFORM_WIN32_KHR) +# include +# include + + /* When VK_USE_PLATFORM_WIN32_KHR is defined, instead of including vulkan.h directly, we include individual parts of the SDK + * This is necessary to avoid including which is very heavy - it takes 200ms to parse without WIN32_LEAN_AND_MEAN + * and 100ms to parse with it. vulkan_win32.h only needs a few symbols that are easy to redefine ourselves. + */ + typedef unsigned long DWORD; + typedef const wchar_t* LPCWSTR; + typedef void* HANDLE; + typedef struct HINSTANCE__* HINSTANCE; + typedef struct HWND__* HWND; + typedef struct HMONITOR__* HMONITOR; + typedef struct _SECURITY_ATTRIBUTES SECURITY_ATTRIBUTES; + +# include + +# ifdef VK_ENABLE_BETA_EXTENSIONS +# include +# endif +# else +# include +# endif +#endif + +/* Disable VK_NVX_image_view_handle because SDK 140 introduced a change that can't be used with prior versions */ +#if VK_HEADER_VERSION < 140 +# undef VK_NVX_image_view_handle +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct VolkDeviceTable; + +/** + * Initialize library by loading Vulkan loader; call this function before creating the Vulkan instance. + * + * Returns VK_SUCCESS on success and VK_ERROR_INITIALIZATION_FAILED otherwise. + */ +VkResult volkInitialize(void); + +/** + * Initialize library by providing a custom handler to load global symbols. + * + * This function can be used instead of volkInitialize. + * The handler function pointer will be asked to load global Vulkan symbols which require no instance + * (such as vkCreateInstance, vkEnumerateInstance* and vkEnumerateInstanceVersion if available). + */ +void volkInitializeCustom(PFN_vkGetInstanceProcAddr handler); + +/** + * Get Vulkan instance version supported by the Vulkan loader, or 0 if Vulkan isn't supported + * + * Returns 0 if volkInitialize wasn't called or failed. + */ +uint32_t volkGetInstanceVersion(void); + +/** + * Load global function pointers using application-created VkInstance; call this function after creating the Vulkan instance. + */ +void volkLoadInstance(VkInstance instance); + +/** + * Load global function pointers using application-created VkInstance; call this function after creating the Vulkan instance. + * Skips loading device-based function pointers, requires usage of volkLoadDevice afterwards. + */ +void volkLoadInstanceOnly(VkInstance instance); + +/** + * Load global function pointers using application-created VkDevice; call this function after creating the Vulkan device. + * + * Note: this is not suitable for applications that want to use multiple VkDevice objects concurrently. + */ +void volkLoadDevice(VkDevice device); + +/** + * Return last VkInstance for which global function pointers have been loaded via volkLoadInstance(), + * or VK_NULL_HANDLE if volkLoadInstance() has not been called. + */ +VkInstance volkGetLoadedInstance(void); + +/** + * Return last VkDevice for which global function pointers have been loaded via volkLoadDevice(), + * or VK_NULL_HANDLE if volkLoadDevice() has not been called. + */ +VkDevice volkGetLoadedDevice(void); + +/** + * Load function pointers using application-created VkDevice into a table. + * Application should use function pointers from that table instead of using global function pointers. + */ +void volkLoadDeviceTable(struct VolkDeviceTable* table, VkDevice device); + +/** + * Device-specific function pointer table + */ +struct VolkDeviceTable +{ + /* VOLK_GENERATE_DEVICE_TABLE */ +#if defined(VK_VERSION_1_0) + PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; + PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets; + PFN_vkAllocateMemory vkAllocateMemory; + PFN_vkBeginCommandBuffer vkBeginCommandBuffer; + PFN_vkBindBufferMemory vkBindBufferMemory; + PFN_vkBindImageMemory vkBindImageMemory; + PFN_vkCmdBeginQuery vkCmdBeginQuery; + PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; + PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets; + PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; + PFN_vkCmdBindPipeline vkCmdBindPipeline; + PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers; + PFN_vkCmdBlitImage vkCmdBlitImage; + PFN_vkCmdClearAttachments vkCmdClearAttachments; + PFN_vkCmdClearColorImage vkCmdClearColorImage; + PFN_vkCmdClearDepthStencilImage vkCmdClearDepthStencilImage; + PFN_vkCmdCopyBuffer vkCmdCopyBuffer; + PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage; + PFN_vkCmdCopyImage vkCmdCopyImage; + PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer; + PFN_vkCmdCopyQueryPoolResults vkCmdCopyQueryPoolResults; + PFN_vkCmdDispatch vkCmdDispatch; + PFN_vkCmdDispatchIndirect vkCmdDispatchIndirect; + PFN_vkCmdDraw vkCmdDraw; + PFN_vkCmdDrawIndexed vkCmdDrawIndexed; + PFN_vkCmdDrawIndexedIndirect vkCmdDrawIndexedIndirect; + PFN_vkCmdDrawIndirect vkCmdDrawIndirect; + PFN_vkCmdEndQuery vkCmdEndQuery; + PFN_vkCmdEndRenderPass vkCmdEndRenderPass; + PFN_vkCmdExecuteCommands vkCmdExecuteCommands; + PFN_vkCmdFillBuffer vkCmdFillBuffer; + PFN_vkCmdNextSubpass vkCmdNextSubpass; + PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; + PFN_vkCmdPushConstants vkCmdPushConstants; + PFN_vkCmdResetEvent vkCmdResetEvent; + PFN_vkCmdResetQueryPool vkCmdResetQueryPool; + PFN_vkCmdResolveImage vkCmdResolveImage; + PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants; + PFN_vkCmdSetDepthBias vkCmdSetDepthBias; + PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds; + PFN_vkCmdSetEvent vkCmdSetEvent; + PFN_vkCmdSetLineWidth vkCmdSetLineWidth; + PFN_vkCmdSetScissor vkCmdSetScissor; + PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask; + PFN_vkCmdSetStencilReference vkCmdSetStencilReference; + PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask; + PFN_vkCmdSetViewport vkCmdSetViewport; + PFN_vkCmdUpdateBuffer vkCmdUpdateBuffer; + PFN_vkCmdWaitEvents vkCmdWaitEvents; + PFN_vkCmdWriteTimestamp vkCmdWriteTimestamp; + PFN_vkCreateBuffer vkCreateBuffer; + PFN_vkCreateBufferView vkCreateBufferView; + PFN_vkCreateCommandPool vkCreateCommandPool; + PFN_vkCreateComputePipelines vkCreateComputePipelines; + PFN_vkCreateDescriptorPool vkCreateDescriptorPool; + PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout; + PFN_vkCreateEvent vkCreateEvent; + PFN_vkCreateFence vkCreateFence; + PFN_vkCreateFramebuffer vkCreateFramebuffer; + PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines; + PFN_vkCreateImage vkCreateImage; + PFN_vkCreateImageView vkCreateImageView; + PFN_vkCreatePipelineCache vkCreatePipelineCache; + PFN_vkCreatePipelineLayout vkCreatePipelineLayout; + PFN_vkCreateQueryPool vkCreateQueryPool; + PFN_vkCreateRenderPass vkCreateRenderPass; + PFN_vkCreateSampler vkCreateSampler; + PFN_vkCreateSemaphore vkCreateSemaphore; + PFN_vkCreateShaderModule vkCreateShaderModule; + PFN_vkDestroyBuffer vkDestroyBuffer; + PFN_vkDestroyBufferView vkDestroyBufferView; + PFN_vkDestroyCommandPool vkDestroyCommandPool; + PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool; + PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout; + PFN_vkDestroyDevice vkDestroyDevice; + PFN_vkDestroyEvent vkDestroyEvent; + PFN_vkDestroyFence vkDestroyFence; + PFN_vkDestroyFramebuffer vkDestroyFramebuffer; + PFN_vkDestroyImage vkDestroyImage; + PFN_vkDestroyImageView vkDestroyImageView; + PFN_vkDestroyPipeline vkDestroyPipeline; + PFN_vkDestroyPipelineCache vkDestroyPipelineCache; + PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout; + PFN_vkDestroyQueryPool vkDestroyQueryPool; + PFN_vkDestroyRenderPass vkDestroyRenderPass; + PFN_vkDestroySampler vkDestroySampler; + PFN_vkDestroySemaphore vkDestroySemaphore; + PFN_vkDestroyShaderModule vkDestroyShaderModule; + PFN_vkDeviceWaitIdle vkDeviceWaitIdle; + PFN_vkEndCommandBuffer vkEndCommandBuffer; + PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges; + PFN_vkFreeCommandBuffers vkFreeCommandBuffers; + PFN_vkFreeDescriptorSets vkFreeDescriptorSets; + PFN_vkFreeMemory vkFreeMemory; + PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; + PFN_vkGetDeviceMemoryCommitment vkGetDeviceMemoryCommitment; + PFN_vkGetDeviceQueue vkGetDeviceQueue; + PFN_vkGetEventStatus vkGetEventStatus; + PFN_vkGetFenceStatus vkGetFenceStatus; + PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; + PFN_vkGetImageSparseMemoryRequirements vkGetImageSparseMemoryRequirements; + PFN_vkGetImageSubresourceLayout vkGetImageSubresourceLayout; + PFN_vkGetPipelineCacheData vkGetPipelineCacheData; + PFN_vkGetQueryPoolResults vkGetQueryPoolResults; + PFN_vkGetRenderAreaGranularity vkGetRenderAreaGranularity; + PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges; + PFN_vkMapMemory vkMapMemory; + PFN_vkMergePipelineCaches vkMergePipelineCaches; + PFN_vkQueueBindSparse vkQueueBindSparse; + PFN_vkQueueSubmit vkQueueSubmit; + PFN_vkQueueWaitIdle vkQueueWaitIdle; + PFN_vkResetCommandBuffer vkResetCommandBuffer; + PFN_vkResetCommandPool vkResetCommandPool; + PFN_vkResetDescriptorPool vkResetDescriptorPool; + PFN_vkResetEvent vkResetEvent; + PFN_vkResetFences vkResetFences; + PFN_vkSetEvent vkSetEvent; + PFN_vkUnmapMemory vkUnmapMemory; + PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; + PFN_vkWaitForFences vkWaitForFences; +#endif /* defined(VK_VERSION_1_0) */ +#if defined(VK_VERSION_1_1) + PFN_vkBindBufferMemory2 vkBindBufferMemory2; + PFN_vkBindImageMemory2 vkBindImageMemory2; + PFN_vkCmdDispatchBase vkCmdDispatchBase; + PFN_vkCmdSetDeviceMask vkCmdSetDeviceMask; + PFN_vkCreateDescriptorUpdateTemplate vkCreateDescriptorUpdateTemplate; + PFN_vkCreateSamplerYcbcrConversion vkCreateSamplerYcbcrConversion; + PFN_vkDestroyDescriptorUpdateTemplate vkDestroyDescriptorUpdateTemplate; + PFN_vkDestroySamplerYcbcrConversion vkDestroySamplerYcbcrConversion; + PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2; + PFN_vkGetDescriptorSetLayoutSupport vkGetDescriptorSetLayoutSupport; + PFN_vkGetDeviceGroupPeerMemoryFeatures vkGetDeviceGroupPeerMemoryFeatures; + PFN_vkGetDeviceQueue2 vkGetDeviceQueue2; + PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2; + PFN_vkGetImageSparseMemoryRequirements2 vkGetImageSparseMemoryRequirements2; + PFN_vkTrimCommandPool vkTrimCommandPool; + PFN_vkUpdateDescriptorSetWithTemplate vkUpdateDescriptorSetWithTemplate; +#endif /* defined(VK_VERSION_1_1) */ +#if defined(VK_VERSION_1_2) + PFN_vkCmdBeginRenderPass2 vkCmdBeginRenderPass2; + PFN_vkCmdDrawIndexedIndirectCount vkCmdDrawIndexedIndirectCount; + PFN_vkCmdDrawIndirectCount vkCmdDrawIndirectCount; + PFN_vkCmdEndRenderPass2 vkCmdEndRenderPass2; + PFN_vkCmdNextSubpass2 vkCmdNextSubpass2; + PFN_vkCreateRenderPass2 vkCreateRenderPass2; + PFN_vkGetBufferDeviceAddress vkGetBufferDeviceAddress; + PFN_vkGetBufferOpaqueCaptureAddress vkGetBufferOpaqueCaptureAddress; + PFN_vkGetDeviceMemoryOpaqueCaptureAddress vkGetDeviceMemoryOpaqueCaptureAddress; + PFN_vkGetSemaphoreCounterValue vkGetSemaphoreCounterValue; + PFN_vkResetQueryPool vkResetQueryPool; + PFN_vkSignalSemaphore vkSignalSemaphore; + PFN_vkWaitSemaphores vkWaitSemaphores; +#endif /* defined(VK_VERSION_1_2) */ +#if defined(VK_AMD_buffer_marker) + PFN_vkCmdWriteBufferMarkerAMD vkCmdWriteBufferMarkerAMD; +#endif /* defined(VK_AMD_buffer_marker) */ +#if defined(VK_AMD_display_native_hdr) + PFN_vkSetLocalDimmingAMD vkSetLocalDimmingAMD; +#endif /* defined(VK_AMD_display_native_hdr) */ +#if defined(VK_AMD_draw_indirect_count) + PFN_vkCmdDrawIndexedIndirectCountAMD vkCmdDrawIndexedIndirectCountAMD; + PFN_vkCmdDrawIndirectCountAMD vkCmdDrawIndirectCountAMD; +#endif /* defined(VK_AMD_draw_indirect_count) */ +#if defined(VK_AMD_shader_info) + PFN_vkGetShaderInfoAMD vkGetShaderInfoAMD; +#endif /* defined(VK_AMD_shader_info) */ +#if defined(VK_ANDROID_external_memory_android_hardware_buffer) + PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID; + PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID; +#endif /* defined(VK_ANDROID_external_memory_android_hardware_buffer) */ +#if defined(VK_EXT_buffer_device_address) + PFN_vkGetBufferDeviceAddressEXT vkGetBufferDeviceAddressEXT; +#endif /* defined(VK_EXT_buffer_device_address) */ +#if defined(VK_EXT_calibrated_timestamps) + PFN_vkGetCalibratedTimestampsEXT vkGetCalibratedTimestampsEXT; +#endif /* defined(VK_EXT_calibrated_timestamps) */ +#if defined(VK_EXT_conditional_rendering) + PFN_vkCmdBeginConditionalRenderingEXT vkCmdBeginConditionalRenderingEXT; + PFN_vkCmdEndConditionalRenderingEXT vkCmdEndConditionalRenderingEXT; +#endif /* defined(VK_EXT_conditional_rendering) */ +#if defined(VK_EXT_debug_marker) + PFN_vkCmdDebugMarkerBeginEXT vkCmdDebugMarkerBeginEXT; + PFN_vkCmdDebugMarkerEndEXT vkCmdDebugMarkerEndEXT; + PFN_vkCmdDebugMarkerInsertEXT vkCmdDebugMarkerInsertEXT; + PFN_vkDebugMarkerSetObjectNameEXT vkDebugMarkerSetObjectNameEXT; + PFN_vkDebugMarkerSetObjectTagEXT vkDebugMarkerSetObjectTagEXT; +#endif /* defined(VK_EXT_debug_marker) */ +#if defined(VK_EXT_discard_rectangles) + PFN_vkCmdSetDiscardRectangleEXT vkCmdSetDiscardRectangleEXT; +#endif /* defined(VK_EXT_discard_rectangles) */ +#if defined(VK_EXT_display_control) + PFN_vkDisplayPowerControlEXT vkDisplayPowerControlEXT; + PFN_vkGetSwapchainCounterEXT vkGetSwapchainCounterEXT; + PFN_vkRegisterDeviceEventEXT vkRegisterDeviceEventEXT; + PFN_vkRegisterDisplayEventEXT vkRegisterDisplayEventEXT; +#endif /* defined(VK_EXT_display_control) */ +#if defined(VK_EXT_extended_dynamic_state) + PFN_vkCmdBindVertexBuffers2EXT vkCmdBindVertexBuffers2EXT; + PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT; + PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT; + PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT; + PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT; + PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT; + PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT; + PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT; + PFN_vkCmdSetScissorWithCountEXT vkCmdSetScissorWithCountEXT; + PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT; + PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT; + PFN_vkCmdSetViewportWithCountEXT vkCmdSetViewportWithCountEXT; +#endif /* defined(VK_EXT_extended_dynamic_state) */ +#if defined(VK_EXT_external_memory_host) + PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT; +#endif /* defined(VK_EXT_external_memory_host) */ +#if defined(VK_EXT_full_screen_exclusive) + PFN_vkAcquireFullScreenExclusiveModeEXT vkAcquireFullScreenExclusiveModeEXT; + PFN_vkReleaseFullScreenExclusiveModeEXT vkReleaseFullScreenExclusiveModeEXT; +#endif /* defined(VK_EXT_full_screen_exclusive) */ +#if defined(VK_EXT_hdr_metadata) + PFN_vkSetHdrMetadataEXT vkSetHdrMetadataEXT; +#endif /* defined(VK_EXT_hdr_metadata) */ +#if defined(VK_EXT_host_query_reset) + PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT; +#endif /* defined(VK_EXT_host_query_reset) */ +#if defined(VK_EXT_image_drm_format_modifier) + PFN_vkGetImageDrmFormatModifierPropertiesEXT vkGetImageDrmFormatModifierPropertiesEXT; +#endif /* defined(VK_EXT_image_drm_format_modifier) */ +#if defined(VK_EXT_line_rasterization) + PFN_vkCmdSetLineStippleEXT vkCmdSetLineStippleEXT; +#endif /* defined(VK_EXT_line_rasterization) */ +#if defined(VK_EXT_private_data) + PFN_vkCreatePrivateDataSlotEXT vkCreatePrivateDataSlotEXT; + PFN_vkDestroyPrivateDataSlotEXT vkDestroyPrivateDataSlotEXT; + PFN_vkGetPrivateDataEXT vkGetPrivateDataEXT; + PFN_vkSetPrivateDataEXT vkSetPrivateDataEXT; +#endif /* defined(VK_EXT_private_data) */ +#if defined(VK_EXT_sample_locations) + PFN_vkCmdSetSampleLocationsEXT vkCmdSetSampleLocationsEXT; +#endif /* defined(VK_EXT_sample_locations) */ +#if defined(VK_EXT_transform_feedback) + PFN_vkCmdBeginQueryIndexedEXT vkCmdBeginQueryIndexedEXT; + PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT; + PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT; + PFN_vkCmdDrawIndirectByteCountEXT vkCmdDrawIndirectByteCountEXT; + PFN_vkCmdEndQueryIndexedEXT vkCmdEndQueryIndexedEXT; + PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT; +#endif /* defined(VK_EXT_transform_feedback) */ +#if defined(VK_EXT_validation_cache) + PFN_vkCreateValidationCacheEXT vkCreateValidationCacheEXT; + PFN_vkDestroyValidationCacheEXT vkDestroyValidationCacheEXT; + PFN_vkGetValidationCacheDataEXT vkGetValidationCacheDataEXT; + PFN_vkMergeValidationCachesEXT vkMergeValidationCachesEXT; +#endif /* defined(VK_EXT_validation_cache) */ +#if defined(VK_GOOGLE_display_timing) + PFN_vkGetPastPresentationTimingGOOGLE vkGetPastPresentationTimingGOOGLE; + PFN_vkGetRefreshCycleDurationGOOGLE vkGetRefreshCycleDurationGOOGLE; +#endif /* defined(VK_GOOGLE_display_timing) */ +#if defined(VK_INTEL_performance_query) + PFN_vkAcquirePerformanceConfigurationINTEL vkAcquirePerformanceConfigurationINTEL; + PFN_vkCmdSetPerformanceMarkerINTEL vkCmdSetPerformanceMarkerINTEL; + PFN_vkCmdSetPerformanceOverrideINTEL vkCmdSetPerformanceOverrideINTEL; + PFN_vkCmdSetPerformanceStreamMarkerINTEL vkCmdSetPerformanceStreamMarkerINTEL; + PFN_vkGetPerformanceParameterINTEL vkGetPerformanceParameterINTEL; + PFN_vkInitializePerformanceApiINTEL vkInitializePerformanceApiINTEL; + PFN_vkQueueSetPerformanceConfigurationINTEL vkQueueSetPerformanceConfigurationINTEL; + PFN_vkReleasePerformanceConfigurationINTEL vkReleasePerformanceConfigurationINTEL; + PFN_vkUninitializePerformanceApiINTEL vkUninitializePerformanceApiINTEL; +#endif /* defined(VK_INTEL_performance_query) */ +#if defined(VK_KHR_bind_memory2) + PFN_vkBindBufferMemory2KHR vkBindBufferMemory2KHR; + PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR; +#endif /* defined(VK_KHR_bind_memory2) */ +#if defined(VK_KHR_buffer_device_address) + PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR; + PFN_vkGetBufferOpaqueCaptureAddressKHR vkGetBufferOpaqueCaptureAddressKHR; + PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR vkGetDeviceMemoryOpaqueCaptureAddressKHR; +#endif /* defined(VK_KHR_buffer_device_address) */ +#if defined(VK_KHR_create_renderpass2) + PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR; + PFN_vkCmdEndRenderPass2KHR vkCmdEndRenderPass2KHR; + PFN_vkCmdNextSubpass2KHR vkCmdNextSubpass2KHR; + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; +#endif /* defined(VK_KHR_create_renderpass2) */ +#if defined(VK_KHR_deferred_host_operations) + PFN_vkCreateDeferredOperationKHR vkCreateDeferredOperationKHR; + PFN_vkDeferredOperationJoinKHR vkDeferredOperationJoinKHR; + PFN_vkDestroyDeferredOperationKHR vkDestroyDeferredOperationKHR; + PFN_vkGetDeferredOperationMaxConcurrencyKHR vkGetDeferredOperationMaxConcurrencyKHR; + PFN_vkGetDeferredOperationResultKHR vkGetDeferredOperationResultKHR; +#endif /* defined(VK_KHR_deferred_host_operations) */ +#if defined(VK_KHR_descriptor_update_template) + PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; + PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; + PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; +#endif /* defined(VK_KHR_descriptor_update_template) */ +#if defined(VK_KHR_device_group) + PFN_vkCmdDispatchBaseKHR vkCmdDispatchBaseKHR; + PFN_vkCmdSetDeviceMaskKHR vkCmdSetDeviceMaskKHR; + PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR vkGetDeviceGroupPeerMemoryFeaturesKHR; +#endif /* defined(VK_KHR_device_group) */ +#if defined(VK_KHR_display_swapchain) + PFN_vkCreateSharedSwapchainsKHR vkCreateSharedSwapchainsKHR; +#endif /* defined(VK_KHR_display_swapchain) */ +#if defined(VK_KHR_draw_indirect_count) + PFN_vkCmdDrawIndexedIndirectCountKHR vkCmdDrawIndexedIndirectCountKHR; + PFN_vkCmdDrawIndirectCountKHR vkCmdDrawIndirectCountKHR; +#endif /* defined(VK_KHR_draw_indirect_count) */ +#if defined(VK_KHR_external_fence_fd) + PFN_vkGetFenceFdKHR vkGetFenceFdKHR; + PFN_vkImportFenceFdKHR vkImportFenceFdKHR; +#endif /* defined(VK_KHR_external_fence_fd) */ +#if defined(VK_KHR_external_fence_win32) + PFN_vkGetFenceWin32HandleKHR vkGetFenceWin32HandleKHR; + PFN_vkImportFenceWin32HandleKHR vkImportFenceWin32HandleKHR; +#endif /* defined(VK_KHR_external_fence_win32) */ +#if defined(VK_KHR_external_memory_fd) + PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR; + PFN_vkGetMemoryFdPropertiesKHR vkGetMemoryFdPropertiesKHR; +#endif /* defined(VK_KHR_external_memory_fd) */ +#if defined(VK_KHR_external_memory_win32) + PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32HandleKHR; + PFN_vkGetMemoryWin32HandlePropertiesKHR vkGetMemoryWin32HandlePropertiesKHR; +#endif /* defined(VK_KHR_external_memory_win32) */ +#if defined(VK_KHR_external_semaphore_fd) + PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR; + PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR; +#endif /* defined(VK_KHR_external_semaphore_fd) */ +#if defined(VK_KHR_external_semaphore_win32) + PFN_vkGetSemaphoreWin32HandleKHR vkGetSemaphoreWin32HandleKHR; + PFN_vkImportSemaphoreWin32HandleKHR vkImportSemaphoreWin32HandleKHR; +#endif /* defined(VK_KHR_external_semaphore_win32) */ +#if defined(VK_KHR_get_memory_requirements2) + PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; + PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; + PFN_vkGetImageSparseMemoryRequirements2KHR vkGetImageSparseMemoryRequirements2KHR; +#endif /* defined(VK_KHR_get_memory_requirements2) */ +#if defined(VK_KHR_maintenance1) + PFN_vkTrimCommandPoolKHR vkTrimCommandPoolKHR; +#endif /* defined(VK_KHR_maintenance1) */ +#if defined(VK_KHR_maintenance3) + PFN_vkGetDescriptorSetLayoutSupportKHR vkGetDescriptorSetLayoutSupportKHR; +#endif /* defined(VK_KHR_maintenance3) */ +#if defined(VK_KHR_performance_query) + PFN_vkAcquireProfilingLockKHR vkAcquireProfilingLockKHR; + PFN_vkReleaseProfilingLockKHR vkReleaseProfilingLockKHR; +#endif /* defined(VK_KHR_performance_query) */ +#if defined(VK_KHR_pipeline_executable_properties) + PFN_vkGetPipelineExecutableInternalRepresentationsKHR vkGetPipelineExecutableInternalRepresentationsKHR; + PFN_vkGetPipelineExecutablePropertiesKHR vkGetPipelineExecutablePropertiesKHR; + PFN_vkGetPipelineExecutableStatisticsKHR vkGetPipelineExecutableStatisticsKHR; +#endif /* defined(VK_KHR_pipeline_executable_properties) */ +#if defined(VK_KHR_push_descriptor) + PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR; +#endif /* defined(VK_KHR_push_descriptor) */ +#if defined(VK_KHR_ray_tracing) + PFN_vkBindAccelerationStructureMemoryKHR vkBindAccelerationStructureMemoryKHR; + PFN_vkBuildAccelerationStructureKHR vkBuildAccelerationStructureKHR; + PFN_vkCmdBuildAccelerationStructureIndirectKHR vkCmdBuildAccelerationStructureIndirectKHR; + PFN_vkCmdBuildAccelerationStructureKHR vkCmdBuildAccelerationStructureKHR; + PFN_vkCmdCopyAccelerationStructureKHR vkCmdCopyAccelerationStructureKHR; + PFN_vkCmdCopyAccelerationStructureToMemoryKHR vkCmdCopyAccelerationStructureToMemoryKHR; + PFN_vkCmdCopyMemoryToAccelerationStructureKHR vkCmdCopyMemoryToAccelerationStructureKHR; + PFN_vkCmdTraceRaysIndirectKHR vkCmdTraceRaysIndirectKHR; + PFN_vkCmdTraceRaysKHR vkCmdTraceRaysKHR; + PFN_vkCmdWriteAccelerationStructuresPropertiesKHR vkCmdWriteAccelerationStructuresPropertiesKHR; + PFN_vkCopyAccelerationStructureKHR vkCopyAccelerationStructureKHR; + PFN_vkCopyAccelerationStructureToMemoryKHR vkCopyAccelerationStructureToMemoryKHR; + PFN_vkCopyMemoryToAccelerationStructureKHR vkCopyMemoryToAccelerationStructureKHR; + PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructureKHR; + PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelinesKHR; + PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructureKHR; + PFN_vkGetAccelerationStructureDeviceAddressKHR vkGetAccelerationStructureDeviceAddressKHR; + PFN_vkGetAccelerationStructureMemoryRequirementsKHR vkGetAccelerationStructureMemoryRequirementsKHR; + PFN_vkGetDeviceAccelerationStructureCompatibilityKHR vkGetDeviceAccelerationStructureCompatibilityKHR; + PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR vkGetRayTracingCaptureReplayShaderGroupHandlesKHR; + PFN_vkGetRayTracingShaderGroupHandlesKHR vkGetRayTracingShaderGroupHandlesKHR; + PFN_vkWriteAccelerationStructuresPropertiesKHR vkWriteAccelerationStructuresPropertiesKHR; +#endif /* defined(VK_KHR_ray_tracing) */ +#if defined(VK_KHR_sampler_ycbcr_conversion) + PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR; + PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR; +#endif /* defined(VK_KHR_sampler_ycbcr_conversion) */ +#if defined(VK_KHR_shared_presentable_image) + PFN_vkGetSwapchainStatusKHR vkGetSwapchainStatusKHR; +#endif /* defined(VK_KHR_shared_presentable_image) */ +#if defined(VK_KHR_swapchain) + PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; + PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; + PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; + PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; + PFN_vkQueuePresentKHR vkQueuePresentKHR; +#endif /* defined(VK_KHR_swapchain) */ +#if defined(VK_KHR_timeline_semaphore) + PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR; + PFN_vkSignalSemaphoreKHR vkSignalSemaphoreKHR; + PFN_vkWaitSemaphoresKHR vkWaitSemaphoresKHR; +#endif /* defined(VK_KHR_timeline_semaphore) */ +#if defined(VK_NVX_image_view_handle) + PFN_vkGetImageViewAddressNVX vkGetImageViewAddressNVX; + PFN_vkGetImageViewHandleNVX vkGetImageViewHandleNVX; +#endif /* defined(VK_NVX_image_view_handle) */ +#if defined(VK_NV_clip_space_w_scaling) + PFN_vkCmdSetViewportWScalingNV vkCmdSetViewportWScalingNV; +#endif /* defined(VK_NV_clip_space_w_scaling) */ +#if defined(VK_NV_device_diagnostic_checkpoints) + PFN_vkCmdSetCheckpointNV vkCmdSetCheckpointNV; + PFN_vkGetQueueCheckpointDataNV vkGetQueueCheckpointDataNV; +#endif /* defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_NV_device_generated_commands) + PFN_vkCmdBindPipelineShaderGroupNV vkCmdBindPipelineShaderGroupNV; + PFN_vkCmdExecuteGeneratedCommandsNV vkCmdExecuteGeneratedCommandsNV; + PFN_vkCmdPreprocessGeneratedCommandsNV vkCmdPreprocessGeneratedCommandsNV; + PFN_vkCreateIndirectCommandsLayoutNV vkCreateIndirectCommandsLayoutNV; + PFN_vkDestroyIndirectCommandsLayoutNV vkDestroyIndirectCommandsLayoutNV; + PFN_vkGetGeneratedCommandsMemoryRequirementsNV vkGetGeneratedCommandsMemoryRequirementsNV; +#endif /* defined(VK_NV_device_generated_commands) */ +#if defined(VK_NV_external_memory_win32) + PFN_vkGetMemoryWin32HandleNV vkGetMemoryWin32HandleNV; +#endif /* defined(VK_NV_external_memory_win32) */ +#if defined(VK_NV_mesh_shader) + PFN_vkCmdDrawMeshTasksIndirectCountNV vkCmdDrawMeshTasksIndirectCountNV; + PFN_vkCmdDrawMeshTasksIndirectNV vkCmdDrawMeshTasksIndirectNV; + PFN_vkCmdDrawMeshTasksNV vkCmdDrawMeshTasksNV; +#endif /* defined(VK_NV_mesh_shader) */ +#if defined(VK_NV_ray_tracing) + PFN_vkBindAccelerationStructureMemoryNV vkBindAccelerationStructureMemoryNV; + PFN_vkCmdBuildAccelerationStructureNV vkCmdBuildAccelerationStructureNV; + PFN_vkCmdCopyAccelerationStructureNV vkCmdCopyAccelerationStructureNV; + PFN_vkCmdTraceRaysNV vkCmdTraceRaysNV; + PFN_vkCmdWriteAccelerationStructuresPropertiesNV vkCmdWriteAccelerationStructuresPropertiesNV; + PFN_vkCompileDeferredNV vkCompileDeferredNV; + PFN_vkCreateAccelerationStructureNV vkCreateAccelerationStructureNV; + PFN_vkCreateRayTracingPipelinesNV vkCreateRayTracingPipelinesNV; + PFN_vkDestroyAccelerationStructureNV vkDestroyAccelerationStructureNV; + PFN_vkGetAccelerationStructureHandleNV vkGetAccelerationStructureHandleNV; + PFN_vkGetAccelerationStructureMemoryRequirementsNV vkGetAccelerationStructureMemoryRequirementsNV; + PFN_vkGetRayTracingShaderGroupHandlesNV vkGetRayTracingShaderGroupHandlesNV; +#endif /* defined(VK_NV_ray_tracing) */ +#if defined(VK_NV_scissor_exclusive) + PFN_vkCmdSetExclusiveScissorNV vkCmdSetExclusiveScissorNV; +#endif /* defined(VK_NV_scissor_exclusive) */ +#if defined(VK_NV_shading_rate_image) + PFN_vkCmdBindShadingRateImageNV vkCmdBindShadingRateImageNV; + PFN_vkCmdSetCoarseSampleOrderNV vkCmdSetCoarseSampleOrderNV; + PFN_vkCmdSetViewportShadingRatePaletteNV vkCmdSetViewportShadingRatePaletteNV; +#endif /* defined(VK_NV_shading_rate_image) */ +#if (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) + PFN_vkGetDeviceGroupSurfacePresentModes2EXT vkGetDeviceGroupSurfacePresentModes2EXT; +#endif /* (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) + PFN_vkCmdPushDescriptorSetWithTemplateKHR vkCmdPushDescriptorSetWithTemplateKHR; +#endif /* (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) + PFN_vkGetDeviceGroupPresentCapabilitiesKHR vkGetDeviceGroupPresentCapabilitiesKHR; + PFN_vkGetDeviceGroupSurfacePresentModesKHR vkGetDeviceGroupSurfacePresentModesKHR; +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) + PFN_vkAcquireNextImage2KHR vkAcquireNextImage2KHR; +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ + /* VOLK_GENERATE_DEVICE_TABLE */ +}; + +/* VOLK_GENERATE_PROTOTYPES_H */ +#if defined(VK_VERSION_1_0) +extern PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; +extern PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets; +extern PFN_vkAllocateMemory vkAllocateMemory; +extern PFN_vkBeginCommandBuffer vkBeginCommandBuffer; +extern PFN_vkBindBufferMemory vkBindBufferMemory; +extern PFN_vkBindImageMemory vkBindImageMemory; +extern PFN_vkCmdBeginQuery vkCmdBeginQuery; +extern PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; +extern PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets; +extern PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; +extern PFN_vkCmdBindPipeline vkCmdBindPipeline; +extern PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers; +extern PFN_vkCmdBlitImage vkCmdBlitImage; +extern PFN_vkCmdClearAttachments vkCmdClearAttachments; +extern PFN_vkCmdClearColorImage vkCmdClearColorImage; +extern PFN_vkCmdClearDepthStencilImage vkCmdClearDepthStencilImage; +extern PFN_vkCmdCopyBuffer vkCmdCopyBuffer; +extern PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage; +extern PFN_vkCmdCopyImage vkCmdCopyImage; +extern PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer; +extern PFN_vkCmdCopyQueryPoolResults vkCmdCopyQueryPoolResults; +extern PFN_vkCmdDispatch vkCmdDispatch; +extern PFN_vkCmdDispatchIndirect vkCmdDispatchIndirect; +extern PFN_vkCmdDraw vkCmdDraw; +extern PFN_vkCmdDrawIndexed vkCmdDrawIndexed; +extern PFN_vkCmdDrawIndexedIndirect vkCmdDrawIndexedIndirect; +extern PFN_vkCmdDrawIndirect vkCmdDrawIndirect; +extern PFN_vkCmdEndQuery vkCmdEndQuery; +extern PFN_vkCmdEndRenderPass vkCmdEndRenderPass; +extern PFN_vkCmdExecuteCommands vkCmdExecuteCommands; +extern PFN_vkCmdFillBuffer vkCmdFillBuffer; +extern PFN_vkCmdNextSubpass vkCmdNextSubpass; +extern PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; +extern PFN_vkCmdPushConstants vkCmdPushConstants; +extern PFN_vkCmdResetEvent vkCmdResetEvent; +extern PFN_vkCmdResetQueryPool vkCmdResetQueryPool; +extern PFN_vkCmdResolveImage vkCmdResolveImage; +extern PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants; +extern PFN_vkCmdSetDepthBias vkCmdSetDepthBias; +extern PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds; +extern PFN_vkCmdSetEvent vkCmdSetEvent; +extern PFN_vkCmdSetLineWidth vkCmdSetLineWidth; +extern PFN_vkCmdSetScissor vkCmdSetScissor; +extern PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask; +extern PFN_vkCmdSetStencilReference vkCmdSetStencilReference; +extern PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask; +extern PFN_vkCmdSetViewport vkCmdSetViewport; +extern PFN_vkCmdUpdateBuffer vkCmdUpdateBuffer; +extern PFN_vkCmdWaitEvents vkCmdWaitEvents; +extern PFN_vkCmdWriteTimestamp vkCmdWriteTimestamp; +extern PFN_vkCreateBuffer vkCreateBuffer; +extern PFN_vkCreateBufferView vkCreateBufferView; +extern PFN_vkCreateCommandPool vkCreateCommandPool; +extern PFN_vkCreateComputePipelines vkCreateComputePipelines; +extern PFN_vkCreateDescriptorPool vkCreateDescriptorPool; +extern PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout; +extern PFN_vkCreateDevice vkCreateDevice; +extern PFN_vkCreateEvent vkCreateEvent; +extern PFN_vkCreateFence vkCreateFence; +extern PFN_vkCreateFramebuffer vkCreateFramebuffer; +extern PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines; +extern PFN_vkCreateImage vkCreateImage; +extern PFN_vkCreateImageView vkCreateImageView; +extern PFN_vkCreateInstance vkCreateInstance; +extern PFN_vkCreatePipelineCache vkCreatePipelineCache; +extern PFN_vkCreatePipelineLayout vkCreatePipelineLayout; +extern PFN_vkCreateQueryPool vkCreateQueryPool; +extern PFN_vkCreateRenderPass vkCreateRenderPass; +extern PFN_vkCreateSampler vkCreateSampler; +extern PFN_vkCreateSemaphore vkCreateSemaphore; +extern PFN_vkCreateShaderModule vkCreateShaderModule; +extern PFN_vkDestroyBuffer vkDestroyBuffer; +extern PFN_vkDestroyBufferView vkDestroyBufferView; +extern PFN_vkDestroyCommandPool vkDestroyCommandPool; +extern PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool; +extern PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout; +extern PFN_vkDestroyDevice vkDestroyDevice; +extern PFN_vkDestroyEvent vkDestroyEvent; +extern PFN_vkDestroyFence vkDestroyFence; +extern PFN_vkDestroyFramebuffer vkDestroyFramebuffer; +extern PFN_vkDestroyImage vkDestroyImage; +extern PFN_vkDestroyImageView vkDestroyImageView; +extern PFN_vkDestroyInstance vkDestroyInstance; +extern PFN_vkDestroyPipeline vkDestroyPipeline; +extern PFN_vkDestroyPipelineCache vkDestroyPipelineCache; +extern PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout; +extern PFN_vkDestroyQueryPool vkDestroyQueryPool; +extern PFN_vkDestroyRenderPass vkDestroyRenderPass; +extern PFN_vkDestroySampler vkDestroySampler; +extern PFN_vkDestroySemaphore vkDestroySemaphore; +extern PFN_vkDestroyShaderModule vkDestroyShaderModule; +extern PFN_vkDeviceWaitIdle vkDeviceWaitIdle; +extern PFN_vkEndCommandBuffer vkEndCommandBuffer; +extern PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties; +extern PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties; +extern PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties; +extern PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties; +extern PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices; +extern PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges; +extern PFN_vkFreeCommandBuffers vkFreeCommandBuffers; +extern PFN_vkFreeDescriptorSets vkFreeDescriptorSets; +extern PFN_vkFreeMemory vkFreeMemory; +extern PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; +extern PFN_vkGetDeviceMemoryCommitment vkGetDeviceMemoryCommitment; +extern PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; +extern PFN_vkGetDeviceQueue vkGetDeviceQueue; +extern PFN_vkGetEventStatus vkGetEventStatus; +extern PFN_vkGetFenceStatus vkGetFenceStatus; +extern PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; +extern PFN_vkGetImageSparseMemoryRequirements vkGetImageSparseMemoryRequirements; +extern PFN_vkGetImageSubresourceLayout vkGetImageSubresourceLayout; +extern PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; +extern PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures; +extern PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties; +extern PFN_vkGetPhysicalDeviceImageFormatProperties vkGetPhysicalDeviceImageFormatProperties; +extern PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; +extern PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; +extern PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties; +extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties vkGetPhysicalDeviceSparseImageFormatProperties; +extern PFN_vkGetPipelineCacheData vkGetPipelineCacheData; +extern PFN_vkGetQueryPoolResults vkGetQueryPoolResults; +extern PFN_vkGetRenderAreaGranularity vkGetRenderAreaGranularity; +extern PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges; +extern PFN_vkMapMemory vkMapMemory; +extern PFN_vkMergePipelineCaches vkMergePipelineCaches; +extern PFN_vkQueueBindSparse vkQueueBindSparse; +extern PFN_vkQueueSubmit vkQueueSubmit; +extern PFN_vkQueueWaitIdle vkQueueWaitIdle; +extern PFN_vkResetCommandBuffer vkResetCommandBuffer; +extern PFN_vkResetCommandPool vkResetCommandPool; +extern PFN_vkResetDescriptorPool vkResetDescriptorPool; +extern PFN_vkResetEvent vkResetEvent; +extern PFN_vkResetFences vkResetFences; +extern PFN_vkSetEvent vkSetEvent; +extern PFN_vkUnmapMemory vkUnmapMemory; +extern PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; +extern PFN_vkWaitForFences vkWaitForFences; +#endif /* defined(VK_VERSION_1_0) */ +#if defined(VK_VERSION_1_1) +extern PFN_vkBindBufferMemory2 vkBindBufferMemory2; +extern PFN_vkBindImageMemory2 vkBindImageMemory2; +extern PFN_vkCmdDispatchBase vkCmdDispatchBase; +extern PFN_vkCmdSetDeviceMask vkCmdSetDeviceMask; +extern PFN_vkCreateDescriptorUpdateTemplate vkCreateDescriptorUpdateTemplate; +extern PFN_vkCreateSamplerYcbcrConversion vkCreateSamplerYcbcrConversion; +extern PFN_vkDestroyDescriptorUpdateTemplate vkDestroyDescriptorUpdateTemplate; +extern PFN_vkDestroySamplerYcbcrConversion vkDestroySamplerYcbcrConversion; +extern PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion; +extern PFN_vkEnumeratePhysicalDeviceGroups vkEnumeratePhysicalDeviceGroups; +extern PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2; +extern PFN_vkGetDescriptorSetLayoutSupport vkGetDescriptorSetLayoutSupport; +extern PFN_vkGetDeviceGroupPeerMemoryFeatures vkGetDeviceGroupPeerMemoryFeatures; +extern PFN_vkGetDeviceQueue2 vkGetDeviceQueue2; +extern PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2; +extern PFN_vkGetImageSparseMemoryRequirements2 vkGetImageSparseMemoryRequirements2; +extern PFN_vkGetPhysicalDeviceExternalBufferProperties vkGetPhysicalDeviceExternalBufferProperties; +extern PFN_vkGetPhysicalDeviceExternalFenceProperties vkGetPhysicalDeviceExternalFenceProperties; +extern PFN_vkGetPhysicalDeviceExternalSemaphoreProperties vkGetPhysicalDeviceExternalSemaphoreProperties; +extern PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2; +extern PFN_vkGetPhysicalDeviceFormatProperties2 vkGetPhysicalDeviceFormatProperties2; +extern PFN_vkGetPhysicalDeviceImageFormatProperties2 vkGetPhysicalDeviceImageFormatProperties2; +extern PFN_vkGetPhysicalDeviceMemoryProperties2 vkGetPhysicalDeviceMemoryProperties2; +extern PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2; +extern PFN_vkGetPhysicalDeviceQueueFamilyProperties2 vkGetPhysicalDeviceQueueFamilyProperties2; +extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 vkGetPhysicalDeviceSparseImageFormatProperties2; +extern PFN_vkTrimCommandPool vkTrimCommandPool; +extern PFN_vkUpdateDescriptorSetWithTemplate vkUpdateDescriptorSetWithTemplate; +#endif /* defined(VK_VERSION_1_1) */ +#if defined(VK_VERSION_1_2) +extern PFN_vkCmdBeginRenderPass2 vkCmdBeginRenderPass2; +extern PFN_vkCmdDrawIndexedIndirectCount vkCmdDrawIndexedIndirectCount; +extern PFN_vkCmdDrawIndirectCount vkCmdDrawIndirectCount; +extern PFN_vkCmdEndRenderPass2 vkCmdEndRenderPass2; +extern PFN_vkCmdNextSubpass2 vkCmdNextSubpass2; +extern PFN_vkCreateRenderPass2 vkCreateRenderPass2; +extern PFN_vkGetBufferDeviceAddress vkGetBufferDeviceAddress; +extern PFN_vkGetBufferOpaqueCaptureAddress vkGetBufferOpaqueCaptureAddress; +extern PFN_vkGetDeviceMemoryOpaqueCaptureAddress vkGetDeviceMemoryOpaqueCaptureAddress; +extern PFN_vkGetSemaphoreCounterValue vkGetSemaphoreCounterValue; +extern PFN_vkResetQueryPool vkResetQueryPool; +extern PFN_vkSignalSemaphore vkSignalSemaphore; +extern PFN_vkWaitSemaphores vkWaitSemaphores; +#endif /* defined(VK_VERSION_1_2) */ +#if defined(VK_AMD_buffer_marker) +extern PFN_vkCmdWriteBufferMarkerAMD vkCmdWriteBufferMarkerAMD; +#endif /* defined(VK_AMD_buffer_marker) */ +#if defined(VK_AMD_display_native_hdr) +extern PFN_vkSetLocalDimmingAMD vkSetLocalDimmingAMD; +#endif /* defined(VK_AMD_display_native_hdr) */ +#if defined(VK_AMD_draw_indirect_count) +extern PFN_vkCmdDrawIndexedIndirectCountAMD vkCmdDrawIndexedIndirectCountAMD; +extern PFN_vkCmdDrawIndirectCountAMD vkCmdDrawIndirectCountAMD; +#endif /* defined(VK_AMD_draw_indirect_count) */ +#if defined(VK_AMD_shader_info) +extern PFN_vkGetShaderInfoAMD vkGetShaderInfoAMD; +#endif /* defined(VK_AMD_shader_info) */ +#if defined(VK_ANDROID_external_memory_android_hardware_buffer) +extern PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID; +extern PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID; +#endif /* defined(VK_ANDROID_external_memory_android_hardware_buffer) */ +#if defined(VK_EXT_acquire_xlib_display) +extern PFN_vkAcquireXlibDisplayEXT vkAcquireXlibDisplayEXT; +extern PFN_vkGetRandROutputDisplayEXT vkGetRandROutputDisplayEXT; +#endif /* defined(VK_EXT_acquire_xlib_display) */ +#if defined(VK_EXT_buffer_device_address) +extern PFN_vkGetBufferDeviceAddressEXT vkGetBufferDeviceAddressEXT; +#endif /* defined(VK_EXT_buffer_device_address) */ +#if defined(VK_EXT_calibrated_timestamps) +extern PFN_vkGetCalibratedTimestampsEXT vkGetCalibratedTimestampsEXT; +extern PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT vkGetPhysicalDeviceCalibrateableTimeDomainsEXT; +#endif /* defined(VK_EXT_calibrated_timestamps) */ +#if defined(VK_EXT_conditional_rendering) +extern PFN_vkCmdBeginConditionalRenderingEXT vkCmdBeginConditionalRenderingEXT; +extern PFN_vkCmdEndConditionalRenderingEXT vkCmdEndConditionalRenderingEXT; +#endif /* defined(VK_EXT_conditional_rendering) */ +#if defined(VK_EXT_debug_marker) +extern PFN_vkCmdDebugMarkerBeginEXT vkCmdDebugMarkerBeginEXT; +extern PFN_vkCmdDebugMarkerEndEXT vkCmdDebugMarkerEndEXT; +extern PFN_vkCmdDebugMarkerInsertEXT vkCmdDebugMarkerInsertEXT; +extern PFN_vkDebugMarkerSetObjectNameEXT vkDebugMarkerSetObjectNameEXT; +extern PFN_vkDebugMarkerSetObjectTagEXT vkDebugMarkerSetObjectTagEXT; +#endif /* defined(VK_EXT_debug_marker) */ +#if defined(VK_EXT_debug_report) +extern PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT; +extern PFN_vkDebugReportMessageEXT vkDebugReportMessageEXT; +extern PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; +#endif /* defined(VK_EXT_debug_report) */ +#if defined(VK_EXT_debug_utils) +extern PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT; +extern PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT; +extern PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT; +extern PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT; +extern PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT; +extern PFN_vkQueueBeginDebugUtilsLabelEXT vkQueueBeginDebugUtilsLabelEXT; +extern PFN_vkQueueEndDebugUtilsLabelEXT vkQueueEndDebugUtilsLabelEXT; +extern PFN_vkQueueInsertDebugUtilsLabelEXT vkQueueInsertDebugUtilsLabelEXT; +extern PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT; +extern PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT; +extern PFN_vkSubmitDebugUtilsMessageEXT vkSubmitDebugUtilsMessageEXT; +#endif /* defined(VK_EXT_debug_utils) */ +#if defined(VK_EXT_direct_mode_display) +extern PFN_vkReleaseDisplayEXT vkReleaseDisplayEXT; +#endif /* defined(VK_EXT_direct_mode_display) */ +#if defined(VK_EXT_directfb_surface) +extern PFN_vkCreateDirectFBSurfaceEXT vkCreateDirectFBSurfaceEXT; +extern PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT vkGetPhysicalDeviceDirectFBPresentationSupportEXT; +#endif /* defined(VK_EXT_directfb_surface) */ +#if defined(VK_EXT_discard_rectangles) +extern PFN_vkCmdSetDiscardRectangleEXT vkCmdSetDiscardRectangleEXT; +#endif /* defined(VK_EXT_discard_rectangles) */ +#if defined(VK_EXT_display_control) +extern PFN_vkDisplayPowerControlEXT vkDisplayPowerControlEXT; +extern PFN_vkGetSwapchainCounterEXT vkGetSwapchainCounterEXT; +extern PFN_vkRegisterDeviceEventEXT vkRegisterDeviceEventEXT; +extern PFN_vkRegisterDisplayEventEXT vkRegisterDisplayEventEXT; +#endif /* defined(VK_EXT_display_control) */ +#if defined(VK_EXT_display_surface_counter) +extern PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT vkGetPhysicalDeviceSurfaceCapabilities2EXT; +#endif /* defined(VK_EXT_display_surface_counter) */ +#if defined(VK_EXT_extended_dynamic_state) +extern PFN_vkCmdBindVertexBuffers2EXT vkCmdBindVertexBuffers2EXT; +extern PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT; +extern PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT; +extern PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT; +extern PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT; +extern PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT; +extern PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT; +extern PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT; +extern PFN_vkCmdSetScissorWithCountEXT vkCmdSetScissorWithCountEXT; +extern PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT; +extern PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT; +extern PFN_vkCmdSetViewportWithCountEXT vkCmdSetViewportWithCountEXT; +#endif /* defined(VK_EXT_extended_dynamic_state) */ +#if defined(VK_EXT_external_memory_host) +extern PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT; +#endif /* defined(VK_EXT_external_memory_host) */ +#if defined(VK_EXT_full_screen_exclusive) +extern PFN_vkAcquireFullScreenExclusiveModeEXT vkAcquireFullScreenExclusiveModeEXT; +extern PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT vkGetPhysicalDeviceSurfacePresentModes2EXT; +extern PFN_vkReleaseFullScreenExclusiveModeEXT vkReleaseFullScreenExclusiveModeEXT; +#endif /* defined(VK_EXT_full_screen_exclusive) */ +#if defined(VK_EXT_hdr_metadata) +extern PFN_vkSetHdrMetadataEXT vkSetHdrMetadataEXT; +#endif /* defined(VK_EXT_hdr_metadata) */ +#if defined(VK_EXT_headless_surface) +extern PFN_vkCreateHeadlessSurfaceEXT vkCreateHeadlessSurfaceEXT; +#endif /* defined(VK_EXT_headless_surface) */ +#if defined(VK_EXT_host_query_reset) +extern PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT; +#endif /* defined(VK_EXT_host_query_reset) */ +#if defined(VK_EXT_image_drm_format_modifier) +extern PFN_vkGetImageDrmFormatModifierPropertiesEXT vkGetImageDrmFormatModifierPropertiesEXT; +#endif /* defined(VK_EXT_image_drm_format_modifier) */ +#if defined(VK_EXT_line_rasterization) +extern PFN_vkCmdSetLineStippleEXT vkCmdSetLineStippleEXT; +#endif /* defined(VK_EXT_line_rasterization) */ +#if defined(VK_EXT_metal_surface) +extern PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT; +#endif /* defined(VK_EXT_metal_surface) */ +#if defined(VK_EXT_private_data) +extern PFN_vkCreatePrivateDataSlotEXT vkCreatePrivateDataSlotEXT; +extern PFN_vkDestroyPrivateDataSlotEXT vkDestroyPrivateDataSlotEXT; +extern PFN_vkGetPrivateDataEXT vkGetPrivateDataEXT; +extern PFN_vkSetPrivateDataEXT vkSetPrivateDataEXT; +#endif /* defined(VK_EXT_private_data) */ +#if defined(VK_EXT_sample_locations) +extern PFN_vkCmdSetSampleLocationsEXT vkCmdSetSampleLocationsEXT; +extern PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT vkGetPhysicalDeviceMultisamplePropertiesEXT; +#endif /* defined(VK_EXT_sample_locations) */ +#if defined(VK_EXT_tooling_info) +extern PFN_vkGetPhysicalDeviceToolPropertiesEXT vkGetPhysicalDeviceToolPropertiesEXT; +#endif /* defined(VK_EXT_tooling_info) */ +#if defined(VK_EXT_transform_feedback) +extern PFN_vkCmdBeginQueryIndexedEXT vkCmdBeginQueryIndexedEXT; +extern PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT; +extern PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT; +extern PFN_vkCmdDrawIndirectByteCountEXT vkCmdDrawIndirectByteCountEXT; +extern PFN_vkCmdEndQueryIndexedEXT vkCmdEndQueryIndexedEXT; +extern PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT; +#endif /* defined(VK_EXT_transform_feedback) */ +#if defined(VK_EXT_validation_cache) +extern PFN_vkCreateValidationCacheEXT vkCreateValidationCacheEXT; +extern PFN_vkDestroyValidationCacheEXT vkDestroyValidationCacheEXT; +extern PFN_vkGetValidationCacheDataEXT vkGetValidationCacheDataEXT; +extern PFN_vkMergeValidationCachesEXT vkMergeValidationCachesEXT; +#endif /* defined(VK_EXT_validation_cache) */ +#if defined(VK_FUCHSIA_imagepipe_surface) +extern PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA; +#endif /* defined(VK_FUCHSIA_imagepipe_surface) */ +#if defined(VK_GGP_stream_descriptor_surface) +extern PFN_vkCreateStreamDescriptorSurfaceGGP vkCreateStreamDescriptorSurfaceGGP; +#endif /* defined(VK_GGP_stream_descriptor_surface) */ +#if defined(VK_GOOGLE_display_timing) +extern PFN_vkGetPastPresentationTimingGOOGLE vkGetPastPresentationTimingGOOGLE; +extern PFN_vkGetRefreshCycleDurationGOOGLE vkGetRefreshCycleDurationGOOGLE; +#endif /* defined(VK_GOOGLE_display_timing) */ +#if defined(VK_INTEL_performance_query) +extern PFN_vkAcquirePerformanceConfigurationINTEL vkAcquirePerformanceConfigurationINTEL; +extern PFN_vkCmdSetPerformanceMarkerINTEL vkCmdSetPerformanceMarkerINTEL; +extern PFN_vkCmdSetPerformanceOverrideINTEL vkCmdSetPerformanceOverrideINTEL; +extern PFN_vkCmdSetPerformanceStreamMarkerINTEL vkCmdSetPerformanceStreamMarkerINTEL; +extern PFN_vkGetPerformanceParameterINTEL vkGetPerformanceParameterINTEL; +extern PFN_vkInitializePerformanceApiINTEL vkInitializePerformanceApiINTEL; +extern PFN_vkQueueSetPerformanceConfigurationINTEL vkQueueSetPerformanceConfigurationINTEL; +extern PFN_vkReleasePerformanceConfigurationINTEL vkReleasePerformanceConfigurationINTEL; +extern PFN_vkUninitializePerformanceApiINTEL vkUninitializePerformanceApiINTEL; +#endif /* defined(VK_INTEL_performance_query) */ +#if defined(VK_KHR_android_surface) +extern PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; +#endif /* defined(VK_KHR_android_surface) */ +#if defined(VK_KHR_bind_memory2) +extern PFN_vkBindBufferMemory2KHR vkBindBufferMemory2KHR; +extern PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR; +#endif /* defined(VK_KHR_bind_memory2) */ +#if defined(VK_KHR_buffer_device_address) +extern PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR; +extern PFN_vkGetBufferOpaqueCaptureAddressKHR vkGetBufferOpaqueCaptureAddressKHR; +extern PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR vkGetDeviceMemoryOpaqueCaptureAddressKHR; +#endif /* defined(VK_KHR_buffer_device_address) */ +#if defined(VK_KHR_create_renderpass2) +extern PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR; +extern PFN_vkCmdEndRenderPass2KHR vkCmdEndRenderPass2KHR; +extern PFN_vkCmdNextSubpass2KHR vkCmdNextSubpass2KHR; +extern PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; +#endif /* defined(VK_KHR_create_renderpass2) */ +#if defined(VK_KHR_deferred_host_operations) +extern PFN_vkCreateDeferredOperationKHR vkCreateDeferredOperationKHR; +extern PFN_vkDeferredOperationJoinKHR vkDeferredOperationJoinKHR; +extern PFN_vkDestroyDeferredOperationKHR vkDestroyDeferredOperationKHR; +extern PFN_vkGetDeferredOperationMaxConcurrencyKHR vkGetDeferredOperationMaxConcurrencyKHR; +extern PFN_vkGetDeferredOperationResultKHR vkGetDeferredOperationResultKHR; +#endif /* defined(VK_KHR_deferred_host_operations) */ +#if defined(VK_KHR_descriptor_update_template) +extern PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; +extern PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; +extern PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; +#endif /* defined(VK_KHR_descriptor_update_template) */ +#if defined(VK_KHR_device_group) +extern PFN_vkCmdDispatchBaseKHR vkCmdDispatchBaseKHR; +extern PFN_vkCmdSetDeviceMaskKHR vkCmdSetDeviceMaskKHR; +extern PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR vkGetDeviceGroupPeerMemoryFeaturesKHR; +#endif /* defined(VK_KHR_device_group) */ +#if defined(VK_KHR_device_group_creation) +extern PFN_vkEnumeratePhysicalDeviceGroupsKHR vkEnumeratePhysicalDeviceGroupsKHR; +#endif /* defined(VK_KHR_device_group_creation) */ +#if defined(VK_KHR_display) +extern PFN_vkCreateDisplayModeKHR vkCreateDisplayModeKHR; +extern PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR; +extern PFN_vkGetDisplayModePropertiesKHR vkGetDisplayModePropertiesKHR; +extern PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR; +extern PFN_vkGetDisplayPlaneSupportedDisplaysKHR vkGetDisplayPlaneSupportedDisplaysKHR; +extern PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vkGetPhysicalDeviceDisplayPlanePropertiesKHR; +extern PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vkGetPhysicalDeviceDisplayPropertiesKHR; +#endif /* defined(VK_KHR_display) */ +#if defined(VK_KHR_display_swapchain) +extern PFN_vkCreateSharedSwapchainsKHR vkCreateSharedSwapchainsKHR; +#endif /* defined(VK_KHR_display_swapchain) */ +#if defined(VK_KHR_draw_indirect_count) +extern PFN_vkCmdDrawIndexedIndirectCountKHR vkCmdDrawIndexedIndirectCountKHR; +extern PFN_vkCmdDrawIndirectCountKHR vkCmdDrawIndirectCountKHR; +#endif /* defined(VK_KHR_draw_indirect_count) */ +#if defined(VK_KHR_external_fence_capabilities) +extern PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR vkGetPhysicalDeviceExternalFencePropertiesKHR; +#endif /* defined(VK_KHR_external_fence_capabilities) */ +#if defined(VK_KHR_external_fence_fd) +extern PFN_vkGetFenceFdKHR vkGetFenceFdKHR; +extern PFN_vkImportFenceFdKHR vkImportFenceFdKHR; +#endif /* defined(VK_KHR_external_fence_fd) */ +#if defined(VK_KHR_external_fence_win32) +extern PFN_vkGetFenceWin32HandleKHR vkGetFenceWin32HandleKHR; +extern PFN_vkImportFenceWin32HandleKHR vkImportFenceWin32HandleKHR; +#endif /* defined(VK_KHR_external_fence_win32) */ +#if defined(VK_KHR_external_memory_capabilities) +extern PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR vkGetPhysicalDeviceExternalBufferPropertiesKHR; +#endif /* defined(VK_KHR_external_memory_capabilities) */ +#if defined(VK_KHR_external_memory_fd) +extern PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR; +extern PFN_vkGetMemoryFdPropertiesKHR vkGetMemoryFdPropertiesKHR; +#endif /* defined(VK_KHR_external_memory_fd) */ +#if defined(VK_KHR_external_memory_win32) +extern PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32HandleKHR; +extern PFN_vkGetMemoryWin32HandlePropertiesKHR vkGetMemoryWin32HandlePropertiesKHR; +#endif /* defined(VK_KHR_external_memory_win32) */ +#if defined(VK_KHR_external_semaphore_capabilities) +extern PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR vkGetPhysicalDeviceExternalSemaphorePropertiesKHR; +#endif /* defined(VK_KHR_external_semaphore_capabilities) */ +#if defined(VK_KHR_external_semaphore_fd) +extern PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR; +extern PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR; +#endif /* defined(VK_KHR_external_semaphore_fd) */ +#if defined(VK_KHR_external_semaphore_win32) +extern PFN_vkGetSemaphoreWin32HandleKHR vkGetSemaphoreWin32HandleKHR; +extern PFN_vkImportSemaphoreWin32HandleKHR vkImportSemaphoreWin32HandleKHR; +#endif /* defined(VK_KHR_external_semaphore_win32) */ +#if defined(VK_KHR_get_display_properties2) +extern PFN_vkGetDisplayModeProperties2KHR vkGetDisplayModeProperties2KHR; +extern PFN_vkGetDisplayPlaneCapabilities2KHR vkGetDisplayPlaneCapabilities2KHR; +extern PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR vkGetPhysicalDeviceDisplayPlaneProperties2KHR; +extern PFN_vkGetPhysicalDeviceDisplayProperties2KHR vkGetPhysicalDeviceDisplayProperties2KHR; +#endif /* defined(VK_KHR_get_display_properties2) */ +#if defined(VK_KHR_get_memory_requirements2) +extern PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; +extern PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; +extern PFN_vkGetImageSparseMemoryRequirements2KHR vkGetImageSparseMemoryRequirements2KHR; +#endif /* defined(VK_KHR_get_memory_requirements2) */ +#if defined(VK_KHR_get_physical_device_properties2) +extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; +extern PFN_vkGetPhysicalDeviceFormatProperties2KHR vkGetPhysicalDeviceFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceImageFormatProperties2KHR vkGetPhysicalDeviceImageFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceMemoryProperties2KHR vkGetPhysicalDeviceMemoryProperties2KHR; +extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; +extern PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR vkGetPhysicalDeviceQueueFamilyProperties2KHR; +extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR vkGetPhysicalDeviceSparseImageFormatProperties2KHR; +#endif /* defined(VK_KHR_get_physical_device_properties2) */ +#if defined(VK_KHR_get_surface_capabilities2) +extern PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR; +#endif /* defined(VK_KHR_get_surface_capabilities2) */ +#if defined(VK_KHR_maintenance1) +extern PFN_vkTrimCommandPoolKHR vkTrimCommandPoolKHR; +#endif /* defined(VK_KHR_maintenance1) */ +#if defined(VK_KHR_maintenance3) +extern PFN_vkGetDescriptorSetLayoutSupportKHR vkGetDescriptorSetLayoutSupportKHR; +#endif /* defined(VK_KHR_maintenance3) */ +#if defined(VK_KHR_performance_query) +extern PFN_vkAcquireProfilingLockKHR vkAcquireProfilingLockKHR; +extern PFN_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR; +extern PFN_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR; +extern PFN_vkReleaseProfilingLockKHR vkReleaseProfilingLockKHR; +#endif /* defined(VK_KHR_performance_query) */ +#if defined(VK_KHR_pipeline_executable_properties) +extern PFN_vkGetPipelineExecutableInternalRepresentationsKHR vkGetPipelineExecutableInternalRepresentationsKHR; +extern PFN_vkGetPipelineExecutablePropertiesKHR vkGetPipelineExecutablePropertiesKHR; +extern PFN_vkGetPipelineExecutableStatisticsKHR vkGetPipelineExecutableStatisticsKHR; +#endif /* defined(VK_KHR_pipeline_executable_properties) */ +#if defined(VK_KHR_push_descriptor) +extern PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR; +#endif /* defined(VK_KHR_push_descriptor) */ +#if defined(VK_KHR_ray_tracing) +extern PFN_vkBindAccelerationStructureMemoryKHR vkBindAccelerationStructureMemoryKHR; +extern PFN_vkBuildAccelerationStructureKHR vkBuildAccelerationStructureKHR; +extern PFN_vkCmdBuildAccelerationStructureIndirectKHR vkCmdBuildAccelerationStructureIndirectKHR; +extern PFN_vkCmdBuildAccelerationStructureKHR vkCmdBuildAccelerationStructureKHR; +extern PFN_vkCmdCopyAccelerationStructureKHR vkCmdCopyAccelerationStructureKHR; +extern PFN_vkCmdCopyAccelerationStructureToMemoryKHR vkCmdCopyAccelerationStructureToMemoryKHR; +extern PFN_vkCmdCopyMemoryToAccelerationStructureKHR vkCmdCopyMemoryToAccelerationStructureKHR; +extern PFN_vkCmdTraceRaysIndirectKHR vkCmdTraceRaysIndirectKHR; +extern PFN_vkCmdTraceRaysKHR vkCmdTraceRaysKHR; +extern PFN_vkCmdWriteAccelerationStructuresPropertiesKHR vkCmdWriteAccelerationStructuresPropertiesKHR; +extern PFN_vkCopyAccelerationStructureKHR vkCopyAccelerationStructureKHR; +extern PFN_vkCopyAccelerationStructureToMemoryKHR vkCopyAccelerationStructureToMemoryKHR; +extern PFN_vkCopyMemoryToAccelerationStructureKHR vkCopyMemoryToAccelerationStructureKHR; +extern PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructureKHR; +extern PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelinesKHR; +extern PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructureKHR; +extern PFN_vkGetAccelerationStructureDeviceAddressKHR vkGetAccelerationStructureDeviceAddressKHR; +extern PFN_vkGetAccelerationStructureMemoryRequirementsKHR vkGetAccelerationStructureMemoryRequirementsKHR; +extern PFN_vkGetDeviceAccelerationStructureCompatibilityKHR vkGetDeviceAccelerationStructureCompatibilityKHR; +extern PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR vkGetRayTracingCaptureReplayShaderGroupHandlesKHR; +extern PFN_vkGetRayTracingShaderGroupHandlesKHR vkGetRayTracingShaderGroupHandlesKHR; +extern PFN_vkWriteAccelerationStructuresPropertiesKHR vkWriteAccelerationStructuresPropertiesKHR; +#endif /* defined(VK_KHR_ray_tracing) */ +#if defined(VK_KHR_sampler_ycbcr_conversion) +extern PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR; +extern PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR; +#endif /* defined(VK_KHR_sampler_ycbcr_conversion) */ +#if defined(VK_KHR_shared_presentable_image) +extern PFN_vkGetSwapchainStatusKHR vkGetSwapchainStatusKHR; +#endif /* defined(VK_KHR_shared_presentable_image) */ +#if defined(VK_KHR_surface) +extern PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; +extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; +extern PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; +extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; +#endif /* defined(VK_KHR_surface) */ +#if defined(VK_KHR_swapchain) +extern PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; +extern PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; +extern PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; +extern PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; +extern PFN_vkQueuePresentKHR vkQueuePresentKHR; +#endif /* defined(VK_KHR_swapchain) */ +#if defined(VK_KHR_timeline_semaphore) +extern PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR; +extern PFN_vkSignalSemaphoreKHR vkSignalSemaphoreKHR; +extern PFN_vkWaitSemaphoresKHR vkWaitSemaphoresKHR; +#endif /* defined(VK_KHR_timeline_semaphore) */ +#if defined(VK_KHR_wayland_surface) +extern PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR; +extern PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR; +#endif /* defined(VK_KHR_wayland_surface) */ +#if defined(VK_KHR_win32_surface) +extern PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR; +extern PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR; +#endif /* defined(VK_KHR_win32_surface) */ +#if defined(VK_KHR_xcb_surface) +extern PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR; +extern PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR; +#endif /* defined(VK_KHR_xcb_surface) */ +#if defined(VK_KHR_xlib_surface) +extern PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR; +extern PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR; +#endif /* defined(VK_KHR_xlib_surface) */ +#if defined(VK_MVK_ios_surface) +extern PFN_vkCreateIOSSurfaceMVK vkCreateIOSSurfaceMVK; +#endif /* defined(VK_MVK_ios_surface) */ +#if defined(VK_MVK_macos_surface) +extern PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK; +#endif /* defined(VK_MVK_macos_surface) */ +#if defined(VK_NN_vi_surface) +extern PFN_vkCreateViSurfaceNN vkCreateViSurfaceNN; +#endif /* defined(VK_NN_vi_surface) */ +#if defined(VK_NVX_image_view_handle) +extern PFN_vkGetImageViewAddressNVX vkGetImageViewAddressNVX; +extern PFN_vkGetImageViewHandleNVX vkGetImageViewHandleNVX; +#endif /* defined(VK_NVX_image_view_handle) */ +#if defined(VK_NV_clip_space_w_scaling) +extern PFN_vkCmdSetViewportWScalingNV vkCmdSetViewportWScalingNV; +#endif /* defined(VK_NV_clip_space_w_scaling) */ +#if defined(VK_NV_cooperative_matrix) +extern PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV vkGetPhysicalDeviceCooperativeMatrixPropertiesNV; +#endif /* defined(VK_NV_cooperative_matrix) */ +#if defined(VK_NV_coverage_reduction_mode) +extern PFN_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV; +#endif /* defined(VK_NV_coverage_reduction_mode) */ +#if defined(VK_NV_device_diagnostic_checkpoints) +extern PFN_vkCmdSetCheckpointNV vkCmdSetCheckpointNV; +extern PFN_vkGetQueueCheckpointDataNV vkGetQueueCheckpointDataNV; +#endif /* defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_NV_device_generated_commands) +extern PFN_vkCmdBindPipelineShaderGroupNV vkCmdBindPipelineShaderGroupNV; +extern PFN_vkCmdExecuteGeneratedCommandsNV vkCmdExecuteGeneratedCommandsNV; +extern PFN_vkCmdPreprocessGeneratedCommandsNV vkCmdPreprocessGeneratedCommandsNV; +extern PFN_vkCreateIndirectCommandsLayoutNV vkCreateIndirectCommandsLayoutNV; +extern PFN_vkDestroyIndirectCommandsLayoutNV vkDestroyIndirectCommandsLayoutNV; +extern PFN_vkGetGeneratedCommandsMemoryRequirementsNV vkGetGeneratedCommandsMemoryRequirementsNV; +#endif /* defined(VK_NV_device_generated_commands) */ +#if defined(VK_NV_external_memory_capabilities) +extern PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV vkGetPhysicalDeviceExternalImageFormatPropertiesNV; +#endif /* defined(VK_NV_external_memory_capabilities) */ +#if defined(VK_NV_external_memory_win32) +extern PFN_vkGetMemoryWin32HandleNV vkGetMemoryWin32HandleNV; +#endif /* defined(VK_NV_external_memory_win32) */ +#if defined(VK_NV_mesh_shader) +extern PFN_vkCmdDrawMeshTasksIndirectCountNV vkCmdDrawMeshTasksIndirectCountNV; +extern PFN_vkCmdDrawMeshTasksIndirectNV vkCmdDrawMeshTasksIndirectNV; +extern PFN_vkCmdDrawMeshTasksNV vkCmdDrawMeshTasksNV; +#endif /* defined(VK_NV_mesh_shader) */ +#if defined(VK_NV_ray_tracing) +extern PFN_vkBindAccelerationStructureMemoryNV vkBindAccelerationStructureMemoryNV; +extern PFN_vkCmdBuildAccelerationStructureNV vkCmdBuildAccelerationStructureNV; +extern PFN_vkCmdCopyAccelerationStructureNV vkCmdCopyAccelerationStructureNV; +extern PFN_vkCmdTraceRaysNV vkCmdTraceRaysNV; +extern PFN_vkCmdWriteAccelerationStructuresPropertiesNV vkCmdWriteAccelerationStructuresPropertiesNV; +extern PFN_vkCompileDeferredNV vkCompileDeferredNV; +extern PFN_vkCreateAccelerationStructureNV vkCreateAccelerationStructureNV; +extern PFN_vkCreateRayTracingPipelinesNV vkCreateRayTracingPipelinesNV; +extern PFN_vkDestroyAccelerationStructureNV vkDestroyAccelerationStructureNV; +extern PFN_vkGetAccelerationStructureHandleNV vkGetAccelerationStructureHandleNV; +extern PFN_vkGetAccelerationStructureMemoryRequirementsNV vkGetAccelerationStructureMemoryRequirementsNV; +extern PFN_vkGetRayTracingShaderGroupHandlesNV vkGetRayTracingShaderGroupHandlesNV; +#endif /* defined(VK_NV_ray_tracing) */ +#if defined(VK_NV_scissor_exclusive) +extern PFN_vkCmdSetExclusiveScissorNV vkCmdSetExclusiveScissorNV; +#endif /* defined(VK_NV_scissor_exclusive) */ +#if defined(VK_NV_shading_rate_image) +extern PFN_vkCmdBindShadingRateImageNV vkCmdBindShadingRateImageNV; +extern PFN_vkCmdSetCoarseSampleOrderNV vkCmdSetCoarseSampleOrderNV; +extern PFN_vkCmdSetViewportShadingRatePaletteNV vkCmdSetViewportShadingRatePaletteNV; +#endif /* defined(VK_NV_shading_rate_image) */ +#if (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) +extern PFN_vkGetDeviceGroupSurfacePresentModes2EXT vkGetDeviceGroupSurfacePresentModes2EXT; +#endif /* (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) +extern PFN_vkCmdPushDescriptorSetWithTemplateKHR vkCmdPushDescriptorSetWithTemplateKHR; +#endif /* (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) +extern PFN_vkGetDeviceGroupPresentCapabilitiesKHR vkGetDeviceGroupPresentCapabilitiesKHR; +extern PFN_vkGetDeviceGroupSurfacePresentModesKHR vkGetDeviceGroupSurfacePresentModesKHR; +extern PFN_vkGetPhysicalDevicePresentRectanglesKHR vkGetPhysicalDevicePresentRectanglesKHR; +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) +extern PFN_vkAcquireNextImage2KHR vkAcquireNextImage2KHR; +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ +/* VOLK_GENERATE_PROTOTYPES_H */ + +#ifdef __cplusplus +} +#endif + +#endif + +#ifdef VOLK_IMPLEMENTATION +#undef VOLK_IMPLEMENTATION +// Prevent tools like dependency checkers that don't evaluate +// macros from detecting a cyclic dependency. +#define VOLK_SOURCE "volk.c" +#include VOLK_SOURCE +#endif + +/** + * Copyright (c) 2018-2019 Arseny Kapoulkine + * + * 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. +*/ +/* clang-format on */