diff --git a/Makefile b/Makefile index 3e7786a1..3dafadb2 100644 --- a/Makefile +++ b/Makefile @@ -2677,6 +2677,10 @@ ifneq ($(BUILD_CLIENT),0) ifneq ($(BUILD_RENDERER_OPENGL2),0) $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/renderer_opengl2_$(SHLIBNAME) $(COPYBINDIR)/renderer_opengl2_$(SHLIBNAME) endif + else + ifneq ($(BUILD_RENDERER_OPENGL2),0) + $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/$(CLIENTBIN)_opengl2$(FULLBINEXT) $(COPYBINDIR)/$(CLIENTBIN)_opengl2$(FULLBINEXT) + endif endif endif diff --git a/README b/README.md similarity index 55% rename from README rename to README.md index 1f4cf49c..35b72fe3 100644 --- a/README +++ b/README.md @@ -39,7 +39,7 @@ renamed to id-readme.txt so as to prevent confusion. Please refer to the web-site for updated status. ---------------------------------------------- Compilation and installation ----- +# Compilation and installation For *nix 1. Change to the directory containing this readme. @@ -73,6 +73,7 @@ x86_64. The following variables may be set, either on the command line or in Makefile.local: +``` CFLAGS - use this for custom CFLAGS V - set to show cc command line when building DEFAULT_BASEDIR - extra path to search for baseq3 and such @@ -108,13 +109,16 @@ Makefile.local: DEBUG_CFLAGS - C compiler flags to use for building debug version COPYDIR - the target installation directory TEMPDIR - specify user defined directory for temp files +``` The defaults for these variables differ depending on the target platform. ------------------------------------------------------------------- Console ----- +# Console -New cvars +## New cvars + +``` cl_autoRecordDemo - record a new demo on each map change cl_aviFrameRate - the framerate to use when capturing video cl_aviMotionJpeg - use the mjpeg codec when capturing video @@ -271,8 +275,11 @@ New cvars cl_aviMotionJpeg is enabled r_mode -2 - This new video mode automatically uses the desktop resolution. +``` -New commands +## New commands + +``` video [filename] - start video capture (use with demo command) stopvideo - stop video capture stopmusic - stop background music @@ -307,132 +314,150 @@ New commands all bots even if someone is named "allbots") tell - send message to a single client (new to server) +``` ---------------------------------------------------------- README for Users ----- +# README for Users -Using shared libraries instead of qvm - To force Q3 to use shared libraries instead of qvms run it with the following - parameters: +set sv_pure 0 +set vm_cgame 0 +set vm_game 0 +set vm_ui 0 +## Using shared libraries instead of qvm -Using Demo Data Files - Copy demoq3/pak0.pk3 from the demo installer to your baseq3 directory. The - qvm files in this pak0.pk3 will not work, so you have to use the native - shared libraries or qvms from this project. To use the new qvms, they must be - put into a pk3 file. A pk3 file is just a zip file, so any compression tool - that can create such files will work. The shared libraries should already be - in the correct place. Use the instructions above to use them. +To force Q3 to use shared libraries instead of qvms run it with the following +parameters: `+set sv_pure 0 +set vm_cgame 0 +set vm_game 0 +set vm_ui 0` - Please bear in mind that you will not be able to play online using the demo - data, nor is it something that we like to spend much time maintaining or - supporting. +## Using Demo Data Files -Help! Ioquake3 won't give me an fps of X anymore when setting com_maxfps! - Ioquake3 now uses the select() system call to wait for the rendering of the - next frame when com_maxfps was hit. This will improve your CPU load - considerably in these cases. However, not all systems may support a - granularity for its timing functions that is required to perform this waiting - correctly. For instance, ioquake3 tells select() to wait 2 milliseconds, but - really it can only wait for a multiple of 5ms, i.e. 5, 10, 15, 20... ms. - In this case you can always revert back to the old behaviour by setting the - cvar com_busyWait to 1. +Copy demoq3/pak0.pk3 from the demo installer to your baseq3 directory. The +qvm files in this pak0.pk3 will not work, so you have to use the native +shared libraries or qvms from this project. To use the new qvms, they must be +put into a pk3 file. A pk3 file is just a zip file, so any compression tool +that can create such files will work. The shared libraries should already be +in the correct place. Use the instructions above to use them. -Using HTTP/FTP Download Support (Server) - You can enable redirected downloads on your server even if it's not - an ioquake3 server. You simply need to use the 'sets' command to put - the sv_dlURL cvar into your SERVERINFO string and ensure sv_allowDownloads - is set to 1 +Please bear in mind that you will not be able to play online using the demo +data, nor is it something that we like to spend much time maintaining or +supporting. - sv_dlURL is the base of the URL that contains your custom .pk3 files - the client will append both fs_game and the filename to the end of - this value. For example, if you have sv_dlURL set to - "http://ioquake3.org", fs_game is "baseq3", and the client is - missing "test.pk3", it will attempt to download from the URL - "http://ioquake3.org/baseq3/test.pk3" +## Help! Ioquake3 won't give me an fps of X anymore when setting com_maxfps! - sv_allowDownload's value is now a bitmask made up of the following - flags: - 1 - ENABLE - 4 - do not use UDP downloads - 8 - do not ask the client to disconnect when using HTTP/FTP +Ioquake3 now uses the select() system call to wait for the rendering of the +next frame when com_maxfps was hit. This will improve your CPU load +considerably in these cases. However, not all systems may support a +granularity for its timing functions that is required to perform this waiting +correctly. For instance, ioquake3 tells select() to wait 2 milliseconds, but +really it can only wait for a multiple of 5ms, i.e. 5, 10, 15, 20... ms. +In this case you can always revert back to the old behaviour by setting the +cvar com_busyWait to 1. - Server operators who are concerned about potential "leeching" from their - HTTP servers from other ioquake3 servers can make use of the HTTP_REFERER - that ioquake3 sets which is "ioQ3://{SERVER_IP}:{SERVER_PORT}". For, - example, Apache's mod_rewrite can restrict access based on HTTP_REFERER. +## Using HTTP/FTP Download Support (Server) - On a sidenote, downloading via UDP has been improved and yields higher data - rates now. You can configure the maximum bandwidth for UDP downloads via the - cvar sv_dlRate. Due to system-specific limits the download rate is capped - at about 1 Mbyte/s per client, so curl downloading may still be faster. +You can enable redirected downloads on your server even if it's not +an ioquake3 server. You simply need to use the 'sets' command to put +the sv_dlURL cvar into your SERVERINFO string and ensure sv_allowDownloads +is set to 1 -Using HTTP/FTP Download Support (Client) - Simply setting cl_allowDownload to 1 will enable HTTP/FTP downloads - assuming ioquake3 was compiled with USE_CURL=1 (the default). - like sv_allowDownload, cl_allowDownload also uses a bitmask value - supporting the following flags: - 1 - ENABLE - 2 - do not use HTTP/FTP downloads - 4 - do not use UDP downloads +sv_dlURL is the base of the URL that contains your custom .pk3 files +the client will append both fs_game and the filename to the end of +this value. For example, if you have sv_dlURL set to +`"http://ioquake3.org"`, fs_game is `"baseq3"`, and the client is +missing `"test.pk3"`, it will attempt to download from the URL +`"http://ioquake3.org/baseq3/test.pk3"` - When ioquake3 is built with USE_CURL_DLOPEN=1 (default on some platforms), - it will use the value of the cvar cl_cURLLib as the filename of the cURL - library to dynamically load. +sv_allowDownload's value is now a bitmask made up of the following +flags: -Multiuser Support on Windows systems - On Windows, all user specific files such as autogenerated configuration, - demos, videos, screenshots, and autodownloaded pk3s are now saved in a - directory specific to the user who is running ioquake3. + * 1 - ENABLE + * 4 - do not use UDP downloads + * 8 - do not ask the client to disconnect when using HTTP/FTP - On NT-based such as Windows XP, this is usually a directory named: - "C:\Documents and Settings\%USERNAME%\Application Data\Quake3\" +Server operators who are concerned about potential "leeching" from their +HTTP servers from other ioquake3 servers can make use of the HTTP_REFERER +that ioquake3 sets which is `"ioQ3://{SERVER_IP}:{SERVER_PORT}"`. For, +example, Apache's mod_rewrite can restrict access based on HTTP_REFERER. - Windows 95, Windows 98, and Windows ME will use a directory like: - "C:\Windows\Application Data\Quake3" - in single-user mode, or: - "C:\Windows\Profiles\%USERNAME%\Application Data\Quake3" - if multiple logins have been enabled. +On a sidenote, downloading via UDP has been improved and yields higher data +rates now. You can configure the maximum bandwidth for UDP downloads via the +cvar sv_dlRate. Due to system-specific limits the download rate is capped +at about 1 Mbyte/s per client, so curl downloading may still be faster. - In order to access this directory more easily, the installer may create a - Shortcut which has its target set to: - "%APPDATA%\Quake3\" - This Shortcut would work for all users on the system regardless of the - locale settings. Unfortunately, this environment variable is only - present on Windows NT based systems. +## Using HTTP/FTP Download Support (Client) + +Simply setting cl_allowDownload to 1 will enable HTTP/FTP downloads +assuming ioquake3 was compiled with USE_CURL=1 (the default). +like sv_allowDownload, cl_allowDownload also uses a bitmask value +supporting the following flags: + + * 1 - ENABLE + * 2 - do not use HTTP/FTP downloads + * 4 - do not use UDP downloads + +When ioquake3 is built with USE_CURL_DLOPEN=1 (default on some platforms), +it will use the value of the cvar cl_cURLLib as the filename of the cURL +library to dynamically load. + +## Multiuser Support on Windows systems +On Windows, all user specific files such as autogenerated configuration, +demos, videos, screenshots, and autodownloaded pk3s are now saved in a +directory specific to the user who is running ioquake3. + +On NT-based such as Windows XP, this is usually a directory named: + + C:\Documents and Settings\%USERNAME%\Application Data\Quake3\ + +Windows 95, Windows 98, and Windows ME will use a directory like: + + C:\Windows\Application Data\Quake3 + +in single-user mode, or: + + C:\Windows\Profiles\%USERNAME%\Application Data\Quake3 + +if multiple logins have been enabled. + +In order to access this directory more easily, the installer may create a +Shortcut which has its target set to: + + %APPDATA%\Quake3\ + +This Shortcut would work for all users on the system regardless of the +locale settings. Unfortunately, this environment variable is only +present on Windows NT based systems. + +You can revert to the old single-user behaviour by setting the fs_homepath +cvar to the directory where ioquake3 is installed. For example: - You can revert to the old single-user behaviour by setting the fs_homepath - cvar to the directory where ioquake3 is installed. For example: ioquake3.exe +set fs_homepath "c:\ioquake3" - Note that this cvar MUST be set as a command line parameter. -SDL Keyboard Differences - ioquake3 clients have different keyboard behaviour compared to the original - Quake3 clients. +Note that this cvar MUST be set as a command line parameter. - * "Caps Lock" and "Num Lock" can not be used as normal binds since they +## SDL Keyboard Differences + +ioquake3 clients have different keyboard behaviour compared to the original +Quake3 clients. + + * "Caps Lock" and "Num Lock" can not be used as normal binds since they do not send a KEYUP event until the key is pressed again. - * SDL > 1.2.9 does not support disabling dead key recognition. In order to + * SDL > 1.2.9 does not support disabling dead key recognition. In order to send dead key characters (e.g. ~, ', `, and ^), you must key a Space (or sometimes the same character again) after the character to send it on many international keyboard layouts. - * The SDL client supports many more keys than the original Quake3 client. + * The SDL client supports many more keys than the original Quake3 client. For example the keys: "Windows", "SysReq", "ScrollLock", and "Break". For non-US keyboards, all of the so called "World" keys are now supported as well as F13, F14, F15, and the country-specific mode/meta keys. - On many international layouts the default console toggle keys are also dead - keys, meaning that dropping the console potentially results in - unintentionally initiating the keying of a dead key. Furthermore SDL 1.2's - dead key support is broken by design and Q3 doesn't support non-ASCII text - entry, so the chances are you won't get the correct character anyway. +On many international layouts the default console toggle keys are also dead +keys, meaning that dropping the console potentially results in +unintentionally initiating the keying of a dead key. Furthermore SDL 1.2's +dead key support is broken by design and Q3 doesn't support non-ASCII text +entry, so the chances are you won't get the correct character anyway. - If you use such a keyboard layout, you can set the cvar cl_consoleKeys. This - is a space delimited list of key names that will toggle the console. The key - names are the usual Q3 names e.g. "~", "`", "c", "BACKSPACE", "PAUSE", - "WINDOWS" etc. It's also possible to use ASCII characters, by hexadecimal - number. Some example values for cl_consoleKeys: +If you use such a keyboard layout, you can set the cvar cl_consoleKeys. This +is a space delimited list of key names that will toggle the console. The key +names are the usual Q3 names e.g. "~", "`", "c", "BACKSPACE", "PAUSE", +"WINDOWS" etc. It's also possible to use ASCII characters, by hexadecimal +number. Some example values for cl_consoleKeys: "~ ` 0x7e 0x60" Toggle on ~ or ` (the default) "WINDOWS" Toggle on the Windows key @@ -440,75 +465,79 @@ SDL Keyboard Differences "0x43" Toggle on the C character (Shift-c) "PAUSE F1 PGUP" Toggle on the Pause, F1 or Page Up keys - Note that when you elect a set of console keys or characters, they cannot - then be used for binding, nor will they generate characters when entering - text. Also, in addition to the nominated console keys, Shift-ESC is hard - coded to always toggle the console. +Note that when you elect a set of console keys or characters, they cannot +then be used for binding, nor will they generate characters when entering +text. Also, in addition to the nominated console keys, Shift-ESC is hard +coded to always toggle the console. -QuakeLive mouse acceleration (patch and this text written by TTimo from id) - I've been using an experimental mouse acceleration code for a while, and - decided to make it available to everyone. Don't be too worried if you don't - understand the explanations below, this is mostly intended for advanced - players: - To enable it, set cl_mouseAccelStyle 1 (0 is the default/legacy behavior) +## QuakeLive mouse acceleration +(patch and this text written by TTimo from id) - New style is controlled with 3 cvars: +I've been using an experimental mouse acceleration code for a while, and +decided to make it available to everyone. Don't be too worried if you don't +understand the explanations below, this is mostly intended for advanced +players: +To enable it, set cl_mouseAccelStyle 1 (0 is the default/legacy behavior) - sensitivity - cl_mouseAccel - cl_mouseAccelOffset +New style is controlled with 3 cvars: - The old code (cl_mouseAccelStyle 0) can be difficult to calibrate because if - you have a base sensitivity setup, as soon as you set a non zero acceleration - your base sensitivity at low speeds will change as well. The other problem - with style 0 is that you are stuck on a square (power of two) acceleration - curve. +sensitivity +cl_mouseAccel +cl_mouseAccelOffset - The new code tries to solve both problems: +The old code (cl_mouseAccelStyle 0) can be difficult to calibrate because if +you have a base sensitivity setup, as soon as you set a non zero acceleration +your base sensitivity at low speeds will change as well. The other problem +with style 0 is that you are stuck on a square (power of two) acceleration +curve. - Once you setup your sensitivity to feel comfortable and accurate enough for - low mouse deltas with no acceleration (cl_mouseAccel 0), you can start - increasing cl_mouseAccel and tweaking cl_mouseAccelOffset to get the - amplification you want for high deltas with little effect on low mouse deltas. +The new code tries to solve both problems: - cl_mouseAccel is a power value. Should be >= 1, 2 will be the same power curve - as style 0. The higher the value, the faster the amplification grows with the - mouse delta. +Once you setup your sensitivity to feel comfortable and accurate enough for +low mouse deltas with no acceleration (cl_mouseAccel 0), you can start +increasing cl_mouseAccel and tweaking cl_mouseAccelOffset to get the +amplification you want for high deltas with little effect on low mouse deltas. - cl_mouseAccelOffset sets how much base mouse delta will be doubled by - acceleration. The closer to zero you bring it, the more acceleration will - happen at low speeds. This is also very useful if you are changing to a new - mouse with higher dpi, if you go from 500 to 1000 dpi, you can divide your - cl_mouseAccelOffset by two to keep the same overall 'feel' (you will likely - gain in precision when you do that, but that is not related to mouse - acceleration). +cl_mouseAccel is a power value. Should be >= 1, 2 will be the same power curve +as style 0. The higher the value, the faster the amplification grows with the +mouse delta. - Mouse acceleration is tricky to configure, and when you do you'll have to - re-learn your aiming. But you will find that it's very much forth it in the - long run. +cl_mouseAccelOffset sets how much base mouse delta will be doubled by +acceleration. The closer to zero you bring it, the more acceleration will +happen at low speeds. This is also very useful if you are changing to a new +mouse with higher dpi, if you go from 500 to 1000 dpi, you can divide your +cl_mouseAccelOffset by two to keep the same overall 'feel' (you will likely +gain in precision when you do that, but that is not related to mouse +acceleration). - If you try the new acceleration code and start using it, I'd be very - interested by your feedback. +Mouse acceleration is tricky to configure, and when you do you'll have to +re-learn your aiming. But you will find that it's very much forth it in the +long run. + +If you try the new acceleration code and start using it, I'd be very +interested by your feedback. ----------------------------------------------------- README for Developers ----- +# README for Developers -pk3dir - ioquake3 has a useful new feature for mappers. Paths in a game directory with - the extension ".pk3dir" are treated like pk3 files. This means you can keep - all files specific to your map in one directory tree and easily zip this - folder for distribution. +## pk3dir -64bit mods - If you wish to compile external mods as shared libraries on a 64bit platform, - and the mod source is derived from the id Q3 SDK, you will need to modify the - interface code a little. Open the files ending in _syscalls.c and change - every instance of int to intptr_t in the declaration of the syscall function - pointer and the dllEntry function. Also find the vmMain function for each - module (usually in cg_main.c g_main.c etc.) and similarly replace the return - value in the prototype with intptr_t (arg0, arg1, ...stay int). +ioquake3 has a useful new feature for mappers. Paths in a game directory with +the extension ".pk3dir" are treated like pk3 files. This means you can keep +all files specific to your map in one directory tree and easily zip this +folder for distribution. - Add the following code snippet to q_shared.h: +## 64bit mods + +If you wish to compile external mods as shared libraries on a 64bit platform, +and the mod source is derived from the id Q3 SDK, you will need to modify the +interface code a little. Open the files ending in _syscalls.c and change +every instance of int to intptr_t in the declaration of the syscall function +pointer and the dllEntry function. Also find the vmMain function for each +module (usually in cg_main.c g_main.c etc.) and similarly replace the return +value in the prototype with intptr_t (arg0, arg1, ...stay int). + +Add the following code snippet to q_shared.h: #ifdef Q3_VM typedef int intptr_t; @@ -516,165 +545,173 @@ pk3dir #include #endif - Note if you simply wish to run mods on a 64bit platform you do not need to - recompile anything since by default Q3 uses a virtual machine system. +Note if you simply wish to run mods on a 64bit platform you do not need to +recompile anything since by default Q3 uses a virtual machine system. -Creating mods compatible with Q3 1.32b - If you're using this package to create mods for the last official release of - Q3, it is necessary to pass the commandline option '-vq3' to your invocation - of q3asm. This is because by default q3asm outputs an updated qvm format that - is necessary to fix a bug involving the optimizing pass of the x86 vm JIT - compiler. +## Creating mods compatible with Q3 1.32b -Creating standalone games - Have you finished the daunting task of removing all dependencies on the Q3 - game data? You probably now want to give your users the opportunity to play - the game without owning a copy of Q3, which consequently means removing cd-key - and authentication server checks. In addition to being a straightforward Q3 - client, ioquake3 also purports to be a reliable and stable code base on which - to base your game project. +If you're using this package to create mods for the last official release of +Q3, it is necessary to pass the commandline option '-vq3' to your invocation +of q3asm. This is because by default q3asm outputs an updated qvm format that +is necessary to fix a bug involving the optimizing pass of the x86 vm JIT +compiler. - However, before you start compiling your own version of ioquake3, you have to - ask yourself: Have we changed or will we need to change anything of importance - in the engine? +## Creating standalone games - If your answer to this question is "no", it probably makes no sense to build - your own binaries. Instead, you can just use the pre-built binaries on the - website. Just make sure the game is called with: +Have you finished the daunting task of removing all dependencies on the Q3 +game data? You probably now want to give your users the opportunity to play +the game without owning a copy of Q3, which consequently means removing cd-key +and authentication server checks. In addition to being a straightforward Q3 +client, ioquake3 also purports to be a reliable and stable code base on which +to base your game project. + +However, before you start compiling your own version of ioquake3, you have to +ask yourself: Have we changed or will we need to change anything of importance +in the engine? + +If your answer to this question is "no", it probably makes no sense to build +your own binaries. Instead, you can just use the pre-built binaries on the +website. Just make sure the game is called with: +set com_basegame - in any links/scripts you install for your users to start the game. The - binary must not detect any original quake3 game pak files. If this - condition is met, the game will set com_standalone to 1 and is then running - in stand alone mode. - - If you want the engine to use a different directory in your homepath than - e.g. "Quake3" on Windows or ".q3a" on Linux, then set a new name at startup - by adding +in any links/scripts you install for your users to start the game. The +binary must not detect any original quake3 game pak files. If this +condition is met, the game will set com_standalone to 1 and is then running +in stand alone mode. +If you want the engine to use a different directory in your homepath than +e.g. "Quake3" on Windows or ".q3a" on Linux, then set a new name at startup +by adding + +set com_homepath - - to the command line. You can also control which game name to use when talking - to the master server: - + +to the command line. You can also control which game name to use when talking +to the master server: + +set com_gamename - - So clients requesting a server list will only receive servers that have a - matching game name. - - Example line: - + +So clients requesting a server list will only receive servers that have a +matching game name. + +Example line: + +set com_basegame basefoo +set com_homepath .foo +set com_gamename foo +If you really changed parts that would make vanilla ioquake3 incompatible with +your mod, we have included another way to conveniently build a stand-alone +binary. Just run make with the option BUILD_STANDALONE=1. Don't forget to edit +the PRODUCT_NAME and subsequent #defines in qcommon/q_shared.h with +information appropriate for your project. - If you really changed parts that would make vanilla ioquake3 incompatible with - your mod, we have included another way to conveniently build a stand-alone - binary. Just run make with the option BUILD_STANDALONE=1. Don't forget to edit - the PRODUCT_NAME and subsequent #defines in qcommon/q_shared.h with - information appropriate for your project. +## Standalone game licensing - While a lot of work has been put into ioquake3 that you can benefit from free - of charge, it does not mean that you have no obligations to fulfill. Please be - aware that as soon as you start distributing your game with an engine based on - our sources we expect you to fully comply with the requirements as stated in - the GPL. That includes making sources and modifications you made to the - ioquake3 engine as well as the game-code used to compile the .qvm files for - the game logic freely available to everyone. Furthermore, note that the "QIIIA - Game Source License" prohibits distribution of mods that are intended to - operate on a version of Q3 not sanctioned by id software: +While a lot of work has been put into ioquake3 that you can benefit from free +of charge, it does not mean that you have no obligations to fulfill. Please be +aware that as soon as you start distributing your game with an engine based on +our sources we expect you to fully comply with the requirements as stated in +the GPL. That includes making sources and modifications you made to the +ioquake3 engine as well as the game-code used to compile the .qvm files for +the game logic freely available to everyone. Furthermore, note that the "QIIIA +Game Source License" prohibits distribution of mods that are intended to +operate on a version of Q3 not sanctioned by id software: "with this Agreement, ID grants to you the non-exclusive and limited right to distribute copies of the Software ... for operation only with the full version of the software game QUAKE III ARENA" - This means that if you're creating a standalone game, you cannot use said - license on any portion of the product. As the only other license this code has - been released under is the GPL, this is the only option. +This means that if you're creating a standalone game, you cannot use said +license on any portion of the product. As the only other license this code has +been released under is the GPL, this is the only option. - This does NOT mean that you cannot market this game commercially. The GPL does - not prohibit commercial exploitation and all assets (e.g. textures, sounds, - maps) created by yourself are your property and can be sold like every other - game you find in stores. +This does NOT mean that you cannot market this game commercially. The GPL does +not prohibit commercial exploitation and all assets (e.g. textures, sounds, +maps) created by yourself are your property and can be sold like every other +game you find in stores. -Network protocols - There are now two cvars that give you some degree of freedom over the reported - protocol versions between clients and servers: "com_protocol" and - "com_legacyprotocol". - The reason for this is that some standalone games increased the protocol - number even though nothing really changed in their protocol and the ioquake3 - engine is still fully compatible. +## Network protocols - In order to harden the network protocol against UDP spoofing attacks a new - network protocol was introduced that defends against such attacks. - Unfortunately, this protocol will be incompatible to the original quake3 1.32c - which is the latest official release from id. - Luckily, ioquake3 has backwards compatibility, on the client as well as on the - server. This means ioquake3 players can play on old servers just as ioquake3 - servers are able to service old clients. +There are now two cvars that give you some degree of freedom over the reported +protocol versions between clients and servers: "com_protocol" and +"com_legacyprotocol". +The reason for this is that some standalone games increased the protocol +number even though nothing really changed in their protocol and the ioquake3 +engine is still fully compatible. - The cvar "com_protocol" denotes the protocol version for the new hardened - protocol, whereas the "com_legacyprotocol" cvar denotes the protocol version - for the legacy protocol. - If the value for "com_protocol" and "com_legacyprotocol" is identical, then - the legacy protocol is always used. If "com_legacyprotocol" is set to 0, then - support for the legacy protocol is disabled. - - Mods that use a standalone engine obviously do not require dual protocol - support, and it is turned off if the engine is compiled with STANDALONE per - default. If you desire backwards compatibility to older versions of your - game you can still enable it in q_shared.h by defining - LEGACY_PROTOCOL. +In order to harden the network protocol against UDP spoofing attacks a new +network protocol was introduced that defends against such attacks. +Unfortunately, this protocol will be incompatible to the original quake3 1.32c +which is the latest official release from id. +Luckily, ioquake3 has backwards compatibility, on the client as well as on the +server. This means ioquake3 players can play on old servers just as ioquake3 +servers are able to service old clients. -cl_guid Support - cl_guid is a cvar which is part of the client's USERINFO string. Its value - is a 32 character string made up of [a-f] and [0-9] characters. This - value is pseudo-unique for every player. Id's Quake 3 Arena client also - sets cl_guid, but only if Punkbuster is enabled on the client. +The cvar "com_protocol" denotes the protocol version for the new hardened +protocol, whereas the "com_legacyprotocol" cvar denotes the protocol version +for the legacy protocol. +If the value for "com_protocol" and "com_legacyprotocol" is identical, then +the legacy protocol is always used. If "com_legacyprotocol" is set to 0, then +support for the legacy protocol is disabled. - If cl_guidServerUniq is non-zero (the default), then this value is also - pseudo-unique for each server a client connects to (based on IP:PORT of - the server). +Mods that use a standalone engine obviously do not require dual protocol +support, and it is turned off if the engine is compiled with STANDALONE per +default. If you desire backwards compatibility to older versions of your +game you can still enable it in q_shared.h by defining +LEGACY_PROTOCOL. - The purpose of cl_guid is to add an identifier for each player on - a server. This value can be reset by the client at any time so it's not - useful for blocking access. However, it can have at least two uses in - your mod's game code: - 1) improve logging to allow statistical tools to index players by more +## cl_guid Support + +cl_guid is a cvar which is part of the client's USERINFO string. Its value +is a 32 character string made up of [a-f] and [0-9] characters. This +value is pseudo-unique for every player. Id's Quake 3 Arena client also +sets cl_guid, but only if Punkbuster is enabled on the client. + +If cl_guidServerUniq is non-zero (the default), then this value is also +pseudo-unique for each server a client connects to (based on IP:PORT of +the server). + +The purpose of cl_guid is to add an identifier for each player on +a server. This value can be reset by the client at any time so it's not +useful for blocking access. However, it can have at least two uses in +your mod's game code: + + 1. improve logging to allow statistical tools to index players by more than just name - 2) granting some weak admin rights to players without requiring passwords + 2. granting some weak admin rights to players without requiring passwords -PNG support - ioquake3 supports the use of PNG (Portable Network Graphic) images as - textures. It should be noted that the use of such images in a map will - result in missing placeholder textures where the map is used with the id - Quake 3 client or earlier versions of ioquake3. +## PNG support - Recent versions of GtkRadiant and q3map2 support PNG images without - modification. However GtkRadiant is not aware that PNG textures are supported - by ioquake3. To change this behaviour open the file 'q3.game' in the 'games' - directory of the GtkRadiant base directory with an editor and change the - line: +ioquake3 supports the use of PNG (Portable Network Graphic) images as +textures. It should be noted that the use of such images in a map will +result in missing placeholder textures where the map is used with the id +Quake 3 client or earlier versions of ioquake3. + +Recent versions of GtkRadiant and q3map2 support PNG images without +modification. However GtkRadiant is not aware that PNG textures are supported +by ioquake3. To change this behaviour open the file 'q3.game' in the 'games' +directory of the GtkRadiant base directory with an editor and change the +line: texturetypes="tga jpg" - to +to texturetypes="tga jpg png" - Restart GtkRadiant and PNG textures are now available. +Restart GtkRadiant and PNG textures are now available. -Building with MinGW for pre Windows XP - IPv6 support requires a header named "wspiapi.h" to abstract away from - differences in earlier versions of Windows' IPv6 stack. There is no MinGW - equivalent of this header and the Microsoft version is obviously not - redistributable, so in its absence we're forced to require Windows XP. - However if this header is acquired separately and placed in the qcommon/ - directory, this restriction is lifted. +## Building with MinGW for pre Windows XP + +IPv6 support requires a header named "wspiapi.h" to abstract away from +differences in earlier versions of Windows' IPv6 stack. There is no MinGW +equivalent of this header and the Microsoft version is obviously not +redistributable, so in its absence we're forced to require Windows XP. +However if this header is acquired separately and placed in the qcommon/ +directory, this restriction is lifted. -------------------------------------------------------------- Contributing ----- +# Contributing Please send all patches to bugzilla (https://bugzilla.icculus.org), or join the mailing list (http://lists.ioquake.org/listinfo.cgi/ioquake3-ioquake.org) and @@ -689,7 +726,7 @@ accepted as long as they are entirely optional, do not require new media and are off by default. ---------------------------------------------- Building Official Installers ----- +# Building Official Installers We need help getting automated installers on all the platforms that ioquake3 supports. We don't necessarily care about all the installers being identical, @@ -722,22 +759,28 @@ but we have some general guidelines: * Your installer will be mirrored to an "official" directory, thus making it a done deal. ------------------------------------------------------------------- Credits ----- + +# Credits Maintainers - James Canete - Ludwig Nussel - Thilo Schulz - Tim Angus - Tony J. White - Zachary J. Slater - Zack Middleton + + * James Canete + * Ludwig Nussel + * Thilo Schulz + * Tim Angus + * Tony J. White + * Zachary J. Slater + * Zack Middleton Significant contributions from - Ryan C. Gordon - Andreas Kohn - Joerg Dietrich - Stuart Dalton - Vincent S. Cojot - optical - Aaron Gyes + + * Ryan C. Gordon + * Andreas Kohn + * Joerg Dietrich + * Stuart Dalton + * Vincent S. Cojot + * optical + * Aaron Gyes + + +[![githalytics.com alpha](https://cruel-carlota.pagodabox.com/6d196bd663b47049a25dcb8caef95949 "githalytics.com")](http://githalytics.com/ioquake/ioq3) diff --git a/code/client/cl_cin.c b/code/client/cl_cin.c index 45c4dd45..599443c9 100644 --- a/code/client/cl_cin.c +++ b/code/client/cl_cin.c @@ -1472,7 +1472,9 @@ int CIN_PlayCinematic( const char *arg, int x, int y, int w, int h, int systemBi Con_Close(); - s_rawend[0] = s_soundtime; + if (!cinTable[currentHandle].silent) { + s_rawend[0] = s_soundtime; + } return currentHandle; } diff --git a/code/client/cl_main.c b/code/client/cl_main.c index ad317e5b..d9946844 100644 --- a/code/client/cl_main.c +++ b/code/client/cl_main.c @@ -112,7 +112,6 @@ cvar_t *cl_conXOffset; cvar_t *cl_inGameVideo; cvar_t *cl_serverStatusResendTime; -cvar_t *cl_trn; cvar_t *cl_lanForcePackets; @@ -671,7 +670,7 @@ void CL_StopRecord_f( void ) { CL_DemoFilename ================== */ -void CL_DemoFilename( int number, char *fileName ) { +void CL_DemoFilename( int number, char *fileName, int fileNameSize ) { int a,b,c,d; if(number < 0 || number > 9999) @@ -685,7 +684,7 @@ void CL_DemoFilename( int number, char *fileName ) { number -= c*10; d = number; - Com_sprintf( fileName, MAX_OSPATH, "demo%i%i%i%i" + Com_sprintf( fileName, fileNameSize, "demo%i%i%i%i" , a, b, c, d ); } @@ -745,7 +744,7 @@ void CL_Record_f( void ) { // scan for a free demo name for ( number = 0 ; number <= 9999 ; number++ ) { - CL_DemoFilename( number, demoName ); + CL_DemoFilename( number, demoName, sizeof( demoName ) ); #ifdef LEGACY_PROTOCOL if(clc.compat) Com_sprintf(name, sizeof(name), "demos/%s.%s%d", demoName, DEMOEXT, com_legacyprotocol->integer); @@ -2429,6 +2428,9 @@ void CL_InitServerInfo( serverInfo_t *server, netadr_t *address ) { server->game[0] = '\0'; server->gameType = 0; server->netType = 0; + server->punkbuster = 0; + server->g_humanplayers = 0; + server->g_needpass = 0; } #define MAX_SERVERSPERPACKET 256 @@ -2937,13 +2939,13 @@ void CL_Frame ( int msec ) { if ( CL_VideoRecording( ) && cl_aviFrameRate->integer && msec) { // save the current screen if ( clc.state == CA_ACTIVE || cl_forceavidemo->integer) { + float fps = MIN(cl_aviFrameRate->value * com_timescale->value, 1000.0f); + float frameDuration = MAX(1000.0f / fps, 1.0f) + clc.aviVideoFrameRemainder; + CL_TakeVideoFrame( ); - // fixed time for next frame' - msec = (int)ceil( (1000.0f / cl_aviFrameRate->value) * com_timescale->value ); - if (msec == 0) { - msec = 1; - } + msec = (int)frameDuration; + clc.aviVideoFrameRemainder = frameDuration - msec; } } @@ -3836,21 +3838,8 @@ void CL_ServerInfoPacket( netadr_t from, msg_t *msg ) { // add this to the list cls.numlocalservers = i+1; - cls.localServers[i].adr = from; - cls.localServers[i].clients = 0; - cls.localServers[i].hostName[0] = '\0'; - cls.localServers[i].mapName[0] = '\0'; - cls.localServers[i].maxClients = 0; - cls.localServers[i].maxPing = 0; - cls.localServers[i].minPing = 0; - cls.localServers[i].ping = -1; - cls.localServers[i].game[0] = '\0'; - cls.localServers[i].gameType = 0; - cls.localServers[i].netType = from.type; - cls.localServers[i].punkbuster = 0; - cls.localServers[i].g_humanplayers = 0; - cls.localServers[i].g_needpass = 0; - + CL_InitServerInfo( &cls.localServers[i], &from ); + Q_strncpyz( info, MSG_ReadString( msg ), MAX_INFO_STRING ); if (strlen(info)) { if (info[strlen(info)-1] != '\n') { diff --git a/code/client/cl_parse.c b/code/client/cl_parse.c index a424aa59..5c9c1471 100644 --- a/code/client/cl_parse.c +++ b/code/client/cl_parse.c @@ -709,7 +709,7 @@ void CL_ParseVoip ( msg_t *msg ) { const int packetsize = MSG_ReadShort(msg); const int flags = MSG_ReadBits(msg, VOIP_FLAGCNT); char encoded[1024]; - int seqdiff = sequence - clc.voipIncomingSequence[sender]; + int seqdiff; int written = 0; int i; @@ -753,6 +753,8 @@ void CL_ParseVoip ( msg_t *msg ) { Com_DPrintf("VoIP: packet accepted!\n"); + seqdiff = sequence - clc.voipIncomingSequence[sender]; + // This is a new "generation" ... a new recording started, reset the bits. if (generation != clc.voipIncomingGeneration[sender]) { Com_DPrintf("VoIP: new generation %d!\n", generation); diff --git a/code/client/client.h b/code/client/client.h index a6155555..a9b3e51e 100644 --- a/code/client/client.h +++ b/code/client/client.h @@ -233,6 +233,9 @@ typedef struct { int timeDemoMaxDuration; // maximum frame duration unsigned char timeDemoDurations[ MAX_TIMEDEMO_DURATIONS ]; // log of frame durations + float aviVideoFrameRemainder; + float aviSoundFrameRemainder; + #ifdef USE_VOIP qboolean voipEnabled; qboolean speexInitialized; diff --git a/code/client/snd_codec_ogg.c b/code/client/snd_codec_ogg.c index c424649f..2fa6abf0 100644 --- a/code/client/snd_codec_ogg.c +++ b/code/client/snd_codec_ogg.c @@ -157,11 +157,8 @@ int S_OGG_Callback_seek(void *datasource, ogg_int64_t offset, int whence) case SEEK_END : { - // Quake 3 seems to have trouble with FS_SEEK_END - // so we use the file length and FS_SEEK_SET - // set the file position in the actual file with the Q3 function - retVal = FS_Seek(stream->file, (long) stream->length + (long) offset, FS_SEEK_SET); + retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_END); // something has gone wrong, so we return here if(retVal < 0) diff --git a/code/client/snd_codec_opus.c b/code/client/snd_codec_opus.c index 190aee9a..b43dea44 100644 --- a/code/client/snd_codec_opus.c +++ b/code/client/snd_codec_opus.c @@ -146,11 +146,8 @@ int S_OggOpus_Callback_seek(void *datasource, opus_int64 offset, int whence) case SEEK_END : { - // Quake 3 seems to have trouble with FS_SEEK_END - // so we use the file length and FS_SEEK_SET - // set the file position in the actual file with the Q3 function - retVal = FS_Seek(stream->file, (long) stream->length + (long) offset, FS_SEEK_SET); + retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_END); // something has gone wrong, so we return here if(retVal < 0) diff --git a/code/client/snd_dma.c b/code/client/snd_dma.c index d4ba8906..e243f406 100644 --- a/code/client/snd_dma.c +++ b/code/client/snd_dma.c @@ -271,6 +271,11 @@ static sfx_t *S_FindName( const char *name ) { return NULL; } + if (name[0] == '*') { + Com_Printf( S_COLOR_YELLOW "WARNING: Tried to load player sound directly: %s\n", name ); + return NULL; + } + hash = S_HashSFXName(name); sfx = sfxHash[hash]; @@ -977,29 +982,34 @@ void S_Base_RawSamples( int stream, int samples, int rate, int width, int s_chan int i; int src, dst; float scale; - int intVolume; + int intVolumeLeft, intVolumeRight; portable_samplepair_t *rawsamples; if ( !s_soundStarted || s_soundMuted ) { return; } - if(entityNum >= 0) - { - // FIXME: support spatialized raw streams, e.g. for VoIP - return; - } - if ( (stream < 0) || (stream >= MAX_RAW_STREAMS) ) { return; } - + rawsamples = s_rawsamples[stream]; - if(s_muted->integer) - intVolume = 0; - else - intVolume = 256 * volume * s_volume->value; + if ( s_muted->integer ) { + intVolumeLeft = intVolumeRight = 0; + } else { + int leftvol, rightvol; + + if ( entityNum >= 0 && entityNum < MAX_GENTITIES ) { + // support spatialized raw streams, e.g. for VoIP + S_SpatializeOrigin( loopSounds[ entityNum ].origin, 256, &leftvol, &rightvol ); + } else { + leftvol = rightvol = 256; + } + + intVolumeLeft = leftvol * volume * s_volume->value; + intVolumeRight = rightvol * volume * s_volume->value; + } if ( s_rawend[stream] < s_soundtime ) { Com_DPrintf( "S_Base_RawSamples: resetting minimum: %i < %i\n", s_rawend[stream], s_soundtime ); @@ -1017,8 +1027,8 @@ void S_Base_RawSamples( int stream, int samples, int rate, int width, int s_chan { dst = s_rawend[stream]&(MAX_RAW_SAMPLES-1); s_rawend[stream]++; - rawsamples[dst].left = ((short *)data)[i*2] * intVolume; - rawsamples[dst].right = ((short *)data)[i*2+1] * intVolume; + rawsamples[dst].left = ((short *)data)[i*2] * intVolumeLeft; + rawsamples[dst].right = ((short *)data)[i*2+1] * intVolumeRight; } } else @@ -1030,8 +1040,8 @@ void S_Base_RawSamples( int stream, int samples, int rate, int width, int s_chan break; dst = s_rawend[stream]&(MAX_RAW_SAMPLES-1); s_rawend[stream]++; - rawsamples[dst].left = ((short *)data)[src*2] * intVolume; - rawsamples[dst].right = ((short *)data)[src*2+1] * intVolume; + rawsamples[dst].left = ((short *)data)[src*2] * intVolumeLeft; + rawsamples[dst].right = ((short *)data)[src*2+1] * intVolumeRight; } } } @@ -1044,13 +1054,14 @@ void S_Base_RawSamples( int stream, int samples, int rate, int width, int s_chan break; dst = s_rawend[stream]&(MAX_RAW_SAMPLES-1); s_rawend[stream]++; - rawsamples[dst].left = ((short *)data)[src] * intVolume; - rawsamples[dst].right = ((short *)data)[src] * intVolume; + rawsamples[dst].left = ((short *)data)[src] * intVolumeLeft; + rawsamples[dst].right = ((short *)data)[src] * intVolumeRight; } } else if (s_channels == 2 && width == 1) { - intVolume *= 256; + intVolumeLeft *= 256; + intVolumeRight *= 256; for (i=0 ; ; i++) { @@ -1059,13 +1070,14 @@ void S_Base_RawSamples( int stream, int samples, int rate, int width, int s_chan break; dst = s_rawend[stream]&(MAX_RAW_SAMPLES-1); s_rawend[stream]++; - rawsamples[dst].left = ((char *)data)[src*2] * intVolume; - rawsamples[dst].right = ((char *)data)[src*2+1] * intVolume; + rawsamples[dst].left = ((char *)data)[src*2] * intVolumeLeft; + rawsamples[dst].right = ((char *)data)[src*2+1] * intVolumeRight; } } else if (s_channels == 1 && width == 1) { - intVolume *= 256; + intVolumeLeft *= 256; + intVolumeRight *= 256; for (i=0 ; ; i++) { @@ -1074,8 +1086,8 @@ void S_Base_RawSamples( int stream, int samples, int rate, int width, int s_chan break; dst = s_rawend[stream]&(MAX_RAW_SAMPLES-1); s_rawend[stream]++; - rawsamples[dst].left = (((byte *)data)[src]-128) * intVolume; - rawsamples[dst].right = (((byte *)data)[src]-128) * intVolume; + rawsamples[dst].left = (((byte *)data)[src]-128) * intVolumeLeft; + rawsamples[dst].right = (((byte *)data)[src]-128) * intVolumeRight; } } @@ -1237,7 +1249,13 @@ void S_GetSoundtime(void) if( CL_VideoRecording( ) ) { - s_soundtime += (int)ceil( dma.speed / cl_aviFrameRate->value ); + float fps = MIN(cl_aviFrameRate->value, 1000.0f); + float frameDuration = MAX(dma.speed / fps, 1.0f) + clc.aviSoundFrameRemainder; + + int msec = (int)frameDuration; + s_soundtime += msec; + clc.aviSoundFrameRemainder = frameDuration - msec; + return; } @@ -1360,6 +1378,32 @@ void S_Base_StopBackgroundTrack( void ) { s_rawend[0] = 0; } +/* +====================== +S_OpenBackgroundStream +====================== +*/ +static void S_OpenBackgroundStream( const char *filename ) { + // close the background track, but DON'T reset s_rawend + // if restarting the same back ground track + if(s_backgroundStream) + { + S_CodecCloseStream(s_backgroundStream); + s_backgroundStream = NULL; + } + + // Open stream + s_backgroundStream = S_CodecOpenStream(filename); + if(!s_backgroundStream) { + Com_Printf( S_COLOR_YELLOW "WARNING: couldn't open music file %s\n", filename ); + return; + } + + if(s_backgroundStream->info.channels != 2 || s_backgroundStream->info.rate != 22050) { + Com_Printf(S_COLOR_YELLOW "WARNING: music file %s is not 22k stereo\n", filename ); + } +} + /* ====================== S_StartBackgroundTrack @@ -1380,30 +1424,9 @@ void S_Base_StartBackgroundTrack( const char *intro, const char *loop ){ return; } - if( !loop ) { - s_backgroundLoop[0] = 0; - } else { - Q_strncpyz( s_backgroundLoop, loop, sizeof( s_backgroundLoop ) ); - } + Q_strncpyz( s_backgroundLoop, loop, sizeof( s_backgroundLoop ) ); - // close the background track, but DON'T reset s_rawend - // if restarting the same back ground track - if(s_backgroundStream) - { - S_CodecCloseStream(s_backgroundStream); - s_backgroundStream = NULL; - } - - // Open stream - s_backgroundStream = S_CodecOpenStream(intro); - if(!s_backgroundStream) { - Com_Printf( S_COLOR_YELLOW "WARNING: couldn't open music file %s\n", intro ); - return; - } - - if(s_backgroundStream->info.channels != 2 || s_backgroundStream->info.rate != 22050) { - Com_Printf(S_COLOR_YELLOW "WARNING: music file %s is not 22k stereo\n", intro ); - } + S_OpenBackgroundStream( intro ); } /* @@ -1466,9 +1489,7 @@ void S_UpdateBackgroundTrack( void ) { // loop if(s_backgroundLoop[0]) { - S_CodecCloseStream(s_backgroundStream); - s_backgroundStream = NULL; - S_Base_StartBackgroundTrack( s_backgroundLoop, s_backgroundLoop ); + S_OpenBackgroundStream( s_backgroundLoop ); if(!s_backgroundStream) return; } diff --git a/code/client/snd_local.h b/code/client/snd_local.h index 66f3bcde..e0f5b1d0 100644 --- a/code/client/snd_local.h +++ b/code/client/snd_local.h @@ -56,6 +56,7 @@ typedef struct sfx_s { qboolean soundCompressed; // not in Memory int soundCompressionMethod; int soundLength; + int soundChannels; char soundName[MAX_QPATH]; int lastTimeUsed; struct sfx_s *next; diff --git a/code/client/snd_mem.c b/code/client/snd_mem.c index d42084b7..655ae420 100644 --- a/code/client/snd_mem.c +++ b/code/client/snd_mem.c @@ -113,47 +113,51 @@ ResampleSfx resample / decimate to the current source rate ================ */ -static void ResampleSfx( sfx_t *sfx, int inrate, int inwidth, byte *data, qboolean compressed ) { +static int ResampleSfx( sfx_t *sfx, int channels, int inrate, int inwidth, int samples, byte *data, qboolean compressed ) { int outcount; int srcsample; float stepscale; - int i; + int i, j; int sample, samplefrac, fracstep; int part; sndBuffer *chunk; stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2 - outcount = sfx->soundLength / stepscale; - sfx->soundLength = outcount; + outcount = samples / stepscale; samplefrac = 0; - fracstep = stepscale * 256; + fracstep = stepscale * 256 * channels; chunk = sfx->soundData; for (i=0 ; i> 8; samplefrac += fracstep; - if( inwidth == 2 ) { - sample = ( ((short *)data)[srcsample] ); - } else { - sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8; - } - part = (i&(SND_CHUNK_SIZE-1)); - if (part == 0) { - sndBuffer *newchunk; - newchunk = SND_malloc(); - if (chunk == NULL) { - sfx->soundData = newchunk; + for (j=0 ; jnext = newchunk; + sample = (int)( (unsigned char)(data[srcsample+j]) - 128) << 8; + } + part = (i*channels+j)&(SND_CHUNK_SIZE-1); + if (part == 0) { + sndBuffer *newchunk; + newchunk = SND_malloc(); + if (chunk == NULL) { + sfx->soundData = newchunk; + } else { + chunk->next = newchunk; + } + chunk = newchunk; } - chunk = newchunk; - } - chunk->sndChunk[part] = sample; + chunk->sndChunk[part] = sample; + } } + + return outcount; } /* @@ -163,11 +167,11 @@ ResampleSfx resample / decimate to the current source rate ================ */ -static int ResampleSfxRaw( short *sfx, int inrate, int inwidth, int samples, byte *data ) { +static int ResampleSfxRaw( short *sfx, int channels, int inrate, int inwidth, int samples, byte *data ) { int outcount; int srcsample; float stepscale; - int i; + int i, j; int sample, samplefrac, fracstep; stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2 @@ -175,18 +179,21 @@ static int ResampleSfxRaw( short *sfx, int inrate, int inwidth, int samples, byt outcount = samples / stepscale; samplefrac = 0; - fracstep = stepscale * 256; + fracstep = stepscale * 256 * channels; for (i=0 ; i> 8; samplefrac += fracstep; - if( inwidth == 2 ) { - sample = LittleShort ( ((short *)data)[srcsample] ); - } else { - sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8; + for (j=0 ; jsoundName[0] == '*') { - return qfalse; - } - // load it in data = S_CodecLoad(sfx->soundName, &info); if(!data) @@ -226,7 +228,7 @@ qboolean S_LoadSound( sfx_t *sfx ) Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is not a 22kHz audio file\n", sfx->soundName); } - samples = Hunk_AllocateTempMemory(info.samples * sizeof(short) * 2); + samples = Hunk_AllocateTempMemory(info.channels * info.samples * sizeof(short) * 2); sfx->lastTimeUsed = Com_Milliseconds()+1; @@ -236,29 +238,30 @@ qboolean S_LoadSound( sfx_t *sfx ) // manager to do the right thing for us and page // sound in as needed - if( sfx->soundCompressed == qtrue) { + if( info.channels == 1 && sfx->soundCompressed == qtrue) { sfx->soundCompressionMethod = 1; sfx->soundData = NULL; - sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, data + info.dataofs ); + sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, data + info.dataofs ); S_AdpcmEncodeSound(sfx, samples); #if 0 - } else if (info.samples>(SND_CHUNK_SIZE*16) && info.width >1) { + } else if (info.channels == 1 && info.samples>(SND_CHUNK_SIZE*16) && info.width >1) { sfx->soundCompressionMethod = 3; sfx->soundData = NULL; - sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) ); + sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, (data + info.dataofs) ); encodeMuLaw( sfx, samples); - } else if (info.samples>(SND_CHUNK_SIZE*6400) && info.width >1) { + } else if (info.channels == 1 && info.samples>(SND_CHUNK_SIZE*6400) && info.width >1) { sfx->soundCompressionMethod = 2; sfx->soundData = NULL; - sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) ); + sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, (data + info.dataofs) ); encodeWavelet( sfx, samples); #endif } else { sfx->soundCompressionMethod = 0; - sfx->soundLength = info.samples; sfx->soundData = NULL; - ResampleSfx( sfx, info.rate, info.width, data + info.dataofs, qfalse ); + sfx->soundLength = ResampleSfx( sfx, info.channels, info.rate, info.width, info.samples, data + info.dataofs, qfalse ); } + + sfx->soundChannels = info.channels; Hunk_FreeTempMemory(samples); Hunk_FreeTempMemory(data); diff --git a/code/client/snd_mix.c b/code/client/snd_mix.c index fca5e15f..38bd0aae 100644 --- a/code/client/snd_mix.c +++ b/code/client/snd_mix.c @@ -234,7 +234,7 @@ static void S_PaintChannelFrom16_altivec( channel_t *ch, const sfx_t *sc, int co portable_samplepair_t *samp; sndBuffer *chunk; short *samples; - float ooff, fdata, fdiv, fleftvol, frightvol; + float ooff, fdata[2], fdiv, fleftvol, frightvol; samp = &paintbuffer[ bufferOffset ]; @@ -242,6 +242,14 @@ static void S_PaintChannelFrom16_altivec( channel_t *ch, const sfx_t *sc, int co sampleOffset = sampleOffset*ch->oldDopplerScale; } + if ( sc->soundChannels == 2 ) { + sampleOffset *= sc->soundChannels; + + if ( sampleOffset & 1 ) { + sampleOffset &= ~1; + } + } + chunk = sc->soundData; while (sampleOffset>=SND_CHUNK_SIZE) { chunk = chunk->next; @@ -274,6 +282,10 @@ static void S_PaintChannelFrom16_altivec( channel_t *ch, const sfx_t *sc, int co while(i < count && (((unsigned long)&samp[i] & 0x1f) || ((count-i) < 8) || ((SND_CHUNK_SIZE - sampleOffset) < 8))) { data = samples[sampleOffset++]; samp[i].left += (data * leftvol)>>8; + + if ( sc->soundChannels == 2 ) { + data = samples[sampleOffset++]; + } samp[i].right += (data * rightvol)>>8; if (sampleOffset == SND_CHUNK_SIZE) { @@ -373,10 +385,10 @@ static void S_PaintChannelFrom16_altivec( channel_t *ch, const sfx_t *sc, int co for ( i=0 ; idopplerScale; + ooff = ooff + ch->dopplerScale * sc->soundChannels; boff = ooff; - fdata = 0; - for (j=aoff; jsoundChannels) { if (j == SND_CHUNK_SIZE) { chunk = chunk->next; if (!chunk) { @@ -385,11 +397,17 @@ static void S_PaintChannelFrom16_altivec( channel_t *ch, const sfx_t *sc, int co samples = chunk->sndChunk; ooff -= SND_CHUNK_SIZE; } - fdata += samples[j&(SND_CHUNK_SIZE-1)]; + if ( sc->soundChannels == 2 ) { + fdata[0] += samples[j&(SND_CHUNK_SIZE-1)]; + fdata[1] += samples[(j+1)&(SND_CHUNK_SIZE-1)]; + } else { + fdata[0] += samples[j&(SND_CHUNK_SIZE-1)]; + fdata[1] += samples[j&(SND_CHUNK_SIZE-1)]; + } } - fdiv = 256 * (boff-aoff); - samp[i].left += (fdata * fleftvol)/fdiv; - samp[i].right += (fdata * frightvol)/fdiv; + fdiv = 256 * (boff-aoff) / sc->soundChannels; + samp[i].left += (fdata[0] * fleftvol)/fdiv; + samp[i].right += (fdata[1] * frightvol)/fdiv; } } } @@ -402,7 +420,7 @@ static void S_PaintChannelFrom16_scalar( channel_t *ch, const sfx_t *sc, int cou portable_samplepair_t *samp; sndBuffer *chunk; short *samples; - float ooff, fdata, fdiv, fleftvol, frightvol; + float ooff, fdata[2], fdiv, fleftvol, frightvol; samp = &paintbuffer[ bufferOffset ]; @@ -410,6 +428,14 @@ static void S_PaintChannelFrom16_scalar( channel_t *ch, const sfx_t *sc, int cou sampleOffset = sampleOffset*ch->oldDopplerScale; } + if ( sc->soundChannels == 2 ) { + sampleOffset *= sc->soundChannels; + + if ( sampleOffset & 1 ) { + sampleOffset &= ~1; + } + } + chunk = sc->soundData; while (sampleOffset>=SND_CHUNK_SIZE) { chunk = chunk->next; @@ -426,6 +452,10 @@ static void S_PaintChannelFrom16_scalar( channel_t *ch, const sfx_t *sc, int cou for ( i=0 ; i>8; + + if ( sc->soundChannels == 2 ) { + data = samples[sampleOffset++]; + } samp[i].right += (data * rightvol)>>8; if (sampleOffset == SND_CHUNK_SIZE) { @@ -447,10 +477,10 @@ static void S_PaintChannelFrom16_scalar( channel_t *ch, const sfx_t *sc, int cou for ( i=0 ; idopplerScale; + ooff = ooff + ch->dopplerScale * sc->soundChannels; boff = ooff; - fdata = 0; - for (j=aoff; jsoundChannels) { if (j == SND_CHUNK_SIZE) { chunk = chunk->next; if (!chunk) { @@ -459,11 +489,17 @@ static void S_PaintChannelFrom16_scalar( channel_t *ch, const sfx_t *sc, int cou samples = chunk->sndChunk; ooff -= SND_CHUNK_SIZE; } - fdata += samples[j&(SND_CHUNK_SIZE-1)]; + if ( sc->soundChannels == 2 ) { + fdata[0] += samples[j&(SND_CHUNK_SIZE-1)]; + fdata[1] += samples[(j+1)&(SND_CHUNK_SIZE-1)]; + } else { + fdata[0] += samples[j&(SND_CHUNK_SIZE-1)]; + fdata[1] += samples[j&(SND_CHUNK_SIZE-1)]; + } } - fdiv = 256 * (boff-aoff); - samp[i].left += (fdata * fleftvol)/fdiv; - samp[i].right += (fdata * frightvol)/fdiv; + fdiv = 256 * (boff-aoff) / sc->soundChannels; + samp[i].left += (fdata[0] * fleftvol)/fdiv; + samp[i].right += (fdata[1] * frightvol)/fdiv; } } } diff --git a/code/client/snd_openal.c b/code/client/snd_openal.c index c15d366a..e4e41a64 100644 --- a/code/client/snd_openal.c +++ b/code/client/snd_openal.c @@ -318,6 +318,11 @@ static sfxHandle_t S_AL_BufferFind(const char *filename) return 0; } + if ( filename[0] == '*' ) { + Com_Printf( S_COLOR_YELLOW "WARNING: Tried to load player sound directly: %s\n", filename ); + return 0; + } + for(i = 0; i < numSfx; i++) { if(!Q_stricmp(knownSfx[i].filename, filename)) @@ -417,6 +422,44 @@ static qboolean S_AL_BufferEvict( void ) return qfalse; } +/* +================= +S_AL_GenBuffers +================= +*/ +static qboolean S_AL_GenBuffers(ALsizei numBuffers, ALuint *buffers, const char *name) +{ + ALenum error; + + S_AL_ClearError( qfalse ); + qalGenBuffers( numBuffers, buffers ); + error = qalGetError(); + + // If we ran out of buffers, start evicting the least recently used sounds + while( error == AL_INVALID_VALUE ) + { + if( !S_AL_BufferEvict( ) ) + { + Com_Printf( S_COLOR_RED "ERROR: Out of audio buffers\n"); + return qfalse; + } + + // Try again + S_AL_ClearError( qfalse ); + qalGenBuffers( numBuffers, buffers ); + error = qalGetError(); + } + + if( error != AL_NO_ERROR ) + { + Com_Printf( S_COLOR_RED "ERROR: Can't create a sound buffer for %s - %s\n", + name, S_AL_ErrorMsg(error)); + return qfalse; + } + + return qtrue; +} + /* ================= S_AL_BufferLoad @@ -435,10 +478,6 @@ static void S_AL_BufferLoad(sfxHandle_t sfx, qboolean cache) if(curSfx->filename[0] == '\0') return; - // Player SFX - if(curSfx->filename[0] == '*') - return; - // Already done? if((curSfx->inMemory) || (curSfx->isDefault) || (!cache && curSfx->isDefaultChecked)) return; @@ -463,14 +502,10 @@ static void S_AL_BufferLoad(sfxHandle_t sfx, qboolean cache) format = S_AL_Format(info.width, info.channels); // Create a buffer - S_AL_ClearError( qfalse ); - qalGenBuffers(1, &curSfx->buffer); - if((error = qalGetError()) != AL_NO_ERROR) + if (!S_AL_GenBuffers(1, &curSfx->buffer, curSfx->filename)) { S_AL_BufferUseDefault(sfx); Hunk_FreeTempMemory(data); - Com_Printf( S_COLOR_RED "ERROR: Can't create a sound buffer for %s - %s\n", - curSfx->filename, S_AL_ErrorMsg(error)); return; } @@ -492,6 +527,7 @@ static void S_AL_BufferLoad(sfxHandle_t sfx, qboolean cache) { if( !S_AL_BufferEvict( ) ) { + qalDeleteBuffers(1, &curSfx->buffer); S_AL_BufferUseDefault(sfx); Hunk_FreeTempMemory(data); Com_Printf( S_COLOR_RED "ERROR: Out of memory loading %s\n", curSfx->filename); @@ -506,6 +542,7 @@ static void S_AL_BufferLoad(sfxHandle_t sfx, qboolean cache) // Some other error condition if(error != AL_NO_ERROR) { + qalDeleteBuffers(1, &curSfx->buffer); S_AL_BufferUseDefault(sfx); Hunk_FreeTempMemory(data); Com_Printf( S_COLOR_RED "ERROR: Can't fill sound buffer for %s - %s\n", @@ -1091,7 +1128,7 @@ static void S_AL_SrcKill(srcHandle_t src) curSource->isPlaying = qfalse; } - // Remove the buffer + // Detach any buffers qalSourcei(curSource->alSource, AL_BUFFER, 0); curSource->sfx = 0; @@ -1621,6 +1658,10 @@ void S_AL_SrcUpdate( void ) if(!curSource->isPlaying) { + qalSourcei(curSource->alSource, AL_LOOPING, AL_TRUE); + curSource->isPlaying = qtrue; + qalSourcePlay(curSource->alSource); + if(curSource->priority == SRCPRI_AMBIENT) { // If there are other ambient looping sources with the same sound, @@ -1678,10 +1719,6 @@ void S_AL_SrcUpdate( void ) } curSfx->loopActiveCnt++; - - qalSourcei(curSource->alSource, AL_LOOPING, AL_TRUE); - curSource->isPlaying = qtrue; - qalSourcePlay(curSource->alSource); } // Update locality @@ -1763,9 +1800,15 @@ ALuint S_AL_SrcGet(srcHandle_t src) //=========================================================================== +// Q3A cinematics use up to 12 buffers at once +#define MAX_STREAM_BUFFERS 20 + static srcHandle_t streamSourceHandles[MAX_RAW_STREAMS]; static qboolean streamPlaying[MAX_RAW_STREAMS]; static ALuint streamSources[MAX_RAW_STREAMS]; +static ALuint streamBuffers[MAX_RAW_STREAMS][MAX_STREAM_BUFFERS]; +static int streamNumBuffers[MAX_RAW_STREAMS]; +static int streamBufIndex[MAX_RAW_STREAMS]; /* ================= @@ -1823,6 +1866,9 @@ static void S_AL_AllocateStreamChannel(int stream, int entityNum) streamSourceHandles[stream] = cursrc; streamSources[stream] = alsrc; + + streamNumBuffers[stream] = 0; + streamBufIndex[stream] = 0; } /* @@ -1835,6 +1881,15 @@ static void S_AL_FreeStreamChannel( int stream ) if ((stream < 0) || (stream >= MAX_RAW_STREAMS)) return; + // Detach any buffers + qalSourcei(streamSources[stream], AL_BUFFER, 0); + + // Delete the buffers + if (streamNumBuffers[stream] > 0) { + qalDeleteBuffers(streamNumBuffers[stream], streamBuffers[stream]); + streamNumBuffers[stream] = 0; + } + // Release the output streamSource S_AL_SrcUnlock(streamSourceHandles[stream]); S_AL_SrcKill(streamSourceHandles[stream]); @@ -1850,6 +1905,7 @@ S_AL_RawSamples static void S_AL_RawSamples(int stream, int samples, int rate, int width, int channels, const byte *data, float volume, int entityNum) { + int numBuffers; ALuint buffer; ALuint format; @@ -1871,8 +1927,40 @@ void S_AL_RawSamples(int stream, int samples, int rate, int width, int channels, } } - // Create a buffer, and stuff the data into it - qalGenBuffers(1, &buffer); + qalGetSourcei(streamSources[stream], AL_BUFFERS_QUEUED, &numBuffers); + + if (numBuffers == MAX_STREAM_BUFFERS) + { + Com_DPrintf(S_COLOR_RED"WARNING: Steam dropping raw samples, reached MAX_STREAM_BUFFERS\n"); + return; + } + + // Allocate a new AL buffer if needed + if (numBuffers == streamNumBuffers[stream]) + { + ALuint oldBuffers[MAX_STREAM_BUFFERS]; + int i; + + if (!S_AL_GenBuffers(1, &buffer, "stream")) + return; + + Com_Memcpy(oldBuffers, &streamBuffers[stream], sizeof (oldBuffers)); + + // Reorder buffer array in order of oldest to newest + for ( i = 0; i < streamNumBuffers[stream]; ++i ) + streamBuffers[stream][i] = oldBuffers[(streamBufIndex[stream] + i) % streamNumBuffers[stream]]; + + // Add the new buffer to end + streamBuffers[stream][streamNumBuffers[stream]] = buffer; + streamBufIndex[stream] = streamNumBuffers[stream]; + streamNumBuffers[stream]++; + } + + // Select next buffer in loop + buffer = streamBuffers[stream][ streamBufIndex[stream] ]; + streamBufIndex[stream] = (streamBufIndex[stream] + 1) % streamNumBuffers[stream]; + + // Fill buffer qalBufferData(buffer, format, (ALvoid *)data, (samples * width * channels), rate); // Shove the data onto the streamSource @@ -1883,6 +1971,13 @@ void S_AL_RawSamples(int stream, int samples, int rate, int width, int channels, // Volume S_AL_Gain (streamSources[stream], volume * s_volume->value * s_alGain->value); } + + // Start stream + if(!streamPlaying[stream]) + { + qalSourcePlay( streamSources[stream] ); + streamPlaying[stream] = qtrue; + } } /* @@ -1902,13 +1997,12 @@ void S_AL_StreamUpdate( int stream ) if(streamSourceHandles[stream] == -1) return; - // Un-queue any buffers, and delete them + // Un-queue any buffers qalGetSourcei( streamSources[stream], AL_BUFFERS_PROCESSED, &numBuffers ); while( numBuffers-- ) { ALuint buffer; qalSourceUnqueueBuffers(streamSources[stream], 1, &buffer); - qalDeleteBuffers(1, &buffer); } // Start the streamSource playing if necessary @@ -1939,8 +2033,6 @@ S_AL_StreamDie static void S_AL_StreamDie( int stream ) { - int numBuffers; - if ((stream < 0) || (stream >= MAX_RAW_STREAMS)) return; @@ -1950,15 +2042,6 @@ void S_AL_StreamDie( int stream ) streamPlaying[stream] = qfalse; qalSourceStop(streamSources[stream]); - // Un-queue any buffers, and delete them - qalGetSourcei( streamSources[stream], AL_BUFFERS_PROCESSED, &numBuffers ); - while( numBuffers-- ) - { - ALuint buffer; - qalSourceUnqueueBuffers(streamSources[stream], 1, &buffer); - qalDeleteBuffers(1, &buffer); - } - S_AL_FreeStreamChannel(stream); } @@ -2050,22 +2133,17 @@ S_AL_StopBackgroundTrack static void S_AL_StopBackgroundTrack( void ) { - int numBuffers; - if(!musicPlaying) return; // Stop playing qalSourceStop(musicSource); - // Un-queue any buffers, and delete them - qalGetSourcei( musicSource, AL_BUFFERS_PROCESSED, &numBuffers ); - while( numBuffers-- ) - { - ALuint buffer; - qalSourceUnqueueBuffers(musicSource, 1, &buffer); - qalDeleteBuffers(1, &buffer); - } + // Detach any buffers + qalSourcei(musicSource, AL_BUFFER, 0); + + // Delete the buffers + qalDeleteBuffers(NUM_MUSIC_BUFFERS, musicBuffers); // Free the musicSource S_AL_MusicSourceFree(); @@ -2198,7 +2276,8 @@ void S_AL_StartBackgroundTrack( const char *intro, const char *loop ) } // Generate the musicBuffers - qalGenBuffers(NUM_MUSIC_BUFFERS, musicBuffers); + if (!S_AL_GenBuffers(NUM_MUSIC_BUFFERS, musicBuffers, "music")) + return; // Queue the musicBuffers up for(i = 0; i < NUM_MUSIC_BUFFERS; i++) @@ -3155,6 +3234,8 @@ qboolean S_AL_Init( soundInterface_t *si ) streamSourceHandles[i] = -1; streamPlaying[i] = qfalse; streamSources[i] = 0; + streamNumBuffers[i] = 0; + streamBufIndex[i] = 0; } // New console variables @@ -3328,11 +3409,14 @@ qboolean S_AL_Init( soundInterface_t *si ) defaultinputdevice = qalcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); // dump a list of available devices to a cvar for the user to see. - while((curlen = strlen(inputdevicelist))) + if (inputdevicelist) { - Q_strcat(inputdevicenames, sizeof(inputdevicenames), inputdevicelist); - Q_strcat(inputdevicenames, sizeof(inputdevicenames), "\n"); - inputdevicelist += curlen + 1; + while((curlen = strlen(inputdevicelist))) + { + Q_strcat(inputdevicenames, sizeof(inputdevicenames), inputdevicelist); + Q_strcat(inputdevicenames, sizeof(inputdevicenames), "\n"); + inputdevicelist += curlen + 1; + } } s_alAvailableInputDevices = Cvar_Get("s_alAvailableInputDevices", inputdevicenames, CVAR_ROM | CVAR_NORESTART); @@ -3341,7 +3425,7 @@ qboolean S_AL_Init( soundInterface_t *si ) // !!! FIXME: should probably open the capture device after // !!! FIXME: initializing Speex so we can change to wideband // !!! FIXME: if we like. - Com_Printf("OpenAL default capture device is '%s'\n", defaultinputdevice); + Com_Printf("OpenAL default capture device is '%s'\n", defaultinputdevice ? defaultinputdevice : "none"); alCaptureDevice = qalcCaptureOpenDevice(inputdevice, 8000, AL_FORMAT_MONO16, 4096); if( !alCaptureDevice && inputdevice ) { diff --git a/code/qcommon/files.c b/code/qcommon/files.c index 2392fb81..2fb2f8af 100644 --- a/code/qcommon/files.c +++ b/code/qcommon/files.c @@ -275,9 +275,9 @@ typedef struct qfile_us { typedef struct { qfile_ut handleFiles; qboolean handleSync; - int baseOffset; int fileSize; int zipFilePos; + int zipFileLen; qboolean zipFile; qboolean streamed; char name[MAX_ZPATH]; @@ -1262,6 +1262,7 @@ long FS_FOpenFileReadDir(const char *filename, searchpath_t *search, fileHandle_ // open the file in the zip unzOpenCurrentFile(fsh[*file].handleFiles.file.z); fsh[*file].zipFilePos = pakFile->pos; + fsh[*file].zipFileLen = pakFile->len; if(fs_debug->integer) { @@ -1628,29 +1629,60 @@ int FS_Seek( fileHandle_t f, long offset, int origin ) { } if (fsh[f].streamed) { + int r; fsh[f].streamed = qfalse; - FS_Seek( f, offset, origin ); + r = FS_Seek( f, offset, origin ); fsh[f].streamed = qtrue; + return r; } if (fsh[f].zipFile == qtrue) { - //FIXME: this is incomplete and really, really - //crappy (but better than what was here before) + //FIXME: this is really, really crappy + //(but better than what was here before) byte buffer[PK3_SEEK_BUFFER_SIZE]; - int remainder = offset; + int remainder; + int currentPosition = FS_FTell( f ); - if( offset < 0 || origin == FS_SEEK_END ) { - Com_Error( ERR_FATAL, "Negative offsets and FS_SEEK_END not implemented " - "for FS_Seek on pk3 file contents" ); - return -1; + // change negative offsets into FS_SEEK_SET + if ( offset < 0 ) { + switch( origin ) { + case FS_SEEK_END: + remainder = fsh[f].zipFileLen + offset; + break; + + case FS_SEEK_CUR: + remainder = currentPosition + offset; + break; + + case FS_SEEK_SET: + default: + remainder = 0; + break; + } + + if ( remainder < 0 ) { + remainder = 0; + } + + origin = FS_SEEK_SET; + } else { + if ( origin == FS_SEEK_END ) { + remainder = fsh[f].zipFileLen - currentPosition + offset; + } else { + remainder = offset; + } } switch( origin ) { case FS_SEEK_SET: + if ( remainder == currentPosition ) { + return offset; + } unzSetOffset(fsh[f].handleFiles.file.z, fsh[f].zipFilePos); unzOpenCurrentFile(fsh[f].handleFiles.file.z); //fallthrough + case FS_SEEK_END: case FS_SEEK_CUR: while( remainder > PK3_SEEK_BUFFER_SIZE ) { FS_Read( buffer, PK3_SEEK_BUFFER_SIZE, f ); @@ -1658,12 +1690,10 @@ int FS_Seek( fileHandle_t f, long offset, int origin ) { } FS_Read( buffer, remainder, f ); return offset; - break; default: Com_Error( ERR_FATAL, "Bad origin in FS_Seek" ); return -1; - break; } } else { FILE *file; @@ -4012,11 +4042,6 @@ int FS_FOpenFileByMode( const char *qpath, fileHandle_t *f, fsMode_t mode ) { } if ( *f ) { - if (fsh[*f].zipFile == qtrue) { - fsh[*f].baseOffset = unztell(fsh[*f].handleFiles.file.z); - } else { - fsh[*f].baseOffset = ftell(fsh[*f].handleFiles.file.o); - } fsh[*f].fileSize = r; fsh[*f].streamed = qfalse; diff --git a/code/qcommon/q_shared.c b/code/qcommon/q_shared.c index 357451c5..690838cc 100644 --- a/code/qcommon/q_shared.c +++ b/code/qcommon/q_shared.c @@ -76,8 +76,12 @@ COM_StripExtension void COM_StripExtension( const char *in, char *out, int destsize ) { const char *dot = strrchr(in, '.'), *slash; + if (dot && (!(slash = strrchr(in, '/')) || slash < dot)) - Q_strncpyz(out, in, (destsize < dot-in+1 ? destsize : dot-in+1)); + destsize = (destsize < dot-in+1 ? destsize : dot-in+1); + + if ( in == out && destsize > 1 ) + out[destsize-1] = '\0'; else Q_strncpyz(out, in, destsize); } diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index ea64d3a8..244fc062 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -694,7 +694,7 @@ int FS_FOpenFileByMode( const char *qpath, fileHandle_t *f, fsMode_t mode ); // opens a file for reading, writing, or appending depending on the value of mode int FS_Seek( fileHandle_t f, long offset, int origin ); -// seek on a file (doesn't work for zip files!!!!!!!!) +// seek on a file qboolean FS_FilenameCompare( const char *s1, const char *s2 ); @@ -1063,19 +1063,6 @@ void * QDECL Sys_LoadGameDll( const char *name, intptr_t (QDECL **entryPoint)(in intptr_t (QDECL *systemcalls)(intptr_t, ...) ); void Sys_UnloadDll( void *dllHandle ); -void Sys_UnloadGame( void ); -void *Sys_GetGameAPI( void *parms ); - -void Sys_UnloadCGame( void ); -void *Sys_GetCGameAPI( void ); - -void Sys_UnloadUI( void ); -void *Sys_GetUIAPI( void ); - -//bot libraries -void Sys_UnloadBotLib( void ); -void *Sys_GetBotLibAPI( void *parms ); - char *Sys_GetCurrentUser( void ); void QDECL Sys_Error( const char *error, ...) __attribute__ ((noreturn, format (printf, 1, 2))); diff --git a/code/qcommon/qfiles.h b/code/qcommon/qfiles.h index c03f1c20..25568eb1 100644 --- a/code/qcommon/qfiles.h +++ b/code/qcommon/qfiles.h @@ -179,94 +179,11 @@ typedef struct { /* ============================================================================== -MD4 file format +MDR file format ============================================================================== */ -#define MD4_IDENT (('4'<<24)+('P'<<16)+('D'<<8)+'I') -#define MD4_VERSION 1 -#define MD4_MAX_BONES 128 - -typedef struct { - int boneIndex; // these are indexes into the boneReferences, - float boneWeight; // not the global per-frame bone list - vec3_t offset; -} md4Weight_t; - -typedef struct { - vec3_t normal; - vec2_t texCoords; - int numWeights; - md4Weight_t weights[1]; // variable sized -} md4Vertex_t; - -typedef struct { - int indexes[3]; -} md4Triangle_t; - -typedef struct { - int ident; - - char name[MAX_QPATH]; // polyset name - char shader[MAX_QPATH]; - int shaderIndex; // for in-game use - - int ofsHeader; // this will be a negative number - - int numVerts; - int ofsVerts; - - int numTriangles; - int ofsTriangles; - - // Bone references are a set of ints representing all the bones - // present in any vertex weights for this surface. This is - // needed because a model may have surfaces that need to be - // drawn at different sort times, and we don't want to have - // to re-interpolate all the bones for each surface. - int numBoneReferences; - int ofsBoneReferences; - - int ofsEnd; // next surface follows -} md4Surface_t; - -typedef struct { - float matrix[3][4]; -} md4Bone_t; - -typedef struct { - vec3_t bounds[2]; // bounds of all surfaces of all LOD's for this frame - vec3_t localOrigin; // midpoint of bounds, used for sphere cull - float radius; // dist from localOrigin to corner - md4Bone_t bones[1]; // [numBones] -} md4Frame_t; - -typedef struct { - int numSurfaces; - int ofsSurfaces; // first surface, others follow - int ofsEnd; // next lod follows -} md4LOD_t; - -typedef struct { - int ident; - int version; - - char name[MAX_QPATH]; // model name - - // frames and bones are shared by all levels of detail - int numFrames; - int numBones; - int ofsBoneNames; // char name[ MAX_QPATH ] - int ofsFrames; // md4Frame_t[numFrames] - - // each level of detail has completely separate sets of surfaces - int numLODs; - int ofsLODs; - - int ofsEnd; // end of file -} md4Header_t; - /* * Here are the definitions for Ravensoft's model format of md4. Raven stores their * playermodels in .mdr files, in some games, which are pretty much like the md4 diff --git a/code/renderercommon/tr_image_png.c b/code/renderercommon/tr_image_png.c index 532454c5..7b6fbada 100644 --- a/code/renderercommon/tr_image_png.c +++ b/code/renderercommon/tr_image_png.c @@ -2274,7 +2274,7 @@ void R_LoadPNG(const char *name, byte **pic, int *width, int *height) { case PNG_ColourType_Grey : { - if(!ChunkHeaderLength == 2) + if(ChunkHeaderLength != 2) { CloseBufferedFile(ThePNG); @@ -2296,7 +2296,7 @@ void R_LoadPNG(const char *name, byte **pic, int *width, int *height) case PNG_ColourType_True : { - if(!ChunkHeaderLength == 6) + if(ChunkHeaderLength != 6) { CloseBufferedFile(ThePNG); diff --git a/code/renderergl1/tr_animation.c b/code/renderergl1/tr_animation.c index ad54dd63..7bcc5bdf 100644 --- a/code/renderergl1/tr_animation.c +++ b/code/renderergl1/tr_animation.c @@ -33,140 +33,6 @@ frame. */ -/* -============== -R_AddAnimSurfaces -============== -*/ -void R_AddAnimSurfaces( trRefEntity_t *ent ) { - md4Header_t *header; - md4Surface_t *surface; - md4LOD_t *lod; - shader_t *shader; - int i; - - header = (md4Header_t *) tr.currentModel->modelData; - lod = (md4LOD_t *)( (byte *)header + header->ofsLODs ); - - surface = (md4Surface_t *)( (byte *)lod + lod->ofsSurfaces ); - for ( i = 0 ; i < lod->numSurfaces ; i++ ) { - shader = R_GetShaderByHandle( surface->shaderIndex ); - R_AddDrawSurf( (void *)surface, shader, 0 /*fogNum*/, qfalse ); - surface = (md4Surface_t *)( (byte *)surface + surface->ofsEnd ); - } -} - -/* -============== -RB_SurfaceAnim -============== -*/ -void RB_SurfaceAnim( md4Surface_t *surface ) { - int i, j, k; - float frontlerp, backlerp; - int *triangles; - int indexes; - int baseIndex, baseVertex; - int numVerts; - md4Vertex_t *v; - md4Bone_t bones[MD4_MAX_BONES]; - md4Bone_t *bonePtr, *bone; - md4Header_t *header; - md4Frame_t *frame; - md4Frame_t *oldFrame; - int frameSize; - - - if ( backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame ) { - backlerp = 0; - frontlerp = 1; - } else { - backlerp = backEnd.currentEntity->e.backlerp; - frontlerp = 1.0f - backlerp; - } - header = (md4Header_t *)((byte *)surface + surface->ofsHeader); - - frameSize = (size_t)( &((md4Frame_t *)0)->bones[ header->numBones ] ); - - frame = (md4Frame_t *)((byte *)header + header->ofsFrames + - backEnd.currentEntity->e.frame * frameSize ); - oldFrame = (md4Frame_t *)((byte *)header + header->ofsFrames + - backEnd.currentEntity->e.oldframe * frameSize ); - - RB_CheckOverflow( surface->numVerts, surface->numTriangles * 3 ); - - triangles = (int *) ((byte *)surface + surface->ofsTriangles); - indexes = surface->numTriangles * 3; - baseIndex = tess.numIndexes; - baseVertex = tess.numVertexes; - for (j = 0 ; j < indexes ; j++) { - tess.indexes[baseIndex + j] = baseIndex + triangles[j]; - } - tess.numIndexes += indexes; - - // - // lerp all the needed bones - // - if ( !backlerp ) { - // no lerping needed - bonePtr = frame->bones; - } else { - bonePtr = bones; - for ( i = 0 ; i < header->numBones*12 ; i++ ) { - ((float *)bonePtr)[i] = frontlerp * ((float *)frame->bones)[i] - + backlerp * ((float *)oldFrame->bones)[i]; - } - } - - // - // deform the vertexes by the lerped bones - // - numVerts = surface->numVerts; - // FIXME - // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left - // in for reference. - //v = (md4Vertex_t *) ((byte *)surface + surface->ofsVerts + 12); - v = (md4Vertex_t *) ((byte *)surface + surface->ofsVerts); - for ( j = 0; j < numVerts; j++ ) { - vec3_t tempVert, tempNormal; - md4Weight_t *w; - - VectorClear( tempVert ); - VectorClear( tempNormal ); - w = v->weights; - for ( k = 0 ; k < v->numWeights ; k++, w++ ) { - bone = bonePtr + w->boneIndex; - - tempVert[0] += w->boneWeight * ( DotProduct( bone->matrix[0], w->offset ) + bone->matrix[0][3] ); - tempVert[1] += w->boneWeight * ( DotProduct( bone->matrix[1], w->offset ) + bone->matrix[1][3] ); - tempVert[2] += w->boneWeight * ( DotProduct( bone->matrix[2], w->offset ) + bone->matrix[2][3] ); - - tempNormal[0] += w->boneWeight * DotProduct( bone->matrix[0], v->normal ); - tempNormal[1] += w->boneWeight * DotProduct( bone->matrix[1], v->normal ); - tempNormal[2] += w->boneWeight * DotProduct( bone->matrix[2], v->normal ); - } - - tess.xyz[baseVertex + j][0] = tempVert[0]; - tess.xyz[baseVertex + j][1] = tempVert[1]; - tess.xyz[baseVertex + j][2] = tempVert[2]; - - tess.normal[baseVertex + j][0] = tempNormal[0]; - tess.normal[baseVertex + j][1] = tempNormal[1]; - tess.normal[baseVertex + j][2] = tempNormal[2]; - - tess.texCoords[baseVertex + j][0][0] = v->texCoords[0]; - tess.texCoords[baseVertex + j][0][1] = v->texCoords[1]; - - // FIXME - // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left - // in for reference. - //v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights] + 12 ); - v = (md4Vertex_t *)&v->weights[v->numWeights]; - } - - tess.numVertexes += surface->numVerts; -} - // copied and adapted from tr_mesh.c @@ -195,7 +61,7 @@ static int R_MDRCullModel( mdrHeader_t *header, trRefEntity_t *ent ) { switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) ) { // Ummm... yeah yeah I know we don't really have an md3 here.. but we pretend - // we do. After all, the purpose of md4s are not that different, are they? + // we do. After all, the purpose of mdrs are not that different, are they? case CULL_OUT: tr.pc.c_sphere_cull_md3_out++; @@ -442,7 +308,7 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) { RB_MDRSurfaceAnim ============== */ -void RB_MDRSurfaceAnim( md4Surface_t *surface ) +void RB_MDRSurfaceAnim( mdrSurface_t *surface ) { int i, j, k; float frontlerp, backlerp; @@ -454,7 +320,7 @@ void RB_MDRSurfaceAnim( md4Surface_t *surface ) mdrHeader_t *header; mdrFrame_t *frame; mdrFrame_t *oldFrame; - mdrBone_t bones[MD4_MAX_BONES], *bonePtr, *bone; + mdrBone_t bones[MDR_MAX_BONES], *bonePtr, *bone; int frameSize; diff --git a/code/renderergl1/tr_backend.c b/code/renderergl1/tr_backend.c index 60449261..0a3fe036 100644 --- a/code/renderergl1/tr_backend.c +++ b/code/renderergl1/tr_backend.c @@ -737,6 +737,10 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte * } R_IssuePendingRenderCommands(); + if ( tess.numIndexes ) { + RB_EndSurface(); + } + // we definately want to sync every frame for the cinematics qglFinish(); diff --git a/code/renderergl1/tr_flares.c b/code/renderergl1/tr_flares.c index 1d0a9175..7bd95194 100644 --- a/code/renderergl1/tr_flares.c +++ b/code/renderergl1/tr_flares.c @@ -86,6 +86,19 @@ flare_t *r_activeFlares, *r_inactiveFlares; int flareCoeff; +/* +================== +R_SetFlareCoeff +================== +*/ +static void R_SetFlareCoeff( void ) { + + if(r_flareCoeff->value == 0.0f) + flareCoeff = atof(FLARE_STDCOEFF); + else + flareCoeff = r_flareCoeff->value; +} + /* ================== R_ClearFlares @@ -102,6 +115,8 @@ void R_ClearFlares( void ) { r_flareStructs[i].next = r_inactiveFlares; r_inactiveFlares = &r_flareStructs[i]; } + + R_SetFlareCoeff(); } @@ -450,11 +465,7 @@ void RB_RenderFlares (void) { if(r_flareCoeff->modified) { - if(r_flareCoeff->value == 0.0f) - flareCoeff = atof(FLARE_STDCOEFF); - else - flareCoeff = r_flareCoeff->value; - + R_SetFlareCoeff(); r_flareCoeff->modified = qfalse; } diff --git a/code/renderergl1/tr_image.c b/code/renderergl1/tr_image.c index 921bf7d0..d1127829 100644 --- a/code/renderergl1/tr_image.c +++ b/code/renderergl1/tr_image.c @@ -900,6 +900,8 @@ image_t *R_CreateImage( const char *name, byte *pic, int width, int height, qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapClampMode ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapClampMode ); + // FIXME: this stops fog from setting border color? + glState.currenttextures[glState.currenttmu] = 0; qglBindTexture( GL_TEXTURE_2D, 0 ); if ( image->TMU == 1 ) { diff --git a/code/renderergl1/tr_init.c b/code/renderergl1/tr_init.c index 8ab50cd7..08358d16 100644 --- a/code/renderergl1/tr_init.c +++ b/code/renderergl1/tr_init.c @@ -872,16 +872,6 @@ void GL_SetDefaultState( void ) qglEnable( GL_SCISSOR_TEST ); qglDisable( GL_CULL_FACE ); qglDisable( GL_BLEND ); - - qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); - qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); - qglClearDepth( 1.0 ); - - qglDrawBuffer( GL_FRONT ); - qglClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_ACCUM_BUFFER_BIT|GL_STENCIL_BUFFER_BIT ); - - qglDrawBuffer( GL_BACK ); - qglClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_ACCUM_BUFFER_BIT|GL_STENCIL_BUFFER_BIT ); } /* @@ -1039,7 +1029,7 @@ void R_Register( void ) r_ignorehwgamma = ri.Cvar_Get( "r_ignorehwgamma", "0", CVAR_ARCHIVE | CVAR_LATCH); r_mode = ri.Cvar_Get( "r_mode", "3", CVAR_ARCHIVE | CVAR_LATCH ); r_fullscreen = ri.Cvar_Get( "r_fullscreen", "1", CVAR_ARCHIVE ); - r_noborder = ri.Cvar_Get("r_noborder", "0", CVAR_ARCHIVE); + r_noborder = ri.Cvar_Get("r_noborder", "0", CVAR_ARCHIVE | CVAR_LATCH); r_customwidth = ri.Cvar_Get( "r_customwidth", "1600", CVAR_ARCHIVE | CVAR_LATCH ); r_customheight = ri.Cvar_Get( "r_customheight", "1024", CVAR_ARCHIVE | CVAR_LATCH ); r_customPixelAspect = ri.Cvar_Get( "r_customPixelAspect", "1", CVAR_ARCHIVE | CVAR_LATCH ); diff --git a/code/renderergl1/tr_local.h b/code/renderergl1/tr_local.h index dd292bc6..66c13d45 100644 --- a/code/renderergl1/tr_local.h +++ b/code/renderergl1/tr_local.h @@ -41,10 +41,6 @@ typedef unsigned int glIndex_t; #define SHADERNUM_BITS 14 #define MAX_SHADERS (1<ofsFrames); // This is a model that uses some type of compressed Bones. We don't want to uncompress every bone for each rendered frame - // over and over again, we'll uncompress it in this function already, so we must adjust the size of the target md4. + // over and over again, we'll uncompress it in this function already, so we must adjust the size of the target mdr. if(pinmodel->ofsFrames < 0) { // mdrFrame_t is larger than mdrCompFrame_t: @@ -873,162 +866,6 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char return qtrue; } -/* -================= -R_LoadMD4 -================= -*/ - -static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name ) { - int i, j, k, lodindex; - md4Header_t *pinmodel, *md4; - md4Frame_t *frame; - md4LOD_t *lod; - md4Surface_t *surf; - md4Triangle_t *tri; - md4Vertex_t *v; - int version; - int size; - shader_t *sh; - int frameSize; - - pinmodel = (md4Header_t *)buffer; - - version = LittleLong (pinmodel->version); - if (version != MD4_VERSION) { - ri.Printf( PRINT_WARNING, "R_LoadMD4: %s has wrong version (%i should be %i)\n", - mod_name, version, MD4_VERSION); - return qfalse; - } - - mod->type = MOD_MD4; - size = LittleLong(pinmodel->ofsEnd); - mod->dataSize += size; - mod->modelData = md4 = ri.Hunk_Alloc( size, h_low ); - - Com_Memcpy(md4, buffer, size); - - LL(md4->ident); - LL(md4->version); - LL(md4->numFrames); - LL(md4->numBones); - LL(md4->numLODs); - LL(md4->ofsFrames); - LL(md4->ofsLODs); - md4->ofsEnd = size; - - if ( md4->numFrames < 1 ) { - ri.Printf( PRINT_WARNING, "R_LoadMD4: %s has no frames\n", mod_name ); - return qfalse; - } - - // we don't need to swap tags in the renderer, they aren't used - - // swap all the frames - frameSize = (size_t)( &((md4Frame_t *)0)->bones[ md4->numBones ] ); - for ( i = 0 ; i < md4->numFrames ; i++) { - frame = (md4Frame_t *) ( (byte *)md4 + md4->ofsFrames + i * frameSize ); - frame->radius = LittleFloat( frame->radius ); - for ( j = 0 ; j < 3 ; j++ ) { - frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] ); - frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] ); - frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] ); - } - for ( j = 0 ; j < md4->numBones * sizeof( md4Bone_t ) / 4 ; j++ ) { - ((float *)frame->bones)[j] = LittleFloat( ((float *)frame->bones)[j] ); - } - } - - // swap all the LOD's - lod = (md4LOD_t *) ( (byte *)md4 + md4->ofsLODs ); - for ( lodindex = 0 ; lodindex < md4->numLODs ; lodindex++ ) { - - // swap all the surfaces - surf = (md4Surface_t *) ( (byte *)lod + lod->ofsSurfaces ); - for ( i = 0 ; i < lod->numSurfaces ; i++) { - LL(surf->ident); - LL(surf->numTriangles); - LL(surf->ofsTriangles); - LL(surf->numVerts); - LL(surf->ofsVerts); - LL(surf->ofsEnd); - - if ( surf->numVerts >= SHADER_MAX_VERTEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadMD4: %s has more than %i verts on %s (%i).\n", - mod_name, SHADER_MAX_VERTEXES - 1, surf->name[0] ? surf->name : "a surface", - surf->numVerts ); - return qfalse; - } - if ( surf->numTriangles*3 >= SHADER_MAX_INDEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadMD4: %s has more than %i triangles on %s (%i).\n", - mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, surf->name[0] ? surf->name : "a surface", - surf->numTriangles ); - return qfalse; - } - - // change to surface identifier - surf->ident = SF_MD4; - - // lowercase the surface name so skin compares are faster - Q_strlwr( surf->name ); - - // register the shaders - sh = R_FindShader( surf->shader, LIGHTMAP_NONE, qtrue ); - if ( sh->defaultShader ) { - surf->shaderIndex = 0; - } else { - surf->shaderIndex = sh->index; - } - - // swap all the triangles - tri = (md4Triangle_t *) ( (byte *)surf + surf->ofsTriangles ); - for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) { - LL(tri->indexes[0]); - LL(tri->indexes[1]); - LL(tri->indexes[2]); - } - - // swap all the vertexes - // FIXME - // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left - // in for reference. - //v = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts + 12); - v = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts); - for ( j = 0 ; j < surf->numVerts ; j++ ) { - v->normal[0] = LittleFloat( v->normal[0] ); - v->normal[1] = LittleFloat( v->normal[1] ); - v->normal[2] = LittleFloat( v->normal[2] ); - - v->texCoords[0] = LittleFloat( v->texCoords[0] ); - v->texCoords[1] = LittleFloat( v->texCoords[1] ); - - v->numWeights = LittleLong( v->numWeights ); - - for ( k = 0 ; k < v->numWeights ; k++ ) { - v->weights[k].boneIndex = LittleLong( v->weights[k].boneIndex ); - v->weights[k].boneWeight = LittleFloat( v->weights[k].boneWeight ); - v->weights[k].offset[0] = LittleFloat( v->weights[k].offset[0] ); - v->weights[k].offset[1] = LittleFloat( v->weights[k].offset[1] ); - v->weights[k].offset[2] = LittleFloat( v->weights[k].offset[2] ); - } - // FIXME - // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left - // in for reference. - //v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights] + 12 ); - v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights]); - } - - // find the next surface - surf = (md4Surface_t *)( (byte *)surf + surf->ofsEnd ); - } - - // find the next LOD - lod = (md4LOD_t *)( (byte *)lod + lod->ofsEnd ); - } - - return qtrue; -} - //============================================================================= @@ -1049,11 +886,6 @@ void RE_BeginRegistration( glconfig_t *glconfigOut ) { RE_ClearScene(); tr.registered = qtrue; - - // NOTE: this sucks, for some reason the first stretch pic is never drawn - // without this we'd see a white flash on a level load because the very - // first time the level shot would not be drawn -// RE_StretchPic(0, 0, 0, 0, 0, 0, 1, 1, 0); } //============================================================================= @@ -1265,17 +1097,6 @@ void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) { VectorCopy( frame->bounds[0], mins ); VectorCopy( frame->bounds[1], maxs ); - return; - } else if (model->type == MOD_MD4) { - md4Header_t *header; - md4Frame_t *frame; - - header = (md4Header_t *)model->modelData; - frame = (md4Frame_t *) ((byte *)header + header->ofsFrames); - - VectorCopy( frame->bounds[0], mins ); - VectorCopy( frame->bounds[1], maxs ); - return; } else if (model->type == MOD_MDR) { mdrHeader_t *header; diff --git a/code/renderergl1/tr_model_iqm.c b/code/renderergl1/tr_model_iqm.c index a0cdbe75..0f99f160 100644 --- a/code/renderergl1/tr_model_iqm.c +++ b/code/renderergl1/tr_model_iqm.c @@ -25,6 +25,13 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define LL(x) x=LittleLong(x) +// 3x4 identity matrix +static float identityMatrix[12] = { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0 +}; + static qboolean IQM_CheckRange( iqmHeader_t *header, int offset, int count,int size ) { // return true if the range specified by offset, count and size @@ -143,6 +150,7 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na iqmData_t *iqmData; srfIQModel_t *surface; char meshName[MAX_QPATH]; + byte blendIndexesType, blendWeightsType; if( filesize < sizeof(iqmHeader_t) ) { return qfalse; @@ -198,6 +206,8 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na return qfalse; } + blendIndexesType = blendWeightsType = IQM_UBYTE; + // check and swap vertex arrays if( IQM_CheckRange( header, header->ofs_vertexarrays, header->num_vertexarrays, @@ -264,11 +274,20 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na } break; case IQM_BLENDINDEXES: + if( (vertexarray->format != IQM_INT && + vertexarray->format != IQM_UBYTE) || + vertexarray->size != 4 ) { + return qfalse; + } + blendIndexesType = vertexarray->format; + break; case IQM_BLENDWEIGHTS: - if( vertexarray->format != IQM_UBYTE || + if( (vertexarray->format != IQM_FLOAT && + vertexarray->format != IQM_UBYTE) || vertexarray->size != 4 ) { return qfalse; } + blendWeightsType = vertexarray->format; break; case IQM_COLOR: if( vertexarray->format != IQM_UBYTE || @@ -343,7 +362,9 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na } } - if( header->num_poses != header->num_joints ) { + if( header->num_poses != header->num_joints && header->num_poses != 0 ) { + ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has %d poses and %d joints, must have the same number or 0 poses\n", + mod_name, header->num_poses, header->num_joints ); return qfalse; } @@ -379,7 +400,10 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na joint_names += strlen( (char *)header + header->ofs_text + joint->name ) + 1; } + } + if ( header->num_poses ) + { // check and swap poses if( IQM_CheckRange( header, header->ofs_poses, header->num_poses, sizeof(iqmPose_t) ) ) { @@ -438,7 +462,7 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na size = sizeof(iqmData_t); size += header->num_meshes * sizeof( srfIQModel_t ); size += header->num_joints * 12 * sizeof( float ); // joint mats - size += header->num_joints * header->num_frames * 12 * sizeof( float ); // pose mats + size += header->num_poses * header->num_frames * 12 * sizeof( float ); // pose mats if(header->ofs_bounds) size += header->num_frames * 6 * sizeof(float); // model bounds size += header->num_vertexes * 3 * sizeof(float); // positions @@ -446,12 +470,18 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na size += header->num_vertexes * 3 * sizeof(float); // normals size += header->num_vertexes * 4 * sizeof(float); // tangents size += header->num_vertexes * 4 * sizeof(byte); // blendIndexes - size += header->num_vertexes * 4 * sizeof(byte); // blendWeights size += header->num_vertexes * 4 * sizeof(byte); // colors size += header->num_joints * sizeof(int); // parents size += header->num_triangles * 3 * sizeof(int); // triangles size += joint_names; // joint names + // blendWeights + if (blendWeightsType == IQM_FLOAT) { + size += header->num_vertexes * 4 * sizeof(float); + } else { + size += header->num_vertexes * 4 * sizeof(byte); + } + mod->type = MOD_IQM; iqmData = (iqmData_t *)ri.Hunk_Alloc( size, h_low ); mod->modelData = iqmData; @@ -462,28 +492,40 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na iqmData->num_frames = header->num_frames; iqmData->num_surfaces = header->num_meshes; iqmData->num_joints = header->num_joints; + iqmData->num_poses = header->num_poses; + iqmData->blendWeightsType = blendWeightsType; iqmData->surfaces = (srfIQModel_t *)(iqmData + 1); iqmData->jointMats = (float *) (iqmData->surfaces + iqmData->num_surfaces); iqmData->poseMats = iqmData->jointMats + 12 * header->num_joints; if(header->ofs_bounds) { - iqmData->bounds = iqmData->poseMats + 12 * header->num_joints * header->num_frames; + iqmData->bounds = iqmData->poseMats + 12 * header->num_poses * header->num_frames; iqmData->positions = iqmData->bounds + 6 * header->num_frames; } else - iqmData->positions = iqmData->poseMats + 12 * header->num_joints * header->num_frames; + iqmData->positions = iqmData->poseMats + 12 * header->num_poses * header->num_frames; iqmData->texcoords = iqmData->positions + 3 * header->num_vertexes; iqmData->normals = iqmData->texcoords + 2 * header->num_vertexes; iqmData->tangents = iqmData->normals + 3 * header->num_vertexes; iqmData->blendIndexes = (byte *)(iqmData->tangents + 4 * header->num_vertexes); - iqmData->blendWeights = iqmData->blendIndexes + 4 * header->num_vertexes; - iqmData->colors = iqmData->blendWeights + 4 * header->num_vertexes; + + if(blendWeightsType == IQM_FLOAT) { + iqmData->blendWeights.f = (float *)(iqmData->blendIndexes + 4 * header->num_vertexes); + iqmData->colors = (byte *)(iqmData->blendWeights.f + 4 * header->num_vertexes); + } else { + iqmData->blendWeights.b = iqmData->blendIndexes + 4 * header->num_vertexes; + iqmData->colors = iqmData->blendWeights.b + 4 * header->num_vertexes; + } + iqmData->jointParents = (int *)(iqmData->colors + 4 * header->num_vertexes); iqmData->triangles = iqmData->jointParents + header->num_joints; iqmData->names = (char *)(iqmData->triangles + 3 * header->num_triangles); if ( header->num_joints == 0 ) - iqmData->jointMats = iqmData->poseMats = NULL; + iqmData->jointMats = NULL; + + if ( header->num_poses == 0 ) + iqmData->poseMats = NULL; // calculate joint matrices and their inverses // joint inverses are needed only until the pose matrices are calculated @@ -620,14 +662,27 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na n * sizeof(float) ); break; case IQM_BLENDINDEXES: - Com_Memcpy( iqmData->blendIndexes, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); + if( blendIndexesType == IQM_INT ) { + int *data = (int*)((byte*)header + vertexarray->offset); + for ( j = 0; j < n; j++ ) { + iqmData->blendIndexes[j] = (byte)data[j]; + } + } else { + Com_Memcpy( iqmData->blendIndexes, + (byte *)header + vertexarray->offset, + n * sizeof(byte) ); + } break; case IQM_BLENDWEIGHTS: - Com_Memcpy( iqmData->blendWeights, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); + if( blendWeightsType == IQM_FLOAT ) { + Com_Memcpy( iqmData->blendWeights.f, + (byte *)header + vertexarray->offset, + n * sizeof(float) ); + } else { + Com_Memcpy( iqmData->blendWeights.b, + (byte *)header + vertexarray->offset, + n * sizeof(byte) ); + } break; case IQM_COLOR: Com_Memcpy( iqmData->colors, @@ -892,9 +947,21 @@ static void ComputePoseMats( iqmData_t *data, int frame, int oldframe, int *joint = data->jointParents; int i; - if ( oldframe == frame ) { - mat1 = data->poseMats + 12 * data->num_joints * frame; + if ( data->num_poses == 0 ) { for( i = 0; i < data->num_joints; i++, joint++ ) { + if( *joint >= 0 ) { + Matrix34Multiply( mat + 12 * *joint, + identityMatrix, mat + 12*i ); + } else { + Com_Memcpy( mat + 12*i, identityMatrix, 12 * sizeof(float) ); + } + } + return; + } + + if ( oldframe == frame ) { + mat1 = data->poseMats + 12 * data->num_poses * frame; + for( i = 0; i < data->num_poses; i++, joint++ ) { if( *joint >= 0 ) { Matrix34Multiply( mat + 12 * *joint, mat1 + 12*i, mat + 12*i ); @@ -903,10 +970,10 @@ static void ComputePoseMats( iqmData_t *data, int frame, int oldframe, } } } else { - mat1 = data->poseMats + 12 * data->num_joints * frame; - mat2 = data->poseMats + 12 * data->num_joints * oldframe; + mat1 = data->poseMats + 12 * data->num_poses * frame; + mat2 = data->poseMats + 12 * data->num_poses * oldframe; - for( i = 0; i < data->num_joints; i++, joint++ ) { + for( i = 0; i < data->num_poses; i++, joint++ ) { if( *joint >= 0 ) { float tmpMat[12]; InterpolateMatrix( mat1 + 12*i, mat2 + 12*i, @@ -974,7 +1041,7 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) { outColor = &tess.vertexColors[tess.numVertexes]; // compute interpolated joint matrices - if ( data->num_joints > 0 ) { + if ( data->num_poses > 0 ) { ComputePoseMats( data, frame, oldframe, backlerp, jointMats ); } @@ -985,28 +1052,31 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) { float vtxMat[12]; float nrmMat[9]; int vtx = i + surf->first_vertex; + float blendWeights[4]; + int numWeights; - if ( data->num_joints == 0 || data->blendWeights[4*vtx] <= 0 ) { + for ( numWeights = 0; numWeights < 4; numWeights++ ) { + if ( data->blendWeightsType == IQM_FLOAT ) + blendWeights[numWeights] = data->blendWeights.f[4*vtx + numWeights]; + else + blendWeights[numWeights] = (float)data->blendWeights.b[4*vtx + numWeights] / 255.0f; + + if ( blendWeights[numWeights] <= 0 ) + break; + } + + if ( data->num_poses == 0 || numWeights == 0 ) { // no blend joint, use identity matrix. - for( j = 0; j < 3; j++ ) { - for( k = 0; k < 4; k++ ) - vtxMat[4*j+k] = ( k == j ) ? 1 : 0; - } + Com_Memcpy( vtxMat, identityMatrix, 12 * sizeof (float) ); } else { // compute the vertex matrix by blending the up to // four blend weights - for( k = 0; k < 12; k++ ) - vtxMat[k] = data->blendWeights[4*vtx] - * jointMats[12*data->blendIndexes[4*vtx] + k]; - for( j = 1; j < 4; j++ ) { - if( data->blendWeights[4*vtx + j] <= 0 ) - break; - for( k = 0; k < 12; k++ ) - vtxMat[k] += data->blendWeights[4*vtx + j] - * jointMats[12*data->blendIndexes[4*vtx + j] + k]; + Com_Memset( vtxMat, 0, 12 * sizeof (float) ); + for( j = 0; j < numWeights; j++ ) { + for( k = 0; k < 12; k++ ) { + vtxMat[k] += blendWeights[j] * jointMats[12*data->blendIndexes[4*vtx + j] + k]; + } } - for( k = 0; k < 12; k++ ) - vtxMat[k] *= 1.0f / 255.0f; } // compute the normal matrix as transpose of the adjoint diff --git a/code/renderergl1/tr_shade.c b/code/renderergl1/tr_shade.c index 04cef08b..08648b2e 100644 --- a/code/renderergl1/tr_shade.c +++ b/code/renderergl1/tr_shade.c @@ -1145,12 +1145,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) // // set state // - if ( pStage->bundle[0].vertexLightmap && ( (r_vertexLight->integer && !r_uiFullScreen->integer) || glConfig.hardwareType == GLHW_PERMEDIA2 ) && r_lightmap->integer ) - { - GL_Bind( tr.whiteImage ); - } - else - R_BindAnimatedImage( &pStage->bundle[0] ); + R_BindAnimatedImage( &pStage->bundle[0] ); GL_State( pStage->stateBits ); @@ -1160,7 +1155,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) R_DrawElements( input->numIndexes, input->indexes ); } // allow skipping out to show just lightmaps during development - if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap || pStage->bundle[0].vertexLightmap ) ) + if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap ) ) { break; } diff --git a/code/renderergl1/tr_surface.c b/code/renderergl1/tr_surface.c index 3b4a943b..dca89c5e 100644 --- a/code/renderergl1/tr_surface.c +++ b/code/renderergl1/tr_surface.c @@ -1233,7 +1233,6 @@ void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( void *) = { (void(*)(void*))RB_SurfaceTriangles, // SF_TRIANGLES, (void(*)(void*))RB_SurfacePolychain, // SF_POLY, (void(*)(void*))RB_SurfaceMesh, // SF_MD3, - (void(*)(void*))RB_SurfaceAnim, // SF_MD4, (void(*)(void*))RB_MDRSurfaceAnim, // SF_MDR, (void(*)(void*))RB_IQMSurfaceAnim, // SF_IQM, (void(*)(void*))RB_SurfaceFlare, // SF_FLARE, diff --git a/code/renderergl2/glsl/bokeh_vp.glsl b/code/renderergl2/glsl/bokeh_vp.glsl index 5ca41600..bdaa74af 100644 --- a/code/renderergl2/glsl/bokeh_vp.glsl +++ b/code/renderergl2/glsl/bokeh_vp.glsl @@ -1,4 +1,4 @@ -attribute vec4 attr_Position; +attribute vec3 attr_Position; attribute vec4 attr_TexCoord0; uniform mat4 u_ModelViewProjectionMatrix; @@ -8,6 +8,6 @@ varying vec2 var_TexCoords; void main() { - gl_Position = u_ModelViewProjectionMatrix * attr_Position; + gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); var_TexCoords = attr_TexCoord0.st; } diff --git a/code/renderergl2/glsl/calclevels4x_vp.glsl b/code/renderergl2/glsl/calclevels4x_vp.glsl index 5ca41600..bdaa74af 100644 --- a/code/renderergl2/glsl/calclevels4x_vp.glsl +++ b/code/renderergl2/glsl/calclevels4x_vp.glsl @@ -1,4 +1,4 @@ -attribute vec4 attr_Position; +attribute vec3 attr_Position; attribute vec4 attr_TexCoord0; uniform mat4 u_ModelViewProjectionMatrix; @@ -8,6 +8,6 @@ varying vec2 var_TexCoords; void main() { - gl_Position = u_ModelViewProjectionMatrix * attr_Position; + gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); var_TexCoords = attr_TexCoord0.st; } diff --git a/code/renderergl2/glsl/dlight_vp.glsl b/code/renderergl2/glsl/dlight_vp.glsl index d9fd71d0..9566a04c 100644 --- a/code/renderergl2/glsl/dlight_vp.glsl +++ b/code/renderergl2/glsl/dlight_vp.glsl @@ -1,4 +1,4 @@ -attribute vec4 attr_Position; +attribute vec3 attr_Position; attribute vec4 attr_TexCoord0; attribute vec3 attr_Normal; @@ -32,7 +32,7 @@ vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) if (u_DeformGen == DGEN_BULGE) { - phase *= M_PI * 0.25 * st.x; + phase *= st.x; } else // if (u_DeformGen <= DGEN_WAVE_INVERSE_SAWTOOTH) { @@ -48,7 +48,7 @@ vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) } else if (u_DeformGen == DGEN_WAVE_SQUARE) { - func = sign(sin(value * 2.0 * M_PI)); + func = sign(0.5 - fract(value)); } else if (u_DeformGen == DGEN_WAVE_TRIANGLE) { @@ -62,7 +62,7 @@ vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) { func = (1.0 - fract(value)); } - else if (u_DeformGen == DGEN_BULGE) + else // if (u_DeformGen == DGEN_BULGE) { func = sin(value); } @@ -73,16 +73,16 @@ vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) void main() { - vec4 position = attr_Position; - vec3 normal = attr_Normal; + vec3 position = attr_Position; + vec3 normal = attr_Normal * 2.0 - vec3(1.0); #if defined(USE_DEFORM_VERTEXES) - position.xyz = DeformPosition(position.xyz, normal, attr_TexCoord0.st); + position = DeformPosition(position, normal, attr_TexCoord0.st); #endif - gl_Position = u_ModelViewProjectionMatrix * position; + gl_Position = u_ModelViewProjectionMatrix * vec4(position, 1.0); - vec3 dist = u_DlightInfo.xyz - position.xyz; + vec3 dist = u_DlightInfo.xyz - position; var_Tex1 = dist.xy * u_DlightInfo.a + vec2(0.5); float dlightmod = step(0.0, dot(dist, normal)); diff --git a/code/renderergl2/glsl/down4x_vp.glsl b/code/renderergl2/glsl/down4x_vp.glsl index 5ca41600..bdaa74af 100644 --- a/code/renderergl2/glsl/down4x_vp.glsl +++ b/code/renderergl2/glsl/down4x_vp.glsl @@ -1,4 +1,4 @@ -attribute vec4 attr_Position; +attribute vec3 attr_Position; attribute vec4 attr_TexCoord0; uniform mat4 u_ModelViewProjectionMatrix; @@ -8,6 +8,6 @@ varying vec2 var_TexCoords; void main() { - gl_Position = u_ModelViewProjectionMatrix * attr_Position; + gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); var_TexCoords = attr_TexCoord0.st; } diff --git a/code/renderergl2/glsl/fogpass_fp.glsl b/code/renderergl2/glsl/fogpass_fp.glsl index 91884304..e2ad465b 100644 --- a/code/renderergl2/glsl/fogpass_fp.glsl +++ b/code/renderergl2/glsl/fogpass_fp.glsl @@ -5,5 +5,5 @@ varying float var_Scale; void main() { gl_FragColor = u_Color; - gl_FragColor.a *= sqrt(clamp(var_Scale, 0.0, 1.0)); + gl_FragColor.a = sqrt(clamp(var_Scale, 0.0, 1.0)); } diff --git a/code/renderergl2/glsl/fogpass_vp.glsl b/code/renderergl2/glsl/fogpass_vp.glsl index 40d14d9f..8f7bc728 100644 --- a/code/renderergl2/glsl/fogpass_vp.glsl +++ b/code/renderergl2/glsl/fogpass_vp.glsl @@ -1,27 +1,30 @@ -attribute vec4 attr_Position; +attribute vec3 attr_Position; attribute vec3 attr_Normal; + attribute vec4 attr_TexCoord0; -//#if defined(USE_VERTEX_ANIMATION) -attribute vec4 attr_Position2; +#if defined(USE_VERTEX_ANIMATION) +attribute vec3 attr_Position2; attribute vec3 attr_Normal2; -//#endif +#endif uniform vec4 u_FogDistance; uniform vec4 u_FogDepth; uniform float u_FogEyeT; -//#if defined(USE_DEFORM_VERTEXES) +#if defined(USE_DEFORM_VERTEXES) uniform int u_DeformGen; uniform float u_DeformParams[5]; -//#endif +#endif uniform float u_Time; uniform mat4 u_ModelViewProjectionMatrix; -//#if defined(USE_VERTEX_ANIMATION) +#if defined(USE_VERTEX_ANIMATION) uniform float u_VertexLerp; -//#endif +#endif + +uniform vec4 u_Color; varying float var_Scale; @@ -41,7 +44,7 @@ vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) if (u_DeformGen == DGEN_BULGE) { - phase *= M_PI * 0.25 * st.x; + phase *= st.x; } else // if (u_DeformGen <= DGEN_WAVE_INVERSE_SAWTOOTH) { @@ -57,7 +60,7 @@ vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) } else if (u_DeformGen == DGEN_WAVE_SQUARE) { - func = sign(sin(value * 2.0 * M_PI)); + func = sign(0.5 - fract(value)); } else if (u_DeformGen == DGEN_WAVE_TRIANGLE) { @@ -71,7 +74,7 @@ vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) { func = (1.0 - fract(value)); } - else if (u_DeformGen == DGEN_BULGE) + else // if (u_DeformGen == DGEN_BULGE) { func = sin(value); } @@ -80,35 +83,36 @@ vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) } #endif -float CalcFog(vec4 position) +float CalcFog(vec3 position) { - float s = dot(position, u_FogDistance) * 8.0; - float t = dot(position, u_FogDepth); + float s = dot(vec4(position, 1.0), u_FogDistance) * 8.0; + float t = dot(vec4(position, 1.0), u_FogDepth); - bool eyeOutside = u_FogEyeT < 0.0; - float t2 = float(t >= float(eyeOutside)); + float eyeOutside = float(u_FogEyeT < 0.0); + float fogged = float(t >= eyeOutside); - if (eyeOutside) - t2 *= t / (t - u_FogEyeT); + t += 1e-6; + t *= fogged / (t - u_FogEyeT * eyeOutside); - return s * t2; + return s * t; } void main() { #if defined(USE_VERTEX_ANIMATION) - vec4 position = mix(attr_Position, attr_Position2, u_VertexLerp); - vec3 normal = normalize(mix(attr_Normal, attr_Normal2, u_VertexLerp)); + vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp); + vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp); + normal = normalize(normal - vec3(0.5)); #else - vec4 position = attr_Position; - vec3 normal = attr_Normal; + vec3 position = attr_Position; + vec3 normal = attr_Normal * 2.0 - vec3(1.0); #endif #if defined(USE_DEFORM_VERTEXES) position.xyz = DeformPosition(position.xyz, normal, attr_TexCoord0.st); #endif - gl_Position = u_ModelViewProjectionMatrix * position; + gl_Position = u_ModelViewProjectionMatrix * vec4(position, 1.0); - var_Scale = CalcFog(position); + var_Scale = CalcFog(position) * u_Color.a * u_Color.a; } diff --git a/code/renderergl2/glsl/generic_fp.glsl b/code/renderergl2/glsl/generic_fp.glsl index 997d4daa..f485797f 100644 --- a/code/renderergl2/glsl/generic_fp.glsl +++ b/code/renderergl2/glsl/generic_fp.glsl @@ -37,6 +37,8 @@ void main() { color = color2; } + + //color = color * (u_Texture1Env.xxxx + color2 * u_Texture1Env.z) + color2 * u_Texture1Env.y; #endif gl_FragColor = color * var_Color; diff --git a/code/renderergl2/glsl/generic_vp.glsl b/code/renderergl2/glsl/generic_vp.glsl index 9ad4489b..0e5b38b4 100644 --- a/code/renderergl2/glsl/generic_vp.glsl +++ b/code/renderergl2/glsl/generic_vp.glsl @@ -1,8 +1,8 @@ -attribute vec4 attr_Position; +attribute vec3 attr_Position; attribute vec3 attr_Normal; #if defined(USE_VERTEX_ANIMATION) -attribute vec4 attr_Position2; +attribute vec3 attr_Position2; attribute vec3 attr_Normal2; #endif @@ -17,7 +17,7 @@ uniform vec4 u_DiffuseTexMatrix; uniform vec4 u_DiffuseTexOffTurb; #if defined(USE_TCGEN) || defined(USE_RGBAGEN) -uniform vec3 u_ViewOrigin; +uniform vec3 u_LocalViewOrigin; #endif #if defined(USE_TCGEN) @@ -48,7 +48,7 @@ uniform int u_ColorGen; uniform int u_AlphaGen; uniform vec3 u_AmbientLight; uniform vec3 u_DirectedLight; -uniform vec4 u_LightOrigin; +uniform vec3 u_ModelLightDir; uniform float u_PortalRange; #endif @@ -73,7 +73,7 @@ vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) if (u_DeformGen == DGEN_BULGE) { - phase *= M_PI * 0.25 * st.x; + phase *= st.x; } else // if (u_DeformGen <= DGEN_WAVE_INVERSE_SAWTOOTH) { @@ -89,7 +89,7 @@ vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) } else if (u_DeformGen == DGEN_WAVE_SQUARE) { - func = sign(sin(value * 2.0 * M_PI)); + func = sign(fract(0.5 - value)); } else if (u_DeformGen == DGEN_WAVE_TRIANGLE) { @@ -103,7 +103,7 @@ vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) { func = (1.0 - fract(value)); } - else if (u_DeformGen == DGEN_BULGE) + else // if (u_DeformGen == DGEN_BULGE) { func = sin(value); } @@ -123,8 +123,10 @@ vec2 GenTexCoords(int TCGen, vec3 position, vec3 normal, vec3 TCGenVector0, vec3 } else if (TCGen == TCGEN_ENVIRONMENT_MAPPED) { - vec3 viewer = normalize(u_ViewOrigin - position); - tex = -reflect(viewer, normal).yz * vec2(0.5, -0.5) + 0.5; + vec3 viewer = normalize(u_LocalViewOrigin - position); + vec2 ref = reflect(viewer, normal).yz; + tex.s = ref.x * -0.5 + 0.5; + tex.t = ref.y * 0.5 + 0.5; } else if (TCGen == TCGEN_VECTOR) { @@ -139,13 +141,14 @@ vec2 GenTexCoords(int TCGen, vec3 position, vec3 normal, vec3 TCGenVector0, vec3 vec2 ModTexCoords(vec2 st, vec3 position, vec4 texMatrix, vec4 offTurb) { float amplitude = offTurb.z; - float phase = offTurb.w; - vec2 st2 = vec2(dot(st, texMatrix.xz), dot(st, texMatrix.yw)) + offTurb.xy; + float phase = offTurb.w * 2.0 * M_PI; + vec2 st2; + st2.x = st.x * texMatrix.x + (st.y * texMatrix.z + offTurb.x); + st2.y = st.x * texMatrix.y + (st.y * texMatrix.w + offTurb.y); - vec3 offsetPos = position / 1024.0; - offsetPos.x += offsetPos.z; + vec2 offsetPos = vec2(position.x + position.z, position.y); - vec2 texOffset = sin((offsetPos.xy + vec2(phase)) * 2.0 * M_PI); + vec2 texOffset = sin(offsetPos * (2.0 * M_PI / 1024.0) + vec2(phase)); return st2 + texOffset * amplitude; } @@ -158,30 +161,25 @@ vec4 CalcColor(vec3 position, vec3 normal) if (u_ColorGen == CGEN_LIGHTING_DIFFUSE) { - float incoming = clamp(dot(normal, u_LightOrigin.xyz), 0.0, 1.0); + float incoming = clamp(dot(normal, u_ModelLightDir), 0.0, 1.0); color.rgb = clamp(u_DirectedLight * incoming + u_AmbientLight, 0.0, 1.0); } - vec3 toView = u_ViewOrigin - position; - vec3 viewer = normalize(u_ViewOrigin - position); + vec3 viewer = u_LocalViewOrigin - position; if (u_AlphaGen == AGEN_LIGHTING_SPECULAR) { - vec3 lightDir = normalize(vec3(-960.0, -1980.0, 96.0) - position.xyz); - vec3 halfangle = normalize(lightDir + viewer); + vec3 lightDir = normalize(vec3(-960.0, 1980.0, 96.0) - position); + vec3 reflected = -reflect(lightDir, normal); - color.a = pow(max(dot(normal, halfangle), 0.0), 8.0); + color.a = clamp(dot(reflected, normalize(viewer)), 0.0, 1.0); + color.a *= color.a; + color.a *= color.a; } else if (u_AlphaGen == AGEN_PORTAL) { - float alpha = length(toView) / u_PortalRange; - - color.a = clamp(alpha, 0.0, 1.0); - } - else if (u_AlphaGen == AGEN_FRESNEL) - { - color.a = 0.10 + 0.90 * pow(1.0 - dot(normal, viewer), 5); + color.a = clamp(length(viewer) / u_PortalRange, 0.0, 1.0); } return color; @@ -189,45 +187,46 @@ vec4 CalcColor(vec3 position, vec3 normal) #endif #if defined(USE_FOG) -float CalcFog(vec4 position) +float CalcFog(vec3 position) { - float s = dot(position, u_FogDistance) * 8.0; - float t = dot(position, u_FogDepth); + float s = dot(vec4(position, 1.0), u_FogDistance) * 8.0; + float t = dot(vec4(position, 1.0), u_FogDepth); - bool eyeOutside = u_FogEyeT < 0.0; - float t2 = float(t >= float(eyeOutside)); + float eyeOutside = float(u_FogEyeT < 0.0); + float fogged = float(t < eyeOutside); - if (eyeOutside) - t2 *= t / (t - u_FogEyeT); + t += 1e-6; + t *= fogged / (t - u_FogEyeT * eyeOutside); - return s * t2; + return s * t; } #endif void main() { #if defined(USE_VERTEX_ANIMATION) - vec4 position = mix(attr_Position, attr_Position2, u_VertexLerp); - vec3 normal = normalize(mix(attr_Normal, attr_Normal2, u_VertexLerp)); + vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp); + vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp); + normal = normalize(normal - vec3(0.5)); #else - vec4 position = attr_Position; - vec3 normal = attr_Normal; + vec3 position = attr_Position; + vec3 normal = attr_Normal * 2.0 - vec3(1.0); #endif #if defined(USE_DEFORM_VERTEXES) - position.xyz = DeformPosition(position.xyz, normal, attr_TexCoord0.st); + position = DeformPosition(position, normal, attr_TexCoord0.st); #endif - gl_Position = u_ModelViewProjectionMatrix * position; + gl_Position = u_ModelViewProjectionMatrix * vec4(position, 1.0); #if defined(USE_TCGEN) - vec2 tex = GenTexCoords(u_TCGen0, position.xyz, normal, u_TCGen0Vector0, u_TCGen0Vector1); + vec2 tex = GenTexCoords(u_TCGen0, position, normal, u_TCGen0Vector0, u_TCGen0Vector1); #else vec2 tex = attr_TexCoord0.st; #endif #if defined(USE_TCMOD) - var_DiffuseTex = ModTexCoords(tex, position.xyz, u_DiffuseTexMatrix, u_DiffuseTexOffTurb); + var_DiffuseTex = ModTexCoords(tex, position, u_DiffuseTexMatrix, u_DiffuseTexOffTurb); #else var_DiffuseTex = tex; #endif @@ -237,7 +236,7 @@ void main() #endif #if defined(USE_RGBAGEN) - var_Color = CalcColor(position.xyz, normal); + var_Color = CalcColor(position, normal); #else var_Color = u_VertColor * attr_Color + u_BaseColor; #endif diff --git a/code/renderergl2/glsl/lightall_fp.glsl b/code/renderergl2/glsl/lightall_fp.glsl index 6dbfe963..d134e409 100644 --- a/code/renderergl2/glsl/lightall_fp.glsl +++ b/code/renderergl2/glsl/lightall_fp.glsl @@ -24,45 +24,49 @@ uniform sampler2D u_ShadowMap; uniform samplerCube u_CubeMap; #endif -#if defined(USE_LIGHT_VECTOR) +#if defined(USE_NORMALMAP) || defined(USE_DELUXEMAP) || defined(USE_SPECULARMAP) || defined(USE_CUBEMAP) +uniform vec4 u_EnableTextures; // x = normal, y = deluxe, z = specular, w = cube +#endif + +#if defined(USE_LIGHT_VECTOR) && !defined(USE_FAST_LIGHT) uniform vec3 u_DirectedLight; uniform vec3 u_AmbientLight; -uniform float u_LightRadius; #endif #if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) uniform vec3 u_PrimaryLightColor; uniform vec3 u_PrimaryLightAmbient; -uniform float u_PrimaryLightRadius; #endif -#if defined(USE_LIGHT) +#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) uniform vec2 u_MaterialInfo; #endif -varying vec2 var_DiffuseTex; -#if defined(USE_LIGHTMAP) -varying vec2 var_LightTex; -#endif +varying vec4 var_TexCoords; + varying vec4 var_Color; -#if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) || defined(USE_PARALLAXMAP) -varying vec3 var_ViewDir; -varying vec3 var_Normal; -varying vec3 var_Tangent; -varying vec3 var_Bitangent; +#if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) + #if defined(USE_VERT_TANGENT_SPACE) +varying vec4 var_Normal; +varying vec4 var_Tangent; +varying vec4 var_Bitangent; + #else +varying vec3 var_Normal; +varying vec3 var_ViewDir; + #endif #endif #if defined(USE_LIGHT_VERTEX) && !defined(USE_FAST_LIGHT) -varying vec3 var_lightColor; +varying vec3 var_LightColor; #endif -#if defined(USE_LIGHT) && !defined(USE_DELUXEMAP) +#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) varying vec4 var_LightDir; #endif #if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) -varying vec3 var_PrimaryLightDir; +varying vec4 var_PrimaryLightDir; #endif @@ -162,36 +166,59 @@ vec3 EnvironmentBRDF(float gloss, float NE, vec3 specular) float a1 = t.w; return clamp( a0 + specular * ( a1 - a0 ), 0.0, 1.0 ); #elif 0 - // from http://seblagarde.wordpress.com/2011/08/17/hello-world/ + // from http://seblagarde.wordpress.com/2011/08/17/hello-world/ return mix(specular.rgb, max(specular.rgb, vec3(gloss)), CalcFresnel(NE)); #else - // from http://advances.realtimerendering.com/s2011/Lazarov-Physically-Based-Lighting-in-Black-Ops%20%28Siggraph%202011%20Advances%20in%20Real-Time%20Rendering%20Course%29.pptx + // from http://advances.realtimerendering.com/s2011/Lazarov-Physically-Based-Lighting-in-Black-Ops%20%28Siggraph%202011%20Advances%20in%20Real-Time%20Rendering%20Course%29.pptx return mix(specular.rgb, vec3(1.0), CalcFresnel(NE) / (4.0 - 3.0 * gloss)); #endif } float CalcBlinn(float NH, float shininess) { -#if 0 - // from http://seblagarde.wordpress.com/2012/06/03/spherical-gaussien-approximation-for-blinn-phong-phong-and-fresnel/ - float a = shininess + 0.775; - return exp(a * NH - a); +#if defined(USE_BLINN) || defined(USE_BLINN_FRESNEL) + // Normalized Blinn-Phong + float norm = shininess * 0.125 + 1.0; +#elif defined(USE_MCAULEY) + // Cook-Torrance as done by Stephen McAuley + // http://blog.selfshadow.com/publications/s2012-shading-course/mcauley/s2012_pbs_farcry3_notes_v2.pdf + float norm = shininess * 0.25 + 0.125; +#elif defined(USE_GOTANDA) + // Neumann-Neumann as done by Yoshiharu Gotanda + // http://research.tri-ace.com/Data/s2012_beyond_CourseNotes.pdf + float norm = shininess * 0.124858 + 0.269182; +#elif defined(USE_LAZAROV) + // Cook-Torrance as done by Dimitar Lazarov + // http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf + float norm = shininess * 0.125 + 0.25; #else - return pow(NH, shininess); + float norm = 1.0; +#endif + +#if 0 + // from http://seblagarde.wordpress.com/2012/06/03/spherical-gaussien-approximation-for-blinn-phong-phong-and-fresnel/ + float a = shininess + 0.775; + return norm * exp(a * NH - a); +#else + return norm * pow(NH, shininess); #endif } -float CalcGGX(float NH, float shininess) +float CalcGGX(float NH, float gloss) { - // from http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes.pdf - float m_sq = 2.0 / shininess; - float d = ((NH * NH) * (m_sq - 1.0) + 1.0); - return m_sq / (d * d); + // from http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf + float a_sq = exp2(gloss * -13.0 + 1.0); + float d = ((NH * NH) * (a_sq - 1.0) + 1.0); + return a_sq / (d * d); } float CalcFresnel(float EH) { #if 1 + // From http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf + // not accurate, but fast + return exp2(-10.0 * EH); +#elif 0 // From http://seblagarde.wordpress.com/2012/06/03/spherical-gaussien-approximation-for-blinn-phong-phong-and-fresnel/ return exp2((-5.55473 * EH - 6.98316) * EH); #elif 0 @@ -201,133 +228,137 @@ float CalcFresnel(float EH) return blend; #else - return pow(1.0 - NH, 5.0); + return pow(1.0 - EH, 5.0); #endif } -float CalcVisibility(float NH, float NL, float NE, float EH, float shininess) +float CalcVisibility(float NH, float NL, float NE, float EH, float gloss) { -#if 0 - float geo = 2.0 * NH * min(NE, NL); - geo /= max(EH, geo); - - return geo; -#else - // Modified from http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes.pdf +#if defined(USE_GOTANDA) + // Neumann-Neumann as done by Yoshiharu Gotanda + // http://research.tri-ace.com/Data/s2012_beyond_CourseNotes.pdf + return 1.0 / max(max(NL, NE), EPSILON); +#elif defined(USE_LAZAROV) + // Cook-Torrance as done by Dimitar Lazarov + // http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf + float k = min(1.0, gloss + 0.545); + return 1.0 / (k * (EH * EH - 1.0) + 1.0); +#elif defined(USE_GGX) + float roughness = exp2(gloss * -6.5); + + // Modified from http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf // NL, NE in numerator factored out from cook-torrance - #if defined(USE_GGX) - float roughness = sqrt(2.0 / (shininess + 2.0)); - float k = (roughness + 1.0); + float k = roughness + 1.0; k *= k * 0.125; - #else - float k = 2.0 / sqrt(3.1415926535 * (shininess + 2.0)); - #endif + float k2 = 1.0 - k; float invGeo1 = NL * k2 + k; float invGeo2 = NE * k2 + k; - + return 1.0 / (invGeo1 * invGeo2); - #endif +#else + return 1.0; +#endif } -vec3 CalcSpecular(vec3 specular, float NH, float NL, float NE, float EH, float shininess) +vec3 CalcSpecular(vec3 specular, float NH, float NL, float NE, float EH, float gloss, float shininess) { - float blinn = CalcBlinn(NH, shininess); +#if defined(USE_GGX) + float distrib = CalcGGX(NH, gloss); +#else + float distrib = CalcBlinn(NH, shininess); +#endif + +#if defined(USE_BLINN) + vec3 fSpecular = specular; +#else vec3 fSpecular = mix(specular, vec3(1.0), CalcFresnel(EH)); - float vis = CalcVisibility(NH, NL, NE, EH, shininess); +#endif - #if defined(USE_BLINN) - // Normalized Blinn-Phong - return specular * blinn * (shininess * 0.125 + 1.0); - #elif defined(USE_BLINN_FRESNEL) - // Normalized Blinn-Phong with Fresnel - return fSpecular * blinn * (shininess * 0.125 + 1.0); - #elif defined(USE_MCAULEY) - // Cook-Torrance as done by Stephen McAuley - // http://blog.selfshadow.com/publications/s2012-shading-course/mcauley/s2012_pbs_farcry3_notes_v2.pdf - return fSpecular * blinn * (shininess * 0.25 + 0.125); - #elif defined(USE_GOTANDA) - // Neumann-Neumann as done by Yoshiharu Gotanda - // http://research.tri-ace.com/Data/s2012_beyond_CourseNotes.pdf - return fSpecular * blinn * (shininess * 0.124858 + 0.269182) / max(max(NL, NE), EPSILON); - #elif defined(USE_LAZAROV) - // Cook-Torrance as done by Dimitar Lazarov - // http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf - return fSpecular * blinn * (shininess * 0.125 + 0.25) * vis; - #endif - - return vec3(0.0); + float vis = CalcVisibility(NH, NL, NE, EH, gloss); + + return fSpecular * (distrib * vis); } -float CalcLightAttenuation(vec3 dir, float sqrRadius) +float CalcLightAttenuation(float point, float normDist) { - // point light at >0 radius, directional otherwise - float point = float(sqrRadius > 0.0); - - // inverse square light - float attenuation = sqrRadius / dot(dir, dir); - - // zero light at radius, approximating q3 style + // zero light at 1.0, approximating q3 style // also don't attenuate directional light - attenuation = (0.5 * attenuation - 1.5) * point + 1.0; - + float attenuation = (0.5 * normDist - 1.5) * point + 1.0; + // clamp attenuation #if defined(NO_LIGHT_CLAMP) - attenuation *= float(attenuation > 0.0); + attenuation = max(attenuation, 0.0); #else attenuation = clamp(attenuation, 0.0, 1.0); #endif - + return attenuation; } +// from http://www.thetenthplanet.de/archives/1180 +mat3 cotangent_frame( vec3 N, vec3 p, vec2 uv ) +{ + // get edge vectors of the pixel triangle + vec3 dp1 = dFdx( p ); + vec3 dp2 = dFdy( p ); + vec2 duv1 = dFdx( uv ); + vec2 duv2 = dFdy( uv ); + + // solve the linear system + vec3 dp2perp = cross( dp2, N ); + vec3 dp1perp = cross( N, dp1 ); + vec3 T = dp2perp * duv1.x + dp1perp * duv2.x; + vec3 B = dp2perp * duv1.y + dp1perp * duv2.y; + + // construct a scale-invariant frame + float invmax = inversesqrt( max( dot(T,T), dot(B,B) ) ); + return mat3( T * invmax, B * invmax, N ); +} void main() { vec3 L, N, E, H; float NL, NH, NE, EH; - -#if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) || defined(USE_PARALLAXMAP) - mat3 tangentToWorld = mat3(var_Tangent, var_Bitangent, var_Normal); -#endif -#if defined(USE_DELUXEMAP) - L = (2.0 * texture2D(u_DeluxeMap, var_LightTex).xyz - vec3(1.0)); - #if defined(USE_TANGENT_SPACE_LIGHT) - L = L * tangentToWorld; +#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) + #if defined(USE_VERT_TANGENT_SPACE) + mat3 tangentToWorld = mat3(var_Tangent.xyz, var_Bitangent.xyz, var_Normal.xyz); + E = vec3(var_Normal.w, var_Tangent.w, var_Bitangent.w); + #else + mat3 tangentToWorld = cotangent_frame(var_Normal, -var_ViewDir, var_TexCoords.xy); + E = var_ViewDir; #endif -#elif defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - L = var_LightDir.xyz; -#endif -#if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) || defined(USE_PARALLAXMAP) - E = normalize(var_ViewDir); + E = normalize(E); + + L = var_LightDir.xyz; + #if defined(USE_DELUXEMAP) + L += (texture2D(u_DeluxeMap, var_TexCoords.zw).xyz - vec3(0.5)) * u_EnableTextures.y; + #endif + float sqrLightDist = dot(L, L); #endif #if defined(USE_LIGHTMAP) - vec4 lightSample = texture2D(u_LightMap, var_LightTex).rgba; - #if defined(RGBM_LIGHTMAP) - lightSample.rgb *= 32.0 * lightSample.a; - #endif + vec4 lightSample = texture2D(u_LightMap, var_TexCoords.zw); vec3 lightColor = lightSample.rgb; + #if defined(RGBM_LIGHTMAP) + lightColor *= 32.0 * lightSample.a; + #endif #elif defined(USE_LIGHT_VECTOR) && !defined(USE_FAST_LIGHT) - vec3 lightColor = u_DirectedLight * CalcLightAttenuation(L, u_LightRadius * u_LightRadius); + vec3 lightColor = u_DirectedLight * CalcLightAttenuation(float(var_LightDir.w > 0.0), var_LightDir.w / sqrLightDist); vec3 ambientColor = u_AmbientLight; #elif defined(USE_LIGHT_VERTEX) && !defined(USE_FAST_LIGHT) - vec3 lightColor = var_lightColor; + vec3 lightColor = var_LightColor; #endif - vec2 texCoords = var_DiffuseTex; + vec2 texCoords = var_TexCoords.xy; #if defined(USE_PARALLAXMAP) - #if defined(USE_TANGENT_SPACE_LIGHT) - vec3 offsetDir = E; - #else - vec3 offsetDir = E * tangentToWorld; - #endif + vec3 offsetDir = normalize(E * tangentToWorld); offsetDir.xy *= -0.05 / offsetDir.z; @@ -335,49 +366,42 @@ void main() #endif vec4 diffuse = texture2D(u_DiffuseMap, texCoords); +#if defined(USE_GAMMA2_TEXTURES) + diffuse.rgb *= diffuse.rgb; +#endif + #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - - #if defined(USE_LINEAR_LIGHT) - diffuse.rgb *= diffuse.rgb; - #endif - #if defined(USE_NORMALMAP) #if defined(SWIZZLE_NORMALMAP) - N.xy = 2.0 * texture2D(u_NormalMap, texCoords).ag - vec2(1.0); + N.xy = texture2D(u_NormalMap, texCoords).ag - vec2(0.5); #else - N.xy = 2.0 * texture2D(u_NormalMap, texCoords).rg - vec2(1.0); + N.xy = texture2D(u_NormalMap, texCoords).rg - vec2(0.5); #endif - N.z = sqrt(1.0 - clamp(dot(N.xy, N.xy), 0.0, 1.0)); - #if !defined(USE_TANGENT_SPACE_LIGHT) - N = normalize(tangentToWorld * N); - #endif - #elif defined(USE_TANGENT_SPACE_LIGHT) - N = vec3(0.0, 0.0, 1.0); + N.xy *= u_EnableTextures.x; + N.z = sqrt((0.25 - N.x * N.x) - N.y * N.y); + N = tangentToWorld * N; #else - N = normalize(var_Normal); + N = var_Normal.xyz; #endif - - L = normalize(L); + + N = normalize(N); + L /= sqrt(sqrLightDist); #if defined(USE_SHADOWMAP) vec2 shadowTex = gl_FragCoord.xy * r_FBufScale; float shadowValue = texture2D(u_ShadowMap, shadowTex).r; // surfaces not facing the light are always shadowed - #if defined(USE_TANGENT_SPACE_LIGHT) - shadowValue *= float(var_PrimaryLightDir.z > 0.0); - #else - shadowValue *= float(dot(var_Normal, var_PrimaryLightDir) > 0.0); - #endif - + shadowValue *= float(dot(var_Normal.xyz, var_PrimaryLightDir.xyz) > 0.0); + #if defined(SHADOWMAP_MODULATE) //vec3 shadowColor = min(u_PrimaryLightAmbient, lightColor); vec3 shadowColor = u_PrimaryLightAmbient * lightColor; #if 0 // Only shadow when the world light is parallel to the primary light - shadowValue = 1.0 + (shadowValue - 1.0) * clamp(dot(L, var_PrimaryLightDir), 0.0, 1.0); + shadowValue = 1.0 + (shadowValue - 1.0) * clamp(dot(L, var_PrimaryLightDir.xyz), 0.0, 1.0); #endif lightColor = mix(shadowColor, lightColor, shadowValue); #endif @@ -385,12 +409,7 @@ void main() #if defined(USE_LIGHTMAP) || defined(USE_LIGHT_VERTEX) vec3 ambientColor = lightColor; - - #if defined(USE_TANGENT_SPACE_LIGHT) - float surfNL = L.z; - #else - float surfNL = clamp(dot(var_Normal, L), 0.0, 1.0); - #endif + float surfNL = clamp(dot(var_Normal.xyz, L), 0.0, 1.0); // Scale the incoming light to compensate for the baked-in light angle // attenuation. @@ -406,105 +425,104 @@ void main() NL = clamp(dot(N, L), 0.0, 1.0); NE = clamp(dot(N, E), 0.0, 1.0); - #if defined(USE_SPECULARMAP) - vec4 specular = texture2D(u_SpecularMap, texCoords); - #if defined(USE_LINEAR_LIGHT) - specular.rgb *= specular.rgb; - #endif - #else vec4 specular = vec4(1.0); + #if defined(USE_SPECULARMAP) + specular += texture2D(u_SpecularMap, texCoords) * u_EnableTextures.z - u_EnableTextures.zzzz; + #if defined(USE_GAMMA2_TEXTURES) + specular.rgb *= specular.rgb; + #endif #endif specular *= u_MaterialInfo.xxxy; - + float gloss = specular.a; float shininess = exp2(gloss * 13.0); - float localOcclusion = clamp((diffuse.r + diffuse.g + diffuse.b) * 16.0f, 0.0, 1.0); #if defined(SPECULAR_IS_METALLIC) - // diffuse is actually base color, and red of specular is metallicness + // diffuse is actually base color, and red of specular is metallicness float metallic = specular.r; - - specular.rgb = vec3(0.04) + 0.96 * diffuse.rgb * metallic; + + specular.rgb = (0.96 * metallic) * diffuse.rgb + vec3(0.04); diffuse.rgb *= 1.0 - metallic; #else // adjust diffuse by specular reflectance, to maintain energy conservation diffuse.rgb *= vec3(1.0) - specular.rgb; #endif - - + reflectance = CalcDiffuse(diffuse.rgb, N, L, E, NE, NL, shininess); #if defined(r_deluxeSpecular) || defined(USE_LIGHT_VECTOR) + float adjGloss = gloss; float adjShininess = shininess; - - #if !defined(USE_LIGHT_VECTOR) - adjShininess = exp2(gloss * r_deluxeSpecular * 13.0); - #endif - + + #if !defined(USE_LIGHT_VECTOR) + adjGloss *= r_deluxeSpecular; + adjShininess = exp2(adjGloss * 13.0); + #endif + H = normalize(L + E); EH = clamp(dot(E, H), 0.0, 1.0); NH = clamp(dot(N, H), 0.0, 1.0); #if !defined(USE_LIGHT_VECTOR) - reflectance += CalcSpecular(specular.rgb, NH, NL, NE, EH, adjShininess) * r_deluxeSpecular * localOcclusion; + reflectance += CalcSpecular(specular.rgb, NH, NL, NE, EH, adjGloss, adjShininess) * r_deluxeSpecular; #else - reflectance += CalcSpecular(specular.rgb, NH, NL, NE, EH, adjShininess) * localOcclusion; + reflectance += CalcSpecular(specular.rgb, NH, NL, NE, EH, adjGloss, adjShininess); #endif #endif - - gl_FragColor.rgb = lightColor * reflectance * NL; + + gl_FragColor.rgb = lightColor * reflectance * NL; gl_FragColor.rgb += ambientColor * (diffuse.rgb + specular.rgb); - + #if defined(USE_CUBEMAP) reflectance = EnvironmentBRDF(gloss, NE, specular.rgb); vec3 R = reflect(E, N); - #if defined(USE_TANGENT_SPACE_LIGHT) - R = tangentToWorld * R; - #endif - vec3 cubeLightColor = textureCubeLod(u_CubeMap, R, 7.0 - gloss * 7.0).rgb; - - #if defined(USE_LINEAR_LIGHT) - cubeLightColor *= cubeLightColor; - #endif + vec3 cubeLightColor = textureCubeLod(u_CubeMap, R, 7.0 - gloss * 7.0).rgb * u_EnableTextures.w; #if defined(USE_LIGHTMAP) cubeLightColor *= lightSample.rgb; #elif defined (USE_LIGHT_VERTEX) - cubeLightColor *= var_lightColor; + cubeLightColor *= var_LightColor; #else cubeLightColor *= lightColor * NL + ambientColor; #endif - - //gl_FragColor.rgb += diffuse.rgb * textureCubeLod(u_CubeMap, N, 7.0).rgb; - gl_FragColor.rgb += cubeLightColor * reflectance * localOcclusion; + + //gl_FragColor.rgb += diffuse.rgb * textureCubeLod(u_CubeMap, N, 7.0).rgb * u_EnableTextures.w; + gl_FragColor.rgb += cubeLightColor * reflectance; #endif #if defined(USE_PRIMARY_LIGHT) - L = normalize(var_PrimaryLightDir); - NL = clamp(dot(N, L), 0.0, 1.0); + vec3 L2, H2; + float NL2, EH2, NH2; - H = normalize(L + E); - EH = clamp(dot(E, H), 0.0, 1.0); - NH = clamp(dot(N, H), 0.0, 1.0); + L2 = var_PrimaryLightDir.xyz; - reflectance = CalcDiffuse(diffuse.rgb, N, L, E, NE, NL, shininess); - reflectance += CalcSpecular(specular.rgb, NH, NL, NE, EH, shininess); + // enable when point lights are supported as primary lights + //sqrLightDist = dot(L2, L2); + //L2 /= sqrt(sqrLightDist); + + NL2 = clamp(dot(N, L2), 0.0, 1.0); + + H2 = normalize(L2 + E); + EH2 = clamp(dot(E, H2), 0.0, 1.0); + NH2 = clamp(dot(N, H2), 0.0, 1.0); + + reflectance = CalcDiffuse(diffuse.rgb, N, L2, E, NE, NL2, shininess); + reflectance += CalcSpecular(specular.rgb, NH2, NL2, NE, EH2, gloss, shininess); + + lightColor = u_PrimaryLightColor; + + // enable when point lights are supported as primary lights + //lightColor *= CalcLightAttenuation(float(u_PrimaryLightDir.w > 0.0), u_PrimaryLightDir.w / sqrLightDist); - lightColor = u_PrimaryLightColor; // * CalcLightAttenuation(L, u_PrimaryLightRadius * u_PrimaryLightRadius); - #if defined(USE_SHADOWMAP) lightColor *= shadowValue; #endif - gl_FragColor.rgb += lightColor * reflectance * NL; - #endif - - #if defined(USE_LINEAR_LIGHT) - gl_FragColor.rgb = sqrt(gl_FragColor.rgb); + gl_FragColor.rgb += lightColor * reflectance * NL2; #endif gl_FragColor.a = diffuse.a; diff --git a/code/renderergl2/glsl/lightall_vp.glsl b/code/renderergl2/glsl/lightall_vp.glsl index 3ea822a4..2e1c899c 100644 --- a/code/renderergl2/glsl/lightall_vp.glsl +++ b/code/renderergl2/glsl/lightall_vp.glsl @@ -6,21 +6,27 @@ attribute vec4 attr_Color; attribute vec3 attr_Position; attribute vec3 attr_Normal; -attribute vec3 attr_Tangent; -attribute vec3 attr_Bitangent; +#if defined(USE_VERT_TANGENT_SPACE) +attribute vec4 attr_Tangent; +#endif #if defined(USE_VERTEX_ANIMATION) attribute vec3 attr_Position2; attribute vec3 attr_Normal2; -attribute vec3 attr_Tangent2; -attribute vec3 attr_Bitangent2; + #if defined(USE_VERT_TANGENT_SPACE) +attribute vec4 attr_Tangent2; + #endif #endif #if defined(USE_LIGHT) && !defined(USE_LIGHT_VECTOR) attribute vec3 attr_LightDirection; #endif -#if defined(USE_TCGEN) || defined(USE_NORMALMAP) || defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) +#if defined(USE_DELUXEMAP) +uniform vec4 u_EnableTextures; // x = normal, y = deluxe, z = specular, w = cube +#endif + +#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) uniform vec3 u_ViewOrigin; #endif @@ -28,6 +34,7 @@ uniform vec3 u_ViewOrigin; uniform int u_TCGen0; uniform vec3 u_TCGen0Vector0; uniform vec3 u_TCGen0Vector1; +uniform vec3 u_LocalViewOrigin; #endif #if defined(USE_TCMOD) @@ -49,45 +56,43 @@ uniform float u_VertexLerp; #if defined(USE_LIGHT_VECTOR) uniform vec4 u_LightOrigin; +uniform float u_LightRadius; #if defined(USE_FAST_LIGHT) uniform vec3 u_DirectedLight; uniform vec3 u_AmbientLight; -uniform float u_LightRadius; #endif #endif #if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) uniform vec4 u_PrimaryLightOrigin; +uniform float u_PrimaryLightRadius; #endif -varying vec2 var_DiffuseTex; - -#if defined(USE_LIGHTMAP) -varying vec2 var_LightTex; -#endif - -#if defined(USE_NORMALMAP) || (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) -varying vec3 var_ViewDir; -#endif +varying vec4 var_TexCoords; varying vec4 var_Color; -#if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) || defined(USE_PARALLAXMAP) +#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) + #if defined(USE_VERT_TANGENT_SPACE) +varying vec4 var_Normal; +varying vec4 var_Tangent; +varying vec4 var_Bitangent; + #else varying vec3 var_Normal; -varying vec3 var_Tangent; -varying vec3 var_Bitangent; +varying vec3 var_ViewDir; + #endif #endif #if defined(USE_LIGHT_VERTEX) && !defined(USE_FAST_LIGHT) -varying vec3 var_lightColor; +varying vec3 var_LightColor; #endif -#if defined(USE_LIGHT) && !defined(USE_DELUXEMAP) && !defined(USE_FAST_LIGHT) +#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) varying vec4 var_LightDir; #endif #if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) -varying vec3 var_PrimaryLightDir; +varying vec4 var_PrimaryLightDir; #endif #if defined(USE_TCGEN) @@ -101,14 +106,16 @@ vec2 GenTexCoords(int TCGen, vec3 position, vec3 normal, vec3 TCGenVector0, vec3 } else if (TCGen == TCGEN_ENVIRONMENT_MAPPED) { - vec3 viewer = normalize(u_ViewOrigin - position); - tex = -reflect(viewer, normal).yz * vec2(0.5, -0.5) + 0.5; + vec3 viewer = normalize(u_LocalViewOrigin - position); + vec2 ref = reflect(viewer, normal).yz; + tex.s = ref.x * -0.5 + 0.5; + tex.t = ref.y * 0.5 + 0.5; } else if (TCGen == TCGEN_VECTOR) { tex = vec2(dot(position, TCGenVector0), dot(position, TCGenVector1)); } - + return tex; } #endif @@ -117,38 +124,33 @@ vec2 GenTexCoords(int TCGen, vec3 position, vec3 normal, vec3 TCGenVector0, vec3 vec2 ModTexCoords(vec2 st, vec3 position, vec4 texMatrix, vec4 offTurb) { float amplitude = offTurb.z; - float phase = offTurb.w; - vec2 st2 = vec2(dot(st, texMatrix.xz), dot(st, texMatrix.yw)) + offTurb.xy; + float phase = offTurb.w * 2.0 * M_PI; + vec2 st2; + st2.x = st.x * texMatrix.x + (st.y * texMatrix.z + offTurb.x); + st2.y = st.x * texMatrix.y + (st.y * texMatrix.w + offTurb.y); + + vec2 offsetPos = vec2(position.x + position.z, position.y); + + vec2 texOffset = sin(offsetPos * (2.0 * M_PI / 1024.0) + vec2(phase)); - vec3 offsetPos = position * 0.0009765625; - offsetPos.x += offsetPos.z; - - vec2 texOffset = sin((offsetPos.xy + vec2(phase)) * 2.0 * M_PI); - return st2 + texOffset * amplitude; } #endif -float CalcLightAttenuation(vec3 dir, float sqrRadius) +float CalcLightAttenuation(float point, float normDist) { - // point light at >0 radius, directional otherwise - float point = float(sqrRadius > 0.0); - - // inverse square light - float attenuation = sqrRadius / dot(dir, dir); - - // zero light at radius, approximating q3 style + // zero light at 1.0, approximating q3 style // also don't attenuate directional light - attenuation = (0.5 * attenuation - 1.5) * point + 1.0; - + float attenuation = (0.5 * normDist - 1.5) * point + 1.0; + // clamp attenuation #if defined(NO_LIGHT_CLAMP) - attenuation *= float(attenuation > 0.0); + attenuation = max(attenuation, 0.0); #else attenuation = clamp(attenuation, 0.0, 1.0); #endif - + return attenuation; } @@ -156,15 +158,22 @@ float CalcLightAttenuation(vec3 dir, float sqrRadius) void main() { #if defined(USE_VERTEX_ANIMATION) - vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp); - vec3 normal = normalize(mix(attr_Normal, attr_Normal2, u_VertexLerp)); - vec3 tangent = normalize(mix(attr_Tangent, attr_Tangent2, u_VertexLerp)); - vec3 bitangent = normalize(mix(attr_Bitangent, attr_Bitangent2, u_VertexLerp)); + vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp); + vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp); + #if defined(USE_VERT_TANGENT_SPACE) && defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) + vec3 tangent = mix(attr_Tangent.xyz, attr_Tangent2.xyz, u_VertexLerp); + #endif #else vec3 position = attr_Position; vec3 normal = attr_Normal; - vec3 tangent = attr_Tangent; - vec3 bitangent = attr_Bitangent; + #if defined(USE_VERT_TANGENT_SPACE) && defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) + vec3 tangent = attr_Tangent.xyz; + #endif +#endif + + normal = normal * 2.0 - vec3(1.0); +#if defined(USE_VERT_TANGENT_SPACE) && defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) + tangent = tangent * 2.0 - vec3(1.0); #endif #if defined(USE_TCGEN) @@ -174,83 +183,78 @@ void main() #endif #if defined(USE_TCMOD) - var_DiffuseTex = ModTexCoords(texCoords, position, u_DiffuseTexMatrix, u_DiffuseTexOffTurb); + var_TexCoords.xy = ModTexCoords(texCoords, position, u_DiffuseTexMatrix, u_DiffuseTexOffTurb); #else - var_DiffuseTex = texCoords; + var_TexCoords.xy = texCoords; #endif gl_Position = u_ModelViewProjectionMatrix * vec4(position, 1.0); #if defined(USE_MODELMATRIX) - position = (u_ModelMatrix * vec4(position, 1.0)).xyz; - normal = (u_ModelMatrix * vec4(normal, 0.0)).xyz; - tangent = (u_ModelMatrix * vec4(tangent, 0.0)).xyz; - bitangent = (u_ModelMatrix * vec4(bitangent, 0.0)).xyz; + position = (u_ModelMatrix * vec4(position, 1.0)).xyz; + normal = (u_ModelMatrix * vec4(normal, 0.0)).xyz; + #if defined(USE_VERT_TANGENT_SPACE) && defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) + tangent = (u_ModelMatrix * vec4(tangent, 0.0)).xyz; + #endif +#endif + +#if defined(USE_VERT_TANGENT_SPACE) && defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) + vec3 bitangent = cross(normal, tangent) * (attr_Tangent.w * 2.0 - 1.0); #endif #if defined(USE_LIGHT_VECTOR) vec3 L = u_LightOrigin.xyz - (position * u_LightOrigin.w); -#elif defined(USE_LIGHT) && !defined(USE_LIGHT_VECTOR) - vec3 L = attr_LightDirection; +#elif defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) + vec3 L = attr_LightDirection * 2.0 - vec3(1.0); #if defined(USE_MODELMATRIX) - L = (u_ModelMatrix * vec4(L, 0.0)).xyz; + L = (u_ModelMatrix * vec4(L, 0.0)).xyz; #endif #endif #if defined(USE_LIGHTMAP) - var_LightTex = attr_TexCoord1.st; + var_TexCoords.zw = attr_TexCoord1.st; #endif - -#if defined(USE_LIGHT_VERTEX) && !defined(USE_FAST_LIGHT) - var_lightColor = u_VertColor.rgb * attr_Color.rgb; - var_Color.rgb = vec3(1.0); - var_Color.a = u_VertColor.a * attr_Color.a + u_BaseColor.a; -#else + var_Color = u_VertColor * attr_Color + u_BaseColor; +#if defined(USE_LIGHT_VERTEX) && !defined(USE_FAST_LIGHT) + var_LightColor = var_Color.rgb; + var_Color.rgb = vec3(1.0); #endif #if defined(USE_LIGHT_VECTOR) && defined(USE_FAST_LIGHT) - float attenuation = CalcLightAttenuation(L, u_LightRadius * u_LightRadius); - float NL = clamp(dot(normal, normalize(L)), 0.0, 1.0); + float sqrLightDist = dot(L, L); + float attenuation = CalcLightAttenuation(u_LightOrigin.w, u_LightRadius * u_LightRadius / sqrLightDist); + float NL = clamp(dot(normalize(normal), L) / sqrt(sqrLightDist), 0.0, 1.0); - var_Color.rgb *= u_DirectedLight * attenuation * NL + u_AmbientLight; -#endif - -#if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) || defined(USE_PARALLAXMAP) - var_Normal = normal; - var_Tangent = tangent; - var_Bitangent = bitangent; + var_Color.rgb *= u_DirectedLight * (attenuation * NL) + u_AmbientLight; #endif #if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) - var_PrimaryLightDir = (u_PrimaryLightOrigin.xyz - (position * u_PrimaryLightOrigin.w)); + var_PrimaryLightDir.xyz = u_PrimaryLightOrigin.xyz - (position * u_PrimaryLightOrigin.w); + var_PrimaryLightDir.w = u_PrimaryLightRadius * u_PrimaryLightRadius; #endif -#if defined(USE_LIGHT) && !defined(USE_DELUXEMAP) && !defined(USE_FAST_LIGHT) +#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) #if defined(USE_LIGHT_VECTOR) - var_LightDir = vec4(L, u_LightOrigin.w); + var_LightDir = vec4(L, u_LightRadius * u_LightRadius); #else var_LightDir = vec4(L, 0.0); #endif + #if defined(USE_DELUXEMAP) + var_LightDir -= u_EnableTextures.y * var_LightDir; + #endif #endif -#if defined(USE_NORMALMAP) || (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) - var_ViewDir = (u_ViewOrigin - position); -#endif - -#if defined(USE_TANGENT_SPACE_LIGHT) - mat3 tangentToWorld = mat3(tangent, bitangent, normal); - - #if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) - var_PrimaryLightDir = var_PrimaryLightDir * tangentToWorld; - #endif - - #if defined(USE_LIGHT) && !defined(USE_DELUXEMAP) && !defined(USE_FAST_LIGHT) - var_LightDir.xyz = var_LightDir.xyz * tangentToWorld; - #endif - - #if defined(USE_NORMALMAP) || (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) - var_ViewDir = var_ViewDir * tangentToWorld; +#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) + vec3 viewDir = u_ViewOrigin - position; + #if defined(USE_VERT_TANGENT_SPACE) + // store view direction in tangent space to save on varyings + var_Normal = vec4(normal, viewDir.x); + var_Tangent = vec4(tangent, viewDir.y); + var_Bitangent = vec4(bitangent, viewDir.z); + #else + var_Normal = normal; + var_ViewDir = viewDir; #endif #endif } diff --git a/code/renderergl2/glsl/pshadow_vp.glsl b/code/renderergl2/glsl/pshadow_vp.glsl index 0e0e3b3d..0f9940cd 100644 --- a/code/renderergl2/glsl/pshadow_vp.glsl +++ b/code/renderergl2/glsl/pshadow_vp.glsl @@ -1,4 +1,4 @@ -attribute vec4 attr_Position; +attribute vec3 attr_Position; attribute vec3 attr_Normal; uniform mat4 u_ModelViewProjectionMatrix; @@ -8,10 +8,8 @@ varying vec3 var_Normal; void main() { - vec4 position = attr_Position; + gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); - gl_Position = u_ModelViewProjectionMatrix * position; - - var_Position = position.xyz; - var_Normal = attr_Normal; + var_Position = attr_Position; + var_Normal = attr_Normal * 2.0 - vec3(1.0); } diff --git a/code/renderergl2/glsl/shadowfill_vp.glsl b/code/renderergl2/glsl/shadowfill_vp.glsl index 10802eca..7a5cc571 100644 --- a/code/renderergl2/glsl/shadowfill_vp.glsl +++ b/code/renderergl2/glsl/shadowfill_vp.glsl @@ -1,9 +1,9 @@ -attribute vec4 attr_Position; +attribute vec3 attr_Position; attribute vec3 attr_Normal; attribute vec4 attr_TexCoord0; //#if defined(USE_VERTEX_ANIMATION) -attribute vec4 attr_Position2; +attribute vec3 attr_Position2; attribute vec3 attr_Normal2; //#endif @@ -38,7 +38,7 @@ vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) if (u_DeformGen == DGEN_BULGE) { - phase *= M_PI * 0.25 * st.x; + phase *= st.x; } else // if (u_DeformGen <= DGEN_WAVE_INVERSE_SAWTOOTH) { @@ -54,7 +54,7 @@ vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) } else if (u_DeformGen == DGEN_WAVE_SQUARE) { - func = sign(sin(value * 2.0 * M_PI)); + func = sign(0.5 - fract(value)); } else if (u_DeformGen == DGEN_WAVE_TRIANGLE) { @@ -68,7 +68,7 @@ vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) { func = (1.0 - fract(value)); } - else if (u_DeformGen == DGEN_BULGE) + else // if (u_DeformGen == DGEN_BULGE) { func = sin(value); } @@ -78,12 +78,13 @@ vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) void main() { - vec4 position = mix(attr_Position, attr_Position2, u_VertexLerp); - vec3 normal = normalize(mix(attr_Normal, attr_Normal2, u_VertexLerp)); + vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp); + vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp); + normal = normalize(normal - vec3(0.5)); - position.xyz = DeformPosition(position.xyz, normal, attr_TexCoord0.st); + position = DeformPosition(position, normal, attr_TexCoord0.st); - gl_Position = u_ModelViewProjectionMatrix * position; + gl_Position = u_ModelViewProjectionMatrix * vec4(position, 1.0); - var_Position = (u_ModelMatrix * position).xyz; + var_Position = (u_ModelMatrix * vec4(position, 1.0)).xyz; } diff --git a/code/renderergl2/glsl/texturecolor_fp.glsl b/code/renderergl2/glsl/texturecolor_fp.glsl index 5646b511..e077e7da 100644 --- a/code/renderergl2/glsl/texturecolor_fp.glsl +++ b/code/renderergl2/glsl/texturecolor_fp.glsl @@ -3,7 +3,7 @@ uniform sampler2D u_DiffuseMap; uniform vec4 u_Color; -varying vec2 var_Tex1; +varying vec2 var_Tex1; void main() diff --git a/code/renderergl2/glsl/texturecolor_vp.glsl b/code/renderergl2/glsl/texturecolor_vp.glsl index ae26a18e..7a5750a5 100644 --- a/code/renderergl2/glsl/texturecolor_vp.glsl +++ b/code/renderergl2/glsl/texturecolor_vp.glsl @@ -1,6 +1,6 @@ #version 120 -attribute vec4 attr_Position; +attribute vec3 attr_Position; attribute vec4 attr_TexCoord0; uniform mat4 u_ModelViewProjectionMatrix; @@ -10,6 +10,6 @@ varying vec2 var_Tex1; void main() { - gl_Position = u_ModelViewProjectionMatrix * attr_Position; + gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); var_Tex1 = attr_TexCoord0.st; } diff --git a/code/renderergl2/glsl/tonemap_vp.glsl b/code/renderergl2/glsl/tonemap_vp.glsl index 5ca41600..bdaa74af 100644 --- a/code/renderergl2/glsl/tonemap_vp.glsl +++ b/code/renderergl2/glsl/tonemap_vp.glsl @@ -1,4 +1,4 @@ -attribute vec4 attr_Position; +attribute vec3 attr_Position; attribute vec4 attr_TexCoord0; uniform mat4 u_ModelViewProjectionMatrix; @@ -8,6 +8,6 @@ varying vec2 var_TexCoords; void main() { - gl_Position = u_ModelViewProjectionMatrix * attr_Position; + gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); var_TexCoords = attr_TexCoord0.st; } diff --git a/code/renderergl2/tr_animation.c b/code/renderergl2/tr_animation.c index 985fe9bb..a5f08986 100644 --- a/code/renderergl2/tr_animation.c +++ b/code/renderergl2/tr_animation.c @@ -33,143 +33,6 @@ frame. */ -/* -============== -R_AddAnimSurfaces -============== -*/ -void R_AddAnimSurfaces( trRefEntity_t *ent ) { - md4Header_t *header; - md4Surface_t *surface; - md4LOD_t *lod; - shader_t *shader; - int cubemapIndex; - int i; - - header = (md4Header_t *) tr.currentModel->modelData; - lod = (md4LOD_t *)( (byte *)header + header->ofsLODs ); - cubemapIndex = R_CubemapForPoint(ent->e.origin); - - surface = (md4Surface_t *)( (byte *)lod + lod->ofsSurfaces ); - for ( i = 0 ; i < lod->numSurfaces ; i++ ) { - shader = R_GetShaderByHandle( surface->shaderIndex ); - R_AddDrawSurf( (void *)surface, shader, 0 /*fogNum*/, qfalse, qfalse, cubemapIndex ); - surface = (md4Surface_t *)( (byte *)surface + surface->ofsEnd ); - } -} - -/* -============== -RB_SurfaceAnim -============== -*/ -void RB_SurfaceAnim( md4Surface_t *surface ) { - int i, j, k; - float frontlerp, backlerp; - int *triangles; - int indexes; - int baseIndex, baseVertex; - int numVerts; - md4Vertex_t *v; - md4Bone_t bones[MD4_MAX_BONES]; - md4Bone_t *bonePtr, *bone; - md4Header_t *header; - md4Frame_t *frame; - md4Frame_t *oldFrame; - int frameSize; - - - if ( backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame ) { - backlerp = 0; - frontlerp = 1; - } else { - backlerp = backEnd.currentEntity->e.backlerp; - frontlerp = 1.0f - backlerp; - } - header = (md4Header_t *)((byte *)surface + surface->ofsHeader); - - frameSize = (size_t)( &((md4Frame_t *)0)->bones[ header->numBones ] ); - - frame = (md4Frame_t *)((byte *)header + header->ofsFrames + - backEnd.currentEntity->e.frame * frameSize ); - oldFrame = (md4Frame_t *)((byte *)header + header->ofsFrames + - backEnd.currentEntity->e.oldframe * frameSize ); - - RB_CheckOverflow( surface->numVerts, surface->numTriangles * 3 ); - - triangles = (int *) ((byte *)surface + surface->ofsTriangles); - indexes = surface->numTriangles * 3; - baseIndex = tess.numIndexes; - baseVertex = tess.numVertexes; - for (j = 0 ; j < indexes ; j++) { - tess.indexes[baseIndex + j] = baseIndex + triangles[j]; - } - tess.numIndexes += indexes; - - // - // lerp all the needed bones - // - if ( !backlerp ) { - // no lerping needed - bonePtr = frame->bones; - } else { - bonePtr = bones; - for ( i = 0 ; i < header->numBones*12 ; i++ ) { - ((float *)bonePtr)[i] = frontlerp * ((float *)frame->bones)[i] - + backlerp * ((float *)oldFrame->bones)[i]; - } - } - - // - // deform the vertexes by the lerped bones - // - numVerts = surface->numVerts; - // FIXME - // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left - // in for reference. - //v = (md4Vertex_t *) ((byte *)surface + surface->ofsVerts + 12); - v = (md4Vertex_t *) ((byte *)surface + surface->ofsVerts); - for ( j = 0; j < numVerts; j++ ) { - vec3_t tempVert, tempNormal; - md4Weight_t *w; - - VectorClear( tempVert ); - VectorClear( tempNormal ); - w = v->weights; - for ( k = 0 ; k < v->numWeights ; k++, w++ ) { - bone = bonePtr + w->boneIndex; - - tempVert[0] += w->boneWeight * ( DotProduct( bone->matrix[0], w->offset ) + bone->matrix[0][3] ); - tempVert[1] += w->boneWeight * ( DotProduct( bone->matrix[1], w->offset ) + bone->matrix[1][3] ); - tempVert[2] += w->boneWeight * ( DotProduct( bone->matrix[2], w->offset ) + bone->matrix[2][3] ); - - tempNormal[0] += w->boneWeight * DotProduct( bone->matrix[0], v->normal ); - tempNormal[1] += w->boneWeight * DotProduct( bone->matrix[1], v->normal ); - tempNormal[2] += w->boneWeight * DotProduct( bone->matrix[2], v->normal ); - } - - tess.xyz[baseVertex + j][0] = tempVert[0]; - tess.xyz[baseVertex + j][1] = tempVert[1]; - tess.xyz[baseVertex + j][2] = tempVert[2]; - - tess.normal[baseVertex + j][0] = tempNormal[0]; - tess.normal[baseVertex + j][1] = tempNormal[1]; - tess.normal[baseVertex + j][2] = tempNormal[2]; - - tess.texCoords[baseVertex + j][0][0] = v->texCoords[0]; - tess.texCoords[baseVertex + j][0][1] = v->texCoords[1]; - - // FIXME - // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left - // in for reference. - //v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights] + 12 ); - v = (md4Vertex_t *)&v->weights[v->numWeights]; - } - - tess.numVertexes += surface->numVerts; -} - - // copied and adapted from tr_mesh.c @@ -198,7 +61,7 @@ static int R_MDRCullModel( mdrHeader_t *header, trRefEntity_t *ent ) { switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) ) { // Ummm... yeah yeah I know we don't really have an md3 here.. but we pretend - // we do. After all, the purpose of md4s are not that different, are they? + // we do. After all, the purpose of mdrs are not that different, are they? case CULL_OUT: tr.pc.c_sphere_cull_md3_out++; @@ -448,7 +311,7 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) { RB_MDRSurfaceAnim ============== */ -void RB_MDRSurfaceAnim( md4Surface_t *surface ) +void RB_MDRSurfaceAnim( mdrSurface_t *surface ) { int i, j, k; float frontlerp, backlerp; @@ -460,7 +323,7 @@ void RB_MDRSurfaceAnim( md4Surface_t *surface ) mdrHeader_t *header; mdrFrame_t *frame; mdrFrame_t *oldFrame; - mdrBone_t bones[MD4_MAX_BONES], *bonePtr, *bone; + mdrBone_t bones[MDR_MAX_BONES], *bonePtr, *bone; int frameSize; @@ -548,9 +411,7 @@ void RB_MDRSurfaceAnim( md4Surface_t *surface ) tess.xyz[baseVertex + j][1] = tempVert[1]; tess.xyz[baseVertex + j][2] = tempVert[2]; - tess.normal[baseVertex + j][0] = tempNormal[0]; - tess.normal[baseVertex + j][1] = tempNormal[1]; - tess.normal[baseVertex + j][2] = tempNormal[2]; + tess.normal[baseVertex + j] = R_VboPackNormal(tempNormal); tess.texCoords[baseVertex + j][0][0] = v->texCoords[0]; tess.texCoords[baseVertex + j][0][1] = v->texCoords[1]; diff --git a/code/renderergl2/tr_backend.c b/code/renderergl2/tr_backend.c index 08dc167e..e4431cf5 100644 --- a/code/renderergl2/tr_backend.c +++ b/code/renderergl2/tr_backend.c @@ -371,17 +371,17 @@ void GL_State( unsigned long stateBits ) } -void GL_SetProjectionMatrix(matrix_t matrix) +void GL_SetProjectionMatrix(mat4_t matrix) { - Matrix16Copy(matrix, glState.projection); - Matrix16Multiply(glState.projection, glState.modelview, glState.modelviewProjection); + Mat4Copy(matrix, glState.projection); + Mat4Multiply(glState.projection, glState.modelview, glState.modelviewProjection); } -void GL_SetModelviewMatrix(matrix_t matrix) +void GL_SetModelviewMatrix(mat4_t matrix) { - Matrix16Copy(matrix, glState.modelview); - Matrix16Multiply(glState.projection, glState.modelview, glState.modelviewProjection); + Mat4Copy(matrix, glState.modelview); + Mat4Multiply(glState.projection, glState.modelview, glState.modelviewProjection); } @@ -449,7 +449,7 @@ void RB_BeginDrawingView (void) { { if (!tr.renderFbo || (backEnd.framePostProcessed && (backEnd.refdef.rdflags & RDF_NOWORLDMODEL))) { - FBO_Bind(tr.screenScratchFbo); + FBO_Bind(NULL); } else { @@ -461,7 +461,7 @@ void RB_BeginDrawingView (void) { FBO_Bind(backEnd.viewParms.targetFbo); // FIXME: hack for cubemap testing - if (backEnd.viewParms.targetFbo == tr.renderCubeFbo) + if (tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo) { //qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + backEnd.viewParms.targetFboLayer, backEnd.viewParms.targetFbo->colorImage[0]->texnum, 0); qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + backEnd.viewParms.targetFboLayer, tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex]->texnum, 0); @@ -501,7 +501,7 @@ void RB_BeginDrawingView (void) { } // clear to black for cube maps - if (backEnd.viewParms.targetFbo == tr.renderCubeFbo) + if (tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo) { clearBits |= GL_COLOR_BUFFER_BIT; qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); @@ -765,7 +765,7 @@ RB_SetGL2D ================ */ void RB_SetGL2D (void) { - matrix_t matrix; + mat4_t matrix; int width, height; if (backEnd.projection2D && backEnd.last2DFBO == glState.currentFBO) @@ -789,9 +789,9 @@ void RB_SetGL2D (void) { qglViewport( 0, 0, width, height ); qglScissor( 0, 0, width, height ); - Matrix16Ortho(0, width, height, 0, 0, 1, matrix); + Mat4Ortho(0, width, height, 0, 0, 1, matrix); GL_SetProjectionMatrix(matrix); - Matrix16Identity(matrix); + Mat4Identity(matrix); GL_SetModelviewMatrix(matrix); GL_State( GLS_DEPTHTEST_DISABLE | @@ -830,6 +830,10 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte * } R_IssuePendingRenderCommands(); + if ( tess.numIndexes ) { + RB_EndSurface(); + } + // we definately want to sync every frame for the cinematics qglFinish(); @@ -859,7 +863,7 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte * { if (!tr.renderFbo || backEnd.framePostProcessed) { - FBO_Bind(tr.screenScratchFbo); + FBO_Bind(NULL); } else { @@ -881,7 +885,7 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte * GLSL_BindProgram(&tr.textureColorShader); - GLSL_SetUniformMatrix16(&tr.textureColorShader, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformMat4(&tr.textureColorShader, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); GLSL_SetUniformVec4(&tr.textureColorShader, UNIFORM_COLOR, colorWhite); RB_InstantQuad2(quadVerts, texCoords); @@ -946,7 +950,7 @@ const void *RB_StretchPic ( const void *data ) { { if (!tr.renderFbo || backEnd.framePostProcessed) { - FBO_Bind(tr.screenScratchFbo); + FBO_Bind(NULL); } else { @@ -1077,7 +1081,7 @@ const void *RB_DrawSurfs( const void *data ) { FBO_BlitFromTexture(tr.renderDepthImage, NULL, NULL, tr.hdrDepthFbo, NULL, NULL, NULL, 0); } - if (backEnd.viewParms.flags & VPF_USESUNLIGHT) + if (r_sunlightMode->integer && backEnd.viewParms.flags & VPF_USESUNLIGHT) { vec4_t quadVerts[4]; vec2_t texCoords[4]; @@ -1122,9 +1126,9 @@ const void *RB_DrawSurfs( const void *data ) { GL_BindToTMU(tr.sunShadowDepthImage[1], TB_SHADOWMAP2); GL_BindToTMU(tr.sunShadowDepthImage[2], TB_SHADOWMAP3); - GLSL_SetUniformMatrix16(&tr.shadowmaskShader, UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[0]); - GLSL_SetUniformMatrix16(&tr.shadowmaskShader, UNIFORM_SHADOWMVP2, backEnd.refdef.sunShadowMvp[1]); - GLSL_SetUniformMatrix16(&tr.shadowmaskShader, UNIFORM_SHADOWMVP3, backEnd.refdef.sunShadowMvp[2]); + GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[0]); + GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP2, backEnd.refdef.sunShadowMvp[1]); + GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP3, backEnd.refdef.sunShadowMvp[2]); GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWORIGIN, backEnd.refdef.vieworg); { @@ -1292,7 +1296,7 @@ const void *RB_DrawSurfs( const void *data ) { RB_RenderFlares(); } - if (glRefConfig.framebufferObject && backEnd.viewParms.targetFbo == tr.renderCubeFbo) + if (glRefConfig.framebufferObject && tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo) { FBO_Bind(NULL); GL_SelectTexture(TB_CUBEMAP); @@ -1443,7 +1447,7 @@ const void *RB_ClearDepth(const void *data) { if (!tr.renderFbo || backEnd.framePostProcessed) { - FBO_Bind(tr.screenScratchFbo); + FBO_Bind(NULL); } else { @@ -1512,32 +1516,13 @@ const void *RB_SwapBuffers( const void *data ) { { // Resolving an RGB16F MSAA FBO to the screen messes with the brightness, so resolve to an RGB16F FBO first FBO_FastBlit(tr.renderFbo, NULL, tr.msaaResolveFbo, NULL, GL_COLOR_BUFFER_BIT, GL_NEAREST); - FBO_FastBlit(tr.msaaResolveFbo, NULL, tr.screenScratchFbo, NULL, GL_COLOR_BUFFER_BIT, GL_NEAREST); + FBO_FastBlit(tr.msaaResolveFbo, NULL, NULL, NULL, GL_COLOR_BUFFER_BIT, GL_NEAREST); } else if (tr.renderFbo) { - FBO_FastBlit(tr.renderFbo, NULL, tr.screenScratchFbo, NULL, GL_COLOR_BUFFER_BIT, GL_NEAREST); + FBO_FastBlit(tr.renderFbo, NULL, NULL, NULL, GL_COLOR_BUFFER_BIT, GL_NEAREST); } } - - if (tr.screenScratchFbo) - { - vec4_t color; - - color[0] = - color[1] = - color[2] = pow(2, tr.overbrightBits); //exp2(tr.overbrightBits); - color[3] = 1.0f; - - // turn off colormask when copying final image - if (backEnd.colorMask[0] || backEnd.colorMask[1] || backEnd.colorMask[2] || backEnd.colorMask[3]) - qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - - FBO_Blit(tr.screenScratchFbo, NULL, NULL, NULL, NULL, NULL, color, 0); - - if (backEnd.colorMask[0] || backEnd.colorMask[1] || backEnd.colorMask[2] || backEnd.colorMask[3]) - qglColorMask(!backEnd.colorMask[0], !backEnd.colorMask[1], !backEnd.colorMask[2], !backEnd.colorMask[3]); - } } if ( !glState.finishCalled ) { @@ -1573,13 +1558,19 @@ const void *RB_CapShadowMap(const void *data) GL_SelectTexture(0); if (cmd->cubeSide != -1) { - GL_Bind(tr.shadowCubemaps[cmd->map]); - qglCopyTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cmd->cubeSide, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - ( backEnd.refdef.y + PSHADOW_MAP_SIZE ), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, 0); + if (tr.shadowCubemaps[cmd->map]) + { + GL_Bind(tr.shadowCubemaps[cmd->map]); + qglCopyTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cmd->cubeSide, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - ( backEnd.refdef.y + PSHADOW_MAP_SIZE ), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, 0); + } } else { - GL_Bind(tr.pshadowMaps[cmd->map]); - qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - ( backEnd.refdef.y + PSHADOW_MAP_SIZE ), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, 0); + if (tr.pshadowMaps[cmd->map]) + { + GL_Bind(tr.pshadowMaps[cmd->map]); + qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - ( backEnd.refdef.y + PSHADOW_MAP_SIZE ), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, 0); + } } } @@ -1597,7 +1588,7 @@ const void *RB_PostProcess(const void *data) { const postProcessCommand_t *cmd = data; FBO_t *srcFbo; - vec4i_t srcBox, dstBox; + ivec4_t srcBox, dstBox; qboolean autoExposure; // finish any 2D drawing if needed @@ -1654,11 +1645,11 @@ const void *RB_PostProcess(const void *data) if (r_hdr->integer && (r_toneMap->integer || r_forceToneMap->integer)) { autoExposure = r_autoExposure->integer || r_forceAutoExposure->integer; - RB_ToneMap(srcFbo, srcBox, tr.screenScratchFbo, dstBox, autoExposure); + RB_ToneMap(srcFbo, srcBox, NULL, dstBox, autoExposure); } else if (r_cameraExposure->value == 0.0f) { - FBO_FastBlit(srcFbo, srcBox, tr.screenScratchFbo, dstBox, GL_COLOR_BUFFER_BIT, GL_NEAREST); + FBO_FastBlit(srcFbo, srcBox, NULL, dstBox, GL_COLOR_BUFFER_BIT, GL_NEAREST); } else { @@ -1669,56 +1660,56 @@ const void *RB_PostProcess(const void *data) color[2] = pow(2, r_cameraExposure->value); //exp2(r_cameraExposure->value); color[3] = 1.0f; - FBO_Blit(srcFbo, srcBox, NULL, tr.screenScratchFbo, dstBox, NULL, color, 0); + FBO_Blit(srcFbo, srcBox, NULL, NULL, dstBox, NULL, color, 0); } } if (r_drawSunRays->integer) - RB_SunRays(tr.screenScratchFbo, srcBox, tr.screenScratchFbo, dstBox); + RB_SunRays(NULL, srcBox, NULL, dstBox); if (1) - RB_BokehBlur(tr.screenScratchFbo, srcBox, tr.screenScratchFbo, dstBox, backEnd.refdef.blurFactor); + RB_BokehBlur(NULL, srcBox, NULL, dstBox, backEnd.refdef.blurFactor); else RB_GaussianBlur(backEnd.refdef.blurFactor); - if (0) + if (0 && r_sunlightMode->integer) { - vec4i_t dstBox; + ivec4_t dstBox; VectorSet4(dstBox, 0, 0, 128, 128); - FBO_BlitFromTexture(tr.sunShadowDepthImage[0], NULL, NULL, tr.screenScratchFbo, dstBox, NULL, NULL, 0); + FBO_BlitFromTexture(tr.sunShadowDepthImage[0], NULL, NULL, NULL, dstBox, NULL, NULL, 0); VectorSet4(dstBox, 128, 0, 128, 128); - FBO_BlitFromTexture(tr.sunShadowDepthImage[1], NULL, NULL, tr.screenScratchFbo, dstBox, NULL, NULL, 0); + FBO_BlitFromTexture(tr.sunShadowDepthImage[1], NULL, NULL, NULL, dstBox, NULL, NULL, 0); VectorSet4(dstBox, 256, 0, 128, 128); - FBO_BlitFromTexture(tr.sunShadowDepthImage[2], NULL, NULL, tr.screenScratchFbo, dstBox, NULL, NULL, 0); + FBO_BlitFromTexture(tr.sunShadowDepthImage[2], NULL, NULL, NULL, dstBox, NULL, NULL, 0); } if (0) { - vec4i_t dstBox; + ivec4_t dstBox; VectorSet4(dstBox, 256, glConfig.vidHeight - 256, 256, 256); - FBO_BlitFromTexture(tr.renderDepthImage, NULL, NULL, tr.screenScratchFbo, dstBox, NULL, NULL, 0); + FBO_BlitFromTexture(tr.renderDepthImage, NULL, NULL, NULL, dstBox, NULL, NULL, 0); VectorSet4(dstBox, 512, glConfig.vidHeight - 256, 256, 256); - FBO_BlitFromTexture(tr.screenShadowImage, NULL, NULL, tr.screenScratchFbo, dstBox, NULL, NULL, 0); + FBO_BlitFromTexture(tr.screenShadowImage, NULL, NULL, NULL, dstBox, NULL, NULL, 0); } if (0) { - vec4i_t dstBox; + ivec4_t dstBox; VectorSet4(dstBox, 256, glConfig.vidHeight - 256, 256, 256); - FBO_BlitFromTexture(tr.sunRaysImage, NULL, NULL, tr.screenScratchFbo, dstBox, NULL, NULL, 0); + FBO_BlitFromTexture(tr.sunRaysImage, NULL, NULL, NULL, dstBox, NULL, NULL, 0); } #if 0 if (r_cubeMapping->integer && tr.numCubemaps) { - vec4i_t dstBox; + ivec4_t dstBox; int cubemapIndex = R_CubemapForPoint( backEnd.viewParms.or.origin ); if (cubemapIndex) { VectorSet4(dstBox, 0, glConfig.vidHeight - 256, 256, 256); - //FBO_BlitFromTexture(tr.renderCubeImage, NULL, NULL, tr.screenScratchFbo, dstBox, &tr.testcubeShader, NULL, 0); - FBO_BlitFromTexture(tr.cubemaps[cubemapIndex - 1], NULL, NULL, tr.screenScratchFbo, dstBox, &tr.testcubeShader, NULL, 0); + //FBO_BlitFromTexture(tr.renderCubeImage, NULL, NULL, NULL, dstBox, &tr.testcubeShader, NULL, 0); + FBO_BlitFromTexture(tr.cubemaps[cubemapIndex - 1], NULL, NULL, NULL, dstBox, &tr.testcubeShader, NULL, 0); } } #endif diff --git a/code/renderergl2/tr_bsp.c b/code/renderergl2/tr_bsp.c index 64d54805..3413ff2d 100644 --- a/code/renderergl2/tr_bsp.c +++ b/code/renderergl2/tr_bsp.c @@ -128,17 +128,34 @@ static void R_ColorShiftLightingBytes( byte in[4], byte out[4] ) { /* =============== -R_ColorShiftLightingBytes +R_ColorShiftLightingFloats =============== */ static void R_ColorShiftLightingFloats(float in[4], float out[4], float scale ) { + float r, g, b; + scale *= pow(2.0f, r_mapOverBrightBits->integer - tr.overbrightBits); - out[0] = in[0] * scale; - out[1] = in[1] * scale; - out[2] = in[2] * scale; + r = in[0] * scale; + g = in[1] * scale; + b = in[2] * scale; + + // normalize by color instead of saturating to white + if ( !r_hdr->integer && ( r > 1 || g > 1 || b > 1 ) ) { + float max; + + max = r > g ? r : g; + max = max > b ? max : b; + r = r / max; + g = g / max; + b = b / max; + } + + out[0] = r; + out[1] = g; + out[2] = b; out[3] = in[3]; } @@ -271,7 +288,7 @@ static void R_LoadLightmaps( lump_t *l, lump_t *surfs ) { if (r_hdr->integer) { - if (glRefConfig.textureFloat && glRefConfig.halfFloatPixel) + if (glRefConfig.textureFloat && glRefConfig.halfFloatPixel && r_floatLightmap->integer) textureInternalFormat = GL_RGBA16F_ARB; else textureInternalFormat = GL_RGBA8; @@ -410,7 +427,7 @@ static void R_LoadLightmaps( lump_t *l, lump_t *surfs ) { VectorScale(color, lightScale, color); - if (glRefConfig.textureFloat && glRefConfig.halfFloatPixel) + if (glRefConfig.textureFloat && glRefConfig.halfFloatPixel && r_floatLightmap->integer) ColorToRGBA16F(color, (unsigned short *)(&image[j*8])); else ColorToRGBM(color, &image[j*4]); @@ -471,7 +488,7 @@ static void R_LoadLightmaps( lump_t *l, lump_t *surfs ) { image[j*4+2] = buf_p[j*3+2]; // make 0,0,0 into 127,127,127 - if ((image[j*4+0] == 0) && (image[j*4+0] == 0) && (image[j*4+2] == 0)) + if ((image[j*4+0] == 0) && (image[j*4+1] == 0) && (image[j*4+2] == 0)) { image[j*4+0] = image[j*4+1] = @@ -652,9 +669,9 @@ ParseFace */ static void ParseFace( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors, msurface_t *surf, int *indexes ) { int i, j; - srfSurfaceFace_t *cv; - srfTriangle_t *tri; - int numVerts, numTriangles, badTriangles; + srfBspSurface_t *cv; + glIndex_t *tri; + int numVerts, numIndexes, badTriangles; int realLightmapNum; realLightmapNum = LittleLong( ds->lightmapNum ); @@ -675,14 +692,14 @@ static void ParseFace( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors, surf->shader = tr.defaultShader; } - numTriangles = LittleLong(ds->numIndexes) / 3; + numIndexes = LittleLong(ds->numIndexes); //cv = ri.Hunk_Alloc(sizeof(*cv), h_low); cv = (void *)surf->data; cv->surfaceType = SF_FACE; - cv->numTriangles = numTriangles; - cv->triangles = ri.Hunk_Alloc(numTriangles * sizeof(cv->triangles[0]), h_low); + cv->numIndexes = numIndexes; + cv->indexes = ri.Hunk_Alloc(numIndexes * sizeof(cv->indexes[0]), h_low); cv->numVerts = numVerts; cv->verts = ri.Hunk_Alloc(numVerts * sizeof(cv->verts[0]), h_low); @@ -740,39 +757,39 @@ static void ParseFace( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors, // copy triangles badTriangles = 0; indexes += LittleLong(ds->firstIndex); - for(i = 0, tri = cv->triangles; i < numTriangles; i++, tri++) + for(i = 0, tri = cv->indexes; i < numIndexes; i += 3, tri += 3) { for(j = 0; j < 3; j++) { - tri->indexes[j] = LittleLong(indexes[i * 3 + j]); + tri[j] = LittleLong(indexes[i + j]); - if(tri->indexes[j] < 0 || tri->indexes[j] >= numVerts) + if(tri[j] >= numVerts) { ri.Error(ERR_DROP, "Bad index in face surface"); } } - if ((tri->indexes[0] == tri->indexes[1]) || (tri->indexes[1] == tri->indexes[2]) || (tri->indexes[0] == tri->indexes[2])) + if ((tri[0] == tri[1]) || (tri[1] == tri[2]) || (tri[0] == tri[2])) { - tri--; + tri -= 3; badTriangles++; } } if (badTriangles) { - ri.Printf(PRINT_WARNING, "Face has bad triangles, originally shader %s %d tris %d verts, now %d tris\n", surf->shader->name, numTriangles, numVerts, numTriangles - badTriangles); - cv->numTriangles -= badTriangles; + ri.Printf(PRINT_WARNING, "Face has bad triangles, originally shader %s %d tris %d verts, now %d tris\n", surf->shader->name, numIndexes / 3, numVerts, numIndexes / 3 - badTriangles); + cv->numIndexes -= badTriangles * 3; } // take the plane information from the lightmap vector for ( i = 0 ; i < 3 ; i++ ) { - cv->plane.normal[i] = LittleFloat( ds->lightmapVecs[2][i] ); + cv->cullPlane.normal[i] = LittleFloat( ds->lightmapVecs[2][i] ); } - cv->plane.dist = DotProduct( cv->verts[0].xyz, cv->plane.normal ); - SetPlaneSignbits( &cv->plane ); - cv->plane.type = PlaneTypeForNormal( cv->plane.normal ); - surf->cullinfo.plane = cv->plane; + cv->cullPlane.dist = DotProduct( cv->verts[0].xyz, cv->cullPlane.normal ); + SetPlaneSignbits( &cv->cullPlane ); + cv->cullPlane.type = PlaneTypeForNormal( cv->cullPlane.normal ); + surf->cullinfo.plane = cv->cullPlane; surf->data = (surfaceType_t *)cv; @@ -781,11 +798,11 @@ static void ParseFace( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors, { srfVert_t *dv[3]; - for(i = 0, tri = cv->triangles; i < numTriangles; i++, tri++) + for(i = 0, tri = cv->indexes; i < numIndexes; i += 3, tri += 3) { - dv[0] = &cv->verts[tri->indexes[0]]; - dv[1] = &cv->verts[tri->indexes[1]]; - dv[2] = &cv->verts[tri->indexes[2]]; + dv[0] = &cv->verts[tri[0]]; + dv[1] = &cv->verts[tri[1]]; + dv[2] = &cv->verts[tri[2]]; R_CalcTangentVectors(dv); } @@ -800,7 +817,7 @@ ParseMesh =============== */ static void ParseMesh ( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors, msurface_t *surf ) { - srfGridMesh_t *grid; + srfBspSurface_t *grid; int i, j; int width, height, numPoints; srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE]; @@ -903,10 +920,10 @@ ParseTriSurf =============== */ static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors, msurface_t *surf, int *indexes ) { - srfTriangles_t *cv; - srfTriangle_t *tri; + srfBspSurface_t *cv; + glIndex_t *tri; int i, j; - int numVerts, numTriangles, badTriangles; + int numVerts, numIndexes, badTriangles; // get fog volume surf->fogIndex = LittleLong( ds->fogNum ) + 1; @@ -918,14 +935,14 @@ static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, float *hdrVertColor } numVerts = LittleLong(ds->numVerts); - numTriangles = LittleLong(ds->numIndexes) / 3; + numIndexes = LittleLong(ds->numIndexes); //cv = ri.Hunk_Alloc(sizeof(*cv), h_low); cv = (void *)surf->data; cv->surfaceType = SF_TRIANGLES; - cv->numTriangles = numTriangles; - cv->triangles = ri.Hunk_Alloc(numTriangles * sizeof(cv->triangles[0]), h_low); + cv->numIndexes = numIndexes; + cv->indexes = ri.Hunk_Alloc(numIndexes * sizeof(cv->indexes[0]), h_low); cv->numVerts = numVerts; cv->verts = ri.Hunk_Alloc(numVerts * sizeof(cv->verts[0]), h_low); @@ -984,29 +1001,29 @@ static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, float *hdrVertColor // copy triangles badTriangles = 0; indexes += LittleLong(ds->firstIndex); - for(i = 0, tri = cv->triangles; i < numTriangles; i++, tri++) + for(i = 0, tri = cv->indexes; i < numIndexes; i += 3, tri += 3) { for(j = 0; j < 3; j++) { - tri->indexes[j] = LittleLong(indexes[i * 3 + j]); + tri[j] = LittleLong(indexes[i + j]); - if(tri->indexes[j] < 0 || tri->indexes[j] >= numVerts) + if(tri[j] >= numVerts) { ri.Error(ERR_DROP, "Bad index in face surface"); } } - if ((tri->indexes[0] == tri->indexes[1]) || (tri->indexes[1] == tri->indexes[2]) || (tri->indexes[0] == tri->indexes[2])) + if ((tri[0] == tri[1]) || (tri[1] == tri[2]) || (tri[0] == tri[2])) { - tri--; + tri -= 3; badTriangles++; } } if (badTriangles) { - ri.Printf(PRINT_WARNING, "Trisurf has bad triangles, originally shader %s %d tris %d verts, now %d tris\n", surf->shader->name, numTriangles, numVerts, numTriangles - badTriangles); - cv->numTriangles -= badTriangles; + ri.Printf(PRINT_WARNING, "Trisurf has bad triangles, originally shader %s %d tris %d verts, now %d tris\n", surf->shader->name, numIndexes / 3, numVerts, numIndexes / 3 - badTriangles); + cv->numIndexes -= badTriangles * 3; } #ifdef USE_VERT_TANGENT_SPACE @@ -1014,11 +1031,11 @@ static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, float *hdrVertColor { srfVert_t *dv[3]; - for(i = 0, tri = cv->triangles; i < numTriangles; i++, tri++) + for(i = 0, tri = cv->indexes; i < numIndexes; i += 3, tri += 3) { - dv[0] = &cv->verts[tri->indexes[0]]; - dv[1] = &cv->verts[tri->indexes[1]]; - dv[2] = &cv->verts[tri->indexes[2]]; + dv[0] = &cv->verts[tri[0]]; + dv[1] = &cv->verts[tri[1]]; + dv[2] = &cv->verts[tri[2]]; R_CalcTangentVectors(dv); } @@ -1065,7 +1082,7 @@ R_MergedWidthPoints returns true if there are grid points merged on a width edge ================= */ -int R_MergedWidthPoints(srfGridMesh_t *grid, int offset) { +int R_MergedWidthPoints(srfBspSurface_t *grid, int offset) { int i, j; for (i = 1; i < grid->width-1; i++) { @@ -1086,7 +1103,7 @@ R_MergedHeightPoints returns true if there are grid points merged on a height edge ================= */ -int R_MergedHeightPoints(srfGridMesh_t *grid, int offset) { +int R_MergedHeightPoints(srfBspSurface_t *grid, int offset) { int i, j; for (i = 1; i < grid->height-1; i++) { @@ -1109,13 +1126,13 @@ NOTE: never sync LoD through grid edges with merged points! FIXME: write generalized version that also avoids cracks between a patch and one that meets half way? ================= */ -void R_FixSharedVertexLodError_r( int start, srfGridMesh_t *grid1 ) { +void R_FixSharedVertexLodError_r( int start, srfBspSurface_t *grid1 ) { int j, k, l, m, n, offset1, offset2, touch; - srfGridMesh_t *grid2; + srfBspSurface_t *grid2; for ( j = start; j < s_worldData.numsurfaces; j++ ) { // - grid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data; + grid2 = (srfBspSurface_t *) s_worldData.surfaces[j].data; // if this surface is not a grid if ( grid2->surfaceType != SF_GRID ) continue; // if the LOD errors are already fixed for this patch @@ -1223,11 +1240,11 @@ If this is not the case this function will still do its job but won't fix the hi */ void R_FixSharedVertexLodError( void ) { int i; - srfGridMesh_t *grid1; + srfBspSurface_t *grid1; for ( i = 0; i < s_worldData.numsurfaces; i++ ) { // - grid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data; + grid1 = (srfBspSurface_t *) s_worldData.surfaces[i].data; // if this surface is not a grid if ( grid1->surfaceType != SF_GRID ) continue; @@ -1249,11 +1266,11 @@ R_StitchPatches */ int R_StitchPatches( int grid1num, int grid2num ) { float *v1, *v2; - srfGridMesh_t *grid1, *grid2; + srfBspSurface_t *grid1, *grid2; int k, l, m, n, offset1, offset2, row, column; - grid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data; - grid2 = (srfGridMesh_t *) s_worldData.surfaces[grid2num].data; + grid1 = (srfBspSurface_t *) s_worldData.surfaces[grid1num].data; + grid2 = (srfBspSurface_t *) s_worldData.surfaces[grid2num].data; for (n = 0; n < 2; n++) { // if (n) offset1 = (grid1->height-1) * grid1->width; @@ -1664,13 +1681,13 @@ might still appear at that side. */ int R_TryStitchingPatch( int grid1num ) { int j, numstitches; - srfGridMesh_t *grid1, *grid2; + srfBspSurface_t *grid1, *grid2; numstitches = 0; - grid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data; + grid1 = (srfBspSurface_t *) s_worldData.surfaces[grid1num].data; for ( j = 0; j < s_worldData.numsurfaces; j++ ) { // - grid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data; + grid2 = (srfBspSurface_t *) s_worldData.surfaces[j].data; // if this surface is not a grid if ( grid2->surfaceType != SF_GRID ) continue; // grids in the same LOD group should have the exact same lod radius @@ -1695,7 +1712,7 @@ R_StitchAllPatches */ void R_StitchAllPatches( void ) { int i, stitched, numstitches; - srfGridMesh_t *grid1; + srfBspSurface_t *grid1; numstitches = 0; do @@ -1703,7 +1720,7 @@ void R_StitchAllPatches( void ) { stitched = qfalse; for ( i = 0; i < s_worldData.numsurfaces; i++ ) { // - grid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data; + grid1 = (srfBspSurface_t *) s_worldData.surfaces[i].data; // if this surface is not a grid if ( grid1->surfaceType != SF_GRID ) continue; @@ -1728,11 +1745,11 @@ R_MovePatchSurfacesToHunk */ void R_MovePatchSurfacesToHunk(void) { int i, size; - srfGridMesh_t *grid, *hunkgrid; + srfBspSurface_t *grid, *hunkgrid; for ( i = 0; i < s_worldData.numsurfaces; i++ ) { // - grid = (srfGridMesh_t *) s_worldData.surfaces[i].data; + grid = (srfBspSurface_t *) s_worldData.surfaces[i].data; // if this surface is not a grid if ( grid->surfaceType != SF_GRID ) continue; @@ -1747,9 +1764,9 @@ void R_MovePatchSurfacesToHunk(void) { hunkgrid->heightLodError = ri.Hunk_Alloc( grid->height * 4, h_low ); Com_Memcpy( hunkgrid->heightLodError, grid->heightLodError, grid->height * 4 ); - hunkgrid->numTriangles = grid->numTriangles; - hunkgrid->triangles = ri.Hunk_Alloc(grid->numTriangles * sizeof(srfTriangle_t), h_low); - Com_Memcpy(hunkgrid->triangles, grid->triangles, grid->numTriangles * sizeof(srfTriangle_t)); + hunkgrid->numIndexes = grid->numIndexes; + hunkgrid->indexes = ri.Hunk_Alloc(grid->numIndexes * sizeof(glIndex_t), h_low); + Com_Memcpy(hunkgrid->indexes, grid->indexes, grid->numIndexes * sizeof(glIndex_t)); hunkgrid->numVerts = grid->numVerts; hunkgrid->verts = ri.Hunk_Alloc(grid->numVerts * sizeof(srfVert_t), h_low); @@ -1810,12 +1827,14 @@ static void CopyVert(const srfVert_t * in, srfVert_t * out) out->xyz[j] = in->xyz[j]; #ifdef USE_VERT_TANGENT_SPACE out->tangent[j] = in->tangent[j]; - out->bitangent[j] = in->bitangent[j]; + //out->bitangent[j] = in->bitangent[j]; #endif out->normal[j] = in->normal[j]; out->lightdir[j] = in->lightdir[j]; } + out->tangent[3] = in->tangent[3]; + for(j = 0; j < 2; j++) { out->st[j] = in->st[j]; @@ -1831,298 +1850,204 @@ static void CopyVert(const srfVert_t * in, srfVert_t * out) /* =============== -R_CreateWorldVBO +R_CreateWorldVBOs =============== */ -static void R_CreateWorldVBO(void) +static void R_CreateWorldVBOs(void) { int i, j, k; int numVerts; srfVert_t *verts; - int numTriangles; - srfTriangle_t *triangles; + int numIndexes; + glIndex_t *indexes; - int numSurfaces; - msurface_t *surface; + int numSortedSurfaces, numSurfaces; + msurface_t *surface, **firstSurf, **lastSurf, **currSurf; msurface_t **surfacesSorted; + VBO_t *vbo; + IBO_t *ibo; + + int maxVboSize = 4 * 1024 * 1024; + int maxIboSize = 4 * 1024 * 1024; + int startTime, endTime; startTime = ri.Milliseconds(); - numVerts = 0; - numTriangles = 0; - numSurfaces = 0; - for(k = 0, surface = &s_worldData.surfaces[0]; k < s_worldData.numsurfaces /* s_worldData.numWorldSurfaces */; k++, surface++) + // count surfaces + numSortedSurfaces = 0; + for(surface = &s_worldData.surfaces[0]; surface < &s_worldData.surfaces[s_worldData.numsurfaces]; surface++) { - if(*surface->data == SF_FACE) - { - srfSurfaceFace_t *face = (srfSurfaceFace_t *) surface->data; + srfBspSurface_t *bspSurf; + shader_t *shader = surface->shader; - if(face->numVerts) - numVerts += face->numVerts; + if (shader->isPortal) + continue; - if(face->numTriangles) - numTriangles += face->numTriangles; + if (shader->isSky) + continue; - numSurfaces++; - } - else if(*surface->data == SF_GRID) - { - srfGridMesh_t *grid = (srfGridMesh_t *) surface->data; + if (ShaderRequiresCPUDeforms(shader)) + continue; - if(grid->numVerts) - numVerts += grid->numVerts; + // check for this now so we can use srfBspSurface_t* universally in the rest of the function + if (!(*surface->data == SF_FACE || *surface->data == SF_GRID || *surface->data == SF_TRIANGLES)) + continue; - if(grid->numTriangles) - numTriangles += grid->numTriangles; + bspSurf = (srfBspSurface_t *) surface->data; - numSurfaces++; - } - else if(*surface->data == SF_TRIANGLES) - { - srfTriangles_t *tri = (srfTriangles_t *) surface->data; + if (!bspSurf->numIndexes || !bspSurf->numVerts) + continue; - if(tri->numVerts) - numVerts += tri->numVerts; - - if(tri->numTriangles) - numTriangles += tri->numTriangles; - - numSurfaces++; - } + numSortedSurfaces++; } - if(!numVerts || !numTriangles) - return; - - ri.Printf(PRINT_ALL, "...calculating world VBO ( %i verts %i tris )\n", numVerts, numTriangles); - - // create arrays - - verts = ri.Hunk_AllocateTempMemory(numVerts * sizeof(srfVert_t)); - - triangles = ri.Hunk_AllocateTempMemory(numTriangles * sizeof(srfTriangle_t)); - // presort surfaces - surfacesSorted = ri.Malloc(numSurfaces * sizeof(*surfacesSorted)); + surfacesSorted = ri.Malloc(numSortedSurfaces * sizeof(*surfacesSorted)); j = 0; - for(k = 0, surface = &s_worldData.surfaces[0]; k < s_worldData.numsurfaces; k++, surface++) + for(surface = &s_worldData.surfaces[0]; surface < &s_worldData.surfaces[s_worldData.numsurfaces]; surface++) { - if(*surface->data == SF_FACE || *surface->data == SF_GRID || *surface->data == SF_TRIANGLES) - { - surfacesSorted[j++] = surface; - } + srfBspSurface_t *bspSurf; + shader_t *shader = surface->shader; + + if (shader->isPortal) + continue; + + if (shader->isSky) + continue; + + if (ShaderRequiresCPUDeforms(shader)) + continue; + + // check for this now so we can use srfBspSurface_t* universally in the rest of the function + if (!(*surface->data == SF_FACE || *surface->data == SF_GRID || *surface->data == SF_TRIANGLES)) + continue; + + bspSurf = (srfBspSurface_t *) surface->data; + + if (!bspSurf->numIndexes || !bspSurf->numVerts) + continue; + + surfacesSorted[j++] = surface; } - qsort(surfacesSorted, numSurfaces, sizeof(*surfacesSorted), BSPSurfaceCompare); + qsort(surfacesSorted, numSortedSurfaces, sizeof(*surfacesSorted), BSPSurfaceCompare); - // set up triangle indices - numVerts = 0; - numTriangles = 0; - for(k = 0, surface = surfacesSorted[k]; k < numSurfaces; k++, surface = surfacesSorted[k]) + k = 0; + for(firstSurf = lastSurf = surfacesSorted; firstSurf < &surfacesSorted[numSortedSurfaces]; firstSurf = lastSurf) { - if(*surface->data == SF_FACE) + int currVboSize, currIboSize; + + // Find range of surfaces to merge by: + // - Collecting a number of surfaces which fit under maxVboSize/maxIboSize, or + // - All the surfaces with a single shader which go over maxVboSize/maxIboSize + currVboSize = currIboSize = 0; + while (currVboSize < maxVboSize && currIboSize < maxIboSize && lastSurf < &surfacesSorted[numSortedSurfaces]) { - srfSurfaceFace_t *srf = (srfSurfaceFace_t *) surface->data; + int addVboSize, addIboSize, currShaderIndex; - srf->firstIndex = numTriangles * 3; + addVboSize = addIboSize = 0; + currShaderIndex = (*lastSurf)->shader->sortedIndex; - if(srf->numTriangles) + for(currSurf = lastSurf; currSurf < &surfacesSorted[numSortedSurfaces] && (*currSurf)->shader->sortedIndex == currShaderIndex; currSurf++) { - srfTriangle_t *tri; + srfBspSurface_t *bspSurf = (srfBspSurface_t *) (*currSurf)->data; - srf->minIndex = numVerts + srf->triangles->indexes[0]; - srf->maxIndex = numVerts + srf->triangles->indexes[0]; - - for(i = 0, tri = srf->triangles; i < srf->numTriangles; i++, tri++) - { - for(j = 0; j < 3; j++) - { - triangles[numTriangles + i].indexes[j] = numVerts + tri->indexes[j]; - srf->minIndex = MIN(srf->minIndex, numVerts + tri->indexes[j]); - srf->maxIndex = MAX(srf->maxIndex, numVerts + tri->indexes[j]); - } - } - - numTriangles += srf->numTriangles; + addVboSize += bspSurf->numVerts * sizeof(srfVert_t); + addIboSize += bspSurf->numIndexes * sizeof(glIndex_t); } - if(srf->numVerts) - numVerts += srf->numVerts; + if ((currVboSize != 0 && addVboSize + currVboSize > maxVboSize) + || (currIboSize != 0 && addIboSize + currIboSize > maxIboSize)) + break; + + lastSurf = currSurf; + + currVboSize += addVboSize; + currIboSize += addIboSize; } - else if(*surface->data == SF_GRID) + + // count verts/indexes/surfaces + numVerts = 0; + numIndexes = 0; + numSurfaces = 0; + for (currSurf = firstSurf; currSurf < lastSurf; currSurf++) { - srfGridMesh_t *srf = (srfGridMesh_t *) surface->data; + srfBspSurface_t *bspSurf = (srfBspSurface_t *) (*currSurf)->data; - srf->firstIndex = numTriangles * 3; + numVerts += bspSurf->numVerts; + numIndexes += bspSurf->numIndexes; + numSurfaces++; + } - if(srf->numTriangles) + ri.Printf(PRINT_ALL, "...calculating world VBO %d ( %i verts %i tris )\n", k, numVerts, numIndexes / 3); + + // create arrays + verts = ri.Hunk_AllocateTempMemory(numVerts * sizeof(srfVert_t)); + indexes = ri.Hunk_AllocateTempMemory(numIndexes * sizeof(glIndex_t)); + + // set up indices and copy vertices + numVerts = 0; + numIndexes = 0; + for (currSurf = firstSurf; currSurf < lastSurf; currSurf++) + { + srfBspSurface_t *bspSurf = (srfBspSurface_t *) (*currSurf)->data; + glIndex_t *surfIndex; + + bspSurf->firstIndex = numIndexes; + bspSurf->minIndex = numVerts + bspSurf->indexes[0]; + bspSurf->maxIndex = numVerts + bspSurf->indexes[0]; + + for(i = 0, surfIndex = bspSurf->indexes; i < bspSurf->numIndexes; i++, surfIndex++) { - srfTriangle_t *tri; - - srf->minIndex = numVerts + srf->triangles->indexes[0]; - srf->maxIndex = numVerts + srf->triangles->indexes[0]; - - for(i = 0, tri = srf->triangles; i < srf->numTriangles; i++, tri++) - { - for(j = 0; j < 3; j++) - { - triangles[numTriangles + i].indexes[j] = numVerts + tri->indexes[j]; - srf->minIndex = MIN(srf->minIndex, numVerts + tri->indexes[j]); - srf->maxIndex = MAX(srf->maxIndex, numVerts + tri->indexes[j]); - } - } - - numTriangles += srf->numTriangles; + indexes[numIndexes++] = numVerts + *surfIndex; + bspSurf->minIndex = MIN(bspSurf->minIndex, numVerts + *surfIndex); + bspSurf->maxIndex = MAX(bspSurf->maxIndex, numVerts + *surfIndex); } - if(srf->numVerts) - numVerts += srf->numVerts; - } - else if(*surface->data == SF_TRIANGLES) - { - srfTriangles_t *srf = (srfTriangles_t *) surface->data; + bspSurf->firstVert = numVerts; - srf->firstIndex = numTriangles * 3; - - if(srf->numTriangles) + for(i = 0; i < bspSurf->numVerts; i++) { - srfTriangle_t *tri; - - srf->minIndex = numVerts + srf->triangles->indexes[0]; - srf->maxIndex = numVerts + srf->triangles->indexes[0]; - - for(i = 0, tri = srf->triangles; i < srf->numTriangles; i++, tri++) - { - for(j = 0; j < 3; j++) - { - triangles[numTriangles + i].indexes[j] = numVerts + tri->indexes[j]; - srf->minIndex = MIN(srf->minIndex, numVerts + tri->indexes[j]); - srf->maxIndex = MAX(srf->maxIndex, numVerts + tri->indexes[j]); - } - } - - numTriangles += srf->numTriangles; - } - - if(srf->numVerts) - numVerts += srf->numVerts; - } - } - - // build vertices - numVerts = 0; - for(k = 0, surface = surfacesSorted[k]; k < numSurfaces; k++, surface = surfacesSorted[k]) - { - if(*surface->data == SF_FACE) - { - srfSurfaceFace_t *srf = (srfSurfaceFace_t *) surface->data; - - srf->firstVert = numVerts; - - if(srf->numVerts) - { - for(i = 0; i < srf->numVerts; i++) - { - CopyVert(&srf->verts[i], &verts[numVerts + i]); - } - - numVerts += srf->numVerts; + CopyVert(&bspSurf->verts[i], &verts[numVerts++]); } } - else if(*surface->data == SF_GRID) - { - srfGridMesh_t *srf = (srfGridMesh_t *) surface->data; - - srf->firstVert = numVerts; - - if(srf->numVerts) - { - for(i = 0; i < srf->numVerts; i++) - { - CopyVert(&srf->verts[i], &verts[numVerts + i]); - } - - numVerts += srf->numVerts; - } - } - else if(*surface->data == SF_TRIANGLES) - { - srfTriangles_t *srf = (srfTriangles_t *) surface->data; - - srf->firstVert = numVerts; - - if(srf->numVerts) - { - for(i = 0; i < srf->numVerts; i++) - { - CopyVert(&srf->verts[i], &verts[numVerts + i]); - } - - numVerts += srf->numVerts; - } - } - } #ifdef USE_VERT_TANGENT_SPACE - s_worldData.vbo = R_CreateVBO2(va("staticBspModel0_VBO %i", 0), numVerts, verts, - ATTR_POSITION | ATTR_TEXCOORD | ATTR_LIGHTCOORD | ATTR_TANGENT | ATTR_BITANGENT | - ATTR_NORMAL | ATTR_COLOR | ATTR_LIGHTDIRECTION, VBO_USAGE_STATIC); + vbo = R_CreateVBO2(va("staticBspModel0_VBO %i", k), numVerts, verts, + ATTR_POSITION | ATTR_TEXCOORD | ATTR_LIGHTCOORD | ATTR_TANGENT | + ATTR_NORMAL | ATTR_COLOR | ATTR_LIGHTDIRECTION, VBO_USAGE_STATIC); #else - s_worldData.vbo = R_CreateVBO2(va("staticBspModel0_VBO %i", 0), numVerts, verts, - ATTR_POSITION | ATTR_TEXCOORD | ATTR_LIGHTCOORD | - ATTR_NORMAL | ATTR_COLOR | ATTR_LIGHTDIRECTION, VBO_USAGE_STATIC); + vbo = R_CreateVBO2(va("staticBspModel0_VBO %i", k), numVerts, verts, + ATTR_POSITION | ATTR_TEXCOORD | ATTR_LIGHTCOORD | + ATTR_NORMAL | ATTR_COLOR | ATTR_LIGHTDIRECTION, VBO_USAGE_STATIC); #endif - s_worldData.ibo = R_CreateIBO2(va("staticBspModel0_IBO %i", 0), numTriangles, triangles, VBO_USAGE_STATIC); + ibo = R_CreateIBO2(va("staticBspModel0_IBO %i", k), numIndexes, indexes, VBO_USAGE_STATIC); - endTime = ri.Milliseconds(); - ri.Printf(PRINT_ALL, "world VBO calculation time = %5.2f seconds\n", (endTime - startTime) / 1000.0); - - // point triangle surfaces to world VBO - for(k = 0, surface = surfacesSorted[k]; k < numSurfaces; k++, surface = surfacesSorted[k]) - { - if(*surface->data == SF_FACE) + // point bsp surfaces to VBO + for (currSurf = firstSurf; currSurf < lastSurf; currSurf++) { - srfSurfaceFace_t *srf = (srfSurfaceFace_t *) surface->data; + srfBspSurface_t *bspSurf = (srfBspSurface_t *) (*currSurf)->data; - if( srf->numVerts && srf->numTriangles) - { - srf->vbo = s_worldData.vbo; - srf->ibo = s_worldData.ibo; - } + bspSurf->vbo = vbo; + bspSurf->ibo = ibo; } - else if(*surface->data == SF_GRID) - { - srfGridMesh_t *srf = (srfGridMesh_t *) surface->data; - if( srf->numVerts && srf->numTriangles) - { - srf->vbo = s_worldData.vbo; - srf->ibo = s_worldData.ibo; - } - } - else if(*surface->data == SF_TRIANGLES) - { - srfTriangles_t *srf = (srfTriangles_t *) surface->data; + ri.Hunk_FreeTempMemory(indexes); + ri.Hunk_FreeTempMemory(verts); - if( srf->numVerts && srf->numTriangles) - { - srf->vbo = s_worldData.vbo; - srf->ibo = s_worldData.ibo; - } - } + k++; } - ri.Free(surfacesSorted); - ri.Hunk_FreeTempMemory(triangles); - ri.Hunk_FreeTempMemory(verts); + endTime = ri.Milliseconds(); + ri.Printf(PRINT_ALL, "world VBOs calculation time = %5.2f seconds\n", (endTime - startTime) / 1000.0); } /* @@ -2187,7 +2112,7 @@ static void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump ) { // Two passes, allocate surfaces first, then load them full of data // This ensures surfaces are close together to reduce L2 cache misses when using VBOs, - // which don't actually use the verts and tris + // which don't actually use the verts and indexes in = (void *)(fileBase + surfs->fileofs); out = s_worldData.surfaces; for ( i = 0 ; i < count ; i++, in++, out++ ) { @@ -2196,10 +2121,10 @@ static void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump ) { // FIXME: do this break; case MST_TRIANGLE_SOUP: - out->data = ri.Hunk_Alloc( sizeof(srfTriangles_t), h_low); + out->data = ri.Hunk_Alloc( sizeof(srfBspSurface_t), h_low); break; case MST_PLANAR: - out->data = ri.Hunk_Alloc( sizeof(srfSurfaceFace_t), h_low); + out->data = ri.Hunk_Alloc( sizeof(srfBspSurface_t), h_low); break; case MST_FLARE: out->data = ri.Hunk_Alloc( sizeof(srfFlare_t), h_low); @@ -2216,13 +2141,13 @@ static void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump ) { case MST_PATCH: ParseMesh ( in, dv, hdrVertColors, out ); { - srfGridMesh_t *surface = (srfGridMesh_t *)out->data; + srfBspSurface_t *surface = (srfBspSurface_t *)out->data; out->cullinfo.type = CULLINFO_BOX | CULLINFO_SPHERE; - VectorCopy(surface->meshBounds[0], out->cullinfo.bounds[0]); - VectorCopy(surface->meshBounds[1], out->cullinfo.bounds[1]); - VectorCopy(surface->localOrigin, out->cullinfo.localOrigin); - out->cullinfo.radius = surface->meshRadius; + VectorCopy(surface->cullBounds[0], out->cullinfo.bounds[0]); + VectorCopy(surface->cullBounds[1], out->cullinfo.bounds[1]); + VectorCopy(surface->cullOrigin, out->cullinfo.localOrigin); + out->cullinfo.radius = surface->cullRadius; } numMeshes++; break; @@ -3006,6 +2931,7 @@ void R_MergeLeafSurfaces(void) int mergedSurfIndex; int numMergedSurfaces; int numUnmergedSurfaces; + VBO_t *vbo; IBO_t *ibo; msurface_t *mergedSurf; @@ -3025,14 +2951,6 @@ void R_MergeLeafSurfaces(void) s_worldData.surfacesViewCount[i] = -1; } - // create ibo - ibo = tr.ibos[tr.numIBOs++] = ri.Hunk_Alloc(sizeof(*ibo), h_low); - memset(ibo, 0, sizeof(*ibo)); - Q_strncpyz(ibo->name, "staticWorldMesh_IBO_mergedSurfs", sizeof(ibo->name)); - - // allocate more than we need - iboIndexes = outIboIndexes = ri.Malloc(s_worldData.ibo->indexesSize); - // mark matching surfaces for (i = 0; i < s_worldData.numnodes - s_worldData.numDecisionNodes; i++) { @@ -3166,6 +3084,9 @@ void R_MergeLeafSurfaces(void) s_worldData.viewSurfaces[i] = s_worldData.marksurfaces[i]; } + // need to be synched here + R_IssuePendingRenderCommands(); + // actually merge surfaces numIboIndexes = 0; mergedSurfIndex = 0; @@ -3177,80 +3098,61 @@ void R_MergeLeafSurfaces(void) vec3_t bounds[2]; int numSurfsToMerge; - int numTriangles; + int numIndexes; int numVerts; int firstIndex; - srfVBOMesh_t *vboSurf; + srfBspSurface_t *vboSurf; if (s_worldData.surfacesViewCount[i] != i) continue; - + surf1 = s_worldData.surfaces + i; + // retrieve vbo + vbo = ((srfBspSurface_t *)(surf1->data))->vbo; + // count verts, indexes, and surfaces numSurfsToMerge = 0; - numTriangles = 0; + numIndexes = 0; numVerts = 0; - for (j = 0; j < numWorldSurfaces; j++) + for (j = i; j < numWorldSurfaces; j++) { msurface_t *surf2; + srfBspSurface_t *bspSurf; if (s_worldData.surfacesViewCount[j] != i) continue; surf2 = s_worldData.surfaces + j; - switch(*surf2->data) - { - case SF_FACE: - { - srfSurfaceFace_t *face; - - face = (srfSurfaceFace_t *) surf2->data; - numTriangles += face->numTriangles; - numVerts += face->numVerts; - } - break; - - case SF_GRID: - { - srfGridMesh_t *grid; - - grid = (srfGridMesh_t *) surf2->data; - numTriangles += grid->numTriangles; - numVerts += grid->numVerts; - } - break; - - case SF_TRIANGLES: - { - srfTriangles_t *tris; - - tris = (srfTriangles_t *) surf2->data; - numTriangles += tris->numTriangles; - numVerts += tris->numVerts; - } - break; - - default: - break; - } - + bspSurf = (srfBspSurface_t *) surf2->data; + numIndexes += bspSurf->numIndexes; + numVerts += bspSurf->numVerts; numSurfsToMerge++; } - if (numVerts == 0 || numTriangles == 0 || numSurfsToMerge < 2) + if (numVerts == 0 || numIndexes == 0 || numSurfsToMerge < 2) { continue; } + // create ibo + ibo = tr.ibos[tr.numIBOs] = ri.Hunk_Alloc(sizeof(*ibo), h_low); + memset(ibo, 0, sizeof(*ibo)); + Q_strncpyz(ibo->name, va("staticWorldMesh_IBO_mergedSurfs%i", tr.numIBOs++), sizeof(ibo->name)); + numIboIndexes = 0; + + // allocate indexes + iboIndexes = outIboIndexes = ri.Malloc(numIndexes * sizeof(*outIboIndexes)); + // Merge surfaces (indexes) and calculate bounds ClearBounds(bounds[0], bounds[1]); firstIndex = numIboIndexes; - for (j = 0; j < numWorldSurfaces; j++) + for (j = i; j < numWorldSurfaces; j++) { msurface_t *surf2; + srfBspSurface_t *bspSurf; if (s_worldData.surfacesViewCount[j] != i) continue; @@ -3260,88 +3162,37 @@ void R_MergeLeafSurfaces(void) AddPointToBounds(surf2->cullinfo.bounds[0], bounds[0], bounds[1]); AddPointToBounds(surf2->cullinfo.bounds[1], bounds[0], bounds[1]); - switch(*surf2->data) + bspSurf = (srfBspSurface_t *) surf2->data; + for (k = 0; k < bspSurf->numIndexes; k++) { - case SF_FACE: - { - srfSurfaceFace_t *face; - - face = (srfSurfaceFace_t *) surf2->data; - - for (k = 0; k < face->numTriangles; k++) - { - *outIboIndexes++ = face->triangles[k].indexes[0] + face->firstVert; - *outIboIndexes++ = face->triangles[k].indexes[1] + face->firstVert; - *outIboIndexes++ = face->triangles[k].indexes[2] + face->firstVert; - numIboIndexes += 3; - } - } - break; - - case SF_GRID: - { - srfGridMesh_t *grid; - - grid = (srfGridMesh_t *) surf2->data; - - for (k = 0; k < grid->numTriangles; k++) - { - *outIboIndexes++ = grid->triangles[k].indexes[0] + grid->firstVert; - *outIboIndexes++ = grid->triangles[k].indexes[1] + grid->firstVert; - *outIboIndexes++ = grid->triangles[k].indexes[2] + grid->firstVert; - numIboIndexes += 3; - } - } - break; - - case SF_TRIANGLES: - { - srfTriangles_t *tris; - - tris = (srfTriangles_t *) surf2->data; - - for (k = 0; k < tris->numTriangles; k++) - { - *outIboIndexes++ = tris->triangles[k].indexes[0] + tris->firstVert; - *outIboIndexes++ = tris->triangles[k].indexes[1] + tris->firstVert; - *outIboIndexes++ = tris->triangles[k].indexes[2] + tris->firstVert; - numIboIndexes += 3; - } - } - break; - - // never happens, but silences a compile warning - default: - break; + *outIboIndexes++ = bspSurf->indexes[k] + bspSurf->firstVert; + numIboIndexes++; } + break; } vboSurf = ri.Hunk_Alloc(sizeof(*vboSurf), h_low); memset(vboSurf, 0, sizeof(*vboSurf)); vboSurf->surfaceType = SF_VBO_MESH; - vboSurf->vbo = s_worldData.vbo; + vboSurf->vbo = vbo; vboSurf->ibo = ibo; - vboSurf->numIndexes = numTriangles * 3; + vboSurf->numIndexes = numIndexes; vboSurf->numVerts = numVerts; vboSurf->firstIndex = firstIndex; vboSurf->minIndex = *(iboIndexes + firstIndex); vboSurf->maxIndex = *(iboIndexes + firstIndex); - for (j = 1; j < numTriangles * 3; j++) + for (j = 0; j < numIndexes; j++) { vboSurf->minIndex = MIN(vboSurf->minIndex, *(iboIndexes + firstIndex + j)); vboSurf->maxIndex = MAX(vboSurf->maxIndex, *(iboIndexes + firstIndex + j)); } - vboSurf->shader = surf1->shader; - vboSurf->fogIndex = surf1->fogIndex; - vboSurf->cubemapIndex = surf1->cubemapIndex; - - VectorCopy(bounds[0], vboSurf->bounds[0]); - VectorCopy(bounds[1], vboSurf->bounds[1]); + VectorCopy(bounds[0], vboSurf->cullBounds[0]); + VectorCopy(bounds[1], vboSurf->cullBounds[1]); VectorCopy(bounds[0], mergedSurf->cullinfo.bounds[0]); VectorCopy(bounds[1], mergedSurf->cullinfo.bounds[1]); @@ -3352,6 +3203,17 @@ void R_MergeLeafSurfaces(void) mergedSurf->cubemapIndex = surf1->cubemapIndex; mergedSurf->shader = surf1->shader; + // finish up the ibo + qglGenBuffersARB(1, &ibo->indexesVBO); + + R_BindIBO(ibo); + qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, numIboIndexes * sizeof(*iboIndexes), iboIndexes, GL_STATIC_DRAW_ARB); + R_BindNullIBO(); + + GL_CheckErrors(); + + ri.Free(iboIndexes); + // redirect view surfaces to this surf for (j = 0; j < numWorldSurfaces; j++) { @@ -3372,21 +3234,6 @@ void R_MergeLeafSurfaces(void) mergedSurf++; } - // finish up the ibo - R_IssuePendingRenderCommands(); - - qglGenBuffersARB(1, &ibo->indexesVBO); - - R_BindIBO(ibo); - - qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, numIboIndexes * sizeof(*iboIndexes), iboIndexes, GL_STATIC_DRAW_ARB); - - R_BindNullIBO(); - - GL_CheckErrors(); - - ri.Free(iboIndexes); - endTime = ri.Milliseconds(); ri.Printf(PRINT_ALL, "Processed %d surfaces into %d merged, %d unmerged in %5.2f seconds\n", @@ -3407,41 +3254,20 @@ void R_CalcVertexLightDirs( void ) for(k = 0, surface = &s_worldData.surfaces[0]; k < s_worldData.numsurfaces /* s_worldData.numWorldSurfaces */; k++, surface++) { - if(*surface->data == SF_FACE) - { - srfSurfaceFace_t *srf = (srfSurfaceFace_t *) surface->data; + srfBspSurface_t *bspSurf = (srfBspSurface_t *) surface->data; - if(srf->numVerts) - { - for(i = 0; i < srf->numVerts; i++) - { - R_LightDirForPoint( srf->verts[i].xyz, srf->verts[i].lightdir, srf->verts[i].normal, &s_worldData ); - } - } - } - else if(*surface->data == SF_GRID) + switch(bspSurf->surfaceType) { - srfGridMesh_t *srf = (srfGridMesh_t *) surface->data; + case SF_FACE: + case SF_GRID: + case SF_TRIANGLES: + for(i = 0; i < bspSurf->numVerts; i++) + R_LightDirForPoint( bspSurf->verts[i].xyz, bspSurf->verts[i].lightdir, bspSurf->verts[i].normal, &s_worldData ); - if(srf->numVerts) - { - for(i = 0; i < srf->numVerts; i++) - { - R_LightDirForPoint( srf->verts[i].xyz, srf->verts[i].lightdir, srf->verts[i].normal, &s_worldData ); - } - } - } - else if(*surface->data == SF_TRIANGLES) - { - srfTriangles_t *srf = (srfTriangles_t *) surface->data; + break; - if(srf->numVerts) - { - for(i = 0; i < srf->numVerts; i++) - { - R_LightDirForPoint( srf->verts[i].xyz, srf->verts[i].lightdir, srf->verts[i].normal, &s_worldData ); - } - } + default: + break; } } } @@ -3743,7 +3569,7 @@ void RE_LoadWorldMap( const char *name ) { } // create static VBOS from the world - R_CreateWorldVBO(); + R_CreateWorldVBOs(); if (r_mergeLeafSurfaces->integer) { R_MergeLeafSurfaces(); diff --git a/code/renderergl2/tr_cmds.c b/code/renderergl2/tr_cmds.c index 1426b581..139a3430 100644 --- a/code/renderergl2/tr_cmds.c +++ b/code/renderergl2/tr_cmds.c @@ -442,12 +442,6 @@ void RE_BeginFrame( stereoFrame_t stereoFrame ) { qglClear(GL_COLOR_BUFFER_BIT); } - if (tr.screenScratchFbo) - { - FBO_Bind(tr.screenScratchFbo); - qglClear(GL_COLOR_BUFFER_BIT); - } - FBO_Bind(NULL); } diff --git a/code/renderergl2/tr_curve.c b/code/renderergl2/tr_curve.c index 3d439257..91c80a4d 100644 --- a/code/renderergl2/tr_curve.c +++ b/code/renderergl2/tr_curve.c @@ -25,14 +25,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* This file does all of the processing necessary to turn a raw grid of points -read from the map file into a srfGridMesh_t ready for rendering. +read from the map file into a srfBspSurface_t ready for rendering. The level of detail solution is direction independent, based only on subdivided distance from the true curve. Only a single entry point: -srfGridMesh_t *R_SubdividePatchToGrid( int width, int height, +srfBspSurface_t *R_SubdividePatchToGrid( int width, int height, srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) { */ @@ -213,13 +213,13 @@ static int neighbors[8][2] = { } #ifdef USE_VERT_TANGENT_SPACE -static void MakeMeshTangentVectors(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], int numTriangles, - srfTriangle_t triangles[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2]) +static void MakeMeshTangentVectors(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], int numIndexes, + glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]) { int i, j; srfVert_t *dv[3]; static srfVert_t ctrl2[MAX_GRID_SIZE * MAX_GRID_SIZE]; - srfTriangle_t *tri; + glIndex_t *tri; // FIXME: use more elegant way for(i = 0; i < width; i++) @@ -231,53 +231,15 @@ static void MakeMeshTangentVectors(int width, int height, srfVert_t ctrl[MAX_GRI } } - for(i = 0, tri = triangles; i < numTriangles; i++, tri++) + for(i = 0, tri = indexes; i < numIndexes; i += 3, tri += 3) { - dv[0] = &ctrl2[tri->indexes[0]]; - dv[1] = &ctrl2[tri->indexes[1]]; - dv[2] = &ctrl2[tri->indexes[2]]; + dv[0] = &ctrl2[tri[0]]; + dv[1] = &ctrl2[tri[1]]; + dv[2] = &ctrl2[tri[2]]; R_CalcTangentVectors(dv); } -#if 0 - for(i = 0; i < (width * height); i++) - { - dv0 = &ctrl2[i]; - - VectorNormalize(dv0->normal); -#if 0 - VectorNormalize(dv0->tangent); - VectorNormalize(dv0->bitangent); -#else - d = DotProduct(dv0->tangent, dv0->normal); - VectorMA(dv0->tangent, -d, dv0->normal, dv0->tangent); - VectorNormalize(dv0->tangent); - - d = DotProduct(dv0->bitangent, dv0->normal); - VectorMA(dv0->bitangent, -d, dv0->normal, dv0->bitangent); - VectorNormalize(dv0->bitangent); -#endif - } -#endif - - -#if 0 - // do another extra smoothing for normals to avoid flat shading - for(i = 0; i < (width * height); i++) - { - for(j = 0; j < (width * height); j++) - { - if(R_CompareVert(&ctrl2[i], &ctrl2[j], qfalse)) - { - VectorAdd(ctrl2[i].normal, ctrl2[j].normal, ctrl2[i].normal); - } - } - - VectorNormalize(ctrl2[i].normal); - } -#endif - for(i = 0; i < width; i++) { for(j = 0; j < height; j++) @@ -285,26 +247,25 @@ static void MakeMeshTangentVectors(int width, int height, srfVert_t ctrl[MAX_GRI dv[0] = &ctrl2[j * width + i]; dv[1] = &ctrl[j][i]; - VectorCopy(dv[0]->tangent, dv[1]->tangent); - VectorCopy(dv[0]->bitangent, dv[1]->bitangent); + VectorCopy4(dv[0]->tangent, dv[1]->tangent); } } } #endif -static int MakeMeshTriangles(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], - srfTriangle_t triangles[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2]) +static int MakeMeshIndexes(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], + glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]) { int i, j; - int numTriangles; + int numIndexes; int w, h; srfVert_t *dv; static srfVert_t ctrl2[MAX_GRID_SIZE * MAX_GRID_SIZE]; h = height - 1; w = width - 1; - numTriangles = 0; + numIndexes = 0; for(i = 0; i < h; i++) { for(j = 0; j < w; j++) @@ -317,20 +278,16 @@ static int MakeMeshTriangles(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE v3 = v2 + width; v4 = v3 + 1; - triangles[numTriangles].indexes[0] = v2; - triangles[numTriangles].indexes[1] = v3; - triangles[numTriangles].indexes[2] = v1; - numTriangles++; + indexes[numIndexes++] = v2; + indexes[numIndexes++] = v3; + indexes[numIndexes++] = v1; - triangles[numTriangles].indexes[0] = v1; - triangles[numTriangles].indexes[1] = v3; - triangles[numTriangles].indexes[2] = v4; - numTriangles++; + indexes[numIndexes++] = v1; + indexes[numIndexes++] = v3; + indexes[numIndexes++] = v4; } } - R_CalcSurfaceTriangleNeighbors(numTriangles, triangles); - // FIXME: use more elegant way for(i = 0; i < width; i++) { @@ -341,9 +298,7 @@ static int MakeMeshTriangles(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE } } - R_CalcSurfaceTrianglePlanes(numTriangles, triangles, ctrl2); - - return numTriangles; + return numIndexes; } @@ -420,13 +375,13 @@ static void PutPointsOnCurve( srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], R_CreateSurfaceGridMesh ================= */ -srfGridMesh_t *R_CreateSurfaceGridMesh(int width, int height, +srfBspSurface_t *R_CreateSurfaceGridMesh(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], float errorTable[2][MAX_GRID_SIZE], - int numTriangles, srfTriangle_t triangles[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2]) { + int numIndexes, glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]) { int i, j, size; srfVert_t *vert; vec3_t tmpVec; - srfGridMesh_t *grid; + srfBspSurface_t *grid; // copy the results out to a grid size = (width * height - 1) * sizeof( srfVert_t ) + sizeof( *grid ); @@ -441,9 +396,9 @@ srfGridMesh_t *R_CreateSurfaceGridMesh(int width, int height, grid->heightLodError = /*ri.Hunk_Alloc*/ ri.Malloc( height * 4 ); Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 ); - grid->numTriangles = numTriangles; - grid->triangles = ri.Malloc(grid->numTriangles * sizeof(srfTriangle_t)); - Com_Memcpy(grid->triangles, triangles, numTriangles * sizeof(srfTriangle_t)); + grid->numIndexes = numIndexes; + grid->indexes = ri.Malloc(grid->numIndexes * sizeof(glIndex_t)); + Com_Memcpy(grid->indexes, indexes, numIndexes * sizeof(glIndex_t)); grid->numVerts = (width * height); grid->verts = ri.Malloc(grid->numVerts * sizeof(srfVert_t)); @@ -457,9 +412,9 @@ srfGridMesh_t *R_CreateSurfaceGridMesh(int width, int height, grid->heightLodError = ri.Hunk_Alloc( height * 4 ); Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 ); - grid->numTriangles = numTriangles; - grid->triangles = ri.Hunk_Alloc(grid->numTriangles * sizeof(srfTriangle_t), h_low); - Com_Memcpy(grid->triangles, triangles, numTriangles * sizeof(srfTriangle_t)); + grid->numIndexes = numIndexes; + grid->indexes = ri.Hunk_Alloc(grid->numIndexes * sizeof(glIndex_t), h_low); + Com_Memcpy(grid->indexes, indexes, numIndexes * sizeof(glIndex_t)); grid->numVerts = (width * height); grid->verts = ri.Hunk_Alloc(grid->numVerts * sizeof(srfVert_t), h_low); @@ -468,23 +423,23 @@ srfGridMesh_t *R_CreateSurfaceGridMesh(int width, int height, grid->width = width; grid->height = height; grid->surfaceType = SF_GRID; - ClearBounds( grid->meshBounds[0], grid->meshBounds[1] ); + ClearBounds( grid->cullBounds[0], grid->cullBounds[1] ); for ( i = 0 ; i < width ; i++ ) { for ( j = 0 ; j < height ; j++ ) { vert = &grid->verts[j*width+i]; *vert = ctrl[j][i]; - AddPointToBounds( vert->xyz, grid->meshBounds[0], grid->meshBounds[1] ); + AddPointToBounds( vert->xyz, grid->cullBounds[0], grid->cullBounds[1] ); } } // compute local origin and bounds - VectorAdd( grid->meshBounds[0], grid->meshBounds[1], grid->localOrigin ); - VectorScale( grid->localOrigin, 0.5f, grid->localOrigin ); - VectorSubtract( grid->meshBounds[0], grid->localOrigin, tmpVec ); - grid->meshRadius = VectorLength( tmpVec ); + VectorAdd( grid->cullBounds[0], grid->cullBounds[1], grid->cullOrigin ); + VectorScale( grid->cullOrigin, 0.5f, grid->cullOrigin ); + VectorSubtract( grid->cullBounds[0], grid->cullOrigin, tmpVec ); + grid->cullRadius = VectorLength( tmpVec ); - VectorCopy( grid->localOrigin, grid->lodOrigin ); - grid->lodRadius = grid->meshRadius; + VectorCopy( grid->cullOrigin, grid->lodOrigin ); + grid->lodRadius = grid->cullRadius; // return grid; } @@ -494,10 +449,10 @@ srfGridMesh_t *R_CreateSurfaceGridMesh(int width, int height, R_FreeSurfaceGridMesh ================= */ -void R_FreeSurfaceGridMesh( srfGridMesh_t *grid ) { +void R_FreeSurfaceGridMesh( srfBspSurface_t *grid ) { ri.Free(grid->widthLodError); ri.Free(grid->heightLodError); - ri.Free(grid->triangles); + ri.Free(grid->indexes); ri.Free(grid->verts); ri.Free(grid); } @@ -507,7 +462,7 @@ void R_FreeSurfaceGridMesh( srfGridMesh_t *grid ) { R_SubdividePatchToGrid ================= */ -srfGridMesh_t *R_SubdividePatchToGrid( int width, int height, +srfBspSurface_t *R_SubdividePatchToGrid( int width, int height, srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) { int i, j, k, l; srfVert_t_cleared( prev ); @@ -518,8 +473,8 @@ srfGridMesh_t *R_SubdividePatchToGrid( int width, int height, int t; srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; float errorTable[2][MAX_GRID_SIZE]; - int numTriangles; - static srfTriangle_t triangles[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2]; + int numIndexes; + static glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]; int consecutiveComplete; for ( i = 0 ; i < width ; i++ ) { @@ -673,16 +628,16 @@ srfGridMesh_t *R_SubdividePatchToGrid( int width, int height, } #endif - // calculate triangles - numTriangles = MakeMeshTriangles(width, height, ctrl, triangles); + // calculate indexes + numIndexes = MakeMeshIndexes(width, height, ctrl, indexes); // calculate normals MakeMeshNormals( width, height, ctrl ); #ifdef USE_VERT_TANGENT_SPACE - MakeMeshTangentVectors(width, height, ctrl, numTriangles, triangles); + MakeMeshTangentVectors(width, height, ctrl, numIndexes, indexes); #endif - return R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numTriangles, triangles); + return R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numIndexes, indexes); } /* @@ -690,15 +645,15 @@ srfGridMesh_t *R_SubdividePatchToGrid( int width, int height, R_GridInsertColumn =============== */ -srfGridMesh_t *R_GridInsertColumn( srfGridMesh_t *grid, int column, int row, vec3_t point, float loderror ) { +srfBspSurface_t *R_GridInsertColumn( srfBspSurface_t *grid, int column, int row, vec3_t point, float loderror ) { int i, j; int width, height, oldwidth; srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; float errorTable[2][MAX_GRID_SIZE]; float lodRadius; vec3_t lodOrigin; - int numTriangles; - static srfTriangle_t triangles[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2]; + int numIndexes; + static glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]; oldwidth = 0; width = grid->width + 1; @@ -728,8 +683,8 @@ srfGridMesh_t *R_GridInsertColumn( srfGridMesh_t *grid, int column, int row, vec // put all the aproximating points on the curve //PutPointsOnCurve( ctrl, width, height ); - // calculate triangles - numTriangles = MakeMeshTriangles(width, height, ctrl, triangles); + // calculate indexes + numIndexes = MakeMeshIndexes(width, height, ctrl, indexes); // calculate normals MakeMeshNormals( width, height, ctrl ); @@ -739,7 +694,7 @@ srfGridMesh_t *R_GridInsertColumn( srfGridMesh_t *grid, int column, int row, vec // free the old grid R_FreeSurfaceGridMesh(grid); // create a new grid - grid = R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numTriangles, triangles); + grid = R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numIndexes, indexes); grid->lodRadius = lodRadius; VectorCopy(lodOrigin, grid->lodOrigin); return grid; @@ -750,15 +705,15 @@ srfGridMesh_t *R_GridInsertColumn( srfGridMesh_t *grid, int column, int row, vec R_GridInsertRow =============== */ -srfGridMesh_t *R_GridInsertRow( srfGridMesh_t *grid, int row, int column, vec3_t point, float loderror ) { +srfBspSurface_t *R_GridInsertRow( srfBspSurface_t *grid, int row, int column, vec3_t point, float loderror ) { int i, j; int width, height, oldheight; srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; float errorTable[2][MAX_GRID_SIZE]; float lodRadius; vec3_t lodOrigin; - int numTriangles; - static srfTriangle_t triangles[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2]; + int numIndexes; + static glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]; oldheight = 0; width = grid->width; @@ -788,8 +743,8 @@ srfGridMesh_t *R_GridInsertRow( srfGridMesh_t *grid, int row, int column, vec3_t // put all the aproximating points on the curve //PutPointsOnCurve( ctrl, width, height ); - // calculate triangles - numTriangles = MakeMeshTriangles(width, height, ctrl, triangles); + // calculate indexes + numIndexes = MakeMeshIndexes(width, height, ctrl, indexes); // calculate normals MakeMeshNormals( width, height, ctrl ); @@ -799,7 +754,7 @@ srfGridMesh_t *R_GridInsertRow( srfGridMesh_t *grid, int row, int column, vec3_t // free the old grid R_FreeSurfaceGridMesh(grid); // create a new grid - grid = R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numTriangles, triangles); + grid = R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numIndexes, indexes); grid->lodRadius = lodRadius; VectorCopy(lodOrigin, grid->lodOrigin); return grid; diff --git a/code/renderergl2/tr_extensions.c b/code/renderergl2/tr_extensions.c index 41cd9164..d7e5f1ba 100644 --- a/code/renderergl2/tr_extensions.c +++ b/code/renderergl2/tr_extensions.c @@ -701,8 +701,25 @@ void GLimp_InitExtraExtensions() glRefConfig.seamlessCubeMap = qfalse; if( GLimp_HaveExtension( extension ) ) { - glRefConfig.seamlessCubeMap = qtrue; - ri.Printf(PRINT_ALL, result[1], extension); + if (r_arb_seamless_cube_map->integer) + glRefConfig.seamlessCubeMap = qtrue; + + ri.Printf(PRINT_ALL, result[glRefConfig.seamlessCubeMap], extension); + } + else + { + ri.Printf(PRINT_ALL, result[2], extension); + } + + // GL_ARB_vertex_type_2_10_10_10_rev + extension = "GL_ARB_vertex_type_2_10_10_10_rev"; + glRefConfig.packedNormalDataType = GL_UNSIGNED_BYTE; + if( GLimp_HaveExtension( extension ) ) + { + if (r_arb_vertex_type_2_10_10_10_rev->integer) + glRefConfig.packedNormalDataType = GL_UNSIGNED_INT_2_10_10_10_REV; + + ri.Printf(PRINT_ALL, result[r_arb_vertex_type_2_10_10_10_rev->integer ? 1 : 0], extension); } else { diff --git a/code/renderergl2/tr_extramath.c b/code/renderergl2/tr_extramath.c index 8cb6fe1a..b844678f 100644 --- a/code/renderergl2/tr_extramath.c +++ b/code/renderergl2/tr_extramath.c @@ -26,7 +26,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // Some matrix helper functions // FIXME: do these already exist in ioq3 and I don't know about them? -void Matrix16Zero( matrix_t out ) +void Mat4Zero( mat4_t out ) { out[ 0] = 0.0f; out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = 0.0f; out[ 1] = 0.0f; out[ 5] = 0.0f; out[ 9] = 0.0f; out[13] = 0.0f; @@ -34,7 +34,7 @@ void Matrix16Zero( matrix_t out ) out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 0.0f; } -void Matrix16Identity( matrix_t out ) +void Mat4Identity( mat4_t out ) { out[ 0] = 1.0f; out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = 0.0f; out[ 1] = 0.0f; out[ 5] = 1.0f; out[ 9] = 0.0f; out[13] = 0.0f; @@ -42,7 +42,7 @@ void Matrix16Identity( matrix_t out ) out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f; } -void Matrix16Copy( const matrix_t in, matrix_t out ) +void Mat4Copy( const mat4_t in, mat4_t out ) { out[ 0] = in[ 0]; out[ 4] = in[ 4]; out[ 8] = in[ 8]; out[12] = in[12]; out[ 1] = in[ 1]; out[ 5] = in[ 5]; out[ 9] = in[ 9]; out[13] = in[13]; @@ -50,7 +50,7 @@ void Matrix16Copy( const matrix_t in, matrix_t out ) out[ 3] = in[ 3]; out[ 7] = in[ 7]; out[11] = in[11]; out[15] = in[15]; } -void Matrix16Multiply( const matrix_t in1, const matrix_t in2, matrix_t out ) +void Mat4Multiply( const mat4_t in1, const mat4_t in2, mat4_t out ) { out[ 0] = in1[ 0] * in2[ 0] + in1[ 4] * in2[ 1] + in1[ 8] * in2[ 2] + in1[12] * in2[ 3]; out[ 1] = in1[ 1] * in2[ 0] + in1[ 5] * in2[ 1] + in1[ 9] * in2[ 2] + in1[13] * in2[ 3]; @@ -73,7 +73,7 @@ void Matrix16Multiply( const matrix_t in1, const matrix_t in2, matrix_t out ) out[15] = in1[ 3] * in2[12] + in1[ 7] * in2[13] + in1[11] * in2[14] + in1[15] * in2[15]; } -void Matrix16Transform( const matrix_t in1, const vec4_t in2, vec4_t out ) +void Mat4Transform( const mat4_t in1, const vec4_t in2, vec4_t out ) { out[ 0] = in1[ 0] * in2[ 0] + in1[ 4] * in2[ 1] + in1[ 8] * in2[ 2] + in1[12] * in2[ 3]; out[ 1] = in1[ 1] * in2[ 0] + in1[ 5] * in2[ 1] + in1[ 9] * in2[ 2] + in1[13] * in2[ 3]; @@ -81,7 +81,7 @@ void Matrix16Transform( const matrix_t in1, const vec4_t in2, vec4_t out ) out[ 3] = in1[ 3] * in2[ 0] + in1[ 7] * in2[ 1] + in1[11] * in2[ 2] + in1[15] * in2[ 3]; } -qboolean Matrix16Compare( const matrix_t a, const matrix_t b ) +qboolean Mat4Compare( const mat4_t a, const mat4_t b ) { return !(a[ 0] != b[ 0] || a[ 4] != b[ 4] || a[ 8] != b[ 8] || a[12] != b[12] || a[ 1] != b[ 1] || a[ 5] != b[ 5] || a[ 9] != b[ 9] || a[13] != b[13] || @@ -89,7 +89,7 @@ qboolean Matrix16Compare( const matrix_t a, const matrix_t b ) a[ 3] != b[ 3] || a[ 7] != b[ 7] || a[11] != b[11] || a[15] != b[15]); } -void Matrix16Dump( const matrix_t in ) +void Mat4Dump( const mat4_t in ) { ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 0], in[ 4], in[ 8], in[12]); ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 1], in[ 5], in[ 9], in[13]); @@ -97,7 +97,7 @@ void Matrix16Dump( const matrix_t in ) ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 3], in[ 7], in[11], in[15]); } -void Matrix16Translation( vec3_t vec, matrix_t out ) +void Mat4Translation( vec3_t vec, mat4_t out ) { out[ 0] = 1.0f; out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = vec[0]; out[ 1] = 0.0f; out[ 5] = 1.0f; out[ 9] = 0.0f; out[13] = vec[1]; @@ -105,7 +105,7 @@ void Matrix16Translation( vec3_t vec, matrix_t out ) out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f; } -void Matrix16Ortho( float left, float right, float bottom, float top, float znear, float zfar, matrix_t out ) +void Mat4Ortho( float left, float right, float bottom, float top, float znear, float zfar, mat4_t out ) { out[ 0] = 2.0f / (right - left); out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = -(right + left) / (right - left); out[ 1] = 0.0f; out[ 5] = 2.0f / (top - bottom); out[ 9] = 0.0f; out[13] = -(top + bottom) / (top - bottom); @@ -113,7 +113,7 @@ void Matrix16Ortho( float left, float right, float bottom, float top, float znea out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f; } -void Matrix16View(vec3_t axes[3], vec3_t origin, matrix_t out) +void Mat4View(vec3_t axes[3], vec3_t origin, mat4_t out) { out[0] = axes[0][0]; out[1] = axes[1][0]; @@ -136,7 +136,7 @@ void Matrix16View(vec3_t axes[3], vec3_t origin, matrix_t out) out[15] = 1; } -void Matrix16SimpleInverse( const matrix_t in, matrix_t out) +void Mat4SimpleInverse( const mat4_t in, mat4_t out) { vec3_t v; float invSqrLen; diff --git a/code/renderergl2/tr_extramath.h b/code/renderergl2/tr_extramath.h index 3e11bb48..0223c640 100644 --- a/code/renderergl2/tr_extramath.h +++ b/code/renderergl2/tr_extramath.h @@ -24,22 +24,22 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #ifndef __TR_EXTRAMATH_H__ #define __TR_EXTRAMATH_H__ -typedef vec_t matrix_t[16]; -typedef int vec2i_t[2]; -typedef int vec3i_t[3]; -typedef int vec4i_t[4]; +typedef vec_t mat4_t[16]; +typedef int ivec2_t[2]; +typedef int ivec3_t[3]; +typedef int ivec4_t[4]; -void Matrix16Zero( matrix_t out ); -void Matrix16Identity( matrix_t out ); -void Matrix16Copy( const matrix_t in, matrix_t out ); -void Matrix16Multiply( const matrix_t in1, const matrix_t in2, matrix_t out ); -void Matrix16Transform( const matrix_t in1, const vec4_t in2, vec4_t out ); -qboolean Matrix16Compare(const matrix_t a, const matrix_t b); -void Matrix16Dump( const matrix_t in ); -void Matrix16Translation( vec3_t vec, matrix_t out ); -void Matrix16Ortho( float left, float right, float bottom, float top, float znear, float zfar, matrix_t out ); -void Matrix16View(vec3_t axes[3], vec3_t origin, matrix_t out); -void Matrix16SimpleInverse( const matrix_t in, matrix_t out); +void Mat4Zero( mat4_t out ); +void Mat4Identity( mat4_t out ); +void Mat4Copy( const mat4_t in, mat4_t out ); +void Mat4Multiply( const mat4_t in1, const mat4_t in2, mat4_t out ); +void Mat4Transform( const mat4_t in1, const vec4_t in2, vec4_t out ); +qboolean Mat4Compare(const mat4_t a, const mat4_t b); +void Mat4Dump( const mat4_t in ); +void Mat4Translation( vec3_t vec, mat4_t out ); +void Mat4Ortho( float left, float right, float bottom, float top, float znear, float zfar, mat4_t out ); +void Mat4View(vec3_t axes[3], vec3_t origin, mat4_t out); +void Mat4SimpleInverse( const mat4_t in, mat4_t out); #define VectorCopy2(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1]) #define VectorSet2(v,x,y) ((v)[0]=(x),(v)[1]=(y)); @@ -52,7 +52,7 @@ void Matrix16SimpleInverse( const matrix_t in, matrix_t out); #define VectorCopy5(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3],(b)[4]=(a)[4]) #define OffsetByteToFloat(a) ((float)(a) * 1.0f/127.5f - 1.0f) -#define FloatToOffsetByte(a) (byte)(((a) + 1.0f) * 127.5f) +#define FloatToOffsetByte(a) (byte)((a) * 127.5f + 128.0f) #define ByteToFloat(a) ((float)(a) * 1.0f/255.0f) #define FloatToByte(a) (byte)((a) * 255.0f) diff --git a/code/renderergl2/tr_fbo.c b/code/renderergl2/tr_fbo.c index a1d1339b..c642b732 100644 --- a/code/renderergl2/tr_fbo.c +++ b/code/renderergl2/tr_fbo.c @@ -386,7 +386,7 @@ void FBO_Init(void) hdrFormat = GL_RGBA8; if (r_hdr->integer && glRefConfig.framebufferObject && glRefConfig.textureFloat) { - hdrFormat = GL_RGB16F_ARB; + hdrFormat = GL_RGBA16F_ARB; } qglGetIntegerv(GL_MAX_SAMPLES_EXT, &multisample); @@ -465,34 +465,48 @@ void FBO_Init(void) } // FIXME: Don't use separate color/depth buffers for a shadow buffer - for( i = 0; i < MAX_DRAWN_PSHADOWS; i++) + if (MAX_DRAWN_PSHADOWS && tr.pshadowMaps[0]) { - tr.pshadowFbos[i] = FBO_Create(va("_shadowmap%d", i), tr.pshadowMaps[i]->width, tr.pshadowMaps[i]->height); - FBO_Bind(tr.pshadowFbos[i]); + for( i = 0; i < MAX_DRAWN_PSHADOWS; i++) + { + tr.pshadowFbos[i] = FBO_Create(va("_shadowmap%d", i), tr.pshadowMaps[i]->width, tr.pshadowMaps[i]->height); + FBO_Bind(tr.pshadowFbos[i]); - //FBO_CreateBuffer(tr.pshadowFbos[i], GL_RGBA8, 0, 0); - FBO_AttachTextureImage(tr.pshadowMaps[i], 0); + //FBO_CreateBuffer(tr.pshadowFbos[i], GL_RGBA8, 0, 0); + FBO_AttachTextureImage(tr.pshadowMaps[i], 0); - FBO_CreateBuffer(tr.pshadowFbos[i], GL_DEPTH_COMPONENT24_ARB, 0, 0); - //R_AttachFBOTextureDepth(tr.textureDepthImage->texnum); + FBO_CreateBuffer(tr.pshadowFbos[i], GL_DEPTH_COMPONENT24_ARB, 0, 0); + //R_AttachFBOTextureDepth(tr.textureDepthImage->texnum); - R_CheckFBO(tr.pshadowFbos[i]); + R_CheckFBO(tr.pshadowFbos[i]); + } } - for ( i = 0; i < 3; i++) + if (tr.sunShadowDepthImage[0]) { - tr.sunShadowFbo[i] = FBO_Create("_sunshadowmap", tr.sunShadowDepthImage[i]->width, tr.sunShadowDepthImage[i]->height); - FBO_Bind(tr.sunShadowFbo[i]); + for ( i = 0; i < 3; i++) + { + tr.sunShadowFbo[i] = FBO_Create("_sunshadowmap", tr.sunShadowDepthImage[i]->width, tr.sunShadowDepthImage[i]->height); + FBO_Bind(tr.sunShadowFbo[i]); - //FBO_CreateBuffer(tr.sunShadowFbo[i], GL_RGBA8, 0, 0); - //FBO_AttachTextureImage(tr.sunShadowImage, 0); - qglDrawBuffer(GL_NONE); - qglReadBuffer(GL_NONE); + //FBO_CreateBuffer(tr.sunShadowFbo[i], GL_RGBA8, 0, 0); + //FBO_AttachTextureImage(tr.sunShadowImage, 0); + qglDrawBuffer(GL_NONE); + qglReadBuffer(GL_NONE); - //FBO_CreateBuffer(tr.sunShadowFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0); - R_AttachFBOTextureDepth(tr.sunShadowDepthImage[i]->texnum); + //FBO_CreateBuffer(tr.sunShadowFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0); + R_AttachFBOTextureDepth(tr.sunShadowDepthImage[i]->texnum); - R_CheckFBO(tr.sunShadowFbo[i]); + R_CheckFBO(tr.sunShadowFbo[i]); + + } + + tr.screenShadowFbo = FBO_Create("_screenshadow", tr.screenShadowImage->width, tr.screenShadowImage->height); + FBO_Bind(tr.screenShadowFbo); + + FBO_AttachTextureImage(tr.screenShadowImage, 0); + + R_CheckFBO(tr.screenShadowFbo); } for (i = 0; i < 2; i++) @@ -526,22 +540,6 @@ void FBO_Init(void) R_CheckFBO(tr.targetLevelsFbo); } - if (r_softOverbright->integer) - { - //tr.screenScratchFbo = FBO_Create("_screenscratch", width, height); - tr.screenScratchFbo = FBO_Create("_screenscratch", tr.screenScratchImage->width, tr.screenScratchImage->height); - FBO_Bind(tr.screenScratchFbo); - - //FBO_CreateBuffer(tr.screenScratchFbo, format, 0, 0); - FBO_AttachTextureImage(tr.screenScratchImage, 0); - - // FIXME: hack: share zbuffer between render fbo and pre-screen fbo - //FBO_CreateBuffer(tr.screenScratchFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0); - R_AttachFBOTextureDepth(tr.renderDepthImage->texnum); - - R_CheckFBO(tr.screenScratchFbo); - } - for (i = 0; i < 2; i++) { tr.quarterFbo[i] = FBO_Create(va("_quarter%d", i), tr.quarterImage[i]->width, tr.quarterImage[i]->height); @@ -553,15 +551,6 @@ void FBO_Init(void) R_CheckFBO(tr.quarterFbo[i]); } - { - tr.screenShadowFbo = FBO_Create("_screenshadow", tr.screenShadowImage->width, tr.screenShadowImage->height); - FBO_Bind(tr.screenShadowFbo); - - FBO_AttachTextureImage(tr.screenShadowImage, 0); - - R_CheckFBO(tr.screenShadowFbo); - } - if (r_ssao->integer) { tr.hdrDepthFbo = FBO_Create("_hdrDepth", tr.hdrDepthImage->width, tr.hdrDepthImage->height); @@ -579,6 +568,7 @@ void FBO_Init(void) R_CheckFBO(tr.screenSsaoFbo); } + if (tr.renderCubeImage) { tr.renderCubeFbo = FBO_Create("_renderCubeFbo", tr.renderCubeImage->width, tr.renderCubeImage->height); FBO_Bind(tr.renderCubeFbo); @@ -667,16 +657,16 @@ void R_FBOList_f(void) // FIXME extern void RB_SetGL2D (void); -void FBO_BlitFromTexture(struct image_s *src, vec4i_t inSrcBox, vec2_t inSrcTexScale, FBO_t *dst, vec4i_t inDstBox, struct shaderProgram_s *shaderProgram, vec4_t inColor, int blend) +void FBO_BlitFromTexture(struct image_s *src, ivec4_t inSrcBox, vec2_t inSrcTexScale, FBO_t *dst, ivec4_t inDstBox, struct shaderProgram_s *shaderProgram, vec4_t inColor, int blend) { - vec4i_t dstBox, srcBox; + ivec4_t dstBox, srcBox; vec2_t srcTexScale; vec4_t color; vec4_t quadVerts[4]; vec2_t texCoords[4]; vec2_t invTexRes; FBO_t *oldFbo = glState.currentFBO; - matrix_t projection; + mat4_t projection; int width, height; if (!src) @@ -757,7 +747,7 @@ void FBO_BlitFromTexture(struct image_s *src, vec4i_t inSrcBox, vec2_t inSrcTexS qglViewport( 0, 0, width, height ); qglScissor( 0, 0, width, height ); - Matrix16Ortho(0, width, height, 0, 0, 1, projection); + Mat4Ortho(0, width, height, 0, 0, 1, projection); qglDisable( GL_CULL_FACE ); @@ -780,7 +770,7 @@ void FBO_BlitFromTexture(struct image_s *src, vec4i_t inSrcBox, vec2_t inSrcTexS GLSL_BindProgram(shaderProgram); - GLSL_SetUniformMatrix16(shaderProgram, UNIFORM_MODELVIEWPROJECTIONMATRIX, projection); + GLSL_SetUniformMat4(shaderProgram, UNIFORM_MODELVIEWPROJECTIONMATRIX, projection); GLSL_SetUniformVec4(shaderProgram, UNIFORM_COLOR, color); GLSL_SetUniformVec2(shaderProgram, UNIFORM_INVTEXRES, invTexRes); GLSL_SetUniformVec2(shaderProgram, UNIFORM_AUTOEXPOSUREMINMAX, tr.refdef.autoExposureMinMax); @@ -791,9 +781,9 @@ void FBO_BlitFromTexture(struct image_s *src, vec4i_t inSrcBox, vec2_t inSrcTexS FBO_Bind(oldFbo); } -void FBO_Blit(FBO_t *src, vec4i_t inSrcBox, vec2_t srcTexScale, FBO_t *dst, vec4i_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend) +void FBO_Blit(FBO_t *src, ivec4_t inSrcBox, vec2_t srcTexScale, FBO_t *dst, ivec4_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend) { - vec4i_t srcBox; + ivec4_t srcBox; if (!src) { @@ -817,9 +807,9 @@ void FBO_Blit(FBO_t *src, vec4i_t inSrcBox, vec2_t srcTexScale, FBO_t *dst, vec4 FBO_BlitFromTexture(src->colorImage[0], srcBox, srcTexScale, dst, dstBox, shaderProgram, color, blend | GLS_DEPTHTEST_DISABLE); } -void FBO_FastBlit(FBO_t *src, vec4i_t srcBox, FBO_t *dst, vec4i_t dstBox, int buffers, int filter) +void FBO_FastBlit(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int buffers, int filter) { - vec4i_t srcBoxFinal, dstBoxFinal; + ivec4_t srcBoxFinal, dstBoxFinal; GLuint srcFb, dstFb; if (!glRefConfig.framebufferBlit) diff --git a/code/renderergl2/tr_fbo.h b/code/renderergl2/tr_fbo.h index f0366251..b5ab18c1 100644 --- a/code/renderergl2/tr_fbo.h +++ b/code/renderergl2/tr_fbo.h @@ -56,9 +56,9 @@ void FBO_Bind(FBO_t *fbo); void FBO_Init(void); void FBO_Shutdown(void); -void FBO_BlitFromTexture(struct image_s *src, vec4i_t srcBox, vec2_t srcTexScale, FBO_t *dst, vec4i_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend); -void FBO_Blit(FBO_t *src, vec4i_t srcBox, vec2_t srcTexScale, FBO_t *dst, vec4i_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend); -void FBO_FastBlit(FBO_t *src, vec4i_t srcBox, FBO_t *dst, vec4i_t dstBox, int buffers, int filter); +void FBO_BlitFromTexture(struct image_s *src, ivec4_t srcBox, vec2_t srcTexScale, FBO_t *dst, ivec4_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend); +void FBO_Blit(FBO_t *src, ivec4_t srcBox, vec2_t srcTexScale, FBO_t *dst, ivec4_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend); +void FBO_FastBlit(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int buffers, int filter); #endif diff --git a/code/renderergl2/tr_flares.c b/code/renderergl2/tr_flares.c index bc016c1c..e1d46d54 100644 --- a/code/renderergl2/tr_flares.c +++ b/code/renderergl2/tr_flares.c @@ -86,6 +86,19 @@ flare_t *r_activeFlares, *r_inactiveFlares; int flareCoeff; +/* +================== +R_SetFlareCoeff +================== +*/ +static void R_SetFlareCoeff( void ) { + + if(r_flareCoeff->value == 0.0f) + flareCoeff = atof(FLARE_STDCOEFF); + else + flareCoeff = r_flareCoeff->value; +} + /* ================== R_ClearFlares @@ -102,6 +115,8 @@ void R_ClearFlares( void ) { r_flareStructs[i].next = r_inactiveFlares; r_inactiveFlares = &r_flareStructs[i]; } + + R_SetFlareCoeff(); } @@ -262,6 +277,7 @@ void RB_TestFlare( flare_t *f ) { qboolean visible; float fade; float screenZ; + FBO_t *oldFbo; backEnd.pc.c_flareTests++; @@ -269,9 +285,22 @@ void RB_TestFlare( flare_t *f ) { // don't bother with another sync glState.finishCalled = qfalse; + // if we're doing multisample rendering, read from the correct FBO + oldFbo = glState.currentFBO; + if (tr.msaaResolveFbo) + { + FBO_Bind(tr.msaaResolveFbo); + } + // read back the z buffer contents qglReadPixels( f->windowX, f->windowY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth ); + // if we're doing multisample rendering, switch to the old FBO + if (tr.msaaResolveFbo) + { + FBO_Bind(oldFbo); + } + screenZ = backEnd.viewParms.projectionMatrix[14] / ( ( 2*depth - 1 ) * backEnd.viewParms.projectionMatrix[11] - backEnd.viewParms.projectionMatrix[10] ); @@ -443,7 +472,7 @@ void RB_RenderFlares (void) { flare_t *f; flare_t **prev; qboolean draw; - matrix_t oldmodelview, oldprojection, matrix; + mat4_t oldmodelview, oldprojection, matrix; if ( !r_flares->integer ) { return; @@ -451,11 +480,7 @@ void RB_RenderFlares (void) { if(r_flareCoeff->modified) { - if(r_flareCoeff->value == 0.0f) - flareCoeff = atof(FLARE_STDCOEFF); - else - flareCoeff = r_flareCoeff->value; - + R_SetFlareCoeff(); r_flareCoeff->modified = qfalse; } @@ -505,11 +530,11 @@ void RB_RenderFlares (void) { qglDisable (GL_CLIP_PLANE0); } - Matrix16Copy(glState.projection, oldprojection); - Matrix16Copy(glState.modelview, oldmodelview); - Matrix16Identity(matrix); + Mat4Copy(glState.projection, oldprojection); + Mat4Copy(glState.modelview, oldmodelview); + Mat4Identity(matrix); GL_SetModelviewMatrix(matrix); - Matrix16Ortho( backEnd.viewParms.viewportX, backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth, + Mat4Ortho( backEnd.viewParms.viewportX, backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportY, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight, -99999, 99999, matrix ); GL_SetProjectionMatrix(matrix); diff --git a/code/renderergl2/tr_glsl.c b/code/renderergl2/tr_glsl.c index a2707cd0..2212c4fe 100644 --- a/code/renderergl2/tr_glsl.c +++ b/code/renderergl2/tr_glsl.c @@ -84,6 +84,8 @@ static uniformInfo_t uniformsInfo[] = { "u_ShadowMvp2", GLSL_MAT16 }, { "u_ShadowMvp3", GLSL_MAT16 }, + { "u_EnableTextures", GLSL_VEC4 }, + { "u_DiffuseTexMatrix", GLSL_VEC4 }, { "u_DiffuseTexOffTurb", GLSL_VEC4 }, { "u_Texture1Env", GLSL_INT }, @@ -106,6 +108,7 @@ static uniformInfo_t uniformsInfo[] = { "u_LightUp", GLSL_VEC3 }, { "u_LightRight", GLSL_VEC3 }, { "u_LightOrigin", GLSL_VEC4 }, + { "u_ModelLightDir", GLSL_VEC3 }, { "u_LightRadius", GLSL_FLOAT }, { "u_AmbientLight", GLSL_VEC3 }, { "u_DirectedLight", GLSL_VEC3 }, @@ -124,11 +127,12 @@ static uniformInfo_t uniformsInfo[] = { "u_VertexLerp" , GLSL_FLOAT }, { "u_MaterialInfo", GLSL_VEC2 }, - { "u_ViewInfo", GLSL_VEC4 }, - { "u_ViewOrigin", GLSL_VEC3 }, - { "u_ViewForward", GLSL_VEC3 }, - { "u_ViewLeft", GLSL_VEC3 }, - { "u_ViewUp", GLSL_VEC3 }, + { "u_ViewInfo", GLSL_VEC4 }, + { "u_ViewOrigin", GLSL_VEC3 }, + { "u_LocalViewOrigin", GLSL_VEC3 }, + { "u_ViewForward", GLSL_VEC3 }, + { "u_ViewLeft", GLSL_VEC3 }, + { "u_ViewUp", GLSL_VEC3 }, { "u_InvTexRes", GLSL_VEC2 }, { "u_AutoExposureMinMax", GLSL_VEC2 }, @@ -294,11 +298,9 @@ static void GLSL_GetShaderHeader( GLenum shaderType, const GLcharARB *extra, cha "#define alphaGen_t\n" "#define AGEN_LIGHTING_SPECULAR %i\n" "#define AGEN_PORTAL %i\n" - "#define AGEN_FRESNEL %i\n" "#endif\n", AGEN_LIGHTING_SPECULAR, - AGEN_PORTAL, - AGEN_FRESNEL)); + AGEN_PORTAL)); Q_strcat(dest, size, va("#ifndef texenv_t\n" @@ -526,9 +528,6 @@ static int GLSL_InitGPUShader2(shaderProgram_t * program, const char *name, int #ifdef USE_VERT_TANGENT_SPACE if(attribs & ATTR_TANGENT) qglBindAttribLocationARB(program->program, ATTR_INDEX_TANGENT, "attr_Tangent"); - - if(attribs & ATTR_BITANGENT) - qglBindAttribLocationARB(program->program, ATTR_INDEX_BITANGENT, "attr_Bitangent"); #endif if(attribs & ATTR_NORMAL) @@ -552,9 +551,6 @@ static int GLSL_InitGPUShader2(shaderProgram_t * program, const char *name, int #ifdef USE_VERT_TANGENT_SPACE if(attribs & ATTR_TANGENT2) qglBindAttribLocationARB(program->program, ATTR_INDEX_TANGENT2, "attr_Tangent2"); - - if(attribs & ATTR_BITANGENT2) - qglBindAttribLocationARB(program->program, ATTR_INDEX_BITANGENT2, "attr_Bitangent2"); #endif GLSL_LinkProgram(program->program); @@ -813,7 +809,7 @@ void GLSL_SetUniformFloat5(shaderProgram_t *program, int uniformNum, const vec5_ qglUniform1fvARB(uniforms[uniformNum], 5, v); } -void GLSL_SetUniformMatrix16(shaderProgram_t *program, int uniformNum, const matrix_t matrix) +void GLSL_SetUniformMat4(shaderProgram_t *program, int uniformNum, const mat4_t matrix) { GLint *uniforms = program->uniforms; vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); @@ -823,16 +819,16 @@ void GLSL_SetUniformMatrix16(shaderProgram_t *program, int uniformNum, const mat if (uniformsInfo[uniformNum].type != GLSL_MAT16) { - ri.Printf( PRINT_WARNING, "GLSL_SetUniformMatrix16: wrong type for uniform %i in program %s\n", uniformNum, program->name); + ri.Printf( PRINT_WARNING, "GLSL_SetUniformMat4: wrong type for uniform %i in program %s\n", uniformNum, program->name); return; } - if (Matrix16Compare(matrix, compare)) + if (Mat4Compare(matrix, compare)) { return; } - Matrix16Copy(matrix, compare); + Mat4Copy(matrix, compare); qglUniformMatrix4fvARB(uniforms[uniformNum], 1, GL_FALSE, matrix); } @@ -907,7 +903,7 @@ void GLSL_InitGPUShaders(void) if (i & GENERICDEF_USE_LIGHTMAP) Q_strcat(extradefines, 1024, "#define USE_LIGHTMAP\n"); - if (r_hdr->integer && !(glRefConfig.textureFloat && glRefConfig.halfFloatPixel)) + if (r_hdr->integer && !(glRefConfig.textureFloat && glRefConfig.halfFloatPixel && r_floatLightmap->integer)) Q_strcat(extradefines, 1024, "#define RGBM_LIGHTMAP\n"); if (!GLSL_InitGPUShader(&tr.genericShader[i], "generic", attribs, qtrue, extradefines, qtrue, fallbackShader_generic_vp, fallbackShader_generic_fp)) @@ -997,27 +993,19 @@ void GLSL_InitGPUShaders(void) for (i = 0; i < LIGHTDEF_COUNT; i++) { + int lightType = i & LIGHTDEF_LIGHTTYPE_MASK; + qboolean fastLight = !(r_normalMapping->integer || r_specularMapping->integer); + // skip impossible combos if ((i & LIGHTDEF_USE_PARALLAXMAP) && !r_parallaxMapping->integer) continue; - if ((i & LIGHTDEF_USE_DELUXEMAP) && !r_deluxeMapping->integer) + if (!lightType && (i & LIGHTDEF_USE_PARALLAXMAP)) continue; - if ((i & LIGHTDEF_USE_CUBEMAP) && !r_cubeMapping->integer) + if (!lightType && (i & LIGHTDEF_USE_SHADOWMAP)) continue; - if (!((i & LIGHTDEF_LIGHTTYPE_MASK) == LIGHTDEF_USE_LIGHTMAP) && (i & LIGHTDEF_USE_DELUXEMAP)) - continue; - - if (!(i & LIGHTDEF_LIGHTTYPE_MASK)) - { - if (i & LIGHTDEF_USE_SHADOWMAP) - continue; - if (i & LIGHTDEF_USE_CUBEMAP) - continue; - } - attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_COLOR | ATTR_NORMAL; extradefines[0] = '\0'; @@ -1026,30 +1014,30 @@ void GLSL_InitGPUShaders(void) Q_strcat(extradefines, 1024, va("#define r_deluxeSpecular %f\n", r_deluxeSpecular->value)); if (r_specularIsMetallic->value) - Q_strcat(extradefines, 1024, va("#define SPECULAR_IS_METALLIC\n")); + Q_strcat(extradefines, 1024, "#define SPECULAR_IS_METALLIC\n"); if (r_dlightMode->integer >= 2) Q_strcat(extradefines, 1024, "#define USE_SHADOWMAP\n"); if (1) - { Q_strcat(extradefines, 1024, "#define SWIZZLE_NORMALMAP\n"); - } - if (r_hdr->integer && !(glRefConfig.textureFloat && glRefConfig.halfFloatPixel)) + if (r_hdr->integer && !(glRefConfig.textureFloat && glRefConfig.halfFloatPixel && r_floatLightmap->integer)) Q_strcat(extradefines, 1024, "#define RGBM_LIGHTMAP\n"); - if (i & LIGHTDEF_LIGHTTYPE_MASK) + if (lightType) { Q_strcat(extradefines, 1024, "#define USE_LIGHT\n"); - if (r_normalMapping->integer == 0 && r_specularMapping->integer == 0) + if (fastLight) Q_strcat(extradefines, 1024, "#define USE_FAST_LIGHT\n"); - switch (i & LIGHTDEF_LIGHTTYPE_MASK) + switch (lightType) { case LIGHTDEF_USE_LIGHTMAP: Q_strcat(extradefines, 1024, "#define USE_LIGHTMAP\n"); + if (r_deluxeMapping->integer && !fastLight) + Q_strcat(extradefines, 1024, "#define USE_DELUXEMAP\n"); attribs |= ATTR_LIGHTCOORD | ATTR_LIGHTDIRECTION; break; case LIGHTDEF_USE_LIGHT_VECTOR: @@ -1062,62 +1050,59 @@ void GLSL_InitGPUShaders(void) default: break; } - } - if (r_normalMapping->integer) - { - Q_strcat(extradefines, 1024, "#define USE_NORMALMAP\n"); + if (r_normalMapping->integer) + { + Q_strcat(extradefines, 1024, "#define USE_NORMALMAP\n"); - if (r_normalMapping->integer == 2) - Q_strcat(extradefines, 1024, "#define USE_OREN_NAYAR\n"); + if (r_normalMapping->integer == 2) + Q_strcat(extradefines, 1024, "#define USE_OREN_NAYAR\n"); - if (r_normalMapping->integer == 3) - Q_strcat(extradefines, 1024, "#define USE_TRIACE_OREN_NAYAR\n"); + if (r_normalMapping->integer == 3) + Q_strcat(extradefines, 1024, "#define USE_TRIACE_OREN_NAYAR\n"); #ifdef USE_VERT_TANGENT_SPACE - Q_strcat(extradefines, 1024, "#define USE_VERT_TANGENT_SPACE\n"); - attribs |= ATTR_TANGENT | ATTR_BITANGENT; + Q_strcat(extradefines, 1024, "#define USE_VERT_TANGENT_SPACE\n"); + attribs |= ATTR_TANGENT; #endif - } - if (r_specularMapping->integer) - { - Q_strcat(extradefines, 1024, "#define USE_SPECULARMAP\n"); - - switch (r_specularMapping->integer) - { - case 1: - default: - Q_strcat(extradefines, 1024, "#define USE_BLINN\n"); - break; - - case 2: - Q_strcat(extradefines, 1024, "#define USE_BLINN_FRESNEL\n"); - break; - - case 3: - Q_strcat(extradefines, 1024, "#define USE_MCAULEY\n"); - break; - - case 4: - Q_strcat(extradefines, 1024, "#define USE_GOTANDA\n"); - break; - - case 5: - Q_strcat(extradefines, 1024, "#define USE_LAZAROV\n"); - break; + if ((i & LIGHTDEF_USE_PARALLAXMAP) && !(i & LIGHTDEF_ENTITY) && r_parallaxMapping->integer) + Q_strcat(extradefines, 1024, "#define USE_PARALLAXMAP\n"); } + + if (r_specularMapping->integer) + { + Q_strcat(extradefines, 1024, "#define USE_SPECULARMAP\n"); + + switch (r_specularMapping->integer) + { + case 1: + default: + Q_strcat(extradefines, 1024, "#define USE_BLINN\n"); + break; + + case 2: + Q_strcat(extradefines, 1024, "#define USE_BLINN_FRESNEL\n"); + break; + + case 3: + Q_strcat(extradefines, 1024, "#define USE_MCAULEY\n"); + break; + + case 4: + Q_strcat(extradefines, 1024, "#define USE_GOTANDA\n"); + break; + + case 5: + Q_strcat(extradefines, 1024, "#define USE_LAZAROV\n"); + break; + } + } + + if (r_cubeMapping->integer) + Q_strcat(extradefines, 1024, "#define USE_CUBEMAP\n"); } - if ((i & LIGHTDEF_USE_DELUXEMAP) && r_deluxeMapping->integer) - Q_strcat(extradefines, 1024, "#define USE_DELUXEMAP\n"); - - if ((i & LIGHTDEF_USE_PARALLAXMAP) && !(i & LIGHTDEF_ENTITY) && r_parallaxMapping->integer) - Q_strcat(extradefines, 1024, "#define USE_PARALLAXMAP\n"); - - if ((i & LIGHTDEF_USE_CUBEMAP)) - Q_strcat(extradefines, 1024, "#define USE_CUBEMAP\n"); - if (i & LIGHTDEF_USE_SHADOWMAP) { Q_strcat(extradefines, 1024, "#define USE_SHADOWMAP\n"); @@ -1142,7 +1127,7 @@ void GLSL_InitGPUShaders(void) #ifdef USE_VERT_TANGENT_SPACE if (r_normalMapping->integer) { - attribs |= ATTR_TANGENT2 | ATTR_BITANGENT2; + attribs |= ATTR_TANGENT2; } #endif } @@ -1409,12 +1394,10 @@ void GLSL_ShutdownGPUShaders(void) qglDisableVertexAttribArrayARB(ATTR_INDEX_NORMAL); #ifdef USE_VERT_TANGENT_SPACE qglDisableVertexAttribArrayARB(ATTR_INDEX_TANGENT); - qglDisableVertexAttribArrayARB(ATTR_INDEX_BITANGENT); #endif qglDisableVertexAttribArrayARB(ATTR_INDEX_NORMAL2); #ifdef USE_VERT_TANGENT_SPACE qglDisableVertexAttribArrayARB(ATTR_INDEX_TANGENT2); - qglDisableVertexAttribArrayARB(ATTR_INDEX_BITANGENT2); #endif qglDisableVertexAttribArrayARB(ATTR_INDEX_COLOR); qglDisableVertexAttribArrayARB(ATTR_INDEX_LIGHTDIRECTION); @@ -1574,20 +1557,6 @@ void GLSL_VertexAttribsState(uint32_t stateBits) qglDisableVertexAttribArrayARB(ATTR_INDEX_TANGENT); } } - - if(diff & ATTR_BITANGENT) - { - if(stateBits & ATTR_BITANGENT) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_BITANGENT )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_BITANGENT); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_BITANGENT )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_BITANGENT); - } - } #endif if(diff & ATTR_COLOR) @@ -1660,20 +1629,6 @@ void GLSL_VertexAttribsState(uint32_t stateBits) qglDisableVertexAttribArrayARB(ATTR_INDEX_TANGENT2); } } - - if(diff & ATTR_BITANGENT2) - { - if(stateBits & ATTR_BITANGENT2) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_BITANGENT2 )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_BITANGENT2); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_BITANGENT2 )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_BITANGENT2); - } - } #endif glState.vertexAttribsState = stateBits; @@ -1683,26 +1638,30 @@ void GLSL_VertexAttribPointers(uint32_t attribBits) { qboolean animated; int newFrame, oldFrame; + VBO_t *vbo = glState.currentVBO; - if(!glState.currentVBO) + if(!vbo) { ri.Error(ERR_FATAL, "GL_VertexAttribPointers: no VBO bound"); return; } // don't just call LogComment, or we will get a call to va() every frame! - GLimp_LogComment(va("--- GL_VertexAttribPointers( %s ) ---\n", glState.currentVBO->name)); + if(r_logFile->integer) + { + GLimp_LogComment(va("--- GL_VertexAttribPointers( %s ) ---\n", vbo->name)); + } - // position/normal/tangent/bitangent are always set in case of animation + // position/normal/tangent are always set in case of animation oldFrame = glState.vertexAttribsOldFrame; newFrame = glState.vertexAttribsNewFrame; - animated = (oldFrame != newFrame) && (glState.vertexAttribsInterpolation > 0.0f); + animated = glState.vertexAnimation; if((attribBits & ATTR_POSITION) && (!(glState.vertexAttribPointersSet & ATTR_POSITION) || animated)) { GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_POSITION )\n"); - qglVertexAttribPointerARB(ATTR_INDEX_POSITION, 3, GL_FLOAT, 0, glState.currentVBO->stride_xyz, BUFFER_OFFSET(glState.currentVBO->ofs_xyz + newFrame * glState.currentVBO->size_xyz)); + qglVertexAttribPointerARB(ATTR_INDEX_POSITION, 3, GL_FLOAT, 0, vbo->stride_xyz, BUFFER_OFFSET(vbo->ofs_xyz + newFrame * vbo->size_xyz)); glState.vertexAttribPointersSet |= ATTR_POSITION; } @@ -1710,7 +1669,7 @@ void GLSL_VertexAttribPointers(uint32_t attribBits) { GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_TEXCOORD )\n"); - qglVertexAttribPointerARB(ATTR_INDEX_TEXCOORD0, 2, GL_FLOAT, 0, glState.currentVBO->stride_st, BUFFER_OFFSET(glState.currentVBO->ofs_st)); + qglVertexAttribPointerARB(ATTR_INDEX_TEXCOORD0, 2, GL_FLOAT, 0, vbo->stride_st, BUFFER_OFFSET(vbo->ofs_st)); glState.vertexAttribPointersSet |= ATTR_TEXCOORD; } @@ -1718,7 +1677,7 @@ void GLSL_VertexAttribPointers(uint32_t attribBits) { GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_LIGHTCOORD )\n"); - qglVertexAttribPointerARB(ATTR_INDEX_TEXCOORD1, 2, GL_FLOAT, 0, glState.currentVBO->stride_lightmap, BUFFER_OFFSET(glState.currentVBO->ofs_lightmap)); + qglVertexAttribPointerARB(ATTR_INDEX_TEXCOORD1, 2, GL_FLOAT, 0, vbo->stride_lightmap, BUFFER_OFFSET(vbo->ofs_lightmap)); glState.vertexAttribPointersSet |= ATTR_LIGHTCOORD; } @@ -1726,7 +1685,7 @@ void GLSL_VertexAttribPointers(uint32_t attribBits) { GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_NORMAL )\n"); - qglVertexAttribPointerARB(ATTR_INDEX_NORMAL, 3, GL_FLOAT, 0, glState.currentVBO->stride_normal, BUFFER_OFFSET(glState.currentVBO->ofs_normal + newFrame * glState.currentVBO->size_normal)); + qglVertexAttribPointerARB(ATTR_INDEX_NORMAL, 4, glRefConfig.packedNormalDataType, GL_TRUE, vbo->stride_normal, BUFFER_OFFSET(vbo->ofs_normal + newFrame * vbo->size_normal)); glState.vertexAttribPointersSet |= ATTR_NORMAL; } @@ -1735,24 +1694,16 @@ void GLSL_VertexAttribPointers(uint32_t attribBits) { GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_TANGENT )\n"); - qglVertexAttribPointerARB(ATTR_INDEX_TANGENT, 3, GL_FLOAT, 0, glState.currentVBO->stride_tangent, BUFFER_OFFSET(glState.currentVBO->ofs_tangent + newFrame * glState.currentVBO->size_normal)); // FIXME + qglVertexAttribPointerARB(ATTR_INDEX_TANGENT, 4, glRefConfig.packedNormalDataType, GL_TRUE, vbo->stride_tangent, BUFFER_OFFSET(vbo->ofs_tangent + newFrame * vbo->size_normal)); // FIXME glState.vertexAttribPointersSet |= ATTR_TANGENT; } - - if((attribBits & ATTR_BITANGENT) && (!(glState.vertexAttribPointersSet & ATTR_BITANGENT) || animated)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_BITANGENT )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_BITANGENT, 3, GL_FLOAT, 0, glState.currentVBO->stride_bitangent, BUFFER_OFFSET(glState.currentVBO->ofs_bitangent + newFrame * glState.currentVBO->size_normal)); // FIXME - glState.vertexAttribPointersSet |= ATTR_BITANGENT; - } #endif if((attribBits & ATTR_COLOR) && !(glState.vertexAttribPointersSet & ATTR_COLOR)) { GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_COLOR )\n"); - qglVertexAttribPointerARB(ATTR_INDEX_COLOR, 4, GL_FLOAT, 0, glState.currentVBO->stride_vertexcolor, BUFFER_OFFSET(glState.currentVBO->ofs_vertexcolor)); + qglVertexAttribPointerARB(ATTR_INDEX_COLOR, 4, GL_FLOAT, 0, vbo->stride_vertexcolor, BUFFER_OFFSET(vbo->ofs_vertexcolor)); glState.vertexAttribPointersSet |= ATTR_COLOR; } @@ -1760,7 +1711,7 @@ void GLSL_VertexAttribPointers(uint32_t attribBits) { GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_LIGHTDIRECTION )\n"); - qglVertexAttribPointerARB(ATTR_INDEX_LIGHTDIRECTION, 3, GL_FLOAT, 0, glState.currentVBO->stride_lightdir, BUFFER_OFFSET(glState.currentVBO->ofs_lightdir)); + qglVertexAttribPointerARB(ATTR_INDEX_LIGHTDIRECTION, 4, glRefConfig.packedNormalDataType, GL_TRUE, vbo->stride_lightdir, BUFFER_OFFSET(vbo->ofs_lightdir)); glState.vertexAttribPointersSet |= ATTR_LIGHTDIRECTION; } @@ -1768,7 +1719,7 @@ void GLSL_VertexAttribPointers(uint32_t attribBits) { GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_POSITION2 )\n"); - qglVertexAttribPointerARB(ATTR_INDEX_POSITION2, 3, GL_FLOAT, 0, glState.currentVBO->stride_xyz, BUFFER_OFFSET(glState.currentVBO->ofs_xyz + oldFrame * glState.currentVBO->size_xyz)); + qglVertexAttribPointerARB(ATTR_INDEX_POSITION2, 3, GL_FLOAT, 0, vbo->stride_xyz, BUFFER_OFFSET(vbo->ofs_xyz + oldFrame * vbo->size_xyz)); glState.vertexAttribPointersSet |= ATTR_POSITION2; } @@ -1776,7 +1727,7 @@ void GLSL_VertexAttribPointers(uint32_t attribBits) { GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_NORMAL2 )\n"); - qglVertexAttribPointerARB(ATTR_INDEX_NORMAL2, 3, GL_FLOAT, 0, glState.currentVBO->stride_normal, BUFFER_OFFSET(glState.currentVBO->ofs_normal + oldFrame * glState.currentVBO->size_normal)); + qglVertexAttribPointerARB(ATTR_INDEX_NORMAL2, 4, glRefConfig.packedNormalDataType, GL_TRUE, vbo->stride_normal, BUFFER_OFFSET(vbo->ofs_normal + oldFrame * vbo->size_normal)); glState.vertexAttribPointersSet |= ATTR_NORMAL2; } @@ -1785,17 +1736,9 @@ void GLSL_VertexAttribPointers(uint32_t attribBits) { GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_TANGENT2 )\n"); - qglVertexAttribPointerARB(ATTR_INDEX_TANGENT2, 3, GL_FLOAT, 0, glState.currentVBO->stride_tangent, BUFFER_OFFSET(glState.currentVBO->ofs_tangent + oldFrame * glState.currentVBO->size_normal)); // FIXME + qglVertexAttribPointerARB(ATTR_INDEX_TANGENT2, 4, glRefConfig.packedNormalDataType, GL_TRUE, vbo->stride_tangent, BUFFER_OFFSET(vbo->ofs_tangent + oldFrame * vbo->size_normal)); // FIXME glState.vertexAttribPointersSet |= ATTR_TANGENT2; } - - if((attribBits & ATTR_BITANGENT2) && (!(glState.vertexAttribPointersSet & ATTR_BITANGENT2) || animated)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_BITANGENT2 )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_BITANGENT2, 3, GL_FLOAT, 0, glState.currentVBO->stride_bitangent, BUFFER_OFFSET(glState.currentVBO->ofs_bitangent + oldFrame * glState.currentVBO->size_normal)); // FIXME - glState.vertexAttribPointersSet |= ATTR_BITANGENT2; - } #endif } @@ -1829,7 +1772,6 @@ shaderProgram_t *GLSL_GetGenericShaderProgram(int stage) { case AGEN_LIGHTING_SPECULAR: case AGEN_PORTAL: - case AGEN_FRESNEL: shaderAttribs |= GENERICDEF_USE_RGBAGEN; break; default: @@ -1846,7 +1788,7 @@ shaderProgram_t *GLSL_GetGenericShaderProgram(int stage) shaderAttribs |= GENERICDEF_USE_DEFORM_VERTEXES; } - if (glState.vertexAttribsInterpolation > 0.0f && backEnd.currentEntity && backEnd.currentEntity != &tr.worldEntity) + if (glState.vertexAnimation) { shaderAttribs |= GENERICDEF_USE_VERTEX_ANIMATION; } diff --git a/code/renderergl2/tr_image.c b/code/renderergl2/tr_image.c index a80c975b..243d27df 100644 --- a/code/renderergl2/tr_image.c +++ b/code/renderergl2/tr_image.c @@ -2303,6 +2303,9 @@ image_t *R_CreateImage( const char *name, byte *pic, int width, int height, imgT qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); + if (image->flags & IMGFLAG_MIPMAP) + qglGenerateMipmapEXT(GL_TEXTURE_CUBE_MAP); + image->uploadWidth = width; image->uploadHeight = height; } @@ -2872,9 +2875,6 @@ void R_CreateBuiltinImages( void ) { Com_Memset( data, 255, sizeof( data ) ); tr.whiteImage = R_CreateImage("*white", (byte *)data, 8, 8, IMGTYPE_COLORALPHA, IMGFLAG_NONE, 0); - Com_Memset( data, 128, sizeof( data ) ); - tr.greyImage = R_CreateImage("*grey", (byte *)data, 8, 8, IMGTYPE_COLORALPHA, IMGFLAG_NONE, GL_RGBA8); - if (r_dlightMode->integer >= 2) { for( x = 0; x < MAX_DLIGHTS; x++) @@ -2922,7 +2922,7 @@ void R_CreateBuiltinImages( void ) { hdrFormat = GL_RGBA8; if (r_hdr->integer && glRefConfig.framebufferObject && glRefConfig.textureFloat) - hdrFormat = GL_RGB16F_ARB; + hdrFormat = GL_RGBA16F_ARB; rgbFormat = GL_RGBA8; @@ -2931,9 +2931,6 @@ void R_CreateBuiltinImages( void ) { if (r_drawSunRays->integer) tr.sunRaysImage = R_CreateImage("*sunRays", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, rgbFormat); - if (r_softOverbright->integer) - tr.screenScratchImage = R_CreateImage("*screenScratch", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, rgbFormat); - if (glRefConfig.framebufferObject) { tr.renderDepthImage = R_CreateImage("*renderdepth", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24_ARB); @@ -2944,7 +2941,7 @@ void R_CreateBuiltinImages( void ) { unsigned short sdata[4]; void *p; - if (hdrFormat == GL_RGB16F_ARB) + if (hdrFormat == GL_RGBA16F_ARB) { sdata[0] = FloatToHalf(0.0f); sdata[1] = FloatToHalf(0.45f); @@ -2975,25 +2972,34 @@ void R_CreateBuiltinImages( void ) { tr.quarterImage[x] = R_CreateImage(va("*quarter%d", x), NULL, width / 2, height / 2, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8); } - tr.screenShadowImage = R_CreateImage("*screenShadow", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8); - if (r_ssao->integer) { tr.screenSsaoImage = R_CreateImage("*screenSsao", NULL, width / 2, height / 2, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8); tr.hdrDepthImage = R_CreateImage("*hdrDepth", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_INTENSITY32F_ARB); } - for( x = 0; x < MAX_DRAWN_PSHADOWS; x++) + if (r_shadows->integer == 4) { - tr.pshadowMaps[x] = R_CreateImage(va("*shadowmap%i", x), NULL, PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8); + for( x = 0; x < MAX_DRAWN_PSHADOWS; x++) + { + tr.pshadowMaps[x] = R_CreateImage(va("*shadowmap%i", x), NULL, PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8); + } } - for ( x = 0; x < 3; x++) + if (r_sunlightMode->integer) { - tr.sunShadowDepthImage[x] = R_CreateImage(va("*sunshadowdepth%i", x), NULL, r_shadowMapSize->integer, r_shadowMapSize->integer, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24_ARB); + for ( x = 0; x < 3; x++) + { + tr.sunShadowDepthImage[x] = R_CreateImage(va("*sunshadowdepth%i", x), NULL, r_shadowMapSize->integer, r_shadowMapSize->integer, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24_ARB); + } + + tr.screenShadowImage = R_CreateImage("*screenShadow", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8); } - tr.renderCubeImage = R_CreateImage("*renderCube", NULL, CUBE_MAP_SIZE, CUBE_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE | IMGFLAG_MIPMAP | IMGFLAG_CUBEMAP, rgbFormat); + if (r_cubeMapping->integer) + { + tr.renderCubeImage = R_CreateImage("*renderCube", NULL, CUBE_MAP_SIZE, CUBE_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE | IMGFLAG_MIPMAP | IMGFLAG_CUBEMAP, rgbFormat); + } } } diff --git a/code/renderergl2/tr_init.c b/code/renderergl2/tr_init.c index b9e5fb58..84bbeba2 100644 --- a/code/renderergl2/tr_init.c +++ b/code/renderergl2/tr_init.c @@ -100,6 +100,8 @@ cvar_t *r_ext_framebuffer_object; cvar_t *r_ext_texture_float; cvar_t *r_arb_half_float_pixel; cvar_t *r_ext_framebuffer_multisample; +cvar_t *r_arb_seamless_cube_map; +cvar_t *r_arb_vertex_type_2_10_10_10_rev; cvar_t *r_mergeMultidraws; cvar_t *r_mergeLeafSurfaces; @@ -109,6 +111,7 @@ cvar_t *r_cameraExposure; cvar_t *r_softOverbright; cvar_t *r_hdr; +cvar_t *r_floatLightmap; cvar_t *r_postProcess; cvar_t *r_toneMap; @@ -156,6 +159,7 @@ cvar_t *r_shadowMapSize; cvar_t *r_shadowCascadeZNear; cvar_t *r_shadowCascadeZFar; cvar_t *r_shadowCascadeZBias; +cvar_t *r_ignoreDstAlpha; cvar_t *r_ignoreGLErrors; cvar_t *r_logFile; @@ -950,16 +954,6 @@ void GL_SetDefaultState( void ) qglDisable( GL_CULL_FACE ); qglDisable( GL_BLEND ); - qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); - qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); - qglClearDepth( 1.0 ); - - qglDrawBuffer( GL_FRONT ); - qglClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_ACCUM_BUFFER_BIT|GL_STENCIL_BUFFER_BIT ); - - qglDrawBuffer( GL_BACK ); - qglClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_ACCUM_BUFFER_BIT|GL_STENCIL_BUFFER_BIT ); - if (glRefConfig.seamlessCubeMap) qglEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); } @@ -1133,6 +1127,8 @@ void R_Register( void ) r_ext_texture_float = ri.Cvar_Get( "r_ext_texture_float", "1", CVAR_ARCHIVE | CVAR_LATCH); r_arb_half_float_pixel = ri.Cvar_Get( "r_arb_half_float_pixel", "1", CVAR_ARCHIVE | CVAR_LATCH); r_ext_framebuffer_multisample = ri.Cvar_Get( "r_ext_framebuffer_multisample", "0", CVAR_ARCHIVE | CVAR_LATCH); + r_arb_seamless_cube_map = ri.Cvar_Get( "r_arb_seamless_cube_map", "0", CVAR_ARCHIVE | CVAR_LATCH); + r_arb_vertex_type_2_10_10_10_rev = ri.Cvar_Get( "r_arb_vertex_type_2_10_10_10_rev", "1", CVAR_ARCHIVE | CVAR_LATCH); r_ext_texture_filter_anisotropic = ri.Cvar_Get( "r_ext_texture_filter_anisotropic", "0", CVAR_ARCHIVE | CVAR_LATCH ); @@ -1153,7 +1149,7 @@ void R_Register( void ) r_ignorehwgamma = ri.Cvar_Get( "r_ignorehwgamma", "0", CVAR_ARCHIVE | CVAR_LATCH); r_mode = ri.Cvar_Get( "r_mode", "-2", CVAR_ARCHIVE | CVAR_LATCH ); r_fullscreen = ri.Cvar_Get( "r_fullscreen", "1", CVAR_ARCHIVE ); - r_noborder = ri.Cvar_Get("r_noborder", "0", CVAR_ARCHIVE); + r_noborder = ri.Cvar_Get("r_noborder", "0", CVAR_ARCHIVE | CVAR_LATCH); r_customwidth = ri.Cvar_Get( "r_customwidth", "1600", CVAR_ARCHIVE | CVAR_LATCH ); r_customheight = ri.Cvar_Get( "r_customheight", "1024", CVAR_ARCHIVE | CVAR_LATCH ); r_customPixelAspect = ri.Cvar_Get( "r_customPixelAspect", "1", CVAR_ARCHIVE | CVAR_LATCH ); @@ -1168,6 +1164,7 @@ void R_Register( void ) r_softOverbright = ri.Cvar_Get( "r_softOverbright", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_hdr = ri.Cvar_Get( "r_hdr", "1", CVAR_ARCHIVE | CVAR_LATCH ); + r_floatLightmap = ri.Cvar_Get( "r_floatLightmap", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_postProcess = ri.Cvar_Get( "r_postProcess", "1", CVAR_ARCHIVE ); r_toneMap = ri.Cvar_Get( "r_toneMap", "1", CVAR_ARCHIVE | CVAR_LATCH ); @@ -1219,6 +1216,7 @@ void R_Register( void ) r_shadowCascadeZNear = ri.Cvar_Get( "r_shadowCascadeZNear", "4", CVAR_ARCHIVE | CVAR_LATCH ); r_shadowCascadeZFar = ri.Cvar_Get( "r_shadowCascadeZFar", "3072", CVAR_ARCHIVE | CVAR_LATCH ); r_shadowCascadeZBias = ri.Cvar_Get( "r_shadowCascadeZBias", "-320", CVAR_ARCHIVE | CVAR_LATCH ); + r_ignoreDstAlpha = ri.Cvar_Get( "r_ignoreDstAlpha", "1", CVAR_ARCHIVE | CVAR_LATCH ); // // temporary latched variables that can only change over a restart diff --git a/code/renderergl2/tr_light.c b/code/renderergl2/tr_light.c index ee7dad92..3d1d1f24 100644 --- a/code/renderergl2/tr_light.c +++ b/code/renderergl2/tr_light.c @@ -94,12 +94,17 @@ void R_DlightBmodel( bmodel_t *bmodel ) { for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) { surf = tr.world->surfaces + bmodel->firstSurface + i; - if ( *surf->data == SF_FACE ) { - ((srfSurfaceFace_t *)surf->data)->dlightBits = mask; - } else if ( *surf->data == SF_GRID ) { - ((srfGridMesh_t *)surf->data)->dlightBits = mask; - } else if ( *surf->data == SF_TRIANGLES ) { - ((srfTriangles_t *)surf->data)->dlightBits = mask; + switch(*surf->data) + { + case SF_FACE: + case SF_GRID: + case SF_TRIANGLES: + case SF_VBO_MESH: + ((srfBspSurface_t *)surf->data)->dlightBits = mask; + break; + + default: + break; } } } @@ -403,8 +408,11 @@ void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) { ((byte *)&ent->ambientLightInt)[3] = 0xff; // transform the direction to local space - // no need to do this if using lightentity glsl shader VectorNormalize( lightDir ); + ent->modelLightDir[0] = DotProduct( lightDir, ent->e.axis[0] ); + ent->modelLightDir[1] = DotProduct( lightDir, ent->e.axis[1] ); + ent->modelLightDir[2] = DotProduct( lightDir, ent->e.axis[2] ); + VectorCopy(lightDir, ent->lightDir); } diff --git a/code/renderergl2/tr_local.h b/code/renderergl2/tr_local.h index 838845b4..0fbabd20 100644 --- a/code/renderergl2/tr_local.h +++ b/code/renderergl2/tr_local.h @@ -47,10 +47,6 @@ typedef unsigned int glIndex_t; #define SHADERNUM_BITS 14 #define MAX_SHADERS (1<st[0] + 10.0f; t = dv[i]->st[1]; @@ -475,12 +477,16 @@ qboolean R_CalcTangentVectors(srfVert_t * dv[3]) bary[1] = ((dv[2]->st[0] - s) * (dv[0]->st[1] - t) - (dv[0]->st[0] - s) * (dv[2]->st[1] - t)) / bb; bary[2] = ((dv[0]->st[0] - s) * (dv[1]->st[1] - t) - (dv[1]->st[0] - s) * (dv[0]->st[1] - t)) / bb; - dv[i]->bitangent[0] = bary[0] * dv[0]->xyz[0] + bary[1] * dv[1]->xyz[0] + bary[2] * dv[2]->xyz[0]; - dv[i]->bitangent[1] = bary[0] * dv[0]->xyz[1] + bary[1] * dv[1]->xyz[1] + bary[2] * dv[2]->xyz[1]; - dv[i]->bitangent[2] = bary[0] * dv[0]->xyz[2] + bary[1] * dv[1]->xyz[2] + bary[2] * dv[2]->xyz[2]; + bitangent[0] = bary[0] * dv[0]->xyz[0] + bary[1] * dv[1]->xyz[0] + bary[2] * dv[2]->xyz[0]; + bitangent[1] = bary[0] * dv[0]->xyz[1] + bary[1] * dv[1]->xyz[1] + bary[2] * dv[2]->xyz[1]; + bitangent[2] = bary[0] * dv[0]->xyz[2] + bary[1] * dv[1]->xyz[2] + bary[2] * dv[2]->xyz[2]; - VectorSubtract(dv[i]->bitangent, dv[i]->xyz, dv[i]->bitangent); - VectorNormalize(dv[i]->bitangent); + VectorSubtract(bitangent, dv[i]->xyz, bitangent); + VectorNormalize(bitangent); + + // store bitangent handedness + CrossProduct(dv[i]->normal, dv[i]->tangent, nxt); + dv[i]->tangent[3] = (DotProduct(nxt, bitangent) < 0.0f) ? -1.0f : 1.0f; // debug code //% Sys_FPrintf( SYS_VRB, "%d S: (%f %f %f) T: (%f %f %f)\n", i, @@ -492,99 +498,6 @@ qboolean R_CalcTangentVectors(srfVert_t * dv[3]) #endif -/* -================= -R_FindSurfaceTriangleWithEdge - -Recoded from Q2E -================= -*/ -static int R_FindSurfaceTriangleWithEdge(int numTriangles, srfTriangle_t * triangles, int start, int end, int ignore) -{ - srfTriangle_t *tri; - int count, match; - int i; - - count = 0; - match = -1; - - for(i = 0, tri = triangles; i < numTriangles; i++, tri++) - { - if((tri->indexes[0] == start && tri->indexes[1] == end) || - (tri->indexes[1] == start && tri->indexes[2] == end) || (tri->indexes[2] == start && tri->indexes[0] == end)) - { - if(i != ignore) - { - match = i; - } - - count++; - } - else if((tri->indexes[1] == start && tri->indexes[0] == end) || - (tri->indexes[2] == start && tri->indexes[1] == end) || (tri->indexes[0] == start && tri->indexes[2] == end)) - { - count++; - } - } - - // detect edges shared by three triangles and make them seams - if(count > 2) - { - match = -1; - } - - return match; -} - - -/* -================= -R_CalcSurfaceTriangleNeighbors - -Recoded from Q2E -================= -*/ -void R_CalcSurfaceTriangleNeighbors(int numTriangles, srfTriangle_t * triangles) -{ - int i; - srfTriangle_t *tri; - - for(i = 0, tri = triangles; i < numTriangles; i++, tri++) - { - tri->neighbors[0] = R_FindSurfaceTriangleWithEdge(numTriangles, triangles, tri->indexes[1], tri->indexes[0], i); - tri->neighbors[1] = R_FindSurfaceTriangleWithEdge(numTriangles, triangles, tri->indexes[2], tri->indexes[1], i); - tri->neighbors[2] = R_FindSurfaceTriangleWithEdge(numTriangles, triangles, tri->indexes[0], tri->indexes[2], i); - } -} - -/* -================= -R_CalcSurfaceTrianglePlanes -================= -*/ -void R_CalcSurfaceTrianglePlanes(int numTriangles, srfTriangle_t * triangles, srfVert_t * verts) -{ - int i; - srfTriangle_t *tri; - - for(i = 0, tri = triangles; i < numTriangles; i++, tri++) - { - float *v1, *v2, *v3; - vec3_t d1, d2; - - v1 = verts[tri->indexes[0]].xyz; - v2 = verts[tri->indexes[1]].xyz; - v3 = verts[tri->indexes[2]].xyz; - - VectorSubtract(v2, v1, d1); - VectorSubtract(v3, v1, d2); - - CrossProduct(d2, d1, tri->plane); - tri->plane[3] = DotProduct(tri->plane, v1); - } -} - - /* ================= R_CullLocalBox @@ -927,7 +840,7 @@ void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms, glMatrix[11] = 0; glMatrix[15] = 1; - Matrix16Copy(glMatrix, or->transformMatrix); + Mat4Copy(glMatrix, or->transformMatrix); myGlMultMatrix( glMatrix, viewParms->world.modelMatrix, or->modelMatrix ); // calculate the viewer origin in the model's space @@ -1365,7 +1278,7 @@ R_PlaneForSurface ============= */ void R_PlaneForSurface (surfaceType_t *surfType, cplane_t *plane) { - srfTriangles_t *tri; + srfBspSurface_t *tri; srfPoly_t *poly; srfVert_t *v1, *v2, *v3; vec4_t plane4; @@ -1377,13 +1290,13 @@ void R_PlaneForSurface (surfaceType_t *surfType, cplane_t *plane) { } switch (*surfType) { case SF_FACE: - *plane = ((srfSurfaceFace_t *)surfType)->plane; + *plane = ((srfBspSurface_t *)surfType)->cullPlane; return; case SF_TRIANGLES: - tri = (srfTriangles_t *)surfType; - v1 = tri->verts + tri->triangles[0].indexes[0]; - v2 = tri->verts + tri->triangles[0].indexes[1]; - v3 = tri->verts + tri->triangles[0].indexes[2]; + tri = (srfBspSurface_t *)surfType; + v1 = tri->verts + tri->indexes[0]; + v2 = tri->verts + tri->indexes[1]; + v3 = tri->verts + tri->indexes[2]; PlaneFromPoints( plane4, v1->xyz, v2->xyz, v3->xyz ); VectorCopy( plane4, plane->normal ); plane->dist = plane4[3]; @@ -1649,7 +1562,8 @@ static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128 for ( i = 0; i < tess.numIndexes; i += 3 ) { - vec3_t normal; + vec3_t normal, tNormal; + float len; VectorSubtract( tess.xyz[tess.indexes[i]], tr.viewParms.or.origin, normal ); @@ -1660,7 +1574,9 @@ static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128 shortest = len; } - if ( DotProduct( normal, tess.normal[tess.indexes[i]] ) >= 0 ) + R_VboUnpackNormal(tNormal, tess.normal[tess.indexes[i]]); + + if ( DotProduct( normal, tNormal ) >= 0 ) { numTriangles--; } @@ -1997,9 +1913,6 @@ static void R_AddEntitySurface (int entityNum) case MOD_MESH: R_AddMD3Surfaces( ent ); break; - case MOD_MD4: - R_AddAnimSurfaces( ent ); - break; case MOD_MDR: R_MDRAddAnimSurfaces( ent ); break; @@ -2286,12 +2199,6 @@ void R_RenderPshadowMaps(const refdef_t *fd) } break; - case MOD_MD4: - { - // FIXME: actually calculate the radius and bounds, this is a horrible hack - radius = r_pshadowDist->value / 2.0f; - } - break; case MOD_MDR: { // FIXME: never actually tested this @@ -2716,7 +2623,7 @@ void R_RenderSunShadowMaps(const refdef_t *fd, int level) // Create bounds for light projection using slice of view projection { - matrix_t lightViewMatrix; + mat4_t lightViewMatrix; vec4_t point, base, lightViewPoint; float lx, ly; @@ -2724,7 +2631,7 @@ void R_RenderSunShadowMaps(const refdef_t *fd, int level) point[3] = 1; lightViewPoint[3] = 1; - Matrix16View(lightViewAxis, lightOrigin, lightViewMatrix); + Mat4View(lightViewAxis, lightOrigin, lightViewMatrix); ClearBounds(lightviewBounds[0], lightviewBounds[1]); @@ -2735,22 +2642,22 @@ void R_RenderSunShadowMaps(const refdef_t *fd, int level) VectorMA(base, lx, fd->viewaxis[1], point); VectorMA(point, ly, fd->viewaxis[2], point); - Matrix16Transform(lightViewMatrix, point, lightViewPoint); + Mat4Transform(lightViewMatrix, point, lightViewPoint); AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); VectorMA(base, -lx, fd->viewaxis[1], point); VectorMA(point, ly, fd->viewaxis[2], point); - Matrix16Transform(lightViewMatrix, point, lightViewPoint); + Mat4Transform(lightViewMatrix, point, lightViewPoint); AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); VectorMA(base, lx, fd->viewaxis[1], point); VectorMA(point, -ly, fd->viewaxis[2], point); - Matrix16Transform(lightViewMatrix, point, lightViewPoint); + Mat4Transform(lightViewMatrix, point, lightViewPoint); AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); VectorMA(base, -lx, fd->viewaxis[1], point); VectorMA(point, -ly, fd->viewaxis[2], point); - Matrix16Transform(lightViewMatrix, point, lightViewPoint); + Mat4Transform(lightViewMatrix, point, lightViewPoint); AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); @@ -2761,22 +2668,22 @@ void R_RenderSunShadowMaps(const refdef_t *fd, int level) VectorMA(base, lx, fd->viewaxis[1], point); VectorMA(point, ly, fd->viewaxis[2], point); - Matrix16Transform(lightViewMatrix, point, lightViewPoint); + Mat4Transform(lightViewMatrix, point, lightViewPoint); AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); VectorMA(base, -lx, fd->viewaxis[1], point); VectorMA(point, ly, fd->viewaxis[2], point); - Matrix16Transform(lightViewMatrix, point, lightViewPoint); + Mat4Transform(lightViewMatrix, point, lightViewPoint); AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); VectorMA(base, lx, fd->viewaxis[1], point); VectorMA(point, -ly, fd->viewaxis[2], point); - Matrix16Transform(lightViewMatrix, point, lightViewPoint); + Mat4Transform(lightViewMatrix, point, lightViewPoint); AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); VectorMA(base, -lx, fd->viewaxis[1], point); VectorMA(point, -ly, fd->viewaxis[2], point); - Matrix16Transform(lightViewMatrix, point, lightViewPoint); + Mat4Transform(lightViewMatrix, point, lightViewPoint); AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); if (!glRefConfig.depthClamp) @@ -2874,7 +2781,7 @@ void R_RenderSunShadowMaps(const refdef_t *fd, int level) R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf ); } - Matrix16Multiply(tr.viewParms.projectionMatrix, tr.viewParms.world.modelMatrix, tr.refdef.sunShadowMvp[level]); + Mat4Multiply(tr.viewParms.projectionMatrix, tr.viewParms.world.modelMatrix, tr.refdef.sunShadowMvp[level]); } } @@ -2944,7 +2851,7 @@ void R_RenderCubemapSide( int cubemapIndex, int cubemapSide, qboolean subscene ) // FIXME: sun shadows aren't rendered correctly in cubemaps // fix involves changing r_FBufScale to fit smaller cubemap image size, or rendering cubemap to framebuffer first - if(0) //(glRefConfig.framebufferObject && (r_forceSun->integer || tr.sunShadows)) + if(0) //(glRefConfig.framebufferObject && r_sunlightMode->integer && (r_forceSun->integer || tr.sunShadows)) { R_RenderSunShadowMaps(&refdef, 0); R_RenderSunShadowMaps(&refdef, 1); diff --git a/code/renderergl2/tr_marks.c b/code/renderergl2/tr_marks.c index 4d070565..830d4d29 100644 --- a/code/renderergl2/tr_marks.c +++ b/code/renderergl2/tr_marks.c @@ -268,8 +268,8 @@ int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projectio vec3_t clipPoints[2][MAX_VERTS_ON_POLY]; int numClipPoints; float *v; - srfGridMesh_t *cv; - srfTriangle_t *tri; + srfBspSurface_t *cv; + glIndex_t *tri; srfVert_t *dv; vec3_t normal; vec3_t projectionDir; @@ -327,7 +327,7 @@ int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projectio if (*surfaces[i] == SF_GRID) { - cv = (srfGridMesh_t *) surfaces[i]; + cv = (srfBspSurface_t *) surfaces[i]; for ( m = 0 ; m < cv->height - 1 ; m++ ) { for ( n = 0 ; n < cv->width - 1 ; n++ ) { // We triangulate the grid and chop all triangles within @@ -407,19 +407,19 @@ int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projectio } else if (*surfaces[i] == SF_FACE) { - srfSurfaceFace_t *surf = ( srfSurfaceFace_t * ) surfaces[i]; + srfBspSurface_t *surf = ( srfBspSurface_t * ) surfaces[i]; // check the normal of this face - if (DotProduct(surf->plane.normal, projectionDir) > -0.5) { + if (DotProduct(surf->cullPlane.normal, projectionDir) > -0.5) { continue; } - for(k = 0, tri = surf->triangles; k < surf->numTriangles; k++, tri++) + for(k = 0, tri = surf->indexes; k < surf->numIndexes; k += 3, tri += 3) { for(j = 0; j < 3; j++) { - v = surf->verts[tri->indexes[j]].xyz; - VectorMA(v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j]); + v = surf->verts[tri[j]].xyz; + VectorMA(v, MARKER_OFFSET, surf->cullPlane.normal, clipPoints[0][j]); } // add the fragments of this face @@ -435,14 +435,14 @@ int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projectio } else if(*surfaces[i] == SF_TRIANGLES && r_marksOnTriangleMeshes->integer) { - srfTriangles_t *surf = (srfTriangles_t *) surfaces[i]; + srfBspSurface_t *surf = (srfBspSurface_t *) surfaces[i]; - for(k = 0, tri = surf->triangles; k < surf->numTriangles; k++, tri++) + for(k = 0, tri = surf->indexes; k < surf->numIndexes; k += 3, tri += 3) { for(j = 0; j < 3; j++) { - v = surf->verts[tri->indexes[j]].xyz; - VectorMA(v, MARKER_OFFSET, surf->verts[tri->indexes[j]].normal, clipPoints[0][j]); + v = surf->verts[tri[j]].xyz; + VectorMA(v, MARKER_OFFSET, surf->verts[tri[j]].normal, clipPoints[0][j]); } // add the fragments of this face diff --git a/code/renderergl2/tr_model.c b/code/renderergl2/tr_model.c index 8feeab0e..c0dbeaa2 100644 --- a/code/renderergl2/tr_model.c +++ b/code/renderergl2/tr_model.c @@ -26,7 +26,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define LL(x) x=LittleLong(x) static qboolean R_LoadMD3(model_t *mod, int lod, void *buffer, int bufferSize, const char *modName); -static qboolean R_LoadMD4(model_t *mod, void *buffer, const char *name ); static qboolean R_LoadMDR(model_t *mod, void *buffer, int filesize, const char *name ); /* @@ -73,15 +72,10 @@ qhandle_t R_RegisterMD3(const char *name, model_t *mod) continue; ident = LittleLong(* (unsigned *) buf.u); - if (ident == MD4_IDENT) - loaded = R_LoadMD4(mod, buf.u, name); + if (ident == MD3_IDENT) + loaded = R_LoadMD3(mod, lod, buf.u, size, name); else - { - if (ident == MD3_IDENT) - loaded = R_LoadMD3(mod, lod, buf.u, size, name); - else - ri.Printf(PRINT_WARNING,"R_RegisterMD3: unknown fileid for %s\n", name); - } + ri.Printf(PRINT_WARNING,"R_RegisterMD3: unknown fileid for %s\n", name); ri.FS_FreeFile(buf.v); @@ -201,7 +195,6 @@ static modelExtToLoaderMap_t modelLoaders[ ] = { { "iqm", R_RegisterIQM }, { "mdr", R_RegisterMDR }, - { "md4", R_RegisterMD3 }, { "md3", R_RegisterMD3 } }; @@ -394,7 +387,7 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, mdvFrame_t *frame; mdvSurface_t *surf;//, *surface; int *shaderIndex; - srfTriangle_t *tri; + glIndex_t *tri; mdvVertex_t *v; mdvSt_t *st; mdvTag_t *tag; @@ -551,19 +544,17 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, } // swap all the triangles - surf->numTriangles = md3Surf->numTriangles; - surf->triangles = tri = ri.Hunk_Alloc(sizeof(*tri) * md3Surf->numTriangles, h_low); + surf->numIndexes = md3Surf->numTriangles * 3; + surf->indexes = tri = ri.Hunk_Alloc(sizeof(*tri) * 3 * md3Surf->numTriangles, h_low); md3Tri = (md3Triangle_t *) ((byte *) md3Surf + md3Surf->ofsTriangles); - for(j = 0; j < md3Surf->numTriangles; j++, tri++, md3Tri++) + for(j = 0; j < md3Surf->numTriangles; j++, tri += 3, md3Tri++) { - tri->indexes[0] = LittleLong(md3Tri->indexes[0]); - tri->indexes[1] = LittleLong(md3Tri->indexes[1]); - tri->indexes[2] = LittleLong(md3Tri->indexes[2]); + tri[0] = LittleLong(md3Tri->indexes[0]); + tri[1] = LittleLong(md3Tri->indexes[1]); + tri[2] = LittleLong(md3Tri->indexes[2]); } - R_CalcSurfaceTriangleNeighbors(surf->numTriangles, surf->triangles); - // swap all the XyzNormals surf->numVerts = md3Surf->numVerts; surf->verts = v = ri.Hunk_Alloc(sizeof(*v) * (md3Surf->numVerts * md3Surf->numFrames), h_low); @@ -625,15 +616,15 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, for(f = 0; f < mdvModel->numFrames; f++) { - for(j = 0, tri = surf->triangles; j < surf->numTriangles; j++, tri++) + for(j = 0, tri = surf->indexes; j < surf->numIndexes; j += 3, tri += 3) { - v0 = surf->verts[surf->numVerts * f + tri->indexes[0]].xyz; - v1 = surf->verts[surf->numVerts * f + tri->indexes[1]].xyz; - v2 = surf->verts[surf->numVerts * f + tri->indexes[2]].xyz; + v0 = surf->verts[surf->numVerts * f + tri[0]].xyz; + v1 = surf->verts[surf->numVerts * f + tri[1]].xyz; + v2 = surf->verts[surf->numVerts * f + tri[2]].xyz; - t0 = surf->st[tri->indexes[0]].st; - t1 = surf->st[tri->indexes[1]].st; - t2 = surf->st[tri->indexes[2]].st; + t0 = surf->st[tri[0]].st; + t1 = surf->st[tri[1]].st; + t2 = surf->st[tri[2]].st; if (!r_recalcMD3Normals->integer) VectorCopy(v->normal, normal); @@ -651,15 +642,15 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, { float *v; - v = surf->verts[surf->numVerts * f + tri->indexes[k]].tangent; + v = surf->verts[surf->numVerts * f + tri[k]].tangent; VectorAdd(v, tangent, v); - v = surf->verts[surf->numVerts * f + tri->indexes[k]].bitangent; + v = surf->verts[surf->numVerts * f + tri[k]].bitangent; VectorAdd(v, bitangent, v); if (r_recalcMD3Normals->integer) { - v = surf->verts[surf->numVerts * f + tri->indexes[k]].normal; + v = surf->verts[surf->numVerts * f + tri[k]].normal; VectorAdd(v, normal, v); } } @@ -691,11 +682,10 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, for (i = 0; i < mdvModel->numSurfaces; i++, vboSurf++, surf++) { vec3_t *verts; - vec3_t *normals; vec2_t *texcoords; + uint32_t *normals; #ifdef USE_VERT_TANGENT_SPACE - vec3_t *tangents; - vec3_t *bitangents; + uint32_t *tangents; #endif byte *data; @@ -703,7 +693,7 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, int ofs_xyz, ofs_normal, ofs_st; #ifdef USE_VERT_TANGENT_SPACE - int ofs_tangent, ofs_bitangent; + int ofs_tangent; #endif dataSize = 0; @@ -717,9 +707,6 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, #ifdef USE_VERT_TANGENT_SPACE ofs_tangent = dataSize; dataSize += surf->numVerts * mdvModel->numFrames * sizeof(*tangents); - - ofs_bitangent = dataSize; - dataSize += surf->numVerts * mdvModel->numFrames * sizeof(*bitangents); #endif ofs_st = dataSize; @@ -731,18 +718,24 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, normals = (void *)(data + ofs_normal); #ifdef USE_VERT_TANGENT_SPACE tangents = (void *)(data + ofs_tangent); - bitangents = (void *)(data + ofs_bitangent); #endif texcoords = (void *)(data + ofs_st); v = surf->verts; for ( j = 0; j < surf->numVerts * mdvModel->numFrames ; j++, v++ ) { + vec3_t nxt; + vec4_t tangent; + VectorCopy(v->xyz, verts[j]); - VectorCopy(v->normal, normals[j]); + + normals[j] = R_VboPackNormal(v->normal); #ifdef USE_VERT_TANGENT_SPACE - VectorCopy(v->tangent, tangents[j]); - VectorCopy(v->bitangent, bitangents[j]); + CrossProduct(v->normal, v->tangent, nxt); + VectorCopy(v->tangent, tangent); + tangent[3] = (DotProduct(nxt, v->bitangent) < 0.0f) ? -1.0f : 1.0f; + + tangents[j] = R_VboPackTangent(tangent); #endif } @@ -755,7 +748,7 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, vboSurf->surfaceType = SF_VBO_MDVMESH; vboSurf->mdvModel = mdvModel; vboSurf->mdvSurface = surf; - vboSurf->numIndexes = surf->numTriangles * 3; + vboSurf->numIndexes = surf->numIndexes; vboSurf->numVerts = surf->numVerts; vboSurf->minIndex = 0; @@ -767,7 +760,6 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, vboSurf->vbo->ofs_normal = ofs_normal; #ifdef USE_VERT_TANGENT_SPACE vboSurf->vbo->ofs_tangent = ofs_tangent; - vboSurf->vbo->ofs_bitangent = ofs_bitangent; #endif vboSurf->vbo->ofs_st = ofs_st; @@ -775,7 +767,6 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, vboSurf->vbo->stride_normal = sizeof(*normals); #ifdef USE_VERT_TANGENT_SPACE vboSurf->vbo->stride_tangent = sizeof(*tangents); - vboSurf->vbo->stride_bitangent = sizeof(*bitangents); #endif vboSurf->vbo->stride_st = sizeof(*st); @@ -784,7 +775,7 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, ri.Free(data); - vboSurf->ibo = R_CreateIBO2(va("staticMD3Mesh_IBO %s", surf->name), surf->numTriangles, surf->triangles, VBO_USAGE_STATIC); + vboSurf->ibo = R_CreateIBO2(va("staticMD3Mesh_IBO %s", surf->name), surf->numIndexes, surf->indexes, VBO_USAGE_STATIC); } } @@ -836,7 +827,7 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char LL(pinmodel->ofsFrames); // This is a model that uses some type of compressed Bones. We don't want to uncompress every bone for each rendered frame - // over and over again, we'll uncompress it in this function already, so we must adjust the size of the target md4. + // over and over again, we'll uncompress it in this function already, so we must adjust the size of the target mdr. if(pinmodel->ofsFrames < 0) { // mdrFrame_t is larger than mdrCompFrame_t: @@ -1133,162 +1124,6 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char return qtrue; } -/* -================= -R_LoadMD4 -================= -*/ - -static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name ) { - int i, j, k, lodindex; - md4Header_t *pinmodel, *md4; - md4Frame_t *frame; - md4LOD_t *lod; - md4Surface_t *surf; - md4Triangle_t *tri; - md4Vertex_t *v; - int version; - int size; - shader_t *sh; - int frameSize; - - pinmodel = (md4Header_t *)buffer; - - version = LittleLong (pinmodel->version); - if (version != MD4_VERSION) { - ri.Printf( PRINT_WARNING, "R_LoadMD4: %s has wrong version (%i should be %i)\n", - mod_name, version, MD4_VERSION); - return qfalse; - } - - mod->type = MOD_MD4; - size = LittleLong(pinmodel->ofsEnd); - mod->dataSize += size; - mod->modelData = md4 = ri.Hunk_Alloc( size, h_low ); - - Com_Memcpy(md4, buffer, size); - - LL(md4->ident); - LL(md4->version); - LL(md4->numFrames); - LL(md4->numBones); - LL(md4->numLODs); - LL(md4->ofsFrames); - LL(md4->ofsLODs); - md4->ofsEnd = size; - - if ( md4->numFrames < 1 ) { - ri.Printf( PRINT_WARNING, "R_LoadMD4: %s has no frames\n", mod_name ); - return qfalse; - } - - // we don't need to swap tags in the renderer, they aren't used - - // swap all the frames - frameSize = (size_t)( &((md4Frame_t *)0)->bones[ md4->numBones ] ); - for ( i = 0 ; i < md4->numFrames ; i++) { - frame = (md4Frame_t *) ( (byte *)md4 + md4->ofsFrames + i * frameSize ); - frame->radius = LittleFloat( frame->radius ); - for ( j = 0 ; j < 3 ; j++ ) { - frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] ); - frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] ); - frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] ); - } - for ( j = 0 ; j < md4->numBones * sizeof( md4Bone_t ) / 4 ; j++ ) { - ((float *)frame->bones)[j] = LittleFloat( ((float *)frame->bones)[j] ); - } - } - - // swap all the LOD's - lod = (md4LOD_t *) ( (byte *)md4 + md4->ofsLODs ); - for ( lodindex = 0 ; lodindex < md4->numLODs ; lodindex++ ) { - - // swap all the surfaces - surf = (md4Surface_t *) ( (byte *)lod + lod->ofsSurfaces ); - for ( i = 0 ; i < lod->numSurfaces ; i++) { - LL(surf->ident); - LL(surf->numTriangles); - LL(surf->ofsTriangles); - LL(surf->numVerts); - LL(surf->ofsVerts); - LL(surf->ofsEnd); - - if ( surf->numVerts >= SHADER_MAX_VERTEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadMD4: %s has more than %i verts on %s (%i).\n", - mod_name, SHADER_MAX_VERTEXES - 1, surf->name[0] ? surf->name : "a surface", - surf->numVerts ); - return qfalse; - } - if ( surf->numTriangles*3 >= SHADER_MAX_INDEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadMD4: %s has more than %i triangles on %s (%i).\n", - mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, surf->name[0] ? surf->name : "a surface", - surf->numTriangles ); - return qfalse; - } - - // change to surface identifier - surf->ident = SF_MD4; - - // lowercase the surface name so skin compares are faster - Q_strlwr( surf->name ); - - // register the shaders - sh = R_FindShader( surf->shader, LIGHTMAP_NONE, qtrue ); - if ( sh->defaultShader ) { - surf->shaderIndex = 0; - } else { - surf->shaderIndex = sh->index; - } - - // swap all the triangles - tri = (md4Triangle_t *) ( (byte *)surf + surf->ofsTriangles ); - for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) { - LL(tri->indexes[0]); - LL(tri->indexes[1]); - LL(tri->indexes[2]); - } - - // swap all the vertexes - // FIXME - // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left - // in for reference. - //v = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts + 12); - v = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts); - for ( j = 0 ; j < surf->numVerts ; j++ ) { - v->normal[0] = LittleFloat( v->normal[0] ); - v->normal[1] = LittleFloat( v->normal[1] ); - v->normal[2] = LittleFloat( v->normal[2] ); - - v->texCoords[0] = LittleFloat( v->texCoords[0] ); - v->texCoords[1] = LittleFloat( v->texCoords[1] ); - - v->numWeights = LittleLong( v->numWeights ); - - for ( k = 0 ; k < v->numWeights ; k++ ) { - v->weights[k].boneIndex = LittleLong( v->weights[k].boneIndex ); - v->weights[k].boneWeight = LittleFloat( v->weights[k].boneWeight ); - v->weights[k].offset[0] = LittleFloat( v->weights[k].offset[0] ); - v->weights[k].offset[1] = LittleFloat( v->weights[k].offset[1] ); - v->weights[k].offset[2] = LittleFloat( v->weights[k].offset[2] ); - } - // FIXME - // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left - // in for reference. - //v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights] + 12 ); - v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights]); - } - - // find the next surface - surf = (md4Surface_t *)( (byte *)surf + surf->ofsEnd ); - } - - // find the next LOD - lod = (md4LOD_t *)( (byte *)lod + lod->ofsEnd ); - } - - return qtrue; -} - //============================================================================= @@ -1311,11 +1146,6 @@ void RE_BeginRegistration( glconfig_t *glconfigOut ) { RE_ClearScene(); tr.registered = qtrue; - - // NOTE: this sucks, for some reason the first stretch pic is never drawn - // without this we'd see a white flash on a level load because the very - // first time the level shot would not be drawn -// RE_StretchPic(0, 0, 0, 0, 0, 0, 1, 1, 0); } //============================================================================= @@ -1528,17 +1358,6 @@ void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) { VectorCopy( frame->bounds[0], mins ); VectorCopy( frame->bounds[1], maxs ); - return; - } else if (model->type == MOD_MD4) { - md4Header_t *header; - md4Frame_t *frame; - - header = (md4Header_t *)model->modelData; - frame = (md4Frame_t *) ((byte *)header + header->ofsFrames); - - VectorCopy( frame->bounds[0], mins ); - VectorCopy( frame->bounds[1], maxs ); - return; } else if (model->type == MOD_MDR) { mdrHeader_t *header; diff --git a/code/renderergl2/tr_model_iqm.c b/code/renderergl2/tr_model_iqm.c index 44c98ee0..b3843c5d 100644 --- a/code/renderergl2/tr_model_iqm.c +++ b/code/renderergl2/tr_model_iqm.c @@ -25,6 +25,13 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define LL(x) x=LittleLong(x) +// 3x4 identity matrix +static float identityMatrix[12] = { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0 +}; + static qboolean IQM_CheckRange( iqmHeader_t *header, int offset, int count,int size ) { // return true if the range specified by offset, count and size @@ -143,6 +150,7 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na iqmData_t *iqmData; srfIQModel_t *surface; char meshName[MAX_QPATH]; + byte blendIndexesType, blendWeightsType; if( filesize < sizeof(iqmHeader_t) ) { return qfalse; @@ -198,6 +206,8 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na return qfalse; } + blendIndexesType = blendWeightsType = IQM_UBYTE; + // check and swap vertex arrays if( IQM_CheckRange( header, header->ofs_vertexarrays, header->num_vertexarrays, @@ -264,11 +274,20 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na } break; case IQM_BLENDINDEXES: + if( (vertexarray->format != IQM_INT && + vertexarray->format != IQM_UBYTE) || + vertexarray->size != 4 ) { + return qfalse; + } + blendIndexesType = vertexarray->format; + break; case IQM_BLENDWEIGHTS: - if( vertexarray->format != IQM_UBYTE || + if( (vertexarray->format != IQM_FLOAT && + vertexarray->format != IQM_UBYTE) || vertexarray->size != 4 ) { return qfalse; } + blendWeightsType = vertexarray->format; break; case IQM_COLOR: if( vertexarray->format != IQM_UBYTE || @@ -343,7 +362,9 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na } } - if( header->num_poses != header->num_joints ) { + if( header->num_poses != header->num_joints && header->num_poses != 0 ) { + ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has %d poses and %d joints, must have the same number or 0 poses\n", + mod_name, header->num_poses, header->num_joints ); return qfalse; } @@ -379,7 +400,10 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na joint_names += strlen( (char *)header + header->ofs_text + joint->name ) + 1; } + } + if ( header->num_poses ) + { // check and swap poses if( IQM_CheckRange( header, header->ofs_poses, header->num_poses, sizeof(iqmPose_t) ) ) { @@ -438,7 +462,7 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na size = sizeof(iqmData_t); size += header->num_meshes * sizeof( srfIQModel_t ); size += header->num_joints * 12 * sizeof( float ); // joint mats - size += header->num_joints * header->num_frames * 12 * sizeof( float ); // pose mats + size += header->num_poses * header->num_frames * 12 * sizeof( float ); // pose mats if(header->ofs_bounds) size += header->num_frames * 6 * sizeof(float); // model bounds size += header->num_vertexes * 3 * sizeof(float); // positions @@ -446,12 +470,18 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na size += header->num_vertexes * 3 * sizeof(float); // normals size += header->num_vertexes * 4 * sizeof(float); // tangents size += header->num_vertexes * 4 * sizeof(byte); // blendIndexes - size += header->num_vertexes * 4 * sizeof(byte); // blendWeights size += header->num_vertexes * 4 * sizeof(byte); // colors size += header->num_joints * sizeof(int); // parents size += header->num_triangles * 3 * sizeof(int); // triangles size += joint_names; // joint names + // blendWeights + if (blendWeightsType == IQM_FLOAT) { + size += header->num_vertexes * 4 * sizeof(float); + } else { + size += header->num_vertexes * 4 * sizeof(byte); + } + mod->type = MOD_IQM; iqmData = (iqmData_t *)ri.Hunk_Alloc( size, h_low ); mod->modelData = iqmData; @@ -462,28 +492,40 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na iqmData->num_frames = header->num_frames; iqmData->num_surfaces = header->num_meshes; iqmData->num_joints = header->num_joints; + iqmData->num_poses = header->num_poses; + iqmData->blendWeightsType = blendWeightsType; iqmData->surfaces = (srfIQModel_t *)(iqmData + 1); iqmData->jointMats = (float *) (iqmData->surfaces + iqmData->num_surfaces); iqmData->poseMats = iqmData->jointMats + 12 * header->num_joints; if(header->ofs_bounds) { - iqmData->bounds = iqmData->poseMats + 12 * header->num_joints * header->num_frames; + iqmData->bounds = iqmData->poseMats + 12 * header->num_poses * header->num_frames; iqmData->positions = iqmData->bounds + 6 * header->num_frames; } else - iqmData->positions = iqmData->poseMats + 12 * header->num_joints * header->num_frames; + iqmData->positions = iqmData->poseMats + 12 * header->num_poses * header->num_frames; iqmData->texcoords = iqmData->positions + 3 * header->num_vertexes; iqmData->normals = iqmData->texcoords + 2 * header->num_vertexes; iqmData->tangents = iqmData->normals + 3 * header->num_vertexes; iqmData->blendIndexes = (byte *)(iqmData->tangents + 4 * header->num_vertexes); - iqmData->blendWeights = iqmData->blendIndexes + 4 * header->num_vertexes; - iqmData->colors = iqmData->blendWeights + 4 * header->num_vertexes; + + if(blendWeightsType == IQM_FLOAT) { + iqmData->blendWeights.f = (float *)(iqmData->blendIndexes + 4 * header->num_vertexes); + iqmData->colors = (byte *)(iqmData->blendWeights.f + 4 * header->num_vertexes); + } else { + iqmData->blendWeights.b = iqmData->blendIndexes + 4 * header->num_vertexes; + iqmData->colors = iqmData->blendWeights.b + 4 * header->num_vertexes; + } + iqmData->jointParents = (int *)(iqmData->colors + 4 * header->num_vertexes); iqmData->triangles = iqmData->jointParents + header->num_joints; iqmData->names = (char *)(iqmData->triangles + 3 * header->num_triangles); if ( header->num_joints == 0 ) - iqmData->jointMats = iqmData->poseMats = NULL; + iqmData->jointMats = NULL; + + if ( header->num_poses == 0 ) + iqmData->poseMats = NULL; // calculate joint matrices and their inverses // joint inverses are needed only until the pose matrices are calculated @@ -620,14 +662,27 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na n * sizeof(float) ); break; case IQM_BLENDINDEXES: - Com_Memcpy( iqmData->blendIndexes, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); + if( blendIndexesType == IQM_INT ) { + int *data = (int*)((byte*)header + vertexarray->offset); + for ( j = 0; j < n; j++ ) { + iqmData->blendIndexes[j] = (byte)data[j]; + } + } else { + Com_Memcpy( iqmData->blendIndexes, + (byte *)header + vertexarray->offset, + n * sizeof(byte) ); + } break; case IQM_BLENDWEIGHTS: - Com_Memcpy( iqmData->blendWeights, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); + if( blendWeightsType == IQM_FLOAT ) { + Com_Memcpy( iqmData->blendWeights.f, + (byte *)header + vertexarray->offset, + n * sizeof(float) ); + } else { + Com_Memcpy( iqmData->blendWeights.b, + (byte *)header + vertexarray->offset, + n * sizeof(byte) ); + } break; case IQM_COLOR: Com_Memcpy( iqmData->colors, @@ -895,9 +950,21 @@ static void ComputePoseMats( iqmData_t *data, int frame, int oldframe, int *joint = data->jointParents; int i; - if ( oldframe == frame ) { - mat1 = data->poseMats + 12 * data->num_joints * frame; + if ( data->num_poses == 0 ) { for( i = 0; i < data->num_joints; i++, joint++ ) { + if( *joint >= 0 ) { + Matrix34Multiply( mat + 12 * *joint, + identityMatrix, mat + 12*i ); + } else { + Com_Memcpy( mat + 12*i, identityMatrix, 12 * sizeof(float) ); + } + } + return; + } + + if ( oldframe == frame ) { + mat1 = data->poseMats + 12 * data->num_poses * frame; + for( i = 0; i < data->num_poses; i++, joint++ ) { if( *joint >= 0 ) { Matrix34Multiply( mat + 12 * *joint, mat1 + 12*i, mat + 12*i ); @@ -906,10 +973,10 @@ static void ComputePoseMats( iqmData_t *data, int frame, int oldframe, } } } else { - mat1 = data->poseMats + 12 * data->num_joints * frame; - mat2 = data->poseMats + 12 * data->num_joints * oldframe; + mat1 = data->poseMats + 12 * data->num_poses * frame; + mat2 = data->poseMats + 12 * data->num_poses * oldframe; - for( i = 0; i < data->num_joints; i++, joint++ ) { + for( i = 0; i < data->num_poses; i++, joint++ ) { if( *joint >= 0 ) { float tmpMat[12]; InterpolateMatrix( mat1 + 12*i, mat2 + 12*i, @@ -957,7 +1024,10 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) { int i; vec4_t *outXYZ; - vec4_t *outNormal; + uint32_t *outNormal; +#ifdef USE_VERT_TANGENT_SPACE + uint32_t *outTangent; +#endif vec2_t (*outTexCoord)[2]; vec4_t *outColor; @@ -973,11 +1043,14 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) { outXYZ = &tess.xyz[tess.numVertexes]; outNormal = &tess.normal[tess.numVertexes]; +#ifdef USE_VERT_TANGENT_SPACE + outTangent = &tess.tangent[tess.numVertexes]; +#endif outTexCoord = &tess.texCoords[tess.numVertexes]; outColor = &tess.vertexColors[tess.numVertexes]; // compute interpolated joint matrices - if ( data->num_joints > 0 ) { + if ( data->num_poses > 0 ) { ComputePoseMats( data, frame, oldframe, backlerp, jointMats ); } @@ -988,28 +1061,31 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) { float vtxMat[12]; float nrmMat[9]; int vtx = i + surf->first_vertex; + float blendWeights[4]; + int numWeights; - if ( data->num_joints == 0 || data->blendWeights[4*vtx] <= 0 ) { + for ( numWeights = 0; numWeights < 4; numWeights++ ) { + if ( data->blendWeightsType == IQM_FLOAT ) + blendWeights[numWeights] = data->blendWeights.f[4*vtx + numWeights]; + else + blendWeights[numWeights] = (float)data->blendWeights.b[4*vtx + numWeights] / 255.0f; + + if ( blendWeights[numWeights] <= 0 ) + break; + } + + if ( data->num_poses == 0 || numWeights == 0 ) { // no blend joint, use identity matrix. - for( j = 0; j < 3; j++ ) { - for( k = 0; k < 4; k++ ) - vtxMat[4*j+k] = ( k == j ) ? 1 : 0; - } + Com_Memcpy( vtxMat, identityMatrix, 12 * sizeof (float) ); } else { // compute the vertex matrix by blending the up to // four blend weights - for( k = 0; k < 12; k++ ) - vtxMat[k] = data->blendWeights[4*vtx] - * jointMats[12*data->blendIndexes[4*vtx] + k]; - for( j = 1; j < 4; j++ ) { - if( data->blendWeights[4*vtx + j] <= 0 ) - break; - for( k = 0; k < 12; k++ ) - vtxMat[k] += data->blendWeights[4*vtx + j] - * jointMats[12*data->blendIndexes[4*vtx + j] + k]; + Com_Memset( vtxMat, 0, 12 * sizeof (float) ); + for( j = 0; j < numWeights; j++ ) { + for( k = 0; k < 12; k++ ) { + vtxMat[k] += blendWeights[j] * jointMats[12*data->blendIndexes[4*vtx + j] + k]; + } } - for( k = 0; k < 12; k++ ) - vtxMat[k] *= 1.0f / 255.0f; } // compute the normal matrix as transpose of the adjoint @@ -1046,19 +1122,25 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) { vtxMat[11]; (*outXYZ)[3] = 1.0f; - (*outNormal)[0] = - nrmMat[ 0] * data->normals[3*vtx+0] + - nrmMat[ 1] * data->normals[3*vtx+1] + - nrmMat[ 2] * data->normals[3*vtx+2]; - (*outNormal)[1] = - nrmMat[ 3] * data->normals[3*vtx+0] + - nrmMat[ 4] * data->normals[3*vtx+1] + - nrmMat[ 5] * data->normals[3*vtx+2]; - (*outNormal)[2] = - nrmMat[ 6] * data->normals[3*vtx+0] + - nrmMat[ 7] * data->normals[3*vtx+1] + - nrmMat[ 8] * data->normals[3*vtx+2]; - (*outNormal)[3] = 0.0f; + { + vec3_t normal; + vec4_t tangent; + + normal[0] = DotProduct(&nrmMat[0], &data->normals[3*vtx]); + normal[1] = DotProduct(&nrmMat[3], &data->normals[3*vtx]); + normal[2] = DotProduct(&nrmMat[6], &data->normals[3*vtx]); + + *outNormal = R_VboPackNormal(normal); + +#ifdef USE_VERT_TANGENT_SPACE + tangent[0] = DotProduct(&nrmMat[0], &data->tangents[4*vtx]); + tangent[1] = DotProduct(&nrmMat[3], &data->tangents[4*vtx]); + tangent[2] = DotProduct(&nrmMat[6], &data->tangents[4*vtx]); + tangent[3] = data->tangents[4*vtx+3]; + + *outTangent++ = R_VboPackTangent(tangent); +#endif + } (*outColor)[0] = data->colors[4*vtx+0] / 255.0f; (*outColor)[1] = data->colors[4*vtx+1] / 255.0f; diff --git a/code/renderergl2/tr_postprocess.c b/code/renderergl2/tr_postprocess.c index cab9d42b..35982fce 100644 --- a/code/renderergl2/tr_postprocess.c +++ b/code/renderergl2/tr_postprocess.c @@ -22,9 +22,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "tr_local.h" -void RB_ToneMap(FBO_t *hdrFbo, vec4i_t hdrBox, FBO_t *ldrFbo, vec4i_t ldrBox, int autoExposure) +void RB_ToneMap(FBO_t *hdrFbo, ivec4_t hdrBox, FBO_t *ldrFbo, ivec4_t ldrBox, int autoExposure) { - vec4i_t srcBox, dstBox; + ivec4_t srcBox, dstBox; vec4_t color; static int lastFrameCount = 0; @@ -103,9 +103,9 @@ Blurs a part of one framebuffer to another. Framebuffers can be identical. ============= */ -void RB_BokehBlur(FBO_t *src, vec4i_t srcBox, FBO_t *dst, vec4i_t dstBox, float blur) +void RB_BokehBlur(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, float blur) { -// vec4i_t srcBox, dstBox; +// ivec4_t srcBox, dstBox; vec4_t color; blur *= 10.0f; @@ -118,7 +118,7 @@ void RB_BokehBlur(FBO_t *src, vec4i_t srcBox, FBO_t *dst, vec4i_t dstBox, float // bokeh blur if (blur > 0.0f) { - vec4i_t quarterBox; + ivec4_t quarterBox; quarterBox[0] = 0; quarterBox[1] = tr.quarterFbo[0]->height; @@ -226,7 +226,7 @@ void RB_BokehBlur(FBO_t *src, vec4i_t srcBox, FBO_t *dst, vec4i_t dstBox, float static void RB_RadialBlur(FBO_t *srcFbo, FBO_t *dstFbo, int passes, float stretch, float x, float y, float w, float h, float xcenter, float ycenter, float alpha) { - vec4i_t srcBox, dstBox; + ivec4_t srcBox, dstBox; vec4_t color; const float inc = 1.f / passes; const float mul = powf(stretch, inc); @@ -255,10 +255,20 @@ static void RB_RadialBlur(FBO_t *srcFbo, FBO_t *dstFbo, int passes, float stretc float s1 = iscale + s0; float t1 = iscale + t0; - srcBox[0] = s0 * srcFbo->width; - srcBox[1] = t0 * srcFbo->height; - srcBox[2] = (s1 - s0) * srcFbo->width; - srcBox[3] = (t1 - t0) * srcFbo->height; + if (srcFbo) + { + srcBox[0] = s0 * srcFbo->width; + srcBox[1] = t0 * srcFbo->height; + srcBox[2] = (s1 - s0) * srcFbo->width; + srcBox[3] = (t1 - t0) * srcFbo->height; + } + else + { + srcBox[0] = s0 * glConfig.vidWidth; + srcBox[1] = t0 * glConfig.vidHeight; + srcBox[2] = (s1 - s0) * glConfig.vidWidth; + srcBox[3] = (t1 - t0) * glConfig.vidHeight; + } FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); @@ -298,7 +308,7 @@ static qboolean RB_UpdateSunFlareVis(void) return sampleCount > 0; } -void RB_SunRays(FBO_t *srcFbo, vec4i_t srcBox, FBO_t *dstFbo, vec4i_t dstBox) +void RB_SunRays(FBO_t *srcFbo, ivec4_t srcBox, FBO_t *dstFbo, ivec4_t dstBox) { vec4_t color; float dot; @@ -306,7 +316,7 @@ void RB_SunRays(FBO_t *srcFbo, vec4i_t srcBox, FBO_t *dstFbo, vec4i_t dstBox) qboolean colorize = qtrue; // float w, h, w2, h2; - matrix_t mvp; + mat4_t mvp; vec4_t pos, hpos; dot = DotProduct(tr.sunDirection, backEnd.viewParms.or.axis[0]); @@ -319,11 +329,11 @@ void RB_SunRays(FBO_t *srcFbo, vec4i_t srcBox, FBO_t *dstFbo, vec4i_t dstBox) // From RB_DrawSun() { float dist; - matrix_t trans, model, mvp; + mat4_t trans, model, mvp; - Matrix16Translation( backEnd.viewParms.or.origin, trans ); - Matrix16Multiply( backEnd.viewParms.world.modelMatrix, trans, model ); - Matrix16Multiply(backEnd.viewParms.projectionMatrix, model, mvp); + Mat4Translation( backEnd.viewParms.or.origin, trans ); + Mat4Multiply( backEnd.viewParms.world.modelMatrix, trans, model ); + Mat4Multiply(backEnd.viewParms.projectionMatrix, model, mvp); dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) @@ -331,8 +341,8 @@ void RB_SunRays(FBO_t *srcFbo, vec4i_t srcBox, FBO_t *dstFbo, vec4i_t dstBox) } // project sun point - //Matrix16Multiply(backEnd.viewParms.projectionMatrix, backEnd.viewParms.world.modelMatrix, mvp); - Matrix16Transform(mvp, pos, hpos); + //Mat4Multiply(backEnd.viewParms.projectionMatrix, backEnd.viewParms.world.modelMatrix, mvp); + Mat4Transform(mvp, pos, hpos); // transform to UV coords hpos[3] = 0.5f / hpos[3]; @@ -344,17 +354,27 @@ void RB_SunRays(FBO_t *srcFbo, vec4i_t srcBox, FBO_t *dstFbo, vec4i_t dstBox) { float mul = 1.f; vec2_t texScale; - vec4i_t rayBox, quarterBox; + ivec4_t rayBox, quarterBox; texScale[0] = texScale[1] = 1.0f; VectorSet4(color, mul, mul, mul, 1); - rayBox[0] = srcBox[0] * tr.sunRaysFbo->width / srcFbo->width; - rayBox[1] = srcBox[1] * tr.sunRaysFbo->height / srcFbo->height; - rayBox[2] = srcBox[2] * tr.sunRaysFbo->width / srcFbo->width; - rayBox[3] = srcBox[3] * tr.sunRaysFbo->height / srcFbo->height; + if (srcFbo) + { + rayBox[0] = srcBox[0] * tr.sunRaysFbo->width / srcFbo->width; + rayBox[1] = srcBox[1] * tr.sunRaysFbo->height / srcFbo->height; + rayBox[2] = srcBox[2] * tr.sunRaysFbo->width / srcFbo->width; + rayBox[3] = srcBox[3] * tr.sunRaysFbo->height / srcFbo->height; + } + else + { + rayBox[0] = srcBox[0] * tr.sunRaysFbo->width / glConfig.vidWidth; + rayBox[1] = srcBox[1] * tr.sunRaysFbo->height / glConfig.vidHeight; + rayBox[2] = srcBox[2] * tr.sunRaysFbo->width / glConfig.vidWidth; + rayBox[3] = srcBox[3] * tr.sunRaysFbo->height / glConfig.vidHeight; + } quarterBox[0] = 0; quarterBox[1] = tr.quarterFbo[0]->height; @@ -421,7 +441,7 @@ static void RB_BlurAxis(FBO_t *srcFbo, FBO_t *dstFbo, float strength, qboolean h ymul *= strength; { - vec4i_t srcBox, dstBox; + ivec4_t srcBox, dstBox; vec4_t color; vec2_t texScale; @@ -470,7 +490,7 @@ void RB_GaussianBlur(float blur) return; { - vec4i_t srcBox, dstBox; + ivec4_t srcBox, dstBox; vec4_t color; vec2_t texScale; @@ -480,7 +500,7 @@ void RB_GaussianBlur(float blur) VectorSet4(color, 1, 1, 1, 1); // first, downsample the framebuffer - FBO_FastBlit(tr.screenScratchFbo, NULL, tr.quarterFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR); + FBO_FastBlit(NULL, NULL, tr.quarterFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR); FBO_FastBlit(tr.quarterFbo[0], NULL, tr.textureScratchFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR); // set the alpha channel @@ -498,6 +518,6 @@ void RB_GaussianBlur(float blur) VectorSet4(srcBox, 0, 0, tr.textureScratchFbo[0]->width, tr.textureScratchFbo[0]->height); VectorSet4(dstBox, 0, 0, glConfig.vidWidth, glConfig.vidHeight); color[3] = factor; - FBO_Blit(tr.textureScratchFbo[0], srcBox, texScale, tr.screenScratchFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA); + FBO_Blit(tr.textureScratchFbo[0], srcBox, texScale, NULL, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA); } } diff --git a/code/renderergl2/tr_postprocess.h b/code/renderergl2/tr_postprocess.h index 6c34ecc2..09daf134 100644 --- a/code/renderergl2/tr_postprocess.h +++ b/code/renderergl2/tr_postprocess.h @@ -25,9 +25,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "tr_fbo.h" -void RB_ToneMap(FBO_t *hdrFbo, vec4i_t hdrBox, FBO_t *ldrFbo, vec4i_t ldrBox, int autoExposure); -void RB_BokehBlur(FBO_t *src, vec4i_t srcBox, FBO_t *dst, vec4i_t dstBox, float blur); -void RB_SunRays(FBO_t *srcFbo, vec4i_t srcBox, FBO_t *dstFbo, vec4i_t dstBox); +void RB_ToneMap(FBO_t *hdrFbo, ivec4_t hdrBox, FBO_t *ldrFbo, ivec4_t ldrBox, int autoExposure); +void RB_BokehBlur(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, float blur); +void RB_SunRays(FBO_t *srcFbo, ivec4_t srcBox, FBO_t *dstFbo, ivec4_t dstBox); void RB_GaussianBlur(float blur); #endif diff --git a/code/renderergl2/tr_scene.c b/code/renderergl2/tr_scene.c index e3f52958..db2d1386 100644 --- a/code/renderergl2/tr_scene.c +++ b/code/renderergl2/tr_scene.c @@ -496,7 +496,7 @@ void RE_RenderScene( const refdef_t *fd ) { } // playing with even more shadows - if(glRefConfig.framebufferObject && !( fd->rdflags & RDF_NOWORLDMODEL ) && (r_forceSun->integer || tr.sunShadows)) + if(glRefConfig.framebufferObject && r_sunlightMode->integer && !( fd->rdflags & RDF_NOWORLDMODEL ) && (r_forceSun->integer || tr.sunShadows)) { R_RenderSunShadowMaps(fd, 0); R_RenderSunShadowMaps(fd, 1); diff --git a/code/renderergl2/tr_shade.c b/code/renderergl2/tr_shade.c index 4ee62984..856b8748 100644 --- a/code/renderergl2/tr_shade.c +++ b/code/renderergl2/tr_shade.c @@ -44,9 +44,9 @@ R_DrawElements void R_DrawElementsVBO( int numIndexes, glIndex_t firstIndex, glIndex_t minIndex, glIndex_t maxIndex ) { if (glRefConfig.drawRangeElements) - qglDrawRangeElementsEXT(GL_TRIANGLES, minIndex, maxIndex, numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(firstIndex * sizeof(GL_INDEX_TYPE))); + qglDrawRangeElementsEXT(GL_TRIANGLES, minIndex, maxIndex, numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(firstIndex * sizeof(glIndex_t))); else - qglDrawElements(GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(firstIndex * sizeof(GL_INDEX_TYPE))); + qglDrawElements(GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(firstIndex * sizeof(glIndex_t))); } @@ -148,7 +148,7 @@ static void DrawTris (shaderCommands_t *input) { GLSL_VertexAttribsState(ATTR_POSITION); GLSL_BindProgram(sp); - GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); VectorSet4(color, 1, 1, 1, 1); GLSL_SetUniformVec4(sp, UNIFORM_COLOR, color); @@ -221,14 +221,22 @@ extern float EvalWaveForm( const waveForm_t *wf ); extern float EvalWaveFormClamped( const waveForm_t *wf ); -static void ComputeTexMatrix( shaderStage_t *pStage, int bundleNum, float *outmatrix) +static void ComputeTexMods( shaderStage_t *pStage, int bundleNum, float *outMatrix, float *outOffTurb) { int tm; - float matrix[16], currentmatrix[16]; + float matrix[6], currentmatrix[6]; textureBundle_t *bundle = &pStage->bundle[bundleNum]; - Matrix16Identity(outmatrix); - Matrix16Identity(currentmatrix); + matrix[0] = 1.0f; matrix[2] = 0.0f; matrix[4] = 0.0f; + matrix[1] = 0.0f; matrix[3] = 1.0f; matrix[5] = 0.0f; + + currentmatrix[0] = 1.0f; currentmatrix[2] = 0.0f; currentmatrix[4] = 0.0f; + currentmatrix[1] = 0.0f; currentmatrix[3] = 1.0f; currentmatrix[5] = 0.0f; + + outMatrix[0] = 1.0f; outMatrix[2] = 0.0f; + outMatrix[1] = 0.0f; outMatrix[3] = 1.0f; + + outOffTurb[0] = 0.0f; outOffTurb[1] = 0.0f; outOffTurb[2] = 0.0f; outOffTurb[3] = 0.0f; for ( tm = 0; tm < bundle->numTexMods ; tm++ ) { switch ( bundle->texMods[tm].type ) @@ -239,59 +247,73 @@ static void ComputeTexMatrix( shaderStage_t *pStage, int bundleNum, float *outma break; case TMOD_TURBULENT: - RB_CalcTurbulentTexMatrix( &bundle->texMods[tm].wave, - matrix ); - outmatrix[12] = matrix[12]; - outmatrix[13] = matrix[13]; - Matrix16Copy(outmatrix, currentmatrix); + RB_CalcTurbulentFactors(&bundle->texMods[tm].wave, &outOffTurb[2], &outOffTurb[3]); break; case TMOD_ENTITY_TRANSLATE: - RB_CalcScrollTexMatrix( backEnd.currentEntity->e.shaderTexCoord, - matrix ); - Matrix16Multiply(matrix, currentmatrix, outmatrix); - Matrix16Copy(outmatrix, currentmatrix); + RB_CalcScrollTexMatrix( backEnd.currentEntity->e.shaderTexCoord, matrix ); break; case TMOD_SCROLL: RB_CalcScrollTexMatrix( bundle->texMods[tm].scroll, matrix ); - Matrix16Multiply(matrix, currentmatrix, outmatrix); - Matrix16Copy(outmatrix, currentmatrix); break; case TMOD_SCALE: RB_CalcScaleTexMatrix( bundle->texMods[tm].scale, matrix ); - Matrix16Multiply(matrix, currentmatrix, outmatrix); - Matrix16Copy(outmatrix, currentmatrix); break; case TMOD_STRETCH: RB_CalcStretchTexMatrix( &bundle->texMods[tm].wave, matrix ); - Matrix16Multiply(matrix, currentmatrix, outmatrix); - Matrix16Copy(outmatrix, currentmatrix); break; case TMOD_TRANSFORM: RB_CalcTransformTexMatrix( &bundle->texMods[tm], matrix ); - Matrix16Multiply(matrix, currentmatrix, outmatrix); - Matrix16Copy(outmatrix, currentmatrix); break; case TMOD_ROTATE: RB_CalcRotateTexMatrix( bundle->texMods[tm].rotateSpeed, matrix ); - Matrix16Multiply(matrix, currentmatrix, outmatrix); - Matrix16Copy(outmatrix, currentmatrix); break; default: ri.Error( ERR_DROP, "ERROR: unknown texmod '%d' in shader '%s'", bundle->texMods[tm].type, tess.shader->name ); break; } + + switch ( bundle->texMods[tm].type ) + { + case TMOD_NONE: + case TMOD_TURBULENT: + default: + break; + + case TMOD_ENTITY_TRANSLATE: + case TMOD_SCROLL: + case TMOD_SCALE: + case TMOD_STRETCH: + case TMOD_TRANSFORM: + case TMOD_ROTATE: + outMatrix[0] = matrix[0] * currentmatrix[0] + matrix[2] * currentmatrix[1]; + outMatrix[1] = matrix[1] * currentmatrix[0] + matrix[3] * currentmatrix[1]; + + outMatrix[2] = matrix[0] * currentmatrix[2] + matrix[2] * currentmatrix[3]; + outMatrix[3] = matrix[1] * currentmatrix[2] + matrix[3] * currentmatrix[3]; + + outOffTurb[0] = matrix[0] * currentmatrix[4] + matrix[2] * currentmatrix[5] + matrix[4]; + outOffTurb[1] = matrix[1] * currentmatrix[4] + matrix[3] * currentmatrix[5] + matrix[5]; + + currentmatrix[0] = outMatrix[0]; + currentmatrix[1] = outMatrix[1]; + currentmatrix[2] = outMatrix[2]; + currentmatrix[3] = outMatrix[3]; + currentmatrix[4] = outOffTurb[0]; + currentmatrix[5] = outOffTurb[1]; + break; + } } } @@ -370,7 +392,7 @@ static void ProjectDlightTexture( void ) { GLSL_BindProgram(sp); - GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); @@ -421,46 +443,29 @@ static void ProjectDlightTexture( void ) { } -static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t vertColor ) +static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t vertColor, int blend ) { + baseColor[0] = + baseColor[1] = + baseColor[2] = + baseColor[3] = 1.0f; + + vertColor[0] = + vertColor[1] = + vertColor[2] = + vertColor[3] = 0.0f; + // // rgbGen // switch ( pStage->rgbGen ) { - case CGEN_IDENTITY: - baseColor[0] = - baseColor[1] = - baseColor[2] = - baseColor[3] = 1.0f; - - vertColor[0] = - vertColor[1] = - vertColor[2] = - vertColor[3] = 0.0f; - break; case CGEN_IDENTITY_LIGHTING: baseColor[0] = baseColor[1] = baseColor[2] = tr.identityLight; - baseColor[3] = 1.0f; - - vertColor[0] = - vertColor[1] = - vertColor[2] = - vertColor[3] = 0.0f; break; case CGEN_EXACT_VERTEX: - baseColor[0] = - baseColor[1] = - baseColor[2] = - baseColor[3] = 0.0f; - - vertColor[0] = - vertColor[1] = - vertColor[2] = - vertColor[3] = 1.0f; - break; case CGEN_EXACT_VERTEX_LIT: baseColor[0] = baseColor[1] = @@ -477,11 +482,6 @@ static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t baseColor[1] = pStage->constantColor[1] / 255.0f; baseColor[2] = pStage->constantColor[2] / 255.0f; baseColor[3] = pStage->constantColor[3] / 255.0f; - - vertColor[0] = - vertColor[1] = - vertColor[2] = - vertColor[3] = 0.0f; break; case CGEN_VERTEX: baseColor[0] = @@ -509,12 +509,10 @@ static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t baseColor[0] = baseColor[1] = baseColor[2] = tr.identityLight; - baseColor[3] = 1.0f; vertColor[0] = vertColor[1] = vertColor[2] = -tr.identityLight; - vertColor[3] = 0.0f; break; case CGEN_FOG: { @@ -527,22 +525,11 @@ static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t baseColor[2] = ((unsigned char *)(&fog->colorInt))[2] / 255.0f; baseColor[3] = ((unsigned char *)(&fog->colorInt))[3] / 255.0f; } - - vertColor[0] = - vertColor[1] = - vertColor[2] = - vertColor[3] = 0.0f; break; case CGEN_WAVEFORM: baseColor[0] = baseColor[1] = baseColor[2] = RB_CalcWaveColorSingle( &pStage->rgbWave ); - baseColor[3] = 1.0f; - - vertColor[0] = - vertColor[1] = - vertColor[2] = - vertColor[3] = 0.0f; break; case CGEN_ENTITY: if (backEnd.currentEntity) @@ -552,11 +539,6 @@ static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t baseColor[2] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[2] / 255.0f; baseColor[3] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f; } - - vertColor[0] = - vertColor[1] = - vertColor[2] = - vertColor[3] = 0.0f; break; case CGEN_ONE_MINUS_ENTITY: if (backEnd.currentEntity) @@ -566,23 +548,10 @@ static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t baseColor[2] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[2] / 255.0f; baseColor[3] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f; } - - vertColor[0] = - vertColor[1] = - vertColor[2] = - vertColor[3] = 0.0f; break; + case CGEN_IDENTITY: case CGEN_LIGHTING_DIFFUSE: case CGEN_BAD: - baseColor[0] = - baseColor[1] = - baseColor[2] = - baseColor[3] = 1.0f; - - vertColor[0] = - vertColor[1] = - vertColor[2] = - vertColor[3] = 0.0f; break; } @@ -593,10 +562,6 @@ static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t { case AGEN_SKIP: break; - case AGEN_IDENTITY: - baseColor[3] = 1.0f; - vertColor[3] = 0.0f; - break; case AGEN_CONST: baseColor[3] = pStage->constantColor[3] / 255.0f; vertColor[3] = 0.0f; @@ -627,15 +592,32 @@ static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t baseColor[3] = 1.0f; vertColor[3] = -1.0f; break; + case AGEN_IDENTITY: case AGEN_LIGHTING_SPECULAR: case AGEN_PORTAL: - case AGEN_FRESNEL: // Done entirely in vertex program baseColor[3] = 1.0f; vertColor[3] = 0.0f; break; } + // multiply color by overbrightbits if this isn't a blend + if (r_softOverbright->integer && tr.overbrightBits + && !((blend & GLS_SRCBLEND_BITS) == GLS_SRCBLEND_DST_COLOR) + && !((blend & GLS_SRCBLEND_BITS) == GLS_SRCBLEND_ONE_MINUS_DST_COLOR) + && !((blend & GLS_DSTBLEND_BITS) == GLS_DSTBLEND_SRC_COLOR) + && !((blend & GLS_DSTBLEND_BITS) == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR)) + { + float scale = 1 << tr.overbrightBits; + + baseColor[0] *= scale; + baseColor[1] *= scale; + baseColor[2] *= scale; + vertColor[0] *= scale; + vertColor[1] *= scale; + vertColor[2] *= scale; + } + // FIXME: find some way to implement this. #if 0 // if in greyscale rendering mode turn all color values into greyscale. @@ -749,7 +731,8 @@ static void ForwardDlight( void ) { dlight_t *dl; shaderProgram_t *sp; vec4_t vector; - matrix_t matrix; + vec4_t texMatrix; + vec4_t texOffTurb; if ( !( tess.dlightBits & ( 1 << l ) ) ) { continue; // this surface definately doesn't have any of this light @@ -764,7 +747,7 @@ static void ForwardDlight( void ) { { int index = pStage->glslShaderIndex; - index &= ~(LIGHTDEF_LIGHTTYPE_MASK | LIGHTDEF_USE_DELUXEMAP); + index &= ~LIGHTDEF_LIGHTTYPE_MASK; index |= LIGHTDEF_USE_LIGHT_VECTOR; sp = &tr.lightallShader[index]; @@ -774,8 +757,9 @@ static void ForwardDlight( void ) { GLSL_BindProgram(sp); - GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); GLSL_SetUniformVec3(sp, UNIFORM_VIEWORIGIN, backEnd.viewParms.or.origin); + GLSL_SetUniformVec3(sp, UNIFORM_LOCALVIEWORIGIN, backEnd.or.viewOrigin); GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); @@ -802,7 +786,7 @@ static void ForwardDlight( void ) { vec4_t baseColor; vec4_t vertColor; - ComputeShaderColors(pStage, baseColor, vertColor); + ComputeShaderColors(pStage, baseColor, vertColor, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE); GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, baseColor); GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, vertColor); @@ -833,7 +817,7 @@ static void ForwardDlight( void ) { // where they aren't rendered GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); - GLSL_SetUniformMatrix16(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); + GLSL_SetUniformMat4(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); if (pStage->bundle[TB_DIFFUSEMAP].image[0]) R_BindAnimatedImageToTMU( &pStage->bundle[TB_DIFFUSEMAP], TB_DIFFUSEMAP); @@ -851,13 +835,9 @@ static void ForwardDlight( void ) { GL_SelectTexture(0); } - ComputeTexMatrix( pStage, TB_DIFFUSEMAP, matrix ); - - VectorSet4(vector, matrix[0], matrix[1], matrix[4], matrix[5]); - GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, vector); - - VectorSet4(vector, matrix[8], matrix[9], matrix[12], matrix[13]); - GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, vector); + ComputeTexMods( pStage, TB_DIFFUSEMAP, texMatrix, texOffTurb ); + GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, texMatrix); + GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, texOffTurb); GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, pStage->bundle[0].tcGen); @@ -914,7 +894,7 @@ static void ProjectPshadowVBOGLSL( void ) { GLSL_BindProgram(sp); - GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); VectorCopy(origin, vector); vector[3] = 1.0f; @@ -982,7 +962,7 @@ static void RB_FogPass( void ) { if (deformGen != DGEN_NONE) index |= FOGDEF_USE_DEFORM_VERTEXES; - if (glState.vertexAttribsInterpolation) + if (glState.vertexAnimation) index |= FOGDEF_USE_VERTEX_ANIMATION; sp = &tr.fogShader[index]; @@ -994,7 +974,7 @@ static void RB_FogPass( void ) { fog = tr.world->fogs + tess.fogNum; - GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); @@ -1039,7 +1019,7 @@ static unsigned int RB_CalcShaderVertexAttribs( shaderCommands_t *input ) { unsigned int vertexAttribs = input->shader->vertexAttribs; - if(glState.vertexAttribsInterpolation > 0.0f) + if(glState.vertexAnimation) { vertexAttribs |= ATTR_POSITION2; if (vertexAttribs & ATTR_NORMAL) @@ -1047,7 +1027,6 @@ static unsigned int RB_CalcShaderVertexAttribs( shaderCommands_t *input ) vertexAttribs |= ATTR_NORMAL2; #ifdef USE_VERT_TANGENT_SPACE vertexAttribs |= ATTR_TANGENT2; - vertexAttribs |= ATTR_BITANGENT2; #endif } } @@ -1058,7 +1037,6 @@ static unsigned int RB_CalcShaderVertexAttribs( shaderCommands_t *input ) static void RB_IterateStagesGeneric( shaderCommands_t *input ) { int stage; - matrix_t matrix; vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0}; float eyeT = 0; @@ -1074,6 +1052,8 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) { shaderStage_t *pStage = input->xstages[stage]; shaderProgram_t *sp; + vec4_t texMatrix; + vec4_t texOffTurb; if ( !pStage ) { @@ -1082,7 +1062,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) if (backEnd.depthFill) { - if (pStage->glslShaderGroup) + if (pStage->glslShaderGroup == tr.lightallShader) { int index = 0; @@ -1107,7 +1087,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) shaderAttribs |= GENERICDEF_USE_DEFORM_VERTEXES; } - if (glState.vertexAttribsInterpolation > 0.0f && backEnd.currentEntity && backEnd.currentEntity != &tr.worldEntity) + if (glState.vertexAnimation) { shaderAttribs |= GENERICDEF_USE_VERTEX_ANIMATION; } @@ -1120,7 +1100,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) sp = &tr.genericShader[shaderAttribs]; } } - else if (pStage->glslShaderGroup) + else if (pStage->glslShaderGroup == tr.lightallShader) { int index = pStage->glslShaderIndex; @@ -1134,11 +1114,6 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) index |= LIGHTDEF_USE_SHADOWMAP; } - if (!(tr.viewParms.flags & VPF_NOCUBEMAPS) && (index & LIGHTDEF_LIGHTTYPE_MASK) && input->cubemapIndex) - { - index |= LIGHTDEF_USE_CUBEMAP; - } - if (r_lightmap->integer && index & LIGHTDEF_USE_LIGHTMAP) { index = LIGHTDEF_USE_LIGHTMAP; @@ -1146,10 +1121,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) sp = &pStage->glslShaderGroup[index]; - if (pStage->glslShaderGroup == tr.lightallShader) - { - backEnd.pc.c_lightallDraws++; - } + backEnd.pc.c_lightallDraws++; } else { @@ -1160,8 +1132,9 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) GLSL_BindProgram(sp); - GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); GLSL_SetUniformVec3(sp, UNIFORM_VIEWORIGIN, backEnd.viewParms.or.origin); + GLSL_SetUniformVec3(sp, UNIFORM_LOCALVIEWORIGIN, backEnd.or.viewOrigin); GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); @@ -1184,7 +1157,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) vec4_t baseColor; vec4_t vertColor; - ComputeShaderColors(pStage, baseColor, vertColor); + ComputeShaderColors(pStage, baseColor, vertColor, pStage->stateBits); if ((backEnd.refdef.colorScale != 1.0f) && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL)) { @@ -1210,6 +1183,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) VectorCopy(backEnd.currentEntity->lightDir, vec); vec[3] = 0.0f; GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vec); + GLSL_SetUniformVec3(sp, UNIFORM_MODELLIGHTDIR, backEnd.currentEntity->modelLightDir); GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, 0.0f); } @@ -1231,16 +1205,9 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) GLSL_SetUniformVec4(sp, UNIFORM_FOGCOLORMASK, fogColorMask); } - ComputeTexMatrix( pStage, TB_DIFFUSEMAP, matrix ); - - { - vec4_t vector; - VectorSet4(vector, matrix[0], matrix[1], matrix[4], matrix[5]); - GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, vector); - - VectorSet4(vector, matrix[8], matrix[9], matrix[12], matrix[13]); - GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, vector); - } + ComputeTexMods( pStage, TB_DIFFUSEMAP, texMatrix, texOffTurb ); + GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, texMatrix); + GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, texOffTurb); GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, pStage->bundle[0].tcGen); if (pStage->bundle[0].tcGen == TCGEN_VECTOR) @@ -1253,7 +1220,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) GLSL_SetUniformVec3(sp, UNIFORM_TCGEN0VECTOR1, vec); } - GLSL_SetUniformMatrix16(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); + GLSL_SetUniformMat4(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); GLSL_SetUniformVec2(sp, UNIFORM_MATERIALINFO, pStage->materialInfo); @@ -1269,11 +1236,12 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) else if ( pStage->bundle[TB_COLORMAP].image[0] != 0 ) R_BindAnimatedImageToTMU( &pStage->bundle[TB_COLORMAP], TB_COLORMAP ); } - else if ( pStage->glslShaderGroup ) + else if ( pStage->glslShaderGroup == tr.lightallShader ) { int i; + vec4_t enableTextures; - if ((backEnd.viewParms.flags & VPF_USESUNLIGHT) && (pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK)) + if (r_sunlightMode->integer && (backEnd.viewParms.flags & VPF_USESUNLIGHT) && (pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK)) { GL_BindToTMU(tr.screenShadowImage, TB_SHADOWMAP); GLSL_SetUniformVec3(sp, UNIFORM_PRIMARYLIGHTAMBIENT, backEnd.refdef.sunAmbCol); @@ -1281,18 +1249,15 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) GLSL_SetUniformVec4(sp, UNIFORM_PRIMARYLIGHTORIGIN, backEnd.refdef.sunDir); } + VectorSet4(enableTextures, 0, 0, 0, 0); if ((r_lightmap->integer == 1 || r_lightmap->integer == 2) && pStage->bundle[TB_LIGHTMAP].image[0]) { for (i = 0; i < NUM_TEXTURE_BUNDLES; i++) { if (i == TB_LIGHTMAP) - { - R_BindAnimatedImageToTMU( &pStage->bundle[i], i); - } - else if (pStage->bundle[i].image[0]) - { - GL_BindToTMU( tr.whiteImage, i); - } + R_BindAnimatedImageToTMU( &pStage->bundle[TB_LIGHTMAP], i); + else + GL_BindToTMU( tr.whiteImage, i ); } } else if (r_lightmap->integer == 3 && pStage->bundle[TB_DELUXEMAP].image[0]) @@ -1300,25 +1265,62 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) for (i = 0; i < NUM_TEXTURE_BUNDLES; i++) { if (i == TB_LIGHTMAP) - { R_BindAnimatedImageToTMU( &pStage->bundle[TB_DELUXEMAP], i); - } - else if (pStage->bundle[i].image[0]) - { - GL_BindToTMU( tr.whiteImage, i); - } + else + GL_BindToTMU( tr.whiteImage, i ); } } else { - for (i = 0; i < NUM_TEXTURE_BUNDLES; i++) + qboolean light = (pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) != 0; + qboolean fastLight = !(r_normalMapping->integer || r_specularMapping->integer); + + if (pStage->bundle[TB_DIFFUSEMAP].image[0]) + R_BindAnimatedImageToTMU( &pStage->bundle[TB_DIFFUSEMAP], TB_DIFFUSEMAP); + + if (pStage->bundle[TB_LIGHTMAP].image[0]) + R_BindAnimatedImageToTMU( &pStage->bundle[TB_LIGHTMAP], TB_LIGHTMAP); + + // bind textures that are sampled and used in the glsl shader, and + // bind whiteImage to textures that are sampled but zeroed in the glsl shader + // + // alternatives: + // - use the last bound texture + // -> costs more to sample a higher res texture then throw out the result + // - disable texture sampling in glsl shader with #ifdefs, as before + // -> increases the number of shaders that must be compiled + // + if (light && !fastLight) { - if (pStage->bundle[i].image[0]) + if (pStage->bundle[TB_NORMALMAP].image[0]) { - R_BindAnimatedImageToTMU( &pStage->bundle[i], i); + R_BindAnimatedImageToTMU( &pStage->bundle[TB_NORMALMAP], TB_NORMALMAP); + enableTextures[0] = 1.0f; } + else if (r_normalMapping->integer) + GL_BindToTMU( tr.whiteImage, TB_NORMALMAP ); + + if (pStage->bundle[TB_DELUXEMAP].image[0]) + { + R_BindAnimatedImageToTMU( &pStage->bundle[TB_DELUXEMAP], TB_DELUXEMAP); + enableTextures[1] = 1.0f; + } + else if (r_deluxeMapping->integer) + GL_BindToTMU( tr.whiteImage, TB_DELUXEMAP ); + + if (pStage->bundle[TB_SPECULARMAP].image[0]) + { + R_BindAnimatedImageToTMU( &pStage->bundle[TB_SPECULARMAP], TB_SPECULARMAP); + enableTextures[2] = 1.0f; + } + else if (r_specularMapping->integer) + GL_BindToTMU( tr.whiteImage, TB_SPECULARMAP ); } + + enableTextures[3] = (r_cubeMapping->integer && !(tr.viewParms.flags & VPF_NOCUBEMAPS) && input->cubemapIndex) ? 1.0f : 0.0f; } + + GLSL_SetUniformVec4(sp, UNIFORM_ENABLETEXTURES, enableTextures); } else if ( pStage->bundle[1].image[0] != 0 ) { @@ -1340,12 +1342,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) // // set state // - if ( pStage->bundle[0].vertexLightmap && ( (r_vertexLight->integer && !r_uiFullScreen->integer) || glConfig.hardwareType == GLHW_PERMEDIA2 ) && r_lightmap->integer ) - { - GL_BindToTMU( tr.whiteImage, 0 ); - } - else - R_BindAnimatedImageToTMU( &pStage->bundle[0], 0 ); + R_BindAnimatedImageToTMU( &pStage->bundle[0], 0 ); GLSL_SetUniformInt(sp, UNIFORM_TEXTURE1ENV, 0); } @@ -1369,7 +1366,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) } // allow skipping out to show just lightmaps during development - if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap || pStage->bundle[0].vertexLightmap ) ) + if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap ) ) { break; } @@ -1394,9 +1391,9 @@ static void RB_RenderShadowmap( shaderCommands_t *input ) GLSL_BindProgram(sp); - GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - GLSL_SetUniformMatrix16(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); + GLSL_SetUniformMat4(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); @@ -1555,8 +1552,8 @@ void RB_StageIteratorGeneric( void ) // // pshadows! // - if (glRefConfig.framebufferObject && tess.pshadowBits && tess.shader->sort <= SS_OPAQUE - && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) { + if (glRefConfig.framebufferObject && r_shadows->integer == 4 && tess.pshadowBits + && tess.shader->sort <= SS_OPAQUE && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) { ProjectPshadowVBOGLSL(); } diff --git a/code/renderergl2/tr_shade_calc.c b/code/renderergl2/tr_shade_calc.c index a5c4e9ab..c9816fa8 100644 --- a/code/renderergl2/tr_shade_calc.c +++ b/code/renderergl2/tr_shade_calc.c @@ -84,42 +84,16 @@ static float EvalWaveFormClamped( const waveForm_t *wf ) } /* -** RB_CalcStretchTexCoords +** RB_CalcStretchTexMatrix */ -void RB_CalcStretchTexCoords( const waveForm_t *wf, float *st ) -{ - float p; - texModInfo_t tmi; - - p = 1.0f / EvalWaveForm( wf ); - - tmi.matrix[0][0] = p; - tmi.matrix[1][0] = 0; - tmi.translate[0] = 0.5f - 0.5f * p; - - tmi.matrix[0][1] = 0; - tmi.matrix[1][1] = p; - tmi.translate[1] = 0.5f - 0.5f * p; - - RB_CalcTransformTexCoords( &tmi, st ); -} - void RB_CalcStretchTexMatrix( const waveForm_t *wf, float *matrix ) { float p; - texModInfo_t tmi; p = 1.0f / EvalWaveForm( wf ); - tmi.matrix[0][0] = p; - tmi.matrix[1][0] = 0; - tmi.translate[0] = 0.5f - 0.5f * p; - - tmi.matrix[0][1] = 0; - tmi.matrix[1][1] = p; - tmi.translate[1] = 0.5f - 0.5f * p; - - RB_CalcTransformTexMatrix( &tmi, matrix ); + matrix[0] = p; matrix[2] = 0; matrix[4] = 0.5f - 0.5f * p; + matrix[1] = 0; matrix[3] = p; matrix[5] = 0.5f - 0.5f * p; } /* @@ -142,27 +116,27 @@ void RB_CalcDeformVertexes( deformStage_t *ds ) vec3_t offset; float scale; float *xyz = ( float * ) tess.xyz; - float *normal = ( float * ) tess.normal; + uint32_t *normal = tess.normal; float *table; if ( ds->deformationWave.frequency == 0 ) { scale = EvalWaveForm( &ds->deformationWave ); - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) + for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal++ ) { - VectorScale( normal, scale, offset ); + R_VboUnpackNormal(offset, *normal); - xyz[0] += offset[0]; - xyz[1] += offset[1]; - xyz[2] += offset[2]; + xyz[0] += offset[0] * scale; + xyz[1] += offset[1] * scale; + xyz[2] += offset[2] * scale; } } else { table = TableForFunc( ds->deformationWave.func ); - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) + for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal++ ) { float off = ( xyz[0] + xyz[1] + xyz[2] ) * ds->deformationSpread; @@ -171,11 +145,11 @@ void RB_CalcDeformVertexes( deformStage_t *ds ) ds->deformationWave.phase + off, ds->deformationWave.frequency ); - VectorScale( normal, scale, offset ); - - xyz[0] += offset[0]; - xyz[1] += offset[1]; - xyz[2] += offset[2]; + R_VboUnpackNormal(offset, *normal); + + xyz[0] += offset[0] * scale; + xyz[1] += offset[1] * scale; + xyz[2] += offset[2] * scale; } } } @@ -191,25 +165,31 @@ void RB_CalcDeformNormals( deformStage_t *ds ) { int i; float scale; float *xyz = ( float * ) tess.xyz; - float *normal = ( float * ) tess.normal; + uint32_t *normal = tess.normal; + + for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal++ ) { + vec3_t fNormal; + + R_VboUnpackNormal(fNormal, *normal); - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) { scale = 0.98f; scale = R_NoiseGet4f( xyz[0] * scale, xyz[1] * scale, xyz[2] * scale, tess.shaderTime * ds->deformationWave.frequency ); - normal[ 0 ] += ds->deformationWave.amplitude * scale; + fNormal[ 0 ] += ds->deformationWave.amplitude * scale; scale = 0.98f; scale = R_NoiseGet4f( 100 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale, tess.shaderTime * ds->deformationWave.frequency ); - normal[ 1 ] += ds->deformationWave.amplitude * scale; + fNormal[ 1 ] += ds->deformationWave.amplitude * scale; scale = 0.98f; scale = R_NoiseGet4f( 200 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale, tess.shaderTime * ds->deformationWave.frequency ); - normal[ 2 ] += ds->deformationWave.amplitude * scale; + fNormal[ 2 ] += ds->deformationWave.amplitude * scale; - VectorNormalizeFast( normal ); + VectorNormalizeFast( fNormal ); + + *normal = R_VboPackNormal(fNormal); } } @@ -223,22 +203,25 @@ void RB_CalcBulgeVertexes( deformStage_t *ds ) { int i; const float *st = ( const float * ) tess.texCoords[0]; float *xyz = ( float * ) tess.xyz; - float *normal = ( float * ) tess.normal; + uint32_t *normal = tess.normal; float now; now = backEnd.refdef.time * ds->bulgeSpeed * 0.001f; - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, st += 4, normal += 4 ) { + for ( i = 0; i < tess.numVertexes; i++, xyz += 4, st += 4, normal++ ) { int off; float scale; + vec3_t fNormal; + + R_VboUnpackNormal(fNormal, *normal); off = (float)( FUNCTABLE_SIZE / (M_PI*2) ) * ( st[0] * ds->bulgeWidth + now ); scale = tr.sinTable[ off & FUNCTABLE_MASK ] * ds->bulgeHeight; - xyz[0] += normal[0] * scale; - xyz[1] += normal[1] * scale; - xyz[2] += normal[2] * scale; + xyz[0] += fNormal[0] * scale; + xyz[1] += fNormal[1] * scale; + xyz[2] += fNormal[2] * scale; } } @@ -288,11 +271,14 @@ void DeformText( const char *text ) { float color[4]; float bottom, top; vec3_t mid; + vec3_t fNormal; height[0] = 0; height[1] = 0; height[2] = -1; - CrossProduct( tess.normal[0], height, width ); + + R_VboUnpackNormal(fNormal, tess.normal[0]); + CrossProduct( fNormal, height, width ); // find the midpoint of the box VectorClear( mid ); @@ -618,88 +604,6 @@ COLORS */ -/* -** RB_CalcColorFromEntity -*/ -void RB_CalcColorFromEntity( unsigned char *dstColors ) -{ - int i; - int *pColors = ( int * ) dstColors; - int c; - - if ( !backEnd.currentEntity ) - return; - - c = * ( int * ) backEnd.currentEntity->e.shaderRGBA; - - for ( i = 0; i < tess.numVertexes; i++, pColors++ ) - { - *pColors = c; - } -} - -/* -** RB_CalcColorFromOneMinusEntity -*/ -void RB_CalcColorFromOneMinusEntity( unsigned char *dstColors ) -{ - int i; - int *pColors = ( int * ) dstColors; - unsigned char invModulate[4]; - int c; - - if ( !backEnd.currentEntity ) - return; - - invModulate[0] = 255 - backEnd.currentEntity->e.shaderRGBA[0]; - invModulate[1] = 255 - backEnd.currentEntity->e.shaderRGBA[1]; - invModulate[2] = 255 - backEnd.currentEntity->e.shaderRGBA[2]; - invModulate[3] = 255 - backEnd.currentEntity->e.shaderRGBA[3]; // this trashes alpha, but the AGEN block fixes it - - c = * ( int * ) invModulate; - - for ( i = 0; i < tess.numVertexes; i++, pColors++ ) - { - *pColors = c; - } -} - -/* -** RB_CalcAlphaFromEntity -*/ -void RB_CalcAlphaFromEntity( unsigned char *dstColors ) -{ - int i; - - if ( !backEnd.currentEntity ) - return; - - dstColors += 3; - - for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 ) - { - *dstColors = backEnd.currentEntity->e.shaderRGBA[3]; - } -} - -/* -** RB_CalcAlphaFromOneMinusEntity -*/ -void RB_CalcAlphaFromOneMinusEntity( unsigned char *dstColors ) -{ - int i; - - if ( !backEnd.currentEntity ) - return; - - dstColors += 3; - - for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 ) - { - *dstColors = 0xff - backEnd.currentEntity->e.shaderRGBA[3]; - } -} - /* ** RB_CalcWaveColorSingle */ @@ -723,29 +627,6 @@ float RB_CalcWaveColorSingle( const waveForm_t *wf ) return glow; } -/* -** RB_CalcWaveColor -*/ -void RB_CalcWaveColor( const waveForm_t *wf, unsigned char *dstColors ) -{ - int i; - int v; - float glow; - int *colors = ( int * ) dstColors; - byte color[4]; - - glow = RB_CalcWaveColorSingle( wf ); - - v = ri.ftol(255 * glow); - color[0] = color[1] = color[2] = v; - color[3] = 255; - v = *(int *)color; - - for ( i = 0; i < tess.numVertexes; i++, colors++ ) { - *colors = v; - } -} - /* ** RB_CalcWaveAlphaSingle */ @@ -754,25 +635,6 @@ float RB_CalcWaveAlphaSingle( const waveForm_t *wf ) return EvalWaveFormClamped( wf ); } -/* -** RB_CalcWaveAlpha -*/ -void RB_CalcWaveAlpha( const waveForm_t *wf, unsigned char *dstColors ) -{ - int i; - int v; - float glow; - - glow = EvalWaveFormClamped( wf ); - - v = 255 * glow; - - for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 ) - { - dstColors[3] = v; - } -} - /* ** RB_CalcModulateColorsByFog */ @@ -793,45 +655,6 @@ void RB_CalcModulateColorsByFog( unsigned char *colors ) { } } -/* -** RB_CalcModulateAlphasByFog -*/ -void RB_CalcModulateAlphasByFog( unsigned char *colors ) { - int i; - float texCoords[SHADER_MAX_VERTEXES][2]; - - // calculate texcoords so we can derive density - // this is not wasted, because it would only have - // been previously called if the surface was opaque - RB_CalcFogTexCoords( texCoords[0] ); - - for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) { - float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] ); - colors[3] *= f; - } -} - -/* -** RB_CalcModulateRGBAsByFog -*/ -void RB_CalcModulateRGBAsByFog( unsigned char *colors ) { - int i; - float texCoords[SHADER_MAX_VERTEXES][2]; - - // calculate texcoords so we can derive density - // this is not wasted, because it would only have - // been previously called if the surface was opaque - RB_CalcFogTexCoords( texCoords[0] ); - - for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) { - float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] ); - colors[0] *= f; - colors[1] *= f; - colors[2] *= f; - colors[3] *= f; - } -} - /* ==================================================================== @@ -928,118 +751,27 @@ void RB_CalcFogTexCoords( float *st ) { } } - - /* -** RB_CalcEnvironmentTexCoords +** RB_CalcTurbulentFactors */ -void RB_CalcEnvironmentTexCoords( float *st ) +void RB_CalcTurbulentFactors( const waveForm_t *wf, float *amplitude, float *now ) { - int i; - float *v, *normal; - vec3_t viewer, reflected; - float d; - - v = tess.xyz[0]; - normal = tess.normal[0]; - - for (i = 0 ; i < tess.numVertexes ; i++, v += 4, normal += 4, st += 2 ) - { - VectorSubtract (backEnd.or.viewOrigin, v, viewer); - VectorNormalizeFast (viewer); - - d = DotProduct (normal, viewer); - - reflected[0] = normal[0]*2*d - viewer[0]; - reflected[1] = normal[1]*2*d - viewer[1]; - reflected[2] = normal[2]*2*d - viewer[2]; - - st[0] = 0.5 + reflected[1] * 0.5; - st[1] = 0.5 - reflected[2] * 0.5; - } + *now = wf->phase + tess.shaderTime * wf->frequency; + *amplitude = wf->amplitude; } /* -** RB_CalcTurbulentTexCoords +** RB_CalcScaleTexMatrix */ -void RB_CalcTurbulentTexCoords( const waveForm_t *wf, float *st ) -{ - int i; - float now; - - now = ( wf->phase + tess.shaderTime * wf->frequency ); - - for ( i = 0; i < tess.numVertexes; i++, st += 2 ) - { - float s = st[0]; - float t = st[1]; - - st[0] = s + tr.sinTable[ ( ( int ) ( ( ( tess.xyz[i][0] + tess.xyz[i][2] )* 1.0/128 * 0.125 + now ) * FUNCTABLE_SIZE ) ) & ( FUNCTABLE_MASK ) ] * wf->amplitude; - st[1] = t + tr.sinTable[ ( ( int ) ( ( tess.xyz[i][1] * 1.0/128 * 0.125 + now ) * FUNCTABLE_SIZE ) ) & ( FUNCTABLE_MASK ) ] * wf->amplitude; - } -} - -void RB_CalcTurbulentTexMatrix( const waveForm_t *wf, matrix_t matrix ) -{ - float now; - - now = ( wf->phase + tess.shaderTime * wf->frequency ); - - // bit of a hack here, hide amplitude and now in the matrix - // the vertex program will extract them and perform a turbulent pass last if it's nonzero - - matrix[ 0] = 1.0f; matrix[ 4] = 0.0f; matrix[ 8] = 0.0f; matrix[12] = wf->amplitude; - matrix[ 1] = 0.0f; matrix[ 5] = 1.0f; matrix[ 9] = 0.0f; matrix[13] = now; - matrix[ 2] = 0.0f; matrix[ 6] = 0.0f; matrix[10] = 1.0f; matrix[14] = 0.0f; - matrix[ 3] = 0.0f; matrix[ 7] = 0.0f; matrix[11] = 0.0f; matrix[15] = 1.0f; -} - -/* -** RB_CalcScaleTexCoords -*/ -void RB_CalcScaleTexCoords( const float scale[2], float *st ) -{ - int i; - - for ( i = 0; i < tess.numVertexes; i++, st += 2 ) - { - st[0] *= scale[0]; - st[1] *= scale[1]; - } -} - void RB_CalcScaleTexMatrix( const float scale[2], float *matrix ) { - matrix[ 0] = scale[0]; matrix[ 4] = 0.0f; matrix[ 8] = 0.0f; matrix[12] = 0.0f; - matrix[ 1] = 0.0f; matrix[ 5] = scale[1]; matrix[ 9] = 0.0f; matrix[13] = 0.0f; - matrix[ 2] = 0.0f; matrix[ 6] = 0.0f; matrix[10] = 1.0f; matrix[14] = 0.0f; - matrix[ 3] = 0.0f; matrix[ 7] = 0.0f; matrix[11] = 0.0f; matrix[15] = 1.0f; + matrix[0] = scale[0]; matrix[2] = 0.0f; matrix[4] = 0.0f; + matrix[1] = 0.0f; matrix[3] = scale[1]; matrix[5] = 0.0f; } /* -** RB_CalcScrollTexCoords +** RB_CalcScrollTexMatrix */ -void RB_CalcScrollTexCoords( const float scrollSpeed[2], float *st ) -{ - int i; - float timeScale = tess.shaderTime; - float adjustedScrollS, adjustedScrollT; - - adjustedScrollS = scrollSpeed[0] * timeScale; - adjustedScrollT = scrollSpeed[1] * timeScale; - - // clamp so coordinates don't continuously get larger, causing problems - // with hardware limits - adjustedScrollS = adjustedScrollS - floor( adjustedScrollS ); - adjustedScrollT = adjustedScrollT - floor( adjustedScrollT ); - - for ( i = 0; i < tess.numVertexes; i++, st += 2 ) - { - st[0] += adjustedScrollS; - st[1] += adjustedScrollT; - } -} - void RB_CalcScrollTexMatrix( const float scrollSpeed[2], float *matrix ) { float timeScale = tess.shaderTime; @@ -1053,73 +785,28 @@ void RB_CalcScrollTexMatrix( const float scrollSpeed[2], float *matrix ) adjustedScrollS = adjustedScrollS - floor( adjustedScrollS ); adjustedScrollT = adjustedScrollT - floor( adjustedScrollT ); - - matrix[ 0] = 1.0f; matrix[ 4] = 0.0f; matrix[ 8] = adjustedScrollS; matrix[12] = 0.0f; - matrix[ 1] = 0.0f; matrix[ 5] = 1.0f; matrix[ 9] = adjustedScrollT; matrix[13] = 0.0f; - matrix[ 2] = 0.0f; matrix[ 6] = 0.0f; matrix[10] = 1.0f; matrix[14] = 0.0f; - matrix[ 3] = 0.0f; matrix[ 7] = 0.0f; matrix[11] = 0.0f; matrix[15] = 1.0f; + matrix[0] = 1.0f; matrix[2] = 0.0f; matrix[4] = adjustedScrollS; + matrix[1] = 0.0f; matrix[3] = 1.0f; matrix[5] = adjustedScrollT; } /* -** RB_CalcTransformTexCoords +** RB_CalcTransformTexMatrix */ -void RB_CalcTransformTexCoords( const texModInfo_t *tmi, float *st ) -{ - int i; - - for ( i = 0; i < tess.numVertexes; i++, st += 2 ) - { - float s = st[0]; - float t = st[1]; - - st[0] = s * tmi->matrix[0][0] + t * tmi->matrix[1][0] + tmi->translate[0]; - st[1] = s * tmi->matrix[0][1] + t * tmi->matrix[1][1] + tmi->translate[1]; - } -} - void RB_CalcTransformTexMatrix( const texModInfo_t *tmi, float *matrix ) { - matrix[ 0] = tmi->matrix[0][0]; matrix[ 4] = tmi->matrix[1][0]; matrix[ 8] = tmi->translate[0]; matrix[12] = 0.0f; - matrix[ 1] = tmi->matrix[0][1]; matrix[ 5] = tmi->matrix[1][1]; matrix[ 9] = tmi->translate[1]; matrix[13] = 0.0f; - matrix[ 2] = 0.0f; matrix[ 6] = 0.0f; matrix[10] = 1.0f; matrix[14] = 0.0f; - matrix[ 3] = 0.0f; matrix[ 7] = 0.0f; matrix[11] = 0.0f; matrix[15] = 1.0f; + matrix[0] = tmi->matrix[0][0]; matrix[2] = tmi->matrix[1][0]; matrix[4] = tmi->translate[0]; + matrix[1] = tmi->matrix[0][1]; matrix[3] = tmi->matrix[1][1]; matrix[5] = tmi->translate[1]; } /* -** RB_CalcRotateTexCoords +** RB_CalcRotateTexMatrix */ -void RB_CalcRotateTexCoords( float degsPerSecond, float *st ) -{ - float timeScale = tess.shaderTime; - float degs; - int index; - float sinValue, cosValue; - texModInfo_t tmi; - - degs = -degsPerSecond * timeScale; - index = degs * ( FUNCTABLE_SIZE / 360.0f ); - - sinValue = tr.sinTable[ index & FUNCTABLE_MASK ]; - cosValue = tr.sinTable[ ( index + FUNCTABLE_SIZE / 4 ) & FUNCTABLE_MASK ]; - - tmi.matrix[0][0] = cosValue; - tmi.matrix[1][0] = -sinValue; - tmi.translate[0] = 0.5 - 0.5 * cosValue + 0.5 * sinValue; - - tmi.matrix[0][1] = sinValue; - tmi.matrix[1][1] = cosValue; - tmi.translate[1] = 0.5 - 0.5 * sinValue - 0.5 * cosValue; - - RB_CalcTransformTexCoords( &tmi, st ); -} - void RB_CalcRotateTexMatrix( float degsPerSecond, float *matrix ) { float timeScale = tess.shaderTime; float degs; int index; float sinValue, cosValue; - texModInfo_t tmi; degs = -degsPerSecond * timeScale; index = degs * ( FUNCTABLE_SIZE / 360.0f ); @@ -1127,213 +814,6 @@ void RB_CalcRotateTexMatrix( float degsPerSecond, float *matrix ) sinValue = tr.sinTable[ index & FUNCTABLE_MASK ]; cosValue = tr.sinTable[ ( index + FUNCTABLE_SIZE / 4 ) & FUNCTABLE_MASK ]; - tmi.matrix[0][0] = cosValue; - tmi.matrix[1][0] = -sinValue; - tmi.translate[0] = 0.5 - 0.5 * cosValue + 0.5 * sinValue; - - tmi.matrix[0][1] = sinValue; - tmi.matrix[1][1] = cosValue; - tmi.translate[1] = 0.5 - 0.5 * sinValue - 0.5 * cosValue; - - RB_CalcTransformTexMatrix( &tmi, matrix ); + matrix[0] = cosValue; matrix[2] = -sinValue; matrix[4] = 0.5 - 0.5 * cosValue + 0.5 * sinValue; + matrix[1] = sinValue; matrix[3] = cosValue; matrix[5] = 0.5 - 0.5 * sinValue - 0.5 * cosValue; } -/* -** RB_CalcSpecularAlpha -** -** Calculates specular coefficient and places it in the alpha channel -*/ -vec3_t lightOrigin = { -960, 1980, 96 }; // FIXME: track dynamically - -void RB_CalcSpecularAlpha( unsigned char *alphas ) { - int i; - float *v, *normal; - vec3_t viewer, reflected; - float l, d; - int b; - vec3_t lightDir; - int numVertexes; - - v = tess.xyz[0]; - normal = tess.normal[0]; - - alphas += 3; - - numVertexes = tess.numVertexes; - for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4, alphas += 4) { - float ilength; - - VectorSubtract( lightOrigin, v, lightDir ); -// ilength = Q_rsqrt( DotProduct( lightDir, lightDir ) ); - VectorNormalizeFast( lightDir ); - - // calculate the specular color - d = DotProduct (normal, lightDir); -// d *= ilength; - - // we don't optimize for the d < 0 case since this tends to - // cause visual artifacts such as faceted "snapping" - reflected[0] = normal[0]*2*d - lightDir[0]; - reflected[1] = normal[1]*2*d - lightDir[1]; - reflected[2] = normal[2]*2*d - lightDir[2]; - - VectorSubtract (backEnd.or.viewOrigin, v, viewer); - ilength = Q_rsqrt( DotProduct( viewer, viewer ) ); - l = DotProduct (reflected, viewer); - l *= ilength; - - if (l < 0) { - b = 0; - } else { - l = l*l; - l = l*l; - b = l * 255; - if (b > 255) { - b = 255; - } - } - - *alphas = b; - } -} - -/* -** RB_CalcDiffuseColor -** -** The basic vertex lighting calc -*/ -#if idppc_altivec -static void RB_CalcDiffuseColor_altivec( unsigned char *colors ) -{ - int i; - float *v, *normal; - trRefEntity_t *ent; - int ambientLightInt; - vec3_t lightDir; - int numVertexes; - vector unsigned char vSel = VECCONST_UINT8(0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff); - vector float ambientLightVec; - vector float directedLightVec; - vector float lightDirVec; - vector float normalVec0, normalVec1; - vector float incomingVec0, incomingVec1, incomingVec2; - vector float zero, jVec; - vector signed int jVecInt; - vector signed short jVecShort; - vector unsigned char jVecChar, normalPerm; - ent = backEnd.currentEntity; - ambientLightInt = ent->ambientLightInt; - // A lot of this could be simplified if we made sure - // entities light info was 16-byte aligned. - jVecChar = vec_lvsl(0, ent->ambientLight); - ambientLightVec = vec_ld(0, (vector float *)ent->ambientLight); - jVec = vec_ld(11, (vector float *)ent->ambientLight); - ambientLightVec = vec_perm(ambientLightVec,jVec,jVecChar); - - jVecChar = vec_lvsl(0, ent->directedLight); - directedLightVec = vec_ld(0,(vector float *)ent->directedLight); - jVec = vec_ld(11,(vector float *)ent->directedLight); - directedLightVec = vec_perm(directedLightVec,jVec,jVecChar); - - jVecChar = vec_lvsl(0, ent->lightDir); - lightDirVec = vec_ld(0,(vector float *)ent->lightDir); - jVec = vec_ld(11,(vector float *)ent->lightDir); - lightDirVec = vec_perm(lightDirVec,jVec,jVecChar); - - zero = (vector float)vec_splat_s8(0); - VectorCopy( ent->lightDir, lightDir ); - - v = tess.xyz[0]; - normal = tess.normal[0]; - - normalPerm = vec_lvsl(0,normal); - numVertexes = tess.numVertexes; - for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) { - normalVec0 = vec_ld(0,(vector float *)normal); - normalVec1 = vec_ld(11,(vector float *)normal); - normalVec0 = vec_perm(normalVec0,normalVec1,normalPerm); - incomingVec0 = vec_madd(normalVec0, lightDirVec, zero); - incomingVec1 = vec_sld(incomingVec0,incomingVec0,4); - incomingVec2 = vec_add(incomingVec0,incomingVec1); - incomingVec1 = vec_sld(incomingVec1,incomingVec1,4); - incomingVec2 = vec_add(incomingVec2,incomingVec1); - incomingVec0 = vec_splat(incomingVec2,0); - incomingVec0 = vec_max(incomingVec0,zero); - normalPerm = vec_lvsl(12,normal); - jVec = vec_madd(incomingVec0, directedLightVec, ambientLightVec); - jVecInt = vec_cts(jVec,0); // RGBx - jVecShort = vec_pack(jVecInt,jVecInt); // RGBxRGBx - jVecChar = vec_packsu(jVecShort,jVecShort); // RGBxRGBxRGBxRGBx - jVecChar = vec_sel(jVecChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255 - vec_ste((vector unsigned int)jVecChar,0,(unsigned int *)&colors[i*4]); // store color - } -} -#endif - -static void RB_CalcDiffuseColor_scalar( unsigned char *colors ) -{ - int i, j; - float *v, *normal; - float incoming; - trRefEntity_t *ent; - int ambientLightInt; - vec3_t ambientLight; - vec3_t lightDir; - vec3_t directedLight; - int numVertexes; - ent = backEnd.currentEntity; - ambientLightInt = ent->ambientLightInt; - VectorCopy( ent->ambientLight, ambientLight ); - VectorCopy( ent->directedLight, directedLight ); - VectorCopy( ent->lightDir, lightDir ); - - v = tess.xyz[0]; - normal = tess.normal[0]; - - numVertexes = tess.numVertexes; - for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) { - incoming = DotProduct (normal, lightDir); - if ( incoming <= 0 ) { - *(int *)&colors[i*4] = ambientLightInt; - continue; - } - j = ri.ftol(ambientLight[0] + incoming * directedLight[0]); - if ( j > 255 ) { - j = 255; - } - colors[i*4+0] = j; - - j = ri.ftol(ambientLight[1] + incoming * directedLight[1]); - if ( j > 255 ) { - j = 255; - } - colors[i*4+1] = j; - - j = ri.ftol(ambientLight[2] + incoming * directedLight[2]); - if ( j > 255 ) { - j = 255; - } - colors[i*4+2] = j; - - colors[i*4+3] = 255; - } -} - -void RB_CalcDiffuseColor( unsigned char *colors ) -{ -#if idppc_altivec - if (com_altivec->integer) { - // must be in a seperate function or G3 systems will crash. - RB_CalcDiffuseColor_altivec( colors ); - return; - } -#endif - RB_CalcDiffuseColor_scalar( colors ); -} - - - - - diff --git a/code/renderergl2/tr_shader.c b/code/renderergl2/tr_shader.c index c246127d..6dbac55a 100644 --- a/code/renderergl2/tr_shader.c +++ b/code/renderergl2/tr_shader.c @@ -203,10 +203,16 @@ static int NameToSrcBlendMode( const char *name ) } else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) ) { + if (r_ignoreDstAlpha->integer) + return GLS_SRCBLEND_ONE; + return GLS_SRCBLEND_DST_ALPHA; } else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) ) { + if (r_ignoreDstAlpha->integer) + return GLS_SRCBLEND_ZERO; + return GLS_SRCBLEND_ONE_MINUS_DST_ALPHA; } else if ( !Q_stricmp( name, "GL_SRC_ALPHA_SATURATE" ) ) @@ -243,10 +249,16 @@ static int NameToDstBlendMode( const char *name ) } else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) ) { + if (r_ignoreDstAlpha->integer) + return GLS_DSTBLEND_ONE; + return GLS_DSTBLEND_DST_ALPHA; } else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) ) { + if (r_ignoreDstAlpha->integer) + return GLS_DSTBLEND_ZERO; + return GLS_DSTBLEND_ONE_MINUS_DST_ALPHA; } else if ( !Q_stricmp( name, "GL_SRC_COLOR" ) ) @@ -1109,10 +1121,6 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) shader.portalRange = atof( token ); } } - else if ( !Q_stricmp( token, "fresnel" ) ) - { - stage->alphaGen = AGEN_FRESNEL; - } else { ri.Printf( PRINT_WARNING, "WARNING: unknown alphaGen parameter '%s' in shader '%s'\n", token, shader.name ); @@ -1951,7 +1959,7 @@ static void ComputeVertexAttribs(void) #ifdef USE_VERT_TANGENT_SPACE if ((pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) && !(r_normalMapping->integer == 0 && r_specularMapping->integer == 0)) { - shader.vertexAttribs |= ATTR_BITANGENT | ATTR_TANGENT; + shader.vertexAttribs |= ATTR_TANGENT; } #endif @@ -2011,7 +2019,6 @@ static void ComputeVertexAttribs(void) switch(pStage->alphaGen) { case AGEN_LIGHTING_SPECULAR: - case AGEN_FRESNEL: shader.vertexAttribs |= ATTR_NORMAL; break; @@ -2213,7 +2220,6 @@ static void CollapseStagesToLightall(shaderStage_t *diffuse, //ri.Printf(PRINT_ALL, ", deluxemap"); diffuse->bundle[TB_DELUXEMAP] = lightmap->bundle[0]; diffuse->bundle[TB_DELUXEMAP].image[0] = tr.deluxemaps[shader.lightmapIndex]; - defs |= LIGHTDEF_USE_DELUXEMAP; } if (r_normalMapping->integer) @@ -2247,15 +2253,6 @@ static void CollapseStagesToLightall(shaderStage_t *diffuse, defs |= LIGHTDEF_USE_PARALLAXMAP; } } - - if (!diffuse->bundle[TB_NORMALMAP].image[0]) - { - // use 0x80 image, shader will interpret as (0,0,1) - diffuse->bundle[TB_NORMALMAP] = diffuse->bundle[0]; - diffuse->bundle[TB_NORMALMAP].numImageAnimations = 0; - diffuse->bundle[TB_NORMALMAP].image[0] = tr.greyImage; - //ri.Printf(PRINT_ALL, ", normalmap %s", diffuse->bundle[TB_NORMALMAP].image[0]->imgName); - } } if (r_specularMapping->integer) @@ -2267,18 +2264,6 @@ static void CollapseStagesToLightall(shaderStage_t *diffuse, diffuse->materialInfo[0] = specular->materialInfo[0]; diffuse->materialInfo[1] = specular->materialInfo[1]; } - else if (lightmap || useLightVector || useLightVertex) - { - // use a white image, materialinfo will do the rest - diffuse->bundle[TB_SPECULARMAP] = diffuse->bundle[0]; - diffuse->bundle[TB_SPECULARMAP].numImageAnimations = 0; - diffuse->bundle[TB_SPECULARMAP].image[0] = tr.whiteImage; - if (!diffuse->materialInfo[0]) - diffuse->materialInfo[0] = r_baseSpecular->value; - if (!diffuse->materialInfo[1]) - diffuse->materialInfo[1] = r_baseGloss->value; - //ri.Printf(PRINT_ALL, ", specularmap %s", diffuse->bundle[TB_SPECULARMAP].image[0]->imgName); - } } if (tcgen || diffuse->bundle[0].numTexMods) @@ -2308,7 +2293,7 @@ static qboolean CollapseStagesToGLSL(void) { // if 2+ stages and first stage is lightmap, switch them // this makes it easier for the later bits to process - if (stages[0].active && stages[0].bundle[0].isLightmap && stages[1].active) + if (stages[0].active && stages[0].bundle[0].tcGen == TCGEN_LIGHTMAP && stages[1].active) { int blendBits = stages[1].stateBits & ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); @@ -2345,7 +2330,7 @@ static qboolean CollapseStagesToGLSL(void) break; } - if (pStage->bundle[0].isLightmap) + if (pStage->bundle[0].tcGen == TCGEN_LIGHTMAP) { int blendBits = pStage->stateBits & ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); @@ -2362,6 +2347,7 @@ static qboolean CollapseStagesToGLSL(void) case TCGEN_TEXTURE: case TCGEN_LIGHTMAP: case TCGEN_ENVIRONMENT_MAPPED: + case TCGEN_VECTOR: break; default: skip = qtrue; @@ -2372,7 +2358,6 @@ static qboolean CollapseStagesToGLSL(void) { case AGEN_LIGHTING_SPECULAR: case AGEN_PORTAL: - case AGEN_FRESNEL: skip = qtrue; break; default: @@ -2397,7 +2382,7 @@ static qboolean CollapseStagesToGLSL(void) continue; // skip lightmaps - if (pStage->bundle[0].isLightmap) + if (pStage->bundle[0].tcGen == TCGEN_LIGHTMAP) continue; diffuse = pStage; @@ -2439,7 +2424,7 @@ static qboolean CollapseStagesToGLSL(void) break; case ST_COLORMAP: - if (pStage2->bundle[0].isLightmap) + if (pStage2->bundle[0].tcGen == TCGEN_LIGHTMAP) { lightmap = pStage2; } @@ -2481,7 +2466,7 @@ static qboolean CollapseStagesToGLSL(void) if (!pStage->active) continue; - if (pStage->bundle[0].isLightmap) + if (pStage->bundle[0].tcGen == TCGEN_LIGHTMAP) { pStage->active = qfalse; } @@ -2547,15 +2532,14 @@ static qboolean CollapseStagesToGLSL(void) if (pStage->adjustColorsForFog) continue; - if (pStage->bundle[TB_DIFFUSEMAP].isLightmap) + if (pStage->bundle[TB_DIFFUSEMAP].tcGen == TCGEN_LIGHTMAP) { pStage->glslShaderGroup = tr.lightallShader; pStage->glslShaderIndex = LIGHTDEF_USE_LIGHTMAP; - if (r_deluxeMapping->integer && tr.worldDeluxeMapping) - pStage->glslShaderIndex |= LIGHTDEF_USE_DELUXEMAP; pStage->bundle[TB_LIGHTMAP] = pStage->bundle[TB_DIFFUSEMAP]; pStage->bundle[TB_DIFFUSEMAP].image[0] = tr.whiteImage; pStage->bundle[TB_DIFFUSEMAP].isLightmap = qfalse; + pStage->bundle[TB_DIFFUSEMAP].tcGen = TCGEN_TEXTURE; } } } @@ -2577,11 +2561,14 @@ static qboolean CollapseStagesToGLSL(void) { pStage->glslShaderGroup = tr.lightallShader; pStage->glslShaderIndex = LIGHTDEF_USE_LIGHT_VECTOR; + + if (pStage->bundle[0].tcGen != TCGEN_TEXTURE || pStage->bundle[0].numTexMods != 0) + pStage->glslShaderIndex |= LIGHTDEF_USE_TCGEN_AND_TCMOD; } } } - // convert any remaining lightingdiffuse stages to a lighting pass + // insert default material info if needed for (i = 0; i < MAX_SHADER_STAGES; i++) { shaderStage_t *pStage = &stages[i]; @@ -2589,14 +2576,21 @@ static qboolean CollapseStagesToGLSL(void) if (!pStage->active) continue; - if (pStage->rgbGen == CGEN_LIGHTING_DIFFUSE) + if (pStage->glslShaderGroup != tr.lightallShader) + continue; + + if ((pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) == 0) + continue; + + if (!pStage->bundle[TB_SPECULARMAP].image[0] && r_specularMapping->integer) { - pStage->glslShaderGroup = tr.lightallShader; - pStage->glslShaderIndex = LIGHTDEF_USE_LIGHT_VECTOR; + if (!pStage->materialInfo[0]) + pStage->materialInfo[0] = r_baseSpecular->value; + if (!pStage->materialInfo[1]) + pStage->materialInfo[1] = r_baseGloss->value; } } - return numStages; } diff --git a/code/renderergl2/tr_sky.c b/code/renderergl2/tr_sky.c index 7fd4b3aa..6a220318 100644 --- a/code/renderergl2/tr_sky.c +++ b/code/renderergl2/tr_sky.c @@ -429,7 +429,7 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max GLSL_VertexAttribsState(ATTR_POSITION | ATTR_TEXCOORD); GLSL_BindProgram(sp); - GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); color[0] = color[1] = @@ -445,11 +445,11 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max GLSL_VertexAttribsState(ATTR_POSITION | ATTR_TEXCOORD); GLSL_BindProgram(sp); - GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); color[0] = color[1] = - color[2] = tr.identityLight * backEnd.refdef.colorScale; + color[2] = (r_softOverbright->integer ? 1.0 : tr.identityLight) * backEnd.refdef.colorScale; color[3] = 1.0f; GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, color); @@ -468,7 +468,7 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max R_DrawElementsVBO(tess.numIndexes - tess.firstIndex, tess.firstIndex, tess.minIndex, tess.maxIndex); - //qglDrawElements(GL_TRIANGLES, tess.numIndexes - tess.firstIndex, GL_INDEX_TYPE, BUFFER_OFFSET(tess.firstIndex * sizeof(GL_INDEX_TYPE))); + //qglDrawElements(GL_TRIANGLES, tess.numIndexes - tess.firstIndex, GL_INDEX_TYPE, BUFFER_OFFSET(tess.firstIndex * sizeof(glIndex_t))); //R_BindNullVBO(); //R_BindNullIBO(); @@ -806,10 +806,10 @@ void RB_DrawSun( float scale, shader_t *shader ) { //qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); { // FIXME: this could be a lot cleaner - matrix_t translation, modelview; + mat4_t translation, modelview; - Matrix16Translation( backEnd.viewParms.or.origin, translation ); - Matrix16Multiply( backEnd.viewParms.world.modelMatrix, translation, modelview ); + Mat4Translation( backEnd.viewParms.or.origin, translation ); + Mat4Multiply( backEnd.viewParms.world.modelMatrix, translation, modelview ); GL_SetModelviewMatrix( modelview ); } @@ -869,18 +869,18 @@ void RB_StageIteratorSky( void ) { // draw the outer skybox if ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) { - matrix_t oldmodelview; + mat4_t oldmodelview; GL_State( 0 ); //qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); { // FIXME: this could be a lot cleaner - matrix_t trans, product; + mat4_t trans, product; - Matrix16Copy( glState.modelview, oldmodelview ); - Matrix16Translation( backEnd.viewParms.or.origin, trans ); - Matrix16Multiply( glState.modelview, trans, product ); + Mat4Copy( glState.modelview, oldmodelview ); + Mat4Translation( backEnd.viewParms.or.origin, trans ); + Mat4Multiply( glState.modelview, trans, product ); GL_SetModelviewMatrix( product ); } diff --git a/code/renderergl2/tr_surface.c b/code/renderergl2/tr_surface.c index 06072a82..72d2f8d6 100644 --- a/code/renderergl2/tr_surface.c +++ b/code/renderergl2/tr_surface.c @@ -124,11 +124,11 @@ void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, float color[4], // constant normal all the way around VectorSubtract( vec3_origin, backEnd.viewParms.or.axis[0], normal ); - VectorCopy(normal, tess.normal[ndx]); - VectorCopy(normal, tess.normal[ndx+1]); - VectorCopy(normal, tess.normal[ndx+2]); - VectorCopy(normal, tess.normal[ndx+3]); - + tess.normal[ndx] = + tess.normal[ndx+1] = + tess.normal[ndx+2] = + tess.normal[ndx+3] = R_VboPackNormal(normal); + // standard square texture coordinates VectorSet2(tess.texCoords[ndx ][0], s1, t1); VectorSet2(tess.texCoords[ndx ][1], s1, t1); @@ -228,7 +228,7 @@ void RB_InstantQuad(vec4_t quadVerts[4]) GLSL_BindProgram(&tr.textureColorShader); - GLSL_SetUniformMatrix16(&tr.textureColorShader, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformMat4(&tr.textureColorShader, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); GLSL_SetUniformVec4(&tr.textureColorShader, UNIFORM_COLOR, colorWhite); RB_InstantQuad2(quadVerts, texCoords); @@ -311,30 +311,30 @@ static void RB_SurfacePolychain( srfPoly_t *p ) { tess.numVertexes = numv; } -static void RB_SurfaceVertsAndTris( int numVerts, srfVert_t *verts, int numTriangles, srfTriangle_t *triangles, int dlightBits, int pshadowBits) +static void RB_SurfaceVertsAndIndexes( int numVerts, srfVert_t *verts, int numIndexes, glIndex_t *indexes, int dlightBits, int pshadowBits) { int i; - srfTriangle_t *tri; + glIndex_t *inIndex; srfVert_t *dv; - float *xyz, *normal, *texCoords, *lightCoords, *lightdir; + float *xyz, *texCoords, *lightCoords; + uint32_t *lightdir; + uint32_t *normal; #ifdef USE_VERT_TANGENT_SPACE - float *tangent, *bitangent; + uint32_t *tangent; #endif - glIndex_t *index; + glIndex_t *outIndex; float *color; RB_CheckVBOandIBO(tess.vbo, tess.ibo); - RB_CHECKOVERFLOW( numVerts, numTriangles * 3 ); + RB_CHECKOVERFLOW( numVerts, numIndexes ); - tri = triangles; - index = &tess.indexes[ tess.numIndexes ]; - for ( i = 0 ; i < numTriangles ; i++, tri++ ) { - *index++ = tess.numVertexes + tri->indexes[0]; - *index++ = tess.numVertexes + tri->indexes[1]; - *index++ = tess.numVertexes + tri->indexes[2]; + inIndex = indexes; + outIndex = &tess.indexes[ tess.numIndexes ]; + for ( i = 0 ; i < numIndexes ; i++ ) { + *outIndex++ = tess.numVertexes + *inIndex++; } - tess.numIndexes += numTriangles * 3; + tess.numIndexes += numIndexes; if ( tess.shader->vertexAttribs & ATTR_POSITION ) { @@ -347,26 +347,18 @@ static void RB_SurfaceVertsAndTris( int numVerts, srfVert_t *verts, int numTrian if ( tess.shader->vertexAttribs & ATTR_NORMAL ) { dv = verts; - normal = tess.normal[ tess.numVertexes ]; - for ( i = 0 ; i < numVerts ; i++, dv++, normal+=4 ) - VectorCopy(dv->normal, normal); + normal = &tess.normal[ tess.numVertexes ]; + for ( i = 0 ; i < numVerts ; i++, dv++, normal++ ) + *normal = R_VboPackNormal(dv->normal); } #ifdef USE_VERT_TANGENT_SPACE if ( tess.shader->vertexAttribs & ATTR_TANGENT ) { dv = verts; - tangent = tess.tangent[ tess.numVertexes ]; - for ( i = 0 ; i < numVerts ; i++, dv++, tangent+=4 ) - VectorCopy(dv->tangent, tangent); - } - - if ( tess.shader->vertexAttribs & ATTR_BITANGENT ) - { - dv = verts; - bitangent = tess.bitangent[ tess.numVertexes ]; - for ( i = 0 ; i < numVerts ; i++, dv++, bitangent+=4 ) - VectorCopy(dv->bitangent, bitangent); + tangent = &tess.tangent[ tess.numVertexes ]; + for ( i = 0 ; i < numVerts ; i++, dv++, tangent++ ) + *tangent = R_VboPackTangent(dv->tangent); } #endif @@ -397,9 +389,9 @@ static void RB_SurfaceVertsAndTris( int numVerts, srfVert_t *verts, int numTrian if ( tess.shader->vertexAttribs & ATTR_LIGHTDIRECTION ) { dv = verts; - lightdir = tess.lightdir[ tess.numVertexes ]; - for ( i = 0 ; i < numVerts ; i++, dv++, lightdir+=4 ) - VectorCopy(dv->lightdir, lightdir); + lightdir = &tess.lightdir[ tess.numVertexes ]; + for ( i = 0 ; i < numVerts ; i++, dv++, lightdir++ ) + *lightdir = R_VboPackNormal(dv->lightdir); } #if 0 // nothing even uses vertex dlightbits @@ -437,8 +429,8 @@ static qboolean RB_SurfaceVbo(VBO_t *vbo, IBO_t *ibo, int numVerts, int numIndex // merge this into any existing multidraw primitives mergeForward = -1; mergeBack = -1; - firstIndexOffset = BUFFER_OFFSET(firstIndex * sizeof(GL_INDEX_TYPE)); - lastIndexOffset = BUFFER_OFFSET((firstIndex + numIndexes) * sizeof(GL_INDEX_TYPE)); + firstIndexOffset = BUFFER_OFFSET(firstIndex * sizeof(glIndex_t)); + lastIndexOffset = BUFFER_OFFSET((firstIndex + numIndexes) * sizeof(glIndex_t)); if (r_mergeMultidraws->integer) { @@ -522,15 +514,15 @@ static qboolean RB_SurfaceVbo(VBO_t *vbo, IBO_t *ibo, int numVerts, int numIndex RB_SurfaceTriangles ============= */ -static void RB_SurfaceTriangles( srfTriangles_t *srf ) { - if( RB_SurfaceVbo (srf->vbo, srf->ibo, srf->numVerts, srf->numTriangles * 3, +static void RB_SurfaceTriangles( srfBspSurface_t *srf ) { + if( RB_SurfaceVbo (srf->vbo, srf->ibo, srf->numVerts, srf->numIndexes, srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qtrue ) ) { return; } - RB_SurfaceVertsAndTris(srf->numVerts, srf->verts, srf->numTriangles, - srf->triangles, srf->dlightBits, srf->pshadowBits); + RB_SurfaceVertsAndIndexes(srf->numVerts, srf->verts, srf->numIndexes, + srf->indexes, srf->dlightBits, srf->pshadowBits); } @@ -614,7 +606,7 @@ static void RB_SurfaceBeam( void ) GLSL_VertexAttribsState(ATTR_POSITION); GLSL_BindProgram(sp); - GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); GLSL_SetUniformVec4(sp, UNIFORM_COLOR, colorRed); @@ -840,6 +832,7 @@ static void RB_SurfaceLightningBolt( void ) { } } +#if 0 /* ** VectorArrayNormalize * @@ -895,12 +888,14 @@ static void VectorArrayNormalize(vec4_t *normals, unsigned int count) #endif } +#endif /* ** LerpMeshVertexes */ +#if 0 #if idppc_altivec static void LerpMeshVertexes_altivec(md3Surface_t *surf, float backlerp) { @@ -1030,6 +1025,7 @@ static void LerpMeshVertexes_altivec(md3Surface_t *surf, float backlerp) } } #endif +#endif static void LerpMeshVertexes_scalar(mdvSurface_t *surf, float backlerp) { @@ -1129,14 +1125,15 @@ static void LerpMeshVertexes_scalar(mdvSurface_t *surf, float backlerp) VectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], numVerts); } #endif - float *outXyz, *outNormal; + float *outXyz; + uint32_t *outNormal; mdvVertex_t *newVerts; int vertNum; newVerts = surf->verts + backEnd.currentEntity->e.frame * surf->numVerts; outXyz = tess.xyz[tess.numVertexes]; - outNormal = tess.normal[tess.numVertexes]; + outNormal = &tess.normal[tess.numVertexes]; if (backlerp == 0) { @@ -1146,11 +1143,16 @@ static void LerpMeshVertexes_scalar(mdvSurface_t *surf, float backlerp) for (vertNum=0 ; vertNum < surf->numVerts ; vertNum++) { + vec3_t normal; + VectorCopy(newVerts->xyz, outXyz); - VectorCopy(newVerts->normal, outNormal); + VectorCopy(newVerts->normal, normal); + + *outNormal = R_VboPackNormal(normal); + newVerts++; outXyz += 4; - outNormal += 4; + outNormal++; } } else @@ -1165,15 +1167,19 @@ static void LerpMeshVertexes_scalar(mdvSurface_t *surf, float backlerp) for (vertNum=0 ; vertNum < surf->numVerts ; vertNum++) { + vec3_t normal; + VectorLerp(newVerts->xyz, oldVerts->xyz, backlerp, outXyz); - VectorLerp(newVerts->normal, oldVerts->normal, backlerp, outNormal); - //VectorNormalize(outNormal); + VectorLerp(newVerts->normal, oldVerts->normal, backlerp, normal); + VectorNormalize(normal); + + *outNormal = R_VboPackNormal(normal); + newVerts++; oldVerts++; outXyz += 4; - outNormal += 4; + outNormal++; } - VectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], surf->numVerts); } } @@ -1201,9 +1207,7 @@ RB_SurfaceMesh static void RB_SurfaceMesh(mdvSurface_t *surface) { int j; float backlerp; - srfTriangle_t *triangles; mdvSt_t *texCoords; - int indexes; int Bob, Doug; int numVerts; @@ -1213,20 +1217,16 @@ static void RB_SurfaceMesh(mdvSurface_t *surface) { backlerp = backEnd.currentEntity->e.backlerp; } - RB_CHECKOVERFLOW( surface->numVerts, surface->numTriangles*3 ); + RB_CHECKOVERFLOW( surface->numVerts, surface->numIndexes ); LerpMeshVertexes (surface, backlerp); - triangles = surface->triangles; - indexes = surface->numTriangles * 3; Bob = tess.numIndexes; Doug = tess.numVertexes; - for (j = 0 ; j < surface->numTriangles ; j++) { - tess.indexes[Bob + j*3 + 0] = Doug + triangles[j].indexes[0]; - tess.indexes[Bob + j*3 + 1] = Doug + triangles[j].indexes[1]; - tess.indexes[Bob + j*3 + 2] = Doug + triangles[j].indexes[2]; + for (j = 0 ; j < surface->numIndexes ; j++) { + tess.indexes[Bob + j] = Doug + surface->indexes[j]; } - tess.numIndexes += indexes; + tess.numIndexes += surface->numIndexes; texCoords = surface->st; @@ -1247,15 +1247,15 @@ static void RB_SurfaceMesh(mdvSurface_t *surface) { RB_SurfaceFace ============== */ -static void RB_SurfaceFace( srfSurfaceFace_t *srf ) { - if( RB_SurfaceVbo (srf->vbo, srf->ibo, srf->numVerts, srf->numTriangles * 3, +static void RB_SurfaceFace( srfBspSurface_t *srf ) { + if( RB_SurfaceVbo (srf->vbo, srf->ibo, srf->numVerts, srf->numIndexes, srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qtrue ) ) { return; } - RB_SurfaceVertsAndTris(srf->numVerts, srf->verts, srf->numTriangles, - srf->triangles, srf->dlightBits, srf->pshadowBits); + RB_SurfaceVertsAndIndexes(srf->numVerts, srf->verts, srf->numIndexes, + srf->indexes, srf->dlightBits, srf->pshadowBits); } @@ -1296,15 +1296,16 @@ RB_SurfaceGrid Just copy the grid of points and triangulate ============= */ -static void RB_SurfaceGrid( srfGridMesh_t *srf ) { +static void RB_SurfaceGrid( srfBspSurface_t *srf ) { int i, j; float *xyz; float *texCoords, *lightCoords; - float *normal; + uint32_t *normal; #ifdef USE_VERT_TANGENT_SPACE - float *tangent, *bitangent; + uint32_t *tangent; #endif - float *color, *lightdir; + float *color; + uint32_t *lightdir; srfVert_t *dv; int rows, irows, vrows; int used; @@ -1317,7 +1318,7 @@ static void RB_SurfaceGrid( srfGridMesh_t *srf ) { int pshadowBits; //int *vDlightBits; - if( RB_SurfaceVbo (srf->vbo, srf->ibo, srf->numVerts, srf->numTriangles * 3, + if( RB_SurfaceVbo (srf->vbo, srf->ibo, srf->numVerts, srf->numIndexes, srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qtrue ) ) { return; @@ -1387,15 +1388,14 @@ static void RB_SurfaceGrid( srfGridMesh_t *srf ) { numVertexes = tess.numVertexes; xyz = tess.xyz[numVertexes]; - normal = tess.normal[numVertexes]; + normal = &tess.normal[numVertexes]; #ifdef USE_VERT_TANGENT_SPACE - tangent = tess.tangent[numVertexes]; - bitangent = tess.bitangent[numVertexes]; + tangent = &tess.tangent[numVertexes]; #endif texCoords = tess.texCoords[numVertexes][0]; lightCoords = tess.texCoords[numVertexes][1]; color = tess.vertexColors[numVertexes]; - lightdir = tess.lightdir[numVertexes]; + lightdir = &tess.lightdir[numVertexes]; //vDlightBits = &tess.vertexDlightBits[numVertexes]; for ( i = 0 ; i < rows ; i++ ) { @@ -1411,21 +1411,13 @@ static void RB_SurfaceGrid( srfGridMesh_t *srf ) { if ( tess.shader->vertexAttribs & ATTR_NORMAL ) { - VectorCopy(dv->normal, normal); - normal += 4; + *normal++ = R_VboPackNormal(dv->normal); } #ifdef USE_VERT_TANGENT_SPACE if ( tess.shader->vertexAttribs & ATTR_TANGENT ) { - VectorCopy(dv->tangent, tangent); - tangent += 4; - } - - if ( tess.shader->vertexAttribs & ATTR_BITANGENT ) - { - VectorCopy(dv->bitangent, bitangent); - bitangent += 4; + *tangent++ = R_VboPackTangent(dv->tangent); } #endif if ( tess.shader->vertexAttribs & ATTR_TEXCOORD ) @@ -1448,8 +1440,7 @@ static void RB_SurfaceGrid( srfGridMesh_t *srf ) { if ( tess.shader->vertexAttribs & ATTR_LIGHTDIRECTION ) { - VectorCopy(dv->lightdir, lightdir); - lightdir += 4; + *lightdir++ = R_VboPackNormal(dv->lightdir); } //*vDlightBits++ = dlightBits; @@ -1574,7 +1565,7 @@ static void RB_SurfaceFlare(srfFlare_t *surf) RB_AddFlare(surf, tess.fogNum, surf->origin, surf->color, surf->normal); } -static void RB_SurfaceVBOMesh(srfVBOMesh_t * srf) +static void RB_SurfaceVBOMesh(srfBspSurface_t * srf) { RB_SurfaceVbo (srf->vbo, srf->ibo, srf->numVerts, srf->numIndexes, srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qfalse ); @@ -1621,11 +1612,12 @@ void RB_SurfaceVBOMDVMesh(srfVBOMDVMesh_t * surface) glState.vertexAttribsOldFrame = refEnt->oldframe; glState.vertexAttribsNewFrame = refEnt->frame; + glState.vertexAnimation = qtrue; RB_EndSurface(); // So we don't lerp surfaces that shouldn't be lerped - glState.vertexAttribsInterpolation = 0; + glState.vertexAnimation = qfalse; } static void RB_SurfaceDisplayList( srfDisplayList_t *surf ) { @@ -1646,7 +1638,6 @@ void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( void *) = { (void(*)(void*))RB_SurfaceTriangles, // SF_TRIANGLES, (void(*)(void*))RB_SurfacePolychain, // SF_POLY, (void(*)(void*))RB_SurfaceMesh, // SF_MDV, - (void(*)(void*))RB_SurfaceAnim, // SF_MD4, (void(*)(void*))RB_MDRSurfaceAnim, // SF_MDR, (void(*)(void*))RB_IQMSurfaceAnim, // SF_IQM, (void(*)(void*))RB_SurfaceFlare, // SF_FLARE, diff --git a/code/renderergl2/tr_vbo.c b/code/renderergl2/tr_vbo.c index e9f2598b..dc0f33be 100644 --- a/code/renderergl2/tr_vbo.c +++ b/code/renderergl2/tr_vbo.c @@ -22,6 +22,75 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // tr_vbo.c #include "tr_local.h" + +uint32_t R_VboPackTangent(vec4_t v) +{ + if (glRefConfig.packedNormalDataType == GL_UNSIGNED_INT_2_10_10_10_REV) + { + return (((uint32_t)(v[3] * 1.5f + 2.0f )) << 30) + | (((uint32_t)(v[2] * 511.5f + 512.0f)) << 20) + | (((uint32_t)(v[1] * 511.5f + 512.0f)) << 10) + | (((uint32_t)(v[0] * 511.5f + 512.0f))); + } + else + { + return (((uint32_t)(v[3] * 127.5f + 128.0f)) << 24) + | (((uint32_t)(v[2] * 127.5f + 128.0f)) << 16) + | (((uint32_t)(v[1] * 127.5f + 128.0f)) << 8) + | (((uint32_t)(v[0] * 127.5f + 128.0f))); + } +} + +uint32_t R_VboPackNormal(vec3_t v) +{ + if (glRefConfig.packedNormalDataType == GL_UNSIGNED_INT_2_10_10_10_REV) + { + return (((uint32_t)(v[2] * 511.5f + 512.0f)) << 20) + | (((uint32_t)(v[1] * 511.5f + 512.0f)) << 10) + | (((uint32_t)(v[0] * 511.5f + 512.0f))); + } + else + { + return (((uint32_t)(v[2] * 127.5f + 128.0f)) << 16) + | (((uint32_t)(v[1] * 127.5f + 128.0f)) << 8) + | (((uint32_t)(v[0] * 127.5f + 128.0f))); + } +} + +void R_VboUnpackTangent(vec4_t v, uint32_t b) +{ + if (glRefConfig.packedNormalDataType == GL_UNSIGNED_INT_2_10_10_10_REV) + { + v[0] = ((b) & 0x3ff) * 1.0f/511.5f - 1.0f; + v[1] = ((b >> 10) & 0x3ff) * 1.0f/511.5f - 1.0f; + v[2] = ((b >> 20) & 0x3ff) * 1.0f/511.5f - 1.0f; + v[3] = ((b >> 30) & 0x3) * 1.0f/1.5f - 1.0f; + } + else + { + v[0] = ((b) & 0xff) * 1.0f/127.5f - 1.0f; + v[1] = ((b >> 8) & 0xff) * 1.0f/127.5f - 1.0f; + v[2] = ((b >> 16) & 0xff) * 1.0f/127.5f - 1.0f; + v[3] = ((b >> 24) & 0xff) * 1.0f/127.5f - 1.0f; + } +} + +void R_VboUnpackNormal(vec3_t v, uint32_t b) +{ + if (glRefConfig.packedNormalDataType == GL_UNSIGNED_INT_2_10_10_10_REV) + { + v[0] = ((b) & 0x3ff) * 1.0f/511.5f - 1.0f; + v[1] = ((b >> 10) & 0x3ff) * 1.0f/511.5f - 1.0f; + v[2] = ((b >> 20) & 0x3ff) * 1.0f/511.5f - 1.0f; + } + else + { + v[0] = ((b) & 0xff) * 1.0f/127.5f - 1.0f; + v[1] = ((b >> 8) & 0xff) * 1.0f/127.5f - 1.0f; + v[2] = ((b >> 16) & 0xff) * 1.0f/127.5f - 1.0f; + } +} + /* ============ R_CreateVBO @@ -142,20 +211,14 @@ VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * vert if(stateBits & ATTR_NORMAL) { vbo->ofs_normal = dataSize; - dataSize += sizeof(verts[0].normal); + dataSize += sizeof(uint32_t); } #ifdef USE_VERT_TANGENT_SPACE if(stateBits & ATTR_TANGENT) { vbo->ofs_tangent = dataSize; - dataSize += sizeof(verts[0].tangent); - } - - if(stateBits & ATTR_BITANGENT) - { - vbo->ofs_bitangent = dataSize; - dataSize += sizeof(verts[0].bitangent); + dataSize += sizeof(uint32_t); } #endif @@ -180,14 +243,13 @@ VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * vert if(stateBits & ATTR_LIGHTDIRECTION) { vbo->ofs_lightdir = dataSize; - dataSize += sizeof(verts[0].lightdir); + dataSize += sizeof(uint32_t); } vbo->stride_xyz = dataSize; vbo->stride_normal = dataSize; #ifdef USE_VERT_TANGENT_SPACE vbo->stride_tangent = dataSize; - vbo->stride_bitangent = dataSize; #endif vbo->stride_st = dataSize; vbo->stride_lightmap = dataSize; @@ -211,23 +273,22 @@ VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * vert // normal if(stateBits & ATTR_NORMAL) { - memcpy(data + dataOfs, &verts[i].normal, sizeof(verts[i].normal)); - dataOfs += sizeof(verts[i].normal); + uint32_t *p = (uint32_t *)(data + dataOfs); + + *p = R_VboPackNormal(verts[i].normal); + + dataOfs += sizeof(uint32_t); } #ifdef USE_VERT_TANGENT_SPACE // tangent if(stateBits & ATTR_TANGENT) { - memcpy(data + dataOfs, &verts[i].tangent, sizeof(verts[i].tangent)); - dataOfs += sizeof(verts[i].tangent); - } + uint32_t *p = (uint32_t *)(data + dataOfs); - // bitangent - if(stateBits & ATTR_BITANGENT) - { - memcpy(data + dataOfs, &verts[i].bitangent, sizeof(verts[i].bitangent)); - dataOfs += sizeof(verts[i].bitangent); + *p = R_VboPackTangent(verts[i].tangent); + + dataOfs += sizeof(uint32_t); } #endif @@ -255,8 +316,11 @@ VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * vert // feed vertex light directions if(stateBits & ATTR_LIGHTDIRECTION) { - memcpy(data + dataOfs, &verts[i].lightdir, sizeof(verts[i].lightdir)); - dataOfs += sizeof(verts[i].lightdir); + uint32_t *p = (uint32_t *)(data + dataOfs); + + *p = R_VboPackNormal(verts[i].lightdir); + + dataOfs += sizeof(uint32_t); } } } @@ -267,18 +331,13 @@ VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * vert if(stateBits & ATTR_NORMAL) { - dataSize += sizeof(verts[0].normal); + dataSize += sizeof(uint32_t); } #ifdef USE_VERT_TANGENT_SPACE if(stateBits & ATTR_TANGENT) { - dataSize += sizeof(verts[0].tangent); - } - - if(stateBits & ATTR_BITANGENT) - { - dataSize += sizeof(verts[0].bitangent); + dataSize += sizeof(uint32_t); } #endif @@ -299,7 +358,7 @@ VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * vert if(stateBits & ATTR_LIGHTDIRECTION) { - dataSize += sizeof(verts[0].lightdir); + dataSize += sizeof(uint32_t); } // create VBO @@ -311,7 +370,6 @@ VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * vert vbo->ofs_normal = 0; #ifdef USE_VERT_TANGENT_SPACE vbo->ofs_tangent = 0; - vbo->ofs_bitangent = 0; #endif vbo->ofs_st = 0; vbo->ofs_lightmap = 0; @@ -319,15 +377,14 @@ VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * vert vbo->ofs_lightdir = 0; vbo->stride_xyz = sizeof(verts[0].xyz); - vbo->stride_normal = sizeof(verts[0].normal); + vbo->stride_normal = sizeof(uint32_t); #ifdef USE_VERT_TANGENT_SPACE - vbo->stride_tangent = sizeof(verts[0].tangent); - vbo->stride_bitangent = sizeof(verts[0].bitangent); + vbo->stride_tangent = sizeof(uint32_t); #endif vbo->stride_vertexcolor = sizeof(verts[0].vertexColors); vbo->stride_st = sizeof(verts[0].st); vbo->stride_lightmap = sizeof(verts[0].lightmap); - vbo->stride_lightdir = sizeof(verts[0].lightdir); + vbo->stride_lightdir = sizeof(uint32_t); //ri.Printf(PRINT_ALL, "2CreateVBO: %d, %d %d %d %d %d, %d %d %d %d %d\n", dataSize, vbo->ofs_xyz, vbo->ofs_normal, vbo->ofs_st, vbo->ofs_lightmap, vbo->ofs_vertexcolor, //vbo->stride_xyz, vbo->stride_normal, vbo->stride_st, vbo->stride_lightmap, vbo->stride_vertexcolor); @@ -345,8 +402,11 @@ VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * vert vbo->ofs_normal = dataOfs; for (i = 0; i < numVertexes; i++) { - memcpy(data + dataOfs, &verts[i].normal, sizeof(verts[i].normal)); - dataOfs += sizeof(verts[i].normal); + uint32_t *p = (uint32_t *)(data + dataOfs); + + *p = R_VboPackNormal(verts[i].normal); + + dataOfs += sizeof(uint32_t); } } @@ -357,19 +417,11 @@ VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * vert vbo->ofs_tangent = dataOfs; for (i = 0; i < numVertexes; i++) { - memcpy(data + dataOfs, &verts[i].tangent, sizeof(verts[i].tangent)); - dataOfs += sizeof(verts[i].tangent); - } - } + uint32_t *p = (uint32_t *)(data + dataOfs); - // bitangent - if(stateBits & ATTR_BITANGENT) - { - vbo->ofs_bitangent = dataOfs; - for (i = 0; i < numVertexes; i++) - { - memcpy(data + dataOfs, &verts[i].bitangent, sizeof(verts[i].bitangent)); - dataOfs += sizeof(verts[i].bitangent); + *p = R_VboPackTangent(verts[i].tangent); + + dataOfs += sizeof(uint32_t); } } #endif @@ -413,8 +465,11 @@ VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * vert vbo->ofs_lightdir = dataOfs; for (i = 0; i < numVertexes; i++) { - memcpy(data + dataOfs, &verts[i].lightdir, sizeof(verts[i].lightdir)); - dataOfs += sizeof(verts[i].lightdir); + uint32_t *p = (uint32_t *)(data + dataOfs); + + *p = R_VboPackNormal(verts[i].lightdir); + + dataOfs += sizeof(uint32_t); } } } @@ -501,17 +556,14 @@ IBO_t *R_CreateIBO(const char *name, byte * indexes, int indexesSize, v R_CreateIBO2 ============ */ -IBO_t *R_CreateIBO2(const char *name, int numTriangles, srfTriangle_t * triangles, vboUsage_t usage) +IBO_t *R_CreateIBO2(const char *name, int numIndexes, glIndex_t * inIndexes, vboUsage_t usage) { IBO_t *ibo; - int i, j; + int i; - byte *indexes; + glIndex_t *indexes; int indexesSize; - int indexesOfs; - srfTriangle_t *tri; - glIndex_t index; int glUsage; switch (usage) @@ -529,7 +581,7 @@ IBO_t *R_CreateIBO2(const char *name, int numTriangles, srfTriangle_t * return NULL; } - if(!numTriangles) + if(!numIndexes) return NULL; if(strlen(name) >= MAX_QPATH) @@ -548,18 +600,12 @@ IBO_t *R_CreateIBO2(const char *name, int numTriangles, srfTriangle_t * Q_strncpyz(ibo->name, name, sizeof(ibo->name)); - indexesSize = numTriangles * 3 * sizeof(int); + indexesSize = numIndexes * sizeof(glIndex_t); indexes = ri.Hunk_AllocateTempMemory(indexesSize); - indexesOfs = 0; - for(i = 0, tri = triangles; i < numTriangles; i++, tri++) + for(i = 0; i < numIndexes; i++) { - for(j = 0; j < 3; j++) - { - index = tri->indexes[j]; - memcpy(indexes + indexesOfs, &index, sizeof(glIndex_t)); - indexesOfs += sizeof(glIndex_t); - } + indexes[i] = inIndexes[i]; } ibo->indexesSize = indexesSize; @@ -608,6 +654,7 @@ void R_BindVBO(VBO_t * vbo) glState.vertexAttribsInterpolation = 0; glState.vertexAttribsOldFrame = 0; glState.vertexAttribsNewFrame = 0; + glState.vertexAnimation = qfalse; qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO); @@ -699,7 +746,6 @@ void R_InitVBOs(void) dataSize += sizeof(tess.normal[0]); #ifdef USE_VERT_TANGENT_SPACE dataSize += sizeof(tess.tangent[0]); - dataSize += sizeof(tess.bitangent[0]); #endif dataSize += sizeof(tess.vertexColors[0]); dataSize += sizeof(tess.texCoords[0][0]) * 2; @@ -714,7 +760,6 @@ void R_InitVBOs(void) tess.vbo->ofs_normal = offset; offset += sizeof(tess.normal[0]) * SHADER_MAX_VERTEXES; #ifdef USE_VERT_TANGENT_SPACE tess.vbo->ofs_tangent = offset; offset += sizeof(tess.tangent[0]) * SHADER_MAX_VERTEXES; - tess.vbo->ofs_bitangent = offset; offset += sizeof(tess.bitangent[0]) * SHADER_MAX_VERTEXES; #endif // these next two are actually interleaved tess.vbo->ofs_st = offset; @@ -728,7 +773,6 @@ void R_InitVBOs(void) tess.vbo->stride_normal = sizeof(tess.normal[0]); #ifdef USE_VERT_TANGENT_SPACE tess.vbo->stride_tangent = sizeof(tess.tangent[0]); - tess.vbo->stride_bitangent = sizeof(tess.bitangent[0]); #endif tess.vbo->stride_vertexcolor = sizeof(tess.vertexColors[0]); tess.vbo->stride_st = sizeof(tess.texCoords[0][0]) * 2; @@ -856,6 +900,9 @@ void RB_UpdateVBOs(unsigned int attribBits) { R_BindVBO(tess.vbo); + // orphan old buffer so we don't stall on it + qglBufferDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->vertexesSize, NULL, GL_DYNAMIC_DRAW_ARB); + if(attribBits & ATTR_BITS) { if(attribBits & ATTR_POSITION) @@ -883,12 +930,6 @@ void RB_UpdateVBOs(unsigned int attribBits) //ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_tangent, tess.numVertexes * sizeof(tess.tangent[0])); qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_tangent, tess.numVertexes * sizeof(tess.tangent[0]), tess.tangent); } - - if(attribBits & ATTR_BITANGENT) - { - //ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_bitangent, tess.numVertexes * sizeof(tess.bitangent[0])); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_bitangent, tess.numVertexes * sizeof(tess.bitangent[0]), tess.bitangent); - } #endif if(attribBits & ATTR_COLOR) @@ -910,7 +951,6 @@ void RB_UpdateVBOs(unsigned int attribBits) qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_normal, tess.numVertexes * sizeof(tess.normal[0]), tess.normal); #ifdef USE_VERT_TANGENT_SPACE qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_tangent, tess.numVertexes * sizeof(tess.tangent[0]), tess.tangent); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_bitangent, tess.numVertexes * sizeof(tess.bitangent[0]), tess.bitangent); #endif qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_vertexcolor, tess.numVertexes * sizeof(tess.vertexColors[0]), tess.vertexColors); qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_lightdir, tess.numVertexes * sizeof(tess.lightdir[0]), tess.lightdir); @@ -923,6 +963,9 @@ void RB_UpdateVBOs(unsigned int attribBits) { R_BindIBO(tess.ibo); + // orphan old buffer so we don't stall on it + qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, tess.ibo->indexesSize, NULL, GL_DYNAMIC_DRAW_ARB); + qglBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, tess.numIndexes * sizeof(tess.indexes[0]), tess.indexes); } } diff --git a/code/renderergl2/tr_world.c b/code/renderergl2/tr_world.c index 0ee4ad28..dba15c45 100644 --- a/code/renderergl2/tr_world.c +++ b/code/renderergl2/tr_world.c @@ -208,16 +208,18 @@ static int R_DlightSurface( msurface_t *surf, int dlightBits ) { } } - if ( *surf->data == SF_FACE ) { - ((srfSurfaceFace_t *)surf->data)->dlightBits = dlightBits; - } else if ( *surf->data == SF_GRID ) { - ((srfGridMesh_t *)surf->data)->dlightBits = dlightBits; - } else if ( *surf->data == SF_TRIANGLES ) { - ((srfTriangles_t *)surf->data)->dlightBits = dlightBits; - } else if ( *surf->data == SF_VBO_MESH ) { - ((srfVBOMesh_t *)surf->data)->dlightBits = dlightBits; - } else { - dlightBits = 0; + switch(*surf->data) + { + case SF_FACE: + case SF_GRID: + case SF_TRIANGLES: + case SF_VBO_MESH: + ((srfBspSurface_t *)surf->data)->dlightBits = dlightBits; + break; + + default: + dlightBits = 0; + break; } if ( dlightBits ) { @@ -292,16 +294,18 @@ static int R_PshadowSurface( msurface_t *surf, int pshadowBits ) { } } - if ( *surf->data == SF_FACE ) { - ((srfSurfaceFace_t *)surf->data)->pshadowBits = pshadowBits; - } else if ( *surf->data == SF_GRID ) { - ((srfGridMesh_t *)surf->data)->pshadowBits = pshadowBits; - } else if ( *surf->data == SF_TRIANGLES ) { - ((srfTriangles_t *)surf->data)->pshadowBits = pshadowBits; - } else if ( *surf->data == SF_VBO_MESH ) { - ((srfVBOMesh_t *)surf->data)->pshadowBits = pshadowBits; - } else { - pshadowBits = 0; + switch(*surf->data) + { + case SF_FACE: + case SF_GRID: + case SF_TRIANGLES: + case SF_VBO_MESH: + ((srfBspSurface_t *)surf->data)->pshadowBits = pshadowBits; + break; + + default: + pshadowBits = 0; + break; } if ( pshadowBits ) { diff --git a/code/sdl/sdl_glimp.c b/code/sdl/sdl_glimp.c index 4d8c752f..5b217ad7 100644 --- a/code/sdl/sdl_glimp.c +++ b/code/sdl/sdl_glimp.c @@ -698,8 +698,8 @@ void GLimp_Init( void ) { r_allowSoftwareGL = ri.Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH ); r_sdlDriver = ri.Cvar_Get( "r_sdlDriver", "", CVAR_ROM ); - r_allowResize = ri.Cvar_Get( "r_allowResize", "0", CVAR_ARCHIVE ); - r_centerWindow = ri.Cvar_Get( "r_centerWindow", "0", CVAR_ARCHIVE ); + r_allowResize = ri.Cvar_Get( "r_allowResize", "0", CVAR_ARCHIVE | CVAR_LATCH ); + r_centerWindow = ri.Cvar_Get( "r_centerWindow", "0", CVAR_ARCHIVE | CVAR_LATCH ); if( ri.Cvar_VariableIntegerValue( "com_abnormalExit" ) ) { diff --git a/code/server/server.h b/code/server/server.h index b577591f..407d6ab6 100644 --- a/code/server/server.h +++ b/code/server/server.h @@ -194,7 +194,7 @@ typedef struct client_s { #endif int oldServerTime; - qboolean csUpdated[MAX_CONFIGSTRINGS+1]; + qboolean csUpdated[MAX_CONFIGSTRINGS]; #ifdef LEGACY_PROTOCOL qboolean compat; diff --git a/code/server/sv_init.c b/code/server/sv_init.c index 2fa94dd7..51a307ae 100644 --- a/code/server/sv_init.c +++ b/code/server/sv_init.c @@ -82,7 +82,7 @@ void SV_UpdateConfigstrings(client_t *client) { int index; - for( index = 0; index <= MAX_CONFIGSTRINGS; index++ ) { + for( index = 0; index < MAX_CONFIGSTRINGS; index++ ) { // if the CS hasn't changed since we went to CS_PRIMED, ignore if(!client->csUpdated[index]) continue; diff --git a/code/ui/ui_atoms.c b/code/ui/ui_atoms.c index c049b1cc..5e78e4ae 100644 --- a/code/ui/ui_atoms.c +++ b/code/ui/ui_atoms.c @@ -429,6 +429,7 @@ qboolean UI_ConsoleCommand(int realTime) if (Q_stricmp(cmd, "ui_test") == 0) { UI_ShowPostGame(qtrue); + return qtrue; } if (Q_stricmp(cmd, "ui_report") == 0) { diff --git a/code/ui/ui_main.c b/code/ui/ui_main.c index a4056e8d..cc75982e 100644 --- a/code/ui/ui_main.c +++ b/code/ui/ui_main.c @@ -1918,7 +1918,7 @@ void UI_ParseMenu(const char *menuFile) int handle; pc_token_t token; - Com_Printf("Parsing menu file:%s\n", menuFile); + Com_Printf("Parsing menu file: %s\n", menuFile); handle = trap_PC_LoadSource(menuFile); if (!handle) { diff --git a/make-macosx-app.sh b/make-macosx-app.sh index 7768964a..7e484dd4 100755 --- a/make-macosx-app.sh +++ b/make-macosx-app.sh @@ -221,13 +221,13 @@ for ARCH in $SEARCH_ARCHS; do IOQ3_UI_ARCHS="${BUILT_PRODUCTS_DIR}/${BASEDIR}/${IOQ3_UI} ${IOQ3_UI_ARCHS}" fi # missionpack - if [ -e ${BUILT_PRODUCTS_DIR}/${BASEDIR}/${IOQ3_MP_CGAME} ]; then + if [ -e ${BUILT_PRODUCTS_DIR}/${MISSIONPACKDIR}/${IOQ3_CGAME} ]; then IOQ3_MP_CGAME_ARCHS="${BUILT_PRODUCTS_DIR}/${MISSIONPACKDIR}/${IOQ3_CGAME} ${IOQ3_MP_CGAME_ARCHS}" fi - if [ -e ${BUILT_PRODUCTS_DIR}/${BASEDIR}/${IOQ3_MP_GAME} ]; then + if [ -e ${BUILT_PRODUCTS_DIR}/${MISSIONPACKDIR}/${IOQ3_GAME} ]; then IOQ3_MP_GAME_ARCHS="${BUILT_PRODUCTS_DIR}/${MISSIONPACKDIR}/${IOQ3_GAME} ${IOQ3_MP_GAME_ARCHS}" fi - if [ -e ${BUILT_PRODUCTS_DIR}/${BASEDIR}/${IOQ3_MP_UI} ]; then + if [ -e ${BUILT_PRODUCTS_DIR}/${MISSIONPACKDIR}/${IOQ3_UI} ]; then IOQ3_MP_UI_ARCHS="${BUILT_PRODUCTS_DIR}/${MISSIONPACKDIR}/${IOQ3_UI} ${IOQ3_MP_UI_ARCHS}" fi diff --git a/misc/msvc/opengl1.vcproj b/misc/msvc/opengl1.vcproj new file mode 100644 index 00000000..6dc6973f --- /dev/null +++ b/misc/msvc/opengl1.vcproj @@ -0,0 +1,932 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +