mirror of
https://github.com/yquake2/ref_gl4.git
synced 2024-12-04 01:52:06 +00:00
Add the OpenGL 4.6 renderer for YQ2
This commit is contained in:
commit
a10924a14f
47 changed files with 40809 additions and 0 deletions
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
/build/
|
||||
/release/
|
||||
*.mk
|
||||
*.user
|
||||
*.d
|
295
CMakeLists.txt
Normal file
295
CMakeLists.txt
Normal file
|
@ -0,0 +1,295 @@
|
|||
cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
|
||||
|
||||
# Print a message that using the Makefiles is recommended.
|
||||
message(NOTICE: " The CMakeLists.txt is unmaintained. Use the Makefile if possible.")
|
||||
|
||||
# Enforce "Debug" as standard build type.
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
|
||||
endif()
|
||||
|
||||
# CMake project configuration.
|
||||
project(yquake2 C)
|
||||
|
||||
# Cmake module search path.
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/stuff/cmake/modules ${CMAKE_MODULE_PATH})
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED OFF)
|
||||
|
||||
if(YQUAKE2LIBS)
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
set(CMAKE_FIND_ROOT_PATH ${YQUAKE2LIBS})
|
||||
else()
|
||||
set(ENV{CMAKE_PREFIX_PATH} ${YQUAKE2LIBS})
|
||||
endif()
|
||||
|
||||
set(ENV{SDL2DIR} ${YQUAKE2LIBS})
|
||||
endif()
|
||||
|
||||
# Add extended path for FreeBSD and Homebrew on OS X.
|
||||
list(APPEND CMAKE_PREFIX_PATH /usr/local)
|
||||
|
||||
if (MSVC)
|
||||
add_compile_options(/MP) # parallel build (use all cores, or as many as configured in VS)
|
||||
|
||||
# ignore some compiler warnings
|
||||
add_compile_options(/wd4244 /wd4305) # possible loss of data/truncation (double to float etc; ignore)
|
||||
add_compile_options(/wd4018) # signed/unsigned missmatch
|
||||
add_compile_options(/wd4996) # 'function': was declared deprecated (like all that secure CRT stuff)
|
||||
# don't show me warnings for system headers, why the fuck isn't this default
|
||||
add_compile_options(/experimental:external /external:W0)
|
||||
else() # GCC/clang/mingw
|
||||
# Enforce compiler flags:
|
||||
# -Wall -> More warnings
|
||||
# -fno-strict-aliasing -> Quake 2 is far away from strict aliasing
|
||||
# -fwrapv -> Make signed integer overflows defined
|
||||
# -fvisibility=hidden -> Force defaultsymbol visibility to hidden
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fno-strict-aliasing -fwrapv -fvisibility=hidden")
|
||||
|
||||
# Use -O2 as maximum optimization level. -O3 has it's problems with yquake2.
|
||||
string(REPLACE "-O3" "-O2" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
|
||||
endif() # MSVC'S else-case
|
||||
|
||||
# Switch off some annoying warnings
|
||||
if (${CMAKE_C_COMPILER_ID} STREQUAL "Clang")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-missing-braces")
|
||||
elseif (${CMAKE_C_COMPILER_ID} STREQUAL "GNU")
|
||||
if (CMAKE_C_COMPILER_VERSION GREATER 7.99)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format-truncation -Wno-format-overflow")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(SYSTEMDIR "" CACHE STRING "Override the system default directory")
|
||||
|
||||
# These variables will act as our list of include folders and linker flags.
|
||||
set(yquake2OpenGLLinkerFlags)
|
||||
set(yquake2SDLLinkerFlags)
|
||||
|
||||
# Set directory locations (allowing us to move directories easily)
|
||||
set(SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/src)
|
||||
set(REF_SRC_DIR ${SOURCE_DIR}/client/refresh)
|
||||
|
||||
# Operating system.
|
||||
set(YQ2OSTYPE "${CMAKE_SYSTEM_NAME}" CACHE STRING "Override operation system type")
|
||||
add_definitions(-DYQ2OSTYPE="${YQ2OSTYPE}")
|
||||
|
||||
# Architecture string
|
||||
# work around CMake's useless/broken CMAKE_SYSTEM_PROCESSOR (taken from dhewm3)
|
||||
|
||||
set(cpu ${CMAKE_SYSTEM_PROCESSOR})
|
||||
|
||||
# Originally, ${CMAKE_SYSTEM_PROCESSOR} was supposed to contain the *target* CPU, according to CMake's documentation.
|
||||
# As far as I can tell this has always been broken (always returns host CPU) at least on Windows
|
||||
# (see e.g. https://cmake.org/pipermail/cmake-developers/2014-September/011405.html) and wasn't reliable on
|
||||
# other systems either, for example on Linux with 32bit userland but 64bit kernel it returned the kernel CPU type
|
||||
# (e.g. x86_64 instead of i686). Instead of fixing this, CMake eventually updated their documentation in 3.20,
|
||||
# now it's officially the same as CMAKE_HOST_SYSTEM_PROCESSOR except when cross-compiling (where it's explicitly set)
|
||||
# So we gotta figure out the actual target CPU type ourselves..
|
||||
if(NOT (CMAKE_SYSTEM_PROCESSOR STREQUAL CMAKE_HOST_SYSTEM_PROCESSOR))
|
||||
# special case: cross-compiling, here CMAKE_SYSTEM_PROCESSOR should be correct, hopefully
|
||||
# (just leave cpu at ${CMAKE_SYSTEM_PROCESSOR})
|
||||
elseif(MSVC)
|
||||
# because all this wasn't ugly enough, it turned out that, unlike standalone CMake, Visual Studio's
|
||||
# integrated CMake doesn't set CMAKE_GENERATOR_PLATFORM, so I gave up on guessing the CPU arch here
|
||||
# and moved the CPU detection to MSVC-specific code in neo/sys/platform.h
|
||||
else() # not MSVC and not cross-compiling, assume GCC or clang (-compatible), seems to work for MinGW as well
|
||||
execute_process(COMMAND ${CMAKE_C_COMPILER} "-dumpmachine"
|
||||
RESULT_VARIABLE cc_dumpmachine_res
|
||||
OUTPUT_VARIABLE cc_dumpmachine_out)
|
||||
if(cc_dumpmachine_res EQUAL 0)
|
||||
string(STRIP ${cc_dumpmachine_out} cc_dumpmachine_out) # get rid of trailing newline
|
||||
message(DEBUG "`${CMAKE_C_COMPILER} -dumpmachine` says: \"${cc_dumpmachine_out}\"")
|
||||
# gcc -dumpmachine and clang -dumpmachine seem to print something like "x86_64-linux-gnu" (gcc)
|
||||
# or "x64_64-pc-linux-gnu" (clang) or "i686-w64-mingw32" (32bit mingw-w64) i.e. starting with the CPU,
|
||||
# then "-" and then OS or whatever - so use everything up to first "-"
|
||||
string(REGEX MATCH "^[^-]+" cpu ${cc_dumpmachine_out})
|
||||
message(DEBUG " => CPU architecture extracted from that: \"${cpu}\"")
|
||||
else()
|
||||
message(WARNING "${CMAKE_C_COMPILER} -dumpmachine failed with error (code) ${cc_dumpmachine_res}")
|
||||
message(WARNING "will use the (sometimes incorrect) CMAKE_SYSTEM_PROCESSOR (${cpu}) to determine YQ2ARCH")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(cpu STREQUAL "powerpc")
|
||||
set(cpu "ppc")
|
||||
elseif(cpu STREQUAL "aarch64")
|
||||
# "arm64" is more obvious, and some operating systems (like macOS) use it instead of "aarch64"
|
||||
set(cpu "arm64")
|
||||
elseif(cpu MATCHES "[aA][mM][dD]64" OR cpu MATCHES "[xX].*64")
|
||||
set(cpu "x86_64")
|
||||
elseif(cpu MATCHES "i.86" OR cpu MATCHES "[xX]86")
|
||||
set(cpu "i386")
|
||||
elseif(cpu MATCHES "[aA][rR][mM].*") # some kind of arm..
|
||||
# On 32bit Raspbian gcc -dumpmachine returns sth starting with "arm-",
|
||||
# while clang -dumpmachine says "arm6k-..." - try to unify that to "arm"
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8) # sizeof(void*) == 8 => must be arm64
|
||||
set(cpu "arm64")
|
||||
else() # should be 32bit arm then (probably "armv7l" "armv6k" or sth like that)
|
||||
set(cpu "arm")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
# for MSVC YQ2ARCH is set in code (in src/common/header/common.h)
|
||||
message(STATUS "Setting YQ2OSTYPE to \"${YQ2OSTYPE}\" - NOT setting YQ2ARCH, because we're targeting MSVC (VisualC++)")
|
||||
else()
|
||||
set(ARCH "${cpu}")
|
||||
add_definitions(-DYQ2ARCH="${ARCH}")
|
||||
message(STATUS "Setting YQ2OSTYPE to \"${YQ2OSTYPE}\" and YQ2ARCH to \"${ARCH}\".")
|
||||
endif()
|
||||
# make sure that ${cpu} isn't used below - if at all use ${ARCH}, but not when compiling with MSVC!
|
||||
unset(cpu)
|
||||
|
||||
# END OF workarounds for CMake's poor choices regarding CPU architecture detection
|
||||
|
||||
|
||||
# Systemwide installation of game assets.
|
||||
if(${SYSTEMWIDE_SUPPORT})
|
||||
add_definitions(-DSYSTEMWIDE)
|
||||
if(NOT ${SYSTEMDIR} STREQUAL "")
|
||||
add_definitions(-DSYSTEMDIR="${SYSTEMDIR}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# We need to pass some options to minizip / unzip.
|
||||
add_definitions(-DNOUNCRYPT)
|
||||
|
||||
if(NOT (CMAKE_SYSTEM_NAME MATCHES "Linux") AND NOT (CMAKE_SYSTEM_NAME MATCHES "Windows"))
|
||||
add_definitions(-DIOAPI_NO_64)
|
||||
endif()
|
||||
|
||||
# Required libraries to build the different components of the binaries. Find
|
||||
# them and add the include/linker directories and flags (in case the package
|
||||
# manager find it in a weird place).
|
||||
find_package(SDL2 REQUIRED)
|
||||
list(APPEND yquake2IncludeDirectories "${SDL2_INCLUDE_DIR}/..")
|
||||
list(APPEND yquake2SDLLinkerFlags ${SDL2_LIBRARY})
|
||||
|
||||
# We need an OpenGL implementation.
|
||||
set(OpenGL_GL_PREFERENCE GLVND)
|
||||
find_package(OpenGL REQUIRED)
|
||||
list(APPEND yquake2IncludeDirectories ${OPENGL_INCLUDE_DIR})
|
||||
list(APPEND yquake2OpenGLLinkerFlags ${OPENGL_LIBRARIES})
|
||||
|
||||
# General linker flags.
|
||||
if(NOT MSVC)
|
||||
list(APPEND yquake2LinkerFlags m)
|
||||
endif()
|
||||
list(APPEND yquake2LinkerFlags ${CMAKE_DL_LIBS})
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||
if(!MSVC)
|
||||
list(APPEND yquake2LinkerFlags "-static-libgcc")
|
||||
endif()
|
||||
else()
|
||||
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
|
||||
list(APPEND yquake2LinkerFlags "-rdynamic")
|
||||
else()
|
||||
list(APPEND yquake2LinkerFlags "-lnetwork")
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
endif()
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
|
||||
list(APPEND yquake2LinkerFlags "-lsocket -lnsl")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD" AND NOT WIN32)
|
||||
list(APPEND yquake2LinkerFlags "-Wl,--no-undefined")
|
||||
endif()
|
||||
|
||||
# With all of those libraries and user defined paths
|
||||
# added, lets give them to the compiler and linker.
|
||||
include_directories(${yquake2IncludeDirectories})
|
||||
link_directories(${yquake2LinkerDirectories})
|
||||
|
||||
# these settings only work for GCC and clang
|
||||
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||
# If we're building with gcc for i386 let's define -ffloat-store.
|
||||
# This helps the old and crappy x87 FPU to produce correct values.
|
||||
# Would be nice if Clang had something comparable.
|
||||
if ("${ARCH}" STREQUAL "i386" AND ${CMAKE_C_COMPILER_ID} STREQUAL "GNU")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffloat-store")
|
||||
endif()
|
||||
|
||||
# Force SSE math on x86_64. All sane compilers should do this
|
||||
# anyway, just to protect us from broken Linux distros.
|
||||
if ("${ARCH}" STREQUAL "x86_64")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpmath=sse")
|
||||
endif()
|
||||
|
||||
if ("${ARCH}" STREQUAL "arm")
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv6k")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||
set(REF-Windows-Source
|
||||
${SOURCE_DIR}/backends/windows/shared/hunk.c
|
||||
)
|
||||
else()
|
||||
set(REF-Unix-Source
|
||||
${SOURCE_DIR}/backends/unix/shared/hunk.c
|
||||
)
|
||||
endif()
|
||||
|
||||
set(GL4-Source
|
||||
${REF_SRC_DIR}/gl4/gl4_draw.c
|
||||
${REF_SRC_DIR}/gl4/gl4_image.c
|
||||
${REF_SRC_DIR}/gl4/gl4_light.c
|
||||
${REF_SRC_DIR}/gl4/gl4_lightmap.c
|
||||
${REF_SRC_DIR}/gl4/gl4_main.c
|
||||
${REF_SRC_DIR}/gl4/gl4_mesh.c
|
||||
${REF_SRC_DIR}/gl4/gl4_misc.c
|
||||
${REF_SRC_DIR}/gl4/gl4_model.c
|
||||
${REF_SRC_DIR}/gl4/gl4_sdl.c
|
||||
${REF_SRC_DIR}/gl4/gl4_surf.c
|
||||
${REF_SRC_DIR}/gl4/gl4_warp.c
|
||||
${REF_SRC_DIR}/gl4/gl4_shaders.c
|
||||
${REF_SRC_DIR}/files/models.c
|
||||
${REF_SRC_DIR}/files/pcx.c
|
||||
${REF_SRC_DIR}/files/stb.c
|
||||
${REF_SRC_DIR}/files/surf.c
|
||||
${REF_SRC_DIR}/files/wal.c
|
||||
${REF_SRC_DIR}/files/pvs.c
|
||||
${SOURCE_DIR}/common/shared/shared.c
|
||||
${SOURCE_DIR}/common/md4.c
|
||||
)
|
||||
|
||||
set(Glad-GL4-Source ${REF_SRC_DIR}/gl4/glad/src/glad.c)
|
||||
|
||||
set(GL4-Header
|
||||
${REF_SRC_DIR}/ref_shared.h
|
||||
${REF_SRC_DIR}/constants/anorms.h
|
||||
${REF_SRC_DIR}/constants/anormtab.h
|
||||
${REF_SRC_DIR}/constants/warpsin.h
|
||||
${REF_SRC_DIR}/files/stb_image.h
|
||||
${REF_SRC_DIR}/gl4/header/DG_dynarr.h
|
||||
${REF_SRC_DIR}/gl4/header/HandmadeMath.h
|
||||
${REF_SRC_DIR}/gl4/header/local.h
|
||||
${REF_SRC_DIR}/gl4/header/model.h
|
||||
${SOURCE_DIR}/common/header/shared.h
|
||||
)
|
||||
|
||||
set(Glad-GL4-Header
|
||||
${REF_SRC_DIR}/gl4/glad/include/glad/glad.h
|
||||
${REF_SRC_DIR}/gl4/glad/include/KHR/khrplatform.h
|
||||
)
|
||||
|
||||
# Build the GL4 dynamic library
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||
add_library(ref_gl4 MODULE ${GL4-Source} ${Glad-GL4-Source} ${GL4-Header} ${Glad-GL4-Header} ${REF-Windows-Source})
|
||||
else()
|
||||
add_library(ref_gl4 MODULE ${GL4-Source} ${Glad-GL4-Source} ${GL4-Header} ${Glad-GL4-Header} ${REF-Unix-Source})
|
||||
endif()
|
||||
|
||||
set_target_properties(ref_gl4 PROPERTIES
|
||||
PREFIX ""
|
||||
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release
|
||||
SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}
|
||||
)
|
||||
target_include_directories(ref_gl4 PRIVATE ${CMAKE_SOURCE_DIR}/src/client/refresh/gl4/glad/include)
|
||||
target_link_libraries(ref_gl4 ${yquake2LinkerFlags} ${yquake2SDLLinkerFlags})
|
515
LICENSE
Normal file
515
LICENSE
Normal file
|
@ -0,0 +1,515 @@
|
|||
Yamagi Quake II contains software developed by multiple individuals,
|
||||
projects and organisations. Following is a list of this software and
|
||||
copys of each license:
|
||||
|
||||
- Quake II
|
||||
- Info-ZIP
|
||||
- Cocoa SDL entry points
|
||||
- stb_image.h, stb_image_write.h, stb_image_resize.h, stb_vorbis.h
|
||||
- miniz
|
||||
|
||||
Parts of other Quake II Clients were included into the source. They're
|
||||
covered by the same GPLv2 license as Quake II itself:
|
||||
|
||||
- Hecatomb
|
||||
- Icculus Quake 2
|
||||
- KMQuake2
|
||||
- Q2Pro
|
||||
- QuDoS
|
||||
- r1q2
|
||||
- stereo quake
|
||||
- zeq2
|
||||
|
||||
The following code is used in library form and thus not part of Yamagi
|
||||
Quake II:
|
||||
|
||||
- cURL
|
||||
- libGL
|
||||
- libopenal
|
||||
- SDL
|
||||
|
||||
===============================================================================
|
||||
|
||||
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.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
|
||||
===============================================================================
|
||||
|
||||
This is version 2009-Jan-02 of the Info-ZIP license.
|
||||
The definitive version of this document should be available at
|
||||
ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely and
|
||||
a copy at http://www.info-zip.org/pub/infozip/license.html.
|
||||
|
||||
|
||||
Copyright (c) 1990-2010 Info-ZIP. All rights reserved.
|
||||
|
||||
For the purposes of this copyright and license, "Info-ZIP" is defined as
|
||||
the following set of individuals:
|
||||
|
||||
Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois,
|
||||
Jean-loup Gailly, Hunter Goatley, Ed Gordon, Ian Gorman, Chris Herborth,
|
||||
Dirk Haase, Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz,
|
||||
David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko,
|
||||
Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs,
|
||||
Kai Uwe Rommel, Steve Salisbury, Dave Smith, Steven M. Schweda,
|
||||
Christian Spieler, Cosmin Truta, Antoine Verheijen, Paul von Behren,
|
||||
Rich Wales, Mike White.
|
||||
|
||||
This software is provided "as is," without warranty of any kind, express
|
||||
or implied. In no event shall Info-ZIP or its contributors be held liable
|
||||
for any direct, indirect, incidental, special or consequential damages
|
||||
arising out of the use of or inability to use this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the above disclaimer and the following restrictions:
|
||||
|
||||
1. Redistributions of source code (in whole or in part) must retain
|
||||
the above copyright notice, definition, disclaimer, and this list
|
||||
of conditions.
|
||||
|
||||
2. Redistributions in binary form (compiled executables and libraries)
|
||||
must reproduce the above copyright notice, definition, disclaimer,
|
||||
and this list of conditions in documentation and/or other materials
|
||||
provided with the distribution. Additional documentation is not needed
|
||||
for executables where a command line license option provides these and
|
||||
a note regarding this option is in the executable's startup banner. The
|
||||
sole exception to this condition is redistribution of a standard
|
||||
UnZipSFX binary (including SFXWiz) as part of a self-extracting archive;
|
||||
that is permitted without inclusion of this license, as long as the
|
||||
normal SFX banner has not been removed from the binary or disabled.
|
||||
|
||||
3. Altered versions--including, but not limited to, ports to new operating
|
||||
systems, existing ports with new graphical interfaces, versions with
|
||||
modified or added functionality, and dynamic, shared, or static library
|
||||
versions not from Info-ZIP--must be plainly marked as such and must not
|
||||
be misrepresented as being the original source or, if binaries,
|
||||
compiled from the original source. Such altered versions also must not
|
||||
be misrepresented as being Info-ZIP releases--including, but not
|
||||
limited to, labeling of the altered versions with the names "Info-ZIP"
|
||||
(or any variation thereof, including, but not limited to, different
|
||||
capitalizations), "Pocket UnZip," "WiZ" or "MacZip" without the
|
||||
explicit permission of Info-ZIP. Such altered versions are further
|
||||
prohibited from misrepresentative use of the Zip-Bugs or Info-ZIP
|
||||
e-mail addresses or the Info-ZIP URL(s), such as to imply Info-ZIP
|
||||
will provide support for the altered versions.
|
||||
|
||||
4. Info-ZIP retains the right to use the names "Info-ZIP," "Zip," "UnZip,"
|
||||
"UnZipSFX," "WiZ," "Pocket UnZip," "Pocket Zip," and "MacZip" for its
|
||||
own source and binary releases.
|
||||
|
||||
===============================================================================
|
||||
|
||||
Main entry point for our Cocoa-ized SDL app
|
||||
Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
|
||||
Non-NIB-Code & other changes: Max Horn <max@quendi.de>
|
||||
|
||||
Feel free to customize this file to suit your needs
|
||||
|
||||
===============================================================================
|
||||
|
||||
stb single-file public domain libraries
|
||||
(stb_image.h, stb_image_resize.h, stb_image_write.h, stb_vorbis.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.
|
||||
|
||||
===============================================================================
|
||||
|
||||
Copyright 2013-2014 RAD Game Tools and Valve Software
|
||||
Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
|
||||
All Rights Reserved.
|
||||
|
||||
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.
|
||||
|
||||
===============================================================================
|
478
Makefile
Normal file
478
Makefile
Normal file
|
@ -0,0 +1,478 @@
|
|||
# ------------------------------------------------------ #
|
||||
# Makefile for the OpenGL 4.6 renderer lib for Quake II #
|
||||
# #
|
||||
# Just type "make" to compile the #
|
||||
# - OpenGL 4.6 renderer lib (ref_gl4.so / rev_gl4.dll) #
|
||||
# #
|
||||
# Dependencies: #
|
||||
# - SDL 2.0 #
|
||||
# - libGL #
|
||||
# #
|
||||
# Platforms: #
|
||||
# - FreeBSD #
|
||||
# - Linux #
|
||||
# - NetBSD #
|
||||
# - OpenBSD #
|
||||
# - Windows #
|
||||
# ------------------------------------------------------ #
|
||||
|
||||
# Variables
|
||||
# ---------
|
||||
|
||||
# - ASAN: Builds with address sanitizer, includes DEBUG.
|
||||
# - DEBUG: Builds a debug build, forces -O0 and adds debug symbols.
|
||||
# - VERBOSE: Prints full compile, linker and misc commands.
|
||||
# - UBSAN: Builds with undefined behavior sanitizer, includes DEBUG.
|
||||
|
||||
# ----------
|
||||
|
||||
# User configurable options
|
||||
# -------------------------
|
||||
|
||||
# Enables HTTP support through cURL. Used for
|
||||
# HTTP download.
|
||||
WITH_CURL:=yes
|
||||
|
||||
# Enables the optional OpenAL sound system.
|
||||
# To use it your system needs libopenal.so.1
|
||||
# or openal32.dll (we recommend openal-soft)
|
||||
# installed
|
||||
WITH_OPENAL:=yes
|
||||
|
||||
# Sets an RPATH to $ORIGIN/lib. It can be used to
|
||||
# inject custom libraries, e.g. a patches libSDL.so
|
||||
# or libopenal.so. Not supported on Windows.
|
||||
WITH_RPATH:=yes
|
||||
|
||||
# Enable systemwide installation of game assets.
|
||||
WITH_SYSTEMWIDE:=no
|
||||
|
||||
# This will set the default SYSTEMDIR, a non-empty string
|
||||
# would actually be used. On Windows normals slashes (/)
|
||||
# instead of backslashed (\) should be used! The string
|
||||
# MUST NOT be surrounded by quotation marks!
|
||||
WITH_SYSTEMDIR:=""
|
||||
|
||||
# This will set the build options to create an MacOS .app-bundle.
|
||||
# The app-bundle itself will not be created, but the runtime paths
|
||||
# will be set to expect the game-data in *.app/
|
||||
# Contents/Resources
|
||||
OSX_APP:=yes
|
||||
|
||||
# This is an optional configuration file, it'll be used in
|
||||
# case of presence.
|
||||
CONFIG_FILE:=config.mk
|
||||
|
||||
# ----------
|
||||
|
||||
# In case a of a configuration file being present, we'll just use it
|
||||
ifeq ($(wildcard $(CONFIG_FILE)), $(CONFIG_FILE))
|
||||
include $(CONFIG_FILE)
|
||||
endif
|
||||
|
||||
# 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
|
||||
ifneq ($(YQ2_OSTYPE), Darwin)
|
||||
# Normalize some abiguous YQ2_ARCH strings
|
||||
YQ2_ARCH ?= $(shell uname -m | sed -e 's/i.86/i386/' -e 's/amd64/x86_64/' -e 's/arm64/aarch64/' -e 's/^arm.*/arm/')
|
||||
else
|
||||
YQ2_ARCH ?= $(shell uname -m)
|
||||
endif
|
||||
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
|
||||
override CFLAGS += -fsanitize=address -DUSE_SANITIZER
|
||||
endif
|
||||
ifdef UBSAN
|
||||
override CFLAGS += -fsanitize=undefined -DUSE_SANITIZER
|
||||
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 += -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
|
||||
|
||||
# ----------
|
||||
|
||||
# ARM needs a sane minimum architecture. We need the `yield`
|
||||
# opcode, arm6k is the first iteration that supports it. arm6k
|
||||
# is also the first Raspberry PI generation and older hardware
|
||||
# is likely too slow to run the game. We're not enforcing the
|
||||
# minimum architecture, but if you're build for something older
|
||||
# like arm5 the `yield` opcode isn't compiled in and the game
|
||||
# (especially q2ded) will consume more CPU time than necessary.
|
||||
ifeq ($(YQ2_ARCH), arm)
|
||||
CFLAGS += -march=armv6k
|
||||
endif
|
||||
|
||||
# ----------
|
||||
|
||||
# Switch of some annoying warnings.
|
||||
ifeq ($(COMPILER), clang)
|
||||
# -Wno-missing-braces because otherwise clang complains
|
||||
# about totally valid 'vec3_t bla = {0}' constructs.
|
||||
override 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.
|
||||
override 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
|
||||
override 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
|
||||
|
||||
# Disable floating-point expression contraction. While this shouldn't be
|
||||
# a problem for C (only for C++) better be safe than sorry. See
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100839 for details.
|
||||
ifeq ($(COMPILER), gcc)
|
||||
override CFLAGS += -ffp-contract=off
|
||||
endif
|
||||
|
||||
# ----------
|
||||
|
||||
# Systemwide installation.
|
||||
ifeq ($(WITH_SYSTEMWIDE),yes)
|
||||
override CFLAGS += -DSYSTEMWIDE
|
||||
ifneq ($(WITH_SYSTEMDIR),"")
|
||||
override CFLAGS += -DSYSTEMDIR=\"$(WITH_SYSTEMDIR)\"
|
||||
endif
|
||||
endif
|
||||
|
||||
# ----------
|
||||
|
||||
# We don't support encrypted ZIP files.
|
||||
ZIPCFLAGS := -DNOUNCRYPT
|
||||
|
||||
# Just set IOAPI_NO_64 on everything that's not Linux or Windows,
|
||||
# otherwise minizip will use fopen64(), fseek64() and friends that
|
||||
# may be unavailable. This is - of course - not really correct, in
|
||||
# a better world we would set -DIOAPI_NO_64 to force everything to
|
||||
# fopen(), fseek() and so on and -D_FILE_OFFSET_BITS=64 to let the
|
||||
# libc headers do their work. Currently we can't do that because
|
||||
# Quake II uses nearly everywere int instead of off_t...
|
||||
#
|
||||
# This may have the side effect that ZIP files larger than 2GB are
|
||||
# unsupported. But I doubt that anyone has such large files, they
|
||||
# would likely hit other internal limits.
|
||||
ifneq ($(YQ2_OSTYPE),Windows)
|
||||
ifneq ($(YQ2_OSTYPE),Linux)
|
||||
ZIPCFLAGS += -DIOAPI_NO_64
|
||||
endif
|
||||
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
|
||||
override LDFLAGS += -fsanitize=address
|
||||
endif
|
||||
|
||||
# Link undefined behavior sanitizer if requested.
|
||||
ifdef UBSAN
|
||||
override LDFLAGS += -fsanitize=undefined
|
||||
endif
|
||||
|
||||
# Required libraries.
|
||||
ifeq ($(YQ2_OSTYPE),Linux)
|
||||
LDLIBS ?= -lm -ldl -rdynamic
|
||||
else ifeq ($(YQ2_OSTYPE),FreeBSD)
|
||||
LDLIBS ?= -lm
|
||||
else ifeq ($(YQ2_OSTYPE),NetBSD)
|
||||
LDLIBS ?= -lm
|
||||
else ifeq ($(YQ2_OSTYPE),OpenBSD)
|
||||
LDLIBS ?= -lm
|
||||
else ifeq ($(YQ2_OSTYPE),Windows)
|
||||
LDLIBS ?= -lws2_32 -lwinmm -static-libgcc
|
||||
else ifeq ($(YQ2_OSTYPE), Darwin)
|
||||
LDLIBS ?= -arch $(YQ2_ARCH)
|
||||
else ifeq ($(YQ2_OSTYPE), Haiku)
|
||||
LDLIBS ?= -lm -lnetwork
|
||||
else ifeq ($(YQ2_OSTYPE), SunOS)
|
||||
LDLIBS ?= -lm -lsocket -lnsl
|
||||
endif
|
||||
|
||||
# ASAN and UBSAN must not be linked
|
||||
# with --no-undefined. OSX and OpenBSD
|
||||
# don't support it at all.
|
||||
ifndef ASAN
|
||||
ifndef UBSAN
|
||||
ifneq ($(YQ2_OSTYPE), Darwin)
|
||||
ifneq ($(YQ2_OSTYPE), OpenBSD)
|
||||
override LDFLAGS += -Wl,--no-undefined
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# ----------
|
||||
|
||||
# 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 ref_gl4
|
||||
|
||||
# ----------
|
||||
|
||||
# Builds everything
|
||||
all: ref_gl4
|
||||
|
||||
# Cleanup
|
||||
clean:
|
||||
@echo "===> CLEAN"
|
||||
${Q}rm -Rf build release/*
|
||||
|
||||
cleanall:
|
||||
@echo "===> CLEAN"
|
||||
${Q}rm -Rf build release
|
||||
|
||||
# ----------
|
||||
|
||||
# The OpenGL 4.6 renderer lib
|
||||
|
||||
ifeq ($(YQ2_OSTYPE), Windows)
|
||||
|
||||
ref_gl4:
|
||||
@echo "===> Building ref_gl4.dll"
|
||||
${Q}mkdir -p release
|
||||
$(MAKE) release/ref_gl4.dll
|
||||
|
||||
release/ref_gl4.dll : GLAD_INCLUDE = -Isrc/client/refresh/gl4/glad/include
|
||||
release/ref_gl4.dll : LDFLAGS += -shared
|
||||
|
||||
else # not Windows or Darwin - macOS doesn't support OpenGL 4.6
|
||||
|
||||
ref_gl4:
|
||||
@echo "===> Building ref_gl4.so"
|
||||
${Q}mkdir -p release
|
||||
$(MAKE) release/ref_gl4.so
|
||||
|
||||
release/ref_gl4.so : GLAD_INCLUDE = -Isrc/client/refresh/gl4/glad/include
|
||||
release/ref_gl4.so : CFLAGS += -fPIC
|
||||
release/ref_gl4.so : LDFLAGS += -shared
|
||||
|
||||
endif # OS specific ref_gl4 stuff
|
||||
|
||||
build/ref_gl4/%.o: %.c
|
||||
@echo "===> CC $<"
|
||||
${Q}mkdir -p $(@D)
|
||||
${Q}$(CC) -c $(CFLAGS) $(SDLCFLAGS) $(INCLUDE) $(GLAD_INCLUDE) -o $@ $<
|
||||
|
||||
# ----------
|
||||
|
||||
REFGL4_OBJS_ := \
|
||||
src/client/refresh/gl4/gl4_draw.o \
|
||||
src/client/refresh/gl4/gl4_image.o \
|
||||
src/client/refresh/gl4/gl4_light.o \
|
||||
src/client/refresh/gl4/gl4_lightmap.o \
|
||||
src/client/refresh/gl4/gl4_main.o \
|
||||
src/client/refresh/gl4/gl4_mesh.o \
|
||||
src/client/refresh/gl4/gl4_misc.o \
|
||||
src/client/refresh/gl4/gl4_model.o \
|
||||
src/client/refresh/gl4/gl4_sdl.o \
|
||||
src/client/refresh/gl4/gl4_surf.o \
|
||||
src/client/refresh/gl4/gl4_warp.o \
|
||||
src/client/refresh/gl4/gl4_shaders.o \
|
||||
src/client/refresh/files/surf.o \
|
||||
src/client/refresh/files/models.o \
|
||||
src/client/refresh/files/pcx.o \
|
||||
src/client/refresh/files/stb.o \
|
||||
src/client/refresh/files/wal.o \
|
||||
src/client/refresh/files/pvs.o \
|
||||
src/common/shared/shared.o \
|
||||
src/common/md4.o
|
||||
|
||||
REFGL4_OBJS_GLADE_ := \
|
||||
src/client/refresh/gl4/glad/src/glad.o
|
||||
|
||||
ifeq ($(YQ2_OSTYPE), Windows)
|
||||
REFGL4_OBJS_ += \
|
||||
src/backends/windows/shared/hunk.o
|
||||
else # not Windows
|
||||
REFGL4_OBJS_ += \
|
||||
src/backends/unix/shared/hunk.o
|
||||
endif
|
||||
|
||||
# ----------
|
||||
|
||||
# Rewrite pathes to our object directory.
|
||||
REFGL4_OBJS = $(patsubst %,build/ref_gl4/%,$(REFGL4_OBJS_))
|
||||
REFGL4_OBJS += $(patsubst %,build/ref_gl4/%,$(REFGL4_OBJS_GLADE_))
|
||||
|
||||
# ----------
|
||||
|
||||
# Generate header dependencies.
|
||||
REFGL4_DEPS= $(REFGL4_OBJS:.o=.d)
|
||||
|
||||
# Suck header dependencies in.
|
||||
-include $(REFGL4_DEPS)
|
||||
|
||||
# ----------
|
||||
|
||||
# release/ref_gl4.so
|
||||
ifeq ($(YQ2_OSTYPE), Windows)
|
||||
release/ref_gl4.dll : $(REFGL4_OBJS)
|
||||
@echo "===> LD $@"
|
||||
${Q}$(CC) $(LDFLAGS) $(REFGL4_OBJS) $(LDLIBS) $(DLL_SDLLDFLAGS) -o $@
|
||||
$(Q)strip $@
|
||||
|
||||
else
|
||||
release/ref_gl4.so : $(REFGL4_OBJS)
|
||||
@echo "===> LD $@"
|
||||
${Q}$(CC) $(LDFLAGS) $(REFGL4_OBJS) $(LDLIBS) $(SDLLDFLAGS) -o $@
|
||||
endif
|
||||
|
||||
# ----------
|
28
README.md
Normal file
28
README.md
Normal file
|
@ -0,0 +1,28 @@
|
|||
# OpenGL 4.6 Renderer Library for Yamagi Quake II
|
||||
|
||||
This is an OpenGL 4.6 renderer library for Yamagi Quake II.
|
||||
|
||||
|
||||
## Compilation
|
||||
|
||||
You'll need:
|
||||
* clang or gcc,
|
||||
* GNU Make,
|
||||
* SDL2 with `sdl2-config`,
|
||||
* opengl-headers
|
||||
|
||||
Type `make` to compile the library. If the compilation is successfull,
|
||||
the library can be found under *release/ref_gl4.dll* (Windows) or
|
||||
*release/ref_gl4.so* (unixoid systems).
|
||||
|
||||
You can also use the provided CMakeLists file to build using Visual Studio on Windows.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
Copy the library next to your Yamagi Quake II executable. You can select
|
||||
OpenGL 4.6 through the video menu.
|
||||
|
||||
If you have run into issues, please attach output logs with OS/driver version
|
||||
and device name to the bug report. [List](https://openbenchmarking.org/test/pts/yquake2)
|
||||
of currently tested devices for the reference.
|
173
src/backends/unix/shared/hunk.c
Normal file
173
src/backends/unix/shared/hunk.c
Normal file
|
@ -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 <sys/mman.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../../../common/header/common.h"
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
#include <machine/param.h>
|
||||
#define MAP_ANONYMOUS MAP_ANON
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <sys/types.h>
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
15
src/backends/windows/header/resource.h
Normal file
15
src/backends/windows/header/resource.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef WIN_RESOURCE_H
|
||||
#define WIN_RESOURCE_H
|
||||
#define IDI_ICON1 101
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 103
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1000
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
97
src/backends/windows/shared/hunk.c
Normal file
97
src/backends/windows/shared/hunk.c
Normal file
|
@ -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 <windows.h>
|
||||
|
||||
#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--;
|
||||
}
|
188
src/client/refresh/constants/anorms.h
Normal file
188
src/client/refresh/constants/anorms.h
Normal file
|
@ -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 },
|
236
src/client/refresh/constants/anormtab.h
Normal file
236
src/client/refresh/constants/anormtab.h
Normal file
|
@ -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 }
|
||||
|
805
src/client/refresh/files/models.c
Normal file
805
src/client/refresh/files/models.c
Normal file
|
@ -0,0 +1,805 @@
|
|||
/*
|
||||
* 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 models file format
|
||||
*
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
#include "../ref_shared.h"
|
||||
|
||||
/*
|
||||
=================
|
||||
Mod_LoadAliasModel/Mod_LoadMD2
|
||||
=================
|
||||
*/
|
||||
void *
|
||||
Mod_LoadMD2 (const char *mod_name, const void *buffer, int modfilelen,
|
||||
vec3_t mins, vec3_t maxs, struct image_s **skins, findimage_t find_image,
|
||||
modtype_t *type)
|
||||
{
|
||||
dmdl_t *pinmodel, *pheader;
|
||||
dtriangle_t *pintri, *pouttri;
|
||||
dstvert_t *pinst, *poutst;
|
||||
int *pincmd, *poutcmd;
|
||||
void *extradata;
|
||||
int version;
|
||||
int ofs_end;
|
||||
int i, j;
|
||||
|
||||
pinmodel = (dmdl_t *)buffer;
|
||||
|
||||
version = LittleLong (pinmodel->version);
|
||||
if (version != ALIAS_VERSION)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "%s: %s has wrong version number (%i should be %i)",
|
||||
__func__, mod_name, version, ALIAS_VERSION);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ofs_end = LittleLong(pinmodel->ofs_end);
|
||||
if (ofs_end < 0 || ofs_end > modfilelen)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "%s: model %s file size(%d) too small, should be %d",
|
||||
__func__, mod_name, modfilelen, ofs_end);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
extradata = Hunk_Begin(modfilelen);
|
||||
pheader = Hunk_Alloc(ofs_end);
|
||||
|
||||
// byte swap the header fields and sanity check
|
||||
for (i=0 ; i<sizeof(dmdl_t)/sizeof(int) ; i++)
|
||||
((int *)pheader)[i] = LittleLong (((int *)buffer)[i]);
|
||||
|
||||
if (pheader->skinheight > MAX_LBM_HEIGHT)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "%s: model %s has a skin taller than %d",
|
||||
__func__, mod_name, MAX_LBM_HEIGHT);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pheader->num_xyz <= 0)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "%s: model %s has no vertices",
|
||||
__func__, mod_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pheader->num_xyz > MAX_VERTS)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "%s: model %s has too many vertices",
|
||||
__func__, mod_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pheader->num_st <= 0)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "%s: model %s has no st vertices",
|
||||
__func__, mod_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pheader->num_tris <= 0)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "%s: model %s has no triangles",
|
||||
__func__, mod_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pheader->num_frames <= 0)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "%s: model %s has no frames",
|
||||
__func__, mod_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pheader->num_skins > MAX_MD2SKINS)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "%s has too many skins (%i > %i), "
|
||||
"extra sprites will be ignored\n",
|
||||
mod_name, pheader->num_skins, MAX_MD2SKINS);
|
||||
pheader->num_skins = MAX_MD2SKINS;
|
||||
}
|
||||
|
||||
//
|
||||
// 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 ; i<pheader->num_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 ; i<pheader->num_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 ; i<pheader->num_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));
|
||||
}
|
||||
|
||||
//
|
||||
// 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 ; i<pheader->num_skins ; i++)
|
||||
{
|
||||
skins[i] = find_image((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME,
|
||||
it_skin);
|
||||
}
|
||||
|
||||
*type = mod_alias;
|
||||
|
||||
mins[0] = -32;
|
||||
mins[1] = -32;
|
||||
mins[2] = -32;
|
||||
maxs[0] = 32;
|
||||
maxs[1] = 32;
|
||||
maxs[2] = 32;
|
||||
|
||||
return extradata;
|
||||
}
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
SPRITE MODELS
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
=================
|
||||
Mod_LoadSP2
|
||||
|
||||
support for .sp2 sprites
|
||||
=================
|
||||
*/
|
||||
void *
|
||||
Mod_LoadSP2 (const char *mod_name, const void *buffer, int modfilelen,
|
||||
struct image_s **skins, findimage_t find_image, modtype_t *type)
|
||||
{
|
||||
dsprite_t *sprin, *sprout;
|
||||
void *extradata;
|
||||
int i;
|
||||
|
||||
sprin = (dsprite_t *)buffer;
|
||||
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)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "%s has wrong version number (%i should be %i)",
|
||||
mod_name, sprout->version, SPRITE_VERSION);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sprout->numframes > MAX_MD2SKINS)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "%s has too many frames (%i > %i), "
|
||||
"extra frames will be ignored\n",
|
||||
mod_name, sprout->numframes, MAX_MD2SKINS);
|
||||
sprout->numframes = MAX_MD2SKINS;
|
||||
}
|
||||
|
||||
/* byte swap everything */
|
||||
for (i = 0; i < sprout->numframes; 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);
|
||||
|
||||
skins[i] = find_image((char *)sprout->frames[i].name, it_sprite);
|
||||
}
|
||||
|
||||
*type = mod_sprite;
|
||||
|
||||
return extradata;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Mod_ReLoad
|
||||
|
||||
Reload images in SP2/MD2 (mark registration_sequence)
|
||||
=================
|
||||
*/
|
||||
int
|
||||
Mod_ReLoadSkins(struct image_s **skins, findimage_t find_image, void *extradata,
|
||||
modtype_t type)
|
||||
{
|
||||
if (type == mod_sprite)
|
||||
{
|
||||
dsprite_t *sprout;
|
||||
int i;
|
||||
|
||||
sprout = (dsprite_t *)extradata;
|
||||
for (i=0; i < sprout->numframes; i++)
|
||||
{
|
||||
skins[i] = find_image(sprout->frames[i].name, it_sprite);
|
||||
}
|
||||
return sprout->numframes;
|
||||
}
|
||||
else if (type == mod_alias)
|
||||
{
|
||||
dmdl_t *pheader;
|
||||
int i;
|
||||
|
||||
pheader = (dmdl_t *)extradata;
|
||||
for (i=0; i < pheader->num_skins; i++)
|
||||
{
|
||||
skins[i] = find_image ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME, it_skin);
|
||||
}
|
||||
return pheader->num_frames;
|
||||
}
|
||||
/* Unknow format, no images associated with it */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Mod_SetParent
|
||||
=================
|
||||
*/
|
||||
static void
|
||||
Mod_SetParent(mnode_t *node, mnode_t *parent)
|
||||
{
|
||||
node->parent = parent;
|
||||
if (node->contents != CONTENTS_NODE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Mod_SetParent (node->children[0], node);
|
||||
Mod_SetParent (node->children[1], node);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Mod_NumberLeafs
|
||||
=================
|
||||
*/
|
||||
static void
|
||||
Mod_NumberLeafs(mleaf_t *leafs, mnode_t *node, int *r_leaftovis, int *r_vistoleaf,
|
||||
int *numvisleafs)
|
||||
{
|
||||
if (node->contents != CONTENTS_NODE)
|
||||
{
|
||||
mleaf_t *leaf;
|
||||
int leafnum;
|
||||
|
||||
leaf = (mleaf_t *)node;
|
||||
leafnum = leaf - leafs;
|
||||
if (leaf->contents & CONTENTS_SOLID)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
r_leaftovis[leafnum] = *numvisleafs;
|
||||
r_vistoleaf[*numvisleafs] = leafnum;
|
||||
(*numvisleafs) ++;
|
||||
return;
|
||||
}
|
||||
|
||||
Mod_NumberLeafs(leafs, node->children[0], r_leaftovis, r_vistoleaf,
|
||||
numvisleafs);
|
||||
Mod_NumberLeafs(leafs, node->children[1], r_leaftovis, r_vistoleaf,
|
||||
numvisleafs);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Mod_LoadNodes
|
||||
=================
|
||||
*/
|
||||
void
|
||||
Mod_LoadNodes(const char *name, cplane_t *planes, int numplanes, mleaf_t *leafs,
|
||||
int numleafs, mnode_t **nodes, int *numnodes, const byte *mod_base,
|
||||
const lump_t *l)
|
||||
{
|
||||
int r_leaftovis[MAX_MAP_LEAFS], r_vistoleaf[MAX_MAP_LEAFS];
|
||||
int i, count, numvisleafs;
|
||||
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__, name);
|
||||
}
|
||||
|
||||
count = l->filelen / sizeof(*in);
|
||||
out = Hunk_Alloc(count * sizeof(*out));
|
||||
|
||||
*nodes = out;
|
||||
*numnodes = count;
|
||||
|
||||
for (i = 0; i < count; i++, in++, out++)
|
||||
{
|
||||
int j, planenum;
|
||||
|
||||
for (j = 0; j < 3; j++)
|
||||
{
|
||||
out->minmaxs[j] = LittleShort(in->mins[j]);
|
||||
out->minmaxs[3 + j] = LittleShort(in->maxs[j]);
|
||||
}
|
||||
|
||||
planenum = LittleLong(in->planenum);
|
||||
if (planenum < 0 || planenum >= numplanes)
|
||||
{
|
||||
ri.Sys_Error(ERR_DROP, "%s: Incorrect %d < %d planenum.",
|
||||
__func__, planenum, numplanes);
|
||||
}
|
||||
out->plane = planes + planenum;
|
||||
|
||||
out->firstsurface = LittleShort(in->firstface);
|
||||
out->numsurfaces = LittleShort(in->numfaces);
|
||||
out->contents = CONTENTS_NODE; /* differentiate from leafs */
|
||||
|
||||
for (j = 0; j < 2; j++)
|
||||
{
|
||||
int leafnum;
|
||||
|
||||
leafnum = LittleLong(in->children[j]);
|
||||
|
||||
if (leafnum >= 0)
|
||||
{
|
||||
if (leafnum < 0 || leafnum >= *numnodes)
|
||||
{
|
||||
ri.Sys_Error(ERR_DROP, "%s: Incorrect %d nodenum as leaf.",
|
||||
__func__, leafnum);
|
||||
}
|
||||
|
||||
out->children[j] = *nodes + leafnum;
|
||||
}
|
||||
else
|
||||
{
|
||||
leafnum = -1 - leafnum;
|
||||
if (leafnum < 0 || leafnum >= numleafs)
|
||||
{
|
||||
ri.Sys_Error(ERR_DROP, "%s: Incorrect %d leafnum.",
|
||||
__func__, leafnum);
|
||||
}
|
||||
|
||||
out->children[j] = (mnode_t *)(leafs + leafnum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Mod_SetParent(*nodes, NULL); /* sets nodes and leafs */
|
||||
|
||||
numvisleafs = 0;
|
||||
Mod_NumberLeafs (leafs, *nodes, r_leaftovis, r_vistoleaf, &numvisleafs);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Mod_LoadVisibility
|
||||
=================
|
||||
*/
|
||||
void
|
||||
Mod_LoadVisibility (dvis_t **vis, const byte *mod_base, const lump_t *l)
|
||||
{
|
||||
dvis_t *out;
|
||||
int i;
|
||||
|
||||
if (!l->filelen)
|
||||
{
|
||||
*vis = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
out = Hunk_Alloc(l->filelen);
|
||||
*vis = out;
|
||||
memcpy(out, mod_base + l->fileofs, l->filelen);
|
||||
|
||||
out->numclusters = LittleLong(out->numclusters);
|
||||
|
||||
for (i = 0; i < out->numclusters; i++)
|
||||
{
|
||||
out->bitofs[i][0] = LittleLong(out->bitofs[i][0]);
|
||||
out->bitofs[i][1] = LittleLong(out->bitofs[i][1]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Mod_LoadVertexes
|
||||
|
||||
extra for skybox
|
||||
=================
|
||||
*/
|
||||
void
|
||||
Mod_LoadVertexes(const char *name, mvertex_t **vertexes, int *numvertexes,
|
||||
const byte *mod_base, const lump_t *l, int extra)
|
||||
{
|
||||
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__, name);
|
||||
}
|
||||
|
||||
count = l->filelen / sizeof(*in);
|
||||
out = Hunk_Alloc((count + extra)*sizeof(*out));
|
||||
|
||||
/*
|
||||
* FIXME: Recheck with soft render
|
||||
* Fix for the problem where the games dumped core
|
||||
* when changing levels.
|
||||
*/
|
||||
memset(out, 0, (count + extra) * sizeof(*out));
|
||||
|
||||
*vertexes = out;
|
||||
*numvertexes = count;
|
||||
|
||||
for (i = 0; i < count; i++, in++, out++)
|
||||
{
|
||||
out->position[0] = LittleFloat(in->point[0]);
|
||||
out->position[1] = LittleFloat(in->point[1]);
|
||||
out->position[2] = LittleFloat(in->point[2]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Mod_LoadLighting
|
||||
=================
|
||||
*/
|
||||
void
|
||||
Mod_LoadLighting(byte **lightdata, const byte *mod_base, const lump_t *l)
|
||||
{
|
||||
int size;
|
||||
|
||||
if (!l->filelen)
|
||||
{
|
||||
*lightdata = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
size = l->filelen;
|
||||
*lightdata = Hunk_Alloc(size);
|
||||
memcpy(*lightdata, mod_base + l->fileofs, size);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Mod_LoadTexinfo
|
||||
|
||||
extra for skybox in soft render
|
||||
=================
|
||||
*/
|
||||
void
|
||||
Mod_LoadTexinfo(const char *name, mtexinfo_t **texinfo, int *numtexinfo,
|
||||
const byte *mod_base, const lump_t *l, findimage_t find_image,
|
||||
struct image_s *notexture, int extra)
|
||||
{
|
||||
texinfo_t *in;
|
||||
mtexinfo_t *out, *step;
|
||||
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__, name);
|
||||
}
|
||||
|
||||
count = l->filelen / sizeof(*in);
|
||||
out = Hunk_Alloc((count + extra)*sizeof(*out));
|
||||
|
||||
*texinfo = out;
|
||||
*numtexinfo = count;
|
||||
|
||||
for ( i=0 ; i<count ; i++, in++, out++)
|
||||
{
|
||||
struct image_s *image;
|
||||
int j, next;
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
out->vecs[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 = *texinfo + next;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Fix for the problem where the game
|
||||
* domed core when loading a new level.
|
||||
*/
|
||||
out->next = NULL;
|
||||
}
|
||||
|
||||
image = GetTexImage(in->texture, find_image);
|
||||
if (!image)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "%s: Couldn't load %s\n",
|
||||
__func__, in->texture);
|
||||
image = notexture;
|
||||
}
|
||||
|
||||
out->image = image;
|
||||
}
|
||||
|
||||
// count animation frames
|
||||
for (i=0 ; i<count ; i++)
|
||||
{
|
||||
out = (*texinfo) + i;
|
||||
out->numframes = 1;
|
||||
for (step = out->next ; step && step != out ; step=step->next)
|
||||
{
|
||||
out->numframes++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Mod_LoadEdges
|
||||
|
||||
extra is used for skybox, which adds 6 surfaces
|
||||
=================
|
||||
*/
|
||||
void
|
||||
Mod_LoadEdges(const char *name, medge_t **edges, int *numedges,
|
||||
const byte *mod_base, const lump_t *l, int extra)
|
||||
{
|
||||
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__, name);
|
||||
}
|
||||
|
||||
count = l->filelen / sizeof(*in);
|
||||
out = Hunk_Alloc((count + extra) * sizeof(*out));
|
||||
|
||||
*edges = out;
|
||||
*numedges = count;
|
||||
|
||||
for ( i=0 ; i<count ; i++, in++, out++)
|
||||
{
|
||||
out->v[0] = (unsigned short)LittleShort(in->v[0]);
|
||||
out->v[1] = (unsigned short)LittleShort(in->v[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Mod_LoadPlanes
|
||||
|
||||
extra is used for skybox, which adds 6 surfaces
|
||||
=================
|
||||
*/
|
||||
void
|
||||
Mod_LoadPlanes(const char *name, cplane_t **planes, int *numplanes,
|
||||
const byte *mod_base, const lump_t *l, int extra)
|
||||
{
|
||||
int i;
|
||||
cplane_t *out;
|
||||
dplane_t *in;
|
||||
int count;
|
||||
|
||||
in = (void *)(mod_base + l->fileofs);
|
||||
|
||||
if (l->filelen % sizeof(*in))
|
||||
{
|
||||
ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s",
|
||||
__func__, name);
|
||||
}
|
||||
|
||||
count = l->filelen / sizeof(*in);
|
||||
// FIXME: why double of count
|
||||
out = Hunk_Alloc((count * 2 + extra) * sizeof(*out));
|
||||
|
||||
*planes = out;
|
||||
*numplanes = count;
|
||||
|
||||
for ( i=0 ; i<count ; i++, in++, out++)
|
||||
{
|
||||
int bits, j;
|
||||
|
||||
bits = 0;
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
out->normal[j] = LittleFloat (in->normal[j]);
|
||||
if (out->normal[j] < 0)
|
||||
bits |= 1<<j;
|
||||
}
|
||||
|
||||
out->dist = LittleFloat (in->dist);
|
||||
out->type = LittleLong (in->type);
|
||||
out->signbits = bits;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Mod_LoadSurfedges
|
||||
=================
|
||||
*/
|
||||
void
|
||||
Mod_LoadSurfedges(const char *name, int **surfedges, int *numsurfedges,
|
||||
const byte *mod_base, const lump_t *l, int extra)
|
||||
{
|
||||
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__, name);
|
||||
}
|
||||
|
||||
count = l->filelen / sizeof(*in);
|
||||
out = Hunk_Alloc((count + extra)*sizeof(*out)); // extra for skybox
|
||||
|
||||
*surfedges = out;
|
||||
*numsurfedges = count;
|
||||
|
||||
for ( i=0 ; i<count ; i++)
|
||||
out[i] = LittleLong (in[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Mod_LoadSurfedges
|
||||
|
||||
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
|
||||
extra is used for skybox, which adds 6 surfaces
|
||||
=================
|
||||
*/
|
||||
int
|
||||
Mod_CalcLumpHunkSize(const lump_t *l, int inSize, int outSize, int extra)
|
||||
{
|
||||
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 + extra;
|
||||
int size = count * outSize;
|
||||
|
||||
// round to cacheline, like Hunk_Alloc() does
|
||||
size = (size + 31) & ~31;
|
||||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
Mod_PointInLeaf
|
||||
===============
|
||||
*/
|
||||
mleaf_t *
|
||||
Mod_PointInLeaf(const vec3_t p, mnode_t *node)
|
||||
{
|
||||
if (!node)
|
||||
{
|
||||
ri.Sys_Error(ERR_DROP, "%s: bad node.", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
float d;
|
||||
cplane_t *plane;
|
||||
|
||||
if (node->contents != CONTENTS_NODE)
|
||||
{
|
||||
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 */
|
||||
}
|
350
src/client/refresh/files/pcx.c
Normal file
350
src/client/refresh/files/pcx.c
Normal file
|
@ -0,0 +1,350 @@
|
|||
/*
|
||||
* 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 "../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(const 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];
|
||||
|
||||
FixFileExt(origname, "pcx", filename, 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(filename, "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(const char *origname, int *width, int *height)
|
||||
{
|
||||
pcx_t *pcx;
|
||||
byte *raw;
|
||||
char filename[256];
|
||||
|
||||
FixFileExt(origname, "pcx", filename, sizeof(filename));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
GetPCXPalette
|
||||
===============
|
||||
*/
|
||||
void
|
||||
GetPCXPalette (byte **colormap, unsigned *d_8to24table)
|
||||
{
|
||||
byte *pal;
|
||||
int i;
|
||||
|
||||
/* get the palette and colormap */
|
||||
LoadPCX ("pics/colormap.pcx", colormap, &pal, NULL, NULL);
|
||||
if (!*colormap || !pal)
|
||||
{
|
||||
ri.Sys_Error (ERR_FATAL, "%s: Couldn't load pics/colormap.pcx",
|
||||
__func__);
|
||||
}
|
||||
|
||||
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 = (255U<<24) + (r<<0) + (g<<8) + (b<<16);
|
||||
d_8to24table[i] = LittleLong(v);
|
||||
}
|
||||
|
||||
d_8to24table[255] &= LittleLong(0xffffff); // 255 is transparent
|
||||
|
||||
free (pal);
|
||||
}
|
90
src/client/refresh/files/pvs.c
Normal file
90
src/client/refresh/files/pvs.c
Normal file
|
@ -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 "../ref_shared.h"
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
Mod_DecompressVis
|
||||
===================
|
||||
*/
|
||||
const byte *
|
||||
Mod_DecompressVis(const 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);
|
||||
}
|
662
src/client/refresh/files/stb.c
Normal file
662
src/client/refresh/files/stb.c
Normal file
|
@ -0,0 +1,662 @@
|
|||
/*
|
||||
* 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 <stdlib.h>
|
||||
|
||||
#include "../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)
|
||||
// Switch of the thread local stuff. Breaks mingw under Windows.
|
||||
#define STBI_NO_THREAD_LOCALS
|
||||
// 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"
|
||||
|
||||
/*
|
||||
* Add extension to file name
|
||||
*/
|
||||
void
|
||||
FixFileExt(const char *origname, const char *ext, char *filename, size_t size)
|
||||
{
|
||||
Q_strlcpy(filename, origname, size);
|
||||
|
||||
/* Add the extension */
|
||||
if (strcmp(COM_FileExtension(filename), ext))
|
||||
{
|
||||
Q_strlcat(filename, ".", size);
|
||||
Q_strlcat(filename, ext, size);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
static qboolean
|
||||
LoadSTB(const char *origname, const char* type, byte **pic, int *width, int *height)
|
||||
{
|
||||
char filename[256];
|
||||
|
||||
FixFileExt(origname, type, filename, 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(const 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(const 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
|
||||
*/
|
||||
{
|
||||
const 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(const 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
|
||||
*/
|
||||
{
|
||||
const 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct image_s *
|
||||
LoadHiColorImage(const char *name, const char* namewe, const char *ext,
|
||||
imagetype_t type, loadimage_t load_image)
|
||||
{
|
||||
int realwidth = 0, realheight = 0;
|
||||
int width = 0, height = 0;
|
||||
struct image_s *image = NULL;
|
||||
byte *pic = NULL;
|
||||
|
||||
/* Get size of the original texture */
|
||||
if (strcmp(ext, "pcx") == 0)
|
||||
{
|
||||
GetPCXInfo(name, &realwidth, &realheight);
|
||||
}
|
||||
else if (strcmp(ext, "wal") == 0)
|
||||
{
|
||||
GetWalInfo(name, &realwidth, &realheight);
|
||||
}
|
||||
else if (strcmp(ext, "m8") == 0)
|
||||
{
|
||||
GetM8Info(name, &realwidth, &realheight);
|
||||
}
|
||||
else if (strcmp(ext, "m32") == 0)
|
||||
{
|
||||
GetM32Info(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 = load_image(name, pic,
|
||||
width, realwidth,
|
||||
height, realheight,
|
||||
width * height,
|
||||
type, 32);
|
||||
}
|
||||
}
|
||||
|
||||
if (pic)
|
||||
{
|
||||
free(pic);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
struct image_s *
|
||||
R_LoadImage(const char *name, const char* namewe, const char *ext, imagetype_t type,
|
||||
qboolean r_retexturing, loadimage_t load_image)
|
||||
{
|
||||
struct image_s *image = NULL;
|
||||
|
||||
// with retexturing and not skin
|
||||
if (r_retexturing)
|
||||
{
|
||||
image = LoadHiColorImage(name, namewe, ext, type, load_image);
|
||||
}
|
||||
|
||||
if (!image)
|
||||
{
|
||||
if (!strcmp(ext, "pcx"))
|
||||
{
|
||||
byte *pic = NULL;
|
||||
byte *palette = NULL;
|
||||
int width = 0, height = 0;
|
||||
|
||||
LoadPCX (namewe, &pic, &palette, &width, &height);
|
||||
if (!pic)
|
||||
return NULL;
|
||||
|
||||
image = load_image(name, pic,
|
||||
width, width,
|
||||
height, height,
|
||||
width * height, type, 8);
|
||||
|
||||
if (palette)
|
||||
{
|
||||
free(palette);
|
||||
}
|
||||
free(pic);
|
||||
}
|
||||
else if (!strcmp(ext, "wal"))
|
||||
{
|
||||
image = LoadWal(namewe, type, load_image);
|
||||
}
|
||||
else if (!strcmp(ext, "m8"))
|
||||
{
|
||||
image = LoadM8(namewe, type, load_image);
|
||||
}
|
||||
else if (!strcmp(ext, "m32"))
|
||||
{
|
||||
image = LoadM32(namewe, type, load_image);
|
||||
}
|
||||
else if (!strcmp(ext, "tga") ||
|
||||
!strcmp(ext, "png") ||
|
||||
!strcmp(ext, "jpg"))
|
||||
{
|
||||
byte *pic = NULL;
|
||||
int width = 0, height = 0;
|
||||
|
||||
if (LoadSTB (namewe, ext, &pic, &width, &height) && pic)
|
||||
{
|
||||
image = load_image(name, pic,
|
||||
width, width,
|
||||
height, height,
|
||||
width * height,
|
||||
type, 32);
|
||||
|
||||
free(pic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
struct image_s*
|
||||
GetSkyImage(const char *skyname, const char* surfname, qboolean palettedtexture,
|
||||
findimage_t find_image)
|
||||
{
|
||||
struct image_s *image = NULL;
|
||||
char pathname[MAX_QPATH];
|
||||
|
||||
/* Quake 2 */
|
||||
if (palettedtexture)
|
||||
{
|
||||
Com_sprintf(pathname, sizeof(pathname), "env/%s%s.pcx",
|
||||
skyname, surfname);
|
||||
image = find_image(pathname, it_sky);
|
||||
}
|
||||
|
||||
if (!image)
|
||||
{
|
||||
Com_sprintf(pathname, sizeof(pathname), "env/%s%s.tga",
|
||||
skyname, surfname);
|
||||
image = find_image(pathname, it_sky);
|
||||
}
|
||||
|
||||
/* Heretic 2 */
|
||||
if (!image)
|
||||
{
|
||||
Com_sprintf(pathname, sizeof(pathname), "pics/Skies/%s%s.m32",
|
||||
skyname, surfname);
|
||||
image = find_image(pathname, it_sky);
|
||||
}
|
||||
|
||||
if (!image)
|
||||
{
|
||||
Com_sprintf(pathname, sizeof(pathname), "pics/Skies/%s%s.m8",
|
||||
skyname, surfname);
|
||||
image = find_image(pathname, it_sky);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
struct image_s *
|
||||
GetTexImage(const char *name, findimage_t find_image)
|
||||
{
|
||||
struct image_s *image = NULL;
|
||||
char pathname[MAX_QPATH];
|
||||
|
||||
/* Quake 2 */
|
||||
Com_sprintf(pathname, sizeof(pathname), "textures/%s.wal", name);
|
||||
image = find_image(pathname, it_wall);
|
||||
|
||||
/* Heretic 2 */
|
||||
if (!image)
|
||||
{
|
||||
Com_sprintf(pathname, sizeof(pathname), "textures/%s.m32", name);
|
||||
image = find_image(pathname, it_wall);
|
||||
}
|
||||
|
||||
if (!image)
|
||||
{
|
||||
Com_sprintf(pathname, sizeof(pathname), "textures/%s.m8", name);
|
||||
image = find_image(pathname, it_wall);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
struct image_s *
|
||||
R_FindPic(const char *name, findimage_t find_image)
|
||||
{
|
||||
struct image_s *image = NULL;
|
||||
|
||||
if ((name[0] != '/') && (name[0] != '\\'))
|
||||
{
|
||||
char pathname[MAX_QPATH];
|
||||
|
||||
/* Quake 2 */
|
||||
Com_sprintf(pathname, sizeof(pathname), "pics/%s.pcx", name);
|
||||
image = find_image(pathname, it_pic);
|
||||
|
||||
/* Heretic 2 */
|
||||
if (!image)
|
||||
{
|
||||
Com_sprintf(pathname, sizeof(pathname), "pics/misc/%s.m32", name);
|
||||
image = find_image(pathname, it_pic);
|
||||
}
|
||||
|
||||
if (!image)
|
||||
{
|
||||
Com_sprintf(pathname, sizeof(pathname), "pics/misc/%s.m8", name);
|
||||
image = find_image(pathname, it_pic);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
image = find_image(name + 1, it_pic);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
7987
src/client/refresh/files/stb_image.h
Normal file
7987
src/client/refresh/files/stb_image.h
Normal file
File diff suppressed because it is too large
Load diff
2634
src/client/refresh/files/stb_image_resize.h
Normal file
2634
src/client/refresh/files/stb_image_resize.h
Normal file
File diff suppressed because it is too large
Load diff
186
src/client/refresh/files/surf.c
Normal file
186
src/client/refresh/files/surf.c
Normal file
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* =======================================================================
|
||||
*
|
||||
* Surface logic
|
||||
*
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
#include "../ref_shared.h"
|
||||
|
||||
/*
|
||||
===============
|
||||
R_TextureAnimation
|
||||
|
||||
Returns the proper texture for a given time and base texture
|
||||
===============
|
||||
*/
|
||||
struct image_s *
|
||||
R_TextureAnimation(const entity_t *currententity, const mtexinfo_t *tex)
|
||||
{
|
||||
int c;
|
||||
|
||||
if (!tex->next)
|
||||
return tex->image;
|
||||
|
||||
if (!currententity)
|
||||
return tex->image;
|
||||
|
||||
c = currententity->frame % tex->numframes;
|
||||
while (c && tex)
|
||||
{
|
||||
tex = tex->next;
|
||||
c--;
|
||||
}
|
||||
|
||||
return tex->image;
|
||||
}
|
||||
|
||||
qboolean
|
||||
R_AreaVisible(const byte *areabits, mleaf_t *pleaf)
|
||||
{
|
||||
int area;
|
||||
|
||||
// check for door connected areas
|
||||
if (!areabits)
|
||||
return true;
|
||||
|
||||
area = pleaf->area;
|
||||
|
||||
if ((areabits[area >> 3] & (1 << (area & 7))))
|
||||
return true;
|
||||
|
||||
return false; // not visible
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
R_MarkLights
|
||||
|
||||
bit: 1 << i for light number i, will be or'ed into msurface_t::dlightbits
|
||||
if surface is affected by this light
|
||||
=============
|
||||
*/
|
||||
void
|
||||
R_MarkLights(dlight_t *light, int bit, mnode_t *node, int r_dlightframecount,
|
||||
marksurfacelights_t mark_surface_lights)
|
||||
{
|
||||
cplane_t *splitplane;
|
||||
float dist;
|
||||
int intensity;
|
||||
|
||||
if (node->contents != CONTENTS_NODE)
|
||||
return;
|
||||
|
||||
splitplane = node->plane;
|
||||
dist = DotProduct(light->origin, splitplane->normal) - splitplane->dist;
|
||||
|
||||
intensity = light->intensity;
|
||||
|
||||
if (dist > intensity - DLIGHT_CUTOFF) // (dist > light->intensity)
|
||||
{
|
||||
R_MarkLights (light, bit, node->children[0], r_dlightframecount,
|
||||
mark_surface_lights);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dist < -intensity + DLIGHT_CUTOFF) // (dist < -light->intensity)
|
||||
{
|
||||
R_MarkLights(light, bit, node->children[1], r_dlightframecount,
|
||||
mark_surface_lights);
|
||||
return;
|
||||
}
|
||||
|
||||
mark_surface_lights(light, bit, node, r_dlightframecount);
|
||||
|
||||
R_MarkLights(light, bit, node->children[0], r_dlightframecount,
|
||||
mark_surface_lights);
|
||||
R_MarkLights(light, bit, node->children[1], r_dlightframecount,
|
||||
mark_surface_lights);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if the box is completely outside the frustom
|
||||
*/
|
||||
qboolean
|
||||
R_CullBox(vec3_t mins, vec3_t maxs, cplane_t *frustum)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if (BOX_ON_PLANE_SIDE(mins, maxs, frustum + i) == 2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
R_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;
|
||||
}
|
||||
|
||||
void
|
||||
R_SetFrustum(vec3_t vup, vec3_t vpn, vec3_t vright, vec3_t r_origin,
|
||||
float fov_x, float fov_y, cplane_t *frustum)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* rotate VPN right by FOV_X/2 degrees */
|
||||
RotatePointAroundVector(frustum[0].normal, vup, vpn,
|
||||
-(90 - fov_x / 2));
|
||||
/* rotate VPN left by FOV_X/2 degrees */
|
||||
RotatePointAroundVector(frustum[1].normal,
|
||||
vup, vpn, 90 - fov_x / 2);
|
||||
/* rotate VPN up by FOV_X/2 degrees */
|
||||
RotatePointAroundVector(frustum[2].normal,
|
||||
vright, vpn, 90 - fov_y / 2);
|
||||
/* rotate VPN down by FOV_X/2 degrees */
|
||||
RotatePointAroundVector(frustum[3].normal, vright, vpn,
|
||||
-(90 - fov_y / 2));
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# pragma GCC unroll 4
|
||||
#endif
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
frustum[i].type = PLANE_ANYZ;
|
||||
frustum[i].dist = DotProduct(r_origin, frustum[i].normal);
|
||||
frustum[i].signbits = R_SignbitsForPlane(&frustum[i]);
|
||||
}
|
||||
}
|
280
src/client/refresh/files/wal.c
Normal file
280
src/client/refresh/files/wal.c
Normal file
|
@ -0,0 +1,280 @@
|
|||
/*
|
||||
* 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 "../ref_shared.h"
|
||||
|
||||
struct image_s *
|
||||
LoadWal(const char *origname, imagetype_t type, loadimage_t load_image)
|
||||
{
|
||||
int width, height, ofs, size;
|
||||
struct image_s *image;
|
||||
char name[256];
|
||||
miptex_t *mt;
|
||||
|
||||
FixFileExt(origname, "wal", name, sizeof(name));
|
||||
|
||||
size = ri.FS_LoadFile(name, (void **)&mt);
|
||||
|
||||
if (!mt)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size < sizeof(miptex_t))
|
||||
{
|
||||
R_Printf(PRINT_ALL, "%s: can't load %s, small header\n", __func__, name);
|
||||
ri.FS_FreeFile((void *)mt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
width = LittleLong(mt->width);
|
||||
height = LittleLong(mt->height);
|
||||
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 NULL;
|
||||
}
|
||||
|
||||
image = load_image(name, (byte *)mt + ofs,
|
||||
width, 0,
|
||||
height, 0,
|
||||
(size - ofs), type, 8);
|
||||
|
||||
ri.FS_FreeFile((void *)mt);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
struct image_s *
|
||||
LoadM8(const char *origname, imagetype_t type, loadimage_t load_image)
|
||||
{
|
||||
m8tex_t *mt;
|
||||
int width, height, ofs, size, i;
|
||||
struct image_s *image;
|
||||
char name[256];
|
||||
unsigned char *image_buffer = NULL;
|
||||
|
||||
FixFileExt(origname, "m8", name, sizeof(name));
|
||||
|
||||
size = ri.FS_LoadFile(name, (void **)&mt);
|
||||
|
||||
if (!mt)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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 NULL;
|
||||
}
|
||||
|
||||
if (LittleLong (mt->version) != M8_VERSION)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "%s: can't load %s, wrong magic value.\n", __func__, name);
|
||||
ri.FS_FreeFile ((void *)mt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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 NULL;
|
||||
}
|
||||
|
||||
image_buffer = malloc ((size - ofs) * 4);
|
||||
for(i=0; i<(size - ofs); i++)
|
||||
{
|
||||
unsigned char value = *((byte *)mt + ofs + i);
|
||||
image_buffer[i * 4 + 0] = mt->palette[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 = load_image(name, image_buffer,
|
||||
width, 0,
|
||||
height, 0,
|
||||
(size - ofs), type, 32);
|
||||
free(image_buffer);
|
||||
|
||||
ri.FS_FreeFile((void *)mt);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
struct image_s *
|
||||
LoadM32(const char *origname, imagetype_t type, loadimage_t load_image)
|
||||
{
|
||||
m32tex_t *mt;
|
||||
int width, height, ofs, size;
|
||||
struct image_s *image;
|
||||
char name[256];
|
||||
|
||||
FixFileExt(origname, "m32", name, sizeof(name));
|
||||
|
||||
size = ri.FS_LoadFile(name, (void **)&mt);
|
||||
|
||||
if (!mt)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size < sizeof(m32tex_t))
|
||||
{
|
||||
R_Printf(PRINT_ALL, "%s: can't load %s, small header\n", __func__, name);
|
||||
ri.FS_FreeFile((void *)mt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (LittleLong (mt->version) != M32_VERSION)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "%s: can't load %s, wrong magic value.\n", __func__, name);
|
||||
ri.FS_FreeFile ((void *)mt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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 * 4)))
|
||||
{
|
||||
R_Printf(PRINT_ALL, "%s: can't load %s, small body\n", __func__, name);
|
||||
ri.FS_FreeFile((void *)mt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
image = load_image(name, (byte *)mt + ofs,
|
||||
width, 0,
|
||||
height, 0,
|
||||
(size - ofs) / 4, type, 32);
|
||||
ri.FS_FreeFile ((void *)mt);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
void
|
||||
GetWalInfo(const char *origname, int *width, int *height)
|
||||
{
|
||||
miptex_t *mt;
|
||||
int size;
|
||||
char filename[256];
|
||||
|
||||
FixFileExt(origname, "wal", filename, sizeof(filename));
|
||||
|
||||
size = ri.FS_LoadFile(filename, (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(const char *origname, int *width, int *height)
|
||||
{
|
||||
m8tex_t *mt;
|
||||
int size;
|
||||
char filename[256];
|
||||
|
||||
FixFileExt(origname, "m8", filename, sizeof(filename));
|
||||
|
||||
size = ri.FS_LoadFile(filename, (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;
|
||||
}
|
||||
|
||||
void
|
||||
GetM32Info(const char *origname, int *width, int *height)
|
||||
{
|
||||
m32tex_t *mt;
|
||||
int size;
|
||||
char filename[256];
|
||||
|
||||
FixFileExt(origname, "m32", filename, sizeof(filename));
|
||||
|
||||
size = ri.FS_LoadFile(filename, (void **)&mt);
|
||||
|
||||
if (!mt)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (size < sizeof(m32tex_t) || LittleLong (mt->version) != M32_VERSION)
|
||||
{
|
||||
ri.FS_FreeFile((void *)mt);
|
||||
return;
|
||||
}
|
||||
|
||||
*width = LittleLong(mt->width[0]);
|
||||
*height = LittleLong(mt->height[0]);
|
||||
|
||||
ri.FS_FreeFile((void *)mt);
|
||||
|
||||
return;
|
||||
}
|
413
src/client/refresh/gl4/gl4_draw.c
Normal file
413
src/client/refresh/gl4/gl4_draw.c
Normal file
|
@ -0,0 +1,413 @@
|
|||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
* Copyright (C) 2016-2017 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.
|
||||
*
|
||||
* =======================================================================
|
||||
*
|
||||
* Drawing of all images that are not textures
|
||||
*
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
#include "header/local.h"
|
||||
|
||||
unsigned d_8to24table[256];
|
||||
|
||||
gl4image_t *draw_chars;
|
||||
|
||||
static GLuint vbo2D = 0, vao2D = 0, vao2Dcolor = 0; // vao2D is for textured rendering, vao2Dcolor for color-only
|
||||
|
||||
void
|
||||
GL4_Draw_InitLocal(void)
|
||||
{
|
||||
/* load console characters */
|
||||
draw_chars = R_FindPic("conchars", (findimage_t)GL4_FindImage);
|
||||
if (!draw_chars)
|
||||
{
|
||||
ri.Sys_Error(ERR_FATAL, "%s: Couldn't load pics/conchars.pcx",
|
||||
__func__);
|
||||
}
|
||||
|
||||
// set up attribute layout for 2D textured rendering
|
||||
glGenVertexArrays(1, &vao2D);
|
||||
glBindVertexArray(vao2D);
|
||||
|
||||
glGenBuffers(1, &vbo2D);
|
||||
GL4_BindVBO(vbo2D);
|
||||
|
||||
GL4_UseProgram(gl4state.si2D.shaderProgram);
|
||||
|
||||
glEnableVertexAttribArray(GL4_ATTRIB_POSITION);
|
||||
// Note: the glVertexAttribPointer() configuration is stored in the VAO, not the shader or sth
|
||||
// (that's why I use one VAO per 2D shader)
|
||||
qglVertexAttribPointer(GL4_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, 4*sizeof(float), 0);
|
||||
|
||||
glEnableVertexAttribArray(GL4_ATTRIB_TEXCOORD);
|
||||
qglVertexAttribPointer(GL4_ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 4*sizeof(float), 2*sizeof(float));
|
||||
|
||||
// set up attribute layout for 2D flat color rendering
|
||||
|
||||
glGenVertexArrays(1, &vao2Dcolor);
|
||||
glBindVertexArray(vao2Dcolor);
|
||||
|
||||
GL4_BindVBO(vbo2D); // yes, both VAOs share the same VBO
|
||||
|
||||
GL4_UseProgram(gl4state.si2Dcolor.shaderProgram);
|
||||
|
||||
glEnableVertexAttribArray(GL4_ATTRIB_POSITION);
|
||||
qglVertexAttribPointer(GL4_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), 0);
|
||||
|
||||
GL4_BindVAO(0);
|
||||
}
|
||||
|
||||
void
|
||||
GL4_Draw_ShutdownLocal(void)
|
||||
{
|
||||
glDeleteBuffers(1, &vbo2D);
|
||||
vbo2D = 0;
|
||||
glDeleteVertexArrays(1, &vao2D);
|
||||
vao2D = 0;
|
||||
glDeleteVertexArrays(1, &vao2Dcolor);
|
||||
vao2Dcolor = 0;
|
||||
}
|
||||
|
||||
// bind the texture before calling this
|
||||
static void
|
||||
drawTexturedRectangle(float x, float y, float w, float h,
|
||||
float sl, float tl, float sh, float th)
|
||||
{
|
||||
/*
|
||||
* x,y+h x+w,y+h
|
||||
* sl,th--------sh,th
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* sl,tl--------sh,tl
|
||||
* x,y x+w,y
|
||||
*/
|
||||
|
||||
GLfloat vBuf[16] = {
|
||||
// X, Y, S, T
|
||||
x, y+h, sl, th,
|
||||
x, y, sl, tl,
|
||||
x+w, y+h, sh, th,
|
||||
x+w, y, sh, tl
|
||||
};
|
||||
|
||||
GL4_BindVAO(vao2D);
|
||||
|
||||
// Note: while vao2D "remembers" its vbo for drawing, binding the vao does *not*
|
||||
// implicitly bind the vbo, so I need to explicitly bind it before glBufferData()
|
||||
GL4_BindVBO(vbo2D);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vBuf), vBuf, GL_STREAM_DRAW);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
//glMultiDrawArrays(mode, first, count, drawcount) ??
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
GL4_Draw_CharScaled(int x, int y, int num, float scale)
|
||||
{
|
||||
int row, col;
|
||||
float frow, fcol, size, scaledSize;
|
||||
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;
|
||||
|
||||
scaledSize = 8*scale;
|
||||
|
||||
// TODO: batchen?
|
||||
|
||||
GL4_UseProgram(gl4state.si2D.shaderProgram);
|
||||
GL4_Bind(draw_chars->texnum);
|
||||
drawTexturedRectangle(x, y, scaledSize, scaledSize, fcol, frow, fcol+size, frow+size);
|
||||
}
|
||||
|
||||
gl4image_t *
|
||||
GL4_Draw_FindPic(char *name)
|
||||
{
|
||||
return R_FindPic(name, (findimage_t)GL4_FindImage);
|
||||
}
|
||||
|
||||
void
|
||||
GL4_Draw_GetPicSize(int *w, int *h, char *pic)
|
||||
{
|
||||
gl4image_t *gl;
|
||||
|
||||
gl = R_FindPic(pic, (findimage_t)GL4_FindImage);
|
||||
|
||||
if (!gl)
|
||||
{
|
||||
*w = *h = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
*w = gl->width;
|
||||
*h = gl->height;
|
||||
}
|
||||
|
||||
void
|
||||
GL4_Draw_StretchPic(int x, int y, int w, int h, char *pic)
|
||||
{
|
||||
gl4image_t *gl = R_FindPic(pic, (findimage_t)GL4_FindImage);
|
||||
|
||||
if (!gl)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "Can't find pic: %s\n", pic);
|
||||
return;
|
||||
}
|
||||
|
||||
GL4_UseProgram(gl4state.si2D.shaderProgram);
|
||||
GL4_Bind(gl->texnum);
|
||||
|
||||
drawTexturedRectangle(x, y, w, h, gl->sl, gl->tl, gl->sh, gl->th);
|
||||
}
|
||||
|
||||
void
|
||||
GL4_Draw_PicScaled(int x, int y, char *pic, float factor)
|
||||
{
|
||||
gl4image_t *gl = R_FindPic(pic, (findimage_t)GL4_FindImage);
|
||||
if (!gl)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "Can't find pic: %s\n", pic);
|
||||
return;
|
||||
}
|
||||
|
||||
GL4_UseProgram(gl4state.si2D.shaderProgram);
|
||||
GL4_Bind(gl->texnum);
|
||||
|
||||
drawTexturedRectangle(x, y, gl->width*factor, gl->height*factor, gl->sl, gl->tl, gl->sh, gl->th);
|
||||
}
|
||||
|
||||
/*
|
||||
* This repeats a 64*64 tile graphic to fill
|
||||
* the screen around a sized down
|
||||
* refresh window.
|
||||
*/
|
||||
void
|
||||
GL4_Draw_TileClear(int x, int y, int w, int h, char *pic)
|
||||
{
|
||||
gl4image_t *image = R_FindPic(pic, (findimage_t)GL4_FindImage);
|
||||
if (!image)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "Can't find pic: %s\n", pic);
|
||||
return;
|
||||
}
|
||||
|
||||
GL4_UseProgram(gl4state.si2D.shaderProgram);
|
||||
GL4_Bind(image->texnum);
|
||||
|
||||
drawTexturedRectangle(x, y, w, h, x/64.0f, y/64.0f, (x+w)/64.0f, (y+h)/64.0f);
|
||||
}
|
||||
|
||||
void
|
||||
GL4_DrawFrameBufferObject(int x, int y, int w, int h, GLuint fboTexture, const float v_blend[4])
|
||||
{
|
||||
qboolean underwater = (gl4_newrefdef.rdflags & RDF_UNDERWATER) != 0;
|
||||
gl4ShaderInfo_t* shader = underwater ? &gl4state.si2DpostProcessWater
|
||||
: &gl4state.si2DpostProcess;
|
||||
GL4_UseProgram(shader->shaderProgram);
|
||||
GL4_Bind(fboTexture);
|
||||
|
||||
if(underwater && shader->uniLmScalesOrTime != -1)
|
||||
{
|
||||
glUniform1f(shader->uniLmScalesOrTime, gl4_newrefdef.time);
|
||||
}
|
||||
if(shader->uniVblend != -1)
|
||||
{
|
||||
glUniform4fv(shader->uniVblend, 1, v_blend);
|
||||
}
|
||||
|
||||
drawTexturedRectangle(x, y, w, h, 0, 1, 1, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fills a box of pixels with a single color
|
||||
*/
|
||||
void
|
||||
GL4_Draw_Fill(int x, int y, int w, int h, int c)
|
||||
{
|
||||
union
|
||||
{
|
||||
unsigned c;
|
||||
byte v[4];
|
||||
} color;
|
||||
int i;
|
||||
|
||||
if ((unsigned)c > 255)
|
||||
{
|
||||
ri.Sys_Error(ERR_FATAL, "Draw_Fill: bad color");
|
||||
}
|
||||
|
||||
color.c = d_8to24table[c];
|
||||
|
||||
GLfloat vBuf[8] = {
|
||||
// X, Y
|
||||
x, y+h,
|
||||
x, y,
|
||||
x+w, y+h,
|
||||
x+w, y
|
||||
};
|
||||
|
||||
for(i=0; i<3; ++i)
|
||||
{
|
||||
gl4state.uniCommonData.color.Elements[i] = color.v[i] * (1.0f/255.0f);
|
||||
}
|
||||
gl4state.uniCommonData.color.A = 1.0f;
|
||||
|
||||
GL4_UpdateUBOCommon();
|
||||
|
||||
GL4_UseProgram(gl4state.si2Dcolor.shaderProgram);
|
||||
GL4_BindVAO(vao2Dcolor);
|
||||
|
||||
GL4_BindVBO(vbo2D);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vBuf), vBuf, GL_STREAM_DRAW);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
// in GL1 this is called R_Flash() (which just calls R_PolyBlend())
|
||||
// now implemented in 2D mode and called after SetGL2D() because
|
||||
// it's pretty similar to GL4_Draw_FadeScreen()
|
||||
void
|
||||
GL4_Draw_Flash(const float color[4], float x, float y, float w, float h)
|
||||
{
|
||||
if (gl_polyblend->value == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int i=0;
|
||||
|
||||
GLfloat vBuf[8] = {
|
||||
// X, Y
|
||||
x, y+h,
|
||||
x, y,
|
||||
x+w, y+h,
|
||||
x+w, y
|
||||
};
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
for(i=0; i<4; ++i) gl4state.uniCommonData.color.Elements[i] = color[i];
|
||||
|
||||
GL4_UpdateUBOCommon();
|
||||
|
||||
GL4_UseProgram(gl4state.si2Dcolor.shaderProgram);
|
||||
|
||||
GL4_BindVAO(vao2Dcolor);
|
||||
|
||||
GL4_BindVBO(vbo2D);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vBuf), vBuf, GL_STREAM_DRAW);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
void
|
||||
GL4_Draw_FadeScreen(void)
|
||||
{
|
||||
float color[4] = {0, 0, 0, 0.6f};
|
||||
GL4_Draw_Flash(color, 0, 0, vid.width, vid.height);
|
||||
}
|
||||
|
||||
void
|
||||
GL4_Draw_StretchRaw(int x, int y, int w, int h, int cols, int rows, const byte *data, int bits)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
GL4_Bind(0);
|
||||
|
||||
unsigned image32[320*240]; /* was 256 * 256, but we want a bit more space */
|
||||
|
||||
unsigned* img = image32;
|
||||
|
||||
if (bits == 32)
|
||||
{
|
||||
img = (unsigned *)data;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(cols*rows > 320*240)
|
||||
{
|
||||
/* in case there is a bigger video after all,
|
||||
* malloc enough space to hold the frame */
|
||||
img = (unsigned*)malloc(cols*rows*4);
|
||||
}
|
||||
|
||||
for(i=0; i<rows; ++i)
|
||||
{
|
||||
int rowOffset = i*cols;
|
||||
for(j=0; j<cols; ++j)
|
||||
{
|
||||
byte palIdx = data[rowOffset+j];
|
||||
img[rowOffset+j] = gl4_rawpalette[palIdx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GL4_UseProgram(gl4state.si2D.shaderProgram);
|
||||
|
||||
GLuint glTex;
|
||||
glGenTextures(1, &glTex);
|
||||
GL4_SelectTMU(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, glTex);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, gl4_tex_solid_format,
|
||||
cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, img);
|
||||
|
||||
if(img != image32 && img != (unsigned *)data)
|
||||
{
|
||||
free(img);
|
||||
}
|
||||
|
||||
// Note: gl_filter_min could be GL_*_MIPMAP_* so we can't use it for min filter here (=> no mipmaps)
|
||||
// but gl_filter_max (either GL_LINEAR or GL_NEAREST) should do the trick.
|
||||
GLint filter = (r_videos_unfiltered->value == 0) ? gl_filter_max : GL_NEAREST;
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
|
||||
|
||||
drawTexturedRectangle(x, y, w, h, 0.0f, 0.0f, 1.0f, 1.0f);
|
||||
|
||||
glDeleteTextures(1, &glTex);
|
||||
|
||||
GL4_Bind(0);
|
||||
}
|
845
src/client/refresh/gl4/gl4_image.c
Normal file
845
src/client/refresh/gl4/gl4_image.c
Normal file
|
@ -0,0 +1,845 @@
|
|||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
* Copyright (C) 2016-2017 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.
|
||||
*
|
||||
* =======================================================================
|
||||
*
|
||||
* Texture handling for OpenGL4
|
||||
*
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
#include "header/local.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
int minimize, maximize;
|
||||
} glmode_t;
|
||||
|
||||
glmode_t modes[] = {
|
||||
{"GL_NEAREST", GL_NEAREST, GL_NEAREST},
|
||||
{"GL_LINEAR", GL_LINEAR, GL_LINEAR},
|
||||
{"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
|
||||
{"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
|
||||
{"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
|
||||
{"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
|
||||
};
|
||||
|
||||
int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST;
|
||||
int gl_filter_max = GL_LINEAR;
|
||||
|
||||
gl4image_t gl4textures[MAX_GL4TEXTURES];
|
||||
int numgl4textures = 0;
|
||||
static int image_max = 0;
|
||||
|
||||
void
|
||||
GL4_TextureMode(char *string)
|
||||
{
|
||||
const int num_modes = sizeof(modes)/sizeof(modes[0]);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_modes; i++)
|
||||
{
|
||||
if (!Q_stricmp(modes[i].name, string))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == num_modes)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "bad filter name '%s' (probably from gl_texturemode)\n", string);
|
||||
return;
|
||||
}
|
||||
|
||||
gl_filter_min = modes[i].minimize;
|
||||
gl_filter_max = modes[i].maximize;
|
||||
|
||||
/* clamp selected anisotropy */
|
||||
if (gl4config.anisotropic)
|
||||
{
|
||||
if (gl_anisotropic->value > gl4config.max_anisotropy)
|
||||
{
|
||||
ri.Cvar_SetValue("r_anisotropic", gl4config.max_anisotropy);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Cvar_SetValue("r_anisotropic", 0.0);
|
||||
}
|
||||
|
||||
gl4image_t *glt;
|
||||
|
||||
const char* nolerplist = gl_nolerp_list->string;
|
||||
const char* lerplist = r_lerp_list->string;
|
||||
qboolean unfiltered2D = r_2D_unfiltered->value != 0;
|
||||
|
||||
/* change all the existing texture objects */
|
||||
for (i = 0, glt = gl4textures; i < numgl4textures; i++, glt++)
|
||||
{
|
||||
qboolean nolerp = false;
|
||||
/* r_2D_unfiltered and gl_nolerp_list allow rendering stuff unfiltered even if gl_filter_* is filtered */
|
||||
if (unfiltered2D && glt->type == it_pic)
|
||||
{
|
||||
// exception to that exception: stuff on the r_lerp_list
|
||||
nolerp = (lerplist== NULL) || (strstr(lerplist, glt->name) == NULL);
|
||||
}
|
||||
else if(nolerplist != NULL && strstr(nolerplist, glt->name) != NULL)
|
||||
{
|
||||
nolerp = true;
|
||||
}
|
||||
|
||||
GL4_SelectTMU(GL_TEXTURE0);
|
||||
GL4_Bind(glt->texnum);
|
||||
if ((glt->type != it_pic) && (glt->type != it_sky)) /* mipmapped texture */
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
|
||||
|
||||
/* Set anisotropic filter if supported and enabled */
|
||||
if (gl4config.anisotropic && gl_anisotropic->value)
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, max(gl_anisotropic->value, 1.f));
|
||||
}
|
||||
}
|
||||
else /* texture has no mipmaps */
|
||||
{
|
||||
if (nolerp)
|
||||
{
|
||||
// this texture shouldn't be filtered at all (no gl_nolerp_list or r_2D_unfiltered case)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we can't use gl_filter_min which might be GL_*_MIPMAP_*
|
||||
// also, there's no anisotropic filtering for textures w/o mipmaps
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GL4_Bind(GLuint texnum)
|
||||
{
|
||||
extern gl4image_t *draw_chars;
|
||||
|
||||
if (gl_nobind->value && draw_chars) /* performance evaluation option */
|
||||
{
|
||||
texnum = draw_chars->texnum;
|
||||
}
|
||||
|
||||
if (gl4state.currenttexture == texnum)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gl4state.currenttexture = texnum;
|
||||
GL4_SelectTMU(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, texnum);
|
||||
}
|
||||
|
||||
void
|
||||
GL4_BindLightmap(int lightmapnum)
|
||||
{
|
||||
int i=0;
|
||||
if(lightmapnum < 0 || lightmapnum >= MAX_LIGHTMAPS)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "WARNING: Invalid lightmapnum %i used!\n", lightmapnum);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gl4state.currentlightmap == lightmapnum)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gl4state.currentlightmap = lightmapnum;
|
||||
for(i=0; i<MAX_LIGHTMAPS_PER_SURFACE; ++i)
|
||||
{
|
||||
// this assumes that GL_TEXTURE<i+1> = GL_TEXTURE<i> + 1
|
||||
// at least for GL_TEXTURE0 .. GL_TEXTURE31 that's true
|
||||
GL4_SelectTMU(GL_TEXTURE1+i);
|
||||
glBindTexture(GL_TEXTURE_2D, gl4state.lightmap_textureIDs[lightmapnum][i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns has_alpha
|
||||
*/
|
||||
qboolean
|
||||
GL4_Upload32(unsigned *data, int width, int height, qboolean mipmap)
|
||||
{
|
||||
qboolean res;
|
||||
|
||||
int i;
|
||||
int c = width * height;
|
||||
byte *scan = ((byte *)data) + 3;
|
||||
int comp = gl4_tex_solid_format;
|
||||
int samples = gl4_solid_format;
|
||||
|
||||
for (i = 0; i < c; i++, scan += 4)
|
||||
{
|
||||
if (*scan != 255)
|
||||
{
|
||||
samples = gl4_alpha_format;
|
||||
comp = gl4_tex_alpha_format;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, comp, width, height,
|
||||
0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
|
||||
res = (samples == gl4_alpha_format);
|
||||
|
||||
if (mipmap)
|
||||
{
|
||||
// TODO: some hardware may require mipmapping disabled for NPOT textures!
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
|
||||
}
|
||||
else // if the texture has no mipmaps, we can't use gl_filter_min which might be GL_*_MIPMAP_*
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
|
||||
}
|
||||
|
||||
if (mipmap && gl4config.anisotropic && gl_anisotropic->value)
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, max(gl_anisotropic->value, 1.f));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns has_alpha
|
||||
*/
|
||||
qboolean
|
||||
GL4_Upload8(byte *data, int width, int height, qboolean mipmap, qboolean is_sky)
|
||||
{
|
||||
int s = width * height;
|
||||
unsigned *trans = malloc(s * sizeof(unsigned));
|
||||
|
||||
for (int i = 0; i < s; i++)
|
||||
{
|
||||
int p = data[i];
|
||||
trans[i] = d_8to24table[p];
|
||||
|
||||
/* transparent, so scan around for
|
||||
another color to avoid alpha fringes */
|
||||
if (p == 255)
|
||||
{
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
qboolean ret = GL4_Upload32(trans, width, height, mipmap);
|
||||
free(trans);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is also used as an entry point for the generated r_notexture
|
||||
*/
|
||||
gl4image_t *
|
||||
GL4_LoadPic(char *name, byte *pic, int width, int realwidth,
|
||||
int height, int realheight, size_t data_size,
|
||||
imagetype_t type, int bits)
|
||||
{
|
||||
gl4image_t *image = NULL;
|
||||
GLuint texNum=0;
|
||||
int i;
|
||||
|
||||
qboolean nolerp = false;
|
||||
if (r_2D_unfiltered->value && type == it_pic)
|
||||
{
|
||||
// if r_2D_unfiltered is true(ish), nolerp should usually be true,
|
||||
// *unless* the texture is on the r_lerp_list
|
||||
nolerp = (r_lerp_list->string == NULL) || (strstr(r_lerp_list->string, name) == NULL);
|
||||
}
|
||||
else if (gl_nolerp_list != NULL && gl_nolerp_list->string != NULL)
|
||||
{
|
||||
nolerp = strstr(gl_nolerp_list->string, name) != NULL;
|
||||
}
|
||||
/* find a free gl4image_t */
|
||||
for (i = 0, image = gl4textures; i < numgl4textures; i++, image++)
|
||||
{
|
||||
if (image->texnum == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == numgl4textures)
|
||||
{
|
||||
if (numgl4textures == MAX_GL4TEXTURES)
|
||||
{
|
||||
ri.Sys_Error(ERR_DROP, "MAX_GLTEXTURES");
|
||||
}
|
||||
|
||||
numgl4textures++;
|
||||
}
|
||||
|
||||
image = &gl4textures[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;
|
||||
|
||||
image->width = width;
|
||||
image->height = height;
|
||||
image->type = type;
|
||||
|
||||
if ((type == it_skin) && (bits == 8))
|
||||
{
|
||||
FloodFillSkin(pic, width, height);
|
||||
}
|
||||
|
||||
image->is_lava = (strstr(name, "lava") != NULL);
|
||||
|
||||
// image->scrap = false; // TODO: reintroduce scrap? would allow optimizations in 2D rendering..
|
||||
|
||||
glGenTextures(1, &texNum);
|
||||
|
||||
image->texnum = texNum;
|
||||
|
||||
GL4_SelectTMU(GL_TEXTURE0);
|
||||
GL4_Bind(texNum);
|
||||
|
||||
if (bits == 8)
|
||||
{
|
||||
// resize 8bit images only when we forced such logic
|
||||
if (r_scale8bittextures->value)
|
||||
{
|
||||
byte *image_converted;
|
||||
int scale = 2;
|
||||
|
||||
// scale 3 times if lerp image
|
||||
if (!nolerp && (vid.height >= 240 * 3))
|
||||
scale = 3;
|
||||
|
||||
image_converted = malloc(width * height * scale * scale);
|
||||
if (!image_converted)
|
||||
return NULL;
|
||||
|
||||
if (scale == 3) {
|
||||
scale3x(pic, image_converted, width, height);
|
||||
} else {
|
||||
scale2x(pic, image_converted, width, height);
|
||||
}
|
||||
|
||||
image->has_alpha = GL4_Upload8(image_converted, width * scale, height * scale,
|
||||
(image->type != it_pic && image->type != it_sky),
|
||||
image->type == it_sky);
|
||||
free(image_converted);
|
||||
}
|
||||
else
|
||||
{
|
||||
image->has_alpha = GL4_Upload8(pic, width, height,
|
||||
(image->type != it_pic && image->type != it_sky),
|
||||
image->type == it_sky);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
image->has_alpha = GL4_Upload32((unsigned *)pic, width, height,
|
||||
(image->type != it_pic && image->type != it_sky));
|
||||
}
|
||||
|
||||
if (realwidth && realheight)
|
||||
{
|
||||
if ((realwidth <= image->width) && (realheight <= image->height))
|
||||
{
|
||||
image->width = realwidth;
|
||||
image->height = realheight;
|
||||
}
|
||||
else
|
||||
{
|
||||
R_Printf(PRINT_DEVELOPER,
|
||||
"Warning, image '%s' has hi-res replacement smaller than the original! (%d x %d) < (%d x %d)\n",
|
||||
name, image->width, image->height, realwidth, realheight);
|
||||
}
|
||||
}
|
||||
|
||||
image->sl = 0;
|
||||
image->sh = 1;
|
||||
image->tl = 0;
|
||||
image->th = 1;
|
||||
|
||||
if (nolerp)
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
#if 0 // TODO: the scrap could allow batch rendering 2D stuff? not sure it's worth the hassle..
|
||||
/* load little pics into the scrap */
|
||||
if (!nolerp && (image->type == it_pic) && (bits == 8) &&
|
||||
(image->width < 64) && (image->height < 64))
|
||||
{
|
||||
int x, y;
|
||||
int i, j, k;
|
||||
int texnum;
|
||||
|
||||
texnum = Scrap_AllocBlock(image->width, image->height, &x, &y);
|
||||
|
||||
if (texnum == -1)
|
||||
{
|
||||
goto nonscrap;
|
||||
}
|
||||
|
||||
scrap_dirty = true;
|
||||
|
||||
/* copy the texels into the scrap block */
|
||||
k = 0;
|
||||
|
||||
for (i = 0; i < image->height; i++)
|
||||
{
|
||||
for (j = 0; j < image->width; j++, k++)
|
||||
{
|
||||
scrap_texels[texnum][(y + i) * BLOCK_WIDTH + x + j] = pic[k];
|
||||
}
|
||||
}
|
||||
|
||||
image->texnum = TEXNUM_SCRAPS + texnum;
|
||||
image->scrap = true;
|
||||
image->has_alpha = true;
|
||||
image->sl = (x + 0.01) / (float)BLOCK_WIDTH;
|
||||
image->sh = (x + image->width - 0.01) / (float)BLOCK_WIDTH;
|
||||
image->tl = (y + 0.01) / (float)BLOCK_WIDTH;
|
||||
image->th = (y + image->height - 0.01) / (float)BLOCK_WIDTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
nonscrap:
|
||||
image->scrap = false;
|
||||
image->texnum = TEXNUM_IMAGES + (image - gltextures);
|
||||
R_Bind(image->texnum);
|
||||
|
||||
if (bits == 8)
|
||||
{
|
||||
image->has_alpha = R_Upload8(pic, width, height,
|
||||
(image->type != it_pic && image->type != it_sky),
|
||||
image->type == it_sky);
|
||||
}
|
||||
else
|
||||
{
|
||||
image->has_alpha = R_Upload32((unsigned *)pic, width, height,
|
||||
(image->type != it_pic && image->type != it_sky));
|
||||
}
|
||||
|
||||
image->upload_width = upload_width; /* after power of 2 and scales */
|
||||
image->upload_height = upload_height;
|
||||
image->paletted = uploaded_paletted;
|
||||
|
||||
if (realwidth && realheight)
|
||||
{
|
||||
if ((realwidth <= image->width) && (realheight <= image->height))
|
||||
{
|
||||
image->width = realwidth;
|
||||
image->height = realheight;
|
||||
}
|
||||
else
|
||||
{
|
||||
R_Printf(PRINT_DEVELOPER,
|
||||
"Warning, image '%s' has hi-res replacement smaller than the original! (%d x %d) < (%d x %d)\n",
|
||||
name, image->width, image->height, realwidth, realheight);
|
||||
}
|
||||
}
|
||||
|
||||
image->sl = 0;
|
||||
image->sh = 1;
|
||||
image->tl = 0;
|
||||
image->th = 1;
|
||||
|
||||
if (nolerp)
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
}
|
||||
#endif // 0
|
||||
return image;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds or loads the given image or NULL
|
||||
*/
|
||||
gl4image_t *
|
||||
GL4_FindImage(const char *name, imagetype_t type)
|
||||
{
|
||||
gl4image_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 = gl4textures; i < numgl4textures; i++, image++)
|
||||
{
|
||||
if (!strcmp(name, image->name))
|
||||
{
|
||||
image->registration_sequence = registration_sequence;
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// load the pic from disk
|
||||
//
|
||||
image = (gl4image_t *)R_LoadImage(name, namewe, ext, type,
|
||||
r_retexturing->value, (loadimage_t)GL4_LoadPic);
|
||||
|
||||
if (!image && r_validation->value)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "%s: can't load %s\n", __func__, name);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
gl4image_t *
|
||||
GL4_RegisterSkin(char *name)
|
||||
{
|
||||
return GL4_FindImage(name, it_skin);
|
||||
}
|
||||
|
||||
/*
|
||||
* Any image that was not touched on
|
||||
* this registration sequence
|
||||
* will be freed.
|
||||
*/
|
||||
void
|
||||
GL4_FreeUnusedImages(void)
|
||||
{
|
||||
int i;
|
||||
gl4image_t *image;
|
||||
|
||||
/* never free r_notexture or particle texture */
|
||||
gl4_notexture->registration_sequence = registration_sequence;
|
||||
gl4_particletexture->registration_sequence = registration_sequence;
|
||||
|
||||
for (i = 0, image = gl4textures; i < numgl4textures; 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 */
|
||||
}
|
||||
|
||||
/* free it */
|
||||
glDeleteTextures(1, &image->texnum);
|
||||
memset(image, 0, sizeof(*image));
|
||||
}
|
||||
}
|
||||
|
||||
qboolean
|
||||
GL4_ImageHasFreeSpace(void)
|
||||
{
|
||||
int i, used;
|
||||
gl4image_t *image;
|
||||
|
||||
used = 0;
|
||||
|
||||
for (i = 0, image = gl4textures; i < numgl4textures; 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 (numgl4textures + used) < MAX_GL4TEXTURES;
|
||||
}
|
||||
|
||||
void
|
||||
GL4_ShutdownImages(void)
|
||||
{
|
||||
int i;
|
||||
gl4image_t *image;
|
||||
|
||||
for (i = 0, image = gl4textures; i < numgl4textures; i++, image++)
|
||||
{
|
||||
if (!image->registration_sequence)
|
||||
{
|
||||
continue; /* free image_t slot */
|
||||
}
|
||||
|
||||
/* free it */
|
||||
glDeleteTextures(1, &image->texnum);
|
||||
memset(image, 0, sizeof(*image));
|
||||
}
|
||||
}
|
||||
|
||||
static qboolean IsNPOT(int v)
|
||||
{
|
||||
unsigned int uv = v;
|
||||
// just try all the power of two values between 1 and 1 << 15 (32k)
|
||||
for(unsigned int i=0; i<16; ++i)
|
||||
{
|
||||
unsigned int pot = (1u << i);
|
||||
if(uv & pot)
|
||||
{
|
||||
return uv != pot;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
GL4_ImageList_f(void)
|
||||
{
|
||||
int i, used, texels;
|
||||
qboolean freeup;
|
||||
gl4image_t *image;
|
||||
const char *formatstrings[2] = {
|
||||
"RGB ",
|
||||
"RGBA"
|
||||
};
|
||||
|
||||
const char* potstrings[2] = {
|
||||
" POT", "NPOT"
|
||||
};
|
||||
|
||||
R_Printf(PRINT_ALL, "------------------\n");
|
||||
texels = 0;
|
||||
used = 0;
|
||||
|
||||
for (i = 0, image = gl4textures; i < numgl4textures; i++, image++)
|
||||
{
|
||||
int w, h;
|
||||
char *in_use = "";
|
||||
qboolean isNPOT = false;
|
||||
if (image->texnum == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (image->registration_sequence == registration_sequence)
|
||||
{
|
||||
in_use = "*";
|
||||
used++;
|
||||
}
|
||||
|
||||
w = image->width;
|
||||
h = image->height;
|
||||
|
||||
isNPOT = IsNPOT(w) || IsNPOT(h);
|
||||
|
||||
texels += w*h;
|
||||
|
||||
char imageType = '?';
|
||||
switch (image->type)
|
||||
{
|
||||
case it_skin:
|
||||
imageType = 'M';
|
||||
break;
|
||||
case it_sprite:
|
||||
imageType = 'S';
|
||||
break;
|
||||
case it_wall:
|
||||
imageType = 'W';
|
||||
break;
|
||||
case it_pic:
|
||||
imageType = 'P';
|
||||
break;
|
||||
case it_sky:
|
||||
imageType = 'Y';
|
||||
break;
|
||||
default:
|
||||
imageType = '?';
|
||||
break;
|
||||
}
|
||||
char isLava = image->is_lava ? 'L' : ' ';
|
||||
|
||||
R_Printf(PRINT_ALL, "%c%c %3i %3i %s %s: %s %s\n", imageType, isLava, w, h,
|
||||
formatstrings[image->has_alpha], potstrings[isNPOT], image->name, in_use);
|
||||
}
|
||||
|
||||
R_Printf(PRINT_ALL, "Total texel count (not counting mipmaps): %i\n", texels);
|
||||
freeup = GL4_ImageHasFreeSpace();
|
||||
R_Printf(PRINT_ALL, "Used %d of %d images%s.\n", used, image_max, freeup ? ", has free space" : "");
|
||||
}
|
403
src/client/refresh/gl4/gl4_light.c
Normal file
403
src/client/refresh/gl4/gl4_light.c
Normal file
|
@ -0,0 +1,403 @@
|
|||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
* Copyright (C) 2016-2017 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.
|
||||
*
|
||||
* =======================================================================
|
||||
*
|
||||
* Lightmaps and dynamic lighting
|
||||
*
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
#include "header/local.h"
|
||||
|
||||
extern gl4lightmapstate_t gl4_lms;
|
||||
|
||||
int r_dlightframecount;
|
||||
static vec3_t pointcolor;
|
||||
static cplane_t *lightplane; /* used as shadow plane */
|
||||
vec3_t lightspot;
|
||||
|
||||
void
|
||||
GL4_MarkSurfaceLights(dlight_t *light, int bit, mnode_t *node, int r_dlightframecount)
|
||||
{
|
||||
msurface_t *surf;
|
||||
int i;
|
||||
|
||||
/* mark the polygons */
|
||||
surf = gl4_worldmodel->surfaces + node->firstsurface;
|
||||
|
||||
for (i = 0; i < node->numsurfaces; i++, surf++)
|
||||
{
|
||||
int sidebit;
|
||||
float dist;
|
||||
|
||||
if (surf->dlightframe != r_dlightframecount)
|
||||
{
|
||||
surf->dlightbits = 0;
|
||||
surf->dlightframe = r_dlightframecount;
|
||||
}
|
||||
|
||||
dist = DotProduct(light->origin, surf->plane->normal) - surf->plane->dist;
|
||||
|
||||
if (dist >= 0)
|
||||
{
|
||||
sidebit = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sidebit = SURF_PLANEBACK;
|
||||
}
|
||||
|
||||
if ((surf->flags & SURF_PLANEBACK) != sidebit)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
surf->dlightbits |= bit;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GL4_PushDlights(void)
|
||||
{
|
||||
int i;
|
||||
dlight_t *l;
|
||||
|
||||
/* because the count hasn't advanced yet for this frame */
|
||||
r_dlightframecount = gl4_framecount + 1;
|
||||
|
||||
l = gl4_newrefdef.dlights;
|
||||
|
||||
gl4state.uniLightsData.numDynLights = gl4_newrefdef.num_dlights;
|
||||
|
||||
for (i = 0; i < gl4_newrefdef.num_dlights; i++, l++)
|
||||
{
|
||||
gl4UniDynLight* udl = &gl4state.uniLightsData.dynLights[i];
|
||||
R_MarkLights(l, 1 << i, gl4_worldmodel->nodes, r_dlightframecount, GL4_MarkSurfaceLights);
|
||||
|
||||
VectorCopy(l->origin, udl->origin);
|
||||
VectorCopy(l->color, udl->color);
|
||||
udl->intensity = l->intensity;
|
||||
}
|
||||
|
||||
assert(MAX_DLIGHTS == 32 && "If MAX_DLIGHTS changes, remember to adjust the uniform buffer definition in the shader!");
|
||||
|
||||
if(i < MAX_DLIGHTS)
|
||||
{
|
||||
memset(&gl4state.uniLightsData.dynLights[i], 0, (MAX_DLIGHTS-i)*sizeof(gl4state.uniLightsData.dynLights[0]));
|
||||
}
|
||||
|
||||
GL4_UpdateUBOLights();
|
||||
}
|
||||
|
||||
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 != CONTENTS_NODE)
|
||||
{
|
||||
return -1; /* didn't hit anything */
|
||||
}
|
||||
|
||||
/* calculate mid point */
|
||||
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 */
|
||||
}
|
||||
|
||||
if ((back < 0) == side)
|
||||
{
|
||||
return -1; /* didn't hit anuthing */
|
||||
}
|
||||
|
||||
/* check for impact on this node */
|
||||
VectorCopy(mid, lightspot);
|
||||
lightplane = plane;
|
||||
|
||||
surf = gl4_worldmodel->surfaces + node->firstsurface;
|
||||
|
||||
for (i = 0; i < node->numsurfaces; i++, surf++)
|
||||
{
|
||||
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 < MAX_LIGHTMAPS_PER_SURFACE && surf->styles[maps] != 255;
|
||||
maps++)
|
||||
{
|
||||
const float *rgb;
|
||||
int j;
|
||||
|
||||
rgb = gl4_newrefdef.lightstyles[surf->styles[maps]].rgb;
|
||||
|
||||
/* Apply light level to models */
|
||||
for (j = 0; j < 3; j++)
|
||||
{
|
||||
float scale;
|
||||
|
||||
scale = rgb[j] * r_modulate->value;
|
||||
pointcolor[j] += lightmap[j] * scale * (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);
|
||||
}
|
||||
|
||||
void
|
||||
GL4_LightPoint(entity_t *currententity, vec3_t p, vec3_t color)
|
||||
{
|
||||
vec3_t end;
|
||||
float r;
|
||||
int lnum;
|
||||
dlight_t *dl;
|
||||
vec3_t dist;
|
||||
float add;
|
||||
|
||||
if (!gl4_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;
|
||||
|
||||
// TODO: don't just aggregate the color, but also save position of brightest+nearest light
|
||||
// for shadow position and maybe lighting on model?
|
||||
|
||||
r = RecursiveLightPoint(gl4_worldmodel->nodes, p, end);
|
||||
|
||||
if (r == -1)
|
||||
{
|
||||
VectorCopy(vec3_origin, color);
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorCopy(pointcolor, color);
|
||||
}
|
||||
|
||||
/* add dynamic lights */
|
||||
dl = gl4_newrefdef.dlights;
|
||||
|
||||
for (lnum = 0; lnum < gl4_newrefdef.num_dlights; lnum++, dl++)
|
||||
{
|
||||
VectorSubtract(currententity->origin,
|
||||
dl->origin, dist);
|
||||
add = dl->intensity - VectorLength(dist);
|
||||
add *= (1.0f / 256.0f);
|
||||
|
||||
if (add > 0)
|
||||
{
|
||||
VectorMA(color, add, dl->color, color);
|
||||
}
|
||||
}
|
||||
|
||||
VectorScale(color, r_modulate->value, color);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Combine and scale multiple lightmaps into the floating format in blocklights
|
||||
*/
|
||||
void
|
||||
GL4_BuildLightMap(msurface_t *surf, int offsetInLMbuf, int stride)
|
||||
{
|
||||
int smax, tmax;
|
||||
int r, g, b, a, max;
|
||||
int i, j, size, map, numMaps;
|
||||
byte *lightmap;
|
||||
|
||||
if (surf->texinfo->flags &
|
||||
(SURF_SKY | SURF_TRANS33 | SURF_TRANS66 | SURF_WARP))
|
||||
{
|
||||
ri.Sys_Error(ERR_DROP, "GL4_BuildLightMap called for non-lit surface");
|
||||
}
|
||||
|
||||
smax = (surf->extents[0] >> 4) + 1;
|
||||
tmax = (surf->extents[1] >> 4) + 1;
|
||||
size = smax * tmax;
|
||||
|
||||
stride -= (smax << 2);
|
||||
|
||||
if (size > 34*34*3)
|
||||
{
|
||||
ri.Sys_Error(ERR_DROP, "Bad s_blocklights size");
|
||||
}
|
||||
|
||||
// count number of lightmaps surf actually has
|
||||
for (numMaps = 0; numMaps < MAX_LIGHTMAPS_PER_SURFACE && surf->styles[numMaps] != 255; ++numMaps)
|
||||
{}
|
||||
|
||||
if (!surf->samples)
|
||||
{
|
||||
// no lightmap samples? set at least one lightmap to fullbright, rest to 0 as normal
|
||||
|
||||
if (numMaps == 0) numMaps = 1; // make sure at least one lightmap is set to fullbright
|
||||
|
||||
for (map = 0; map < MAX_LIGHTMAPS_PER_SURFACE; ++map)
|
||||
{
|
||||
// we always create 4 (MAX_LIGHTMAPS_PER_SURFACE) lightmaps.
|
||||
// if surf has less (numMaps < 4), the remaining ones are zeroed out.
|
||||
// this makes sure that all 4 lightmap textures in gl4state.lightmap_textureIDs[i] have the same layout
|
||||
// and the shader can use the same texture coordinates for all of them
|
||||
|
||||
int c = (map < numMaps) ? 255 : 0;
|
||||
byte* dest = gl4_lms.lightmap_buffers[map] + offsetInLMbuf;
|
||||
|
||||
for (i = 0; i < tmax; i++, dest += stride)
|
||||
{
|
||||
memset(dest, c, 4*smax);
|
||||
dest += 4*smax;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* add all the lightmaps */
|
||||
|
||||
// Note: dynamic lights aren't handled here anymore, they're handled in the shader
|
||||
|
||||
// as we don't apply scale here anymore, nor blend the numMaps lightmaps together,
|
||||
// the code has gotten a lot easier and we can copy directly from surf->samples to dest
|
||||
// without converting to float first etc
|
||||
|
||||
lightmap = surf->samples;
|
||||
|
||||
for(map=0; map<numMaps; ++map)
|
||||
{
|
||||
byte* dest = gl4_lms.lightmap_buffers[map] + offsetInLMbuf;
|
||||
int idxInLightmap = 0;
|
||||
for (i = 0; i < tmax; i++, dest += stride)
|
||||
{
|
||||
for (j = 0; j < smax; j++)
|
||||
{
|
||||
r = lightmap[idxInLightmap * 3 + 0];
|
||||
g = lightmap[idxInLightmap * 3 + 1];
|
||||
b = lightmap[idxInLightmap * 3 + 2];
|
||||
|
||||
/* 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;
|
||||
|
||||
dest[0] = r;
|
||||
dest[1] = g;
|
||||
dest[2] = b;
|
||||
dest[3] = a;
|
||||
|
||||
dest += 4;
|
||||
++idxInLightmap;
|
||||
}
|
||||
}
|
||||
|
||||
lightmap += size * 3; /* skip to next lightmap */
|
||||
}
|
||||
|
||||
for ( ; map < MAX_LIGHTMAPS_PER_SURFACE; ++map)
|
||||
{
|
||||
// like above, fill up remaining lightmaps with 0
|
||||
|
||||
byte* dest = gl4_lms.lightmap_buffers[map] + offsetInLMbuf;
|
||||
|
||||
for (i = 0; i < tmax; i++, dest += stride)
|
||||
{
|
||||
memset(dest, 0, 4*smax);
|
||||
dest += 4*smax;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
268
src/client/refresh/gl4/gl4_lightmap.c
Normal file
268
src/client/refresh/gl4/gl4_lightmap.c
Normal file
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
* Copyright (C) 2016-2017 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.
|
||||
*
|
||||
* =======================================================================
|
||||
*
|
||||
* Lightmap handling
|
||||
*
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
#include "header/local.h"
|
||||
|
||||
|
||||
#define TEXNUM_LIGHTMAPS 1024
|
||||
|
||||
extern gl4lightmapstate_t gl4_lms;
|
||||
|
||||
void
|
||||
GL4_LM_InitBlock(void)
|
||||
{
|
||||
memset(gl4_lms.allocated, 0, sizeof(gl4_lms.allocated));
|
||||
}
|
||||
|
||||
void
|
||||
GL4_LM_UploadBlock(void)
|
||||
{
|
||||
int map;
|
||||
|
||||
// NOTE: we don't use the dynamic lightmap anymore - all lightmaps are loaded at level load
|
||||
// and not changed after that. they're blended dynamically depending on light styles
|
||||
// though, and dynamic lights are (will be) applied in shader, hopefully per fragment.
|
||||
|
||||
GL4_BindLightmap(gl4_lms.current_lightmap_texture);
|
||||
|
||||
// upload all 4 lightmaps
|
||||
for(map=0; map < MAX_LIGHTMAPS_PER_SURFACE; ++map)
|
||||
{
|
||||
GL4_SelectTMU(GL_TEXTURE1+map); // this relies on GL_TEXTURE2 being GL_TEXTURE1+1 etc
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
gl4_lms.internal_format = GL_LIGHTMAP_FORMAT;
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, gl4_lms.internal_format,
|
||||
BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_LIGHTMAP_FORMAT,
|
||||
GL_UNSIGNED_BYTE, gl4_lms.lightmap_buffers[map]);
|
||||
}
|
||||
|
||||
if (++gl4_lms.current_lightmap_texture == MAX_LIGHTMAPS)
|
||||
{
|
||||
ri.Sys_Error(ERR_DROP, "LM_UploadBlock() - MAX_LIGHTMAPS exceeded\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* returns a texture number and the position inside it
|
||||
*/
|
||||
qboolean
|
||||
GL4_LM_AllocBlock(int w, int h, int *x, int *y)
|
||||
{
|
||||
int i, j;
|
||||
int best, best2;
|
||||
|
||||
best = BLOCK_HEIGHT;
|
||||
|
||||
for (i = 0; i < BLOCK_WIDTH - w; i++)
|
||||
{
|
||||
best2 = 0;
|
||||
|
||||
for (j = 0; j < w; j++)
|
||||
{
|
||||
if (gl4_lms.allocated[i + j] >= best)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (gl4_lms.allocated[i + j] > best2)
|
||||
{
|
||||
best2 = gl4_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; i < w; i++)
|
||||
{
|
||||
gl4_lms.allocated[*x + i] = best + h;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
GL4_LM_BuildPolygonFromSurface(gl4model_t *currentmodel, msurface_t *fa)
|
||||
{
|
||||
int i, lindex, lnumverts;
|
||||
medge_t *pedges, *r_pedge;
|
||||
float *vec;
|
||||
float s, t;
|
||||
glpoly_t *poly;
|
||||
vec3_t total;
|
||||
vec3_t normal;
|
||||
|
||||
/* reconstruct the polygon */
|
||||
pedges = currentmodel->edges;
|
||||
lnumverts = fa->numedges;
|
||||
|
||||
VectorClear(total);
|
||||
|
||||
/* draw texture */
|
||||
poly = Hunk_Alloc(sizeof(glpoly_t) +
|
||||
(lnumverts - 4) * sizeof(gl4_3D_vtx_t));
|
||||
poly->next = fa->polys;
|
||||
poly->flags = fa->flags;
|
||||
fa->polys = poly;
|
||||
poly->numverts = lnumverts;
|
||||
|
||||
VectorCopy(fa->plane->normal, normal);
|
||||
|
||||
if(fa->flags & SURF_PLANEBACK)
|
||||
{
|
||||
// if for some reason the normal sticks to the back of the plane, invert it
|
||||
// so it's usable for the shader
|
||||
for (i=0; i<3; ++i) normal[i] = -normal[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < lnumverts; i++)
|
||||
{
|
||||
gl4_3D_vtx_t* vert = &poly->vertices[i];
|
||||
|
||||
lindex = currentmodel->surfedges[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, vert->pos);
|
||||
vert->texCoord[0] = s;
|
||||
vert->texCoord[1] = 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; */
|
||||
|
||||
vert->lmTexCoord[0] = s;
|
||||
vert->lmTexCoord[1] = t;
|
||||
|
||||
VectorCopy(normal, vert->normal);
|
||||
vert->lightFlags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GL4_LM_CreateSurfaceLightmap(msurface_t *surf)
|
||||
{
|
||||
int smax, tmax;
|
||||
|
||||
if (surf->flags & (SURF_DRAWSKY | SURF_DRAWTURB))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
smax = (surf->extents[0] >> 4) + 1;
|
||||
tmax = (surf->extents[1] >> 4) + 1;
|
||||
|
||||
if (!GL4_LM_AllocBlock(smax, tmax, &surf->light_s, &surf->light_t))
|
||||
{
|
||||
GL4_LM_UploadBlock();
|
||||
GL4_LM_InitBlock();
|
||||
|
||||
if (!GL4_LM_AllocBlock(smax, tmax, &surf->light_s, &surf->light_t))
|
||||
{
|
||||
ri.Sys_Error(ERR_FATAL, "Consecutive calls to LM_AllocBlock(%d,%d) failed\n",
|
||||
smax, tmax);
|
||||
}
|
||||
}
|
||||
|
||||
surf->lightmaptexturenum = gl4_lms.current_lightmap_texture;
|
||||
|
||||
GL4_BuildLightMap(surf, (surf->light_t * BLOCK_WIDTH + surf->light_s) * LIGHTMAP_BYTES, BLOCK_WIDTH * LIGHTMAP_BYTES);
|
||||
}
|
||||
|
||||
void
|
||||
GL4_LM_BeginBuildingLightmaps(gl4model_t *m)
|
||||
{
|
||||
|
||||
static lightstyle_t lightstyles[MAX_LIGHTSTYLES];
|
||||
int i;
|
||||
|
||||
memset(gl4_lms.allocated, 0, sizeof(gl4_lms.allocated));
|
||||
|
||||
gl4_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;
|
||||
}
|
||||
|
||||
gl4_newrefdef.lightstyles = lightstyles;
|
||||
|
||||
gl4_lms.current_lightmap_texture = 0;
|
||||
gl4_lms.internal_format = GL_LIGHTMAP_FORMAT;
|
||||
|
||||
// Note: the dynamic lightmap used to be initialized here, we don't use that anymore.
|
||||
}
|
||||
|
||||
void
|
||||
GL4_LM_EndBuildingLightmaps(void)
|
||||
{
|
||||
GL4_LM_UploadBlock();
|
||||
}
|
||||
|
2059
src/client/refresh/gl4/gl4_main.c
Normal file
2059
src/client/refresh/gl4/gl4_main.c
Normal file
File diff suppressed because it is too large
Load diff
1002
src/client/refresh/gl4/gl4_mesh.c
Normal file
1002
src/client/refresh/gl4/gl4_mesh.c
Normal file
File diff suppressed because it is too large
Load diff
171
src/client/refresh/gl4/gl4_misc.c
Normal file
171
src/client/refresh/gl4/gl4_misc.c
Normal file
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
* Copyright (C) 2016-2017 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.
|
||||
*
|
||||
* =======================================================================
|
||||
*
|
||||
* Misc OpenGL4 refresher functions
|
||||
*
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
#include "header/local.h"
|
||||
|
||||
gl4image_t *gl4_notexture; /* use for bad textures */
|
||||
gl4image_t *gl4_particletexture; /* little dot for particles */
|
||||
|
||||
void
|
||||
GL4_SetDefaultState(void)
|
||||
{
|
||||
glClearColor(1, 0, 0.5, 0.5);
|
||||
#ifndef YQ2_GL3_GLES
|
||||
// in GLES this is only supported with an extension:
|
||||
// https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_multisample_compatibility.txt
|
||||
// but apparently it's just enabled by default if set in the context?
|
||||
glDisable(GL_MULTISAMPLE);
|
||||
#endif
|
||||
glCullFace(GL_FRONT);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
#ifndef YQ2_GL3_GLES
|
||||
// in GLES GL_FILL is the only supported mode
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
#endif
|
||||
|
||||
// TODO: gl1_texturealphamode?
|
||||
GL4_TextureMode(gl_texturemode->string);
|
||||
//R_TextureAlphaMode(gl1_texturealphamode->string);
|
||||
//R_TextureSolidMode(gl1_texturesolidmode->string);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
#ifndef YQ2_GL3_GLES // see above
|
||||
if (gl_msaa_samples->value)
|
||||
{
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
// glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST); TODO what is this for?
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
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
|
||||
GL4_InitParticleTexture(void)
|
||||
{
|
||||
int x, y;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
gl4_particletexture = GL4_LoadPic("***particle***", (byte *)data,
|
||||
8, 0, 8, 0, 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;
|
||||
}
|
||||
}
|
||||
|
||||
gl4_notexture = GL4_LoadPic("***r_notexture***", (byte *)data,
|
||||
8, 0, 8, 0, 8 * 8, it_wall, 32);
|
||||
}
|
||||
|
||||
void
|
||||
GL4_ScreenShot(void)
|
||||
{
|
||||
int w=vid.width, h=vid.height;
|
||||
|
||||
#ifdef YQ2_GL3_GLES
|
||||
// My RPi4's GLES3 doesn't like GL_RGB, so use GL_RGBA with GLES
|
||||
// TODO: we could convert the screenshot to RGB before writing
|
||||
// so the resulting file is smaller
|
||||
static const int comps = 4;
|
||||
#else // Desktop GL
|
||||
static const int comps = 3;
|
||||
#endif
|
||||
byte *buffer = malloc(w*h*comps);
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "GL4_ScreenShot: Couldn't malloc %d bytes\n", w*h*3);
|
||||
return;
|
||||
}
|
||||
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glReadPixels(0, 0, w, h, (comps == 4) ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, buffer);
|
||||
|
||||
// the pixels are now row-wise left to right, bottom to top,
|
||||
// but we need them row-wise left to right, top to bottom.
|
||||
// so swap bottom rows with top rows
|
||||
{
|
||||
size_t bytesPerRow = comps*w;
|
||||
YQ2_VLA(byte, rowBuffer, bytesPerRow);
|
||||
byte *curRowL = buffer; // first byte of first row
|
||||
byte *curRowH = buffer + bytesPerRow*(h-1); // first byte of last row
|
||||
while(curRowL < curRowH)
|
||||
{
|
||||
memcpy(rowBuffer, curRowL, bytesPerRow);
|
||||
memcpy(curRowL, curRowH, bytesPerRow);
|
||||
memcpy(curRowH, rowBuffer, bytesPerRow);
|
||||
|
||||
curRowL += bytesPerRow;
|
||||
curRowH -= bytesPerRow;
|
||||
}
|
||||
YQ2_VLAFREE(rowBuffer);
|
||||
}
|
||||
|
||||
ri.Vid_WriteScreenshot(w, h, comps, buffer);
|
||||
|
||||
free(buffer);
|
||||
}
|
828
src/client/refresh/gl4/gl4_model.c
Normal file
828
src/client/refresh/gl4/gl4_model.c
Normal file
|
@ -0,0 +1,828 @@
|
|||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
* Copyright (C) 2016-2017 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.
|
||||
*
|
||||
* =======================================================================
|
||||
*
|
||||
* Model loading and caching for OpenGL4. Includes the .bsp file format
|
||||
*
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
#include "header/local.h"
|
||||
|
||||
enum { MAX_MOD_KNOWN = 512 };
|
||||
|
||||
YQ2_ALIGNAS_TYPE(int) static byte mod_novis[MAX_MAP_LEAFS / 8];
|
||||
gl4model_t mod_known[MAX_MOD_KNOWN];
|
||||
static int mod_numknown;
|
||||
static int mod_max = 0;
|
||||
int registration_sequence;
|
||||
|
||||
//===============================================================================
|
||||
|
||||
static qboolean
|
||||
Mod_HasFreeSpace(void)
|
||||
{
|
||||
int i, used;
|
||||
gl4model_t *mod;
|
||||
|
||||
used = 0;
|
||||
|
||||
for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++)
|
||||
{
|
||||
if (!mod->name[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_numknown + mod_max) < MAX_MOD_KNOWN;
|
||||
}
|
||||
|
||||
const byte*
|
||||
GL4_Mod_ClusterPVS(int cluster, const gl4model_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);
|
||||
}
|
||||
|
||||
void
|
||||
GL4_Mod_Modellist_f(void)
|
||||
{
|
||||
int i, total, used;
|
||||
gl4model_t *mod;
|
||||
qboolean freeup;
|
||||
|
||||
total = 0;
|
||||
used = 0;
|
||||
R_Printf(PRINT_ALL, "Loaded models:\n");
|
||||
|
||||
for (i = 0, mod = mod_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\n", total);
|
||||
// update statistics
|
||||
freeup = Mod_HasFreeSpace();
|
||||
R_Printf(PRINT_ALL, "Used %d of %d models%s.\n", used, mod_max, freeup ? ", has free space" : "");
|
||||
}
|
||||
|
||||
void
|
||||
GL4_Mod_Init(void)
|
||||
{
|
||||
mod_max = 0;
|
||||
memset(mod_novis, 0xff, sizeof(mod_novis));
|
||||
}
|
||||
|
||||
static void
|
||||
Mod_LoadSubmodels(gl4model_t *loadmodel, byte *mod_base, lump_t *l)
|
||||
{
|
||||
dmodel_t *in;
|
||||
gl4model_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; i < count; i++, in++, out++)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
// copy parent as template for first model
|
||||
memcpy(out, loadmodel, sizeof(*out));
|
||||
}
|
||||
else
|
||||
{
|
||||
// copy first as template for model
|
||||
memcpy(out, loadmodel->submodels, 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 = Mod_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Fills in s->texturemins[] and s->extents[]
|
||||
*/
|
||||
static void
|
||||
Mod_CalcSurfaceExtents(gl4model_t *loadmodel, msurface_t *s)
|
||||
{
|
||||
float mins[2], maxs[2], val;
|
||||
int i, j, e;
|
||||
mvertex_t *v;
|
||||
mtexinfo_t *tex;
|
||||
int bmins[2], bmaxs[2];
|
||||
|
||||
mins[0] = mins[1] = 999999;
|
||||
maxs[0] = maxs[1] = -99999;
|
||||
|
||||
tex = s->texinfo;
|
||||
|
||||
for (i = 0; i < s->numedges; i++)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
extern void
|
||||
GL4_SubdivideSurface(msurface_t *fa, gl4model_t* loadmodel);
|
||||
|
||||
static int calcTexinfoAndFacesSize(byte *mod_base, const lump_t *fl, 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()
|
||||
|
||||
// GL4_SubdivideSurface(out, loadmodel); /* cut up polygon for warps */
|
||||
// for each (pot. recursive) call to R_SubdividePolygon():
|
||||
// sizeof(glpoly_t) + ((numverts - 4) + 2) * sizeof(gl4_3D_vtx_t)
|
||||
|
||||
// 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
|
||||
{
|
||||
// GL4_LM_BuildPolygonFromSurface(out);
|
||||
// => poly = Hunk_Alloc(sizeof(glpoly_t) + (numverts - 4) * sizeof(gl4_3D_vtx_t));
|
||||
int polySize = sizeof(glpoly_t) + (numverts - 4) * sizeof(gl4_3D_vtx_t);
|
||||
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 += 5000000; // and 5MB extra just in case
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
Mod_LoadFaces(gl4model_t *loadmodel, byte *mod_base, lump_t *l)
|
||||
{
|
||||
dface_t *in;
|
||||
msurface_t *out;
|
||||
int i, count, surfnum;
|
||||
int planenum, side;
|
||||
int ti;
|
||||
|
||||
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;
|
||||
|
||||
GL4_LM_BeginBuildingLightmaps(loadmodel);
|
||||
|
||||
for (surfnum = 0; surfnum < count; surfnum++, in++, out++)
|
||||
{
|
||||
out->firstedge = LittleLong(in->firstedge);
|
||||
out->numedges = LittleShort(in->numedges);
|
||||
out->flags = 0;
|
||||
out->polys = NULL;
|
||||
|
||||
planenum = LittleShort(in->planenum);
|
||||
side = LittleShort(in->side);
|
||||
|
||||
if (side)
|
||||
{
|
||||
out->flags |= SURF_PLANEBACK;
|
||||
}
|
||||
|
||||
if (planenum < 0 || planenum >= loadmodel->numplanes)
|
||||
{
|
||||
ri.Sys_Error(ERR_DROP, "%s: Incorrect %d planenum.",
|
||||
__func__, planenum);
|
||||
}
|
||||
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;
|
||||
|
||||
Mod_CalcSurfaceExtents(loadmodel, out);
|
||||
|
||||
/* lighting info */
|
||||
for (i = 0; i < MAX_LIGHTMAPS_PER_SURFACE; i++)
|
||||
{
|
||||
out->styles[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;
|
||||
}
|
||||
|
||||
GL4_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)))
|
||||
{
|
||||
GL4_LM_CreateSurfaceLightmap(out);
|
||||
}
|
||||
|
||||
if (!(out->texinfo->flags & SURF_WARP))
|
||||
{
|
||||
GL4_LM_BuildPolygonFromSurface(loadmodel, out);
|
||||
}
|
||||
}
|
||||
|
||||
GL4_LM_EndBuildingLightmaps();
|
||||
}
|
||||
|
||||
static void
|
||||
Mod_LoadLeafs(gl4model_t *loadmodel, byte *mod_base, lump_t *l)
|
||||
{
|
||||
dleaf_t *in;
|
||||
mleaf_t *out;
|
||||
int i, j, count, p;
|
||||
|
||||
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; i < count; i++, in++, out++)
|
||||
{
|
||||
unsigned firstleafface;
|
||||
|
||||
for (j = 0; j < 3; j++)
|
||||
{
|
||||
out->minmaxs[j] = LittleShort(in->mins[j]);
|
||||
out->minmaxs[3 + j] = LittleShort(in->maxs[j]);
|
||||
}
|
||||
|
||||
p = LittleLong(in->contents);
|
||||
out->contents = p;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
Mod_LoadMarksurfaces(gl4model_t *loadmodel, byte *mod_base, lump_t *l)
|
||||
{
|
||||
int i, j, 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 < count; i++)
|
||||
{
|
||||
j = LittleShort(in[i]);
|
||||
|
||||
if ((j < 0) || (j >= loadmodel->numsurfaces))
|
||||
{
|
||||
ri.Sys_Error(ERR_DROP, "%s: bad surface number", __func__);
|
||||
}
|
||||
|
||||
out[i] = loadmodel->surfaces + j;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
Mod_LoadBrushModel(gl4model_t *mod, void *buffer, int modfilelen)
|
||||
{
|
||||
int i;
|
||||
dheader_t *header;
|
||||
byte *mod_base;
|
||||
|
||||
if (mod != mod_known)
|
||||
{
|
||||
ri.Sys_Error(ERR_DROP, "Loaded a brush model after the world");
|
||||
}
|
||||
|
||||
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__, mod->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 += Mod_CalcLumpHunkSize(&header->lumps[LUMP_VERTEXES], sizeof(dvertex_t), sizeof(mvertex_t), 0);
|
||||
hunkSize += Mod_CalcLumpHunkSize(&header->lumps[LUMP_EDGES], sizeof(dedge_t), sizeof(medge_t), 0);
|
||||
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 += Mod_CalcLumpHunkSize(&header->lumps[LUMP_SURFEDGES], sizeof(int), sizeof(int), 0);
|
||||
hunkSize += Mod_CalcLumpHunkSize(&header->lumps[LUMP_LIGHTING], 1, 1, 0);
|
||||
hunkSize += Mod_CalcLumpHunkSize(&header->lumps[LUMP_PLANES], sizeof(dplane_t), sizeof(cplane_t)*2, 0);
|
||||
hunkSize += calcTexinfoAndFacesSize(mod_base, &header->lumps[LUMP_FACES], &header->lumps[LUMP_TEXINFO]);
|
||||
hunkSize += Mod_CalcLumpHunkSize(&header->lumps[LUMP_LEAFFACES], sizeof(short), sizeof(msurface_t *), 0); // yes, out is indeed a pointer!
|
||||
hunkSize += Mod_CalcLumpHunkSize(&header->lumps[LUMP_VISIBILITY], 1, 1, 0);
|
||||
hunkSize += Mod_CalcLumpHunkSize(&header->lumps[LUMP_LEAFS], sizeof(dleaf_t), sizeof(mleaf_t), 0);
|
||||
hunkSize += Mod_CalcLumpHunkSize(&header->lumps[LUMP_NODES], sizeof(dnode_t), sizeof(mnode_t), 0);
|
||||
hunkSize += Mod_CalcLumpHunkSize(&header->lumps[LUMP_MODELS], sizeof(dmodel_t), sizeof(gl4model_t), 0);
|
||||
|
||||
mod->extradata = Hunk_Begin(hunkSize);
|
||||
mod->type = mod_brush;
|
||||
|
||||
/* load into heap */
|
||||
Mod_LoadVertexes(mod->name, &mod->vertexes, &mod->numvertexes, mod_base,
|
||||
&header->lumps[LUMP_VERTEXES], 0);
|
||||
Mod_LoadEdges(mod->name, &mod->edges, &mod->numedges,
|
||||
mod_base, &header->lumps[LUMP_EDGES], 1);
|
||||
Mod_LoadSurfedges(mod->name, &mod->surfedges, &mod->numsurfedges,
|
||||
mod_base, &header->lumps[LUMP_SURFEDGES], 0);
|
||||
Mod_LoadLighting(&mod->lightdata, mod_base, &header->lumps[LUMP_LIGHTING]);
|
||||
Mod_LoadPlanes (mod->name, &mod->planes, &mod->numplanes,
|
||||
mod_base, &header->lumps[LUMP_PLANES], 0);
|
||||
Mod_LoadTexinfo (mod->name, &mod->texinfo, &mod->numtexinfo,
|
||||
mod_base, &header->lumps[LUMP_TEXINFO], (findimage_t)GL4_FindImage,
|
||||
gl4_notexture, 0);
|
||||
Mod_LoadFaces(mod, mod_base, &header->lumps[LUMP_FACES]);
|
||||
Mod_LoadMarksurfaces(mod, mod_base, &header->lumps[LUMP_LEAFFACES]);
|
||||
Mod_LoadVisibility(&mod->vis, mod_base, &header->lumps[LUMP_VISIBILITY]);
|
||||
Mod_LoadLeafs(mod, mod_base, &header->lumps[LUMP_LEAFS]);
|
||||
Mod_LoadNodes(mod->name, mod->planes, mod->numplanes, mod->leafs,
|
||||
mod->numleafs, &mod->nodes, &mod->numnodes, mod_base,
|
||||
&header->lumps[LUMP_NODES]);
|
||||
Mod_LoadSubmodels (mod, mod_base, &header->lumps[LUMP_MODELS]);
|
||||
mod->numframes = 2; /* regular and alternate animation */
|
||||
}
|
||||
|
||||
static void
|
||||
Mod_Free(gl4model_t *mod)
|
||||
{
|
||||
Hunk_Free(mod->extradata);
|
||||
memset(mod, 0, sizeof(*mod));
|
||||
}
|
||||
|
||||
void
|
||||
GL4_Mod_FreeAll(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < mod_numknown; i++)
|
||||
{
|
||||
if (mod_known[i].extradatasize)
|
||||
{
|
||||
Mod_Free(&mod_known[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads in a model for the given name
|
||||
*/
|
||||
static gl4model_t *
|
||||
Mod_ForName (char *name, gl4model_t *parent_model, qboolean crash)
|
||||
{
|
||||
gl4model_t *mod;
|
||||
void *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 = (int)strtol(name + 1, (char **)NULL, 10);
|
||||
|
||||
if (i < 1 || i >= parent_model->numsubmodels)
|
||||
{
|
||||
ri.Sys_Error(ERR_DROP, "%s: bad inline model number",
|
||||
__func__);
|
||||
}
|
||||
|
||||
return &parent_model->submodels[i];
|
||||
}
|
||||
|
||||
/* search the currently loaded models */
|
||||
for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++)
|
||||
{
|
||||
if (!mod->name[0])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(mod->name, name))
|
||||
{
|
||||
return mod;
|
||||
}
|
||||
}
|
||||
|
||||
/* find a free model slot spot */
|
||||
for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++)
|
||||
{
|
||||
if (!mod->name[0])
|
||||
{
|
||||
break; /* free spot */
|
||||
}
|
||||
}
|
||||
|
||||
if (i == mod_numknown)
|
||||
{
|
||||
if (mod_numknown == MAX_MOD_KNOWN)
|
||||
{
|
||||
ri.Sys_Error(ERR_DROP, "mod_numknown == MAX_MOD_KNOWN");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
memset(mod->name, 0, sizeof(mod->name));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* call the apropriate loader */
|
||||
switch (LittleLong(*(unsigned *)buf))
|
||||
{
|
||||
case IDALIASHEADER:
|
||||
{
|
||||
mod->extradata = Mod_LoadMD2(mod->name, buf, modfilelen,
|
||||
mod->mins, mod->maxs,
|
||||
(struct image_s **)mod->skins, (findimage_t)GL4_FindImage,
|
||||
&(mod->type));
|
||||
if (!mod->extradata)
|
||||
{
|
||||
ri.Sys_Error(ERR_DROP, "%s: Failed to load %s",
|
||||
__func__, mod->name);
|
||||
}
|
||||
};
|
||||
break;
|
||||
|
||||
case IDSPRITEHEADER:
|
||||
{
|
||||
mod->extradata = Mod_LoadSP2(mod->name, buf, modfilelen,
|
||||
(struct image_s **)mod->skins, (findimage_t)GL4_FindImage,
|
||||
&(mod->type));
|
||||
if (!mod->extradata)
|
||||
{
|
||||
ri.Sys_Error(ERR_DROP, "%s: Failed to load %s",
|
||||
__func__, mod->name);
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Specifies the model that will be used as the world
|
||||
*/
|
||||
void
|
||||
GL4_BeginRegistration(char *model)
|
||||
{
|
||||
char fullname[MAX_QPATH];
|
||||
cvar_t *flushmap;
|
||||
|
||||
registration_sequence++;
|
||||
gl4_oldviewcluster = -1; /* force markleafs */
|
||||
|
||||
gl4state.currentlightmap = -1;
|
||||
|
||||
Com_sprintf(fullname, sizeof(fullname), "maps/%s.bsp", model);
|
||||
|
||||
/* explicitly free the old map if different
|
||||
this guarantees that mod_known[0] is the
|
||||
world map */
|
||||
flushmap = ri.Cvar_Get("flushmap", "0", 0);
|
||||
|
||||
if (strcmp(mod_known[0].name, fullname) || flushmap->value)
|
||||
{
|
||||
Mod_Free(&mod_known[0]);
|
||||
}
|
||||
|
||||
gl4_worldmodel = Mod_ForName(fullname, NULL, true);
|
||||
|
||||
gl4_viewcluster = -1;
|
||||
}
|
||||
|
||||
struct model_s *
|
||||
GL4_RegisterModel(char *name)
|
||||
{
|
||||
gl4model_t *mod;
|
||||
|
||||
mod = Mod_ForName(name, gl4_worldmodel, false);
|
||||
|
||||
if (mod)
|
||||
{
|
||||
mod->registration_sequence = registration_sequence;
|
||||
|
||||
/* register any images used by the models */
|
||||
if (mod->type == mod_brush)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < mod->numtexinfo; i++)
|
||||
{
|
||||
mod->texinfo[i].image->registration_sequence = registration_sequence;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* numframes is unused for SP2 but lets set it also */
|
||||
mod->numframes = Mod_ReLoadSkins((struct image_s **)mod->skins,
|
||||
(findimage_t)GL4_FindImage, mod->extradata, mod->type);
|
||||
}
|
||||
}
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
void
|
||||
GL4_EndRegistration(void)
|
||||
{
|
||||
int i;
|
||||
gl4model_t *mod;
|
||||
|
||||
if (Mod_HasFreeSpace() && GL4_ImageHasFreeSpace())
|
||||
{
|
||||
// should be enough space for load next maps
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++)
|
||||
{
|
||||
if (!mod->name[0])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mod->registration_sequence != registration_sequence)
|
||||
{
|
||||
/* don't need this model */
|
||||
Mod_Free(mod);
|
||||
}
|
||||
}
|
||||
|
||||
GL4_FreeUnusedImages();
|
||||
}
|
436
src/client/refresh/gl4/gl4_sdl.c
Normal file
436
src/client/refresh/gl4/gl4_sdl.c
Normal file
|
@ -0,0 +1,436 @@
|
|||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
* Copyright (C) 2016-2017 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.
|
||||
*
|
||||
* =======================================================================
|
||||
*
|
||||
* SDL backend for the GL4 renderer. Everything that needs to be on the
|
||||
* renderer side of thing. Also all glad (or whatever OpenGL loader I
|
||||
* end up using) specific things.
|
||||
*
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
#include "header/local.h"
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
static SDL_Window* window = NULL;
|
||||
static SDL_GLContext context = NULL;
|
||||
static qboolean vsyncActive = false;
|
||||
qboolean IsHighDPIaware = false;
|
||||
|
||||
// --------
|
||||
|
||||
enum {
|
||||
// Not all GL.h header know about GL_DEBUG_SEVERITY_NOTIFICATION_*.
|
||||
// DG: yes, it's the same value in GLES3.2
|
||||
QGL_DEBUG_SEVERITY_NOTIFICATION = 0x826B
|
||||
};
|
||||
|
||||
/*
|
||||
* Callback function for debug output.
|
||||
*/
|
||||
static void APIENTRY
|
||||
DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
|
||||
const GLchar *message, const void *userParam)
|
||||
{
|
||||
const char* sourceStr = "Source: Unknown";
|
||||
const char* typeStr = "Type: Unknown";
|
||||
const char* severityStr = "Severity: Unknown";
|
||||
|
||||
switch (severity)
|
||||
{
|
||||
#ifdef YQ2_GL3_GLES
|
||||
#define SVRCASE(X, STR) case GL_DEBUG_SEVERITY_ ## X ## _KHR : severityStr = STR; break;
|
||||
#else // Desktop GL
|
||||
#define SVRCASE(X, STR) case GL_DEBUG_SEVERITY_ ## X ## _ARB : severityStr = STR; break;
|
||||
#endif
|
||||
|
||||
case QGL_DEBUG_SEVERITY_NOTIFICATION: return;
|
||||
SVRCASE(HIGH, "Severity: High")
|
||||
SVRCASE(MEDIUM, "Severity: Medium")
|
||||
SVRCASE(LOW, "Severity: Low")
|
||||
#undef SVRCASE
|
||||
}
|
||||
|
||||
switch (source)
|
||||
{
|
||||
#ifdef YQ2_GL3_GLES
|
||||
#define SRCCASE(X) case GL_DEBUG_SOURCE_ ## X ## _KHR: sourceStr = "Source: " #X; break;
|
||||
#else
|
||||
#define SRCCASE(X) case GL_DEBUG_SOURCE_ ## X ## _ARB: sourceStr = "Source: " #X; break;
|
||||
#endif
|
||||
SRCCASE(API);
|
||||
SRCCASE(WINDOW_SYSTEM);
|
||||
SRCCASE(SHADER_COMPILER);
|
||||
SRCCASE(THIRD_PARTY);
|
||||
SRCCASE(APPLICATION);
|
||||
SRCCASE(OTHER);
|
||||
#undef SRCCASE
|
||||
}
|
||||
|
||||
switch(type)
|
||||
{
|
||||
#ifdef YQ2_GL3_GLES
|
||||
#define TYPECASE(X) case GL_DEBUG_TYPE_ ## X ## _KHR: typeStr = "Type: " #X; break;
|
||||
#else
|
||||
#define TYPECASE(X) case GL_DEBUG_TYPE_ ## X ## _ARB: typeStr = "Type: " #X; break;
|
||||
#endif
|
||||
TYPECASE(ERROR);
|
||||
TYPECASE(DEPRECATED_BEHAVIOR);
|
||||
TYPECASE(UNDEFINED_BEHAVIOR);
|
||||
TYPECASE(PORTABILITY);
|
||||
TYPECASE(PERFORMANCE);
|
||||
TYPECASE(OTHER);
|
||||
#undef TYPECASE
|
||||
}
|
||||
|
||||
// use PRINT_ALL - this is only called with gl4_debugcontext != 0 anyway.
|
||||
R_Printf(PRINT_ALL, "GLDBG %s %s %s: %s\n", sourceStr, typeStr, severityStr, message);
|
||||
}
|
||||
|
||||
// ---------
|
||||
|
||||
/*
|
||||
* Swaps the buffers and shows the next frame.
|
||||
*/
|
||||
void GL4_EndFrame(void)
|
||||
{
|
||||
if(gl4config.useBigVBO)
|
||||
{
|
||||
// I think this is a good point to orphan the VBO and get a fresh one
|
||||
GL4_BindVAO(gl4state.vao3D);
|
||||
GL4_BindVBO(gl4state.vbo3D);
|
||||
glBufferData(GL_ARRAY_BUFFER, gl4state.vbo3Dsize, NULL, GL_STREAM_DRAW);
|
||||
gl4state.vbo3DcurOffset = 0;
|
||||
}
|
||||
|
||||
SDL_GL_SwapWindow(window);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns whether the vsync is enabled.
|
||||
*/
|
||||
qboolean GL4_IsVsyncActive(void)
|
||||
{
|
||||
return vsyncActive;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enables or disabes the vsync.
|
||||
*/
|
||||
void GL4_SetVsync(void)
|
||||
{
|
||||
// Make sure that the user given
|
||||
// value is SDL compatible...
|
||||
int vsync = 0;
|
||||
|
||||
if (r_vsync->value == 1)
|
||||
{
|
||||
vsync = 1;
|
||||
}
|
||||
else if (r_vsync->value == 2)
|
||||
{
|
||||
vsync = -1;
|
||||
}
|
||||
|
||||
if (SDL_GL_SetSwapInterval(vsync) == -1)
|
||||
{
|
||||
if (vsync == -1)
|
||||
{
|
||||
// Not every system supports adaptive
|
||||
// vsync, fallback to normal vsync.
|
||||
R_Printf(PRINT_ALL, "Failed to set adaptive vsync, reverting to normal vsync.\n");
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
}
|
||||
}
|
||||
|
||||
vsyncActive = SDL_GL_GetSwapInterval() != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the flags used at the SDL window
|
||||
* creation by GLimp_InitGraphics(). In case of error -1
|
||||
* is returned.
|
||||
*/
|
||||
int GL4_PrepareForWindow(void)
|
||||
{
|
||||
// Mkay, let's try to load the libGL,
|
||||
const char *libgl;
|
||||
cvar_t *gl4_libgl = ri.Cvar_Get("gl4_libgl", "", CVAR_ARCHIVE);
|
||||
|
||||
if (strlen(gl4_libgl->string) == 0)
|
||||
{
|
||||
libgl = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
libgl = gl4_libgl->string;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (SDL_GL_LoadLibrary(libgl) < 0)
|
||||
{
|
||||
if (libgl == NULL)
|
||||
{
|
||||
ri.Sys_Error(ERR_FATAL, "%s: Couldn't load libGL: %s!",
|
||||
__func__, SDL_GetError());
|
||||
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
R_Printf(PRINT_ALL, "%s: Couldn't load libGL: %s!\n",
|
||||
__func__, SDL_GetError());
|
||||
R_Printf(PRINT_ALL, "Retrying with default...\n");
|
||||
|
||||
ri.Cvar_Set("gl3_libgl", "");
|
||||
libgl = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Set GL context attributs bound to the window.
|
||||
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
|
||||
if (SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8) == 0)
|
||||
{
|
||||
gl4config.stencil = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
gl4config.stencil = false;
|
||||
}
|
||||
|
||||
#ifdef YQ2_GL3_GLES3
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||
#else // Desktop GL
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
#endif
|
||||
|
||||
// Set GL context flags.
|
||||
int contextFlags = 0;
|
||||
|
||||
#ifndef YQ2_GL3_GLES // Desktop GL (at least RPi4 doesn't like this for GLES3)
|
||||
contextFlags |= SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG;
|
||||
#endif
|
||||
|
||||
if (gl4_debugcontext && gl4_debugcontext->value)
|
||||
{
|
||||
contextFlags |= SDL_GL_CONTEXT_DEBUG_FLAG;
|
||||
}
|
||||
|
||||
if (contextFlags != 0)
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, contextFlags);
|
||||
}
|
||||
|
||||
// Let's see if the driver supports MSAA.
|
||||
int msaa_samples = 0;
|
||||
|
||||
if (gl_msaa_samples->value)
|
||||
{
|
||||
msaa_samples = gl_msaa_samples->value;
|
||||
|
||||
if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1) < 0)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "MSAA is unsupported: %s\n", SDL_GetError());
|
||||
|
||||
ri.Cvar_SetValue ("r_msaa_samples", 0);
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
|
||||
}
|
||||
else if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, msaa_samples) < 0)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "MSAA %ix is unsupported: %s\n", msaa_samples, SDL_GetError());
|
||||
|
||||
ri.Cvar_SetValue("r_msaa_samples", 0);
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
|
||||
}
|
||||
|
||||
return SDL_WINDOW_OPENGL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initializes the OpenGL context. Returns true at
|
||||
* success and false at failure.
|
||||
*/
|
||||
int GL4_InitContext(void* win)
|
||||
{
|
||||
// Coders are stupid.
|
||||
if (win == NULL)
|
||||
{
|
||||
ri.Sys_Error(ERR_FATAL, "R_InitContext() must not be called with NULL argument!");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
window = (SDL_Window *)win;
|
||||
|
||||
// Initialize GL context.
|
||||
context = SDL_GL_CreateContext(window);
|
||||
|
||||
if(context == NULL)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "GL4_InitContext(): Creating OpenGL Context failed: %s\n", SDL_GetError());
|
||||
|
||||
window = NULL;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if we've got the requested MSAA.
|
||||
int msaa_samples = 0;
|
||||
|
||||
if (gl_msaa_samples->value)
|
||||
{
|
||||
if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &msaa_samples) == 0)
|
||||
{
|
||||
ri.Cvar_SetValue("r_msaa_samples", msaa_samples);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we've got at least 8 stencil bits
|
||||
int stencil_bits = 0;
|
||||
|
||||
if (gl4config.stencil)
|
||||
{
|
||||
if (SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &stencil_bits) < 0 || stencil_bits < 8)
|
||||
{
|
||||
gl4config.stencil = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Enable vsync if requested.
|
||||
GL4_SetVsync();
|
||||
|
||||
// Load GL pointrs through GLAD and check context.
|
||||
#ifdef YQ2_GL3_GLES
|
||||
if( !gladLoadGLES2Loader(SDL_GL_GetProcAddress))
|
||||
#else // Desktop GL
|
||||
if( !gladLoadGLLoader(SDL_GL_GetProcAddress))
|
||||
#endif
|
||||
{
|
||||
R_Printf(PRINT_ALL, "GL4_InitContext(): ERROR: loading OpenGL function pointers failed!\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
#ifdef YQ2_GL3_GLES3
|
||||
else if (GLVersion.major < 3)
|
||||
#else // Desktop GL
|
||||
else if (GLVersion.major < 4 || (GLVersion.major == 4 && GLVersion.minor < 6))
|
||||
#endif
|
||||
{
|
||||
R_Printf(PRINT_ALL, "GL4_InitContext(): ERROR: glad only got GL version %d.%d!\n", GLVersion.major, GLVersion.minor);
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
R_Printf(PRINT_ALL, "Successfully loaded OpenGL function pointers using glad, got version %d.%d!\n", GLVersion.major, GLVersion.minor);
|
||||
}
|
||||
|
||||
#ifdef YQ2_GL3_GLES
|
||||
gl4config.debug_output = GLAD_GL_KHR_debug != 0;
|
||||
#else // Desktop GL
|
||||
gl4config.debug_output = GLAD_GL_ARB_debug_output != 0;
|
||||
#endif
|
||||
gl4config.anisotropic = GLAD_GL_ARB_texture_filter_anisotropic != 0;
|
||||
|
||||
gl4config.major_version = GLVersion.major;
|
||||
gl4config.minor_version = GLVersion.minor;
|
||||
|
||||
// Debug context setup.
|
||||
if (gl4_debugcontext && gl4_debugcontext->value && gl4config.debug_output)
|
||||
{
|
||||
#ifdef YQ2_GL3_GLES
|
||||
glDebugMessageCallbackKHR(DebugCallback, NULL);
|
||||
|
||||
// Call GL3_DebugCallback() synchronously, i.e. directly when and
|
||||
// where the error happens (so we can get the cause in a backtrace)
|
||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR);
|
||||
#else // Desktop GL
|
||||
glDebugMessageCallbackARB(DebugCallback, NULL);
|
||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Window title - set here so we can display renderer name in it.
|
||||
char title[40] = {0};
|
||||
#ifdef YQ2_GL3_GLES3
|
||||
snprintf(title, sizeof(title), "Yamagi Quake II %s - OpenGL ES 3.0", YQ2VERSION);
|
||||
#else
|
||||
snprintf(title, sizeof(title), "Yamagi Quake II %s - OpenGL 4.6", YQ2VERSION);
|
||||
#endif
|
||||
SDL_SetWindowTitle(window, title);
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 26, 0)
|
||||
// Figure out if we are high dpi aware.
|
||||
int flags = SDL_GetWindowFlags(win);
|
||||
IsHighDPIaware = (flags & SDL_WINDOW_ALLOW_HIGHDPI) ? true : false;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fills the actual size of the drawable into width and height.
|
||||
*/
|
||||
void GL4_GetDrawableSize(int* width, int* height)
|
||||
{
|
||||
SDL_GL_GetDrawableSize(window, width, height);
|
||||
}
|
||||
|
||||
/*
|
||||
* Shuts the GL context down.
|
||||
*/
|
||||
void GL4_ShutdownContext()
|
||||
{
|
||||
if (window)
|
||||
{
|
||||
if(context)
|
||||
{
|
||||
SDL_GL_DeleteContext(context);
|
||||
context = NULL;
|
||||
}
|
||||
}
|
||||
}
|
1365
src/client/refresh/gl4/gl4_shaders.c
Normal file
1365
src/client/refresh/gl4/gl4_shaders.c
Normal file
File diff suppressed because it is too large
Load diff
885
src/client/refresh/gl4/gl4_surf.c
Normal file
885
src/client/refresh/gl4/gl4_surf.c
Normal file
|
@ -0,0 +1,885 @@
|
|||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
* Copyright (C) 2016-2017 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.
|
||||
*
|
||||
* =======================================================================
|
||||
*
|
||||
* Surface generation and drawing
|
||||
*
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h> // ofsetof()
|
||||
|
||||
#include "header/local.h"
|
||||
|
||||
int c_visible_lightmaps;
|
||||
int c_visible_textures;
|
||||
static vec3_t modelorg; /* relative to viewpoint */
|
||||
static msurface_t *gl4_alpha_surfaces;
|
||||
|
||||
gl4lightmapstate_t gl4_lms;
|
||||
|
||||
#define BACKFACE_EPSILON 0.01
|
||||
|
||||
extern gl4image_t gl4textures[MAX_GL4TEXTURES];
|
||||
extern int numgl4textures;
|
||||
|
||||
void GL4_SurfInit(void)
|
||||
{
|
||||
// init the VAO and VBO for the standard vertexdata: 10 floats and 1 uint
|
||||
// (X, Y, Z), (S, T), (LMS, LMT), (normX, normY, normZ) ; lightFlags - last two groups for lightmap/dynlights
|
||||
|
||||
glGenVertexArrays(1, &gl4state.vao3D);
|
||||
GL4_BindVAO(gl4state.vao3D);
|
||||
|
||||
glGenBuffers(1, &gl4state.vbo3D);
|
||||
GL4_BindVBO(gl4state.vbo3D);
|
||||
|
||||
if(gl4config.useBigVBO)
|
||||
{
|
||||
gl4state.vbo3Dsize = 5*1024*1024; // a 5MB buffer seems to work well?
|
||||
gl4state.vbo3DcurOffset = 0;
|
||||
glBufferData(GL_ARRAY_BUFFER, gl4state.vbo3Dsize, NULL, GL_STREAM_DRAW); // allocate/reserve that data
|
||||
}
|
||||
|
||||
glEnableVertexAttribArray(GL4_ATTRIB_POSITION);
|
||||
qglVertexAttribPointer(GL4_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, sizeof(gl4_3D_vtx_t), 0);
|
||||
|
||||
glEnableVertexAttribArray(GL4_ATTRIB_TEXCOORD);
|
||||
qglVertexAttribPointer(GL4_ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(gl4_3D_vtx_t), offsetof(gl4_3D_vtx_t, texCoord));
|
||||
|
||||
glEnableVertexAttribArray(GL4_ATTRIB_LMTEXCOORD);
|
||||
qglVertexAttribPointer(GL4_ATTRIB_LMTEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(gl4_3D_vtx_t), offsetof(gl4_3D_vtx_t, lmTexCoord));
|
||||
|
||||
glEnableVertexAttribArray(GL4_ATTRIB_NORMAL);
|
||||
qglVertexAttribPointer(GL4_ATTRIB_NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(gl4_3D_vtx_t), offsetof(gl4_3D_vtx_t, normal));
|
||||
|
||||
glEnableVertexAttribArray(GL4_ATTRIB_LIGHTFLAGS);
|
||||
qglVertexAttribIPointer(GL4_ATTRIB_LIGHTFLAGS, 1, GL_UNSIGNED_INT, sizeof(gl4_3D_vtx_t), offsetof(gl4_3D_vtx_t, lightFlags));
|
||||
|
||||
|
||||
|
||||
// init VAO and VBO for model vertexdata: 9 floats
|
||||
// (X,Y,Z), (S,T), (R,G,B,A)
|
||||
|
||||
glGenVertexArrays(1, &gl4state.vaoAlias);
|
||||
GL4_BindVAO(gl4state.vaoAlias);
|
||||
|
||||
glGenBuffers(1, &gl4state.vboAlias);
|
||||
GL4_BindVBO(gl4state.vboAlias);
|
||||
|
||||
glEnableVertexAttribArray(GL4_ATTRIB_POSITION);
|
||||
qglVertexAttribPointer(GL4_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), 0);
|
||||
|
||||
glEnableVertexAttribArray(GL4_ATTRIB_TEXCOORD);
|
||||
qglVertexAttribPointer(GL4_ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), 3*sizeof(GLfloat));
|
||||
|
||||
glEnableVertexAttribArray(GL4_ATTRIB_COLOR);
|
||||
qglVertexAttribPointer(GL4_ATTRIB_COLOR, 4, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), 5*sizeof(GLfloat));
|
||||
|
||||
glGenBuffers(1, &gl4state.eboAlias);
|
||||
|
||||
// init VAO and VBO for particle vertexdata: 9 floats
|
||||
// (X,Y,Z), (point_size,distace_to_camera), (R,G,B,A)
|
||||
|
||||
glGenVertexArrays(1, &gl4state.vaoParticle);
|
||||
GL4_BindVAO(gl4state.vaoParticle);
|
||||
|
||||
glGenBuffers(1, &gl4state.vboParticle);
|
||||
GL4_BindVBO(gl4state.vboParticle);
|
||||
|
||||
glEnableVertexAttribArray(GL4_ATTRIB_POSITION);
|
||||
qglVertexAttribPointer(GL4_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), 0);
|
||||
|
||||
// TODO: maybe move point size and camera origin to UBO and calculate distance in vertex shader
|
||||
glEnableVertexAttribArray(GL4_ATTRIB_TEXCOORD); // it's abused for (point_size, distance) here..
|
||||
qglVertexAttribPointer(GL4_ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), 3*sizeof(GLfloat));
|
||||
|
||||
glEnableVertexAttribArray(GL4_ATTRIB_COLOR);
|
||||
qglVertexAttribPointer(GL4_ATTRIB_COLOR, 4, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), 5*sizeof(GLfloat));
|
||||
}
|
||||
|
||||
void GL4_SurfShutdown(void)
|
||||
{
|
||||
glDeleteBuffers(1, &gl4state.vbo3D);
|
||||
gl4state.vbo3D = 0;
|
||||
glDeleteVertexArrays(1, &gl4state.vao3D);
|
||||
gl4state.vao3D = 0;
|
||||
|
||||
glDeleteBuffers(1, &gl4state.eboAlias);
|
||||
gl4state.eboAlias = 0;
|
||||
glDeleteBuffers(1, &gl4state.vboAlias);
|
||||
gl4state.vboAlias = 0;
|
||||
glDeleteVertexArrays(1, &gl4state.vaoAlias);
|
||||
gl4state.vaoAlias = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
SetLightFlags(msurface_t *surf)
|
||||
{
|
||||
unsigned int lightFlags = 0;
|
||||
if (surf->dlightframe == gl4_framecount)
|
||||
{
|
||||
lightFlags = surf->dlightbits;
|
||||
}
|
||||
|
||||
gl4_3D_vtx_t* verts = surf->polys->vertices;
|
||||
|
||||
int numVerts = surf->polys->numverts;
|
||||
for(int i=0; i<numVerts; ++i)
|
||||
{
|
||||
verts[i].lightFlags = lightFlags;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
SetAllLightFlags(msurface_t *surf)
|
||||
{
|
||||
unsigned int lightFlags = 0xffffffff;
|
||||
|
||||
gl4_3D_vtx_t* verts = surf->polys->vertices;
|
||||
|
||||
int numVerts = surf->polys->numverts;
|
||||
for(int i=0; i<numVerts; ++i)
|
||||
{
|
||||
verts[i].lightFlags = lightFlags;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GL4_DrawGLPoly(msurface_t *fa)
|
||||
{
|
||||
glpoly_t *p = fa->polys;
|
||||
|
||||
GL4_BindVAO(gl4state.vao3D);
|
||||
GL4_BindVBO(gl4state.vbo3D);
|
||||
|
||||
GL4_BufferAndDraw3D(p->vertices, p->numverts, GL_TRIANGLE_FAN);
|
||||
}
|
||||
|
||||
void
|
||||
GL4_DrawGLFlowingPoly(msurface_t *fa)
|
||||
{
|
||||
glpoly_t *p;
|
||||
float scroll;
|
||||
|
||||
p = fa->polys;
|
||||
|
||||
scroll = -64.0f * ((gl4_newrefdef.time / 40.0f) - (int)(gl4_newrefdef.time / 40.0f));
|
||||
|
||||
if (scroll == 0.0f)
|
||||
{
|
||||
scroll = -64.0f;
|
||||
}
|
||||
|
||||
if(gl4state.uni3DData.scroll != scroll)
|
||||
{
|
||||
gl4state.uni3DData.scroll = scroll;
|
||||
GL4_UpdateUBO3D();
|
||||
}
|
||||
|
||||
GL4_BindVAO(gl4state.vao3D);
|
||||
GL4_BindVBO(gl4state.vbo3D);
|
||||
|
||||
GL4_BufferAndDraw3D(p->vertices, p->numverts, GL_TRIANGLE_FAN);
|
||||
}
|
||||
|
||||
static void
|
||||
DrawTriangleOutlines(void)
|
||||
{
|
||||
STUB_ONCE("TODO: Implement for gl_showtris support!");
|
||||
#if 0
|
||||
int i, j;
|
||||
glpoly_t *p;
|
||||
|
||||
if (!gl_showtris->value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glColor4f(1, 1, 1, 1);
|
||||
|
||||
for (i = 0; i < MAX_LIGHTMAPS; i++)
|
||||
{
|
||||
msurface_t *surf;
|
||||
|
||||
for (surf = gl4_lms.lightmap_surfaces[i];
|
||||
surf != 0;
|
||||
surf = surf->lightmapchain)
|
||||
{
|
||||
p = surf->polys;
|
||||
|
||||
for ( ; p; p = p->chain)
|
||||
{
|
||||
for (j = 2; j < p->numverts; j++)
|
||||
{
|
||||
GLfloat vtx[12];
|
||||
unsigned int k;
|
||||
|
||||
for (k=0; k<3; k++)
|
||||
{
|
||||
vtx[0+k] = p->vertices [ 0 ][ k ];
|
||||
vtx[3+k] = p->vertices [ j - 1 ][ k ];
|
||||
vtx[6+k] = p->vertices [ j ][ k ];
|
||||
vtx[9+k] = p->vertices [ 0 ][ k ];
|
||||
}
|
||||
|
||||
glEnableClientState( GL_VERTEX_ARRAY );
|
||||
|
||||
glVertexPointer( 3, GL_FLOAT, 0, vtx );
|
||||
glDrawArrays( GL_LINE_STRIP, 0, 4 );
|
||||
|
||||
glDisableClientState( GL_VERTEX_ARRAY );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
#endif // 0
|
||||
}
|
||||
|
||||
static void
|
||||
UpdateLMscales(const hmm_vec4 lmScales[MAX_LIGHTMAPS_PER_SURFACE], gl4ShaderInfo_t* si)
|
||||
{
|
||||
int i;
|
||||
qboolean hasChanged = false;
|
||||
|
||||
for(i=0; i<MAX_LIGHTMAPS_PER_SURFACE; ++i)
|
||||
{
|
||||
if(hasChanged)
|
||||
{
|
||||
si->lmScales[i] = lmScales[i];
|
||||
}
|
||||
else if( si->lmScales[i].R != lmScales[i].R
|
||||
|| si->lmScales[i].G != lmScales[i].G
|
||||
|| si->lmScales[i].B != lmScales[i].B
|
||||
|| si->lmScales[i].A != lmScales[i].A )
|
||||
{
|
||||
si->lmScales[i] = lmScales[i];
|
||||
hasChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(hasChanged)
|
||||
{
|
||||
glUniform4fv(si->uniLmScalesOrTime, MAX_LIGHTMAPS_PER_SURFACE, si->lmScales[0].Elements);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
RenderBrushPoly(entity_t *currententity, msurface_t *fa)
|
||||
{
|
||||
int map;
|
||||
gl4image_t *image;
|
||||
|
||||
c_brush_polys++;
|
||||
|
||||
image = R_TextureAnimation(currententity, fa->texinfo);
|
||||
|
||||
if (fa->flags & SURF_DRAWTURB)
|
||||
{
|
||||
GL4_Bind(image->texnum);
|
||||
|
||||
GL4_EmitWaterPolys(fa);
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
GL4_Bind(image->texnum);
|
||||
}
|
||||
|
||||
hmm_vec4 lmScales[MAX_LIGHTMAPS_PER_SURFACE] = {0};
|
||||
lmScales[0] = HMM_Vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
GL4_BindLightmap(fa->lightmaptexturenum);
|
||||
|
||||
// Any dynamic lights on this surface?
|
||||
for (map = 0; map < MAX_LIGHTMAPS_PER_SURFACE && fa->styles[map] != 255; map++)
|
||||
{
|
||||
lmScales[map].R = gl4_newrefdef.lightstyles[fa->styles[map]].rgb[0];
|
||||
lmScales[map].G = gl4_newrefdef.lightstyles[fa->styles[map]].rgb[1];
|
||||
lmScales[map].B = gl4_newrefdef.lightstyles[fa->styles[map]].rgb[2];
|
||||
lmScales[map].A = 1.0f;
|
||||
}
|
||||
|
||||
if (fa->texinfo->flags & SURF_FLOWING)
|
||||
{
|
||||
GL4_UseProgram(gl4state.si3DlmFlow.shaderProgram);
|
||||
UpdateLMscales(lmScales, &gl4state.si3DlmFlow);
|
||||
GL4_DrawGLFlowingPoly(fa);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL4_UseProgram(gl4state.si3Dlm.shaderProgram);
|
||||
UpdateLMscales(lmScales, &gl4state.si3Dlm);
|
||||
GL4_DrawGLPoly(fa);
|
||||
}
|
||||
|
||||
// Note: lightmap chains are gone, lightmaps are rendered together with normal texture in one pass
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
GL4_DrawAlphaSurfaces(void)
|
||||
{
|
||||
msurface_t *s;
|
||||
|
||||
/* go back to the world matrix */
|
||||
gl4state.uni3DData.transModelMat4 = gl4_identityMat4;
|
||||
GL4_UpdateUBO3D();
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
for (s = gl4_alpha_surfaces; s != NULL; s = s->texturechain)
|
||||
{
|
||||
GL4_Bind(s->texinfo->image->texnum);
|
||||
c_brush_polys++;
|
||||
float alpha = 1.0f;
|
||||
if (s->texinfo->flags & SURF_TRANS33)
|
||||
{
|
||||
alpha = 0.333f;
|
||||
}
|
||||
else if (s->texinfo->flags & SURF_TRANS66)
|
||||
{
|
||||
alpha = 0.666f;
|
||||
}
|
||||
if(alpha != gl4state.uni3DData.alpha)
|
||||
{
|
||||
gl4state.uni3DData.alpha = alpha;
|
||||
GL4_UpdateUBO3D();
|
||||
}
|
||||
|
||||
if (s->flags & SURF_DRAWTURB)
|
||||
{
|
||||
GL4_EmitWaterPolys(s);
|
||||
}
|
||||
else if (s->texinfo->flags & SURF_FLOWING)
|
||||
{
|
||||
GL4_UseProgram(gl4state.si3DtransFlow.shaderProgram);
|
||||
GL4_DrawGLFlowingPoly(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL4_UseProgram(gl4state.si3Dtrans.shaderProgram);
|
||||
GL4_DrawGLPoly(s);
|
||||
}
|
||||
}
|
||||
|
||||
gl4state.uni3DData.alpha = 1.0f;
|
||||
GL4_UpdateUBO3D();
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
gl4_alpha_surfaces = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
DrawTextureChains(entity_t *currententity)
|
||||
{
|
||||
int i;
|
||||
msurface_t *s;
|
||||
gl4image_t *image;
|
||||
|
||||
c_visible_textures = 0;
|
||||
|
||||
for (i = 0, image = gl4textures; i < numgl4textures; i++, image++)
|
||||
{
|
||||
if (!image->registration_sequence)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
s = image->texturechain;
|
||||
|
||||
if (!s)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
c_visible_textures++;
|
||||
|
||||
for ( ; s; s = s->texturechain)
|
||||
{
|
||||
SetLightFlags(s);
|
||||
RenderBrushPoly(currententity, s);
|
||||
}
|
||||
|
||||
image->texturechain = NULL;
|
||||
}
|
||||
|
||||
// TODO: maybe one loop for normal faces and one for SURF_DRAWTURB ???
|
||||
}
|
||||
|
||||
static void
|
||||
RenderLightmappedPoly(entity_t *currententity, msurface_t *surf)
|
||||
{
|
||||
int map;
|
||||
gl4image_t *image = R_TextureAnimation(currententity, surf->texinfo);
|
||||
|
||||
hmm_vec4 lmScales[MAX_LIGHTMAPS_PER_SURFACE] = {0};
|
||||
lmScales[0] = HMM_Vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
assert((surf->texinfo->flags & (SURF_SKY | SURF_TRANS33 | SURF_TRANS66 | SURF_WARP)) == 0
|
||||
&& "RenderLightMappedPoly mustn't be called with transparent, sky or warping surfaces!");
|
||||
|
||||
// Any dynamic lights on this surface?
|
||||
for (map = 0; map < MAX_LIGHTMAPS_PER_SURFACE && surf->styles[map] != 255; map++)
|
||||
{
|
||||
lmScales[map].R = gl4_newrefdef.lightstyles[surf->styles[map]].rgb[0];
|
||||
lmScales[map].G = gl4_newrefdef.lightstyles[surf->styles[map]].rgb[1];
|
||||
lmScales[map].B = gl4_newrefdef.lightstyles[surf->styles[map]].rgb[2];
|
||||
lmScales[map].A = 1.0f;
|
||||
}
|
||||
|
||||
c_brush_polys++;
|
||||
|
||||
GL4_Bind(image->texnum);
|
||||
GL4_BindLightmap(surf->lightmaptexturenum);
|
||||
|
||||
if (surf->texinfo->flags & SURF_FLOWING)
|
||||
{
|
||||
GL4_UseProgram(gl4state.si3DlmFlow.shaderProgram);
|
||||
UpdateLMscales(lmScales, &gl4state.si3DlmFlow);
|
||||
GL4_DrawGLFlowingPoly(surf);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL4_UseProgram(gl4state.si3Dlm.shaderProgram);
|
||||
UpdateLMscales(lmScales, &gl4state.si3Dlm);
|
||||
GL4_DrawGLPoly(surf);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
DrawInlineBModel(entity_t *currententity, gl4model_t *currentmodel)
|
||||
{
|
||||
int i, k;
|
||||
cplane_t *pplane;
|
||||
float dot;
|
||||
msurface_t *psurf;
|
||||
dlight_t *lt;
|
||||
|
||||
/* calculate dynamic lighting for bmodel */
|
||||
lt = gl4_newrefdef.dlights;
|
||||
|
||||
for (k = 0; k < gl4_newrefdef.num_dlights; k++, lt++)
|
||||
{
|
||||
R_MarkLights(lt, 1 << k, currentmodel->nodes + currentmodel->firstnode,
|
||||
r_dlightframecount, GL4_MarkSurfaceLights);
|
||||
}
|
||||
|
||||
psurf = ¤tmodel->surfaces[currentmodel->firstmodelsurface];
|
||||
|
||||
if (currententity->flags & RF_TRANSLUCENT)
|
||||
{
|
||||
glEnable(GL_BLEND);
|
||||
/* TODO: should I care about the 0.25 part? we'll just set alpha to 0.33 or 0.66 depending on surface flag..
|
||||
glColor4f(1, 1, 1, 0.25);
|
||||
R_TexEnv(GL_MODULATE);
|
||||
*/
|
||||
}
|
||||
|
||||
/* draw texture */
|
||||
for (i = 0; i < currentmodel->nummodelsurfaces; i++, psurf++)
|
||||
{
|
||||
/* 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 = gl4_alpha_surfaces;
|
||||
gl4_alpha_surfaces = psurf;
|
||||
}
|
||||
else if(!(psurf->flags & SURF_DRAWTURB))
|
||||
{
|
||||
SetAllLightFlags(psurf);
|
||||
RenderLightmappedPoly(currententity, psurf);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderBrushPoly(currententity, psurf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currententity->flags & RF_TRANSLUCENT)
|
||||
{
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GL4_DrawBrushModel(entity_t *e, gl4model_t *currentmodel)
|
||||
{
|
||||
vec3_t mins, maxs;
|
||||
int i;
|
||||
qboolean rotated;
|
||||
|
||||
if (currentmodel->nummodelsurfaces == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gl4state.currenttexture = -1;
|
||||
|
||||
if (e->angles[0] || e->angles[1] || e->angles[2])
|
||||
{
|
||||
rotated = true;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
mins[i] = e->origin[i] - currentmodel->radius;
|
||||
maxs[i] = e->origin[i] + currentmodel->radius;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rotated = false;
|
||||
VectorAdd(e->origin, currentmodel->mins, mins);
|
||||
VectorAdd(e->origin, currentmodel->maxs, maxs);
|
||||
}
|
||||
|
||||
if (r_cull->value && R_CullBox(mins, maxs, frustum))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (gl_zfix->value)
|
||||
{
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
}
|
||||
|
||||
VectorSubtract(gl4_newrefdef.vieworg, e->origin, modelorg);
|
||||
|
||||
if (rotated)
|
||||
{
|
||||
vec3_t temp;
|
||||
vec3_t forward, right, up;
|
||||
|
||||
VectorCopy(modelorg, temp);
|
||||
AngleVectors(e->angles, forward, right, up);
|
||||
modelorg[0] = DotProduct(temp, forward);
|
||||
modelorg[1] = -DotProduct(temp, right);
|
||||
modelorg[2] = DotProduct(temp, up);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//glPushMatrix();
|
||||
hmm_mat4 oldMat = gl4state.uni3DData.transModelMat4;
|
||||
|
||||
e->angles[0] = -e->angles[0];
|
||||
e->angles[2] = -e->angles[2];
|
||||
GL4_RotateForEntity(e);
|
||||
e->angles[0] = -e->angles[0];
|
||||
e->angles[2] = -e->angles[2];
|
||||
|
||||
DrawInlineBModel(e, currentmodel);
|
||||
|
||||
// glPopMatrix();
|
||||
gl4state.uni3DData.transModelMat4 = oldMat;
|
||||
GL4_UpdateUBO3D();
|
||||
|
||||
if (gl_zfix->value)
|
||||
{
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
RecursiveWorldNode(entity_t *currententity, mnode_t *node)
|
||||
{
|
||||
int c, side, sidebit;
|
||||
cplane_t *plane;
|
||||
msurface_t *surf, **mark;
|
||||
mleaf_t *pleaf;
|
||||
float dot;
|
||||
gl4image_t *image;
|
||||
|
||||
if (node->contents == CONTENTS_SOLID)
|
||||
{
|
||||
return; /* solid */
|
||||
}
|
||||
|
||||
if (node->visframe != gl4_visframecount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (r_cull->value && R_CullBox(node->minmaxs, node->minmaxs + 3, frustum))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* if a leaf node, draw stuff */
|
||||
if (node->contents != CONTENTS_NODE)
|
||||
{
|
||||
pleaf = (mleaf_t *)node;
|
||||
|
||||
/* check for door connected areas */
|
||||
// check for door connected areas
|
||||
if (!R_AreaVisible(gl4_newrefdef.areabits, pleaf))
|
||||
return; // not visible
|
||||
|
||||
mark = pleaf->firstmarksurface;
|
||||
c = pleaf->nummarksurfaces;
|
||||
|
||||
if (c)
|
||||
{
|
||||
do
|
||||
{
|
||||
(*mark)->visframe = gl4_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 */
|
||||
RecursiveWorldNode(currententity, node->children[side]);
|
||||
|
||||
/* draw stuff */
|
||||
for (c = node->numsurfaces,
|
||||
surf = gl4_worldmodel->surfaces + node->firstsurface;
|
||||
c; c--, surf++)
|
||||
{
|
||||
if (surf->visframe != gl4_framecount)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((surf->flags & SURF_PLANEBACK) != sidebit)
|
||||
{
|
||||
continue; /* wrong side */
|
||||
}
|
||||
|
||||
if (surf->texinfo->flags & SURF_SKY)
|
||||
{
|
||||
/* just adds to visible sky bounds */
|
||||
GL4_AddSkySurface(surf);
|
||||
}
|
||||
else if (surf->texinfo->flags & (SURF_TRANS33 | SURF_TRANS66))
|
||||
{
|
||||
/* add to the translucent chain */
|
||||
surf->texturechain = gl4_alpha_surfaces;
|
||||
gl4_alpha_surfaces = surf;
|
||||
gl4_alpha_surfaces->texinfo->image = R_TextureAnimation(currententity, surf->texinfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
// calling RenderLightmappedPoly() here probably isn't optimal, rendering everything
|
||||
// through texturechains should be faster, because far less glBindTexture() is needed
|
||||
// (and it might allow batching the drawcalls of surfaces with the same texture)
|
||||
#if 0
|
||||
if(!(surf->flags & SURF_DRAWTURB))
|
||||
{
|
||||
RenderLightmappedPoly(surf);
|
||||
}
|
||||
else
|
||||
#endif // 0
|
||||
{
|
||||
/* the polygon is visible, so add it to the texture sorted chain */
|
||||
image = R_TextureAnimation(currententity, surf->texinfo);
|
||||
surf->texturechain = image->texturechain;
|
||||
image->texturechain = surf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* recurse down the back side */
|
||||
RecursiveWorldNode(currententity, node->children[!side]);
|
||||
}
|
||||
|
||||
void
|
||||
GL4_DrawWorld(void)
|
||||
{
|
||||
entity_t ent;
|
||||
|
||||
if (!r_drawworld->value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (gl4_newrefdef.rdflags & RDF_NOWORLDMODEL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
VectorCopy(gl4_newrefdef.vieworg, modelorg);
|
||||
|
||||
/* auto cycle the world frame for texture animation */
|
||||
memset(&ent, 0, sizeof(ent));
|
||||
ent.frame = (int)(gl4_newrefdef.time * 2);
|
||||
|
||||
gl4state.currenttexture = -1;
|
||||
|
||||
GL4_ClearSkyBox();
|
||||
RecursiveWorldNode(&ent, gl4_worldmodel->nodes);
|
||||
DrawTextureChains(&ent);
|
||||
GL4_DrawSkyBox();
|
||||
DrawTriangleOutlines();
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark the leaves and nodes that are
|
||||
* in the PVS for the current cluster
|
||||
*/
|
||||
void
|
||||
GL4_MarkLeaves(void)
|
||||
{
|
||||
const byte *vis;
|
||||
YQ2_ALIGNAS_TYPE(int) byte fatvis[MAX_MAP_LEAFS / 8];
|
||||
mnode_t *node;
|
||||
int i, c;
|
||||
mleaf_t *leaf;
|
||||
int cluster;
|
||||
|
||||
if ((gl4_oldviewcluster == gl4_viewcluster) &&
|
||||
(gl4_oldviewcluster2 == gl4_viewcluster2) &&
|
||||
!r_novis->value &&
|
||||
(gl4_viewcluster != -1))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* development aid to let you run around
|
||||
and see exactly where the pvs ends */
|
||||
if (r_lockpvs->value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gl4_visframecount++;
|
||||
gl4_oldviewcluster = gl4_viewcluster;
|
||||
gl4_oldviewcluster2 = gl4_viewcluster2;
|
||||
|
||||
if (r_novis->value || (gl4_viewcluster == -1) || !gl4_worldmodel->vis)
|
||||
{
|
||||
/* mark everything */
|
||||
for (i = 0; i < gl4_worldmodel->numleafs; i++)
|
||||
{
|
||||
gl4_worldmodel->leafs[i].visframe = gl4_visframecount;
|
||||
}
|
||||
|
||||
for (i = 0; i < gl4_worldmodel->numnodes; i++)
|
||||
{
|
||||
gl4_worldmodel->nodes[i].visframe = gl4_visframecount;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
vis = GL4_Mod_ClusterPVS(gl4_viewcluster, gl4_worldmodel);
|
||||
|
||||
/* may have to combine two clusters because of solid water boundaries */
|
||||
if (gl4_viewcluster2 != gl4_viewcluster)
|
||||
{
|
||||
memcpy(fatvis, vis, (gl4_worldmodel->numleafs + 7) / 8);
|
||||
vis = GL4_Mod_ClusterPVS(gl4_viewcluster2, gl4_worldmodel);
|
||||
c = (gl4_worldmodel->numleafs + 31) / 32;
|
||||
|
||||
for (i = 0; i < c; i++)
|
||||
{
|
||||
((int *)fatvis)[i] |= ((int *)vis)[i];
|
||||
}
|
||||
|
||||
vis = fatvis;
|
||||
}
|
||||
|
||||
for (i = 0, leaf = gl4_worldmodel->leafs;
|
||||
i < gl4_worldmodel->numleafs;
|
||||
i++, leaf++)
|
||||
{
|
||||
cluster = leaf->cluster;
|
||||
|
||||
if (cluster == -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vis[cluster >> 3] & (1 << (cluster & 7)))
|
||||
{
|
||||
node = (mnode_t *)leaf;
|
||||
|
||||
do
|
||||
{
|
||||
if (node->visframe == gl4_visframecount)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
node->visframe = gl4_visframecount;
|
||||
node = node->parent;
|
||||
}
|
||||
while (node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
751
src/client/refresh/gl4/gl4_warp.c
Normal file
751
src/client/refresh/gl4/gl4_warp.c
Normal file
|
@ -0,0 +1,751 @@
|
|||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
* Copyright (C) 2016-2017 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.
|
||||
*
|
||||
* =======================================================================
|
||||
*
|
||||
* Warps. Used on water surfaces und for skybox rotation.
|
||||
*
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
#include "header/local.h"
|
||||
|
||||
static void
|
||||
R_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 < numverts; i++)
|
||||
{
|
||||
for (j = 0; j < 3; j++, v++)
|
||||
{
|
||||
if (*v < mins[j])
|
||||
{
|
||||
mins[j] = *v;
|
||||
}
|
||||
|
||||
if (*v > maxs[j])
|
||||
{
|
||||
maxs[j] = *v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const float SUBDIVIDE_SIZE = 64.0f;
|
||||
|
||||
static void
|
||||
R_SubdividePolygon(int numverts, float *verts, msurface_t *warpface)
|
||||
{
|
||||
int i, j, k;
|
||||
vec3_t mins, maxs;
|
||||
float m;
|
||||
float *v;
|
||||
vec3_t front[64], back[64];
|
||||
int f, b;
|
||||
float dist[64];
|
||||
float frac;
|
||||
glpoly_t *poly;
|
||||
float s, t;
|
||||
vec3_t total;
|
||||
float total_s, total_t;
|
||||
vec3_t normal;
|
||||
|
||||
VectorCopy(warpface->plane->normal, normal);
|
||||
|
||||
if (numverts > 60)
|
||||
{
|
||||
ri.Sys_Error(ERR_DROP, "numverts = %i", numverts);
|
||||
}
|
||||
|
||||
R_BoundPoly(numverts, verts, mins, maxs);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
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 < numverts; j++, v += 3)
|
||||
{
|
||||
dist[j] = *v - m;
|
||||
}
|
||||
|
||||
/* wrap cases */
|
||||
dist[j] = dist[0];
|
||||
v -= i;
|
||||
VectorCopy(verts, v);
|
||||
|
||||
f = b = 0;
|
||||
v = verts;
|
||||
|
||||
for (j = 0; j < numverts; j++, v += 3)
|
||||
{
|
||||
if (dist[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++;
|
||||
}
|
||||
}
|
||||
|
||||
R_SubdividePolygon(f, front[0], warpface);
|
||||
R_SubdividePolygon(b, back[0], warpface);
|
||||
return;
|
||||
}
|
||||
|
||||
/* add a point in the center to help keep warp valid */
|
||||
poly = Hunk_Alloc(sizeof(glpoly_t) + ((numverts - 4) + 2) * sizeof(gl4_3D_vtx_t));
|
||||
poly->next = warpface->polys;
|
||||
warpface->polys = poly;
|
||||
poly->numverts = numverts + 2;
|
||||
VectorClear(total);
|
||||
total_s = 0;
|
||||
total_t = 0;
|
||||
|
||||
for (i = 0; i < numverts; i++, verts += 3)
|
||||
{
|
||||
VectorCopy(verts, poly->vertices[i + 1].pos);
|
||||
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->vertices[i + 1].texCoord[0] = s;
|
||||
poly->vertices[i + 1].texCoord[1] = t;
|
||||
VectorCopy(normal, poly->vertices[i + 1].normal);
|
||||
poly->vertices[i + 1].lightFlags = 0;
|
||||
}
|
||||
|
||||
VectorScale(total, (1.0 / numverts), poly->vertices[0].pos);
|
||||
poly->vertices[0].texCoord[0] = total_s / numverts;
|
||||
poly->vertices[0].texCoord[1] = total_t / numverts;
|
||||
VectorCopy(normal, poly->vertices[0].normal);
|
||||
|
||||
/* copy first vertex to last */
|
||||
//memcpy(poly->vertices[i + 1], poly->vertices[1], sizeof(poly->vertices[0]));
|
||||
poly->vertices[i + 1] = poly->vertices[1];
|
||||
}
|
||||
|
||||
/*
|
||||
* Breaks a polygon up along axial 64 unit
|
||||
* boundaries so that turbulent and sky warps
|
||||
* can be done reasonably.
|
||||
*/
|
||||
void
|
||||
GL4_SubdivideSurface(msurface_t *fa, gl4model_t* loadmodel)
|
||||
{
|
||||
vec3_t verts[64];
|
||||
int numverts;
|
||||
int i;
|
||||
int lindex;
|
||||
float *vec;
|
||||
|
||||
/* convert edges back to a normal polygon */
|
||||
numverts = 0;
|
||||
|
||||
for (i = 0; i < fa->numedges; i++)
|
||||
{
|
||||
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++;
|
||||
}
|
||||
|
||||
R_SubdividePolygon(numverts, verts[0], fa);
|
||||
}
|
||||
|
||||
/*
|
||||
* Does a water warp on the pre-fragmented glpoly_t chain
|
||||
*/
|
||||
void
|
||||
GL4_EmitWaterPolys(msurface_t *fa)
|
||||
{
|
||||
glpoly_t *bp;
|
||||
float scroll = 0.0f;
|
||||
|
||||
if (fa->texinfo->flags & SURF_FLOWING)
|
||||
{
|
||||
scroll = -64.0f * ((gl4_newrefdef.time * 0.5) - (int)(gl4_newrefdef.time * 0.5));
|
||||
if (scroll == 0.0f) // this is done in GL4_DrawGLFlowingPoly() TODO: keep?
|
||||
{
|
||||
scroll = -64.0f;
|
||||
}
|
||||
}
|
||||
|
||||
qboolean updateUni3D = false;
|
||||
if(gl4state.uni3DData.scroll != scroll)
|
||||
{
|
||||
gl4state.uni3DData.scroll = scroll;
|
||||
updateUni3D = true;
|
||||
}
|
||||
// these surfaces (mostly water and lava, I think?) don't have a lightmap.
|
||||
// rendering water at full brightness looks bad (esp. for water in dark environments)
|
||||
// so default use a factor of 0.5 (ontop of intensity)
|
||||
// but lava should be bright and glowing, so use full brightness there
|
||||
float lightScale = fa->texinfo->image->is_lava ? 1.0f : 0.5f;
|
||||
if(lightScale != gl4state.uni3DData.lightScaleForTurb)
|
||||
{
|
||||
gl4state.uni3DData.lightScaleForTurb = lightScale;
|
||||
updateUni3D = true;
|
||||
}
|
||||
|
||||
if(updateUni3D)
|
||||
{
|
||||
GL4_UpdateUBO3D();
|
||||
}
|
||||
|
||||
GL4_UseProgram(gl4state.si3Dturb.shaderProgram);
|
||||
|
||||
GL4_BindVAO(gl4state.vao3D);
|
||||
GL4_BindVBO(gl4state.vbo3D);
|
||||
|
||||
for (bp = fa->polys; bp != NULL; bp = bp->next)
|
||||
{
|
||||
GL4_BufferAndDraw3D(bp->vertices, bp->numverts, GL_TRIANGLE_FAN);
|
||||
}
|
||||
}
|
||||
|
||||
// ########### below: Sky-specific stuff ##########
|
||||
|
||||
#define ON_EPSILON 0.1 /* point on plane side epsilon */
|
||||
enum { MAX_CLIP_VERTS = 64 };
|
||||
|
||||
|
||||
static const int skytexorder[6] = {0, 2, 1, 3, 4, 5};
|
||||
|
||||
static float skymins[2][6], skymaxs[2][6];
|
||||
static float sky_min, sky_max;
|
||||
|
||||
static float skyrotate;
|
||||
static vec3_t skyaxis;
|
||||
static gl4image_t* sky_images[6];
|
||||
|
||||
/* 3dstudio environment map names */
|
||||
static const char* suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
|
||||
|
||||
vec3_t skyclip[6] = {
|
||||
{1, 1, 0},
|
||||
{1, -1, 0},
|
||||
{0, -1, 1},
|
||||
{0, 1, 1},
|
||||
{1, 0, 1},
|
||||
{-1, 0, 1}
|
||||
};
|
||||
int c_sky;
|
||||
|
||||
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 */
|
||||
};
|
||||
|
||||
int vec_to_st[6][3] = {
|
||||
{-2, 3, 1},
|
||||
{2, 3, -1},
|
||||
|
||||
{1, 3, 2},
|
||||
{-1, 3, -2},
|
||||
|
||||
{-2, -1, 3},
|
||||
{-2, 1, -3}
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
GL4_SetSky(char *name, float rotate, vec3_t axis)
|
||||
{
|
||||
char skyname[MAX_QPATH];
|
||||
int i;
|
||||
|
||||
Q_strlcpy(skyname, name, sizeof(skyname));
|
||||
skyrotate = rotate;
|
||||
VectorCopy(axis, skyaxis);
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
gl4image_t *image;
|
||||
|
||||
image = (gl4image_t *)GetSkyImage(skyname, suf[i],
|
||||
r_palettedtexture->value, (findimage_t)GL4_FindImage);
|
||||
|
||||
if (!image)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "%s: can't load %s:%s sky\n",
|
||||
__func__, skyname, suf[i]);
|
||||
image = gl4_notexture;
|
||||
}
|
||||
|
||||
sky_images[i] = image;
|
||||
}
|
||||
|
||||
sky_min = 1.0 / 512;
|
||||
sky_max = 511.0 / 512;
|
||||
}
|
||||
|
||||
static void
|
||||
DrawSkyPolygon(int nump, vec3_t vecs)
|
||||
{
|
||||
int i, j;
|
||||
vec3_t v, av;
|
||||
float s, t, dv;
|
||||
int axis;
|
||||
float *vp;
|
||||
|
||||
c_sky++;
|
||||
|
||||
/* decide which face it maps to */
|
||||
VectorCopy(vec3_origin, v);
|
||||
|
||||
for (i = 0, vp = vecs; i < nump; i++, vp += 3)
|
||||
{
|
||||
VectorAdd(vp, v, v);
|
||||
}
|
||||
|
||||
av[0] = fabs(v[0]);
|
||||
av[1] = fabs(v[1]);
|
||||
av[2] = fabs(v[2]);
|
||||
|
||||
if ((av[0] > 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 < nump; i++, vecs += 3)
|
||||
{
|
||||
j = vec_to_st[axis][2];
|
||||
|
||||
if (j > 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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, "R_ClipSkyPolygon: MAX_CLIP_VERTS");
|
||||
}
|
||||
|
||||
if (stage == 6)
|
||||
{
|
||||
/* fully clipped, so draw it */
|
||||
DrawSkyPolygon(nump, vecs);
|
||||
return;
|
||||
}
|
||||
|
||||
front = back = false;
|
||||
norm = skyclip[stage];
|
||||
|
||||
for (i = 0, v = vecs; i < nump; i++, v += 3)
|
||||
{
|
||||
d = DotProduct(v, norm);
|
||||
|
||||
if (d > 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; i < nump; i++, v += 3)
|
||||
{
|
||||
switch (sides[i])
|
||||
{
|
||||
case SIDE_FRONT:
|
||||
VectorCopy(v, newv[0][newc[0]]);
|
||||
newc[0]++;
|
||||
break;
|
||||
case SIDE_BACK:
|
||||
VectorCopy(v, newv[1][newc[1]]);
|
||||
newc[1]++;
|
||||
break;
|
||||
case SIDE_ON:
|
||||
VectorCopy(v, newv[0][newc[0]]);
|
||||
newc[0]++;
|
||||
VectorCopy(v, newv[1][newc[1]]);
|
||||
newc[1]++;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((sides[i] == SIDE_ON) ||
|
||||
(sides[i + 1] == SIDE_ON) ||
|
||||
(sides[i + 1] == sides[i]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
d = dists[i] / (dists[i] - dists[i + 1]);
|
||||
|
||||
for (j = 0; j < 3; j++)
|
||||
{
|
||||
e = v[j] + d * (v[j + 3] - v[j]);
|
||||
newv[0][newc[0]][j] = e;
|
||||
newv[1][newc[1]][j] = e;
|
||||
}
|
||||
|
||||
newc[0]++;
|
||||
newc[1]++;
|
||||
}
|
||||
|
||||
/* continue */
|
||||
ClipSkyPolygon(newc[0], newv[0][0], stage + 1);
|
||||
ClipSkyPolygon(newc[1], newv[1][0], stage + 1);
|
||||
}
|
||||
|
||||
void
|
||||
GL4_AddSkySurface(msurface_t *fa)
|
||||
{
|
||||
int i;
|
||||
vec3_t verts[MAX_CLIP_VERTS];
|
||||
glpoly_t *p;
|
||||
|
||||
/* calculate vertex values for sky box */
|
||||
for (p = fa->polys; p; p = p->next)
|
||||
{
|
||||
for (i = 0; i < p->numverts; i++)
|
||||
{
|
||||
VectorSubtract(p->vertices[i].pos, gl4_origin, verts[i]);
|
||||
}
|
||||
|
||||
ClipSkyPolygon(p->numverts, verts[0], 0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GL4_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, gl4_3D_vtx_t* vert)
|
||||
{
|
||||
vec3_t v, b;
|
||||
int j, k;
|
||||
|
||||
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++)
|
||||
{
|
||||
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;
|
||||
|
||||
VectorCopy(v, vert->pos);
|
||||
|
||||
vert->texCoord[0] = s;
|
||||
vert->texCoord[1] = t;
|
||||
|
||||
vert->lmTexCoord[0] = vert->lmTexCoord[1] = 0.0f;
|
||||
}
|
||||
|
||||
void
|
||||
GL4_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 */
|
||||
}
|
||||
}
|
||||
|
||||
// glPushMatrix();
|
||||
hmm_mat4 origModelMat = gl4state.uni3DData.transModelMat4;
|
||||
|
||||
// glTranslatef(gl4_origin[0], gl4_origin[1], gl4_origin[2]);
|
||||
hmm_vec3 transl = HMM_Vec3(gl4_origin[0], gl4_origin[1], gl4_origin[2]);
|
||||
hmm_mat4 modMVmat = HMM_MultiplyMat4(origModelMat, HMM_Translate(transl));
|
||||
if(skyrotate != 0.0f)
|
||||
{
|
||||
// glRotatef(gl4_newrefdef.time * skyrotate, skyaxis[0], skyaxis[1], skyaxis[2]);
|
||||
hmm_vec3 rotAxis = HMM_Vec3(skyaxis[0], skyaxis[1], skyaxis[2]);
|
||||
modMVmat = HMM_MultiplyMat4(modMVmat, HMM_Rotate(gl4_newrefdef.time * skyrotate, rotAxis));
|
||||
}
|
||||
gl4state.uni3DData.transModelMat4 = modMVmat;
|
||||
GL4_UpdateUBO3D();
|
||||
|
||||
GL4_UseProgram(gl4state.si3Dsky.shaderProgram);
|
||||
GL4_BindVAO(gl4state.vao3D);
|
||||
GL4_BindVBO(gl4state.vbo3D);
|
||||
|
||||
// TODO: this could all be done in one drawcall.. but.. whatever, it's <= 6 drawcalls/frame
|
||||
|
||||
gl4_3D_vtx_t skyVertices[4];
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
if (skyrotate != 0.0f)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
GL4_Bind(sky_images[skytexorder[i]]->texnum);
|
||||
|
||||
MakeSkyVec( skymins [ 0 ] [ i ], skymins [ 1 ] [ i ], i, &skyVertices[0] );
|
||||
MakeSkyVec( skymins [ 0 ] [ i ], skymaxs [ 1 ] [ i ], i, &skyVertices[1] );
|
||||
MakeSkyVec( skymaxs [ 0 ] [ i ], skymaxs [ 1 ] [ i ], i, &skyVertices[2] );
|
||||
MakeSkyVec( skymaxs [ 0 ] [ i ], skymins [ 1 ] [ i ], i, &skyVertices[3] );
|
||||
|
||||
GL4_BufferAndDraw3D(skyVertices, 4, GL_TRIANGLE_FAN);
|
||||
}
|
||||
|
||||
// glPopMatrix();
|
||||
gl4state.uni3DData.transModelMat4 = origModelMat;
|
||||
GL4_UpdateUBO3D();
|
||||
}
|
311
src/client/refresh/gl4/glad/include/KHR/khrplatform.h
Normal file
311
src/client/refresh/gl4/glad/include/KHR/khrplatform.h
Normal file
|
@ -0,0 +1,311 @@
|
|||
#ifndef __khrplatform_h_
|
||||
#define __khrplatform_h_
|
||||
|
||||
/*
|
||||
** Copyright (c) 2008-2018 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
** "Materials"), to deal in the Materials without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
** permit persons to whom the Materials are furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included
|
||||
** in all copies or substantial portions of the Materials.
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
/* Khronos platform-specific types and definitions.
|
||||
*
|
||||
* The master copy of khrplatform.h is maintained in the Khronos EGL
|
||||
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
|
||||
* The last semantic modification to khrplatform.h was at commit ID:
|
||||
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
|
||||
*
|
||||
* Adopters may modify this file to suit their platform. Adopters are
|
||||
* encouraged to submit platform specific modifications to the Khronos
|
||||
* group so that they can be included in future versions of this file.
|
||||
* Please submit changes by filing pull requests or issues on
|
||||
* the EGL Registry repository linked above.
|
||||
*
|
||||
*
|
||||
* See the Implementer's Guidelines for information about where this file
|
||||
* should be located on your system and for more details of its use:
|
||||
* http://www.khronos.org/registry/implementers_guide.pdf
|
||||
*
|
||||
* This file should be included as
|
||||
* #include <KHR/khrplatform.h>
|
||||
* by Khronos client API header files that use its types and defines.
|
||||
*
|
||||
* The types in khrplatform.h should only be used to define API-specific types.
|
||||
*
|
||||
* Types defined in khrplatform.h:
|
||||
* khronos_int8_t signed 8 bit
|
||||
* khronos_uint8_t unsigned 8 bit
|
||||
* khronos_int16_t signed 16 bit
|
||||
* khronos_uint16_t unsigned 16 bit
|
||||
* khronos_int32_t signed 32 bit
|
||||
* khronos_uint32_t unsigned 32 bit
|
||||
* khronos_int64_t signed 64 bit
|
||||
* khronos_uint64_t unsigned 64 bit
|
||||
* khronos_intptr_t signed same number of bits as a pointer
|
||||
* khronos_uintptr_t unsigned same number of bits as a pointer
|
||||
* khronos_ssize_t signed size
|
||||
* khronos_usize_t unsigned size
|
||||
* khronos_float_t signed 32 bit floating point
|
||||
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
|
||||
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
|
||||
* nanoseconds
|
||||
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
|
||||
* khronos_boolean_enum_t enumerated boolean type. This should
|
||||
* only be used as a base type when a client API's boolean type is
|
||||
* an enum. Client APIs which use an integer or other type for
|
||||
* booleans cannot use this as the base type for their boolean.
|
||||
*
|
||||
* Tokens defined in khrplatform.h:
|
||||
*
|
||||
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
|
||||
*
|
||||
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
|
||||
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
|
||||
*
|
||||
* Calling convention macros defined in this file:
|
||||
* KHRONOS_APICALL
|
||||
* KHRONOS_APIENTRY
|
||||
* KHRONOS_APIATTRIBUTES
|
||||
*
|
||||
* These may be used in function prototypes as:
|
||||
*
|
||||
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
|
||||
* int arg1,
|
||||
* int arg2) KHRONOS_APIATTRIBUTES;
|
||||
*/
|
||||
|
||||
#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
|
||||
# define KHRONOS_STATIC 1
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APICALL
|
||||
*-------------------------------------------------------------------------
|
||||
* This precedes the return type of the function in the function prototype.
|
||||
*/
|
||||
#if defined(KHRONOS_STATIC)
|
||||
/* If the preprocessor constant KHRONOS_STATIC is defined, make the
|
||||
* header compatible with static linking. */
|
||||
# define KHRONOS_APICALL
|
||||
#elif defined(_WIN32)
|
||||
# define KHRONOS_APICALL __declspec(dllimport)
|
||||
#elif defined (__SYMBIAN32__)
|
||||
# define KHRONOS_APICALL IMPORT_C
|
||||
#elif defined(__ANDROID__)
|
||||
# define KHRONOS_APICALL __attribute__((visibility("default")))
|
||||
#else
|
||||
# define KHRONOS_APICALL
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APIENTRY
|
||||
*-------------------------------------------------------------------------
|
||||
* This follows the return type of the function and precedes the function
|
||||
* name in the function prototype.
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
|
||||
/* Win32 but not WinCE */
|
||||
# define KHRONOS_APIENTRY __stdcall
|
||||
#else
|
||||
# define KHRONOS_APIENTRY
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APIATTRIBUTES
|
||||
*-------------------------------------------------------------------------
|
||||
* This follows the closing parenthesis of the function prototype arguments.
|
||||
*/
|
||||
#if defined (__ARMCC_2__)
|
||||
#define KHRONOS_APIATTRIBUTES __softfp
|
||||
#else
|
||||
#define KHRONOS_APIATTRIBUTES
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* basic type definitions
|
||||
*-----------------------------------------------------------------------*/
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
|
||||
|
||||
|
||||
/*
|
||||
* Using <stdint.h>
|
||||
*/
|
||||
#include <stdint.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
/*
|
||||
* To support platform where unsigned long cannot be used interchangeably with
|
||||
* inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
|
||||
* Ideally, we could just use (u)intptr_t everywhere, but this could result in
|
||||
* ABI breakage if khronos_uintptr_t is changed from unsigned long to
|
||||
* unsigned long long or similar (this results in different C++ name mangling).
|
||||
* To avoid changes for existing platforms, we restrict usage of intptr_t to
|
||||
* platforms where the size of a pointer is larger than the size of long.
|
||||
*/
|
||||
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
|
||||
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
|
||||
#define KHRONOS_USE_INTPTR_T
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#elif defined(__VMS ) || defined(__sgi)
|
||||
|
||||
/*
|
||||
* Using <inttypes.h>
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
|
||||
|
||||
/*
|
||||
* Win32
|
||||
*/
|
||||
typedef __int32 khronos_int32_t;
|
||||
typedef unsigned __int32 khronos_uint32_t;
|
||||
typedef __int64 khronos_int64_t;
|
||||
typedef unsigned __int64 khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(__sun__) || defined(__digital__)
|
||||
|
||||
/*
|
||||
* Sun or Digital
|
||||
*/
|
||||
typedef int khronos_int32_t;
|
||||
typedef unsigned int khronos_uint32_t;
|
||||
#if defined(__arch64__) || defined(_LP64)
|
||||
typedef long int khronos_int64_t;
|
||||
typedef unsigned long int khronos_uint64_t;
|
||||
#else
|
||||
typedef long long int khronos_int64_t;
|
||||
typedef unsigned long long int khronos_uint64_t;
|
||||
#endif /* __arch64__ */
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif 0
|
||||
|
||||
/*
|
||||
* Hypothetical platform with no float or int64 support
|
||||
*/
|
||||
typedef int khronos_int32_t;
|
||||
typedef unsigned int khronos_uint32_t;
|
||||
#define KHRONOS_SUPPORT_INT64 0
|
||||
#define KHRONOS_SUPPORT_FLOAT 0
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* Generic fallback
|
||||
*/
|
||||
#include <stdint.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Types that are (so far) the same on all platforms
|
||||
*/
|
||||
typedef signed char khronos_int8_t;
|
||||
typedef unsigned char khronos_uint8_t;
|
||||
typedef signed short int khronos_int16_t;
|
||||
typedef unsigned short int khronos_uint16_t;
|
||||
|
||||
/*
|
||||
* Types that differ between LLP64 and LP64 architectures - in LLP64,
|
||||
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
|
||||
* to be the only LLP64 architecture in current use.
|
||||
*/
|
||||
#ifdef KHRONOS_USE_INTPTR_T
|
||||
typedef intptr_t khronos_intptr_t;
|
||||
typedef uintptr_t khronos_uintptr_t;
|
||||
#elif defined(_WIN64)
|
||||
typedef signed long long int khronos_intptr_t;
|
||||
typedef unsigned long long int khronos_uintptr_t;
|
||||
#else
|
||||
typedef signed long int khronos_intptr_t;
|
||||
typedef unsigned long int khronos_uintptr_t;
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64)
|
||||
typedef signed long long int khronos_ssize_t;
|
||||
typedef unsigned long long int khronos_usize_t;
|
||||
#else
|
||||
typedef signed long int khronos_ssize_t;
|
||||
typedef unsigned long int khronos_usize_t;
|
||||
#endif
|
||||
|
||||
#if KHRONOS_SUPPORT_FLOAT
|
||||
/*
|
||||
* Float type
|
||||
*/
|
||||
typedef float khronos_float_t;
|
||||
#endif
|
||||
|
||||
#if KHRONOS_SUPPORT_INT64
|
||||
/* Time types
|
||||
*
|
||||
* These types can be used to represent a time interval in nanoseconds or
|
||||
* an absolute Unadjusted System Time. Unadjusted System Time is the number
|
||||
* of nanoseconds since some arbitrary system event (e.g. since the last
|
||||
* time the system booted). The Unadjusted System Time is an unsigned
|
||||
* 64 bit value that wraps back to 0 every 584 years. Time intervals
|
||||
* may be either signed or unsigned.
|
||||
*/
|
||||
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
|
||||
typedef khronos_int64_t khronos_stime_nanoseconds_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dummy value used to pad enum types to 32 bits.
|
||||
*/
|
||||
#ifndef KHRONOS_MAX_ENUM
|
||||
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enumerated boolean type
|
||||
*
|
||||
* Values other than zero should be considered to be true. Therefore
|
||||
* comparisons should not be made against KHRONOS_TRUE.
|
||||
*/
|
||||
typedef enum {
|
||||
KHRONOS_FALSE = 0,
|
||||
KHRONOS_TRUE = 1,
|
||||
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
|
||||
} khronos_boolean_enum_t;
|
||||
|
||||
#endif /* __khrplatform_h_ */
|
3734
src/client/refresh/gl4/glad/include/glad/glad.h
Normal file
3734
src/client/refresh/gl4/glad/include/glad/glad.h
Normal file
File diff suppressed because it is too large
Load diff
1717
src/client/refresh/gl4/glad/src/glad.c
Normal file
1717
src/client/refresh/gl4/glad/src/glad.c
Normal file
File diff suppressed because it is too large
Load diff
960
src/client/refresh/gl4/header/DG_dynarr.h
Normal file
960
src/client/refresh/gl4/header/DG_dynarr.h
Normal file
|
@ -0,0 +1,960 @@
|
|||
/*
|
||||
* A header-only typesafe dynamic array implementation for plain C,
|
||||
* kinda like C++ std::vector. This code is compatible with C++, but should
|
||||
* only be used with POD (plain old data) types, as it uses memcpy() etc
|
||||
* instead of copy/move construction/assignment.
|
||||
* It requires a new type (created with the DA_TYPEDEF(ELEMENT_TYPE, ARRAY_TYPE_NAME)
|
||||
* macro) for each kind of element you want to put in a dynamic array; however
|
||||
* the "functions" to manipulate the array are actually macros and the same
|
||||
* for all element types.
|
||||
* The array elements are accessed via dynArr.p[i] or da_get(dynArr, i)
|
||||
* - the latter checks whether i is a valid index and asserts if not.
|
||||
*
|
||||
* One thing to keep in mind is that, because of using macros, the arguments to
|
||||
* the "functions" are usually evaluated more than once, so you should avoid
|
||||
* putting things with side effect (like function-calls with side effects or i++)
|
||||
* into them. Notable exceptions are the value arguments (v) of da_push()
|
||||
* and da_insert(), so it's still ok to do da_push(arr, fun_with_sideffects());
|
||||
* or da_insert(a, 3, x++);
|
||||
*
|
||||
* The function-like da_* macros are short aliases of dg_dynarr_* macros.
|
||||
* If the short names clash with anything in your code or other headers
|
||||
* you are using, you can, before #including this header, do
|
||||
* #define DG_DYNARR_NO_SHORTNAMES
|
||||
* and use the long dg_dynarr_* forms of the macros instead.
|
||||
*
|
||||
* Using this library in your project:
|
||||
* Put this file somewhere in your project.
|
||||
* In *one* of your .c/.cpp files, do
|
||||
* #define DG_DYNARR_IMPLEMENTATION
|
||||
* #include "DG_dynarr.h"
|
||||
* to create the implementation of this library in that file.
|
||||
* You can just #include "DG_dynarr.h" (without the #define) in other source
|
||||
* files to use it there.
|
||||
*
|
||||
* See below this comment block for a usage example.
|
||||
*
|
||||
* You can #define your own allocators, assertion and the amount of runtime
|
||||
* checking of indexes, see CONFIGURATION section in the code for more information.
|
||||
*
|
||||
*
|
||||
* This is heavily inspired by Sean Barrett's stretchy_buffer.h
|
||||
* ( see: https://github.com/nothings/stb/blob/master/stretchy_buffer.h )
|
||||
* However I wanted to have a struct that holds the array pointer and the length
|
||||
* and capacity, so that struct always remains at the same address while the
|
||||
* array memory might be reallocated.
|
||||
* I can live with arr.p[i] instead of arr[i], but I like how he managed to use
|
||||
* macros to create an API that doesn't force the user to specify the stored
|
||||
* type over and over again, so I stole some of his tricks :-)
|
||||
*
|
||||
* This has been tested with GCC 4.8 and clang 3.8 (-std=gnu89, -std=c99 and as C++;
|
||||
* -std=c89 works if you convert the C++-style comments to C comments) and
|
||||
* Microsoft Visual Studio 6 and 2010 (32bit) and 2013 (32bit and 64bit).
|
||||
* I guess it works with all (recentish) C++ compilers and C compilers supporting
|
||||
* C99 or even C89 + C++ comments (otherwise converting the comments should help).
|
||||
*
|
||||
* (C) 2016 Daniel Gibson
|
||||
*
|
||||
* LICENSE
|
||||
* This software is dual-licensed to the public domain and under the following
|
||||
* license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||
* publish, and distribute this file as you see fit.
|
||||
* No warranty implied; use at your own risk.
|
||||
*/
|
||||
#if 0 // Usage Example:
|
||||
#define DG_DYNARR_IMPLEMENTATION // this define is only needed in *one* .c/.cpp file!
|
||||
#include "DG_dynarr.h"
|
||||
|
||||
DA_TYPEDEF(int, MyIntArrType); // creates MyIntArrType - a dynamic array for ints
|
||||
|
||||
void printIntArr(MyIntArrType* arr, const char* name)
|
||||
{
|
||||
// note that arr is a pointer here, so use *arr in the da_*() functions.
|
||||
printf("%s = {", name);
|
||||
if(da_count(*arr) > 0)
|
||||
printf(" %d", arr->p[0]);
|
||||
for(int i=1; i<da_count(*arr); ++i)
|
||||
printf(", %d", arr->p[i]);
|
||||
printf(" }\n");
|
||||
}
|
||||
|
||||
void myFunction()
|
||||
{
|
||||
MyIntArrType a1 = {0}; // make sure to zero out the struct
|
||||
// instead of = {0}; you could also call da_init(a1);
|
||||
|
||||
da_push(a1, 42);
|
||||
assert(da_count(a1) == 1 && a1.p[0] == 42);
|
||||
|
||||
int* addedElements = da_addn_uninit(a1, 3);
|
||||
assert(da_count(a1) == 4);
|
||||
for(size_t i=0; i<3; ++i)
|
||||
addedElements[i] = i+5;
|
||||
|
||||
printIntArr(&a1, "a1"); // "a1 = { 42, 5, 6, 7 }"
|
||||
|
||||
MyIntArrType a2;
|
||||
da_init(a2);
|
||||
|
||||
da_addn(a2, a1.p, da_count(a1)); // copy all elements from a1 to a2
|
||||
assert(da_count(a2) == 4);
|
||||
|
||||
da_insert(a2, 1, 11);
|
||||
printIntArr(&a2, "a2"); // "a2 = { 42, 11, 5, 6, 7 }"
|
||||
|
||||
da_delete(a2, 2);
|
||||
printIntArr(&a2, "a2"); // "a2 = { 42, 11, 6, 7 }"
|
||||
|
||||
da_deletefast(a2, 0);
|
||||
printIntArr(&a2, "a2"); // "a2 = { 7, 11, 6 }"
|
||||
|
||||
da_push(a1, 3);
|
||||
printIntArr(&a1, "a1"); // "a1 = { 42, 5, 6, 7, 3 }"
|
||||
|
||||
int x=da_pop(a1);
|
||||
printf("x = %d\n", x); // "x = 3"
|
||||
printIntArr(&a1, "a1"); // "a1 = { 42, 5, 6, 7 }"
|
||||
|
||||
da_free(a1); // make sure not to leak memory!
|
||||
da_free(a2);
|
||||
}
|
||||
#endif // 0 (usage example)
|
||||
|
||||
#ifndef DG__DYNARR_H
|
||||
#define DG__DYNARR_H
|
||||
|
||||
// ######### CONFIGURATION #########
|
||||
|
||||
// following: some #defines that you can tweak to your liking
|
||||
|
||||
// you can reduce some overhead by defining DG_DYNARR_INDEX_CHECK_LEVEL to 2, 1 or 0
|
||||
#ifndef DG_DYNARR_INDEX_CHECK_LEVEL
|
||||
|
||||
// 0: (almost) no index checking
|
||||
// 1: macros "returning" something return a.p[0] or NULL if the index was invalid
|
||||
// 2: assertions in all macros taking indexes that make sure they're valid
|
||||
// 3: 1 and 2
|
||||
#define DG_DYNARR_INDEX_CHECK_LEVEL 3
|
||||
|
||||
#endif // DG_DYNARR_INDEX_CHECK_LEVEL
|
||||
|
||||
// you can #define your own DG_DYNARR_ASSERT(condition, msgstring)
|
||||
// that will be used for all assertions in this code.
|
||||
#ifndef DG_DYNARR_ASSERT
|
||||
#include <assert.h>
|
||||
#define DG_DYNARR_ASSERT(cond, msg) assert((cond) && msg)
|
||||
#endif
|
||||
|
||||
// you can #define DG_DYNARR_OUT_OF_MEMORY to some code that will be executed
|
||||
// if allocating memory fails
|
||||
// it's needed only before the #define DG_DYNARR_IMPLEMENTATION #include of
|
||||
// this header, so the following is here only for reference and commented out
|
||||
/*
|
||||
#ifndef DG_DYNARR_OUT_OF_MEMORY
|
||||
#define DG_DYNARR_OUT_OF_MEMORY DG_DYNARR_ASSERT(0, "Out of Memory!");
|
||||
#endif
|
||||
*/
|
||||
|
||||
// By default, C's malloc(), realloc() and free() is used to allocate/free heap memory
|
||||
// (see beginning of "#ifdef DG_DYNARR_IMPLEMENTATION" block below).
|
||||
// You can #define DG_DYNARR_MALLOC, DG_DYNARR_REALLOC and DG_DYNARR_FREE yourself
|
||||
// to provide alternative implementations like Win32 Heap(Re)Alloc/HeapFree
|
||||
// it's needed only before the #define DG_DYNARR_IMPLEMENTATION #include of
|
||||
// this header, so the following is here only for reference and commented out
|
||||
/*
|
||||
#define DG_DYNARR_MALLOC(elemSize, numElems) malloc(elemSize*numElems)
|
||||
|
||||
// oldNumElems is not used for C's realloc, but maybe you need it for
|
||||
// your allocator to copy the old elements over
|
||||
#define DG_DYNARR_REALLOC(ptr, elemSize, oldNumElems, newCapacity) \
|
||||
realloc(ptr, elemSize*newCapacity);
|
||||
|
||||
#define DG_DYNARR_FREE(ptr) free(ptr)
|
||||
*/
|
||||
|
||||
// if you want to prepend something to the non inline (DG_DYNARR_INLINE) functions,
|
||||
// like "__declspec(dllexport)" or whatever, #define DG_DYNARR_DEF
|
||||
#ifndef DG_DYNARR_DEF
|
||||
// by defaults it's empty.
|
||||
#define DG_DYNARR_DEF
|
||||
#endif
|
||||
|
||||
// some functions are inline, in case your compiler doesn't like "static inline"
|
||||
// but wants "__inline__" or something instead, #define DG_DYNARR_INLINE accordingly.
|
||||
#ifndef DG_DYNARR_INLINE
|
||||
// for pre-C99 compilers you might have to use something compiler-specific (or maybe only "static")
|
||||
#ifdef _MSC_VER
|
||||
#define DG_DYNARR_INLINE static __inline
|
||||
#else
|
||||
#define DG_DYNARR_INLINE static inline
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// ############### Short da_* aliases for the long names ###############
|
||||
|
||||
#ifndef DG_DYNARR_NO_SHORTNAMES
|
||||
|
||||
// this macro is used to create an array type (struct) for elements of TYPE
|
||||
// use like DA_TYPEDEF(int, MyIntArrType); MyIntArrType ia = {0}; da_push(ia, 42); ...
|
||||
#define DA_TYPEDEF(TYPE, NewArrayTypeName) \
|
||||
DG_DYNARR_TYPEDEF(TYPE, NewArrayTypeName)
|
||||
|
||||
// makes sure the array is initialized and can be used.
|
||||
// either do YourArray arr = {0}; or YourArray arr; da_init(arr);
|
||||
#define da_init(a) \
|
||||
dg_dynarr_init(a)
|
||||
|
||||
/*
|
||||
* This allows you to provide an external buffer that'll be used as long as it's big enough
|
||||
* once you add more elements than buf can hold, fresh memory will be allocated on the heap
|
||||
* Use like:
|
||||
* DA_TYPEDEF(double, MyDoubleArrType);
|
||||
* MyDoubleArrType arr;
|
||||
* double buf[8];
|
||||
* dg_dynarr_init_external(arr, buf, 8);
|
||||
* dg_dynarr_push(arr, 1.23);
|
||||
* ...
|
||||
*/
|
||||
#define da_init_external(a, buf, buf_cap) \
|
||||
dg_dynarr_init_external(a, buf, buf_cap)
|
||||
|
||||
// use this to free the memory allocated by dg_dynarr once you don't need the array anymore
|
||||
// Note: it is safe to add new elements to the array after da_free()
|
||||
// it will allocate new memory, just like it would directly after da_init()
|
||||
#define da_free(a) \
|
||||
dg_dynarr_free(a)
|
||||
|
||||
|
||||
// add an element to the array (appended at the end)
|
||||
#define da_push(a, v) \
|
||||
dg_dynarr_push(a, v)
|
||||
|
||||
// add an element to the array (appended at the end)
|
||||
// does the same as push, just for consistency with addn (like insert and insertn)
|
||||
#define da_add(a, v) \
|
||||
dg_dynarr_add(a, v)
|
||||
|
||||
// append n elements to a and initialize them from array vals, doesn't return anything
|
||||
// ! vals (and all other args) are evaluated multiple times !
|
||||
#define da_addn(a, vals, n) \
|
||||
dg_dynarr_addn(a, vals, n)
|
||||
|
||||
// add n elements to the end of the array and zeroes them with memset()
|
||||
// returns pointer to first added element, NULL if out of memory (array is empty then)
|
||||
#define da_addn_zeroed(a, n) \
|
||||
dg_dynarr_addn_zeroed(a, n)
|
||||
|
||||
// add n elements to the end of the array, will remain uninitialized
|
||||
// returns pointer to first added element, NULL if out of memory (array is empty then)
|
||||
#define da_addn_uninit(a, n) \
|
||||
dg_dynarr_addn_uninit(a, n)
|
||||
|
||||
|
||||
// insert a single value v at index idx
|
||||
#define da_insert(a, idx, v) \
|
||||
dg_dynarr_insert(a, idx, v)
|
||||
|
||||
// insert n elements into a at idx, initialize them from array vals
|
||||
// doesn't return anything
|
||||
// ! vals (and all other args) is evaluated multiple times !
|
||||
#define da_insertn(a, idx, vals, n) \
|
||||
dg_dynarr_insertn(a, idx, vals, n)
|
||||
|
||||
// insert n elements into a at idx and zeroe them with memset()
|
||||
// returns pointer to first inserted element or NULL if out of memory
|
||||
#define da_insertn_zeroed(a, idx, n) \
|
||||
dg_dynarr_insertn_zeroed(a, idx, n)
|
||||
|
||||
// insert n uninitialized elements into a at idx;
|
||||
// returns pointer to first inserted element or NULL if out of memory
|
||||
#define da_insertn_uninit(a, idx, n) \
|
||||
dg_dynarr_insertn_uninit(a, idx, n)
|
||||
|
||||
// set a single value v at index idx - like "a.p[idx] = v;" but with checks (unless disabled)
|
||||
#define da_set(a, idx, v) \
|
||||
dg_dynarr_set(a, idx, v)
|
||||
|
||||
// overwrite n elements of a, starting at idx, with values from array vals
|
||||
// doesn't return anything
|
||||
// ! vals (and all other args) is evaluated multiple times !
|
||||
#define da_setn(a, idx, vals, n) \
|
||||
dg_dynarr_setn(a, idx, vals, n)
|
||||
|
||||
// delete the element at idx, moving all following elements (=> keeps order)
|
||||
#define da_delete(a, idx) \
|
||||
dg_dynarr_delete(a, idx)
|
||||
|
||||
// delete n elements starting at idx, moving all following elements (=> keeps order)
|
||||
#define da_deleten(a, idx, n) \
|
||||
dg_dynarr_deleten(a, idx, n)
|
||||
|
||||
// delete the element at idx, move the last element there (=> doesn't keep order)
|
||||
#define da_deletefast(a, idx) \
|
||||
dg_dynarr_deletefast(a, idx)
|
||||
|
||||
// delete n elements starting at idx, move the last n elements there (=> doesn't keep order)
|
||||
#define da_deletenfast(a, idx, n) \
|
||||
dg_dynarr_deletenfast(a, idx, n)
|
||||
|
||||
// removes all elements from the array, but does not free the buffer
|
||||
// (if you want to free the buffer too, just use da_free())
|
||||
#define da_clear(a) \
|
||||
dg_dynarr_clear(a)
|
||||
|
||||
// sets the logical number of elements in the array
|
||||
// if cnt > dg_dynarr_count(a), the logical count will be increased accordingly
|
||||
// and the new elements will be uninitialized
|
||||
#define da_setcount(a, cnt) \
|
||||
dg_dynarr_setcount(a, cnt)
|
||||
|
||||
// make sure the array can store cap elements without reallocating
|
||||
// logical count remains unchanged
|
||||
#define da_reserve(a, cap) \
|
||||
dg_dynarr_reserve(a, cap)
|
||||
|
||||
// this makes sure a only uses as much memory as for its elements
|
||||
// => maybe useful if a used to contain a huge amount of elements,
|
||||
// but you deleted most of them and want to free some memory
|
||||
// Note however that this implies an allocation and copying the remaining
|
||||
// elements, so only do this if it frees enough memory to be worthwhile!
|
||||
#define da_shrink_to_fit(a) \
|
||||
dg_dynarr_shrink_to_fit(a)
|
||||
|
||||
|
||||
// removes and returns the last element of the array
|
||||
#define da_pop(a) \
|
||||
dg_dynarr_pop(a)
|
||||
|
||||
// returns the last element of the array
|
||||
#define da_last(a) \
|
||||
dg_dynarr_last(a)
|
||||
|
||||
// returns the pointer *to* the last element of the array
|
||||
// (in contrast to dg_dynarr_end() which returns a pointer *after* the last element)
|
||||
// returns NULL if array is empty
|
||||
#define da_lastptr(a) \
|
||||
dg_dynarr_lastptr(a)
|
||||
|
||||
// get element at index idx (like a.p[idx]), but with checks
|
||||
// (unless you disabled them with #define DG_DYNARR_INDEX_CHECK_LEVEL 0)
|
||||
#define da_get(a, idx) \
|
||||
dg_dynarr_get(a,idx)
|
||||
|
||||
// get pointer to element at index idx (like &a.p[idx]), but with checks
|
||||
// and it returns NULL if idx is invalid
|
||||
#define da_getptr(a, idx) \
|
||||
dg_dynarr_getptr(a, idx)
|
||||
|
||||
// returns a pointer to the first element of the array
|
||||
// (together with dg_dynarr_end() you can do C++-style iterating)
|
||||
#define da_begin(a) \
|
||||
dg_dynarr_begin(a)
|
||||
|
||||
// returns a pointer to the past-the-end element of the array
|
||||
// Allows C++-style iterating, in case you're into that kind of thing:
|
||||
// for(T *it=da_begin(a), *end=da_end(a); it!=end; ++it) foo(*it);
|
||||
// (see da_lastptr() to get a pointer *to* the last element)
|
||||
#define da_end(a) \
|
||||
dg_dynarr_end(a)
|
||||
|
||||
|
||||
// returns (logical) number of elements currently in the array
|
||||
#define da_count(a) \
|
||||
dg_dynarr_count(a)
|
||||
|
||||
// get the current reserved capacity of the array
|
||||
#define da_capacity(a) \
|
||||
dg_dynarr_capacity(a)
|
||||
|
||||
// returns 1 if the array is empty, else 0
|
||||
#define da_empty(a) \
|
||||
dg_dynarr_empty(a)
|
||||
|
||||
// returns 1 if the last (re)allocation when inserting failed (Out Of Memory)
|
||||
// or if the array has never allocated any memory yet, else 0
|
||||
// deleting the contents when growing fails instead of keeping old may seem
|
||||
// a bit uncool, but it's simple and OOM should rarely happen on modern systems
|
||||
// anyway - after all you need to deplete both RAM and swap/pagefile.sys
|
||||
#define da_oom(a) \
|
||||
dg_dynarr_oom(a)
|
||||
|
||||
|
||||
// sort a using the given qsort()-comparator cmp
|
||||
// (just a slim wrapper around qsort())
|
||||
#define da_sort(a, cmp) \
|
||||
dg_dynarr_sort(a, cmp)
|
||||
|
||||
#endif // DG_DYNARR_NO_SHORTNAMES
|
||||
|
||||
|
||||
// ######### Implementation of the actual macros (using the long names) ##########
|
||||
|
||||
// use like DG_DYNARR_TYPEDEF(int, MyIntArrType); MyIntArrType ia = {0}; dg_dynarr_push(ia, 42); ...
|
||||
#define DG_DYNARR_TYPEDEF(TYPE, NewArrayTypeName) \
|
||||
typedef struct { TYPE* p; dg__dynarr_md md; } NewArrayTypeName;
|
||||
|
||||
// makes sure the array is initialized and can be used.
|
||||
// either do YourArray arr = {0}; or YourArray arr; dg_dynarr_init(arr);
|
||||
#define dg_dynarr_init(a) \
|
||||
dg__dynarr_init((void**)&(a).p, &(a).md, NULL, 0)
|
||||
|
||||
// this allows you to provide an external buffer that'll be used as long as it's big enough
|
||||
// once you add more elements than buf can hold, fresh memory will be allocated on the heap
|
||||
#define dg_dynarr_init_external(a, buf, buf_cap) \
|
||||
dg__dynarr_init((void**)&(a).p, &(a).md, (buf), (buf_cap))
|
||||
|
||||
// use this to free the memory allocated by dg_dynarr
|
||||
// Note: it is safe to add new elements to the array after dg_dynarr_free()
|
||||
// it will allocate new memory, just like it would directly after dg_dynarr_init()
|
||||
#define dg_dynarr_free(a) \
|
||||
dg__dynarr_free((void**)&(a).p, &(a).md)
|
||||
|
||||
|
||||
// add an element to the array (appended at the end)
|
||||
#define dg_dynarr_push(a, v) \
|
||||
(dg__dynarr_maybegrowadd(dg__dynarr_unp(a), 1) ? (((a).p[(a).md.cnt++] = (v)),0) : 0)
|
||||
|
||||
// add an element to the array (appended at the end)
|
||||
// does the same as push, just for consistency with addn (like insert and insertn)
|
||||
#define dg_dynarr_add(a, v) \
|
||||
dg_dynarr_push((a), (v))
|
||||
|
||||
// append n elements to a and initialize them from array vals, doesn't return anything
|
||||
// ! vals (and all other args) are evaluated multiple times !
|
||||
#define dg_dynarr_addn(a, vals, n) do { \
|
||||
DG_DYNARR_ASSERT((vals)!=NULL, "Don't pass NULL als vals to dg_dynarr_addn!"); \
|
||||
if((vals)!=NULL && dg__dynarr_add(dg__dynarr_unp(a), n, 0)) { \
|
||||
size_t i_=(a).md.cnt-(n), v_=0; \
|
||||
while(i_<(a).md.cnt) (a).p[i_++]=(vals)[v_++]; \
|
||||
} } DG__DYNARR_WHILE0
|
||||
|
||||
// add n elements to the end of the array and zeroe them with memset()
|
||||
// returns pointer to first added element, NULL if out of memory (array is empty then)
|
||||
#define dg_dynarr_addn_zeroed(a, n) \
|
||||
(dg__dynarr_add(dg__dynarr_unp(a), (n), 1) ? &(a).p[(a).md.cnt-(size_t)(n)] : NULL)
|
||||
|
||||
// add n elements to the end of the array, which are uninitialized
|
||||
// returns pointer to first added element, NULL if out of memory (array is empty then)
|
||||
#define dg_dynarr_addn_uninit(a, n) \
|
||||
(dg__dynarr_add(dg__dynarr_unp(a), (n), 0) ? &(a).p[(a).md.cnt-(size_t)(n)] : NULL)
|
||||
|
||||
// insert a single value v at index idx
|
||||
#define dg_dynarr_insert(a, idx, v) \
|
||||
(dg__dynarr_checkidxle((a),(idx)), \
|
||||
dg__dynarr_insert(dg__dynarr_unp(a), (idx), 1, 0), \
|
||||
(a).p[dg__dynarr_idx((a).md, (idx))] = (v))
|
||||
|
||||
// insert n elements into a at idx, initialize them from array vals
|
||||
// doesn't return anything
|
||||
// ! vals (and all other args) is evaluated multiple times !
|
||||
#define dg_dynarr_insertn(a, idx, vals, n) do { \
|
||||
DG_DYNARR_ASSERT((vals)!=NULL, "Don't pass NULL as vals to dg_dynarr_insertn!"); \
|
||||
dg__dynarr_checkidxle((a),(idx)); \
|
||||
if((vals)!=NULL && dg__dynarr_insert(dg__dynarr_unp(a), (idx), (n), 0)){ \
|
||||
size_t i_=(idx), v_=0, e_=(idx)+(n); \
|
||||
while(i_ < e_) (a).p[i_++] = (vals)[v_++]; \
|
||||
}} DG__DYNARR_WHILE0
|
||||
|
||||
// insert n elements into a at idx and zeroe them with memset()
|
||||
// returns pointer to first inserted element or NULL if out of memory
|
||||
#define dg_dynarr_insertn_zeroed(a, idx, n) \
|
||||
(dg__dynarr_checkidxle((a),(idx)), \
|
||||
dg__dynarr_insert(dg__dynarr_unp(a), (idx), (n), 1) \
|
||||
? &(a).p[dg__dynarr_idx((a).md, (idx))] : NULL)
|
||||
|
||||
// insert n uninitialized elements into a at idx;
|
||||
// returns pointer to first inserted element or NULL if out of memory
|
||||
#define dg_dynarr_insertn_uninit(a, idx, n) \
|
||||
(dg__dynarr_checkidxle((a),(idx)), \
|
||||
dg__dynarr_insert(dg__dynarr_unp(a), idx, n, 0) \
|
||||
? &(a).p[dg__dynarr_idx((a).md, (idx))] : NULL)
|
||||
|
||||
// set a single value v at index idx - like "a.p[idx] = v;" but with checks (unless disabled)
|
||||
#define dg_dynarr_set(a, idx, v) \
|
||||
(dg__dynarr_checkidx((a),(idx)), \
|
||||
(a).p[dg__dynarr_idx((a).md, (idx))] = (v))
|
||||
|
||||
// overwrite n elements of a, starting at idx, with values from array vals
|
||||
// doesn't return anything
|
||||
// ! vals (and all other args) is evaluated multiple times !
|
||||
#define dg_dynarr_setn(a, idx, vals, n) do { \
|
||||
DG_DYNARR_ASSERT((vals)!=NULL, "Don't pass NULL as vals to dg_dynarr_setn!"); \
|
||||
size_t idx_=(idx); size_t end_=idx_+(size_t)n; \
|
||||
dg__dynarr_checkidx((a),idx_); dg__dynarr_checkidx((a),end_-1); \
|
||||
if((vals)!=NULL && idx_ < (a).md.cnt && end_ <= (a).md.cnt) { \
|
||||
size_t v_=0; \
|
||||
while(idx_ < end_) (a).p[idx_++] = (vals)[v_++]; \
|
||||
}} DG__DYNARR_WHILE0
|
||||
|
||||
|
||||
// delete the element at idx, moving all following elements (=> keeps order)
|
||||
#define dg_dynarr_delete(a, idx) \
|
||||
(dg__dynarr_checkidx((a),(idx)), dg__dynarr_delete(dg__dynarr_unp(a), (idx), 1))
|
||||
|
||||
// delete n elements starting at idx, moving all following elements (=> keeps order)
|
||||
#define dg_dynarr_deleten(a, idx, n) \
|
||||
(dg__dynarr_checkidx((a),(idx)), dg__dynarr_delete(dg__dynarr_unp(a), (idx), (n)))
|
||||
// TODO: check whether idx+n < count?
|
||||
|
||||
// delete the element at idx, move the last element there (=> doesn't keep order)
|
||||
#define dg_dynarr_deletefast(a, idx) \
|
||||
(dg__dynarr_checkidx((a),(idx)), dg__dynarr_deletefast(dg__dynarr_unp(a), (idx), 1))
|
||||
|
||||
// delete n elements starting at idx, move the last n elements there (=> doesn't keep order)
|
||||
#define dg_dynarr_deletenfast(a, idx, n) \
|
||||
(dg__dynarr_checkidx((a),(idx)), dg__dynarr_deletefast(dg__dynarr_unp(a), idx, n))
|
||||
// TODO: check whether idx+n < count?
|
||||
|
||||
// removes all elements from the array, but does not free the buffer
|
||||
// (if you want to free the buffer too, just use dg_dynarr_free())
|
||||
#define dg_dynarr_clear(a) \
|
||||
((a).md.cnt=0)
|
||||
|
||||
// sets the logical number of elements in the array
|
||||
// if cnt > dg_dynarr_count(a), the logical count will be increased accordingly
|
||||
// and the new elements will be uninitialized
|
||||
#define dg_dynarr_setcount(a, n) \
|
||||
(dg__dynarr_maybegrow(dg__dynarr_unp(a), (n)) ? ((a).md.cnt = (n)) : 0)
|
||||
|
||||
// make sure the array can store cap elements without reallocating
|
||||
// logical count remains unchanged
|
||||
#define dg_dynarr_reserve(a, cap) \
|
||||
dg__dynarr_maybegrow(dg__dynarr_unp(a), (cap))
|
||||
|
||||
// this makes sure a only uses as much memory as for its elements
|
||||
// => maybe useful if a used to contain a huge amount of elements,
|
||||
// but you deleted most of them and want to free some memory
|
||||
// Note however that this implies an allocation and copying the remaining
|
||||
// elements, so only do this if it frees enough memory to be worthwhile!
|
||||
#define dg_dynarr_shrink_to_fit(a) \
|
||||
dg__dynarr_shrink_to_fit(dg__dynarr_unp(a))
|
||||
|
||||
|
||||
#if (DG_DYNARR_INDEX_CHECK_LEVEL == 1) || (DG_DYNARR_INDEX_CHECK_LEVEL == 3)
|
||||
|
||||
// removes and returns the last element of the array
|
||||
#define dg_dynarr_pop(a) \
|
||||
(dg__dynarr_check_notempty((a), "Don't pop an empty array!"), \
|
||||
(a).p[((a).md.cnt > 0) ? (--(a).md.cnt) : 0])
|
||||
|
||||
// returns the last element of the array
|
||||
#define dg_dynarr_last(a) \
|
||||
(dg__dynarr_check_notempty((a), "Don't call da_last() on an empty array!"), \
|
||||
(a).p[((a).md.cnt > 0) ? ((a).md.cnt-1) : 0])
|
||||
|
||||
#elif (DG_DYNARR_INDEX_CHECK_LEVEL == 0) || (DG_DYNARR_INDEX_CHECK_LEVEL == 2)
|
||||
|
||||
// removes and returns the last element of the array
|
||||
#define dg_dynarr_pop(a) \
|
||||
(dg__dynarr_check_notempty((a), "Don't pop an empty array!"), \
|
||||
(a).p[--(a).md.cnt])
|
||||
|
||||
// returns the last element of the array
|
||||
#define dg_dynarr_last(a) \
|
||||
(dg__dynarr_check_notempty((a), "Don't call da_last() on an empty array!"), \
|
||||
(a).p[(a).md.cnt-1])
|
||||
|
||||
#else // invalid DG_DYNARR_INDEX_CHECK_LEVEL
|
||||
#error Invalid index check level DG_DYNARR_INDEX_CHECK_LEVEL (must be 0-3) !
|
||||
#endif // DG_DYNARR_INDEX_CHECK_LEVEL
|
||||
|
||||
// returns the pointer *to* the last element of the array
|
||||
// (in contrast to dg_dynarr_end() which returns a pointer *after* the last element)
|
||||
// returns NULL if array is empty
|
||||
#define dg_dynarr_lastptr(a) \
|
||||
(((a).md.cnt > 0) ? ((a).p + (a).md.cnt - 1) : NULL)
|
||||
|
||||
// get element at index idx (like a.p[idx]), but with checks
|
||||
// (unless you disabled them with #define DG_DYNARR_INDEX_CHECK_LEVEL 0)
|
||||
#define dg_dynarr_get(a, idx) \
|
||||
(dg__dynarr_checkidx((a),(idx)), (a).p[dg__dynarr_idx((a).md, (idx))])
|
||||
|
||||
// get pointer to element at index idx (like &a.p[idx]), but with checks
|
||||
// (unless you disabled them with #define DG_DYNARR_INDEX_CHECK_LEVEL 0)
|
||||
// if index-checks are disabled, it returns NULL on invalid index (else it asserts() before returning)
|
||||
#define dg_dynarr_getptr(a, idx) \
|
||||
(dg__dynarr_checkidx((a),(idx)), \
|
||||
((size_t)(idx) < (a).md.cnt) ? ((a).p+(size_t)(idx)) : NULL)
|
||||
|
||||
// returns a pointer to the first element of the array
|
||||
// (together with dg_dynarr_end() you can do C++-style iterating)
|
||||
#define dg_dynarr_begin(a) \
|
||||
((a).p)
|
||||
|
||||
// returns a pointer to the past-the-end element of the array
|
||||
// Allows C++-style iterating, in case you're into that kind of thing:
|
||||
// for(T *it=dg_dynarr_begin(a), *end=dg_dynarr_end(a); it!=end; ++it) foo(*it);
|
||||
// (see dg_dynarr_lastptr() to get a pointer *to* the last element)
|
||||
#define dg_dynarr_end(a) \
|
||||
((a).p + (a).md.cnt)
|
||||
|
||||
|
||||
// returns (logical) number of elements currently in the array
|
||||
#define dg_dynarr_count(a) \
|
||||
((a).md.cnt)
|
||||
|
||||
// get the current reserved capacity of the array
|
||||
#define dg_dynarr_capacity(a) \
|
||||
((a).md.cap & DG__DYNARR_SIZE_T_ALL_BUT_MSB)
|
||||
|
||||
// returns 1 if the array is empty, else 0
|
||||
#define dg_dynarr_empty(a) \
|
||||
((a).md.cnt == 0)
|
||||
|
||||
// returns 1 if the last (re)allocation when inserting failed (Out Of Memory)
|
||||
// or if the array has never allocated any memory yet, else 0
|
||||
// deleting the contents when growing fails instead of keeping old may seem
|
||||
// a bit uncool, but it's simple and OOM should rarely happen on modern systems
|
||||
// anyway - after all you need to deplete both RAM and swap/pagefile.sys
|
||||
// or deplete the address space, which /might/ happen with 32bit applications
|
||||
// but probably not with 64bit (at least in the foreseeable future)
|
||||
#define dg_dynarr_oom(a) \
|
||||
((a).md.cap == 0)
|
||||
|
||||
|
||||
// sort a using the given qsort()-comparator cmp
|
||||
// (just a slim wrapper around qsort())
|
||||
#define dg_dynarr_sort(a, cmp) \
|
||||
qsort((a).p, (a).md.cnt, sizeof((a).p[0]), (cmp))
|
||||
|
||||
|
||||
// ######### Implementation-Details that are not part of the API ##########
|
||||
|
||||
#include <stdlib.h> // size_t, malloc(), free(), realloc()
|
||||
#include <string.h> // memset(), memcpy(), memmove()
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
size_t cnt; // logical number of elements
|
||||
size_t cap; // cap & DG__DYNARR_SIZE_T_ALL_BUT_MSB is actual capacity (in elements, *not* bytes!)
|
||||
// if(cap & DG__DYNARR_SIZE_T_MSB) the current memory is not allocated by dg_dynarr,
|
||||
// but was set with dg_dynarr_init_external()
|
||||
// that's handy to give an array a base-element storage on the stack, for example
|
||||
// TODO: alternatively, we could introduce a flag field to this struct and use that,
|
||||
// so we don't have to calculate & everytime cap is needed
|
||||
} dg__dynarr_md;
|
||||
|
||||
// I used to have the following in an enum, but MSVC assumes enums are always 32bit ints
|
||||
static const size_t DG__DYNARR_SIZE_T_MSB = ((size_t)1) << (sizeof(size_t)*8 - 1);
|
||||
static const size_t DG__DYNARR_SIZE_T_ALL_BUT_MSB = (((size_t)1) << (sizeof(size_t)*8 - 1))-1;
|
||||
|
||||
// "unpack" the elements of an array struct for use with helper functions
|
||||
// (to void** arr, dg__dynarr_md* md, size_t itemsize)
|
||||
#define dg__dynarr_unp(a) \
|
||||
(void**)&(a).p, &(a).md, sizeof((a).p[0])
|
||||
|
||||
// MSVC warns about "conditional expression is constant" when using the
|
||||
// do { ... } while(0) idiom in macros..
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER >= 1400 // MSVC 2005 and newer
|
||||
// people claim MSVC 2005 and newer support __pragma, even though it's only documented
|
||||
// for 2008+ (https://msdn.microsoft.com/en-us/library/d9x1s805%28v=vs.90%29.aspx)
|
||||
// the following workaround is based on
|
||||
// http://cnicholson.net/2009/03/stupid-c-tricks-dowhile0-and-c4127/
|
||||
#define DG__DYNARR_WHILE0 \
|
||||
__pragma(warning(push)) \
|
||||
__pragma(warning(disable:4127)) \
|
||||
while(0) \
|
||||
__pragma(warning(pop))
|
||||
#else // older MSVC versions don't support __pragma - I heard this helps for them
|
||||
#define DG__DYNARR_WHILE0 while(0,0)
|
||||
#endif
|
||||
|
||||
#else // other compilers
|
||||
|
||||
#define DG__DYNARR_WHILE0 while(0)
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
|
||||
#if (DG_DYNARR_INDEX_CHECK_LEVEL == 2) || (DG_DYNARR_INDEX_CHECK_LEVEL == 3)
|
||||
|
||||
#define dg__dynarr_checkidx(a,i) \
|
||||
DG_DYNARR_ASSERT((size_t)i < a.md.cnt, "index out of bounds!")
|
||||
|
||||
// special case for insert operations: == cnt is also ok, insert will append then
|
||||
#define dg__dynarr_checkidxle(a,i) \
|
||||
DG_DYNARR_ASSERT((size_t)i <= a.md.cnt, "index out of bounds!")
|
||||
|
||||
#define dg__dynarr_check_notempty(a, msg) \
|
||||
DG_DYNARR_ASSERT(a.md.cnt > 0, msg)
|
||||
|
||||
#elif (DG_DYNARR_INDEX_CHECK_LEVEL == 0) || (DG_DYNARR_INDEX_CHECK_LEVEL == 1)
|
||||
|
||||
// no assertions that check if index is valid
|
||||
#define dg__dynarr_checkidx(a,i) (void)0
|
||||
#define dg__dynarr_checkidxle(a,i) (void)0
|
||||
|
||||
#define dg__dynarr_check_notempty(a, msg) (void)0
|
||||
|
||||
#else // invalid DG_DYNARR_INDEX_CHECK_LEVEL
|
||||
#error Invalid index check level DG_DYNARR_INDEX_CHECK_LEVEL (must be 0-3) !
|
||||
#endif // DG_DYNARR_INDEX_CHECK_LEVEL
|
||||
|
||||
|
||||
#if (DG_DYNARR_INDEX_CHECK_LEVEL == 1) || (DG_DYNARR_INDEX_CHECK_LEVEL == 3)
|
||||
|
||||
// the given index, if valid, else 0
|
||||
#define dg__dynarr_idx(md,i) \
|
||||
(((size_t)(i) < md.cnt) ? (size_t)(i) : 0)
|
||||
|
||||
#elif (DG_DYNARR_INDEX_CHECK_LEVEL == 0) || (DG_DYNARR_INDEX_CHECK_LEVEL == 2)
|
||||
|
||||
// don't check and default to 0 if invalid, but just use the given value
|
||||
#define dg__dynarr_idx(md,i) (size_t)(i)
|
||||
|
||||
#else // invalid DG_DYNARR_INDEX_CHECK_LEVEL
|
||||
#error Invalid index check level DG_DYNARR_INDEX_CHECK_LEVEL (must be 0-3) !
|
||||
#endif // DG_DYNARR_INDEX_CHECK_LEVEL
|
||||
|
||||
// the functions allocating/freeing memory are not implemented inline, but
|
||||
// in the #ifdef DG_DYNARR_IMPLEMENTATION section
|
||||
// one reason is that dg__dynarr_grow has the most code in it, the other is
|
||||
// that windows has weird per-dll heaps so free() or realloc() should be
|
||||
// called from code in the same dll that allocated the memory - these kind
|
||||
// of wrapper functions that end up compiled into the exe or *one* dll
|
||||
// (instead of inline functions compiled into everything) should ensure that.
|
||||
|
||||
DG_DYNARR_DEF void
|
||||
dg__dynarr_free(void** p, dg__dynarr_md* md);
|
||||
|
||||
DG_DYNARR_DEF void
|
||||
dg__dynarr_shrink_to_fit(void** arr, dg__dynarr_md* md, size_t itemsize);
|
||||
|
||||
// grow array to have enough space for at least min_needed elements
|
||||
// if it fails (OOM), the array will be deleted, a.p will be NULL, a.md.cap and a.md.cnt will be 0
|
||||
// and the functions returns 0; else (on success) it returns 1
|
||||
DG_DYNARR_DEF int
|
||||
dg__dynarr_grow(void** arr, dg__dynarr_md* md, size_t itemsize, size_t min_needed);
|
||||
|
||||
|
||||
// the following functions are implemented inline, because they're quite short
|
||||
// and mosty implemented in functions so the macros don't get too ugly
|
||||
|
||||
DG_DYNARR_INLINE void
|
||||
dg__dynarr_init(void** p, dg__dynarr_md* md, void* buf, size_t buf_cap)
|
||||
{
|
||||
*p = buf;
|
||||
md->cnt = 0;
|
||||
if(buf == NULL) md->cap = 0;
|
||||
else md->cap = (DG__DYNARR_SIZE_T_MSB | buf_cap);
|
||||
}
|
||||
|
||||
DG_DYNARR_INLINE int
|
||||
dg__dynarr_maybegrow(void** arr, dg__dynarr_md* md, size_t itemsize, size_t min_needed)
|
||||
{
|
||||
if((md->cap & DG__DYNARR_SIZE_T_ALL_BUT_MSB) >= min_needed) return 1;
|
||||
else return dg__dynarr_grow(arr, md, itemsize, min_needed);
|
||||
}
|
||||
|
||||
DG_DYNARR_INLINE int
|
||||
dg__dynarr_maybegrowadd(void** arr, dg__dynarr_md* md, size_t itemsize, size_t num_add)
|
||||
{
|
||||
size_t min_needed = md->cnt+num_add;
|
||||
if((md->cap & DG__DYNARR_SIZE_T_ALL_BUT_MSB) >= min_needed) return 1;
|
||||
else return dg__dynarr_grow(arr, md, itemsize, min_needed);
|
||||
}
|
||||
|
||||
DG_DYNARR_INLINE int
|
||||
dg__dynarr_insert(void** arr, dg__dynarr_md* md, size_t itemsize, size_t idx, size_t n, int init0)
|
||||
{
|
||||
// allow idx == md->cnt to append
|
||||
size_t oldCount = md->cnt;
|
||||
size_t newCount = oldCount+n;
|
||||
if(idx <= oldCount && dg__dynarr_maybegrow(arr, md, itemsize, newCount))
|
||||
{
|
||||
unsigned char* p = (unsigned char*)*arr; // *arr might have changed in dg__dynarr_grow()!
|
||||
// move all existing items after a[idx] to a[idx+n]
|
||||
if(idx < oldCount) memmove(p+(idx+n)*itemsize, p+idx*itemsize, itemsize*(oldCount - idx));
|
||||
|
||||
// if the memory is supposed to be zeroed, do that
|
||||
if(init0) memset(p+idx*itemsize, 0, n*itemsize);
|
||||
|
||||
md->cnt = newCount;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DG_DYNARR_INLINE int
|
||||
dg__dynarr_add(void** arr, dg__dynarr_md* md, size_t itemsize, size_t n, int init0)
|
||||
{
|
||||
size_t cnt = md->cnt;
|
||||
if(dg__dynarr_maybegrow(arr, md, itemsize, cnt+n))
|
||||
{
|
||||
unsigned char* p = (unsigned char*)*arr; // *arr might have changed in dg__dynarr_grow()!
|
||||
// if the memory is supposed to be zeroed, do that
|
||||
if(init0) memset(p+cnt*itemsize, 0, n*itemsize);
|
||||
|
||||
md->cnt += n;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DG_DYNARR_INLINE void
|
||||
dg__dynarr_delete(void** arr, dg__dynarr_md* md, size_t itemsize, size_t idx, size_t n)
|
||||
{
|
||||
size_t cnt = md->cnt;
|
||||
if(idx < cnt)
|
||||
{
|
||||
if(idx+n >= cnt) md->cnt = idx; // removing last element(s) => just reduce count
|
||||
else
|
||||
{
|
||||
unsigned char* p = (unsigned char*)*arr;
|
||||
// move all items following a[idx+n] to a[idx]
|
||||
memmove(p+itemsize*idx, p+itemsize*(idx+n), itemsize*(cnt - (idx+n)));
|
||||
md->cnt -= n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DG_DYNARR_INLINE void
|
||||
dg__dynarr_deletefast(void** arr, dg__dynarr_md* md, size_t itemsize, size_t idx, size_t n)
|
||||
{
|
||||
size_t cnt = md->cnt;
|
||||
if(idx < cnt)
|
||||
{
|
||||
if(idx+n >= cnt) md->cnt = idx; // removing last element(s) => just reduce count
|
||||
else
|
||||
{
|
||||
unsigned char* p = (unsigned char*)*arr;
|
||||
// copy the last n items to a[idx] - but handle the case that
|
||||
// the array has less than n elements left after the deleted elements
|
||||
size_t numItemsAfterDeleted = cnt - (idx+n);
|
||||
size_t m = (n < numItemsAfterDeleted) ? n : numItemsAfterDeleted;
|
||||
memcpy(p+itemsize*idx, p+itemsize*(cnt - m), itemsize*m);
|
||||
md->cnt -= n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // DG__DYNARR_H
|
||||
|
||||
|
||||
// ############## Implementation of non-inline functions ##############
|
||||
|
||||
#ifdef DG_DYNARR_IMPLEMENTATION
|
||||
|
||||
// by default, C's malloc(), realloc() and free() is used to allocate/free heap memory.
|
||||
// you can #define DG_DYNARR_MALLOC, DG_DYNARR_REALLOC and DG_DYNARR_FREE
|
||||
// to provide alternative implementations like Win32 Heap(Re)Alloc/HeapFree
|
||||
//
|
||||
#ifndef DG_DYNARR_MALLOC
|
||||
#define DG_DYNARR_MALLOC(elemSize, numElems) malloc(elemSize*numElems)
|
||||
|
||||
// oldNumElems is not used here, but maybe you need it for your allocator
|
||||
// to copy the old elements over
|
||||
#define DG_DYNARR_REALLOC(ptr, elemSize, oldNumElems, newCapacity) \
|
||||
realloc(ptr, elemSize*newCapacity);
|
||||
|
||||
#define DG_DYNARR_FREE(ptr) free(ptr)
|
||||
#endif
|
||||
|
||||
// you can #define DG_DYNARR_OUT_OF_MEMORY to some code that will be executed
|
||||
// if allocating memory fails
|
||||
#ifndef DG_DYNARR_OUT_OF_MEMORY
|
||||
#define DG_DYNARR_OUT_OF_MEMORY DG_DYNARR_ASSERT(0, "Out of Memory!");
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DG_DYNARR_DEF void
|
||||
dg__dynarr_free(void** p, dg__dynarr_md* md)
|
||||
{
|
||||
// only free memory if it doesn't point to external memory
|
||||
if(!(md->cap & DG__DYNARR_SIZE_T_MSB))
|
||||
{
|
||||
DG_DYNARR_FREE(*p);
|
||||
*p = NULL;
|
||||
md->cap = 0;
|
||||
}
|
||||
md->cnt = 0;
|
||||
}
|
||||
|
||||
|
||||
DG_DYNARR_DEF int
|
||||
dg__dynarr_grow(void** arr, dg__dynarr_md* md, size_t itemsize, size_t min_needed)
|
||||
{
|
||||
size_t cap = md->cap & DG__DYNARR_SIZE_T_ALL_BUT_MSB;
|
||||
|
||||
DG_DYNARR_ASSERT(min_needed > cap, "dg__dynarr_grow() should only be called if storage actually needs to grow!");
|
||||
|
||||
if(min_needed < DG__DYNARR_SIZE_T_MSB)
|
||||
{
|
||||
size_t newcap = (cap > 4) ? (2*cap) : 8; // allocate for at least 8 elements
|
||||
// make sure not to set DG__DYNARR_SIZE_T_MSB (unlikely anyway)
|
||||
if(newcap >= DG__DYNARR_SIZE_T_MSB) newcap = DG__DYNARR_SIZE_T_MSB-1;
|
||||
if(min_needed > newcap) newcap = min_needed;
|
||||
|
||||
// the memory was allocated externally, don't free it, just copy contents
|
||||
if(md->cap & DG__DYNARR_SIZE_T_MSB)
|
||||
{
|
||||
void* p = DG_DYNARR_MALLOC(itemsize, newcap);
|
||||
if(p != NULL) memcpy(p, *arr, itemsize*md->cnt);
|
||||
*arr = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
void* p = DG_DYNARR_REALLOC(*arr, itemsize, md->cnt, newcap);
|
||||
if(p == NULL) DG_DYNARR_FREE(*arr); // realloc failed, at least don't leak memory
|
||||
*arr = p;
|
||||
}
|
||||
|
||||
// TODO: handle OOM by setting highest bit of count and keeping old data?
|
||||
|
||||
if(*arr) md->cap = newcap;
|
||||
else
|
||||
{
|
||||
md->cap = 0;
|
||||
md->cnt = 0;
|
||||
|
||||
DG_DYNARR_OUT_OF_MEMORY ;
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
DG_DYNARR_ASSERT(min_needed < DG__DYNARR_SIZE_T_MSB, "Arrays must stay below SIZE_T_MAX/2 elements!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
DG_DYNARR_DEF void
|
||||
dg__dynarr_shrink_to_fit(void** arr, dg__dynarr_md* md, size_t itemsize)
|
||||
{
|
||||
// only do this if we allocated the memory ourselves
|
||||
if(!(md->cap & DG__DYNARR_SIZE_T_MSB))
|
||||
{
|
||||
size_t cnt = md->cnt;
|
||||
if(cnt == 0) dg__dynarr_free(arr, md);
|
||||
else if((md->cap & DG__DYNARR_SIZE_T_ALL_BUT_MSB) > cnt)
|
||||
{
|
||||
void* p = DG_DYNARR_MALLOC(itemsize, cnt);
|
||||
if(p != NULL)
|
||||
{
|
||||
memcpy(p, *arr, cnt*itemsize);
|
||||
md->cap = cnt;
|
||||
DG_DYNARR_FREE(*arr);
|
||||
*arr = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // DG_DYNARR_IMPLEMENTATION
|
2453
src/client/refresh/gl4/header/HandmadeMath.h
Normal file
2453
src/client/refresh/gl4/header/HandmadeMath.h
Normal file
File diff suppressed because it is too large
Load diff
562
src/client/refresh/gl4/header/local.h
Normal file
562
src/client/refresh/gl4/header/local.h
Normal file
|
@ -0,0 +1,562 @@
|
|||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
* Copyright (C) 2016-2017 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.
|
||||
*
|
||||
* =======================================================================
|
||||
*
|
||||
* Local header for the OpenGL4 refresher.
|
||||
*
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SRC_CLIENT_REFRESH_GL4_HEADER_LOCAL_H_
|
||||
#define SRC_CLIENT_REFRESH_GL4_HEADER_LOCAL_H_
|
||||
|
||||
#ifdef IN_IDE_PARSER
|
||||
// this is just a hack to get proper auto-completion in IDEs:
|
||||
// using system headers for their parsers/indexers but glad for real build
|
||||
// (in glad glFoo is just a #define to glad_glFoo or sth, which screws up autocompletion)
|
||||
// (you may have to configure your IDE to #define IN_IDE_PARSER, but not for building!)
|
||||
#ifdef YQ2_GL3_GLES3
|
||||
#include <GLES3/gl32.h>
|
||||
#else // desktop GL4
|
||||
#define GL_GLEXT_PROTOTYPES 1
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glext.h>
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#ifdef YQ2_GL3_GLES3
|
||||
#include "../glad-gles3/include/glad/glad.h"
|
||||
// yes, this is a bit hacky, but it works :-P
|
||||
#define glDepthRange glDepthRangef
|
||||
#else // desktop GL4
|
||||
#include "../glad/include/glad/glad.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include "../../ref_shared.h"
|
||||
|
||||
#include "HandmadeMath.h"
|
||||
|
||||
#if 0 // only use this for development ..
|
||||
#define STUB_ONCE(msg) do { \
|
||||
static int show=1; \
|
||||
if(show) { \
|
||||
show = 0; \
|
||||
R_Printf(PRINT_ALL, "STUB: %s() %s\n", __FUNCTION__, msg); \
|
||||
} \
|
||||
} while(0);
|
||||
#else // .. so make this a no-op in released code
|
||||
#define STUB_ONCE(msg)
|
||||
#endif
|
||||
|
||||
// a wrapper around glVertexAttribPointer() to stay sane
|
||||
// (caller doesn't have to cast to GLintptr and then void*)
|
||||
static inline void
|
||||
qglVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset)
|
||||
{
|
||||
glVertexAttribPointer(index, size, type, normalized, stride, (const void*)offset);
|
||||
}
|
||||
|
||||
static inline void
|
||||
qglVertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset)
|
||||
{
|
||||
glVertexAttribIPointer(index, size, type, stride, (void*)offset);
|
||||
}
|
||||
|
||||
// attribute locations for vertex shaders
|
||||
enum {
|
||||
GL4_ATTRIB_POSITION = 0,
|
||||
GL4_ATTRIB_TEXCOORD = 1, // for normal texture
|
||||
GL4_ATTRIB_LMTEXCOORD = 2, // for lightmap
|
||||
GL4_ATTRIB_COLOR = 3, // per-vertex color
|
||||
GL4_ATTRIB_NORMAL = 4, // vertex normal
|
||||
GL4_ATTRIB_LIGHTFLAGS = 5 // uint, each set bit means "dyn light i affects this surface"
|
||||
};
|
||||
|
||||
// always using RGBA now, GLES3 on RPi4 doesn't work otherwise
|
||||
// and I think all modern GPUs prefer 4byte pixels over 3bytes
|
||||
static const int gl4_solid_format = GL_RGBA;
|
||||
static const int gl4_alpha_format = GL_RGBA;
|
||||
static const int gl4_tex_solid_format = GL_RGBA;
|
||||
static const int gl4_tex_alpha_format = GL_RGBA;
|
||||
|
||||
extern unsigned gl4_rawpalette[256];
|
||||
extern unsigned d_8to24table[256];
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *renderer_string;
|
||||
const char *vendor_string;
|
||||
const char *version_string;
|
||||
const char *glsl_version_string;
|
||||
|
||||
int major_version;
|
||||
int minor_version;
|
||||
|
||||
// ----
|
||||
|
||||
qboolean anisotropic; // is GL_EXT_texture_filter_anisotropic supported?
|
||||
qboolean debug_output; // is GL_ARB_debug_output supported?
|
||||
qboolean stencil; // Do we have a stencil buffer?
|
||||
|
||||
qboolean useBigVBO; // workaround for AMDs windows driver for fewer calls to glBufferData()
|
||||
|
||||
// ----
|
||||
|
||||
float max_anisotropy;
|
||||
} gl4config_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GLuint shaderProgram;
|
||||
GLint uniVblend;
|
||||
GLint uniLmScalesOrTime; // for 3D it's lmScales, for 2D underwater PP it's time
|
||||
hmm_vec4 lmScales[4];
|
||||
} gl4ShaderInfo_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GLfloat gamma;
|
||||
GLfloat intensity;
|
||||
GLfloat intensity2D; // for HUD, menus etc
|
||||
|
||||
// entries of std430 UBOs are aligned to multiples of their own size
|
||||
// so we'll need to pad accordingly for following vec4
|
||||
GLfloat _padding;
|
||||
|
||||
hmm_vec4 color;
|
||||
} gl4UniCommon_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
hmm_mat4 transMat4;
|
||||
} gl4Uni2D_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
hmm_mat4 transProjViewMat4; // gl4state.projMat3D * gl4state.viewMat3D - so we don't have to do this in the shader
|
||||
hmm_mat4 transModelMat4;
|
||||
|
||||
GLfloat scroll; // for SURF_FLOWING
|
||||
GLfloat time; // for warping surfaces like water & possibly other things
|
||||
GLfloat alpha; // for translucent surfaces (water, glass, ..)
|
||||
GLfloat overbrightbits; // gl4_overbrightbits, applied to lightmaps (and elsewhere to models)
|
||||
GLfloat particleFadeFactor; // gl4_particle_fade_factor, higher => less fading out towards edges
|
||||
|
||||
GLfloat lightScaleForTurb; // surfaces with SURF_DRAWTURB (water, lava) don't have lightmaps, use this instead
|
||||
GLfloat _padding[2]; // again, some padding to ensure this has right size
|
||||
} gl4Uni3D_t;
|
||||
|
||||
extern const hmm_mat4 gl4_identityMat4;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vec3_t origin;
|
||||
GLfloat _padding;
|
||||
vec3_t color;
|
||||
GLfloat intensity;
|
||||
} gl4UniDynLight;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gl4UniDynLight dynLights[MAX_DLIGHTS];
|
||||
GLuint numDynLights;
|
||||
GLfloat _padding[3];
|
||||
} gl4UniLights_t;
|
||||
|
||||
enum {
|
||||
// width and height used to be 128, so now we should be able to get the same lightmap data
|
||||
// that used 32 lightmaps before into one, so 4 lightmaps should be enough
|
||||
BLOCK_WIDTH = 1024,
|
||||
BLOCK_HEIGHT = 512,
|
||||
LIGHTMAP_BYTES = 4,
|
||||
MAX_LIGHTMAPS = 4,
|
||||
MAX_LIGHTMAPS_PER_SURFACE = MAXLIGHTMAPS // 4
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// TODO: what of this do we need?
|
||||
qboolean fullscreen;
|
||||
|
||||
int prev_mode;
|
||||
|
||||
// each lightmap consists of 4 sub-lightmaps allowing changing shadows on the same surface
|
||||
// used for switching on/off light and stuff like that.
|
||||
// most surfaces only have one really and the remaining for are filled with dummy data
|
||||
GLuint lightmap_textureIDs[MAX_LIGHTMAPS][MAX_LIGHTMAPS_PER_SURFACE]; // instead of lightmap_textures+i use lightmap_textureIDs[i]
|
||||
|
||||
GLuint currenttexture; // bound to GL_TEXTURE0
|
||||
int currentlightmap; // lightmap_textureIDs[currentlightmap] bound to GL_TEXTURE1
|
||||
GLuint currenttmu; // GL_TEXTURE0 or GL_TEXTURE1
|
||||
|
||||
// FBO for postprocess effects (like under-water-warping)
|
||||
GLuint ppFBO;
|
||||
GLuint ppFBtex; // ppFBO's texture for color buffer
|
||||
int ppFBtexWidth, ppFBtexHeight;
|
||||
GLuint ppFBrbo; // ppFBO's renderbuffer object for depth and stencil buffer
|
||||
qboolean ppFBObound; // is it currently bound (rendered to)?
|
||||
|
||||
//float camera_separation;
|
||||
//enum stereo_modes stereo_mode;
|
||||
|
||||
GLuint currentVAO;
|
||||
GLuint currentVBO;
|
||||
GLuint currentEBO;
|
||||
GLuint currentShaderProgram;
|
||||
GLuint currentUBO;
|
||||
|
||||
// NOTE: make sure si2D is always the first shaderInfo (or adapt GL4_ShutdownShaders())
|
||||
gl4ShaderInfo_t si2D; // shader for rendering 2D with textures
|
||||
gl4ShaderInfo_t si2Dcolor; // shader for rendering 2D with flat colors
|
||||
gl4ShaderInfo_t si2DpostProcess; // shader to render postprocess FBO, when *not* underwater
|
||||
gl4ShaderInfo_t si2DpostProcessWater; // shader to apply water-warp postprocess effect
|
||||
|
||||
gl4ShaderInfo_t si3Dlm; // a regular opaque face (e.g. from brush) with lightmap
|
||||
// TODO: lm-only variants for gl_lightmap 1
|
||||
gl4ShaderInfo_t si3Dtrans; // transparent is always w/o lightmap
|
||||
gl4ShaderInfo_t si3DcolorOnly; // used for beams - no lightmaps
|
||||
gl4ShaderInfo_t si3Dturb; // for water etc - always without lightmap
|
||||
gl4ShaderInfo_t si3DlmFlow; // for flowing/scrolling things with lightmap (conveyor, ..?)
|
||||
gl4ShaderInfo_t si3DtransFlow; // for transparent flowing/scrolling things (=> no lightmap)
|
||||
gl4ShaderInfo_t si3Dsky; // guess what..
|
||||
gl4ShaderInfo_t si3Dsprite; // for sprites
|
||||
gl4ShaderInfo_t si3DspriteAlpha; // for sprites with alpha-testing
|
||||
|
||||
gl4ShaderInfo_t si3Dalias; // for models
|
||||
gl4ShaderInfo_t si3DaliasColor; // for models w/ flat colors
|
||||
|
||||
// NOTE: make sure siParticle is always the last shaderInfo (or adapt GL4_ShutdownShaders())
|
||||
gl4ShaderInfo_t siParticle; // for particles. surprising, right?
|
||||
|
||||
GLuint vao3D, vbo3D; // for brushes etc, using 10 floats and one uint as vertex input (x,y,z, s,t, lms,lmt, normX,normY,normZ ; lightFlags)
|
||||
|
||||
// the next two are for gl4config.useBigVBO == true
|
||||
int vbo3Dsize;
|
||||
int vbo3DcurOffset;
|
||||
|
||||
GLuint vaoAlias, vboAlias, eboAlias; // for models, using 9 floats as (x,y,z, s,t, r,g,b,a)
|
||||
GLuint vaoParticle, vboParticle; // for particles, using 9 floats (x,y,z, size,distance, r,g,b,a)
|
||||
|
||||
// UBOs and their data
|
||||
gl4UniCommon_t uniCommonData;
|
||||
gl4Uni2D_t uni2DData;
|
||||
gl4Uni3D_t uni3DData;
|
||||
gl4UniLights_t uniLightsData;
|
||||
GLuint uniCommonUBO;
|
||||
GLuint uni2DUBO;
|
||||
GLuint uni3DUBO;
|
||||
GLuint uniLightsUBO;
|
||||
|
||||
hmm_mat4 projMat3D;
|
||||
hmm_mat4 viewMat3D;
|
||||
} gl4state_t;
|
||||
|
||||
extern gl4config_t gl4config;
|
||||
extern gl4state_t gl4state;
|
||||
|
||||
extern viddef_t vid;
|
||||
|
||||
extern refdef_t gl4_newrefdef;
|
||||
|
||||
extern int gl4_visframecount; /* bumped when going to a new PVS */
|
||||
extern int gl4_framecount; /* used for dlight push checking */
|
||||
|
||||
extern int gl4_viewcluster, gl4_viewcluster2, gl4_oldviewcluster, gl4_oldviewcluster2;
|
||||
|
||||
extern int c_brush_polys, c_alias_polys;
|
||||
|
||||
extern qboolean IsHighDPIaware;
|
||||
|
||||
/* NOTE: struct image_s* is what re.RegisterSkin() etc return so no gl4image_s!
|
||||
* (I think the client only passes the pointer around and doesn't know the
|
||||
* definition of this struct, so this being different from struct image_s
|
||||
* in ref_gl should be ok)
|
||||
*/
|
||||
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 */
|
||||
GLuint texnum; /* gl texture binding */
|
||||
float sl, tl, sh, th; /* 0,0 - 1,1 unless part of the scrap */
|
||||
// qboolean scrap; // currently unused
|
||||
qboolean has_alpha;
|
||||
qboolean is_lava; // DG: added for lava brightness hack
|
||||
|
||||
} gl4image_t;
|
||||
|
||||
enum {MAX_GL4TEXTURES = 1024};
|
||||
|
||||
// include this down here so it can use gl4image_t
|
||||
#include "model.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int internal_format;
|
||||
int current_lightmap_texture; // index into gl4state.lightmap_textureIDs[]
|
||||
|
||||
//msurface_t *lightmap_surfaces[MAX_LIGHTMAPS]; - no more lightmap chains, lightmaps are rendered multitextured
|
||||
|
||||
int allocated[BLOCK_WIDTH];
|
||||
|
||||
/* the lightmap texture data needs to be kept in
|
||||
main memory so texsubimage can update properly */
|
||||
byte lightmap_buffers[MAX_LIGHTMAPS_PER_SURFACE][4 * BLOCK_WIDTH * BLOCK_HEIGHT];
|
||||
} gl4lightmapstate_t;
|
||||
|
||||
extern gl4model_t *gl4_worldmodel;
|
||||
|
||||
extern float gl4depthmin, gl4depthmax;
|
||||
|
||||
extern cplane_t frustum[4];
|
||||
|
||||
extern vec3_t gl4_origin;
|
||||
|
||||
extern gl4image_t *gl4_notexture; /* use for bad textures */
|
||||
extern gl4image_t *gl4_particletexture; /* little dot for particles */
|
||||
|
||||
extern int gl_filter_min;
|
||||
extern int gl_filter_max;
|
||||
|
||||
static inline void
|
||||
GL4_UseProgram(GLuint shaderProgram)
|
||||
{
|
||||
if(shaderProgram != gl4state.currentShaderProgram)
|
||||
{
|
||||
gl4state.currentShaderProgram = shaderProgram;
|
||||
glUseProgram(shaderProgram);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
GL4_BindVAO(GLuint vao)
|
||||
{
|
||||
if(vao != gl4state.currentVAO)
|
||||
{
|
||||
gl4state.currentVAO = vao;
|
||||
glBindVertexArray(vao);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
GL4_BindVBO(GLuint vbo)
|
||||
{
|
||||
if(vbo != gl4state.currentVBO)
|
||||
{
|
||||
gl4state.currentVBO = vbo;
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
GL4_BindEBO(GLuint ebo)
|
||||
{
|
||||
if(ebo != gl4state.currentEBO)
|
||||
{
|
||||
gl4state.currentEBO = ebo;
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
||||
}
|
||||
}
|
||||
|
||||
extern void GL4_BufferAndDraw3D(const gl4_3D_vtx_t* verts, int numVerts, GLenum drawMode);
|
||||
|
||||
extern void GL4_RotateForEntity(entity_t *e);
|
||||
|
||||
// gl4_sdl.c
|
||||
extern int GL4_InitContext(void* win);
|
||||
extern void GL4_GetDrawableSize(int* width, int* height);
|
||||
extern int GL4_PrepareForWindow(void);
|
||||
extern qboolean GL4_IsVsyncActive(void);
|
||||
extern void GL4_EndFrame(void);
|
||||
extern void GL4_SetVsync(void);
|
||||
extern void GL4_ShutdownContext(void);
|
||||
|
||||
// gl4_misc.c
|
||||
extern void GL4_InitParticleTexture(void);
|
||||
extern void GL4_ScreenShot(void);
|
||||
extern void GL4_SetDefaultState(void);
|
||||
|
||||
// gl4_model.c
|
||||
extern int registration_sequence;
|
||||
extern void GL4_Mod_Init(void);
|
||||
extern void GL4_Mod_FreeAll(void);
|
||||
extern void GL4_BeginRegistration(char *model);
|
||||
extern struct model_s * GL4_RegisterModel(char *name);
|
||||
extern void GL4_EndRegistration(void);
|
||||
extern void GL4_Mod_Modellist_f(void);
|
||||
extern const byte* GL4_Mod_ClusterPVS(int cluster, const gl4model_t *model);
|
||||
|
||||
// gl4_draw.c
|
||||
extern void GL4_Draw_InitLocal(void);
|
||||
extern void GL4_Draw_ShutdownLocal(void);
|
||||
extern gl4image_t * GL4_Draw_FindPic(char *name);
|
||||
extern void GL4_Draw_GetPicSize(int *w, int *h, char *pic);
|
||||
|
||||
extern void GL4_Draw_PicScaled(int x, int y, char *pic, float factor);
|
||||
extern void GL4_Draw_StretchPic(int x, int y, int w, int h, char *pic);
|
||||
extern void GL4_Draw_CharScaled(int x, int y, int num, float scale);
|
||||
extern void GL4_Draw_TileClear(int x, int y, int w, int h, char *pic);
|
||||
extern void GL4_DrawFrameBufferObject(int x, int y, int w, int h, GLuint fboTexture, const float v_blend[4]);
|
||||
extern void GL4_Draw_Fill(int x, int y, int w, int h, int c);
|
||||
extern void GL4_Draw_FadeScreen(void);
|
||||
extern void GL4_Draw_Flash(const float color[4], float x, float y, float w, float h);
|
||||
extern void GL4_Draw_StretchRaw(int x, int y, int w, int h, int cols, int rows, const byte *data, int bits);
|
||||
|
||||
// gl4_image.c
|
||||
|
||||
static inline void
|
||||
GL4_SelectTMU(GLenum tmu)
|
||||
{
|
||||
if(gl4state.currenttmu != tmu)
|
||||
{
|
||||
glActiveTexture(tmu);
|
||||
gl4state.currenttmu = tmu;
|
||||
}
|
||||
}
|
||||
|
||||
extern void GL4_TextureMode(char *string);
|
||||
extern void GL4_Bind(GLuint texnum);
|
||||
extern void GL4_BindLightmap(int lightmapnum);
|
||||
extern gl4image_t *GL4_LoadPic(char *name, byte *pic, int width, int realwidth,
|
||||
int height, int realheight, size_t data_size,
|
||||
imagetype_t type, int bits);
|
||||
extern gl4image_t *GL4_FindImage(const char *name, imagetype_t type);
|
||||
extern gl4image_t *GL4_RegisterSkin(char *name);
|
||||
extern void GL4_ShutdownImages(void);
|
||||
extern void GL4_FreeUnusedImages(void);
|
||||
extern qboolean GL4_ImageHasFreeSpace(void);
|
||||
extern void GL4_ImageList_f(void);
|
||||
|
||||
// gl4_light.c
|
||||
extern int r_dlightframecount;
|
||||
extern void GL4_MarkSurfaceLights(dlight_t *light, int bit, mnode_t *node,
|
||||
int r_dlightframecount);
|
||||
extern void GL4_PushDlights(void);
|
||||
extern void GL4_LightPoint(entity_t *currententity, vec3_t p, vec3_t color);
|
||||
extern void GL4_BuildLightMap(msurface_t *surf, int offsetInLMbuf, int stride);
|
||||
|
||||
// gl4_lightmap.c
|
||||
#define GL_LIGHTMAP_FORMAT GL_RGBA
|
||||
|
||||
extern void GL4_LM_InitBlock(void);
|
||||
extern void GL4_LM_UploadBlock(void);
|
||||
extern qboolean GL4_LM_AllocBlock(int w, int h, int *x, int *y);
|
||||
extern void GL4_LM_BuildPolygonFromSurface(gl4model_t *currentmodel, msurface_t *fa);
|
||||
extern void GL4_LM_CreateSurfaceLightmap(msurface_t *surf);
|
||||
extern void GL4_LM_BeginBuildingLightmaps(gl4model_t *m);
|
||||
extern void GL4_LM_EndBuildingLightmaps(void);
|
||||
|
||||
// gl4_warp.c
|
||||
extern void GL4_EmitWaterPolys(msurface_t *fa);
|
||||
extern void GL4_SubdivideSurface(msurface_t *fa, gl4model_t* loadmodel);
|
||||
|
||||
extern void GL4_SetSky(char *name, float rotate, vec3_t axis);
|
||||
extern void GL4_DrawSkyBox(void);
|
||||
extern void GL4_ClearSkyBox(void);
|
||||
extern void GL4_AddSkySurface(msurface_t *fa);
|
||||
|
||||
|
||||
// gl4_surf.c
|
||||
extern void GL4_SurfInit(void);
|
||||
extern void GL4_SurfShutdown(void);
|
||||
extern void GL4_DrawGLPoly(msurface_t *fa);
|
||||
extern void GL4_DrawGLFlowingPoly(msurface_t *fa);
|
||||
extern void GL4_DrawTriangleOutlines(void);
|
||||
extern void GL4_DrawAlphaSurfaces(void);
|
||||
extern void GL4_DrawBrushModel(entity_t *e, gl4model_t *currentmodel);
|
||||
extern void GL4_DrawWorld(void);
|
||||
extern void GL4_MarkLeaves(void);
|
||||
|
||||
// gl4_mesh.c
|
||||
extern void GL4_DrawAliasModel(entity_t *e);
|
||||
extern void GL4_ResetShadowAliasModels(void);
|
||||
extern void GL4_DrawAliasShadows(void);
|
||||
extern void GL4_ShutdownMeshes(void);
|
||||
|
||||
// gl4_shaders.c
|
||||
|
||||
extern qboolean GL4_RecreateShaders(void);
|
||||
extern qboolean GL4_InitShaders(void);
|
||||
extern void GL4_ShutdownShaders(void);
|
||||
extern void GL4_UpdateUBOCommon(void);
|
||||
extern void GL4_UpdateUBO2D(void);
|
||||
extern void GL4_UpdateUBO3D(void);
|
||||
extern void GL4_UpdateUBOLights(void);
|
||||
|
||||
// ############ Cvars ###########
|
||||
|
||||
extern cvar_t *gl_msaa_samples;
|
||||
extern cvar_t *r_vsync;
|
||||
extern cvar_t *r_retexturing;
|
||||
extern cvar_t *r_scale8bittextures;
|
||||
extern cvar_t *vid_fullscreen;
|
||||
extern cvar_t *r_mode;
|
||||
extern cvar_t *r_customwidth;
|
||||
extern cvar_t *r_customheight;
|
||||
|
||||
extern cvar_t *r_2D_unfiltered;
|
||||
extern cvar_t *r_videos_unfiltered;
|
||||
extern cvar_t *gl_nolerp_list;
|
||||
extern cvar_t *r_lerp_list;
|
||||
extern cvar_t *gl_nobind;
|
||||
extern cvar_t *r_lockpvs;
|
||||
extern cvar_t *r_novis;
|
||||
|
||||
extern cvar_t *r_cull;
|
||||
extern cvar_t *gl_zfix;
|
||||
extern cvar_t *r_fullbright;
|
||||
|
||||
extern cvar_t *r_norefresh;
|
||||
extern cvar_t *gl_lefthand;
|
||||
extern cvar_t *r_gunfov;
|
||||
extern cvar_t *r_farsee;
|
||||
extern cvar_t *r_drawworld;
|
||||
|
||||
extern cvar_t *vid_gamma;
|
||||
extern cvar_t *gl4_intensity;
|
||||
extern cvar_t *gl4_intensity_2D;
|
||||
extern cvar_t *gl_anisotropic;
|
||||
extern cvar_t *gl_texturemode;
|
||||
|
||||
extern cvar_t *r_lightlevel;
|
||||
extern cvar_t *gl4_overbrightbits;
|
||||
extern cvar_t *gl4_particle_fade_factor;
|
||||
extern cvar_t *gl4_particle_square;
|
||||
extern cvar_t *gl4_colorlight;
|
||||
extern cvar_t *gl_polyblend;
|
||||
|
||||
extern cvar_t *r_modulate;
|
||||
extern cvar_t *gl_lightmap;
|
||||
extern cvar_t *gl_shadows;
|
||||
extern cvar_t *r_fixsurfsky;
|
||||
extern cvar_t *r_palettedtexture;
|
||||
extern cvar_t *r_validation;
|
||||
|
||||
extern cvar_t *gl4_debugcontext;
|
||||
|
||||
#endif /* SRC_CLIENT_REFRESH_GL4_HEADER_LOCAL_H_ */
|
163
src/client/refresh/gl4/header/model.h
Normal file
163
src/client/refresh/gl4/header/model.h
Normal file
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* 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 for the model stuff.
|
||||
*
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
#ifndef SRC_CLIENT_REFRESH_GL4_HEADER_MODEL_H_
|
||||
#define SRC_CLIENT_REFRESH_GL4_HEADER_MODEL_H_
|
||||
|
||||
// used for vertex array elements when drawing brushes, sprites, sky and more
|
||||
// (ok, it has the layout used for rendering brushes, but is not used there)
|
||||
typedef struct gl4_3D_vtx_s {
|
||||
vec3_t pos;
|
||||
float texCoord[2];
|
||||
float lmTexCoord[2]; // lightmap texture coordinate (sometimes unused)
|
||||
vec3_t normal;
|
||||
GLuint lightFlags; // bit i set means: dynlight i affects surface
|
||||
} gl4_3D_vtx_t;
|
||||
|
||||
// used for vertex array elements when drawing models
|
||||
typedef struct gl4_alias_vtx_s {
|
||||
GLfloat pos[3];
|
||||
GLfloat texCoord[2];
|
||||
GLfloat color[4];
|
||||
} gl4_alias_vtx_t;
|
||||
|
||||
/* in memory representation */
|
||||
|
||||
typedef struct glpoly_s
|
||||
{
|
||||
struct glpoly_s *next;
|
||||
struct glpoly_s *chain;
|
||||
int numverts;
|
||||
int flags; /* for SURF_UNDERWATER (not needed anymore?) */
|
||||
gl4_3D_vtx_t vertices[4]; /* variable sized */
|
||||
} glpoly_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 */
|
||||
|
||||
glpoly_t *polys; /* multiple if warped */
|
||||
struct msurface_s *texturechain;
|
||||
// struct msurface_s *lightmapchain; not used/needed anymore
|
||||
|
||||
mtexinfo_t *texinfo;
|
||||
|
||||
/* lighting info */
|
||||
int dlightframe;
|
||||
int dlightbits;
|
||||
|
||||
int lightmaptexturenum;
|
||||
byte styles[MAXLIGHTMAPS]; // MAXLIGHTMAPS = MAX_LIGHTMAPS_PER_SURFACE (defined in local.h)
|
||||
// I think cached_light is not used/needed anymore
|
||||
//float cached_light[MAXLIGHTMAPS]; /* values currently used in lightmap */
|
||||
byte *samples; /* [numstyles*surfsize] */
|
||||
} msurface_t;
|
||||
|
||||
/* Whole model */
|
||||
|
||||
// this, must be struct model_s, not gl4model_s,
|
||||
// because struct model_s* is returned by re.RegisterModel()
|
||||
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 */
|
||||
gl4image_t *skins[MAX_MD2SKINS];
|
||||
|
||||
int extradatasize;
|
||||
void *extradata;
|
||||
|
||||
// submodules
|
||||
vec3_t origin; // for sounds or lights
|
||||
} gl4model_t;
|
||||
|
||||
#endif /* SRC_CLIENT_REFRESH_GL4_HEADER_MODEL_H_ */
|
226
src/client/refresh/ref_shared.h
Normal file
226
src/client/refresh/ref_shared.h
Normal file
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* 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 "../vid/header/ref.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
#define YQ2_VLA(TYPE, VARNAME, NUMELEMS) \
|
||||
TYPE * VARNAME = (TYPE *) _malloca(sizeof(TYPE) * NUMELEMS)
|
||||
#define YQ2_VLAFREE(VARNAME) \
|
||||
_freea(VARNAME); VARNAME=NULL;
|
||||
|
||||
#else // other compilers hopefully support C99 VLAs (gcc/mingw and clang do)
|
||||
|
||||
#define YQ2_VLA(TYPE, VARNAME, NUMELEMS) \
|
||||
TYPE VARNAME[NUMELEMS]
|
||||
#define YQ2_VLAFREE(VARNAME)
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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, ...) PRINTF_ATTR(2, 3);
|
||||
|
||||
/* Shared images load */
|
||||
typedef struct image_s* (*loadimage_t)(const char *name, byte *pic, int width, int realwidth,
|
||||
int height, int realheight, size_t data_size, imagetype_t type, int bits);
|
||||
extern struct image_s* LoadWal(const char *origname, imagetype_t type, loadimage_t load_image);
|
||||
extern struct image_s* LoadM8(const char *origname, imagetype_t type, loadimage_t load_image);
|
||||
extern struct image_s* LoadM32(const char *origname, imagetype_t type, loadimage_t load_image);
|
||||
extern void FixFileExt(const char *origname, const char *ext, char *filename, size_t size);
|
||||
extern void GetPCXPalette(byte **colormap, unsigned *d_8to24table);
|
||||
extern void LoadPCX(const char *origname, byte **pic, byte **palette, int *width, int *height);
|
||||
extern void GetPCXInfo(const char *origname, int *width, int *height);
|
||||
extern void GetWalInfo(const char *name, int *width, int *height);
|
||||
extern void GetM8Info(const char *name, int *width, int *height);
|
||||
extern void GetM32Info(const char *name, int *width, int *height);
|
||||
|
||||
extern qboolean ResizeSTB(const 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(const byte *src, byte *dst, int width, int height);
|
||||
extern void scale3x(const byte *src, byte *dst, int width, int height);
|
||||
|
||||
extern float Mod_RadiusFromBounds(const vec3_t mins, const vec3_t maxs);
|
||||
extern const byte* Mod_DecompressVis(const byte *in, int row);
|
||||
|
||||
/* Shared models struct */
|
||||
|
||||
enum {
|
||||
SIDE_FRONT = 0,
|
||||
SIDE_BACK = 1,
|
||||
SIDE_ON = 2
|
||||
};
|
||||
|
||||
// FIXME: differentiate from texinfo SURF_ flags
|
||||
enum {
|
||||
SURF_PLANEBACK = 0x02,
|
||||
SURF_DRAWSKY = 0x04, // sky brush face
|
||||
SURF_DRAWTURB = 0x10,
|
||||
SURF_DRAWBACKGROUND = 0x40,
|
||||
SURF_UNDERWATER = 0x80
|
||||
};
|
||||
|
||||
typedef struct mvertex_s
|
||||
{
|
||||
vec3_t position;
|
||||
} mvertex_t;
|
||||
|
||||
typedef struct medge_s
|
||||
{
|
||||
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 */
|
||||
struct image_s *image;
|
||||
} mtexinfo_t;
|
||||
|
||||
#define CONTENTS_NODE -1
|
||||
typedef struct mnode_s
|
||||
{
|
||||
/* common with leaf */
|
||||
int contents; /* CONTENTS_NODE, 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 leaf */
|
||||
int contents; /* CONTENTS_NODE, to differentiate from leafs */
|
||||
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;
|
||||
|
||||
struct msurface_s **firstmarksurface;
|
||||
int nummarksurfaces;
|
||||
int key; /* BSP sequence number for leaf's contents */
|
||||
} mleaf_t;
|
||||
|
||||
/* Shared models func */
|
||||
typedef struct image_s* (*findimage_t)(const char *name, imagetype_t type);
|
||||
extern void *Mod_LoadMD2 (const char *mod_name, const void *buffer, int modfilelen,
|
||||
vec3_t mins, vec3_t maxs, struct image_s **skins,
|
||||
findimage_t find_image, modtype_t *type);
|
||||
extern void *Mod_LoadSP2 (const char *mod_name, const void *buffer, int modfilelen,
|
||||
struct image_s **skins, findimage_t find_image, modtype_t *type);
|
||||
extern int Mod_ReLoadSkins(struct image_s **skins, findimage_t find_image,
|
||||
void *extradata, modtype_t type);
|
||||
extern struct image_s *GetSkyImage(const char *skyname, const char* surfname,
|
||||
qboolean palettedtexture, findimage_t find_image);
|
||||
extern struct image_s *GetTexImage(const char *name, findimage_t find_image);
|
||||
extern struct image_s *R_FindPic(const char *name, findimage_t find_image);
|
||||
extern struct image_s* R_LoadImage(const char *name, const char* namewe, const char *ext,
|
||||
imagetype_t type, qboolean r_retexturing, loadimage_t load_image);
|
||||
extern void Mod_LoadNodes(const char *name, cplane_t *planes, int numplanes,
|
||||
mleaf_t *leafs, int numleafs, mnode_t **nodes, int *numnodes,
|
||||
const byte *mod_base, const lump_t *l);
|
||||
extern void Mod_LoadVertexes(const char *name, mvertex_t **vertexes, int *numvertexes,
|
||||
const byte *mod_base, const lump_t *l, int extra);
|
||||
extern void Mod_LoadVisibility(dvis_t **vis, const byte *mod_base, const lump_t *l);
|
||||
extern void Mod_LoadLighting(byte **lightdata, const byte *mod_base, const lump_t *l);
|
||||
extern void Mod_LoadTexinfo(const char *name, mtexinfo_t **texinfo, int *numtexinfo,
|
||||
const byte *mod_base, const lump_t *l, findimage_t find_image,
|
||||
struct image_s *notexture, int extra);
|
||||
extern void Mod_LoadEdges(const char *name, medge_t **edges, int *numedges,
|
||||
const byte *mod_base, const lump_t *l, int extra);
|
||||
extern void Mod_LoadPlanes (const char *name, cplane_t **planes, int *numplanes,
|
||||
const byte *mod_base, const lump_t *l, int extra);
|
||||
extern void Mod_LoadSurfedges (const char *name, int **surfedges, int *numsurfedges,
|
||||
const byte *mod_base, const lump_t *l, int extra);
|
||||
extern int Mod_CalcLumpHunkSize(const lump_t *l, int inSize, int outSize, int extra);
|
||||
extern mleaf_t *Mod_PointInLeaf(const vec3_t p, mnode_t *node);
|
||||
|
||||
/* Surface logic */
|
||||
#define DLIGHT_CUTOFF 64
|
||||
|
||||
typedef void (*marksurfacelights_t)(dlight_t *light, int bit, mnode_t *node,
|
||||
int r_dlightframecount);
|
||||
extern void R_MarkLights (dlight_t *light, int bit, mnode_t *node, int r_dlightframecount,
|
||||
marksurfacelights_t mark_surface_lights);
|
||||
extern struct image_s *R_TextureAnimation(const entity_t *currententity,
|
||||
const mtexinfo_t *tex);
|
||||
extern qboolean R_AreaVisible(const byte *areabits, mleaf_t *pleaf);
|
||||
extern qboolean R_CullBox(vec3_t mins, vec3_t maxs, cplane_t *frustum);
|
||||
extern void R_SetFrustum(vec3_t vup, vec3_t vpn, vec3_t vright, vec3_t r_origin,
|
||||
float fov_x, float fov_y, cplane_t *frustum);
|
||||
|
||||
#endif /* SRC_CLIENT_REFRESH_REF_SHARED_H_ */
|
292
src/client/vid/header/ref.h
Normal file
292
src/client/vid/header/ref.h
Normal file
|
@ -0,0 +1,292 @@
|
|||
/*
|
||||
* 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/header/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 6
|
||||
#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);
|
||||
|
||||
// called by GLimp_InitGraphics() *after* creating render
|
||||
// context. Returns the actual drawable size in the width
|
||||
// and height variables. This may be differend from the
|
||||
// window size due to high dpi awareness.
|
||||
void (EXPORT *GetDrawableSize)(int* width, int* height);
|
||||
|
||||
// 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 if bits equals to 8).
|
||||
* Note that calls
|
||||
*/
|
||||
void (EXPORT *DrawStretchRaw) (int x, int y, int w, int h, int cols, int rows, const byte *data, int bits);
|
||||
|
||||
/*
|
||||
** 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, ...) PRINTF_ATTR(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, const byte *data, int bits);
|
||||
//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
|
1619
src/client/vid/header/stb_image_write.h
Normal file
1619
src/client/vid/header/stb_image_write.h
Normal file
File diff suppressed because it is too large
Load diff
70
src/client/vid/header/vid.h
Normal file
70
src/client/vid/header/vid.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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/header/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.
|
||||
qboolean VID_HasRenderer(const char *renderer);
|
||||
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
|
871
src/common/header/common.h
Normal file
871
src/common/header/common.h
Normal file
|
@ -0,0 +1,871 @@
|
|||
/*
|
||||
* 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.21pre"
|
||||
#define BASEDIRNAME "baseq2"
|
||||
|
||||
#ifndef YQ2OSTYPE
|
||||
#error YQ2OSTYPE should be defined by the build system
|
||||
#endif
|
||||
|
||||
#ifndef BUILD_DATE
|
||||
#define BUILD_DATE __DATE__
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define CFGDIR "YamagiQ2"
|
||||
#else
|
||||
#ifndef __HAIKU__
|
||||
#define CFGDIR ".yq2"
|
||||
#else
|
||||
#define CFGDIR "yq2"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef YQ2ARCH
|
||||
#ifdef _MSC_VER
|
||||
// Setting YQ2ARCH for VisualC++ from CMake doesn't work when using VS integrated CMake
|
||||
// so set it in code instead
|
||||
#ifdef YQ2ARCH
|
||||
#undef YQ2ARCH
|
||||
#endif
|
||||
#ifdef _M_X64
|
||||
// this matches AMD64 and ARM64EC (but not regular ARM64), but they're supposed to be binary-compatible somehow, so whatever
|
||||
#define YQ2ARCH "x86_64"
|
||||
#elif defined(_M_ARM64)
|
||||
#define YQ2ARCH "arm64"
|
||||
#elif defined(_M_ARM)
|
||||
#define YQ2ARCH "arm"
|
||||
#elif defined(_M_IX86)
|
||||
#define YQ2ARCH "x86"
|
||||
#else
|
||||
// if you're not targeting one of the aforementioned architectures,
|
||||
// check https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros
|
||||
// to find out how to detect yours and add it here - and please send a patch :)
|
||||
#error "Unknown CPU architecture!"
|
||||
// (for a quick and dirty solution, comment out the previous line, but keep in mind
|
||||
// that savegames may not be compatible with other builds of Yamagi Quake II)
|
||||
#define YQ2ARCH "UNKNOWN"
|
||||
#endif // _M_X64 etc
|
||||
#else // other compilers than MSVC
|
||||
#error YQ2ARCH should be defined by the build system
|
||||
#endif // _MSC_VER
|
||||
#endif // YQ2ARCH
|
||||
|
||||
/* ================================================================== */
|
||||
|
||||
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, /* <see code> */
|
||||
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_Shutdown(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_ShutdownFilesystem(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, ...) PRINTF_ATTR(1, 2);
|
||||
void Com_DPrintf(char *fmt, ...) PRINTF_ATTR(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, ...) PRINTF_ATTR(1, 2);
|
||||
YQ2_ATTR_NORETURN_FUNCPTR void Com_Error(int code, char *fmt, ...) PRINTF_ATTR(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_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);
|
||||
qboolean 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
|
33
src/common/header/crc.h
Normal file
33
src/common/header/crc.h
Normal file
|
@ -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
|
483
src/common/header/files.h
Normal file
483
src/common/header/files.h
Normal file
|
@ -0,0 +1,483 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/* .M32 texture file format */
|
||||
|
||||
#define M32_VERSION 0x4
|
||||
#define M32_MIP_LEVELS 16
|
||||
|
||||
typedef struct m32tex_s
|
||||
{
|
||||
int version;
|
||||
char name[128];
|
||||
char altname[128]; // texture substitution
|
||||
char animname[128]; // next frame in animation chain
|
||||
char damagename[128]; // image that should be shown when damaged
|
||||
unsigned width[M32_MIP_LEVELS], height[M32_MIP_LEVELS];
|
||||
unsigned offsets[M32_MIP_LEVELS];
|
||||
int flags;
|
||||
int contents;
|
||||
int value;
|
||||
float scale_x, scale_y;
|
||||
int mip_scale;
|
||||
|
||||
// detail texturing info
|
||||
char dt_name[128]; // detailed texture name
|
||||
float dt_scale_x, dt_scale_y;
|
||||
float dt_u, dt_v;
|
||||
float dt_alpha;
|
||||
int dt_src_blend_mode, dt_dst_blend_mode;
|
||||
|
||||
int unused[20]; // future expansion to maintain compatibility with h2
|
||||
} m32tex_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
|
||||
|
1229
src/common/header/shared.h
Normal file
1229
src/common/header/shared.h
Normal file
File diff suppressed because it is too large
Load diff
224
src/common/md4.c
Normal file
224
src/common/md4.c
Normal file
|
@ -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 <inttypes.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
1412
src/common/shared/shared.c
Normal file
1412
src/common/shared/shared.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue