Merge remote-tracking branch 'yquake2/master'

This commit is contained in:
Denis Pauk 2024-08-12 18:46:04 +03:00
commit 247acb32fd
26 changed files with 2624 additions and 286 deletions

View file

@ -6,8 +6,9 @@ on:
- 'master' - 'master'
pull_request: pull_request:
types: types:
- opened
- edited - edited
- opened
- synchronize
concurrency: concurrency:
# Cancel concurrent workflows for the same PR or commit hash. # Cancel concurrent workflows for the same PR or commit hash.
group: ${{github.workflow}}-${{github.event_name == 'pull_request' && github.head_ref || github.sha}} group: ${{github.workflow}}-${{github.event_name == 'pull_request' && github.head_ref || github.sha}}

View file

@ -6,8 +6,9 @@ on:
- 'master' - 'master'
pull_request: pull_request:
types: types:
- opened
- edited - edited
- opened
- synchronize
concurrency: concurrency:
# Cancel concurrent workflows for the same PR or commit hash. # Cancel concurrent workflows for the same PR or commit hash.
group: ${{github.workflow}}-${{github.event_name == 'pull_request' && github.head_ref || github.sha}} group: ${{github.workflow}}-${{github.event_name == 'pull_request' && github.head_ref || github.sha}}

View file

@ -8,8 +8,9 @@ on:
- "*" - "*"
pull_request: pull_request:
types: types:
- opened
- edited - edited
- opened
- synchronize
concurrency: concurrency:
# Cancel concurrent workflows for the same PR or commit hash. # Cancel concurrent workflows for the same PR or commit hash.
group: ${{github.workflow}}-${{github.event_name == 'pull_request' && github.head_ref || github.sha}} group: ${{github.workflow}}-${{github.event_name == 'pull_request' && github.head_ref || github.sha}}

View file

@ -602,6 +602,8 @@ set(GL1-Source
${COMMON_SRC_DIR}/md4.c ${COMMON_SRC_DIR}/md4.c
) )
set(Glad-GLES1-Source ${REF_SRC_DIR}/gl1/glad-gles1/src/glad.c)
set(GL1-Header set(GL1-Header
${REF_SRC_DIR}/ref_shared.h ${REF_SRC_DIR}/ref_shared.h
${REF_SRC_DIR}/constants/anorms.h ${REF_SRC_DIR}/constants/anorms.h
@ -615,6 +617,11 @@ set(GL1-Header
${COMMON_SRC_DIR}/header/shared.h ${COMMON_SRC_DIR}/header/shared.h
) )
set(Glad-GLES1-Header
${REF_SRC_DIR}/gl1/glad-gles1/include/glad/glad.h
${REF_SRC_DIR}/gl1/glad-gles1/include/KHR/khrplatform.h
)
set(GL3-Source set(GL3-Source
${REF_SRC_DIR}/gl3/gl3_draw.c ${REF_SRC_DIR}/gl3/gl3_draw.c
${REF_SRC_DIR}/gl3/gl3_image.c ${REF_SRC_DIR}/gl3/gl3_image.c
@ -830,3 +837,24 @@ target_link_libraries(ref_soft ${yquake2LinkerFlags} ${yquake2SDLLinkerFlags})
if(SDL3_SUPPORT) if(SDL3_SUPPORT)
target_link_libraries(ref_soft SDL3::SDL3) target_link_libraries(ref_soft SDL3::SDL3)
endif() endif()
if(FALSE)
# Build the GLES1 dynamic library
add_library(ref_gles1 MODULE ${GL1-Source} ${Glad-GLES1-Source} ${GL1-Header} ${Glad-GLES1-Header} ${REF-Platform-Specific-Source})
set_target_properties(ref_gles1 PROPERTIES
PREFIX ""
#COMPILE_DEFINITIONS "YQ2_GL1_GLES=1"
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release
SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}
)
target_include_directories(ref_gles1 PRIVATE ${CMAKE_SOURCE_DIR}/src/client/refresh/gl1/glad-gles1/include)
target_compile_definitions(ref_gles1 PRIVATE YQ2_GL1_GLES=1)
target_link_libraries(ref_gles1 ${yquake2LinkerFlags} ${yquake2SDLLinkerFlags})
if(SDL3_SUPPORT)
target_link_libraries(ref_gles1 SDL3::SDL3)
endif()
endif()

93
LICENSE
View file

@ -4,9 +4,11 @@ copys of each license:
- Quake II - Quake II
- Info-ZIP - Info-ZIP
- zlib
- Cocoa SDL entry points - Cocoa SDL entry points
- stb_image.h, stb_image_write.h, stb_image_resize.h, stb_vorbis.h - stb_image.h, stb_image_write.h, stb_image_resize.h, stb_vorbis.h
- miniz - miniz
- GLAD
Parts of other Quake II Clients were included into the source. They're Parts of other Quake II Clients were included into the source. They're
covered by the same GPLv2 license as Quake II itself: covered by the same GPLv2 license as Quake II itself:
@ -437,6 +439,31 @@ freely, subject to the above disclaimer and the following restrictions:
=============================================================================== ===============================================================================
Copyright notice:
(C) 1995-2024 Jean-loup Gailly and Mark Adler
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jean-loup Gailly Mark Adler
jloup@gzip.org madler@alumni.caltech.edu
===============================================================================
Main entry point for our Cocoa-ized SDL app Main entry point for our Cocoa-ized SDL app
Initial Version: Darrell Walisser <dwaliss1@purdue.edu> Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
Non-NIB-Code & other changes: Max Horn <max@quendi.de> Non-NIB-Code & other changes: Max Horn <max@quendi.de>
@ -513,3 +540,69 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
=============================================================================== ===============================================================================
The glad source code:
The MIT License (MIT)
Copyright (c) 2013-2022 David Herberth
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.
The Khronos Specifications:
Copyright (c) 2013-2020 The Khronos Group Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
The EGL Specification and various headers:
Copyright (c) 2007-2016 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.
===============================================================================

View file

@ -401,15 +401,20 @@ endif
# ---------- # ----------
# Phony targets # Phony targets
.PHONY : all client game icon server ref_gl1 ref_gl3 ref_gles3 ref_soft ref_vk ref_gl4 .PHONY : all client game icon server ref_gl1 ref_gl3 ref_gles1 ref_gles3 ref_soft ref_vk ref_gl4
# ---------- # ----------
# Builds everything # Builds everything but the GLES1 renderer
all: config client server game ref_gl1 ref_gl3 ref_gles3 ref_soft ref_vk ref_gl4 all: config client server game ref_gl1 ref_gl3 ref_gles3 ref_soft ref_vk ref_gl4
# ---------- # ----------
# Builds everything, including the GLES1 renderer
with_gles1: all ref_gles1
# ----------
# Print config values # Print config values
config: config:
@echo "Build configuration" @echo "Build configuration"
@ -637,6 +642,47 @@ build/ref_gl1/%.o: %.c
# ---------- # ----------
# The OpenGL ES 1.0 renderer lib
ifeq ($(YQ2_OSTYPE), Windows)
ref_gles1:
@echo "===> Building ref_gles1.dll"
$(MAKE) release/ref_gles1.dll
release/ref_gles1.dll : GLAD_INCLUDE = -Isrc/client/refresh/gl1/glad-gles1/include
release/ref_gles1.dll : CFLAGS += -DYQ2_GL1_GLES
release/ref_gles1.dll : LDFLAGS += -shared
else ifeq ($(YQ2_OSTYPE), Darwin)
ref_gles1:
@echo "===> Building ref_gles1.dylib"
$(MAKE) release/ref_gles1.dylib
release/ref_gles1.dylib : GLAD_INCLUDE = -Isrc/client/refresh/gl1/glad-gles1/include
release/ref_gles1.dylib : CFLAGS += -DYQ2_GL1_GLES
release/ref_gles1.dylib : LDFLAGS += -shared
else # not Windows or Darwin
ref_gles1:
@echo "===> Building ref_gles1.so"
$(MAKE) release/ref_gles1.so
release/ref_gles1.so : GLAD_INCLUDE = -Isrc/client/refresh/gl1/glad-gles1/include
release/ref_gles1.so : CFLAGS += -DYQ2_GL1_GLES -fPIC
release/ref_gles1.so : LDFLAGS += -shared
endif # OS specific ref_gles1 stuff
build/ref_gles1/%.o: %.c
@echo "===> CC $<"
${Q}mkdir -p $(@D)
${Q}$(CC) -c $(CFLAGS) $(SDLCFLAGS) $(INCLUDE) $(GLAD_INCLUDE) -o $@ $<
# ----------
# The OpenGL 3.x renderer lib # The OpenGL 3.x renderer lib
ifeq ($(YQ2_OSTYPE), Windows) ifeq ($(YQ2_OSTYPE), Windows)
@ -1111,6 +1157,9 @@ REFGL1_OBJS_ := \
src/common/cmodels.o \ src/common/cmodels.o \
src/common/md4.o src/common/md4.o
REFGL1_OBJS_GLADEES_ := \
src/client/refresh/gl1/glad-gles1/src/glad.o
ifeq ($(YQ2_OSTYPE), Windows) ifeq ($(YQ2_OSTYPE), Windows)
REFGL1_OBJS_ += \ REFGL1_OBJS_ += \
src/backends/windows/shared/hunk.o src/backends/windows/shared/hunk.o
@ -1362,6 +1411,8 @@ endif
# Rewrite paths to our object directory. # Rewrite paths to our object directory.
CLIENT_OBJS = $(patsubst %,build/client/%,$(CLIENT_OBJS_)) CLIENT_OBJS = $(patsubst %,build/client/%,$(CLIENT_OBJS_))
REFGL1_OBJS = $(patsubst %,build/ref_gl1/%,$(REFGL1_OBJS_)) REFGL1_OBJS = $(patsubst %,build/ref_gl1/%,$(REFGL1_OBJS_))
REFGLES1_OBJS = $(patsubst %,build/ref_gles1/%,$(REFGL1_OBJS_))
REFGLES1_OBJS += $(patsubst %,build/ref_gles1/%,$(REFGL1_OBJS_GLADEES_))
REFGL3_OBJS = $(patsubst %,build/ref_gl3/%,$(REFGL3_OBJS_)) REFGL3_OBJS = $(patsubst %,build/ref_gl3/%,$(REFGL3_OBJS_))
REFGL3_OBJS += $(patsubst %,build/ref_gl3/%,$(REFGL3_OBJS_GLADE_)) REFGL3_OBJS += $(patsubst %,build/ref_gl3/%,$(REFGL3_OBJS_GLADE_))
REFGLES3_OBJS = $(patsubst %,build/ref_gles3/%,$(REFGL3_OBJS_)) REFGLES3_OBJS = $(patsubst %,build/ref_gles3/%,$(REFGL3_OBJS_))
@ -1379,6 +1430,7 @@ GAME_OBJS = $(patsubst %,build/baseq2/%,$(GAME_OBJS_))
CLIENT_DEPS= $(CLIENT_OBJS:.o=.d) CLIENT_DEPS= $(CLIENT_OBJS:.o=.d)
GAME_DEPS= $(GAME_OBJS:.o=.d) GAME_DEPS= $(GAME_OBJS:.o=.d)
REFGL1_DEPS= $(REFGL1_OBJS:.o=.d) REFGL1_DEPS= $(REFGL1_OBJS:.o=.d)
REFGLES1_DEPS= $(REFGLES1_OBJS:.o=.d)
REFGL3_DEPS= $(REFGL3_OBJS:.o=.d) REFGL3_DEPS= $(REFGL3_OBJS:.o=.d)
REFGLES3_DEPS= $(REFGLES3_OBJS:.o=.d) REFGLES3_DEPS= $(REFGLES3_OBJS:.o=.d)
REFGL4_DEPS= $(REFGL4_OBJS:.o=.d) REFGL4_DEPS= $(REFGL4_OBJS:.o=.d)
@ -1390,6 +1442,7 @@ SERVER_DEPS= $(SERVER_OBJS:.o=.d)
-include $(CLIENT_DEPS) -include $(CLIENT_DEPS)
-include $(GAME_DEPS) -include $(GAME_DEPS)
-include $(REFGL1_DEPS) -include $(REFGL1_DEPS)
-include $(REFGLES1_DEPS)
-include $(REFGL3_DEPS) -include $(REFGL3_DEPS)
-include $(REFGLES3_DEPS) -include $(REFGLES3_DEPS)
-include $(REFGL4_DEPS) -include $(REFGL4_DEPS)
@ -1441,6 +1494,22 @@ release/ref_gl1.so : $(REFGL1_OBJS)
${Q}$(CC) $(LDFLAGS) $(REFGL1_OBJS) $(LDLIBS) $(SDLLDFLAGS) -o $@ ${Q}$(CC) $(LDFLAGS) $(REFGL1_OBJS) $(LDLIBS) $(SDLLDFLAGS) -o $@
endif endif
# release/ref_gles1.so
ifeq ($(YQ2_OSTYPE), Windows)
release/ref_gles1.dll : $(REFGLES1_OBJS)
@echo "===> LD $@"
${Q}$(CC) $(LDFLAGS) $(REFGLES1_OBJS) $(LDLIBS) $(DLL_SDLLDFLAGS) -o $@
$(Q)strip $@
else ifeq ($(YQ2_OSTYPE), Darwin)
release/ref_gles1.dylib : $(REFGLES1_OBJS)
@echo "===> LD $@"
${Q}$(CC) $(LDFLAGS) $(REFGLES1_OBJS) $(LDLIBS) $(SDLLDFLAGS) -o $@
else
release/ref_gles1.so : $(REFGLES1_OBJS)
@echo "===> LD $@"
${Q}$(CC) $(LDFLAGS) $(REFGLES1_OBJS) $(LDLIBS) $(SDLLDFLAGS) -o $@
endif
# release/ref_gl3.so # release/ref_gl3.so
ifeq ($(YQ2_OSTYPE), Windows) ifeq ($(YQ2_OSTYPE), Windows)
release/ref_gl3.dll : $(REFGL3_OBJS) release/ref_gl3.dll : $(REFGL3_OBJS)

View file

@ -146,27 +146,87 @@ Code tested with such [maps](doc/100_tested_maps.md).
# Yamagi Quake II # Yamagi Quake II
Yamagi Quake II is an enhanced client for id Software's Quake Yamagi Quake II is an enhanced client for id Software's Quake II with
II with focus on offline and coop gameplay. Both the gameplay and the graphics focus on offline and coop gameplay. Both the gameplay and the graphics
are unchanged, but many bugs in the last official release were fixed and some are unchanged, but many bugs in the last official release were fixed and
nice to have features like widescreen support and a modern OpenGL 3.2 renderer some nice to have features like widescreen support, reliable support for
were added. Unlike most other Quake II source ports Yamagi Quake II is fully 64-bit high framerates, a modern sound backend based upon OpenAL, support for
clean. It works perfectly on modern processors and operating systems. Yamagi modern game controllers and a modern OpenGL 3.2 renderer were added.
Quake II runs on nearly all common platforms; including FreeBSD, Linux, NetBSD, Unlike most other Quake II source ports Yamagi Quake II is fully 64-bit
OpenBSD, Windows and macOS (experimental). clean. It works perfectly on modern processors and operating systems.
This code is built upon Icculus Quake II, which itself is based on Quake
II 3.21. Yamagi Quake II is released under the terms of the GPL version
2. See LICENSE for further information:
* [LICENSE](https://github.com/yquake2/yquake2/blob/master/LICENSE)
Officially supported operating systems are:
* FreeBSD
* Linux
* Windows
Beside theses Yamagi Quake II has community support for MacOS and most
other unixoid operating systems, including NetBSD, OpenBSD and Solaris.
## Addons and partner projects
This repository contains Yamagi Quake II itself. The official addons
have their own repositories:
* [The Reckoning](https://github.com/yquake2/xatrix)
* [Ground Zero](https://github.com/yquake2/rogue)
* [Three Waves Capture The Flag](https://github.com/yquake2/ctf)
Yamagi Quake II Remaster is a project providing optional support for the
assets of Quake II Remaster by Nightdive Studios and has a less
conservative approach in regards to new features. It also lives in it's
own repository:
* [Yamagi Quake II Remaster](https://github.com/yquake2/yquake2remaster)
## Development
Yamagi Quake II is a community driven project and lives from community
involvement. Please report bugs in our issue tracker:
* [Issue Tracker](https://github.com/yquake2/yquake2/issues)
We are always open to code contributions, no matter if they are small
bugfixes or bigger features. However, Yamagi Quake II is a conservative
project with big focus on stability and backward compatibility. We don't
accept breaking changes. When in doubt please open an issue and ask if a
contribution in welcome before putting too much work into it. Open a
pull request to submit code:
* [Pull Requests](https://github.com/yquake2/yquake2/pulls)
Also have a look at our contributors guide:
* [Contributors Guide](https://github.com/yquake2/yquake2/blob/master/doc/080_contributing.md).
This code is built upon Icculus Quake II, which itself is based on Quake II
3.21. Yamagi Quake II is released under the terms of the GPL version 2. See the
LICENSE file for further information.
## Documentation ## Documentation
Before asking any question, read through the documentation! The current Yamagi Quake II has rather extensive documentation covering all relevant
version can be found here: [doc/010_index.md](doc/010_index.md) areas from installation and configuration to package building. Have a
look at the documentation index:
* [Documentation Index](https://github.com/yquake2/yquake2/blob/master/doc/010_index.md)
## Releases ## Releases
The official releases (including Windows binaries) can be found at our Yamagi Quake II releases at an irregular schedule. The official releases
homepage: <https://www.yamagi.org/quake2> with source code tarballs and prebuild Windows binaries can be found at
**Unsupported** preview builds for Windows can be found at the homepage:
<https://deponie.yamagi.org/quake2/misc/>
* [Homepage](https://www.yamagi.org/quake2/)
Our CI builds **unsupported** Linux, MacOS and Windows binaries at every
commit. The artifacts can be found here:
* [Github Actions](https://github.com/yquake2/yquake2/actions)

View file

@ -345,6 +345,10 @@ or *gmake* (FreeBSD, NetBSD, OpenBSD). Note on Solaris systems, *make*
After the build finished, copy everything from the *release/* directory After the build finished, copy everything from the *release/* directory
to the Yamagi Quake II installation directory. to the Yamagi Quake II installation directory.
If you want to generate the OpenGL ES 1.0 renderer, which may be the only
graphics API available on some SoCs (like Raspberry Pi 3 or older), type
*make with_gles1*.
For the addons download or clone their source, change into the source For the addons download or clone their source, change into the source
directory and type *make* (Linux, MacOS and Windows) or *gmake* directory and type *make* (Linux, MacOS and Windows) or *gmake*
(FreeBSD, NetBSD, OpenBSD). After the compilation finishes the *release/game.so* (FreeBSD, NetBSD, OpenBSD). After the compilation finishes the *release/game.so*

View file

@ -8,7 +8,7 @@ have been renamed. The prefixes are:
* No prefix: General stuff. * No prefix: General stuff.
* `cl_`: Client. * `cl_`: Client.
* `gl_`: Common to all OpenGL renderers. * `gl_`: Common to all OpenGL renderers.
* `gl1_`: OpenGL 1.4 renderer. * `gl1_`: OpenGL 1.4 and OpenGL ES1 renderers.
* `gl3_`: OpenGL 3.2 and OpenGL ES3 renderers. * `gl3_`: OpenGL 3.2 and OpenGL ES3 renderers.
* `ogg_`: Ogg/Vorbis music playback. * `ogg_`: Ogg/Vorbis music playback.
* `r_`: Common to all renderers. * `r_`: Common to all renderers.
@ -480,6 +480,10 @@ it's `+set busywait 0` (setting the `busywait` cvar) and `-portable`
the overlapping surfaces to mitigate the flickering. This may make the overlapping surfaces to mitigate the flickering. This may make
things better or worse, depending on the map. things better or worse, depending on the map.
* **gl_polyblend**: Toggles the palette blending effect, a.k.a. the
"flash" you see when getting injured or picking up an item. In GL1 is
also used for looking underwater. Default is `1` (enabled).
* **gl_texturemode**: How textures are filtered. * **gl_texturemode**: How textures are filtered.
- `GL_NEAREST`: No filtering (using value of *nearest* source pixel), - `GL_NEAREST`: No filtering (using value of *nearest* source pixel),
mipmaps not used mipmaps not used
@ -499,7 +503,7 @@ it's `+set busywait 0` (setting the `busywait` cvar) and `-portable`
- `3`: render will try to run with OpenGL 3.0, - `3`: render will try to run with OpenGL 3.0,
- `4`: render will try to run with OpenGL 4.0. - `4`: render will try to run with OpenGL 4.0.
## Graphics (OpenGL 1.4 only) ## Graphics (OpenGL 1.4 and OpenGL ES1 only)
* **gl1_intensity**: Sets the color intensity. Must be a floating point * **gl1_intensity**: Sets the color intensity. Must be a floating point
value, at least `1.0` - default is `2.0`. Applied when textures are value, at least `1.0` - default is `2.0`. Applied when textures are
@ -522,6 +526,16 @@ it's `+set busywait 0` (setting the `busywait` cvar) and `-portable`
* **gl1_stencilshadow**: If `gl_shadows` is set to `1`, this makes them * **gl1_stencilshadow**: If `gl_shadows` is set to `1`, this makes them
look a bit better (no flickering) by using the stencil buffer. look a bit better (no flickering) by using the stencil buffer.
* **gl1_lightmapcopies**: When enabled (`1`), keep 3 copies of the same
lightmap rotating, shifting to another one when drawing a new frame.
Meant for mobile/embedded devices, where changing textures just shown
(dynamic lighting) causes slowdown. By default in GL1 is disabled,
while in GLES1 is enabled. Needs `gl1_multitexture 1` & `vid_restart`.
* **gl1_discardfb**: Only available in ES1. If set to `1` (default),
send a hint to discard framebuffers after finishing a frame. Useful
for GPUs that attempt to reuse them, something Quake 2 doesn't do.
## Graphics (OpenGL 3.2 and OpenGL ES3 only) ## Graphics (OpenGL 3.2 and OpenGL ES3 only)

View file

@ -43,7 +43,6 @@ extern cvar_t *vid_renderer;
static cvar_t *r_vsync; static cvar_t *r_vsync;
static cvar_t *gl_anisotropic; static cvar_t *gl_anisotropic;
static cvar_t *gl_msaa_samples; static cvar_t *gl_msaa_samples;
static cvar_t *gl1_colorlight;
static cvar_t *gl3_colorlight; static cvar_t *gl3_colorlight;
static cvar_t *r_dynamic; static cvar_t *r_dynamic;
@ -61,7 +60,6 @@ static menuslider_s s_vk_intensity_slider;
static menuslider_s s_gl1_overbrightbits_slider; static menuslider_s s_gl1_overbrightbits_slider;
static menuslider_s s_gl3_overbrightbits_slider; static menuslider_s s_gl3_overbrightbits_slider;
static menuslider_s s_vk_overbrightbits_slider; static menuslider_s s_vk_overbrightbits_slider;
static menulist_s s_gl1_colorlight_list;
static menulist_s s_gl3_colorlight_list; static menulist_s s_gl3_colorlight_list;
static menulist_s s_r_dynamic_list; static menulist_s s_r_dynamic_list;
static menulist_s s_fs_box; static menulist_s s_fs_box;
@ -74,8 +72,8 @@ static menuaction_s s_apply_action;
// -------- // --------
// gl1, gl3, gles3, gl4, vk, soft // gl1, gl3, gles1, gles3, gl4, vk, soft
#define MAXRENDERERS 6 #define MAXRENDERERS 7
typedef struct typedef struct
{ {
@ -98,6 +96,13 @@ Renderer_FillRenderdef(void)
rendererlist[numrenderer].cvarstr = "gl1"; rendererlist[numrenderer].cvarstr = "gl1";
} }
if (VID_HasRenderer("gles1"))
{
numrenderer++;
rendererlist[numrenderer].boxstr = "[OpenGL ES1]";
rendererlist[numrenderer].cvarstr = "gles1";
}
if (VID_HasRenderer("gl3")) if (VID_HasRenderer("gl3"))
{ {
numrenderer++; numrenderer++;
@ -190,7 +195,7 @@ static void
ApplyFilter(void* unused) ApplyFilter(void* unused)
{ {
if (Q_stricmp(vid_renderer->string, "gl3") == 0 || Q_stricmp(vid_renderer->string, "gles3") == 0 || if (Q_stricmp(vid_renderer->string, "gl3") == 0 || Q_stricmp(vid_renderer->string, "gles3") == 0 ||
Q_stricmp(vid_renderer->string, "gl1") == 0) Q_stricmp(vid_renderer->string, "gl1") == 0 || Q_stricmp(vid_renderer->string, "gles1") == 0)
{ {
if (s_filter_list.curvalue == 0) if (s_filter_list.curvalue == 0)
{ {
@ -303,11 +308,6 @@ ApplyChanges(void *unused)
Cvar_SetValue("gl3_colorlight", s_gl3_colorlight_list.curvalue); Cvar_SetValue("gl3_colorlight", s_gl3_colorlight_list.curvalue);
} }
if (gl1_colorlight && gl1_colorlight->value != s_gl1_colorlight_list.curvalue)
{
Cvar_SetValue("gl1_colorlight", s_gl1_colorlight_list.curvalue);
}
/* anisotropic filtering */ /* anisotropic filtering */
if (s_af_list.curvalue == 0) if (s_af_list.curvalue == 0)
{ {
@ -567,7 +567,6 @@ VID_MenuInit(void)
if (strcmp(vid_renderer->string, "gl3") == 0 || strcmp(vid_renderer->string, "gles3") == 0) if (strcmp(vid_renderer->string, "gl3") == 0 || strcmp(vid_renderer->string, "gles3") == 0)
{ {
gl1_colorlight = NULL;
s_gl3_intensity_slider.generic.type = MTYPE_SLIDER; s_gl3_intensity_slider.generic.type = MTYPE_SLIDER;
s_gl3_intensity_slider.generic.name = "color intensity"; s_gl3_intensity_slider.generic.name = "color intensity";
s_gl3_intensity_slider.generic.x = 0; s_gl3_intensity_slider.generic.x = 0;
@ -640,14 +639,6 @@ VID_MenuInit(void)
s_gl1_overbrightbits_slider.maxvalue = 2; s_gl1_overbrightbits_slider.maxvalue = 2;
s_gl1_overbrightbits_slider.slidestep = 1; s_gl1_overbrightbits_slider.slidestep = 1;
s_gl1_overbrightbits_slider.printformat = "%.0f"; s_gl1_overbrightbits_slider.printformat = "%.0f";
gl1_colorlight = Cvar_Get("gl1_colorlight", "1", CVAR_ARCHIVE);
s_gl1_colorlight_list.generic.type = MTYPE_SPINCONTROL;
s_gl1_colorlight_list.generic.name = "color light";
s_gl1_colorlight_list.generic.x = 0;
s_gl1_colorlight_list.generic.y = (y += 10);
s_gl1_colorlight_list.itemnames = yesno_names;
s_gl1_colorlight_list.curvalue = (gl1_colorlight->value != 0);
} }
s_uiscale_list.generic.type = MTYPE_SPINCONTROL; s_uiscale_list.generic.type = MTYPE_SPINCONTROL;
@ -731,7 +722,7 @@ VID_MenuInit(void)
int mode = 0; int mode = 0;
if (Q_stricmp(vid_renderer->string, "gl3") == 0 || Q_stricmp(vid_renderer->string, "gles3") == 0 || if (Q_stricmp(vid_renderer->string, "gl3") == 0 || Q_stricmp(vid_renderer->string, "gles3") == 0 ||
Q_stricmp(vid_renderer->string, "gl1") == 0) Q_stricmp(vid_renderer->string, "gl1") == 0 || Q_stricmp(vid_renderer->string, "gles1") == 0)
{ {
s_filter_list.generic.x = 0; s_filter_list.generic.x = 0;
s_filter_list.generic.y = (y += 10); s_filter_list.generic.y = (y += 10);
@ -805,11 +796,10 @@ VID_MenuInit(void)
Menu_AddItem(&s_opengl_menu, (void *)&s_vk_overbrightbits_slider); Menu_AddItem(&s_opengl_menu, (void *)&s_vk_overbrightbits_slider);
Menu_AddItem(&s_opengl_menu, (void *)&s_r_dynamic_list); Menu_AddItem(&s_opengl_menu, (void *)&s_r_dynamic_list);
} }
else if (strcmp(vid_renderer->string, "gl1") == 0) else if (strcmp(vid_renderer->string, "gl1") == 0 || strcmp(vid_renderer->string, "gles1") == 0)
{ {
Menu_AddItem(&s_opengl_menu, (void *)&s_gl1_intensity_slider); Menu_AddItem(&s_opengl_menu, (void *)&s_gl1_intensity_slider);
Menu_AddItem(&s_opengl_menu, (void *)&s_gl1_overbrightbits_slider); Menu_AddItem(&s_opengl_menu, (void *)&s_gl1_overbrightbits_slider);
Menu_AddItem(&s_opengl_menu, (void *)&s_gl1_colorlight_list);
} }
Menu_AddItem(&s_opengl_menu, (void *)&s_uiscale_list); Menu_AddItem(&s_opengl_menu, (void *)&s_uiscale_list);
Menu_AddItem(&s_opengl_menu, (void *)&s_fs_box); Menu_AddItem(&s_opengl_menu, (void *)&s_fs_box);
@ -817,7 +807,8 @@ VID_MenuInit(void)
Menu_AddItem(&s_opengl_menu, (void *)&s_af_list); Menu_AddItem(&s_opengl_menu, (void *)&s_af_list);
Menu_AddItem(&s_opengl_menu, (void *)&s_msaa_list); Menu_AddItem(&s_opengl_menu, (void *)&s_msaa_list);
if (Q_stricmp(vid_renderer->string, "gl3") == 0 || Q_stricmp(vid_renderer->string, "gles3") == 0 || if (Q_stricmp(vid_renderer->string, "gl3") == 0 || Q_stricmp(vid_renderer->string, "gles3") == 0 ||
Q_stricmp(vid_renderer->string, "gl1") == 0 || Q_stricmp(vid_renderer->string, "soft") == 0) Q_stricmp(vid_renderer->string, "gl1") == 0 || Q_stricmp(vid_renderer->string, "gles1") == 0 ||
Q_stricmp(vid_renderer->string, "soft") == 0)
{ {
Menu_AddItem(&s_opengl_menu, (void *)&s_filter_list); Menu_AddItem(&s_opengl_menu, (void *)&s_filter_list);
} }

View file

@ -29,33 +29,21 @@
#include "header/local.h" #include "header/local.h"
#define MAX_VERTICES 16384 #define GLBUFFER_RESET vtx_ptr = idx_ptr = 0; gl_buf.vt = gl_buf.tx = gl_buf.cl = 0;
#define MAX_INDICES (MAX_VERTICES * 4)
typedef struct // 832k aprox. glbuffer_t gl_buf; // our drawing buffer, used globally
{ int cur_lm_copy; // which lightmap copy to use (when lightmapcopies=on)
buffered_draw_t type;
GLfloat static GLushort vtx_ptr, idx_ptr; // pointers for array positions in gl_buf
vtx[MAX_VERTICES * 3], // vertexes
tex[MAX_TEXTURE_UNITS][MAX_VERTICES * 2], // texture coords
clr[MAX_VERTICES * 4]; // color components
GLushort
idx[MAX_INDICES], // indices
vtx_ptr, idx_ptr; // pointers for array positions
int texture[MAX_TEXTURE_UNITS];
int flags; // entity flags
float alpha;
} glbuffer_t;
glbuffer_t gl_buf;
GLuint vt, tx, cl; // indices for arrays in gl_buf
extern void R_MYgluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar); extern void R_MYgluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);
void
R_ResetGLBuffer(void)
{
GLBUFFER_RESET
}
void void
R_ApplyGLBuffer(void) R_ApplyGLBuffer(void)
{ {
@ -64,7 +52,7 @@ R_ApplyGLBuffer(void)
qboolean texture, mtex, alpha, color, alias, texenv_set; qboolean texture, mtex, alpha, color, alias, texenv_set;
float fovy, dist; float fovy, dist;
if (gl_buf.vtx_ptr == 0 || gl_buf.idx_ptr == 0) if (vtx_ptr == 0 || idx_ptr == 0)
{ {
return; return;
} }
@ -194,7 +182,13 @@ R_ApplyGLBuffer(void)
if (mtex) if (mtex)
{ {
// TMU 1: Lightmap texture // TMU 1: Lightmap texture
R_MBind(GL_TEXTURE1, gl_state.lightmap_textures + gl_buf.texture[1]); int lmtexture = gl_state.lightmap_textures + gl_buf.texture[1];
if (gl_config.lightmapcopies)
{
// Bind appropiate lightmap copy for this frame
lmtexture += gl_state.max_lightmaps * cur_lm_copy;
}
R_MBind(GL_TEXTURE1, lmtexture);
if (gl1_overbrightbits->value) if (gl1_overbrightbits->value)
{ {
@ -224,7 +218,7 @@ R_ApplyGLBuffer(void)
} }
// All set, we can finally draw // All set, we can finally draw
glDrawElements(GL_TRIANGLES, gl_buf.idx_ptr, GL_UNSIGNED_SHORT, gl_buf.idx); glDrawElements(GL_TRIANGLES, idx_ptr, GL_UNSIGNED_SHORT, gl_buf.idx);
// ... and now, turn back everything as it was // ... and now, turn back everything as it was
if (color) if (color)
@ -277,7 +271,7 @@ R_ApplyGLBuffer(void)
} }
} }
gl_buf.vtx_ptr = gl_buf.idx_ptr = 0; GLBUFFER_RESET
} }
void void
@ -304,46 +298,46 @@ R_Buffer2DQuad(GLfloat ul_vx, GLfloat ul_vy, GLfloat dr_vx, GLfloat dr_vy,
{ {
static const GLushort idx_max = MAX_INDICES - 7; static const GLushort idx_max = MAX_INDICES - 7;
static const GLushort vtx_max = MAX_VERTICES - 5; static const GLushort vtx_max = MAX_VERTICES - 5;
unsigned int i;
if (gl_buf.idx_ptr > idx_max || gl_buf.vtx_ptr > vtx_max) if (idx_ptr > idx_max || vtx_ptr > vtx_max)
{ {
R_ApplyGLBuffer(); R_ApplyGLBuffer();
} }
i = gl_buf.vtx_ptr * 2; // vertex index
// "Quad" = 2-triangle GL_TRIANGLE_FAN // "Quad" = 2-triangle GL_TRIANGLE_FAN
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr; gl_buf.idx[idx_ptr] = vtx_ptr;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+1; gl_buf.idx[idx_ptr+1] = vtx_ptr+1;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+2; gl_buf.idx[idx_ptr+2] = vtx_ptr+2;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr; gl_buf.idx[idx_ptr+3] = vtx_ptr;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+2; gl_buf.idx[idx_ptr+4] = vtx_ptr+2;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+3; gl_buf.idx[idx_ptr+5] = vtx_ptr+3;
idx_ptr += 6;
// up left corner coords // up left corner coords
gl_buf.vtx[i] = ul_vx; gl_buf.vtx[gl_buf.vt] = ul_vx;
gl_buf.vtx[i+1] = ul_vy; gl_buf.vtx[gl_buf.vt+1] = ul_vy;
// up right // up right
gl_buf.vtx[i+2] = dr_vx; gl_buf.vtx[gl_buf.vt+2] = dr_vx;
gl_buf.vtx[i+3] = ul_vy; gl_buf.vtx[gl_buf.vt+3] = ul_vy;
// down right // down right
gl_buf.vtx[i+4] = dr_vx; gl_buf.vtx[gl_buf.vt+4] = dr_vx;
gl_buf.vtx[i+5] = dr_vy; gl_buf.vtx[gl_buf.vt+5] = dr_vy;
// and finally, down left // and finally, down left
gl_buf.vtx[i+6] = ul_vx; gl_buf.vtx[gl_buf.vt+6] = ul_vx;
gl_buf.vtx[i+7] = dr_vy; gl_buf.vtx[gl_buf.vt+7] = dr_vy;
gl_buf.tex[0][i] = ul_tx; gl_buf.tex[0][gl_buf.tx] = ul_tx;
gl_buf.tex[0][i+1] = ul_ty; gl_buf.tex[0][gl_buf.tx+1] = ul_ty;
gl_buf.tex[0][i+2] = dr_tx; gl_buf.tex[0][gl_buf.tx+2] = dr_tx;
gl_buf.tex[0][i+3] = ul_ty; gl_buf.tex[0][gl_buf.tx+3] = ul_ty;
gl_buf.tex[0][i+4] = dr_tx; gl_buf.tex[0][gl_buf.tx+4] = dr_tx;
gl_buf.tex[0][i+5] = dr_ty; gl_buf.tex[0][gl_buf.tx+5] = dr_ty;
gl_buf.tex[0][i+6] = ul_tx; gl_buf.tex[0][gl_buf.tx+6] = ul_tx;
gl_buf.tex[0][i+7] = dr_ty; gl_buf.tex[0][gl_buf.tx+7] = dr_ty;
gl_buf.vtx_ptr += 4; vtx_ptr += 4;
gl_buf.vt += 8;
gl_buf.tx += 8;
} }
/* /*
@ -354,8 +348,8 @@ R_SetBufferIndices(GLenum type, GLuint vertices_num)
{ {
int i; int i;
if ( gl_buf.vtx_ptr + vertices_num >= MAX_VERTICES || if ( vtx_ptr + vertices_num >= MAX_VERTICES ||
gl_buf.idx_ptr + ( (vertices_num - 2) * 3 ) >= MAX_INDICES ) idx_ptr + ( (vertices_num - 2) * 3 ) >= MAX_INDICES )
{ {
R_ApplyGLBuffer(); R_ApplyGLBuffer();
} }
@ -365,9 +359,10 @@ R_SetBufferIndices(GLenum type, GLuint vertices_num)
case GL_TRIANGLE_FAN: case GL_TRIANGLE_FAN:
for (i = 0; i < vertices_num-2; i++) for (i = 0; i < vertices_num-2; i++)
{ {
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr; gl_buf.idx[idx_ptr] = vtx_ptr;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+i+1; gl_buf.idx[idx_ptr+1] = vtx_ptr+i+1;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+i+2; gl_buf.idx[idx_ptr+2] = vtx_ptr+i+2;
idx_ptr += 3;
} }
break; break;
case GL_TRIANGLE_STRIP: case GL_TRIANGLE_STRIP:
@ -375,16 +370,17 @@ R_SetBufferIndices(GLenum type, GLuint vertices_num)
{ {
if (i % 2 == 0) if (i % 2 == 0)
{ {
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+i; gl_buf.idx[idx_ptr] = vtx_ptr+i;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+i+1; gl_buf.idx[idx_ptr+1] = vtx_ptr+i+1;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+i+2; gl_buf.idx[idx_ptr+2] = vtx_ptr+i+2;
} }
else // backwards order else // backwards order
{ {
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+i+2; gl_buf.idx[idx_ptr] = vtx_ptr+i+2;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+i+1; gl_buf.idx[idx_ptr+1] = vtx_ptr+i+1;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+i; gl_buf.idx[idx_ptr+2] = vtx_ptr+i;
} }
idx_ptr += 3;
} }
break; break;
default: default:
@ -392,58 +388,6 @@ R_SetBufferIndices(GLenum type, GLuint vertices_num)
return; return;
} }
// These affect the functions that follow in this file // GLBUFFER_VERTEX() must be called as many times as vertices_num
vt = gl_buf.vtx_ptr * 3; // vertex index vtx_ptr += vertices_num;
tx = gl_buf.vtx_ptr * 2; // texcoord index
cl = gl_buf.vtx_ptr * 4; // color index
// R_BufferVertex() must be called as many times as vertices_num
gl_buf.vtx_ptr += vertices_num;
}
/*
* Adds a single vertex to buffer
*/
void
R_BufferVertex(GLfloat x, GLfloat y, GLfloat z)
{
gl_buf.vtx[vt++] = x;
gl_buf.vtx[vt++] = y;
gl_buf.vtx[vt++] = z;
}
/*
* Adds texture coordinates for color texture (no lightmap coords)
*/
void
R_BufferSingleTex(GLfloat s, GLfloat t)
{
// tx should be set before this is called, by R_SetBufferIndices
gl_buf.tex[0][tx++] = s;
gl_buf.tex[0][tx++] = t;
}
/*
* Adds texture coordinates for color and lightmap
*/
void
R_BufferMultiTex(GLfloat cs, GLfloat ct, GLfloat ls, GLfloat lt)
{
gl_buf.tex[0][tx] = cs;
gl_buf.tex[0][tx+1] = ct;
gl_buf.tex[1][tx] = ls;
gl_buf.tex[1][tx+1] = lt;
tx += 2;
}
/*
* Adds color components of vertex
*/
void
R_BufferColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
{
gl_buf.clr[cl++] = r;
gl_buf.clr[cl++] = g;
gl_buf.clr[cl++] = b;
gl_buf.clr[cl++] = a;
} }

View file

@ -47,9 +47,17 @@ qboolean R_Upload32(unsigned *data, int width, int height, qboolean mipmap);
int gl_solid_format = GL_RGB; int gl_solid_format = GL_RGB;
int gl_alpha_format = GL_RGBA; int gl_alpha_format = GL_RGBA;
int gl_tex_solid_format = GL_RGB; #ifdef YQ2_GL1_GLES
#define DEFAULT_SOLID_FORMAT GL_RGBA
#else
#define DEFAULT_SOLID_FORMAT GL_RGB
#endif
int gl_tex_solid_format = DEFAULT_SOLID_FORMAT;
int gl_tex_alpha_format = GL_RGBA; int gl_tex_alpha_format = GL_RGBA;
#undef DEFAULT_SOLID_FORMAT
int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST; int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST;
int gl_filter_max = GL_LINEAR; int gl_filter_max = GL_LINEAR;
@ -76,6 +84,20 @@ typedef struct
int mode; int mode;
} gltmode_t; } gltmode_t;
#ifdef YQ2_GL1_GLES
gltmode_t gl_alpha_modes[] = {
{"default", GL_RGBA},
{"GL_RGBA", GL_RGBA},
};
gltmode_t gl_solid_modes[] = {
{"default", GL_RGBA},
{"GL_RGBA", GL_RGBA},
};
#else
gltmode_t gl_alpha_modes[] = { gltmode_t gl_alpha_modes[] = {
{"default", GL_RGBA}, {"default", GL_RGBA},
{"GL_RGBA", GL_RGBA}, {"GL_RGBA", GL_RGBA},
@ -85,8 +107,6 @@ gltmode_t gl_alpha_modes[] = {
{"GL_RGBA2", GL_RGBA2}, {"GL_RGBA2", GL_RGBA2},
}; };
#define NUM_GL_ALPHA_MODES (sizeof(gl_alpha_modes) / sizeof(gltmode_t))
gltmode_t gl_solid_modes[] = { gltmode_t gl_solid_modes[] = {
{"default", GL_RGB}, {"default", GL_RGB},
{"GL_RGB", GL_RGB}, {"GL_RGB", GL_RGB},
@ -96,6 +116,9 @@ gltmode_t gl_solid_modes[] = {
{"GL_R3_G3_B2", GL_R3_G3_B2}, {"GL_R3_G3_B2", GL_R3_G3_B2},
}; };
#endif
#define NUM_GL_ALPHA_MODES (sizeof(gl_alpha_modes) / sizeof(gltmode_t))
#define NUM_GL_SOLID_MODES (sizeof(gl_solid_modes) / sizeof(gltmode_t)) #define NUM_GL_SOLID_MODES (sizeof(gl_solid_modes) / sizeof(gltmode_t))
typedef struct typedef struct

View file

@ -43,9 +43,9 @@ R_RenderDlight(dlight_t *light)
vtx [ i ] = light->origin [ i ] - vpn [ i ] * rad; vtx [ i ] = light->origin [ i ] - vpn [ i ] * rad;
} }
R_BufferVertex( vtx[0], vtx[1], vtx[2] ); GLBUFFER_VERTEX( vtx[0], vtx[1], vtx[2] )
R_BufferColor( light->color[0] * 0.2, light->color[1] * 0.2, GLBUFFER_COLOR( light->color[0] * 0.2, light->color[1] * 0.2,
light->color[2] * 0.2, 1 ); light->color[2] * 0.2, 1 )
for ( i = 16; i >= 0; i-- ) for ( i = 16; i >= 0; i-- )
{ {
@ -59,8 +59,8 @@ R_RenderDlight(dlight_t *light)
+ vup [ j ] * sin( a ) * rad; + vup [ j ] * sin( a ) * rad;
} }
R_BufferVertex( vtx[0], vtx[1], vtx[2] ); GLBUFFER_VERTEX( vtx[0], vtx[1], vtx[2] )
R_BufferColor( 0, 0, 0, 1 ); GLBUFFER_COLOR( 0, 0, 0, 1 )
} }
} }

View file

@ -91,8 +91,7 @@ LM_UploadBlock(qboolean dynamic)
if (dynamic) if (dynamic)
{ {
int i; int i, height = 0;
int height = 0;
for (i = 0; i < gl_state.block_width; i++) for (i = 0; i < gl_state.block_width; i++)
{ {
@ -113,6 +112,23 @@ LM_UploadBlock(qboolean dynamic)
0, GL_LIGHTMAP_FORMAT, GL_UNSIGNED_BYTE, 0, GL_LIGHTMAP_FORMAT, GL_UNSIGNED_BYTE,
gl_lms.lightmap_buffer[buffer]); gl_lms.lightmap_buffer[buffer]);
if (gl_config.lightmapcopies && buffer != 0)
{
int i;
// Upload to all lightmap copies
for (i = 1; i < MAX_LIGHTMAP_COPIES; i++)
{
R_Bind(gl_state.lightmap_textures + (gl_state.max_lightmaps * i) + texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LIGHTMAP_FORMAT,
gl_state.block_width, gl_state.block_height,
0, GL_LIGHTMAP_FORMAT, GL_UNSIGNED_BYTE,
gl_lms.lightmap_buffer[buffer]);
}
}
if (++gl_lms.current_lightmap_texture == gl_state.max_lightmaps) if (++gl_lms.current_lightmap_texture == gl_state.max_lightmaps)
{ {
Com_Error(ERR_DROP, Com_Error(ERR_DROP,

View file

@ -92,6 +92,8 @@ cvar_t *gl1_particle_square;
cvar_t *gl1_palettedtexture; cvar_t *gl1_palettedtexture;
cvar_t *gl1_pointparameters; cvar_t *gl1_pointparameters;
cvar_t *gl1_multitexture; cvar_t *gl1_multitexture;
cvar_t *gl1_lightmapcopies;
cvar_t *gl1_discardfb;
cvar_t *gl_drawbuffer; cvar_t *gl_drawbuffer;
cvar_t *gl_lightmap; cvar_t *gl_lightmap;
@ -149,6 +151,8 @@ void LM_FreeLightmapBuffers(void);
void Scrap_Free(void); void Scrap_Free(void);
void Scrap_Init(void); void Scrap_Init(void);
extern void R_ResetGLBuffer(void);
void void
R_RotateForEntity(entity_t *e) R_RotateForEntity(entity_t *e)
{ {
@ -928,6 +932,7 @@ R_SetGL2D(void)
static void static void
R_RenderView(const refdef_t *fd) R_RenderView(const refdef_t *fd)
{ {
#ifndef YQ2_GL1_GLES
if ((gl_state.stereo_mode != STEREO_MODE_NONE) && gl_state.camera_separation) { if ((gl_state.stereo_mode != STEREO_MODE_NONE) && gl_state.camera_separation) {
qboolean drawing_left_eye = gl_state.camera_separation < 0; qboolean drawing_left_eye = gl_state.camera_separation < 0;
@ -1035,7 +1040,7 @@ R_RenderView(const refdef_t *fd)
break; break;
} }
} }
#endif
if (r_norefresh->value) if (r_norefresh->value)
{ {
@ -1176,6 +1181,12 @@ RI_RenderFrame(refdef_t *fd)
R_SetGL2D(); R_SetGL2D();
} }
#ifdef YQ2_GL1_GLES
#define DEFAULT_LMCOPIES "1"
#else
#define DEFAULT_LMCOPIES "0"
#endif
void void
R_Register(void) R_Register(void)
{ {
@ -1234,6 +1245,10 @@ R_Register(void)
gl1_palettedtexture = ri.Cvar_Get("r_palettedtextures", "0", CVAR_ARCHIVE); gl1_palettedtexture = ri.Cvar_Get("r_palettedtextures", "0", CVAR_ARCHIVE);
gl1_pointparameters = ri.Cvar_Get("gl1_pointparameters", "1", CVAR_ARCHIVE); gl1_pointparameters = ri.Cvar_Get("gl1_pointparameters", "1", CVAR_ARCHIVE);
gl1_multitexture = ri.Cvar_Get("gl1_multitexture", "1", CVAR_ARCHIVE); gl1_multitexture = ri.Cvar_Get("gl1_multitexture", "1", CVAR_ARCHIVE);
gl1_lightmapcopies = ri.Cvar_Get("gl1_lightmapcopies", DEFAULT_LMCOPIES, CVAR_ARCHIVE);
#ifdef YQ2_GL1_GLES
gl1_discardfb = ri.Cvar_Get("gl1_discardfb", "1", CVAR_ARCHIVE);
#endif
gl_drawbuffer = ri.Cvar_Get("gl_drawbuffer", "GL_BACK", 0); gl_drawbuffer = ri.Cvar_Get("gl_drawbuffer", "GL_BACK", 0);
r_vsync = ri.Cvar_Get("r_vsync", "1", CVAR_ARCHIVE); r_vsync = ri.Cvar_Get("r_vsync", "1", CVAR_ARCHIVE);
@ -1271,6 +1286,8 @@ R_Register(void)
ri.Cmd_AddCommand("gl_strings", R_Strings); ri.Cmd_AddCommand("gl_strings", R_Strings);
} }
#undef DEFAULT_LMCOPIES
/* /*
* Changes the video mode * Changes the video mode
*/ */
@ -1411,12 +1428,27 @@ R_SetMode(void)
return true; return true;
} }
// just to avoid too many preprocessor directives in RI_Init()
typedef enum
{
rf_opengl14,
rf_opengles10
} refresher_t;
qboolean qboolean
RI_Init(void) RI_Init(void)
{ {
int j; int j;
extern float r_turbsin[256]; extern float r_turbsin[256];
#ifdef YQ2_GL1_GLES
#define GLEXTENSION_NPOT "GL_OES_texture_npot"
static const refresher_t refresher = rf_opengles10;
#else
#define GLEXTENSION_NPOT "GL_ARB_texture_non_power_of_two"
static const refresher_t refresher = rf_opengl14;
#endif
Swap_Init(); Swap_Init();
for (j = 0; j < 256; j++) for (j = 0; j < 256; j++)
@ -1472,7 +1504,7 @@ RI_Init(void)
sscanf(gl_config.version_string, "%d.%d", &gl_config.major_version, &gl_config.minor_version); sscanf(gl_config.version_string, "%d.%d", &gl_config.major_version, &gl_config.minor_version);
if (gl_config.major_version == 1) if (refresher == rf_opengl14 && gl_config.major_version == 1)
{ {
if (gl_config.minor_version < 4) if (gl_config.minor_version < 4)
{ {
@ -1490,7 +1522,8 @@ RI_Init(void)
/* Point parameters */ /* Point parameters */
R_Printf(PRINT_ALL, " - Point parameters: "); R_Printf(PRINT_ALL, " - Point parameters: ");
if ( strstr(gl_config.extensions_string, "GL_ARB_point_parameters") || if ( refresher == rf_opengles10 ||
strstr(gl_config.extensions_string, "GL_ARB_point_parameters") ||
strstr(gl_config.extensions_string, "GL_EXT_point_parameters") ) // should exist for all OGL 1.4 hw... strstr(gl_config.extensions_string, "GL_EXT_point_parameters") ) // should exist for all OGL 1.4 hw...
{ {
qglPointParameterf = (void (APIENTRY *)(GLenum, GLfloat))RI_GetProcAddress ( "glPointParameterf" ); qglPointParameterf = (void (APIENTRY *)(GLenum, GLfloat))RI_GetProcAddress ( "glPointParameterf" );
@ -1583,7 +1616,7 @@ RI_Init(void)
/* Non power of two textures */ /* Non power of two textures */
R_Printf(PRINT_ALL, " - Non power of two textures: "); R_Printf(PRINT_ALL, " - Non power of two textures: ");
if (strstr(gl_config.extensions_string, "GL_ARB_texture_non_power_of_two")) if (strstr(gl_config.extensions_string, GLEXTENSION_NPOT))
{ {
gl_config.npottextures = true; gl_config.npottextures = true;
R_Printf(PRINT_ALL, "Okay\n"); R_Printf(PRINT_ALL, "Okay\n");
@ -1594,6 +1627,8 @@ RI_Init(void)
R_Printf(PRINT_ALL, "Failed\n"); R_Printf(PRINT_ALL, "Failed\n");
} }
#undef GLEXTENSION_NPOT
// ---- // ----
/* Multitexturing */ /* Multitexturing */
@ -1601,7 +1636,7 @@ RI_Init(void)
R_Printf(PRINT_ALL, " - Multitexturing: "); R_Printf(PRINT_ALL, " - Multitexturing: ");
if (strstr(gl_config.extensions_string, "GL_ARB_multitexture")) if ( refresher == rf_opengles10 || strstr(gl_config.extensions_string, "GL_ARB_multitexture") )
{ {
qglActiveTexture = (void (APIENTRY *)(GLenum))RI_GetProcAddress ("glActiveTexture"); qglActiveTexture = (void (APIENTRY *)(GLenum))RI_GetProcAddress ("glActiveTexture");
qglClientActiveTexture = (void (APIENTRY *)(GLenum))RI_GetProcAddress ("glClientActiveTexture"); qglClientActiveTexture = (void (APIENTRY *)(GLenum))RI_GetProcAddress ("glClientActiveTexture");
@ -1632,6 +1667,65 @@ RI_Init(void)
// ---- // ----
/* Lightmap copies: keep multiple copies of "the same" lightmap on video memory.
* All of them are actually different, because they are affected by different dynamic lighting,
* in different frames. This is not meant for Immediate-Mode Rendering systems (desktop),
* but for Tile-Based / Deferred Rendering ones (embedded / mobile), since active manipulation
* of textures already being used in the last few frames can cause slowdown on these systems.
* Needless to say, GPU memory usage is highly increased, so watch out in low memory situations.
*/
R_Printf(PRINT_ALL, " - Lightmap copies: ");
gl_config.lightmapcopies = false;
if (gl_config.multitexture && gl1_lightmapcopies->value)
{
gl_config.lightmapcopies = true;
R_Printf(PRINT_ALL, "Okay\n");
}
else
{
R_Printf(PRINT_ALL, "Disabled\n");
}
// ----
/* Discard framebuffer: Available only on GLES1, enables the use of a "performance hint"
* to the graphic driver, to get rid of the contents of the depth and stencil buffers.
* Useful for some GPUs that may attempt to keep them and/or write them back to
* external/uniform memory, actions that are useless for Quake 2 rendering path.
* https://registry.khronos.org/OpenGL/extensions/EXT/EXT_discard_framebuffer.txt
*/
gl_config.discardfb = false;
#ifdef YQ2_GL1_GLES
R_Printf(PRINT_ALL, " - Discard framebuffer: ");
if (strstr(gl_config.extensions_string, "GL_EXT_discard_framebuffer"))
{
qglDiscardFramebufferEXT = (void (APIENTRY *)(GLenum, GLsizei, const GLenum *))
RI_GetProcAddress ("glDiscardFramebufferEXT");
}
if (gl1_discardfb->value)
{
if (qglDiscardFramebufferEXT)
{
gl_config.discardfb = true;
R_Printf(PRINT_ALL, "Okay\n");
}
else
{
R_Printf(PRINT_ALL, "Failed\n");
}
}
else
{
R_Printf(PRINT_ALL, "Disabled\n");
}
#endif
// ----
/* Big lightmaps: this used to be fast, but after the implementation of the "GL Buffer", it /* Big lightmaps: this used to be fast, but after the implementation of the "GL Buffer", it
* became too evident that the bigger the texture, the slower the call to glTexSubImage2D() is. * became too evident that the bigger the texture, the slower the call to glTexSubImage2D() is.
* Original logic remains, but it's preferable not to make it visible to the user. * Original logic remains, but it's preferable not to make it visible to the user.
@ -1654,6 +1748,7 @@ RI_Init(void)
Mod_Init(); Mod_Init();
R_InitParticleTexture(); R_InitParticleTexture();
Draw_InitLocal(); Draw_InitLocal();
R_ResetGLBuffer();
return true; return true;
} }
@ -1794,6 +1889,7 @@ RI_BeginFrame(float camera_separation)
gl1_particle_square->modified = false; gl1_particle_square->modified = false;
} }
#ifndef YQ2_GL1_GLES
/* draw buffer stuff */ /* draw buffer stuff */
if (gl_drawbuffer->modified) if (gl_drawbuffer->modified)
{ {
@ -1811,6 +1907,7 @@ RI_BeginFrame(float camera_separation)
} }
} }
} }
#endif
/* texturemode stuff */ /* texturemode stuff */
if (gl_texturemode->modified || (gl_config.anisotropic && gl_anisotropic->modified) if (gl_texturemode->modified || (gl_config.anisotropic && gl_anisotropic->modified)

View file

@ -63,11 +63,11 @@ R_DrawAliasDrawCommands(const entity_t *currententity, int *order, const int *or
index_xyz = order[2]; index_xyz = order[2];
order += 3; order += 3;
R_BufferVertex(s_lerped[index_xyz][0], GLBUFFER_VERTEX(s_lerped[index_xyz][0],
s_lerped[index_xyz][1], s_lerped[index_xyz][2]); s_lerped[index_xyz][1], s_lerped[index_xyz][2])
R_BufferColor(shadelight[0], shadelight[1], GLBUFFER_COLOR(shadelight[0], shadelight[1],
shadelight[2], alpha); shadelight[2], alpha)
} }
while (--count); while (--count);
} }
@ -96,13 +96,13 @@ R_DrawAliasDrawCommands(const entity_t *currententity, int *order, const int *or
/* shadevector is set above according to rotation (around Z axis I think) */ /* shadevector is set above according to rotation (around Z axis I think) */
l = DotProduct(normal, shadevector) + 1; l = DotProduct(normal, shadevector) + 1;
R_BufferVertex(s_lerped[index_xyz][0], GLBUFFER_VERTEX(s_lerped[index_xyz][0],
s_lerped[index_xyz][1], s_lerped[index_xyz][2]); s_lerped[index_xyz][1], s_lerped[index_xyz][2])
R_BufferSingleTex(tex[0], tex[1]); GLBUFFER_SINGLETEX(tex[0], tex[1])
R_BufferColor(l * shadelight[0], l * shadelight[1], GLBUFFER_COLOR(l * shadelight[0], l * shadelight[1],
l * shadelight[2], alpha); l * shadelight[2], alpha)
} }
while (--count); while (--count);
} }
@ -225,7 +225,7 @@ R_DrawAliasShadowCommand(const entity_t *currententity, int *order, const int *o
point[1] -= shadevector[1] * (point[2] + lheight); point[1] -= shadevector[1] * (point[2] + lheight);
point[2] = height; point[2] = height;
R_BufferVertex( point[0], point[1], point[2] ); GLBUFFER_VERTEX( point[0], point[1], point[2] )
order += 3; order += 3;
} }

View file

@ -47,6 +47,13 @@ void
RI_EndFrame(void) RI_EndFrame(void)
{ {
R_ApplyGLBuffer(); // to draw buffered 2D text R_ApplyGLBuffer(); // to draw buffered 2D text
#ifdef YQ2_GL1_GLES
if (gl_config.discardfb)
{
static const GLenum attachments[] = { GL_DEPTH_EXT, GL_STENCIL_EXT };
qglDiscardFramebufferEXT(GL_FRAMEBUFFER_OES, 2, attachments);
}
#endif
SDL_GL_SwapWindow(window); SDL_GL_SwapWindow(window);
} }
@ -80,6 +87,7 @@ int RI_PrepareForWindow(void)
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
if (SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8) == 0) if (SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8) == 0)
{ {
@ -90,6 +98,12 @@ int RI_PrepareForWindow(void)
gl_state.stencil = false; gl_state.stencil = false;
} }
#ifdef YQ2_GL1_GLES
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
#endif
if (gl_msaa_samples->value) if (gl_msaa_samples->value)
{ {
/* Let's see if the driver supports MSAA. */ /* Let's see if the driver supports MSAA. */
@ -222,6 +236,21 @@ int RI_InitContext(void* win)
return false; return false;
} }
#ifdef YQ2_GL1_GLES
// Load GL pointers through GLAD and check context.
if( !gladLoadGLES1Loader(SDL_GL_GetProcAddress))
{
R_Printf(PRINT_ALL, "RI_InitContext(): ERROR: loading OpenGL ES function pointers failed!\n");
return false;
}
gl_config.major_version = GLVersion.major;
gl_config.minor_version = GLVersion.minor;
R_Printf(PRINT_ALL, "Initialized OpenGL ES version %d.%d context\n", gl_config.major_version, gl_config.minor_version);
#else
// Check if it's really OpenGL 1.4. // Check if it's really OpenGL 1.4.
const char* glver = (char *)glGetString(GL_VERSION); const char* glver = (char *)glGetString(GL_VERSION);
sscanf(glver, "%d.%d", &gl_config.major_version, &gl_config.minor_version); sscanf(glver, "%d.%d", &gl_config.major_version, &gl_config.minor_version);
@ -246,6 +275,8 @@ int RI_InitContext(void* win)
} }
#endif
// Check if we've got the requested MSAA. // Check if we've got the requested MSAA.
int msaa_samples = 0; int msaa_samples = 0;
@ -277,7 +308,11 @@ int RI_InitContext(void* win)
// Window title - set here so we can display renderer name in it. // Window title - set here so we can display renderer name in it.
char title[40] = {0}; char title[40] = {0};
#ifdef YQ2_GL1_GLES
snprintf(title, sizeof(title), "Yamagi Quake II %s - OpenGL ES 1.0", YQ2VERSION);
#else
snprintf(title, sizeof(title), "Yamagi Quake II %s - OpenGL 1.4", YQ2VERSION); snprintf(title, sizeof(title), "Yamagi Quake II %s - OpenGL 1.4", YQ2VERSION);
#endif
SDL_SetWindowTitle(window, title); SDL_SetWindowTitle(window, title);
#if SDL_VERSION_ATLEAST(2, 26, 0) #if SDL_VERSION_ATLEAST(2, 26, 0)

View file

@ -28,12 +28,18 @@
#include "header/local.h" #include "header/local.h"
typedef struct
{
int top, bottom, left, right;
} lmrect_t;
int c_visible_lightmaps; int c_visible_lightmaps;
int c_visible_textures; int c_visible_textures;
static vec3_t modelorg; /* relative to viewpoint */ static vec3_t modelorg; /* relative to viewpoint */
msurface_t *r_alpha_surfaces; msurface_t *r_alpha_surfaces;
gllightmapstate_t gl_lms; gllightmapstate_t gl_lms;
extern int cur_lm_copy;
void LM_InitBlock(void); void LM_InitBlock(void);
void LM_UploadBlock(qboolean dynamic); void LM_UploadBlock(qboolean dynamic);
@ -55,8 +61,8 @@ R_DrawGLPoly(msurface_t *fa)
for ( i = 0; i < nv; i++, v ++) for ( i = 0; i < nv; i++, v ++)
{ {
R_BufferVertex(v->pos[0], v->pos[1], v->pos[2]); GLBUFFER_VERTEX( v->pos[0], v->pos[1], v->pos[2] )
R_BufferSingleTex(v->texCoord[0] + sscroll, v->texCoord[1] + tscroll); GLBUFFER_SINGLETEX( v->texCoord[0] + sscroll, v->texCoord[1] + tscroll )
} }
} }
@ -510,52 +516,6 @@ R_DrawAlphaSurfaces(void)
r_alpha_surfaces = NULL; r_alpha_surfaces = NULL;
} }
static qboolean
R_HasDynamicLights(msurface_t *surf, int *mapNum)
{
int map;
qboolean is_dynamic = false;
if ( r_fullbright->value || !r_dynamic->value ||
(surf->texinfo->flags & (SURF_SKY | SURF_TRANSPARENT | SURF_WARP)) )
{
return false;
}
// Any dynamic lights on this surface?
for (map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255; map++)
{
if (r_newrefdef.lightstyles[surf->styles[map]].white != surf->cached_light[map])
{
is_dynamic = true;
break;
}
}
// No matter if it is this frame or was in the previous one: has dynamic lights
if ( !is_dynamic && (surf->dlightframe == r_framecount || surf->dirty_lightmap) )
{
is_dynamic = true;
}
if (mapNum)
{
*mapNum = map;
}
return is_dynamic;
}
static void
R_UpdateSurfCache(msurface_t *surf, int map)
{
if ( ((surf->styles[map] >= 32) || (surf->styles[map] == 0))
&& (surf->dlightframe != r_framecount) )
{
R_SetCacheState(surf, &r_newrefdef);
}
surf->dirty_lightmap = (surf->dlightframe == r_framecount);
}
static void static void
R_RenderLightmappedPoly(const entity_t *currententity, msurface_t *surf) R_RenderLightmappedPoly(const entity_t *currententity, msurface_t *surf)
{ {
@ -573,9 +533,31 @@ R_RenderLightmappedPoly(const entity_t *currententity, msurface_t *surf)
for (i = 0; i < nv; i++, vert++) for (i = 0; i < nv; i++, vert++)
{ {
R_BufferVertex( vert->pos[0], vert->pos[1], vert->pos[2] ); GLBUFFER_VERTEX( vert->pos[0], vert->pos[1], vert->pos[2] )
R_BufferMultiTex( vert->texCoord[0] + sscroll, vert->texCoord[1] + tscroll, GLBUFFER_MULTITEX( vert->texCoord[0] + sscroll, vert->texCoord[1] + tscroll,
vert->lmTexCoord[0], vert->lmTexCoord[1] ); vert->lmTexCoord[0], vert->lmTexCoord[1] )
}
}
/* Add "adding" area to "obj" */
static void
R_JoinAreas(lmrect_t *adding, lmrect_t *obj)
{
if (adding->top < obj->top)
{
obj->top = adding->top;
}
if (adding->bottom > obj->bottom)
{
obj->bottom = adding->bottom;
}
if (adding->left < obj->left)
{
obj->left = adding->left;
}
if (adding->right > obj->right)
{
obj->right = adding->right;
} }
} }
@ -583,16 +565,33 @@ R_RenderLightmappedPoly(const entity_t *currententity, msurface_t *surf)
static void static void
R_RegenAllLightmaps() R_RegenAllLightmaps()
{ {
int i, map, smax, tmax, top, bottom, left, right, bt, bb, bl, br; static lmrect_t lmchange[MAX_LIGHTMAPS][MAX_LIGHTMAP_COPIES];
qboolean affected_lightmap, pixelstore_set = false; static qboolean altered[MAX_LIGHTMAPS][MAX_LIGHTMAP_COPIES];
int i, map, smax, tmax, lmtex;
lmrect_t current, best;
msurface_t *surf; msurface_t *surf;
byte *base; byte *base;
qboolean affected_lightmap;
#ifndef YQ2_GL1_GLES
qboolean pixelstore_set = false;
#endif
if ( !gl_config.multitexture ) if ( !gl_config.multitexture || r_fullbright->value || !r_dynamic->value )
{ {
return; return;
} }
if (gl_config.lightmapcopies)
{
cur_lm_copy = (cur_lm_copy + 1) % MAX_LIGHTMAP_COPIES; // select the next lightmap copy
lmtex = gl_state.max_lightmaps * cur_lm_copy; // ...and its corresponding texture
}
else
{
lmtex = 0;
}
for (i = 1; i < gl_state.max_lightmaps; i++) for (i = 1; i < gl_state.max_lightmaps; i++)
{ {
if (!gl_lms.lightmap_surfaces[i] || !gl_lms.lightmap_buffer[i]) if (!gl_lms.lightmap_surfaces[i] || !gl_lms.lightmap_buffer[i])
@ -601,77 +600,131 @@ R_RegenAllLightmaps()
} }
affected_lightmap = false; affected_lightmap = false;
bt = gl_state.block_height; best.top = gl_state.block_height;
bl = gl_state.block_width; best.left = gl_state.block_width;
bb = br = 0; best.bottom = best.right = 0;
for (surf = gl_lms.lightmap_surfaces[i]; for (surf = gl_lms.lightmap_surfaces[i];
surf != 0; surf != 0;
surf = surf->lightmapchain) surf = surf->lightmapchain)
{ {
if ( !R_HasDynamicLights(surf, &map) ) if (surf->texinfo->flags & (SURF_SKY | SURF_TRANS33 | SURF_TRANS66 | SURF_WARP))
{ {
continue; continue;
} }
// Any dynamic lights on this surface?
for (map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255; map++)
{
if (r_newrefdef.lightstyles[surf->styles[map]].white != surf->cached_light[map])
{
goto dynamic_surf;
}
}
// Doesn't matter if it is this frame or was in the previous one: surface has dynamic lights
if ( surf->dlightframe == r_framecount || surf->dirty_lightmap )
{
goto dynamic_surf;
}
continue; // no dynamic lights affect this surface in this frame
dynamic_surf:
affected_lightmap = true; affected_lightmap = true;
smax = (surf->extents[0] >> surf->lmshift) + 1; smax = (surf->extents[0] >> surf->lmshift) + 1;
tmax = (surf->extents[1] >> surf->lmshift) + 1; tmax = (surf->extents[1] >> surf->lmshift) + 1;
left = surf->light_s; current.left = surf->light_s;
right = surf->light_s + smax; current.right = surf->light_s + smax;
top = surf->light_t; current.top = surf->light_t;
bottom = surf->light_t + tmax; current.bottom = surf->light_t + tmax;
base = gl_lms.lightmap_buffer[i]; base = gl_lms.lightmap_buffer[i];
base += (top * gl_state.block_width + left) * LIGHTMAP_BYTES; base += (current.top * gl_state.block_width + current.left) * LIGHTMAP_BYTES;
R_BuildLightMap(surf, base, gl_state.block_width * LIGHTMAP_BYTES, R_BuildLightMap(surf, base, gl_state.block_width * LIGHTMAP_BYTES,
&r_newrefdef, r_modulate->value, r_framecount); &r_newrefdef, r_modulate->value, r_framecount);
R_UpdateSurfCache(surf, map);
if (left < bl) if ( ((surf->styles[map] >= 32) || (surf->styles[map] == 0))
&& (surf->dlightframe != r_framecount) )
{ {
bl = left; R_SetCacheState(surf, &r_newrefdef);
}
if (right > br)
{
br = right;
}
if (top < bt)
{
bt = top;
}
if (bottom > bb)
{
bb = bottom;
} }
surf->dirty_lightmap = (surf->dlightframe == r_framecount);
R_JoinAreas(&current, &best);
} }
if (!affected_lightmap) if (!gl_config.lightmapcopies && !affected_lightmap)
{ {
continue; continue;
} }
if (gl_config.lightmapcopies)
{
// Add all the changes that have happened in the last few frames,
// at least just for consistency between them.
qboolean apply_changes = affected_lightmap;
current = best; // save state for next frames... +
for (int k = 0; k < MAX_LIGHTMAP_COPIES; k++)
{
if (altered[i][k])
{
apply_changes = true;
R_JoinAreas(&lmchange[i][k], &best);
}
}
altered[i][cur_lm_copy] = affected_lightmap;
if (affected_lightmap)
{
lmchange[i][cur_lm_copy] = current; // + ...here
}
if (!apply_changes)
{
continue;
}
}
#ifndef YQ2_GL1_GLES
if (!pixelstore_set) if (!pixelstore_set)
{ {
glPixelStorei(GL_UNPACK_ROW_LENGTH, gl_state.block_width); glPixelStorei(GL_UNPACK_ROW_LENGTH, gl_state.block_width);
pixelstore_set = true; pixelstore_set = true;
} }
#endif
base = gl_lms.lightmap_buffer[i];
base += (bt * gl_state.block_width + bl) * LIGHTMAP_BYTES;
// upload changes // upload changes
R_Bind(gl_state.lightmap_textures + i); base = gl_lms.lightmap_buffer[i];
glTexSubImage2D(GL_TEXTURE_2D, 0, bl, bt, br - bl, bb - bt,
GL_LIGHTMAP_FORMAT, GL_UNSIGNED_BYTE, base); #ifdef YQ2_GL1_GLES
base += (best.top * gl_state.block_width) * LIGHTMAP_BYTES;
R_Bind(gl_state.lightmap_textures + i + lmtex);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, best.top,
gl_state.block_width, best.bottom - best.top,
GL_LIGHTMAP_FORMAT, GL_UNSIGNED_BYTE, base);
#else
base += (best.top * gl_state.block_width + best.left) * LIGHTMAP_BYTES;
R_Bind(gl_state.lightmap_textures + i + lmtex);
glTexSubImage2D(GL_TEXTURE_2D, 0, best.left, best.top,
best.right - best.left, best.bottom - best.top,
GL_LIGHTMAP_FORMAT, GL_UNSIGNED_BYTE, base);
#endif
} }
#ifndef YQ2_GL1_GLES
if (pixelstore_set) if (pixelstore_set)
{ {
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
} }
#endif
} }
static void static void

View file

@ -88,8 +88,8 @@ R_EmitWaterPolys(msurface_t *fa)
s = os + r_turbsin [ (int) ( ( ot * 0.125 + r_newrefdef.time ) * TURBSCALE ) & 255 ] + sscroll; s = os + r_turbsin [ (int) ( ( ot * 0.125 + r_newrefdef.time ) * TURBSCALE ) & 255 ] + sscroll;
t = ot + r_turbsin [ (int) ( ( os * 0.125 + r_newrefdef.time ) * TURBSCALE ) & 255 ] + tscroll; t = ot + r_turbsin [ (int) ( ( os * 0.125 + r_newrefdef.time ) * TURBSCALE ) & 255 ] + tscroll;
R_BufferVertex( v->pos[0], v->pos[1], v->pos[2] ); GLBUFFER_VERTEX( v->pos[0], v->pos[1], v->pos[2] )
R_BufferSingleTex( s * ( 1.0 / 64 ), t * ( 1.0 / 64 ) ); GLBUFFER_SINGLETEX( s * ( 1.0 / 64 ), t * ( 1.0 / 64 ) )
} }
} }
} }

View 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_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,526 @@
/*
OpenGL ES loader generated by glad 0.1.36 on Sun Aug 11 03:16:24 2024.
Language/Generator: C/C++
Specification: gl
APIs: gles1=1.0
Profile: core
Extensions:
GL_EXT_discard_framebuffer,
GL_OES_framebuffer_object,
GL_OES_texture_npot
Loader: False
Local files: False
Omit khrplatform: False
Reproducible: False
Commandline:
--profile="core" --api="gles1=1.0" --generator="c" --spec="gl" --no-loader --extensions="GL_EXT_discard_framebuffer,GL_OES_framebuffer_object,GL_OES_texture_npot"
Online:
https://glad.dav1d.de/#profile=core&language=c&specification=gl&api=gles1%3D1.0&extensions=GL_EXT_discard_framebuffer&extensions=GL_OES_framebuffer_object&extensions=GL_OES_texture_npot
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glad/glad.h>
struct gladGLversionStruct GLVersion = { 0, 0 };
#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0)
#define _GLAD_IS_SOME_NEW_VERSION 1
#endif
static int max_loaded_major;
static int max_loaded_minor;
static const char *exts = NULL;
static int num_exts_i = 0;
static char **exts_i = NULL;
static int get_exts(void) {
#ifdef _GLAD_IS_SOME_NEW_VERSION
if(max_loaded_major < 3) {
#endif
exts = (const char *)glGetString(GL_EXTENSIONS);
#ifdef _GLAD_IS_SOME_NEW_VERSION
} else {
int index;
num_exts_i = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i);
if (num_exts_i > 0) {
exts_i = (char **)malloc((size_t)num_exts_i * (sizeof *exts_i));
}
if (exts_i == NULL) {
return 0;
}
for(index = 0; index < num_exts_i; index++) {
const char *gl_str_tmp = (const char*)glGetStringi(GL_EXTENSIONS, index);
size_t len = strlen(gl_str_tmp);
char *local_str = (char*)malloc((len+1) * sizeof(char));
if(local_str != NULL) {
memcpy(local_str, gl_str_tmp, (len+1) * sizeof(char));
}
exts_i[index] = local_str;
}
}
#endif
return 1;
}
static void free_exts(void) {
if (exts_i != NULL) {
int index;
for(index = 0; index < num_exts_i; index++) {
free((char *)exts_i[index]);
}
free((void *)exts_i);
exts_i = NULL;
}
}
static int has_ext(const char *ext) {
#ifdef _GLAD_IS_SOME_NEW_VERSION
if(max_loaded_major < 3) {
#endif
const char *extensions;
const char *loc;
const char *terminator;
extensions = exts;
if(extensions == NULL || ext == NULL) {
return 0;
}
while(1) {
loc = strstr(extensions, ext);
if(loc == NULL) {
return 0;
}
terminator = loc + strlen(ext);
if((loc == extensions || *(loc - 1) == ' ') &&
(*terminator == ' ' || *terminator == '\0')) {
return 1;
}
extensions = terminator;
}
#ifdef _GLAD_IS_SOME_NEW_VERSION
} else {
int index;
if(exts_i == NULL) return 0;
for(index = 0; index < num_exts_i; index++) {
const char *e = exts_i[index];
if(exts_i[index] != NULL && strcmp(e, ext) == 0) {
return 1;
}
}
}
#endif
return 0;
}
int GLAD_GL_VERSION_ES_CM_1_0 = 0;
PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL;
PFNGLALPHAFUNCPROC glad_glAlphaFunc = NULL;
PFNGLALPHAFUNCXPROC glad_glAlphaFuncx = NULL;
PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL;
PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL;
PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL;
PFNGLBUFFERDATAPROC glad_glBufferData = NULL;
PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL;
PFNGLCLEARPROC glad_glClear = NULL;
PFNGLCLEARCOLORPROC glad_glClearColor = NULL;
PFNGLCLEARCOLORXPROC glad_glClearColorx = NULL;
PFNGLCLEARDEPTHFPROC glad_glClearDepthf = NULL;
PFNGLCLEARDEPTHXPROC glad_glClearDepthx = NULL;
PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL;
PFNGLCLIENTACTIVETEXTUREPROC glad_glClientActiveTexture = NULL;
PFNGLCLIPPLANEFPROC glad_glClipPlanef = NULL;
PFNGLCLIPPLANEXPROC glad_glClipPlanex = NULL;
PFNGLCOLOR4FPROC glad_glColor4f = NULL;
PFNGLCOLOR4UBPROC glad_glColor4ub = NULL;
PFNGLCOLOR4XPROC glad_glColor4x = NULL;
PFNGLCOLORMASKPROC glad_glColorMask = NULL;
PFNGLCOLORPOINTERPROC glad_glColorPointer = NULL;
PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL;
PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL;
PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL;
PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL;
PFNGLCULLFACEPROC glad_glCullFace = NULL;
PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL;
PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL;
PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL;
PFNGLDEPTHMASKPROC glad_glDepthMask = NULL;
PFNGLDEPTHRANGEFPROC glad_glDepthRangef = NULL;
PFNGLDEPTHRANGEXPROC glad_glDepthRangex = NULL;
PFNGLDISABLEPROC glad_glDisable = NULL;
PFNGLDISABLECLIENTSTATEPROC glad_glDisableClientState = NULL;
PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL;
PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL;
PFNGLENABLEPROC glad_glEnable = NULL;
PFNGLENABLECLIENTSTATEPROC glad_glEnableClientState = NULL;
PFNGLFINISHPROC glad_glFinish = NULL;
PFNGLFLUSHPROC glad_glFlush = NULL;
PFNGLFOGFPROC glad_glFogf = NULL;
PFNGLFOGFVPROC glad_glFogfv = NULL;
PFNGLFOGXPROC glad_glFogx = NULL;
PFNGLFOGXVPROC glad_glFogxv = NULL;
PFNGLFRONTFACEPROC glad_glFrontFace = NULL;
PFNGLFRUSTUMFPROC glad_glFrustumf = NULL;
PFNGLFRUSTUMXPROC glad_glFrustumx = NULL;
PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL;
PFNGLGENTEXTURESPROC glad_glGenTextures = NULL;
PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL;
PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL;
PFNGLGETCLIPPLANEFPROC glad_glGetClipPlanef = NULL;
PFNGLGETCLIPPLANEXPROC glad_glGetClipPlanex = NULL;
PFNGLGETERRORPROC glad_glGetError = NULL;
PFNGLGETFIXEDVPROC glad_glGetFixedv = NULL;
PFNGLGETFLOATVPROC glad_glGetFloatv = NULL;
PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL;
PFNGLGETLIGHTFVPROC glad_glGetLightfv = NULL;
PFNGLGETLIGHTXVPROC glad_glGetLightxv = NULL;
PFNGLGETMATERIALFVPROC glad_glGetMaterialfv = NULL;
PFNGLGETMATERIALXVPROC glad_glGetMaterialxv = NULL;
PFNGLGETPOINTERVPROC glad_glGetPointerv = NULL;
PFNGLGETSTRINGPROC glad_glGetString = NULL;
PFNGLGETTEXENVFVPROC glad_glGetTexEnvfv = NULL;
PFNGLGETTEXENVIVPROC glad_glGetTexEnviv = NULL;
PFNGLGETTEXENVXVPROC glad_glGetTexEnvxv = NULL;
PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL;
PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL;
PFNGLGETTEXPARAMETERXVPROC glad_glGetTexParameterxv = NULL;
PFNGLHINTPROC glad_glHint = NULL;
PFNGLISBUFFERPROC glad_glIsBuffer = NULL;
PFNGLISENABLEDPROC glad_glIsEnabled = NULL;
PFNGLISTEXTUREPROC glad_glIsTexture = NULL;
PFNGLLIGHTMODELFPROC glad_glLightModelf = NULL;
PFNGLLIGHTMODELFVPROC glad_glLightModelfv = NULL;
PFNGLLIGHTMODELXPROC glad_glLightModelx = NULL;
PFNGLLIGHTMODELXVPROC glad_glLightModelxv = NULL;
PFNGLLIGHTFPROC glad_glLightf = NULL;
PFNGLLIGHTFVPROC glad_glLightfv = NULL;
PFNGLLIGHTXPROC glad_glLightx = NULL;
PFNGLLIGHTXVPROC glad_glLightxv = NULL;
PFNGLLINEWIDTHPROC glad_glLineWidth = NULL;
PFNGLLINEWIDTHXPROC glad_glLineWidthx = NULL;
PFNGLLOADIDENTITYPROC glad_glLoadIdentity = NULL;
PFNGLLOADMATRIXFPROC glad_glLoadMatrixf = NULL;
PFNGLLOADMATRIXXPROC glad_glLoadMatrixx = NULL;
PFNGLLOGICOPPROC glad_glLogicOp = NULL;
PFNGLMATERIALFPROC glad_glMaterialf = NULL;
PFNGLMATERIALFVPROC glad_glMaterialfv = NULL;
PFNGLMATERIALXPROC glad_glMaterialx = NULL;
PFNGLMATERIALXVPROC glad_glMaterialxv = NULL;
PFNGLMATRIXMODEPROC glad_glMatrixMode = NULL;
PFNGLMULTMATRIXFPROC glad_glMultMatrixf = NULL;
PFNGLMULTMATRIXXPROC glad_glMultMatrixx = NULL;
PFNGLMULTITEXCOORD4FPROC glad_glMultiTexCoord4f = NULL;
PFNGLMULTITEXCOORD4XPROC glad_glMultiTexCoord4x = NULL;
PFNGLNORMAL3FPROC glad_glNormal3f = NULL;
PFNGLNORMAL3XPROC glad_glNormal3x = NULL;
PFNGLNORMALPOINTERPROC glad_glNormalPointer = NULL;
PFNGLORTHOFPROC glad_glOrthof = NULL;
PFNGLORTHOXPROC glad_glOrthox = NULL;
PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL;
PFNGLPOINTPARAMETERFPROC glad_glPointParameterf = NULL;
PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv = NULL;
PFNGLPOINTPARAMETERXPROC glad_glPointParameterx = NULL;
PFNGLPOINTPARAMETERXVPROC glad_glPointParameterxv = NULL;
PFNGLPOINTSIZEPROC glad_glPointSize = NULL;
PFNGLPOINTSIZEXPROC glad_glPointSizex = NULL;
PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL;
PFNGLPOLYGONOFFSETXPROC glad_glPolygonOffsetx = NULL;
PFNGLPOPMATRIXPROC glad_glPopMatrix = NULL;
PFNGLPUSHMATRIXPROC glad_glPushMatrix = NULL;
PFNGLREADPIXELSPROC glad_glReadPixels = NULL;
PFNGLROTATEFPROC glad_glRotatef = NULL;
PFNGLROTATEXPROC glad_glRotatex = NULL;
PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL;
PFNGLSAMPLECOVERAGEXPROC glad_glSampleCoveragex = NULL;
PFNGLSCALEFPROC glad_glScalef = NULL;
PFNGLSCALEXPROC glad_glScalex = NULL;
PFNGLSCISSORPROC glad_glScissor = NULL;
PFNGLSHADEMODELPROC glad_glShadeModel = NULL;
PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL;
PFNGLSTENCILMASKPROC glad_glStencilMask = NULL;
PFNGLSTENCILOPPROC glad_glStencilOp = NULL;
PFNGLTEXCOORDPOINTERPROC glad_glTexCoordPointer = NULL;
PFNGLTEXENVFPROC glad_glTexEnvf = NULL;
PFNGLTEXENVFVPROC glad_glTexEnvfv = NULL;
PFNGLTEXENVIPROC glad_glTexEnvi = NULL;
PFNGLTEXENVIVPROC glad_glTexEnviv = NULL;
PFNGLTEXENVXPROC glad_glTexEnvx = NULL;
PFNGLTEXENVXVPROC glad_glTexEnvxv = NULL;
PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL;
PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL;
PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL;
PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL;
PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL;
PFNGLTEXPARAMETERXPROC glad_glTexParameterx = NULL;
PFNGLTEXPARAMETERXVPROC glad_glTexParameterxv = NULL;
PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL;
PFNGLTRANSLATEFPROC glad_glTranslatef = NULL;
PFNGLTRANSLATEXPROC glad_glTranslatex = NULL;
PFNGLVERTEXPOINTERPROC glad_glVertexPointer = NULL;
PFNGLVIEWPORTPROC glad_glViewport = NULL;
int GLAD_GL_EXT_discard_framebuffer = 0;
int GLAD_GL_OES_framebuffer_object = 0;
int GLAD_GL_OES_texture_npot = 0;
PFNGLDISCARDFRAMEBUFFEREXTPROC glad_glDiscardFramebufferEXT = NULL;
PFNGLISRENDERBUFFEROESPROC glad_glIsRenderbufferOES = NULL;
PFNGLBINDRENDERBUFFEROESPROC glad_glBindRenderbufferOES = NULL;
PFNGLDELETERENDERBUFFERSOESPROC glad_glDeleteRenderbuffersOES = NULL;
PFNGLGENRENDERBUFFERSOESPROC glad_glGenRenderbuffersOES = NULL;
PFNGLRENDERBUFFERSTORAGEOESPROC glad_glRenderbufferStorageOES = NULL;
PFNGLGETRENDERBUFFERPARAMETERIVOESPROC glad_glGetRenderbufferParameterivOES = NULL;
PFNGLISFRAMEBUFFEROESPROC glad_glIsFramebufferOES = NULL;
PFNGLBINDFRAMEBUFFEROESPROC glad_glBindFramebufferOES = NULL;
PFNGLDELETEFRAMEBUFFERSOESPROC glad_glDeleteFramebuffersOES = NULL;
PFNGLGENFRAMEBUFFERSOESPROC glad_glGenFramebuffersOES = NULL;
PFNGLCHECKFRAMEBUFFERSTATUSOESPROC glad_glCheckFramebufferStatusOES = NULL;
PFNGLFRAMEBUFFERRENDERBUFFEROESPROC glad_glFramebufferRenderbufferOES = NULL;
PFNGLFRAMEBUFFERTEXTURE2DOESPROC glad_glFramebufferTexture2DOES = NULL;
PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVOESPROC glad_glGetFramebufferAttachmentParameterivOES = NULL;
PFNGLGENERATEMIPMAPOESPROC glad_glGenerateMipmapOES = NULL;
static void load_GL_VERSION_ES_CM_1_0(GLADloadproc load) {
if(!GLAD_GL_VERSION_ES_CM_1_0) return;
glad_glAlphaFunc = (PFNGLALPHAFUNCPROC)load("glAlphaFunc");
glad_glClearColor = (PFNGLCLEARCOLORPROC)load("glClearColor");
glad_glClearDepthf = (PFNGLCLEARDEPTHFPROC)load("glClearDepthf");
glad_glClipPlanef = (PFNGLCLIPPLANEFPROC)load("glClipPlanef");
glad_glColor4f = (PFNGLCOLOR4FPROC)load("glColor4f");
glad_glDepthRangef = (PFNGLDEPTHRANGEFPROC)load("glDepthRangef");
glad_glFogf = (PFNGLFOGFPROC)load("glFogf");
glad_glFogfv = (PFNGLFOGFVPROC)load("glFogfv");
glad_glFrustumf = (PFNGLFRUSTUMFPROC)load("glFrustumf");
glad_glGetClipPlanef = (PFNGLGETCLIPPLANEFPROC)load("glGetClipPlanef");
glad_glGetFloatv = (PFNGLGETFLOATVPROC)load("glGetFloatv");
glad_glGetLightfv = (PFNGLGETLIGHTFVPROC)load("glGetLightfv");
glad_glGetMaterialfv = (PFNGLGETMATERIALFVPROC)load("glGetMaterialfv");
glad_glGetTexEnvfv = (PFNGLGETTEXENVFVPROC)load("glGetTexEnvfv");
glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC)load("glGetTexParameterfv");
glad_glLightModelf = (PFNGLLIGHTMODELFPROC)load("glLightModelf");
glad_glLightModelfv = (PFNGLLIGHTMODELFVPROC)load("glLightModelfv");
glad_glLightf = (PFNGLLIGHTFPROC)load("glLightf");
glad_glLightfv = (PFNGLLIGHTFVPROC)load("glLightfv");
glad_glLineWidth = (PFNGLLINEWIDTHPROC)load("glLineWidth");
glad_glLoadMatrixf = (PFNGLLOADMATRIXFPROC)load("glLoadMatrixf");
glad_glMaterialf = (PFNGLMATERIALFPROC)load("glMaterialf");
glad_glMaterialfv = (PFNGLMATERIALFVPROC)load("glMaterialfv");
glad_glMultMatrixf = (PFNGLMULTMATRIXFPROC)load("glMultMatrixf");
glad_glMultiTexCoord4f = (PFNGLMULTITEXCOORD4FPROC)load("glMultiTexCoord4f");
glad_glNormal3f = (PFNGLNORMAL3FPROC)load("glNormal3f");
glad_glOrthof = (PFNGLORTHOFPROC)load("glOrthof");
glad_glPointParameterf = (PFNGLPOINTPARAMETERFPROC)load("glPointParameterf");
glad_glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC)load("glPointParameterfv");
glad_glPointSize = (PFNGLPOINTSIZEPROC)load("glPointSize");
glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC)load("glPolygonOffset");
glad_glRotatef = (PFNGLROTATEFPROC)load("glRotatef");
glad_glScalef = (PFNGLSCALEFPROC)load("glScalef");
glad_glTexEnvf = (PFNGLTEXENVFPROC)load("glTexEnvf");
glad_glTexEnvfv = (PFNGLTEXENVFVPROC)load("glTexEnvfv");
glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC)load("glTexParameterf");
glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC)load("glTexParameterfv");
glad_glTranslatef = (PFNGLTRANSLATEFPROC)load("glTranslatef");
glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC)load("glActiveTexture");
glad_glAlphaFuncx = (PFNGLALPHAFUNCXPROC)load("glAlphaFuncx");
glad_glBindBuffer = (PFNGLBINDBUFFERPROC)load("glBindBuffer");
glad_glBindTexture = (PFNGLBINDTEXTUREPROC)load("glBindTexture");
glad_glBlendFunc = (PFNGLBLENDFUNCPROC)load("glBlendFunc");
glad_glBufferData = (PFNGLBUFFERDATAPROC)load("glBufferData");
glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)load("glBufferSubData");
glad_glClear = (PFNGLCLEARPROC)load("glClear");
glad_glClearColorx = (PFNGLCLEARCOLORXPROC)load("glClearColorx");
glad_glClearDepthx = (PFNGLCLEARDEPTHXPROC)load("glClearDepthx");
glad_glClearStencil = (PFNGLCLEARSTENCILPROC)load("glClearStencil");
glad_glClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREPROC)load("glClientActiveTexture");
glad_glClipPlanex = (PFNGLCLIPPLANEXPROC)load("glClipPlanex");
glad_glColor4ub = (PFNGLCOLOR4UBPROC)load("glColor4ub");
glad_glColor4x = (PFNGLCOLOR4XPROC)load("glColor4x");
glad_glColorMask = (PFNGLCOLORMASKPROC)load("glColorMask");
glad_glColorPointer = (PFNGLCOLORPOINTERPROC)load("glColorPointer");
glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)load("glCompressedTexImage2D");
glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)load("glCompressedTexSubImage2D");
glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC)load("glCopyTexImage2D");
glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC)load("glCopyTexSubImage2D");
glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace");
glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)load("glDeleteBuffers");
glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC)load("glDeleteTextures");
glad_glDepthFunc = (PFNGLDEPTHFUNCPROC)load("glDepthFunc");
glad_glDepthMask = (PFNGLDEPTHMASKPROC)load("glDepthMask");
glad_glDepthRangex = (PFNGLDEPTHRANGEXPROC)load("glDepthRangex");
glad_glDisable = (PFNGLDISABLEPROC)load("glDisable");
glad_glDisableClientState = (PFNGLDISABLECLIENTSTATEPROC)load("glDisableClientState");
glad_glDrawArrays = (PFNGLDRAWARRAYSPROC)load("glDrawArrays");
glad_glDrawElements = (PFNGLDRAWELEMENTSPROC)load("glDrawElements");
glad_glEnable = (PFNGLENABLEPROC)load("glEnable");
glad_glEnableClientState = (PFNGLENABLECLIENTSTATEPROC)load("glEnableClientState");
glad_glFinish = (PFNGLFINISHPROC)load("glFinish");
glad_glFlush = (PFNGLFLUSHPROC)load("glFlush");
glad_glFogx = (PFNGLFOGXPROC)load("glFogx");
glad_glFogxv = (PFNGLFOGXVPROC)load("glFogxv");
glad_glFrontFace = (PFNGLFRONTFACEPROC)load("glFrontFace");
glad_glFrustumx = (PFNGLFRUSTUMXPROC)load("glFrustumx");
glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC)load("glGetBooleanv");
glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load("glGetBufferParameteriv");
glad_glGetClipPlanex = (PFNGLGETCLIPPLANEXPROC)load("glGetClipPlanex");
glad_glGenBuffers = (PFNGLGENBUFFERSPROC)load("glGenBuffers");
glad_glGenTextures = (PFNGLGENTEXTURESPROC)load("glGenTextures");
glad_glGetError = (PFNGLGETERRORPROC)load("glGetError");
glad_glGetFixedv = (PFNGLGETFIXEDVPROC)load("glGetFixedv");
glad_glGetIntegerv = (PFNGLGETINTEGERVPROC)load("glGetIntegerv");
glad_glGetLightxv = (PFNGLGETLIGHTXVPROC)load("glGetLightxv");
glad_glGetMaterialxv = (PFNGLGETMATERIALXVPROC)load("glGetMaterialxv");
glad_glGetPointerv = (PFNGLGETPOINTERVPROC)load("glGetPointerv");
glad_glGetString = (PFNGLGETSTRINGPROC)load("glGetString");
glad_glGetTexEnviv = (PFNGLGETTEXENVIVPROC)load("glGetTexEnviv");
glad_glGetTexEnvxv = (PFNGLGETTEXENVXVPROC)load("glGetTexEnvxv");
glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC)load("glGetTexParameteriv");
glad_glGetTexParameterxv = (PFNGLGETTEXPARAMETERXVPROC)load("glGetTexParameterxv");
glad_glHint = (PFNGLHINTPROC)load("glHint");
glad_glIsBuffer = (PFNGLISBUFFERPROC)load("glIsBuffer");
glad_glIsEnabled = (PFNGLISENABLEDPROC)load("glIsEnabled");
glad_glIsTexture = (PFNGLISTEXTUREPROC)load("glIsTexture");
glad_glLightModelx = (PFNGLLIGHTMODELXPROC)load("glLightModelx");
glad_glLightModelxv = (PFNGLLIGHTMODELXVPROC)load("glLightModelxv");
glad_glLightx = (PFNGLLIGHTXPROC)load("glLightx");
glad_glLightxv = (PFNGLLIGHTXVPROC)load("glLightxv");
glad_glLineWidthx = (PFNGLLINEWIDTHXPROC)load("glLineWidthx");
glad_glLoadIdentity = (PFNGLLOADIDENTITYPROC)load("glLoadIdentity");
glad_glLoadMatrixx = (PFNGLLOADMATRIXXPROC)load("glLoadMatrixx");
glad_glLogicOp = (PFNGLLOGICOPPROC)load("glLogicOp");
glad_glMaterialx = (PFNGLMATERIALXPROC)load("glMaterialx");
glad_glMaterialxv = (PFNGLMATERIALXVPROC)load("glMaterialxv");
glad_glMatrixMode = (PFNGLMATRIXMODEPROC)load("glMatrixMode");
glad_glMultMatrixx = (PFNGLMULTMATRIXXPROC)load("glMultMatrixx");
glad_glMultiTexCoord4x = (PFNGLMULTITEXCOORD4XPROC)load("glMultiTexCoord4x");
glad_glNormal3x = (PFNGLNORMAL3XPROC)load("glNormal3x");
glad_glNormalPointer = (PFNGLNORMALPOINTERPROC)load("glNormalPointer");
glad_glOrthox = (PFNGLORTHOXPROC)load("glOrthox");
glad_glPixelStorei = (PFNGLPIXELSTOREIPROC)load("glPixelStorei");
glad_glPointParameterx = (PFNGLPOINTPARAMETERXPROC)load("glPointParameterx");
glad_glPointParameterxv = (PFNGLPOINTPARAMETERXVPROC)load("glPointParameterxv");
glad_glPointSizex = (PFNGLPOINTSIZEXPROC)load("glPointSizex");
glad_glPolygonOffsetx = (PFNGLPOLYGONOFFSETXPROC)load("glPolygonOffsetx");
glad_glPopMatrix = (PFNGLPOPMATRIXPROC)load("glPopMatrix");
glad_glPushMatrix = (PFNGLPUSHMATRIXPROC)load("glPushMatrix");
glad_glReadPixels = (PFNGLREADPIXELSPROC)load("glReadPixels");
glad_glRotatex = (PFNGLROTATEXPROC)load("glRotatex");
glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC)load("glSampleCoverage");
glad_glSampleCoveragex = (PFNGLSAMPLECOVERAGEXPROC)load("glSampleCoveragex");
glad_glScalex = (PFNGLSCALEXPROC)load("glScalex");
glad_glScissor = (PFNGLSCISSORPROC)load("glScissor");
glad_glShadeModel = (PFNGLSHADEMODELPROC)load("glShadeModel");
glad_glStencilFunc = (PFNGLSTENCILFUNCPROC)load("glStencilFunc");
glad_glStencilMask = (PFNGLSTENCILMASKPROC)load("glStencilMask");
glad_glStencilOp = (PFNGLSTENCILOPPROC)load("glStencilOp");
glad_glTexCoordPointer = (PFNGLTEXCOORDPOINTERPROC)load("glTexCoordPointer");
glad_glTexEnvi = (PFNGLTEXENVIPROC)load("glTexEnvi");
glad_glTexEnvx = (PFNGLTEXENVXPROC)load("glTexEnvx");
glad_glTexEnviv = (PFNGLTEXENVIVPROC)load("glTexEnviv");
glad_glTexEnvxv = (PFNGLTEXENVXVPROC)load("glTexEnvxv");
glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC)load("glTexImage2D");
glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC)load("glTexParameteri");
glad_glTexParameterx = (PFNGLTEXPARAMETERXPROC)load("glTexParameterx");
glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC)load("glTexParameteriv");
glad_glTexParameterxv = (PFNGLTEXPARAMETERXVPROC)load("glTexParameterxv");
glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC)load("glTexSubImage2D");
glad_glTranslatex = (PFNGLTRANSLATEXPROC)load("glTranslatex");
glad_glVertexPointer = (PFNGLVERTEXPOINTERPROC)load("glVertexPointer");
glad_glViewport = (PFNGLVIEWPORTPROC)load("glViewport");
}
static void load_GL_EXT_discard_framebuffer(GLADloadproc load) {
if(!GLAD_GL_EXT_discard_framebuffer) return;
glad_glDiscardFramebufferEXT = (PFNGLDISCARDFRAMEBUFFEREXTPROC)load("glDiscardFramebufferEXT");
}
static void load_GL_OES_framebuffer_object(GLADloadproc load) {
if(!GLAD_GL_OES_framebuffer_object) return;
glad_glIsRenderbufferOES = (PFNGLISRENDERBUFFEROESPROC)load("glIsRenderbufferOES");
glad_glBindRenderbufferOES = (PFNGLBINDRENDERBUFFEROESPROC)load("glBindRenderbufferOES");
glad_glDeleteRenderbuffersOES = (PFNGLDELETERENDERBUFFERSOESPROC)load("glDeleteRenderbuffersOES");
glad_glGenRenderbuffersOES = (PFNGLGENRENDERBUFFERSOESPROC)load("glGenRenderbuffersOES");
glad_glRenderbufferStorageOES = (PFNGLRENDERBUFFERSTORAGEOESPROC)load("glRenderbufferStorageOES");
glad_glGetRenderbufferParameterivOES = (PFNGLGETRENDERBUFFERPARAMETERIVOESPROC)load("glGetRenderbufferParameterivOES");
glad_glIsFramebufferOES = (PFNGLISFRAMEBUFFEROESPROC)load("glIsFramebufferOES");
glad_glBindFramebufferOES = (PFNGLBINDFRAMEBUFFEROESPROC)load("glBindFramebufferOES");
glad_glDeleteFramebuffersOES = (PFNGLDELETEFRAMEBUFFERSOESPROC)load("glDeleteFramebuffersOES");
glad_glGenFramebuffersOES = (PFNGLGENFRAMEBUFFERSOESPROC)load("glGenFramebuffersOES");
glad_glCheckFramebufferStatusOES = (PFNGLCHECKFRAMEBUFFERSTATUSOESPROC)load("glCheckFramebufferStatusOES");
glad_glFramebufferRenderbufferOES = (PFNGLFRAMEBUFFERRENDERBUFFEROESPROC)load("glFramebufferRenderbufferOES");
glad_glFramebufferTexture2DOES = (PFNGLFRAMEBUFFERTEXTURE2DOESPROC)load("glFramebufferTexture2DOES");
glad_glGetFramebufferAttachmentParameterivOES = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVOESPROC)load("glGetFramebufferAttachmentParameterivOES");
glad_glGenerateMipmapOES = (PFNGLGENERATEMIPMAPOESPROC)load("glGenerateMipmapOES");
}
static int find_extensionsGLES1(void) {
if (!get_exts()) return 0;
GLAD_GL_EXT_discard_framebuffer = has_ext("GL_EXT_discard_framebuffer");
GLAD_GL_OES_framebuffer_object = has_ext("GL_OES_framebuffer_object");
GLAD_GL_OES_texture_npot = has_ext("GL_OES_texture_npot");
free_exts();
return 1;
}
static void find_coreGLES1(void) {
/* Thank you @elmindreda
* https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176
* https://github.com/glfw/glfw/blob/master/src/context.c#L36
*/
int i, major, minor;
const char* version;
const char* prefixes[] = {
"OpenGL ES-CM ",
"OpenGL ES-CL ",
"OpenGL ES ",
NULL
};
version = (const char*) glGetString(GL_VERSION);
if (!version) return;
for (i = 0; prefixes[i]; i++) {
const size_t length = strlen(prefixes[i]);
if (strncmp(version, prefixes[i], length) == 0) {
version += length;
break;
}
}
/* PR #18 */
#ifdef _MSC_VER
sscanf_s(version, "%d.%d", &major, &minor);
#else
sscanf(version, "%d.%d", &major, &minor);
#endif
GLVersion.major = major; GLVersion.minor = minor;
max_loaded_major = major; max_loaded_minor = minor;
GLAD_GL_VERSION_ES_CM_1_0 = (major == 1 && minor >= 0) || major > 1;
if (GLVersion.major > 1 || (GLVersion.major >= 1 && GLVersion.minor >= 0)) {
max_loaded_major = 1;
max_loaded_minor = 0;
}
}
int gladLoadGLES1Loader(GLADloadproc load) {
GLVersion.major = 0; GLVersion.minor = 0;
glGetString = (PFNGLGETSTRINGPROC)load("glGetString");
if(glGetString == NULL) return 0;
if(glGetString(GL_VERSION) == NULL) return 0;
find_coreGLES1();
load_GL_VERSION_ES_CM_1_0(load);
if (!find_extensionsGLES1()) return 0;
load_GL_EXT_discard_framebuffer(load);
load_GL_OES_framebuffer_object(load);
return GLVersion.major != 0 || GLVersion.minor != 0;
}

View file

@ -34,22 +34,32 @@
#include "../../ref_shared.h" #include "../../ref_shared.h"
#include "qgl.h" #include "qgl.h"
#ifdef YQ2_GL1_GLES
#define REF_VERSION "Yamagi Quake II OpenGL ES1 Refresher"
#define GL_COLOR_INDEX GL_RGBA
#define GL_COLOR_INDEX8_EXT GL_RGBA
#else
#define REF_VERSION "Yamagi Quake II OpenGL Refresher"
#ifndef GL_COLOR_INDEX8_EXT #ifndef GL_COLOR_INDEX8_EXT
#define GL_COLOR_INDEX8_EXT GL_COLOR_INDEX #define GL_COLOR_INDEX8_EXT GL_COLOR_INDEX
#endif
#endif #endif
#define MAX_LIGHTMAPS 256 #define MAX_LIGHTMAPS 256
#define MAX_LIGHTMAP_COPIES 3 // Meant for tile / deferred rendering platforms
#define MAX_SCRAPS 1 #define MAX_SCRAPS 1
#define TEXNUM_LIGHTMAPS 1024 #define TEXNUM_LIGHTMAPS 1024
#define TEXNUM_SCRAPS (TEXNUM_LIGHTMAPS + MAX_LIGHTMAPS) #define TEXNUM_SCRAPS (TEXNUM_LIGHTMAPS + MAX_LIGHTMAPS * MAX_LIGHTMAP_COPIES)
#define TEXNUM_IMAGES (TEXNUM_SCRAPS + MAX_SCRAPS) #define TEXNUM_IMAGES (TEXNUM_SCRAPS + MAX_SCRAPS)
#define BLOCK_WIDTH 256 // default values; now defined in glstate_t #define BLOCK_WIDTH 256 // default values; now defined in glstate_t
#define BLOCK_HEIGHT 256 #define BLOCK_HEIGHT 256
#define REF_VERSION "Yamagi Quake II OpenGL Refresher"
#define MAX_TEXTURE_UNITS 2 #define MAX_TEXTURE_UNITS 2
#define GL_LIGHTMAP_FORMAT GL_RGBA #define GL_LIGHTMAP_FORMAT GL_RGBA
// GL buffer definitions
#define MAX_VERTICES 16384
#define MAX_INDICES (MAX_VERTICES * 4)
extern viddef_t vid; extern viddef_t vid;
@ -97,10 +107,29 @@ typedef enum
buf_shadow buf_shadow
} buffered_draw_t; } buffered_draw_t;
typedef struct // 832k aprox.
{
buffered_draw_t type;
GLfloat
vtx[MAX_VERTICES * 3], // vertexes
tex[MAX_TEXTURE_UNITS][MAX_VERTICES * 2], // texture coords
clr[MAX_VERTICES * 4]; // color components
GLushort idx[MAX_INDICES]; // indices for the draw call
GLuint vt, tx, cl; // indices for GLfloat arrays above
int texture[MAX_TEXTURE_UNITS];
int flags; // entity flags
float alpha;
} glbuffer_t;
#include "model.h" #include "model.h"
void R_SetDefaultState(void); void R_SetDefaultState(void);
extern glbuffer_t gl_buf;
extern float gldepthmin, gldepthmax; extern float gldepthmin, gldepthmax;
extern image_t gltextures[MAX_TEXTURES]; extern image_t gltextures[MAX_TEXTURES];
@ -266,16 +295,35 @@ void R_TextureAlphaMode(const char *string);
void R_TextureSolidMode(const char *string); void R_TextureSolidMode(const char *string);
int Scrap_AllocBlock(int w, int h, int *x, int *y); int Scrap_AllocBlock(int w, int h, int *x, int *y);
// GL buffer operations
#define GLBUFFER_VERTEX(X, Y, Z) \
gl_buf.vtx[gl_buf.vt] = X; gl_buf.vtx[gl_buf.vt+1] = Y; \
gl_buf.vtx[gl_buf.vt+2] = Z; gl_buf.vt += 3;
#define GLBUFFER_SINGLETEX(S, T) \
gl_buf.tex[0][gl_buf.tx] = S; gl_buf.tex[0][gl_buf.tx+1] = T; gl_buf.tx += 2;
#define GLBUFFER_MULTITEX(CS, CT, LS, LT) \
gl_buf.tex[0][gl_buf.tx] = CS; gl_buf.tex[0][gl_buf.tx+1] = CT; \
gl_buf.tex[1][gl_buf.tx] = LS; gl_buf.tex[1][gl_buf.tx+1] = LT; gl_buf.tx += 2;
#define GLBUFFER_COLOR(R, G, B, A) \
gl_buf.clr[gl_buf.cl] = R; gl_buf.clr[gl_buf.cl+1] = G; \
gl_buf.clr[gl_buf.cl+2] = B; gl_buf.clr[gl_buf.cl+3] = A; gl_buf.cl += 4;
void R_ApplyGLBuffer(void); void R_ApplyGLBuffer(void);
void R_UpdateGLBuffer(buffered_draw_t type, int colortex, int lighttex, int flags, float alpha); void R_UpdateGLBuffer(buffered_draw_t type, int colortex, int lighttex, int flags, float alpha);
void R_Buffer2DQuad(GLfloat ul_vx, GLfloat ul_vy, GLfloat dr_vx, GLfloat dr_vy, void R_Buffer2DQuad(GLfloat ul_vx, GLfloat ul_vy, GLfloat dr_vx, GLfloat dr_vy,
GLfloat ul_tx, GLfloat ul_ty, GLfloat dr_tx, GLfloat dr_ty); GLfloat ul_tx, GLfloat ul_ty, GLfloat dr_tx, GLfloat dr_ty);
void R_SetBufferIndices(GLenum type, GLuint vertices_num); void R_SetBufferIndices(GLenum type, GLuint vertices_num);
void R_BufferVertex(GLfloat x, GLfloat y, GLfloat z);
void R_BufferSingleTex(GLfloat s, GLfloat t);
void R_BufferMultiTex(GLfloat cs, GLfloat ct, GLfloat ls, GLfloat lt);
void R_BufferColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a);
#ifdef YQ2_GL1_GLES
#define glPolygonMode(...)
#define glFrustum(...) glFrustumf(__VA_ARGS__)
#define glDepthRange(...) glDepthRangef(__VA_ARGS__)
#define glOrtho(...) glOrthof(__VA_ARGS__)
#else
#ifdef DEBUG #ifdef DEBUG
void glCheckError_(const char *file, const char *function, int line); void glCheckError_(const char *file, const char *function, int line);
// Ideally, the following list should contain all OpenGL calls. // Ideally, the following list should contain all OpenGL calls.
@ -325,6 +373,7 @@ void glCheckError_(const char *file, const char *function, int line);
#define glBegin(...) glBegin(__VA_ARGS__); glCheckError_(__FILE__, __func__, __LINE__) #define glBegin(...) glBegin(__VA_ARGS__); glCheckError_(__FILE__, __func__, __LINE__)
#define glEnd() glEnd(); glCheckError_(__FILE__, __func__, __LINE__) #define glEnd() glEnd(); glCheckError_(__FILE__, __func__, __LINE__)
#endif #endif
#endif
/* /*
* GL config stuff * GL config stuff
@ -347,6 +396,8 @@ typedef struct
qboolean palettedtexture; qboolean palettedtexture;
qboolean pointparameters; qboolean pointparameters;
qboolean multitexture; qboolean multitexture;
qboolean lightmapcopies; // many copies of same lightmap, for embedded
qboolean discardfb;
// ---- // ----

View file

@ -33,12 +33,16 @@
#include <windows.h> #include <windows.h>
#endif #endif
#ifdef YQ2_GL1_GLES
#include "../glad-gles1/include/glad/glad.h"
#else
#if defined(__APPLE__) #if defined(__APPLE__)
#define GL_SILENCE_DEPRECATION #define GL_SILENCE_DEPRECATION
#include <OpenGL/gl.h> #include <OpenGL/gl.h>
#else #else
#include <GL/gl.h> #include <GL/gl.h>
#endif #endif
#endif
#ifndef APIENTRY #ifndef APIENTRY
#define APIENTRY #define APIENTRY
@ -93,5 +97,7 @@ extern void ( APIENTRY *qglColorTableEXT ) ( GLenum, GLenum, GLsizei, GLenum,
GLenum, const GLvoid * ); GLenum, const GLvoid * );
extern void ( APIENTRY *qglActiveTexture ) ( GLenum texture ); extern void ( APIENTRY *qglActiveTexture ) ( GLenum texture );
extern void ( APIENTRY *qglClientActiveTexture ) ( GLenum texture ); extern void ( APIENTRY *qglClientActiveTexture ) ( GLenum texture );
extern void ( APIENTRY *qglDiscardFramebufferEXT ) ( GLenum target,
GLsizei numAttachments, const GLenum *attachments );
#endif #endif

View file

@ -44,6 +44,8 @@ void (APIENTRY *qglColorTableEXT)(GLenum, GLenum, GLsizei, GLenum, GLenum,
const GLvoid *); const GLvoid *);
void (APIENTRY *qglActiveTexture) (GLenum texture); void (APIENTRY *qglActiveTexture) (GLenum texture);
void (APIENTRY *qglClientActiveTexture) (GLenum texture); void (APIENTRY *qglClientActiveTexture) (GLenum texture);
void (APIENTRY *qglDiscardFramebufferEXT) (GLenum target,
GLsizei numAttachments, const GLenum *attachments);
/* ========================================================================= */ /* ========================================================================= */
@ -54,6 +56,7 @@ static void QGL_EXT_Reset ( void )
qglColorTableEXT = NULL; qglColorTableEXT = NULL;
qglActiveTexture = NULL; qglActiveTexture = NULL;
qglClientActiveTexture = NULL; qglClientActiveTexture = NULL;
qglDiscardFramebufferEXT = NULL;
} }
/* ========================================================================= */ /* ========================================================================= */

View file

@ -538,10 +538,11 @@ VID_CheckChanges(void)
// Mkay, let's try our luck. // Mkay, let's try our luck.
while (!VID_LoadRenderer()) while (!VID_LoadRenderer())
{ {
// We try: custom -> gl3 -> gles3 -> gl1 -> soft. // We try: custom -> gl3 -> gles3 -> gl1 -> gles1 -> soft.
if ((strcmp(vid_renderer->string, "gl3") != 0) && if ((strcmp(vid_renderer->string, "gl3") != 0) &&
(strcmp(vid_renderer->string, "gles3") != 0) && (strcmp(vid_renderer->string, "gles3") != 0) &&
(strcmp(vid_renderer->string, "gl1") != 0) && (strcmp(vid_renderer->string, "gl1") != 0) &&
(strcmp(vid_renderer->string, "gles1") != 0) &&
(strcmp(vid_renderer->string, "soft") != 0)) (strcmp(vid_renderer->string, "soft") != 0))
{ {
Com_Printf("Retrying with gl3...\n"); Com_Printf("Retrying with gl3...\n");
@ -558,6 +559,11 @@ VID_CheckChanges(void)
Cvar_Set("vid_renderer", "gl1"); Cvar_Set("vid_renderer", "gl1");
} }
else if (strcmp(vid_renderer->string, "gl1") == 0) else if (strcmp(vid_renderer->string, "gl1") == 0)
{
Com_Printf("Retrying with gles1...\n");
Cvar_Set("vid_renderer", "gles1");
}
else if (strcmp(vid_renderer->string, "gles1") == 0)
{ {
Com_Printf("Retrying with soft...\n"); Com_Printf("Retrying with soft...\n");
Cvar_Set("vid_renderer", "soft"); Cvar_Set("vid_renderer", "soft");