diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..e3989359 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,473 @@ +#Note: this file was made primarily to support msvc and its project file incompatibilities nightmare. + + +CMAKE_MINIMUM_REQUIRED(VERSION 3.0) +PROJECT(fteqw) + +INCLUDE_DIRECTORIES( + engine/common + engine/client + engine/qclib + engine/gl + engine/server + engine +) + +EXECUTE_PROCESS(COMMAND + "echo" hello world + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + OUTPUT_VARIABLE FTE_REVISON + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE +) + +IF (NOT "${FTE_REVISON}" STREQUAL "") + SET(FTE_REVISON SVNREVISION=${FTE_REVISON}) +ENDIF() + +#plugins need visibility hidden in order to avoid conflicts with function names that match the engine. +#this is consistent with how windows works so no great loss. +#plus it means that gcc can inline more (with LTO), including optimising args. +set(CMAKE_CXX_VISIBILITY_PRESET hidden) +set(CMAKE_C_VISIBILITY_PRESET hidden) + +#use LTO where possible. reportedly requires cmake 3.9 to actually work +set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) + +IF(${WIN32}) + INCLUDE_DIRECTORIES(engine/libs engine/libs/freetype2/include) +# LINK_DIRECTORIES(engine/libs/mingw64-libs) + + # engine/server/sv_sys_win.c + + SET(FTE_LIBS z ole32 gdi32 wsock32 winmm) + SET(FTE_DEFINES GLQUAKE;VKQUAKE;D3D9QUAKE;DYNAMIC_LIBPNG;DYNAMIC_LIBJPEG) #D3D11QUAKE not included. + SET(FTE_ARCH_FILES + engine/client/winquake.rc + engine/common/sys_win_threads.c + engine/common/net_ssl_winsspi.c + engine/common/fs_win32.c + engine/client/cd_win.c + engine/client/in_win.c + engine/client/snd_al.c + engine/client/snd_directx.c + engine/client/snd_wasapi.c + engine/client/snd_win.c + engine/client/snd_xaudio.c + engine/client/sys_win.c + + engine/gl/gl_vidnt.c + + engine/d3d/d3d_backend.c + engine/d3d/d3d_image.c + engine/d3d/d3d_shader.c + engine/d3d/d3d11_backend.c + engine/d3d/d3d11_image.c + engine/d3d/d3d11_shader.c + engine/d3d/d3d8_backend.c + engine/d3d/d3d8_image.c + engine/d3d/vid_d3d.c + engine/d3d/vid_d3d11.c + engine/d3d/vid_d3d8.c + ) + + SET(FTESV_LIBS z wsock32 winmm) + SET(FTESV_ARCH_FILES + engine/client/winquake.rc + engine/common/sys_win_threads.c + engine/common/net_ssl_winsspi.c + engine/common/fs_win32.c + engine/server/sv_sys_win.c + ) +ELSEIF(${UNIX}) #linux(ish) + FIND_PACKAGE(Freetype REQUIRED) + + INCLUDE_DIRECTORIES( ${FREETYPE_INCLUDE_DIRS} ) + + SET(FTE_DEFINES GLQUAKE;VKQUAKE;DYNAMIC_LIBPNG;DYNAMIC_LIBJPEG;DYNAMIC_SDL;MULTITHREAD;stricmp=strcasecmp;strnicmp=strncasecmp) + SET(FTE_LIBS z m dl pthread ${SDL2_LIBRARIES}) + SET(FTE_ARCH_FILES + engine/client/sys_linux.c + engine/common/sys_linux_threads.c + engine/common/net_ssl_gnutls.c + + engine/client/snd_al.c + engine/client/snd_alsa.c + engine/client/snd_linux.c + engine/client/snd_sdl.c #we use SDL audio even without sys_sdl, because of pulseaudio fucking over alsa, alsa fucking over oss3, and oss4 not being used. Either way, openal should be the default anyway. + + engine/client/cd_linux.c + engine/gl/gl_vidlinuxglx.c + engine/gl/gl_videgl.c + +# engine/gl/gl_vidrpi.c +# engine/gl/gl_vidwayland.c + ) + + SET(FTESV_DEFINES stricmp=strcasecmp;strnicmp=strncasecmp) + SET(FTESV_ARCH_FILES + engine/server/sv_sys_unix.c + engine/common/sys_linux_threads.c + engine/common/net_ssl_gnutls.c + ) + SET(FTESV_LIBS z m dl) +ELSEIF(1) #SDL + FIND_PACKAGE(Freetype REQUIRED) +# INCLUDE_DIRECTORIES(engine/libs engine/libs/freetype2/include) + + FIND_PACKAGE(PkgConfig REQUIRED) + PKG_SEARCH_MODULE(sdl2 REQUIRED sdl2) + +# FIND_PACKAGE(SDL2 REQUIRED) + + INCLUDE_DIRECTORIES(${FREETYPE_INCLUDE_DIRS} ${SDL2_INCLUDE_DIRS}) + + #SDL2.0.7 supports vulkan, so lets use it. + SET(FTE_DEFINES GLQUAKE;VKQUAKE;FTE_SDL;DYNAMIC_LIBPNG;DYNAMIC_LIBJPEG;stricmp=strcasecmp;strnicmp=strncasecmp) + SET(FTE_LIBS z m dl ${SDL2_LIBRARIES}) + SET(FTE_ARCH_FILES + engine/client/sys_sdl.c + engine/client/snd_al.c + engine/client/snd_sdl.c + engine/client/in_sdl.c + engine/client/cd_sdl.c + engine/gl/gl_vidsdl.c + ) + + SET(FTESV_DEFINES FTE_SDL;stricmp=strcasecmp;strnicmp=strncasecmp) + SET(FTESV_LIBS z m dl ${SDL2_LIBRARIES}) + + IF(WIN32) + SET(FTE_LIBS ${FTE_LIBS} wsock32 gdi32 ole32) + SET(FTE_DEFINES ${FTE_DEFINES};NO_DIRECTX) + SET(FTE_ARCH_FILES ${FTE_ARCH_FILES} + engine/client/winquake.rc + engine/common/net_ssl_winsspi.c + ) + SET(FTESV_ARCH_FILES ${FTESV_ARCH_FILES} + engine/client/winquake.rc + engine/common/net_ssl_winsspi.c + engine/server/sv_sys_win.c + ) + ELSE() + SET(FTE_ARCH_FILES ${FTE_ARCH_FILES} + engine/common/net_ssl_gnutls.c + ) + SET(FTESV_ARCH_FILES ${FTESV_ARCH_FILES} + engine/common/net_ssl_gnutls.c + engine/common/sys_linux_threads.c + engine/server/sv_sys_unix.c + ) + ENDIF() +ELSE() +# engine/common/sys_linux_threads.c +# engine/common/net_ssl_gnutls.c +# engine/server/sv_sys_unix.c + +# engine/client/snd_alsa.c +# engine/client/snd_droid.c +# engine/client/snd_linux.c +# engine/client/snd_macos.c +# engine/client/snd_morphos.c +# engine/client/snd_sblaster.c +# engine/client/snd_sdl.c +# engine/client/snd_sndio.c + +# engine/client/sys_dos.c +# engine/client/sys_droid.c +# engine/client/sys_linux.c +# engine/client/sys_morphos.c +# engine/client/sys_npfte.c +# engine/client/sys_plugfte.c +# engine/client/sys_sdl.c +# engine/client/sys_xdk.c + +# engine/client/cd_linux.c +# engine/client/cd_null.c +# engine/client/cd_sdl.c +# engine/client/in_morphos.c +# engine/client/in_sdl.c + +# engine/gl/gl_viddroid.c +# engine/gl/gl_videgl.c +# engine/gl/gl_vidlinuxglx.c +# engine/gl/gl_vidmacos.c +# engine/gl/gl_vidmorphos.c +# engine/gl/gl_vidnull.c +# engine/gl/gl_vidrpi.c +# engine/gl/gl_vidsdl.c +# engine/gl/gl_vidtinyglstubs.c +# engine/gl/gl_vidwayland.c +ENDIF() + +SET(FTE_COMMON_FILES + #these files are common to both server-only and client+server builds. + engine/common/cmd.c + engine/common/com_mesh.c + engine/common/common.c + engine/common/crc.c + engine/common/cvar.c + engine/common/fs.c + engine/common/fs_dzip.c + engine/common/fs_pak.c + engine/common/fs_stdio.c + engine/common/fs_xz.c + engine/common/fs_zip.c + engine/common/gl_q2bsp.c + engine/common/huff.c + engine/common/log.c + engine/common/mathlib.c + engine/common/md4.c + engine/common/net_chan.c + engine/common/net_ice.c + engine/common/net_wins.c + engine/common/plugin.c + engine/common/pmove.c + engine/common/pmovetst.c + engine/common/pr_bgcmd.c + engine/common/q1bsp.c + engine/common/q2pmove.c + engine/common/q3common.c + engine/common/qvm.c + engine/common/sha1.c + engine/common/translate.c + engine/common/zone.c + + #sigh + engine/client/pr_skelobj.c + engine/client/m_download.c + engine/client/net_master.c + + #these are here because of hitmodel etc + engine/gl/gl_heightmap.c + engine/gl/gl_hlmdl.c + engine/gl/gl_model.c + + engine/server/net_preparse.c + engine/server/pr_cmds.c + engine/server/pr_lua.c + engine/server/pr_q1qvm.c + engine/server/savegame.c + engine/server/sv_ccmds.c + engine/server/sv_chat.c + engine/server/sv_cluster.c + engine/server/sv_demo.c + engine/server/sv_ents.c + engine/server/sv_init.c + engine/server/sv_main.c + engine/server/sv_master.c + engine/server/sv_move.c + engine/server/sv_mvd.c + engine/server/sv_nchan.c + engine/server/sv_phys.c + engine/server/sv_rankin.c + engine/server/sv_send.c + engine/server/sv_sql.c + engine/server/sv_user.c +# engine/server/svhl_game.c +# engine/server/svhl_phys.c +# engine/server/svhl_world.c + engine/server/svq2_ents.c + engine/server/svq2_game.c + engine/server/svq3_game.c + engine/server/world.c + + engine/qclib/comprout.c + engine/qclib/hash.c + engine/qclib/initlib.c + engine/qclib/pr_edict.c + engine/qclib/pr_exec.c + engine/qclib/pr_multi.c + engine/qclib/qcc_cmdlib.c + engine/qclib/qcc_pr_comp.c + engine/qclib/qcc_pr_lex.c +# engine/qclib/decomp.c +# engine/qclib/packager.c +# engine/qclib/pr_x86.c +# engine/qclib/qccgui.c +# engine/qclib/qccguistuff.c +# engine/qclib/qcctui.c + engine/qclib/qccmain.c + engine/qclib/qcd_main.c + engine/qclib/qcdecomp.c + + engine/http/httpclient.c +) + +ADD_EXECUTABLE(fteqw WIN32 + ${FTE_ARCH_FILES} + ${FTE_COMMON_FILES} + + engine/client/cl_cam.c + engine/client/cl_cg.c + engine/client/cl_demo.c + engine/client/cl_ents.c + engine/client/cl_ignore.c + engine/client/cl_input.c + engine/client/cl_main.c + engine/client/cl_parse.c + engine/client/cl_pred.c + engine/client/cl_screen.c + engine/client/cl_tent.c + engine/client/cl_ui.c +# engine/client/clhl_game.c + engine/client/clq2_cin.c + engine/client/clq2_ents.c + engine/client/clq3_parse.c + engine/client/console.c + engine/client/fragstats.c + engine/client/image.c + engine/client/in_generic.c + engine/client/keys.c + engine/client/m_items.c + engine/client/m_master.c + engine/client/m_mp3.c + engine/client/m_multi.c + engine/client/m_options.c + engine/client/m_script.c + engine/client/m_single.c + engine/client/menu.c + engine/client/p_classic.c + engine/client/p_null.c + engine/client/p_script.c + engine/client/pr_clcmd.c + engine/client/pr_csqc.c + engine/client/pr_menu.c + engine/client/r_2d.c + engine/client/r_d3.c + engine/client/r_part.c + engine/client/r_partset.c + engine/client/r_surf.c + engine/client/renderer.c + engine/client/renderque.c + engine/client/roq_read.c + engine/client/sbar.c + engine/client/skin.c + engine/client/snd_dma.c + engine/client/snd_mem.c + engine/client/snd_mix.c + engine/client/snd_mp3.c + engine/client/snd_ov.c + engine/client/textedit.c + engine/client/valid.c + engine/client/vid_headless.c + engine/client/view.c + engine/client/wad.c + engine/client/zqtp.c + + +#These are generic renderer files + engine/gl/gl_alias.c + engine/gl/gl_font.c + engine/gl/gl_ngraph.c + engine/gl/gl_rlight.c + engine/gl/gl_shader.c + engine/gl/gl_shadow.c + engine/gl/gl_warp.c + engine/gl/ltface.c + +#These are GL-specific + engine/gl/gl_backend.c + engine/gl/gl_bloom.c + engine/gl/gl_draw.c + engine/gl/gl_rmain.c + engine/gl/gl_rmisc.c + engine/gl/gl_rsurf.c + engine/gl/gl_screen.c + engine/gl/gl_vidcommon.c + engine/gl/glmod_doom.c + + engine/vk/vk_backend.c + engine/vk/vk_init.c +) +SET_TARGET_PROPERTIES(fteqw PROPERTIES COMPILE_DEFINITIONS "${FTE_DEFINES};${FTE_REVISON}") +TARGET_LINK_LIBRARIES(fteqw ${FTE_LIBS} ) + +ADD_EXECUTABLE(fteqw-sv + ${FTESV_ARCH_FILES} + ${FTE_COMMON_FILES} +) +SET_TARGET_PROPERTIES(fteqw-sv PROPERTIES COMPILE_DEFINITIONS "SERVERONLY;${FTESV_DEFINES};${FTE_REVISON}") +TARGET_LINK_LIBRARIES(fteqw-sv ${FTESV_LIBS}) + + +ADD_EXECUTABLE(fteqcc + engine/qclib/qcctui.c + engine/qclib/comprout.c + engine/qclib/hash.c + engine/qclib/qcc_cmdlib.c + engine/qclib/qcc_pr_comp.c + engine/qclib/qcc_pr_lex.c + engine/qclib/qccmain.c + engine/qclib/qcd_main.c +) +TARGET_LINK_LIBRARIES(fteqcc z m) + + +IF(${WIN32}) + ADD_EXECUTABLE(fteqccgui WIN32 + engine/qclib/qccgui.c + engine/qclib/qccguistuff.c + engine/qclib/comprout.c + engine/qclib/hash.c + engine/qclib/qcc_cmdlib.c + engine/qclib/qcc_pr_comp.c + engine/qclib/qcc_pr_lex.c + engine/qclib/qccmain.c + engine/qclib/decomp.c + engine/qclib/packager.c + engine/qclib/qcd_main.c + ) + TARGET_LINK_LIBRARIES(fteqccgui z shlwapi ole32 comctl32 comdlg32) +ENDIF() + + + +#Quake Injector Alike plugin +ADD_LIBRARY(qi MODULE + plugins/qvm_api.c + plugins/plugin.c + plugins/qi/qi.c + plugins/emailnot/md5.c + plugins/jabber/xml.c +) +SET_TARGET_PROPERTIES(qi PROPERTIES COMPILE_DEFINITIONS "FTEPLUGIN") +SET_TARGET_PROPERTIES(qi PROPERTIES PREFIX "fteplug_") + +#EzQuake Hud port plugin +ADD_LIBRARY(ezhud MODULE + plugins/qvm_api.c + plugins/plugin.c + plugins/ezhud/ezquakeisms.c + plugins/ezhud/hud.c + plugins/ezhud/hud_common.c + plugins/ezhud/hud_editor.c +) +SET_TARGET_PROPERTIES(ezhud PROPERTIES COMPILE_DEFINITIONS "FTEPLUGIN") +SET_TARGET_PROPERTIES(ezhud PROPERTIES PREFIX "fteplug_") + +#IRC client plugin +ADD_LIBRARY(irc MODULE + plugins/qvm_api.c + plugins/plugin.c + plugins/irc/ircclient.c +) +SET_TARGET_PROPERTIES(irc PROPERTIES COMPILE_DEFINITIONS "FTEPLUGIN") +SET_TARGET_PROPERTIES(irc PROPERTIES PREFIX "fteplug_") + +#XMPP/jabber client plugin +ADD_LIBRARY(xmpp MODULE + plugins/qvm_api.c + plugins/plugin.c + plugins/jabber/jabberclient.c + plugins/jabber/xml.c + plugins/jabber/jingle.c + plugins/jabber/sift.c + engine/common/sha1.c + plugins/emailnot/md5.c +) +SET_TARGET_PROPERTIES(xmpp PROPERTIES COMPILE_DEFINITIONS "FTEPLUGIN") +SET_TARGET_PROPERTIES(xmpp PROPERTIES PREFIX "fteplug_") + +#ffmpeg plugin +#cef plugin +#bullet plugin diff --git a/engine/Makefile b/engine/Makefile index e5f86c8c..9a557245 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -611,7 +611,6 @@ endif CLIENT_OBJS = \ textedit.o \ fragstats.o \ - teamplay.o \ zqtp.o \ cl_demo.o \ cl_ents.o \ diff --git a/engine/client/cl_cam.c b/engine/client/cl_cam.c index ebd0aa8f..3cbdc65b 100644 --- a/engine/client/cl_cam.c +++ b/engine/client/cl_cam.c @@ -559,8 +559,6 @@ void Cam_Unlock(playerview_t *pv) void Cam_Lock(playerview_t *pv, int playernum) { - int i; - pv->cam_lastviewtime = -1000; //allow the wallcam to re-snap as soon as it can CL_SendClientCommand(true, "ptrack %i", playernum); @@ -592,8 +590,13 @@ void Cam_Lock(playerview_t *pv, int playernum) Sbar_Changed(); - for (i = 0; i < cl.allocated_client_slots; i++) - CL_NewTranslation(i); +#ifdef QWSKINS + { + int i; + for (i = 0; i < cl.allocated_client_slots; i++) + CL_NewTranslation(i); + } +#endif } trace_t Cam_DoTrace(vec3_t vec1, vec3_t vec2) diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index d7639df2..16f50964 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -2012,8 +2012,8 @@ void CL_RotateAroundTag(entity_t *ent, int entnum, int parenttagent, int parentt if ((ent->flags & RF_WEAPONMODEL) && ent->playerindex == -1 && ps->colormap > 0 && ps->colormap <= cl.allocated_client_slots) { ent->playerindex = ps->colormap-1; - ent->topcolour = cl.players[ent->playerindex].ttopcolor; - ent->bottomcolour = cl.players[ent->playerindex].tbottomcolor; + ent->topcolour = cl.players[ent->playerindex].dtopcolor; + ent->bottomcolour = cl.players[ent->playerindex].dbottomcolor; } } else @@ -4057,8 +4057,8 @@ void CL_LinkPacketEntities (void) #ifdef HEXEN2 ent->h2playerclass = cl.players[ent->playerindex].h2playerclass; #endif - ent->topcolour = cl.players[ent->playerindex].ttopcolor; - ent->bottomcolour = cl.players[ent->playerindex].tbottomcolor; + ent->topcolour = cl.players[ent->playerindex].dtopcolor; + ent->bottomcolour = cl.players[ent->playerindex].dbottomcolor; } // set skin @@ -5109,8 +5109,8 @@ void CL_LinkPlayers (void) // set colormap ent->playerindex = j; - ent->topcolour = info->ttopcolor; - ent->bottomcolour = info->tbottomcolor; + ent->topcolour = info->dtopcolor; + ent->bottomcolour = info->dbottomcolor; #ifdef HEXEN2 ent->h2playerclass = info->h2playerclass; #endif diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 934fa488..14752f68 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -1924,7 +1924,7 @@ void CL_SendCmd (double frametime, qboolean mainloop) } #ifdef HLCLIENT - if (!CLHL_BuildUserInput(msecstouse, &independantphysics[0])) + if (!CLHL_BuildUserInput(msecstouse, &cl_pendingcmd[0])) #endif for (plnum = 0; plnum < (cl.splitclients?cl.splitclients:1); plnum++) { @@ -1952,13 +1952,7 @@ void CL_SendCmd (double frametime, qboolean mainloop) // if (cl.spectator) Cam_Track(&cl.playerview[plnum], &cl_pendingcmd[plnum]); Cam_FinishMove(&cl.playerview[plnum], &cl_pendingcmd[plnum]); - - //HACK: 1000/77 = 12.98. nudge it just under so we never appear to be using 83fps at 77fps (which can trip cheat detection in mods that expect 72 fps when many servers are configured for 77) - //so lets just never use 12. - if (fullsend && (cl_pendingcmd[plnum].msec > 12.9 && cl_pendingcmd[plnum].msec < 13) && cls.maxfps == 77) - cl_pendingcmd[plnum].msec = 13; } -// msecstouse = cl_pendingcmd[0].msec; //the main loop isn't allowed to send if (runningindepphys && mainloop) @@ -1973,6 +1967,13 @@ void CL_SendCmd (double frametime, qboolean mainloop) // if (msecstouse > 127) // Con_Printf("%i\n", msecstouse, msecs); + //HACK: 1000/77 = 12.98. nudge it just under so we never appear to be using 83fps at 77fps (which can trip cheat detection in mods that expect 72 fps when many servers are configured for 77) + //so lets just never use 12. + if (fullsend && cls.maxfps == 77) + for (plnum = 0; plnum < (cl.splitclients?cl.splitclients:1); plnum++) + if (cl_pendingcmd[plnum].msec > 12.9 && cl_pendingcmd[plnum].msec < 13) + cl_pendingcmd[plnum].msec = 13; + #ifdef NQPROT if (cls.protocol != CP_NETQUAKE || cls.netchan.nqreliable_allowed) #endif diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 5270670e..d5e316e8 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -4116,8 +4116,10 @@ void CL_Init (void) extern void CL_Say_f (void); extern void CL_SayMe_f (void); extern void CL_SayTeam_f (void); +#ifdef QWSKINS extern cvar_t baseskin; extern cvar_t noskins; +#endif char *ver; cls.state = ca_disconnected; @@ -4204,8 +4206,10 @@ void CL_Init (void) Cvar_Register (&cl_muzzleflash, cl_controlgroup); +#ifdef QWSKINS Cvar_Register (&baseskin, "Teamplay"); Cvar_Register (&noskins, "Teamplay"); +#endif Cvar_Register (&cl_noblink, "Console controls"); //for lack of a better group Cvar_Register (&cl_item_bobbing, "Item effects"); @@ -4335,7 +4339,9 @@ void CL_Init (void) Cmd_AddCommand ("stopdemo", CL_Stopdemo_f); Cmd_AddCommand ("skins", Skin_Skins_f); +#ifdef QWSKINS Cmd_AddCommand ("allskins", Skin_AllSkins_f); +#endif Cmd_AddCommand ("cl_status", CL_Status_f); Cmd_AddCommandD ("quit", CL_Quit_f, "Use this command when you get angry. Does not save any cvars. Use cfg_save to save settings, or use the menu for a prompt."); @@ -5518,12 +5524,13 @@ double Host_Frame (double time) // host_frametime = 0.2; // get new key events - Sys_SendKeyEvents (); + Sys_SendKeyEvents (); //from windowing system + INS_Move(); //from things that need special polling - // allow mice or other external controllers to add commands + // check what we got, and handle any click/button events IN_Commands (); - // process console commands + // process console commands from said click/button events Cbuf_Execute (); #ifndef CLIENTONLY @@ -5543,6 +5550,8 @@ double Host_Frame (double time) // fetch results from server CL_ReadPackets (); + CL_RequestNextDownload(); + // send intentions now // resend a connection request if necessary if (cls.state == ca_disconnected) @@ -5669,12 +5678,10 @@ double Host_Frame (double time) } - IN_Commands (); +// IN_Commands (); // process console commands - Cbuf_Execute (); - - CL_RequestNextDownload(); +// Cbuf_Execute (); CL_QTVPoll(); diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 092ad641..96b84d17 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -840,8 +840,10 @@ void CL_DownloadFinished(qdownload_t *dl) } S_ResetFailedLoad(); //okay, so this can still get a little spammy in bad places... +#ifdef QWSKINS //this'll do the magic for us Skin_FlushSkin(filename); +#endif } } @@ -4892,6 +4894,7 @@ void CL_ParseClientdata (void) CL_AckedInputFrame(cls.netchan.incoming_sequence, cl.parsecount, false); } +#ifdef QWSKINS static qboolean CLQ2_PlayerSkinIsOkay(skinid_t id) { skinfile_t *sk = Mod_LookupSkin(id); @@ -5025,6 +5028,7 @@ void CL_NewTranslation (int slot) player->ttopcolor = top; player->tbottomcolor = bottom; } +#endif /* ============== @@ -5064,7 +5068,6 @@ static void CL_ProcessUserInfo (int slot, player_info_t *player) if (player->rbottomcolor > 13) player->rbottomcolor = 13; */ - player->model = NULL; #ifdef HEXEN2 /*if we're running hexen2, they have to be some class...*/ @@ -5075,7 +5078,10 @@ static void CL_ProcessUserInfo (int slot, player_info_t *player) player->h2playerclass = 1; #endif +#ifdef QWSKINS + player->model = NULL; player->colourised = TP_FindColours(player->name); +#endif // If it's us for (i = 0; i < cl.splitclients; i++) @@ -5098,13 +5104,15 @@ static void CL_ProcessUserInfo (int slot, player_info_t *player) Skin_FlushPlayers(); } +#ifdef QWSKINS else if (cl.teamplay && cl.playerview[0].spectator && slot == Cam_TrackNum(&cl.playerview[0])) //skin forcing cares about the team of the guy we're tracking. Skin_FlushPlayers(); else if (cls.state == ca_active) Skin_Find (player); - Sbar_Changed (); CL_NewTranslation (slot); +#endif + Sbar_Changed (); } /* @@ -7863,13 +7871,14 @@ void CLNQ_ParseServerMessage (void) // CLNQ_CheckPlayerIsSpectator(i); +#ifdef QWSKINS if (cls.state == ca_active) Skin_Find (&cl.players[i]); - if (i == cl.playerview[destsplit].playernum) Skin_FlushPlayers(); - Sbar_Changed (); CL_NewTranslation (i); +#endif + Sbar_Changed (); } } break; diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index 1ee16775..a54a5769 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -2538,6 +2538,18 @@ qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void **buffer, } else if (!Q_strcasecmp(ext, "tga")) //tga return WriteTGA(filename, fsroot, buffer[0], bytestride, width, height, fmt); + /*else if (!Q_strcasecmp(ext, "ktx")) //ktx + { + struct pendingtextureinfo out = {PTI_2D}; + out.encoding = fmt; + out.mipcount = 1; + out.mip[0].data = buffer[0]; + out.mip[0].datasize = bytestride*height; + out.mip[0].width = width; + out.mip[0].height = height; + out.mip[0].depth = 1; + return Image_WriteKTXFile(filename, fsroot, &out); + }*/ else //extension / type not recognised. return false; return true; diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index 202f354c..a575fea4 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -3103,9 +3103,9 @@ void CL_UpdateExplosions (void) if (ex->flags & Q2RF_BEAM) { ent->rtype = RT_BEAM; - ent->shaderRGBAf[0] = ((d_8to24rgbtable[ex->skinnum & 0xFF] >> 0) & 0xFF)/255.0; - ent->shaderRGBAf[1] = ((d_8to24rgbtable[ex->skinnum & 0xFF] >> 8) & 0xFF)/255.0; - ent->shaderRGBAf[2] = ((d_8to24rgbtable[ex->skinnum & 0xFF] >> 16) & 0xFF)/255.0; + ent->shaderRGBAf[0] = ((d_8to24srgbtable[ex->skinnum & 0xFF] >> 0) & 0xFF)/255.0; + ent->shaderRGBAf[1] = ((d_8to24srgbtable[ex->skinnum & 0xFF] >> 8) & 0xFF)/255.0; + ent->shaderRGBAf[2] = ((d_8to24srgbtable[ex->skinnum & 0xFF] >> 16) & 0xFF)/255.0; } else if (ex->skinnum < 0) { diff --git a/engine/client/client.h b/engine/client/client.h index 441e601e..64be8f41 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -163,6 +163,7 @@ typedef struct player_info_s float teamstatustime; // scoreboard information + int spectator; char name[MAX_SCOREBOARDNAME]; char team[MAX_INFO_KEY]; float realentertime; //pegged against realtime, to cope with potentially not knowing the server's time when we first receive this message @@ -185,21 +186,27 @@ typedef struct player_info_s qboolean ignored; qboolean vignored; - colourised_t *colourised; - // skin information unsigned int rtopcolor; //real, according to their userinfo unsigned int rbottomcolor; +#ifdef QWSKINS + colourised_t *colourised; + + qwskin_t *qwskin; + qwskin_t *lastskin; //last-known-good skin + unsigned int ttopcolor; //team, according to colour forcing unsigned int tbottomcolor; - int spectator; - qwskin_t *qwskin; - qwskin_t *lastskin; //last-known-good skin - skinid_t skinid; - struct model_s *model; + #define dtopcolor ttopcolor + #define dbottomcolor tbottomcolor +#else + #define dtopcolor rtopcolor + #define dbottomcolor rbottomcolor +#endif + skinid_t skinid; // unsigned short vweapindex; #ifdef HEXEN2 diff --git a/engine/client/clq2_ents.c b/engine/client/clq2_ents.c index fc642e67..60d9cd0d 100644 --- a/engine/client/clq2_ents.c +++ b/engine/client/clq2_ents.c @@ -1884,9 +1884,9 @@ static void CLQ2_AddPacketEntities (q2frame_t *frame) if ( renderfx & Q2RF_BEAM ) { // the four beam colors are encoded in 32 bits of skinnum (hack) ent.skinnum = (s1->skinnum >> ((rand() % 4)*8)) & 0xff; - ent.shaderRGBAf[0] = ((d_8to24rgbtable[ent.skinnum & 0xFF] >> 0) & 0xFF)/255.0; - ent.shaderRGBAf[1] = ((d_8to24rgbtable[ent.skinnum & 0xFF] >> 8) & 0xFF)/255.0; - ent.shaderRGBAf[2] = ((d_8to24rgbtable[ent.skinnum & 0xFF] >> 16) & 0xFF)/255.0; + ent.shaderRGBAf[0] = ((d_8to24srgbtable[ent.skinnum & 0xFF] >> 0) & 0xFF)/255.0; + ent.shaderRGBAf[1] = ((d_8to24srgbtable[ent.skinnum & 0xFF] >> 8) & 0xFF)/255.0; + ent.shaderRGBAf[2] = ((d_8to24srgbtable[ent.skinnum & 0xFF] >> 16) & 0xFF)/255.0; ent.shaderRGBAf[3] = 0.30; ent.model = NULL; ent.framestate.g[FS_REG].lerpweight[0] = 0; diff --git a/engine/client/console.c b/engine/client/console.c index 018d7397..6e1e985d 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -2120,12 +2120,12 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in if (l->flags & CONL_EXECUTION) { if (l->flags & CONL_BREAKPOINT) - R2D_ImageColours(0.3,0.15,0.0, alphaval); + R2D_ImageColours(SRGBA(0.3,0.15,0.0, alphaval)); else - R2D_ImageColours(0.3,0.3,0.0, alphaval); + R2D_ImageColours(SRGBA(0.3,0.3,0.0, alphaval)); } else //if (l->flags & CONL_BREAKPOINT) - R2D_ImageColours(0.3,0.0,0.0, alphaval); + R2D_ImageColours(SRGBA(0.3,0.0,0.0, alphaval)); R2D_FillBlock((sx*(float)vid.width)/(float)vid.rotpixelwidth, (y*vid.height)/(float)vid.rotpixelheight, ((ex - sx)*vid.width)/(float)vid.rotpixelwidth, (Font_CharHeight()*vid.height)/(float)vid.rotpixelheight); R2D_Flush(); } @@ -2174,7 +2174,7 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in sstart += center; send += center; - R2D_ImageColours(0.1,0.1,0.3, alphaval); + R2D_ImageColours(SRGBA(0.1,0.1,0.3, alphaval)); if (send < sstart) R2D_FillBlock((send*(float)vid.width)/(float)vid.rotpixelwidth, (y*vid.height)/(float)vid.rotpixelheight, ((sstart - send)*vid.width)/(float)vid.rotpixelwidth, (Font_CharHeight()*vid.height)/(float)vid.rotpixelheight); else @@ -2258,7 +2258,7 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in if (selactive == 1) { - R2D_ImageColours(0.1,0.1,0.3, alphaval); + R2D_ImageColours(SRGBA(0.1,0.1,0.3, alphaval)); if (send < sstart) R2D_FillBlock((send*vid.width)/(float)vid.rotpixelwidth, (y*vid.height)/(float)vid.rotpixelheight, ((sstart - send)*vid.width)/(float)vid.rotpixelwidth, (Font_CharHeight()*vid.height)/(float)vid.rotpixelheight); else @@ -2374,9 +2374,9 @@ void Con_DrawConsole (int lines, qboolean noback) { int top = 8; //padding at the top if (con_curwindow==w) - R2D_ImageColours(0.0, 0.05, 0.1, 0.8); + R2D_ImageColours(SRGBA(0.0, 0.05, 0.1, 0.8)); else - R2D_ImageColours(0.0, 0.05, 0.1, 0.5); + R2D_ImageColours(SRGBA(0.0, 0.05, 0.1, 0.5)); R2D_FillBlock(w->wnd_x, w->wnd_y, w->wnd_w, w->wnd_h); R2D_ImageColours(1, 1, 1, 1); @@ -2495,7 +2495,7 @@ void Con_DrawConsole (int lines, qboolean noback) { if (!fadetime) { - R2D_ImageColours(0, 0.1, 0.2, 1.0); + R2D_ImageColours(SRGBA(0, 0.1, 0.2, 1.0)); if ((w->buttonsdown & CB_SIZELEFT) || (con_curwindow==w && w->mousecursor[0] >= -8 && w->mousecursor[0] < 0 && w->mousecursor[1] >= 8 && w->mousecursor[1] < w->wnd_h)) R2D_FillBlock(w->wnd_x, w->wnd_y+8, 8, w->wnd_h-8); if ((w->buttonsdown & CB_SIZERIGHT) || (con_curwindow==w && w->mousecursor[0] >= w->wnd_w-16 && w->mousecursor[0] < w->wnd_w-8 && w->mousecursor[1] >= 8 && w->mousecursor[1] < w->wnd_h)) diff --git a/engine/client/image.c b/engine/client/image.c index 5255c7b7..675c6b39 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -1112,7 +1112,7 @@ err: qpng_write_info(png_ptr, info_ptr); if (fmt == TF_RGBX32 || fmt == TF_BGRX32) - png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); + qpng_set_filler(png_ptr, 0, PNG_FILLER_AFTER); if (numbuffers == 2) { //standard stereographic png image. @@ -2577,10 +2577,52 @@ static void Image_LoadTextureMips(void *ctx, void *data, size_t a, size_t b) // tex->width = mips->mip[0].width; // tex->height = mips->mip[0].height; + //d3d9 needs to reconfigure samplers depending on whether the data is srgb or not. + switch(mips->encoding) + { + case PTI_RGBA8_SRGB: + case PTI_RGBX8_SRGB: + case PTI_BGRA8_SRGB: + case PTI_BGRX8_SRGB: + case PTI_BC1_RGB_SRGB: + case PTI_BC1_RGBA_SRGB: + case PTI_BC2_RGBA_SRGB: + case PTI_BC3_RGBA_SRGB: + case PTI_BC7_RGBA_SRGB: + case PTI_ETC2_RGB8_SRGB: + case PTI_ETC2_RGB8A1_SRGB: + case PTI_ETC2_RGB8A8_SRGB: + case PTI_ASTC_4X4_SRGB: + case PTI_ASTC_5X4_SRGB: + case PTI_ASTC_5X5_SRGB: + case PTI_ASTC_6X5_SRGB: + case PTI_ASTC_6X6_SRGB: + case PTI_ASTC_8X5_SRGB: + case PTI_ASTC_8X6_SRGB: + case PTI_ASTC_10X5_SRGB: + case PTI_ASTC_10X6_SRGB: + case PTI_ASTC_8X8_SRGB: + case PTI_ASTC_10X8_SRGB: + case PTI_ASTC_10X10_SRGB: + case PTI_ASTC_12X10_SRGB: + case PTI_ASTC_12X12_SRGB: + tex->flags |= IF_SRGB; + break; + default: + tex->flags &= ~IF_SRGB; + break; + } + if (rf->IMG_LoadTextureMips(tex, mips)) + { + tex->format = mips->encoding; tex->status = TEX_LOADED; + } else + { + tex->format = TF_INVALID; tex->status = TEX_FAILED; + } for (i = 0; i < mips->mipcount; i++) if (mips->mip[i].needfree) @@ -2625,6 +2667,136 @@ typedef struct unsigned int numberofmipmaplevels; unsigned int bytesofkeyvaluedata; } ktxheader_t; +void Image_WriteKTXFile(const char *filename, struct pendingtextureinfo *mips) +{ + vfsfile_t *file; + ktxheader_t header = {{0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A}, 0x04030201, + 0/*type*/, 1/*typesize*/, 0/*format*/, 0/*internalformat*/, + 0/*base*/, mips->mip[0].width, mips->mip[0].height, 0/*depth*/, + 0/*array elements*/, (mips->type==PTI_CUBEMAP)?6:1, mips->mipcount, 0/*kvdatasize*/}; + size_t mipnum; + if (mips->type != PTI_2D)// && mips->type != PTI_CUBEMAP) + return; + header.numberofmipmaplevels /= header.numberoffaces; + + switch(mips->encoding) + { + case PTI_ETC1_RGB8: header.glinternalformat = 0x8D64/*GL_ETC1_RGB8_OES*/; break; + case PTI_ETC2_RGB8: header.glinternalformat = 0x9274/*GL_COMPRESSED_RGB8_ETC2*/; break; + case PTI_ETC2_RGB8_SRGB: header.glinternalformat = 0x9275/*GL_COMPRESSED_SRGB8_ETC2*/; break; + case PTI_ETC2_RGB8A1: header.glinternalformat = 0x9276/*GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2*/; break; + case PTI_ETC2_RGB8A1_SRGB: header.glinternalformat = 0x9277/*GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2*/; break; + case PTI_ETC2_RGB8A8: header.glinternalformat = 0x9278/*GL_COMPRESSED_RGBA8_ETC2_EAC*/; break; + case PTI_ETC2_RGB8A8_SRGB: header.glinternalformat = 0x9279/*GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC*/; break; + case PTI_EAC_R11: header.glinternalformat = 0x9270/*GL_COMPRESSED_R11_EAC*/; break; + case PTI_EAC_R11_SNORM: header.glinternalformat = 0x9271/*GL_COMPRESSED_SIGNED_R11_EAC*/; break; + case PTI_EAC_RG11: header.glinternalformat = 0x9272/*GL_COMPRESSED_RG11_EAC*/; break; + case PTI_EAC_RG11_SNORM: header.glinternalformat = 0x9273/*GL_COMPRESSED_SIGNED_RG11_EAC*/; break; + case PTI_BC1_RGB: header.glinternalformat = 0x83F0/*GL_COMPRESSED_RGB_S3TC_DXT1_EXT*/; break; + case PTI_BC1_RGB_SRGB: header.glinternalformat = 0x8C4C/*GL_COMPRESSED_SRGB_S3TC_DXT1_EXT*/; break; + case PTI_BC1_RGBA: header.glinternalformat = 0x83F1/*GL_COMPRESSED_RGBA_S3TC_DXT1_EXT*/; break; + case PTI_BC1_RGBA_SRGB: header.glinternalformat = 0x8C4D/*GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT*/; break; + case PTI_BC2_RGBA: header.glinternalformat = 0x83F2/*GL_COMPRESSED_RGBA_S3TC_DXT3_EXT*/; break; + case PTI_BC2_RGBA_SRGB: header.glinternalformat = 0x8C4E/*GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT*/; break; + case PTI_BC3_RGBA: header.glinternalformat = 0x83F3/*GL_COMPRESSED_RGBA_S3TC_DXT5_EXT*/; break; + case PTI_BC3_RGBA_SRGB: header.glinternalformat = 0x8C4F/*GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT*/; break; + case PTI_BC4_R8_SNORM: header.glinternalformat = 0x8DBC/*GL_COMPRESSED_SIGNED_RED_RGTC1*/; break; + case PTI_BC4_R8: header.glinternalformat = 0x8DBB/*GL_COMPRESSED_RED_RGTC1*/; break; + case PTI_BC5_RG8_SNORM: header.glinternalformat = 0x8DBE/*GL_COMPRESSED_SIGNED_RG_RGTC2*/; break; + case PTI_BC5_RG8: header.glinternalformat = 0x8DBD/*GL_COMPRESSED_RG_RGTC2*/; break; + case PTI_BC6_RGB_UFLOAT: header.glinternalformat = 0x8E8F/*GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB*/; break; + case PTI_BC6_RGB_SFLOAT: header.glinternalformat = 0x8E8E/*GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB*/; break; + case PTI_BC7_RGBA: header.glinternalformat = 0x8E8C/*GL_COMPRESSED_RGBA_BPTC_UNORM_ARB*/; break; + case PTI_BC7_RGBA_SRGB: header.glinternalformat = 0x8E8D/*GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB*/; break; + case PTI_ASTC_4X4: header.glinternalformat = 0x93B0/*GL_COMPRESSED_RGBA_ASTC_4x4_KHR*/; break; + case PTI_ASTC_5X4: header.glinternalformat = 0x93B1/*GL_COMPRESSED_RGBA_ASTC_5x4_KHR*/; break; + case PTI_ASTC_5X5: header.glinternalformat = 0x93B2/*GL_COMPRESSED_RGBA_ASTC_5x5_KHR*/; break; + case PTI_ASTC_6X5: header.glinternalformat = 0x93B3/*GL_COMPRESSED_RGBA_ASTC_6x5_KHR*/; break; + case PTI_ASTC_6X6: header.glinternalformat = 0x93B4/*GL_COMPRESSED_RGBA_ASTC_6x6_KHR*/; break; + case PTI_ASTC_8X5: header.glinternalformat = 0x93B5/*GL_COMPRESSED_RGBA_ASTC_8x5_KHR*/; break; + case PTI_ASTC_8X6: header.glinternalformat = 0x93B6/*GL_COMPRESSED_RGBA_ASTC_8x6_KHR*/; break; + case PTI_ASTC_10X5: header.glinternalformat = 0x93B7/*GL_COMPRESSED_RGBA_ASTC_10x5_KHR*/; break; + case PTI_ASTC_10X6: header.glinternalformat = 0x93B8/*GL_COMPRESSED_RGBA_ASTC_10x6_KHR*/; break; + case PTI_ASTC_8X8: header.glinternalformat = 0x93B9/*GL_COMPRESSED_RGBA_ASTC_8x8_KHR*/; break; + case PTI_ASTC_10X8: header.glinternalformat = 0x93BA/*GL_COMPRESSED_RGBA_ASTC_10x8_KHR*/; break; + case PTI_ASTC_10X10: header.glinternalformat = 0x93BB/*GL_COMPRESSED_RGBA_ASTC_10x10_KHR*/; break; + case PTI_ASTC_12X10: header.glinternalformat = 0x93BC/*GL_COMPRESSED_RGBA_ASTC_12x10_KHR*/; break; + case PTI_ASTC_12X12: header.glinternalformat = 0x93BD/*GL_COMPRESSED_RGBA_ASTC_12x12_KHR*/; break; + case PTI_ASTC_4X4_SRGB: header.glinternalformat = 0x93D0/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR*/; break; + case PTI_ASTC_5X4_SRGB: header.glinternalformat = 0x93D1/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR*/; break; + case PTI_ASTC_5X5_SRGB: header.glinternalformat = 0x93D2/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR*/; break; + case PTI_ASTC_6X5_SRGB: header.glinternalformat = 0x93D3/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR*/; break; + case PTI_ASTC_6X6_SRGB: header.glinternalformat = 0x93D4/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR*/; break; + case PTI_ASTC_8X5_SRGB: header.glinternalformat = 0x93D5/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR*/; break; + case PTI_ASTC_8X6_SRGB: header.glinternalformat = 0x93D6/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR*/; break; + case PTI_ASTC_10X5_SRGB: header.glinternalformat = 0x93D7/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR*/; break; + case PTI_ASTC_10X6_SRGB: header.glinternalformat = 0x93D8/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR*/; break; + case PTI_ASTC_8X8_SRGB: header.glinternalformat = 0x93D9/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR*/; break; + case PTI_ASTC_10X8_SRGB: header.glinternalformat = 0x93DA/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR*/; break; + case PTI_ASTC_10X10_SRGB: header.glinternalformat = 0x93DB/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR*/; break; + case PTI_ASTC_12X10_SRGB: header.glinternalformat = 0x93DC/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR*/; break; + case PTI_ASTC_12X12_SRGB: header.glinternalformat = 0x93DD/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR*/; break; + + case PTI_BGRA8: header.glinternalformat = 0x8058/*GL_RGBA8*/; header.glbaseinternalformat = 0x1908/*GL_RGBA*/; header.glformat = 0x80E1/*GL_BGRA*/; header.gltype = 0x1401/*GL_UNSIGNED_BYTE*/; header.gltypesize = 1; break; + case PTI_RGBA8: header.glinternalformat = 0x8058/*GL_RGBA8*/; header.glbaseinternalformat = 0x1908/*GL_RGBA*/; header.glformat = 0x1908/*GL_RGBA*/; header.gltype = 0x1401/*GL_UNSIGNED_BYTE*/; header.gltypesize = 1; break; + case PTI_BGRA8_SRGB: header.glinternalformat = 0x8C43/*GL_SRGB8_ALPHA8*/; header.glbaseinternalformat = 0x1908/*GL_RGBA*/; header.glformat = 0x80E1/*GL_BGRA*/; header.gltype = 0x1401/*GL_UNSIGNED_BYTE*/; header.gltypesize = 1; break; + case PTI_RGBA8_SRGB: header.glinternalformat = 0x8C43/*GL_SRGB8_ALPHA8*/; header.glbaseinternalformat = 0x1908/*GL_RGBA*/; header.glformat = 0x1908/*GL_RGBA*/; header.gltype = 0x1401/*GL_UNSIGNED_BYTE*/; header.gltypesize = 1; break; + case PTI_L8: header.glinternalformat = 0x8040/*GL_LUMINANCE8*/; header.glbaseinternalformat = 0x1909/*GL_LUMINANCE*/; header.glformat = 0x1909/*GL_LUMINANCE*/; header.gltype = 0x1401/*GL_UNSIGNED_BYTE*/; header.gltypesize = 1; break; + case PTI_L8A8: header.glinternalformat = 0x8045/*GL_LUMINANCE8_ALPHA8*/; header.glbaseinternalformat = 0x190A/*GL_LUMINANCE_ALPHA*/; header.glformat = 0x190A/*GL_LUMINANCE_ALPHA*/; header.gltype = 0x1401/*GL_UNSIGNED_BYTE*/; header.gltypesize = 1; break; + case PTI_RGB8: header.glinternalformat = 0x8051/*GL_RGB8*/; header.glbaseinternalformat = 0x1907/*GL_RGB*/; header.glformat = 0x1907/*GL_RGB*/; header.gltype = 0x1401/*GL_UNSIGNED_BYTE*/; header.gltypesize = 1; break; + case PTI_BGR8: header.glinternalformat = 0x8051/*GL_RGB8*/; header.glbaseinternalformat = 0x1907/*GL_RGB*/; header.glformat = 0x80E0/*GL_BGR*/; header.gltype = 0x1401/*GL_UNSIGNED_BYTE*/; header.gltypesize = 1; break; + case PTI_RGBA16F: header.glinternalformat = 0x881A/*GL_RGBA16F*/; header.glbaseinternalformat = 0x1908/*GL_RGBA*/; header.glformat = 0x1908/*GL_RGBA*/; header.gltype = 0x140B/*GL_HALF_FLOAT*/; header.gltypesize = 2; break; + case PTI_RGBA32F: header.glinternalformat = 0x8814/*GL_RGBA32F*/; header.glbaseinternalformat = 0x1908/*GL_RGBA*/; header.glformat = 0x1908/*GL_RGBA*/; header.gltype = 0x1406/*GL_FLOAT*/; header.gltypesize = 4; break; + case PTI_A2BGR10: header.glinternalformat = 0x8059/*GL_RGB10_A2*/; header.glbaseinternalformat = 0x1908/*GL_RGBA*/; header.glformat = 0x1908/*GL_RGBA*/; header.gltype = 0x8368/*GL_UNSIGNED_INT_2_10_10_10_REV*/; header.gltypesize = 4; break; + case PTI_E5BGR9: header.glinternalformat = 0x8C3D/*GL_RGB9_E5*/; header.glbaseinternalformat = 0x8C3D/*GL_RGB9_E5*/; header.glformat = 0x1907/*GL_RGB*/; header.gltype = 0x8C3E/*GL_UNSIGNED_INT_5_9_9_9_REV*/; header.gltypesize = 4; break; + case PTI_R8: header.glinternalformat = 0x8229/*GL_R8*/; header.glbaseinternalformat = 0x1903/*GL_RED*/; header.glformat = 0x1903/*GL_RED*/; header.gltype = 0x1401/*GL_UNSIGNED_BYTE*/; header.gltypesize = 1; break; + case PTI_RG8: header.glinternalformat = 0x822B/*GL_RG8*/; header.glbaseinternalformat = 0x8227/*GL_RG*/; header.glformat = 0x8227/*GL_RG*/; header.gltype = 0x1401/*GL_UNSIGNED_BYTE*/; header.gltypesize = 1; break; + case PTI_R8_SNORM: header.glinternalformat = 0x8F94/*GL_R8_SNORM*/; header.glbaseinternalformat = 0x1903/*GL_RED*/; header.glformat = 0x1903/*GL_RED*/; header.gltype = 0x1400/*GL_BYTE*/; header.gltypesize = 1; break; + case PTI_RG8_SNORM: header.glinternalformat = 0x8F95/*GL_RG8_SNORM*/; header.glbaseinternalformat = 0x8227/*GL_RG*/; header.glformat = 0x8227/*GL_RG*/; header.gltype = 0x1400/*GL_BYTE*/; header.gltypesize = 1; break; + case PTI_BGRX8: header.glinternalformat = 0x8051/*GL_RGB8*/; header.glbaseinternalformat = 0x1907/*GL_RGB*/; header.glformat = 0x80E1/*GL_BGRA*/; header.gltype = 0x1401/*GL_UNSIGNED_BYTE*/; header.gltypesize = 1; break; + case PTI_RGBX8: header.glinternalformat = 0x8051/*GL_RGB8*/; header.glbaseinternalformat = 0x1907/*GL_RGB*/; header.glformat = 0x1908/*GL_RGBA*/; header.gltype = 0x1401/*GL_UNSIGNED_BYTE*/; header.gltypesize = 1; break; + case PTI_BGRX8_SRGB: header.glinternalformat = 0x8C41/*GL_SRGB8*/; header.glbaseinternalformat = 0x1908/*GL_RGBA*/; header.glformat = 0x80E1/*GL_BGRA*/; header.gltype = 0x1401/*GL_UNSIGNED_BYTE*/; header.gltypesize = 1; break; + case PTI_RGBX8_SRGB: header.glinternalformat = 0x8C41/*GL_SRGB8*/; header.glbaseinternalformat = 0x1908/*GL_RGBA*/; header.glformat = 0x1908/*GL_RGBA*/; header.gltype = 0x1401/*GL_UNSIGNED_BYTE*/; header.gltypesize = 1; break; + case PTI_RGB565: header.glinternalformat = 0x8D62/*GL_RGB565*/; header.glbaseinternalformat = 0x1907/*GL_RGB*/; header.glformat = 0x1907/*GL_RGB*/; header.gltype = 0x8363/*GL_UNSIGNED_SHORT_5_6_5*/; header.gltypesize = 2; break; + case PTI_RGBA4444: header.glinternalformat = 0x8056/*GL_RGBA4*/; header.glbaseinternalformat = 0x1908/*GL_RGBA*/; header.glformat = 0x1908/*GL_RGBA*/; header.gltype = 0x8033/*GL_UNSIGNED_SHORT_4_4_4_4*/; header.gltypesize = 2; break; + case PTI_ARGB4444: header.glinternalformat = 0x8056/*GL_RGBA4*/; header.glbaseinternalformat = 0x1908/*GL_RGBA*/; header.glformat = 0x80E1/*GL_BGRA*/; header.gltype = 0x8365/*GL_UNSIGNED_SHORT_4_4_4_4_REV*/; header.gltypesize = 2; break; + case PTI_RGBA5551: header.glinternalformat = 0x8057/*GL_RGB5_A1*/; header.glbaseinternalformat = 0x1908/*GL_RGBA*/; header.glformat = 0x1908/*GL_RGBA*/; header.gltype = 0x8034/*GL_UNSIGNED_SHORT_5_5_5_1*/; header.gltypesize = 2; break; + case PTI_ARGB1555: header.glinternalformat = 0x8057/*GL_RGB5_A1*/; header.glbaseinternalformat = 0x1908/*GL_RGBA*/; header.glformat = 0x80E1/*GL_BGRA*/; header.gltype = 0x8366/*GL_UNSIGNED_SHORT_1_5_5_5_REV*/; header.gltypesize = 2; break; + case PTI_DEPTH16: header.glinternalformat = 0x81A5/*GL_DEPTH_COMPONENT16*/; header.glbaseinternalformat = 0x1902/*GL_DEPTH_COMPONENT*/; header.glformat = 0x1902/*GL_DEPTH_COMPONENT*/; header.gltype = 0x1403/*GL_UNSIGNED_SHORT*/; header.gltypesize = 2; break; + case PTI_DEPTH24: header.glinternalformat = 0x81A6/*GL_DEPTH_COMPONENT24*/; header.glbaseinternalformat = 0x1902/*GL_DEPTH_COMPONENT*/; header.glformat = 0x1902/*GL_DEPTH_COMPONENT*/; header.gltype = 0x1405/*GL_UNSIGNED_INT*/; header.gltypesize = 4; break; + case PTI_DEPTH32: header.glinternalformat = 0x81A7/*GL_DEPTH_COMPONENT32*/; header.glbaseinternalformat = 0x1902/*GL_DEPTH_COMPONENT*/; header.glformat = 0x1902/*GL_DEPTH_COMPONENT*/; header.gltype = 0x1406/*GL_FLOAT*/; header.gltypesize = 4; break; + case PTI_DEPTH24_8: header.glinternalformat = 0x88F0/*GL_DEPTH24_STENCIL8*/; header.glbaseinternalformat = 0x84F9/*GL_DEPTH_STENCIL*/; header.glformat = 0x84F9/*GL_DEPTH_STENCIL*/; header.gltype = 0x84FA/*GL_UNSIGNED_INT_24_8*/; header.gltypesize = 4; break; + + case PTI_EMULATED: + case PTI_MAX: + return; + +// default: +// return; + } + + if (strchr(filename, '*') || strchr(filename, ':')) + return; + + file = FS_OpenVFS(filename, "wb", FS_GAMEONLY); + if (!file) + return; + VFS_WRITE(file, &header, sizeof(header)); + + for (mipnum = 0; mipnum < mips->mipcount; mipnum++) + { + unsigned int pad = 0; + unsigned int sz = mips->mip[mipnum].datasize; + if (!(mipnum % header.numberoffaces)) + VFS_WRITE(file, &sz, 4); + + VFS_WRITE(file, mips->mip[mipnum].data, sz); + if ((sz & 3) && mips->type == PTI_CUBEMAP) + VFS_WRITE(file, &pad, 4-(sz&3)); + } + + VFS_CLOSE(file); +} static struct pendingtextureinfo *Image_ReadKTXFile(unsigned int flags, char *fname, qbyte *filedata, size_t filesize) { static const char magic[12] = {0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A}; @@ -2633,9 +2805,9 @@ static struct pendingtextureinfo *Image_ReadKTXFile(unsigned int flags, char *fn int mipnum; int face; int datasize; - unsigned int w, h; + unsigned int w, h, d; struct pendingtextureinfo *mips; - int encoding; + int encoding = TF_INVALID; qbyte *in; if (memcmp(filedata, magic, sizeof(magic))) @@ -2662,9 +2834,14 @@ static struct pendingtextureinfo *Image_ReadKTXFile(unsigned int flags, char *fn if (header->pixeldepth && header->pixelwidth != header->pixeldepth && header->pixelheight != header->pixeldepth) return NULL; //we only support 3d textures where width+height+depth are the same. too lazy to change it now. + /*FIXME: validate format+type for non-compressed formats*/ switch(header->glinternalformat) { case 0x8D64/*GL_ETC1_RGB8_OES*/: encoding = PTI_ETC1_RGB8; break; + case 0x9270/*GL_COMPRESSED_R11_EAC*/: encoding = PTI_EAC_R11; break; + case 0x9271/*GL_COMPRESSED_SIGNED_R11_EAC*/: encoding = PTI_EAC_R11_SNORM; break; + case 0x9272/*GL_COMPRESSED_RG11_EAC*/: encoding = PTI_EAC_RG11; break; + case 0x9273/*GL_COMPRESSED_SIGNED_RG11_EAC*/: encoding = PTI_EAC_RG11_SNORM; break; case 0x9274/*GL_COMPRESSED_RGB8_ETC2*/: encoding = PTI_ETC2_RGB8; break; case 0x9275/*GL_COMPRESSED_SRGB8_ETC2*/: encoding = PTI_ETC2_RGB8_SRGB; break; case 0x9276/*GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2*/: encoding = PTI_ETC2_RGB8A1; break; @@ -2679,12 +2856,12 @@ static struct pendingtextureinfo *Image_ReadKTXFile(unsigned int flags, char *fn case 0x8C4E/*GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT*/: encoding = PTI_BC2_RGBA_SRGB; break; case 0x83F3/*GL_COMPRESSED_RGBA_S3TC_DXT5_EXT*/: encoding = PTI_BC3_RGBA; break; case 0x8C4F/*GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT*/: encoding = PTI_BC3_RGBA_SRGB; break; - case 0x8DBC/*GL_COMPRESSED_SIGNED_RED_RGTC1*/: encoding = PTI_BC4_R8_SIGNED; break; + case 0x8DBC/*GL_COMPRESSED_SIGNED_RED_RGTC1*/: encoding = PTI_BC4_R8_SNORM; break; case 0x8DBB/*GL_COMPRESSED_RED_RGTC1*/: encoding = PTI_BC4_R8; break; - case 0x8DBE/*GL_COMPRESSED_SIGNED_RG_RGTC2*/: encoding = PTI_BC5_RG8_SIGNED; break; + case 0x8DBE/*GL_COMPRESSED_SIGNED_RG_RGTC2*/: encoding = PTI_BC5_RG8_SNORM; break; case 0x8DBD/*GL_COMPRESSED_RG_RGTC2*/: encoding = PTI_BC5_RG8; break; - case 0x8E8F/*GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB*/: encoding = PTI_BC6_RGBF; break; - case 0x8E8E/*GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB*/: encoding = PTI_BC6_RGBF_SIGNED; break; + case 0x8E8F/*GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB*/: encoding = PTI_BC6_RGB_UFLOAT; break; + case 0x8E8E/*GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB*/: encoding = PTI_BC6_RGB_SFLOAT; break; case 0x8E8C/*GL_COMPRESSED_RGBA_BPTC_UNORM_ARB*/: encoding = PTI_BC7_RGBA; break; case 0x8E8D/*GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB*/: encoding = PTI_BC7_RGBA_SRGB; break; case 0x93B0/*GL_COMPRESSED_RGBA_ASTC_4x4_KHR*/: encoding = PTI_ASTC_4X4; break; @@ -2715,17 +2892,67 @@ static struct pendingtextureinfo *Image_ReadKTXFile(unsigned int flags, char *fn case 0x93DB/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR*/: encoding = PTI_ASTC_10X10_SRGB; break; case 0x93DC/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR*/: encoding = PTI_ASTC_12X10_SRGB; break; case 0x93DD/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR*/: encoding = PTI_ASTC_12X12_SRGB; break; - case 0x80E1/*GL_BGRA_EXT*/: encoding = PTI_BGRA8; break; - case 0x1908/*GL_RGBA*/: encoding = PTI_RGBA8; break; - case 0x8C43/*GL_SRGB8_ALPHA8_EXT*/: encoding = PTI_RGBA8_SRGB; break; - case 0x8045/*GL_LUMINANCE8_ALPHA8*/: encoding = PTI_LUMINANCE8_ALPHA8; break; - case 0x8051/*GL_RGB8*/: encoding = PTI_RGB8; break; -// case 0x????/*GL_BGR8_EXT*/: encoding = PTI_BGR8; break; + case 0x80E1/*GL_BGRA_EXT*/: encoding = PTI_BGRA8; break; //not even an internal format + case 0x1908/*GL_RGBA*/: encoding = (header->glformat==0x80E1/*GL_BGRA*/)?PTI_BGRA8:PTI_RGBA8; break; //unsized types shouldn't really be here + case 0x8C43/*GL_SRGB8_ALPHA8*/: encoding = (header->glformat==0x80E1/*GL_BGRA*/)?PTI_BGRA8_SRGB:PTI_RGBA8_SRGB; break; + case 0x8040/*GL_LUMINANCE8*/: encoding = PTI_L8; break; + case 0x8045/*GL_LUMINANCE8_ALPHA8*/: encoding = PTI_L8A8; break; case 0x881A/*GL_RGBA16F_ARB*/: encoding = PTI_RGBA16F; break; case 0x8814/*GL_RGBA32F_ARB*/: encoding = PTI_RGBA32F; break; + case 0x8059/*GL_RGB10_A2*/: encoding = PTI_A2BGR10; break; + case 0x8229/*GL_R8*/: encoding = PTI_R8; break; + case 0x822B/*GL_RG8*/: encoding = PTI_RG8; break; + case 0x8F94/*GL_R8_SNORM*/: encoding = PTI_R8_SNORM; break; + case 0x8F95/*GL_RG8_SNORM*/: encoding = PTI_RG8_SNORM; break; + case 0x81A5/*GL_DEPTH_COMPONENT16*/: encoding = PTI_DEPTH16; break; + case 0x81A6/*GL_DEPTH_COMPONENT24*/: encoding = PTI_DEPTH24; break; + case 0x81A7/*GL_DEPTH_COMPONENT32*/: encoding = PTI_DEPTH32; break; + case 0x88F0/*GL_DEPTH24_STENCIL8*/: encoding = PTI_DEPTH24_8; break; - //note: this could be pretty much anything, including 24bit data. - default: + case 0x8C40/*GL_SRGB*/: + case 0x8C41/*GL_SRGB8*/: + if (header->glformat==0x80E1/*GL_BGRA*/) + encoding = PTI_BGRX8_SRGB; + else if (header->glformat==0x1908/*GL_RGBA*/) + encoding = PTI_RGBX8_SRGB; + break; + + case 0x1907/*GL_RGB*/: //invalid sized format. treat as GL_RGB8, and do weird checks. + case 0x8051/*GL_RGB8*/: //other sized RGB formats are treated based upon the data format rather than the sized format, in case they were meant to be converted by the driver... + case 0x8C3D/*GL_RGB9_E5*/: + case 0x8D62/*GL_RGB565*/: + if (header->glformat == 0x80E0/*GL_BGR*/) + encoding = PTI_BGR8; + else if (header->glformat == 0x80E1/*GL_BGRA*/) + encoding = PTI_BGRX8; + else if (header->glformat == 0x1907/*GL_RGB*/) + { + if (header->gltype == 0x8C3E/*GL_UNSIGNED_INT_5_9_9_9_REV*/) + encoding = PTI_E5BGR9; + else if (header->gltype == 0x8363/*GL_UNSIGNED_SHORT_5_6_5*/) + encoding = PTI_RGB565; + else + encoding = PTI_RGB8; + } + else if (header->glformat == 0x1908/*GL_RGBA*/) + encoding = PTI_RGBX8; + else + encoding = PTI_RGB8; + break; + case 0x8056/*GL_RGBA4*/: + case 0x8057/*GL_RGB5_A1*/: + if (header->glformat == 0x1908/*GL_RGBA*/ && header->gltype == 0x8034/*GL_UNSIGNED_SHORT_5_5_5_1*/) + encoding = PTI_RGBA5551; + else if (header->glformat == 0x80E1/*GL_BGRA*/ && header->gltype == 0x8366/*GL_UNSIGNED_SHORT_1_5_5_5_REV*/) + encoding = PTI_ARGB1555; + else if (header->glformat == 0x1908/*GL_RGBA*/ && header->gltype == 0x8033/*GL_UNSIGNED_SHORT_4_4_4_4*/) + encoding = PTI_RGBA4444; + else if (header->glformat == 0x80E1/*GL_BGRA*/ && header->gltype == 0x8365/*GL_UNSIGNED_SHORT_4_4_4_4_REV*/) + encoding = PTI_ARGB4444; + break; + } + if (encoding == TF_INVALID) + { Con_Printf("Unsupported ktx internalformat %x in %s\n", header->glinternalformat, fname); return NULL; } @@ -2741,9 +2968,25 @@ static struct pendingtextureinfo *Image_ReadKTXFile(unsigned int flags, char *fn if (header->pixeldepth) mips->type = PTI_3D; else if (header->numberoffaces==6) - mips->type = PTI_CUBEMAP; + { + if (header->numberofarrayelements) + { + header->pixeldepth = header->numberofarrayelements*6; + mips->type = PTI_CUBEMAP_ARRAY; + } + else + mips->type = PTI_CUBEMAP; + } else - mips->type = PTI_2D; + { + if (header->numberofarrayelements) + { + header->pixeldepth = header->numberofarrayelements; + mips->type = PTI_2D_ARRAY; + } + else + mips->type = PTI_2D; + } mips->extrafree = filedata; mips->encoding = encoding; @@ -2755,10 +2998,13 @@ static struct pendingtextureinfo *Image_ReadKTXFile(unsigned int flags, char *fn w = header->pixelwidth; h = header->pixelheight; + d = header->pixeldepth; for (mipnum = 0; mipnum < nummips; mipnum++) { datasize = *(int*)filedata; filedata += 4; + //FIXME: validate the data size + for (face = 0; face < header->numberoffaces; face++) { if (mips->mipcount >= countof(mips->mip)) @@ -2767,14 +3013,17 @@ static struct pendingtextureinfo *Image_ReadKTXFile(unsigned int flags, char *fn mips->mip[mips->mipcount].datasize = datasize; mips->mip[mips->mipcount].width = w; mips->mip[mips->mipcount].height = h; + mips->mip[mips->mipcount].depth = d; mips->mipcount++; filedata += datasize; - if (datasize & 3) + if ((datasize & 3) && mips->type == PTI_CUBEMAP) filedata += 4-(datasize&3); } w = (w+1)>>1; h = (h+1)>>1; + if (mips->type == PTI_3D) + d = (d+1)>>1; } return mips; @@ -2817,9 +3066,9 @@ static struct pendingtextureinfo *Image_ReadPKMFile(unsigned int flags, char *fn else if (dfmt == 6) encoding = PTI_EAC_RG11; else if (dfmt == 7) - encoding = PTI_EAC_R11_SIGNED; + encoding = PTI_EAC_R11_SNORM; else if (dfmt == 8) - encoding = PTI_EAC_RG11_SIGNED; + encoding = PTI_EAC_RG11_SNORM; else if (dfmt == 9) encoding = PTI_ETC2_RGB8_SRGB; //srgb else if (dfmt == 10) @@ -2840,13 +3089,13 @@ static struct pendingtextureinfo *Image_ReadPKMFile(unsigned int flags, char *fn case PTI_ETC2_RGB8A1: case PTI_ETC2_RGB8A1_SRGB: case PTI_EAC_R11: - case PTI_EAC_R11_SIGNED: + case PTI_EAC_R11_SNORM: blockbytes = 8; break; case PTI_ETC2_RGB8A8: case PTI_ETC2_RGB8A8_SRGB: case PTI_EAC_RG11: - case PTI_EAC_RG11_SIGNED: + case PTI_EAC_RG11_SNORM: blockbytes = 16; break; default: @@ -2865,6 +3114,7 @@ static struct pendingtextureinfo *Image_ReadPKMFile(unsigned int flags, char *fn mips->mip[0].datasize = filesize-16; mips->mip[0].width = imgwidth; mips->mip[0].height = imgheight; + mips->mip[0].depth = 1; mips->mip[0].needfree = false; return mips; } @@ -2976,6 +3226,15 @@ static struct pendingtextureinfo *Image_ReadDDSFile(unsigned int flags, char *fn // pad = 8; switch(fmt10header.dxgiformat) { + case 10/*DXGI_FORMAT_R16G16B16A16_FLOAT*/: + encoding = PTI_RGBA16F; + break; + case 24/*DXGI_FORMAT_R10G10B10A2_UNORM*/: + encoding = PTI_A2BGR10; + break; + case 67/*DXGI_FORMAT_R9G9B9E5_SHAREDEXP*/: + encoding = PTI_E5BGR9; + break; case 71/*DXGI_FORMAT_BC1_UNORM*/: encoding = PTI_BC1_RGBA; break; @@ -2998,19 +3257,25 @@ static struct pendingtextureinfo *Image_ReadDDSFile(unsigned int flags, char *fn encoding = PTI_BC4_R8; break; case 81/*DXGI_FORMAT_BC4_SNORM*/: - encoding = PTI_BC4_R8_SIGNED; + encoding = PTI_BC4_R8_SNORM; break; case 83/*DXGI_FORMAT_BC5_UNORM*/: encoding = PTI_BC5_RG8; break; case 84/*DXGI_FORMAT_BC5_SNORM*/: - encoding = PTI_BC5_RG8_SIGNED; + encoding = PTI_BC5_RG8_SNORM; + break; + case 85/*DXGI_FORMAT_B5G6R5_UNORM*/: + encoding = PTI_RGB565; + break; + case 86/*DXGI_FORMAT_B5G5R5A1_UNORM*/: + encoding = PTI_ARGB1555; break; case 95/*DXGI_FORMAT_BC6H_UF16*/: - encoding = PTI_BC6_RGBF; + encoding = PTI_BC6_RGB_UFLOAT; break; case 96/*DXGI_FORMAT_BC6H_SF16*/: - encoding = PTI_BC6_RGBF_SIGNED; + encoding = PTI_BC6_RGB_SFLOAT; break; case 98/*DXGI_FORMAT_BC7_UNORM*/: encoding = PTI_BC7_RGBA; @@ -3077,6 +3342,7 @@ static struct pendingtextureinfo *Image_ReadDDSFile(unsigned int flags, char *fn mips->mip[mips->mipcount].datasize = datasize; mips->mip[mips->mipcount].width = w; mips->mip[mips->mipcount].height = h; + mips->mip[mips->mipcount].depth = 1; mips->mipcount++; filedata += datasize; } @@ -3157,6 +3423,7 @@ static struct pendingtextureinfo *Image_ReadBLPFile(unsigned int flags, char *fn break; mips->mip[miplevel].width = w; mips->mip[miplevel].height = h; + mips->mip[miplevel].depth = 1; mips->mip[miplevel].data = filedata + LittleLong(blp->mipoffset[miplevel]); mips->mip[miplevel].datasize = LittleLong(blp->mipsize[miplevel]); @@ -3199,6 +3466,7 @@ static struct pendingtextureinfo *Image_ReadBLPFile(unsigned int flags, char *fn mips->mip[miplevel].width = w; mips->mip[miplevel].height = h; + mips->mip[miplevel].depth = 1; mips->mip[miplevel].datasize = 4*w*h; mips->mip[miplevel].data = tmpmem = BZ_Malloc(4*w*h); mips->mip[miplevel].needfree = true; @@ -3566,6 +3834,7 @@ static void Image_GenerateMips(struct pendingtextureinfo *mips, unsigned int fla { mips->mip[mip].width = mips->mip[mip-1].width >> 1; mips->mip[mip].height = mips->mip[mip-1].height >> 1; + mips->mip[mip].depth = 1; if (mips->mip[mip].width < 1 && mips->mip[mip].height < 1) break; if (mips->mip[mip].width < 1) @@ -3592,6 +3861,7 @@ static void Image_GenerateMips(struct pendingtextureinfo *mips, unsigned int fla { mips->mip[mip].width = mips->mip[mip-1].width >> 1; mips->mip[mip].height = mips->mip[mip-1].height >> 1; + mips->mip[mip].depth = 1; if (mips->mip[mip].width < 1 && mips->mip[mip].height < 1) break; if (mips->mip[mip].width < 1) @@ -3928,145 +4198,212 @@ static void Image_RoundDimensions(int *scaled_width, int *scaled_height, unsigne } //may operate in place -static void Image_8888to565(qbyte *in, unsigned short *out, unsigned int w, unsigned int h, qboolean bgra) +static void Image_8888to565(struct pendingtextureinfo *mips, qboolean bgra) { - unsigned int p = w*h; - unsigned short tmp; + unsigned int mip; + for (mip = 0; mip < mips->mipcount; mip++) + { + qbyte *in = mips->mip[mip].data; + unsigned short *out = mips->mip[mip].data; + unsigned int w = mips->mip[mip].width; + unsigned int h = mips->mip[mip].height; + unsigned int p = w*h; + unsigned short tmp; + if (!mips->mip[mip].needfree && !mips->extrafree) + { + mips->mip[mip].needfree = true; + mips->mip[mip].data = out = BZ_Malloc(sizeof(tmp)*p); + } - if (bgra) - { - while(p-->0) + if (bgra) { - tmp = ((*in++>>3) << 0);//b - tmp |= ((*in++>>2) << 5);//g - tmp |= ((*in++>>3) << 11);//r - in++; - *out++ = tmp; + while(p-->0) + { + tmp = ((*in++>>3) << 0);//b + tmp |= ((*in++>>2) << 5);//g + tmp |= ((*in++>>3) << 11);//r + in++; + *out++ = tmp; + } } - } - else - { - while(p-->0) + else { - tmp = ((*in++>>3) << 11);//r - tmp |= ((*in++>>2) << 5);//g - tmp |= ((*in++>>3) << 0);//b - in++; - *out++ = tmp; + while(p-->0) + { + tmp = ((*in++>>3) << 11);//r + tmp |= ((*in++>>2) << 5);//g + tmp |= ((*in++>>3) << 0);//b + in++; + *out++ = tmp; + } } } } -//may operate in place -static void Image_8888to1555(qbyte *in, unsigned short *out, unsigned int w, unsigned int h, qboolean bgra) -{ - unsigned int p = w*h; - unsigned short tmp; - if (bgra) - { - while(p-->0) - { - tmp = ((*in++>>3) << 0);//b - tmp |= ((*in++>>3) << 5);//g - tmp |= ((*in++>>3) << 10);//r - tmp |= ((*in++>>7) << 15);//a - *out++ = tmp; - } - } - else - { - while(p-->0) - { - tmp = ((*in++>>3) << 10);//r - tmp |= ((*in++>>3) << 5);//g - tmp |= ((*in++>>3) << 0);//b - tmp |= ((*in++>>7) << 15);//a - *out++ = tmp; - } - } -} -//may operate in place -static void Image_8888to5551(qbyte *in, unsigned short *out, unsigned int w, unsigned int h, qboolean bgra) -{ - unsigned int p = w*h; - unsigned short tmp; - if (bgra) - { - while(p-->0) - { - tmp = ((*in++>>3) << 1);//b - tmp |= ((*in++>>3) << 6);//g - tmp |= ((*in++>>3) << 11);//r - tmp |= ((*in++>>7) << 0);//a - *out++ = tmp; - } - } - else - { - while(p-->0) - { - tmp = ((*in++>>3) << 11);//r - tmp |= ((*in++>>3) << 6);//g - tmp |= ((*in++>>3) << 1);//b - tmp |= ((*in++>>7) << 0);//a - *out++ = tmp; - } - } -} -//may operate in place -static void Image_8888to4444(qbyte *in, unsigned short *out, unsigned int w, unsigned int h, qboolean bgra) -{ - unsigned int p = w*h; - unsigned short tmp; - if (bgra) +static void Image_8888to1555(struct pendingtextureinfo *mips, qboolean bgra) +{ + unsigned int mip; + for (mip = 0; mip < mips->mipcount; mip++) { - while(p-->0) + qbyte *in = mips->mip[mip].data; + unsigned short *out = mips->mip[mip].data; + unsigned int w = mips->mip[mip].width; + unsigned int h = mips->mip[mip].height; + unsigned int p = w*h; + unsigned short tmp; + if (!mips->mip[mip].needfree && !mips->extrafree) { - tmp = ((*in++>>4) << 4);//b - tmp |= ((*in++>>4) << 8);//g - tmp |= ((*in++>>4) << 12);//r - tmp |= ((*in++>>4) << 0);//a - *out++ = tmp; + mips->mip[mip].needfree = true; + mips->mip[mip].data = out = BZ_Malloc(sizeof(tmp)*p); + } + + if (bgra) + { + while(p-->0) + { + tmp = ((*in++>>3) << 0);//b + tmp |= ((*in++>>3) << 5);//g + tmp |= ((*in++>>3) << 10);//r + tmp |= ((*in++>>7) << 15);//a + *out++ = tmp; + } + } + else + { + while(p-->0) + { + tmp = ((*in++>>3) << 10);//r + tmp |= ((*in++>>3) << 5);//g + tmp |= ((*in++>>3) << 0);//b + tmp |= ((*in++>>7) << 15);//a + *out++ = tmp; + } } } - else +} + +static void Image_8888to5551(struct pendingtextureinfo *mips, qboolean bgra) +{ + unsigned int mip; + for (mip = 0; mip < mips->mipcount; mip++) { - while(p-->0) + qbyte *in = mips->mip[mip].data; + unsigned short *out = mips->mip[mip].data; + unsigned int w = mips->mip[mip].width; + unsigned int h = mips->mip[mip].height; + unsigned int p = w*h; + unsigned short tmp; + if (!mips->mip[mip].needfree && !mips->extrafree) { - tmp = ((*in++>>4) << 12);//r - tmp |= ((*in++>>4) << 8);//g - tmp |= ((*in++>>4) << 4);//b - tmp |= ((*in++>>4) << 0);//a - *out++ = tmp; + mips->mip[mip].needfree = true; + mips->mip[mip].data = out = BZ_Malloc(sizeof(tmp)*p); + } + + if (bgra) + { + while(p-->0) + { + tmp = ((*in++>>3) << 1);//b + tmp |= ((*in++>>3) << 6);//g + tmp |= ((*in++>>3) << 11);//r + tmp |= ((*in++>>7) << 0);//a + *out++ = tmp; + } + } + else + { + while(p-->0) + { + tmp = ((*in++>>3) << 11);//r + tmp |= ((*in++>>3) << 6);//g + tmp |= ((*in++>>3) << 1);//b + tmp |= ((*in++>>7) << 0);//a + *out++ = tmp; + } + } + } +} + +static void Image_8888to4444(struct pendingtextureinfo *mips, qboolean bgra) +{ + unsigned int mip; + for (mip = 0; mip < mips->mipcount; mip++) + { + qbyte *in = mips->mip[mip].data; + unsigned short *out = mips->mip[mip].data; + unsigned int w = mips->mip[mip].width; + unsigned int h = mips->mip[mip].height; + unsigned int p = w*h; + unsigned short tmp; + if (!mips->mip[mip].needfree && !mips->extrafree) + { + mips->mip[mip].needfree = true; + mips->mip[mip].data = out = BZ_Malloc(sizeof(tmp)*p); + } + + if (bgra) + { + while(p-->0) + { + tmp = ((*in++>>4) << 4);//b + tmp |= ((*in++>>4) << 8);//g + tmp |= ((*in++>>4) << 12);//r + tmp |= ((*in++>>4) << 0);//a + *out++ = tmp; + } + } + else + { + while(p-->0) + { + tmp = ((*in++>>4) << 12);//r + tmp |= ((*in++>>4) << 8);//g + tmp |= ((*in++>>4) << 4);//b + tmp |= ((*in++>>4) << 0);//a + *out++ = tmp; + } } } } //may operate in place -static void Image_8888toARGB4444(qbyte *in, unsigned short *out, unsigned int w, unsigned int h, qboolean bgra) +static void Image_8888toARGB4444(struct pendingtextureinfo *mips, qboolean bgra) { - unsigned int p = w*h; - unsigned short tmp; - - if (bgra) + unsigned int mip; + for (mip = 0; mip < mips->mipcount; mip++) { - while(p-->0) + qbyte *in = mips->mip[mip].data; + unsigned short *out = mips->mip[mip].data; + unsigned int w = mips->mip[mip].width; + unsigned int h = mips->mip[mip].height; + unsigned int p = w*h; + unsigned short tmp; + if (!mips->mip[mip].needfree && !mips->extrafree) { - tmp = ((*in++>>4) << 0);//b - tmp |= ((*in++>>4) << 4);//g - tmp |= ((*in++>>4) << 8);//r - tmp |= ((*in++>>4) << 12);//a - *out++ = tmp; + mips->mip[mip].needfree = true; + mips->mip[mip].data = out = BZ_Malloc(sizeof(tmp)*p); } - } - else - { - while(p-->0) + + if (bgra) { - tmp = ((*in++>>4) << 8);//r - tmp |= ((*in++>>4) << 4);//g - tmp |= ((*in++>>4) << 0);//b - tmp |= ((*in++>>4) << 12);//a - *out++ = tmp; + while(p-->0) + { + tmp = ((*in++>>4) << 0);//b + tmp |= ((*in++>>4) << 4);//g + tmp |= ((*in++>>4) << 8);//r + tmp |= ((*in++>>4) << 12);//a + *out++ = tmp; + } + } + else + { + while(p-->0) + { + tmp = ((*in++>>4) << 8);//r + tmp |= ((*in++>>4) << 4);//g + tmp |= ((*in++>>4) << 0);//b + tmp |= ((*in++>>4) << 12);//a + *out++ = tmp; + } } } } @@ -4092,7 +4429,7 @@ typedef union } pixel32_t; #ifdef DECOMPRESS_ETC2 //FIXME: this is littleendian only... -static void Image_ETC2_Decode_Block_TH_Internal(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w, pixel32_t base1, pixel32_t base2, int d, qboolean tmode) +static void Image_Decode_ETC2_Block_TH_Internal(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w, pixel32_t base1, pixel32_t base2, int d, qboolean tmode) { pixel32_t painttable[4]; int dtab[] = {3,6,11,16,23,32,41,64}; //writing that felt like giving out lottery numbers. @@ -4145,7 +4482,7 @@ static void Image_ETC2_Decode_Block_TH_Internal(qbyte *fte_restrict in, pixel32_ etc2_th_pix(out[3], 15); #undef etc2_th_pix } -static void Image_ETC2_Decode_Block_Internal(qbyte *fte_restrict in, pixel32_t *fte_restrict out0, int w, int alphamode) +static void Image_Decode_ETC2_Block_Internal(qbyte *fte_restrict in, pixel32_t *fte_restrict out0, int w, int alphamode) { static const char tab[8][2] = { @@ -4187,7 +4524,7 @@ static void Image_ETC2_Decode_Block_Internal(qbyte *fte_restrict in, pixel32_t * tv = ((in[3]&0x0c)>>1)|(in[3]&0x01); etc_expandv(base1,4,4,4); etc_expandv(base2,4,4,4); - Image_ETC2_Decode_Block_TH_Internal(in, out0, w, base1, base2, tv, true); + Image_Decode_ETC2_Block_TH_Internal(in, out0, w, base1, base2, tv, true); return; } G1 += (char)((in[1]&3)|((in[1]&4)*0x3f)); //48+3 @@ -4198,7 +4535,7 @@ static void Image_ETC2_Decode_Block_Internal(qbyte *fte_restrict in, pixel32_t * tv = ((in[3]&0x04)>>1)|(in[3]&0x01); etc_expandv(base1,4,4,4); etc_expandv(base2,4,4,4); - Image_ETC2_Decode_Block_TH_Internal(in, out0, w, base1, base2, tv, false); + Image_Decode_ETC2_Block_TH_Internal(in, out0, w, base1, base2, tv, false); return; } B1 += (char)((in[2]&3)|((in[2]&4)*0x3f)); //40+3 @@ -4296,7 +4633,7 @@ static void Image_ETC2_Decode_Block_Internal(qbyte *fte_restrict in, pixel32_t * } #undef etc1_pix } -static void Image_EAC8U_Decode_Block_Internal(qbyte *fte_restrict in, qbyte *fte_restrict out, int stride, qboolean goestoeleven) +static void Image_Decode_EAC8U_Block_Internal(qbyte *fte_restrict in, qbyte *fte_restrict out, int stride, qboolean goestoeleven) { static const char tabs[16][8] = { @@ -4329,44 +4666,44 @@ static void Image_EAC8U_Decode_Block_Internal(qbyte *fte_restrict in, qbyte *fte #undef EAC_Row #undef EAC_Pix } -static void Image_ETC2_RGB8_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +static void Image_Decode_ETC2_RGB8_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) { - Image_ETC2_Decode_Block_Internal(in, out, w, false); + Image_Decode_ETC2_Block_Internal(in, out, w, false); } //punchthrough alpha works by removing interleaved mode releasing a bit that says whether a block can have alpha=0, . -static void Image_ETC2_RGB8A1_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +static void Image_Decode_ETC2_RGB8A1_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) { - Image_ETC2_Decode_Block_Internal(in, out, w, true); + Image_Decode_ETC2_Block_Internal(in, out, w, true); } //ETC2 RGBA's alpha and R11(and RG11) work the same way as each other, but with varying extra blocks with either 8 or 11 bits of valid precision. -static void Image_ETC2_RGB8A8_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +static void Image_Decode_ETC2_RGB8A8_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) { - Image_ETC2_Decode_Block_Internal(in+8, out, w, false); - Image_EAC8U_Decode_Block_Internal(in, out->v+3, w*4, false); + Image_Decode_ETC2_Block_Internal(in+8, out, w, false); + Image_Decode_EAC8U_Block_Internal(in, out->v+3, w*4, false); } -static void Image_EAC_R11U_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +static void Image_Decode_EAC_R11U_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) { pixel32_t r; int i = 0; Vector4Set(r.v, 0, 0, 0, 0xff); for (i = 0; i < 4; i++) out[w*0+i] = out[w*1+i] = out[w*2+i] = out[w*3+i] = r; - Image_EAC8U_Decode_Block_Internal(in, out->v, w*4, false); + Image_Decode_EAC8U_Block_Internal(in, out->v, w*4, false); } -static void Image_EAC_RG11U_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +static void Image_Decode_EAC_RG11U_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) { pixel32_t r; int i = 0; Vector4Set(r.v, 0, 0, 0, 0xff); for (i = 0; i < 4; i++) out[w*0+i] = out[w*1+i] = out[w*2+i] = out[w*3+i] = r; - Image_EAC8U_Decode_Block_Internal(in, out->v+0, w*4, false); - Image_EAC8U_Decode_Block_Internal(in+8, out->v+1, w*4, false); + Image_Decode_EAC8U_Block_Internal(in, out->v+0, w*4, false); + Image_Decode_EAC8U_Block_Internal(in+8, out->v+1, w*4, false); } #endif #ifdef DECOMPRESS_S3TC -static void Image_S3TC_Decode_Block_Internal(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w, qbyte blackalpha) +static void Image_Decode_S3TC_Block_Internal(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w, qbyte blackalpha) { pixel32_t tab[4]; unsigned int bits; @@ -4412,15 +4749,15 @@ static void Image_S3TC_Decode_Block_Internal(qbyte *fte_restrict in, pixel32_t * BC1_Pix(out[2], 14); BC1_Pix(out[3], 15); } -static void Image_BC1_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +static void Image_Decode_BC1_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) { Image_S3TC_Decode_Block_Internal(in, out, w, 0xff); } -static void Image_BC1A_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +static void Image_Decode_BC1A_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) { Image_S3TC_Decode_Block_Internal(in, out, w, 0); } -static void Image_BC2_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +static void Image_Decode_BC2_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) { Image_S3TC_Decode_Block_Internal(in+8, out, w, 0xff); @@ -4442,7 +4779,7 @@ static void Image_BC2_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restri } #endif #ifdef DECOMPRESS_RGTC -static void Image_RGTC_Decode_Block_Internal(qbyte *fte_restrict in, qbyte *fte_restrict out, int stride, qboolean issigned) +static void Image_Decode_RGTC_Block_Internal(qbyte *fte_restrict in, qbyte *fte_restrict out, int stride, qboolean issigned) { quint64_t bits; union @@ -4504,64 +4841,68 @@ static void Image_RGTC_Decode_Block_Internal(qbyte *fte_restrict in, qbyte *fte_ } #ifdef DECOMPRESS_S3TC //s3tc rgb channel, with an rgtc alpha channel that depends upon both encodings (really the origin of rgtc, but mneh). -static void Image_BC3_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +static void Image_Decode_BC3_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) { Image_S3TC_Decode_Block_Internal(in+8, out, w, 0xff); Image_RGTC_Decode_Block_Internal(in, out->v+3, w*4, false); } #endif -static void Image_BC4U_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +static void Image_Decode_BC4U_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) { //BC4: BC3's alpha channel but used as red only. pixel32_t r; int i = 0; Vector4Set(r.v, 0, 0, 0, 0xff); for (i = 0; i < 4; i++) out[w*0+i] = out[w*1+i] = out[w*2+i] = out[w*3+i] = r; - Image_RGTC_Decode_Block_Internal(in, out->v+0, w*4, false); + Image_Decode_RGTC_Block_Internal(in, out->v+0, w*4, false); } -static void Image_BC4S_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +static void Image_Decode_BC4S_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) { //BC4: BC3's alpha channel but used as red only. pixel32_t r; int i = 0; Vector4Set(r.v, 0, 0, 0, 0xff); for (i = 0; i < 4; i++) out[w*0+i] = out[w*1+i] = out[w*2+i] = out[w*3+i] = r; - Image_RGTC_Decode_Block_Internal(in, out->v+0, w*4, true); + Image_Decode_RGTC_Block_Internal(in, out->v+0, w*4, true); } -static void Image_BC5U_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +static void Image_Decode_BC5U_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) { //BC5: two of BC3's alpha channels but used as red+green only. pixel32_t r; int i = 0; Vector4Set(r.v, 0, 0, 0, 0xff); for (i = 0; i < 4; i++) out[w*0+i] = out[w*1+i] = out[w*2+i] = out[w*3+i] = r; - Image_RGTC_Decode_Block_Internal(in+0, out->v+0, w*4, false); - Image_RGTC_Decode_Block_Internal(in+8, out->v+1, w*4, false); + Image_Decode_RGTC_Block_Internal(in+0, out->v+0, w*4, false); + Image_Decode_RGTC_Block_Internal(in+8, out->v+1, w*4, false); } -static void Image_BC5S_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +static void Image_Decode_BC5S_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) { //BC5: two of BC3's alpha channels but used as red+green only. pixel32_t r; int i = 0; Vector4Set(r.v, 0, 0, 0, 0xff); for (i = 0; i < 4; i++) out[w*0+i] = out[w*1+i] = out[w*2+i] = out[w*3+i] = r; - Image_RGTC_Decode_Block_Internal(in+0, out->v+0, w*4, true); - Image_RGTC_Decode_Block_Internal(in+8, out->v+1, w*4, true); + Image_Decode_RGTC_Block_Internal(in+0, out->v+0, w*4, true); + Image_Decode_RGTC_Block_Internal(in+8, out->v+1, w*4, true); } #endif -static void Image_RGB8_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +static void Image_Decode_RGB8_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) { Vector4Set(out->v, in[0], in[1], in[2], 0xff); } -static void Image_LUMA8_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +static void Image_Decode_L8A8_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +{ + Vector4Set(out->v, in[0], in[0], in[0], in[1]); +} +static void Image_Decode_L8_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) { Vector4Set(out->v, in[0], in[0], in[0], 0xff); } -void Image_BlockSizeForEncoding(unsigned int encoding, unsigned int *blockbytes, unsigned int *blockwidth, unsigned int *blockheight) +void Image_BlockSizeForEncoding(uploadfmt_t encoding, unsigned int *blockbytes, unsigned int *blockwidth, unsigned int *blockheight) { - unsigned int b, w = 1, h = 1; + unsigned int b = 0, w = 1, h = 1; switch(encoding) { case PTI_RGB565: @@ -4579,6 +4920,8 @@ void Image_BlockSizeForEncoding(unsigned int encoding, unsigned int *blockbytes, case PTI_RGBX8_SRGB: case PTI_BGRA8_SRGB: case PTI_BGRX8_SRGB: + case PTI_A2BGR10: + case PTI_E5BGR9: b = 4; break; @@ -4589,11 +4932,11 @@ void Image_BlockSizeForEncoding(unsigned int encoding, unsigned int *blockbytes, b = 4*4; break; case PTI_R8: - case PTI_R8_SIGNED: + case PTI_R8_SNORM: b = 1; break; case PTI_RG8: - case PTI_RG8_SIGNED: + case PTI_RG8_SNORM: b = 2; break; @@ -4611,9 +4954,13 @@ void Image_BlockSizeForEncoding(unsigned int encoding, unsigned int *blockbytes, break; case PTI_RGB8: + case PTI_BGR8: b = 3; break; - case PTI_LUMINANCE8_ALPHA8: + case PTI_L8: + b = 1; + break; + case PTI_L8A8: b = 2; break; @@ -4622,14 +4969,14 @@ void Image_BlockSizeForEncoding(unsigned int encoding, unsigned int *blockbytes, case PTI_BC1_RGBA: case PTI_BC1_RGBA_SRGB: case PTI_BC4_R8: - case PTI_BC4_R8_SIGNED: + case PTI_BC4_R8_SNORM: case PTI_ETC1_RGB8: case PTI_ETC2_RGB8: case PTI_ETC2_RGB8_SRGB: case PTI_ETC2_RGB8A1: case PTI_ETC2_RGB8A1_SRGB: case PTI_EAC_R11: - case PTI_EAC_R11_SIGNED: + case PTI_EAC_R11_SNORM: w = h = 4; b = 8; break; @@ -4638,15 +4985,15 @@ void Image_BlockSizeForEncoding(unsigned int encoding, unsigned int *blockbytes, case PTI_BC3_RGBA: case PTI_BC3_RGBA_SRGB: case PTI_BC5_RG8: - case PTI_BC5_RG8_SIGNED: - case PTI_BC6_RGBF: - case PTI_BC6_RGBF_SIGNED: + case PTI_BC5_RG8_SNORM: + case PTI_BC6_RGB_UFLOAT: + case PTI_BC6_RGB_SFLOAT: case PTI_BC7_RGBA: case PTI_BC7_RGBA_SRGB: case PTI_ETC2_RGB8A8: case PTI_ETC2_RGB8A8_SRGB: case PTI_EAC_RG11: - case PTI_EAC_RG11_SIGNED: + case PTI_EAC_RG11_SNORM: w = h = 4; b = 16; break; @@ -4681,11 +5028,11 @@ void Image_BlockSizeForEncoding(unsigned int encoding, unsigned int *blockbytes, case PTI_ASTC_12X12_SRGB: case PTI_ASTC_12X12: w = 12; h = 12; b = 16; break; + case PTI_EMULATED: +#ifdef FTE_TARGET_WEB case PTI_WHOLEFILE: //UNKNOWN! +#endif case PTI_MAX: - default: - w = h = 1; - b = 0; break; } @@ -4694,7 +5041,106 @@ void Image_BlockSizeForEncoding(unsigned int encoding, unsigned int *blockbytes, *blockheight = h; } -static pixel32_t *Image_Block_Decode(qbyte *fte_restrict in, int w, int h, void(*decodeblock)(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w), int encoding) +const char *Image_FormatName(uploadfmt_t fmt) +{ + switch(fmt) + { + case PTI_RGB565: return "RGB565"; + case PTI_RGBA4444: return "RGBA4444"; + case PTI_ARGB4444: return "ARGB4444"; + case PTI_RGBA5551: return "RGBA5551"; + case PTI_ARGB1555: return "ARGB1555"; + case PTI_RGBA8: return "RGBA8"; + case PTI_RGBX8: return "RGBX8"; + case PTI_BGRA8: return "RGBA8"; + case PTI_BGRX8: return "RGBX8"; + case PTI_RGBA8_SRGB: return "RGBA8_SRGB"; + case PTI_RGBX8_SRGB: return "RGBX8_SRGB"; + case PTI_BGRA8_SRGB: return "RGBA8_SRGB"; + case PTI_BGRX8_SRGB: return "RGBX8_SRGB"; + case PTI_A2BGR10: return "A2BGR10"; + case PTI_E5BGR9: return "E5BGR9"; + case PTI_RGBA16F: return "RGBA16F"; + case PTI_RGBA32F: return "RGBA32F"; + case PTI_R8: return "R8"; + case PTI_R8_SNORM: return "R8_SNORM"; + case PTI_RG8: return "RG8"; + case PTI_RG8_SNORM: return "RG8_SNORM"; + case PTI_DEPTH16: return "DEPTH16"; + case PTI_DEPTH24: return "DEPTH24"; + case PTI_DEPTH32: return "DEPTH32"; + case PTI_DEPTH24_8: return "DEPTH24_8"; + case PTI_RGB8: return "RGB8"; + case PTI_BGR8: return "BGR8"; + case PTI_L8: return "L8"; + case PTI_L8A8: return "L8A8"; + case PTI_BC1_RGB: return "BC1_RGB"; + case PTI_BC1_RGB_SRGB: return "BC1_RGB_SRGB"; + case PTI_BC1_RGBA: return "RGB1_RGBA"; + case PTI_BC1_RGBA_SRGB: return "BC1_RGBA_SRGB"; + case PTI_BC4_R8: return "BC4_R8"; + case PTI_BC4_R8_SNORM: return "BC4_R8_SNORM"; + case PTI_ETC1_RGB8: return "ETC1_RGB8"; + case PTI_ETC2_RGB8: return "ETC2_RGB8"; + case PTI_ETC2_RGB8_SRGB: return "ETC2_RGB8_SRGB"; + case PTI_ETC2_RGB8A1: return "ETC2_RGB8A1"; + case PTI_ETC2_RGB8A1_SRGB: return "ETC2_RGB8A1_SRGB"; + case PTI_EAC_R11: return "EAC_R11"; + case PTI_EAC_R11_SNORM: return "EAC_R11_SNORM"; + case PTI_BC2_RGBA: return "BC2_RGBA"; + case PTI_BC2_RGBA_SRGB: return "BC2_RGBA_SRGB"; + case PTI_BC3_RGBA: return "BC3_RGBA"; + case PTI_BC3_RGBA_SRGB: return "BC3_RGBA_SRGB"; + case PTI_BC5_RG8: return "BC5_RG8"; + case PTI_BC5_RG8_SNORM: return "BC5_RG8_SNORM"; + case PTI_BC6_RGB_UFLOAT: return "BC6_RGBF"; + case PTI_BC6_RGB_SFLOAT: return "BC6_RGBF_SNORM"; + case PTI_BC7_RGBA: return "BC7_RGBA"; + case PTI_BC7_RGBA_SRGB: return "BC7_RGBA_SRGB"; + case PTI_ETC2_RGB8A8: return "ETC2_RGB8A8"; + case PTI_ETC2_RGB8A8_SRGB: return "ETC2_RGB8A8_SRGB"; + case PTI_EAC_RG11: return "EAC_RG11"; + case PTI_EAC_RG11_SNORM: return "EAC_RG11_SNORM"; + case PTI_ASTC_4X4_SRGB: return "ASTC_4X4_SRGB"; + case PTI_ASTC_4X4: return "ASTC_4X4"; + case PTI_ASTC_5X4_SRGB: return "ASTC_5X4_SRGB"; + case PTI_ASTC_5X4: return "ASTC_5X4"; + case PTI_ASTC_5X5_SRGB: return "ASTC_5X5_SRGB"; + case PTI_ASTC_5X5: return "ASTC_5X5"; + case PTI_ASTC_6X5_SRGB: return "ASTC_6X5_SRGB"; + case PTI_ASTC_6X5: return "ASTC_6X5"; + case PTI_ASTC_6X6_SRGB: return "ASTC_6X6_SRGB"; + case PTI_ASTC_6X6: return "ASTC_6X6"; + case PTI_ASTC_8X5_SRGB: return "ASTC_8X5_SRGB"; + case PTI_ASTC_8X5: return "ASTC_8X5"; + case PTI_ASTC_8X6_SRGB: return "ASTC_8X6_SRGB"; + case PTI_ASTC_8X6: return "ASTC_8X6"; + case PTI_ASTC_10X5_SRGB: return "ASTC_10X5_SRGB"; + case PTI_ASTC_10X5: return "ASTC_10X5"; + case PTI_ASTC_10X6_SRGB: return "ASTC_10X6_SRGB"; + case PTI_ASTC_10X6: return "ASTC_10X6"; + case PTI_ASTC_8X8_SRGB: return "ASTC_8X8_SRGB"; + case PTI_ASTC_8X8: return "ASTC_8X8"; + case PTI_ASTC_10X8_SRGB: return "ASTC_10X8_SRGB"; + case PTI_ASTC_10X8: return "ASTC_10X8"; + case PTI_ASTC_10X10_SRGB: return "ASTC_10X10_SRGB"; + case PTI_ASTC_10X10: return "ASTC_10X10"; + case PTI_ASTC_12X10_SRGB: return "ASTC_12X10_SRGB"; + case PTI_ASTC_12X10: return "ASTC_12X10"; + case PTI_ASTC_12X12_SRGB: return "ASTC_12X12_SRGB"; + case PTI_ASTC_12X12: return "ASTC_12X12"; + +#ifdef FTE_TARGET_WEB + case PTI_WHOLEFILE: return "Whole File"; +#endif + case PTI_EMULATED: + case PTI_MAX: + break; + } + return "Unknown"; +} + +static pixel32_t *Image_Block_Decode(qbyte *fte_restrict in, int w, int h, void(*decodeblock)(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w), uploadfmt_t encoding) { #define TMPBLOCKSIZE 16u pixel32_t *ret, *out; @@ -4800,87 +5246,91 @@ static void Image_ChangeFormat(struct pendingtextureinfo *mips, unsigned int fla default: break; case PTI_RGB8: - decodefunc = Image_RGB8_Decode_Block; + decodefunc = Image_Decode_RGB8_Block; rcoding = PTI_RGBX8; break; - case PTI_LUMINANCE8_ALPHA8: - decodefunc = Image_LUMA8_Decode_Block; + case PTI_L8A8: + decodefunc = Image_Decode_L8A8_Block; + rcoding = PTI_RGBA8; + break; + case PTI_L8: + decodefunc = Image_Decode_L8_Block; rcoding = PTI_RGBA8; break; #ifdef DECOMPRESS_ETC2 case PTI_ETC1_RGB8: case PTI_ETC2_RGB8: //backwards compatible, so we just treat them the same case PTI_ETC2_RGB8_SRGB: - decodefunc = Image_ETC2_RGB8_Decode_Block; + decodefunc = Image_Decode_ETC2_RGB8_Block; rcoding = (mips->encoding==PTI_ETC2_RGB8_SRGB)?PTI_RGBX8_SRGB:PTI_RGBX8; break; case PTI_ETC2_RGB8A1: //weird hack mode case PTI_ETC2_RGB8A1_SRGB: - decodefunc = Image_ETC2_RGB8A1_Decode_Block; + decodefunc = Image_Decode_ETC2_RGB8A1_Block; rcoding = (mips->encoding==PTI_ETC2_RGB8A1_SRGB)?PTI_RGBA8_SRGB:PTI_RGBA8; break; case PTI_ETC2_RGB8A8: case PTI_ETC2_RGB8A8_SRGB: - decodefunc = Image_ETC2_RGB8A8_Decode_Block; + decodefunc = Image_Decode_ETC2_RGB8A8_Block; rcoding = (mips->encoding==PTI_ETC2_RGB8A8_SRGB)?PTI_RGBA8_SRGB:PTI_RGBA8; break; -/* case PTI_EAC_R11_SIGNED: - decodefunc = Image_EAC_R11S_Decode_Block; + case PTI_EAC_R11: + decodefunc = Image_Decode_EAC_R11U_Block; rcoding = PTI_RGBX8; break; -*/ case PTI_EAC_R11_SIGNED: - decodefunc = Image_EAC_R11U_Decode_Block; - rcoding = PTI_RGBX8; - break; -/* case PTI_EAC_RG11_SIGNED: - decodefunc = Image_EAC_RG11S_Decode_Block; +/* case PTI_EAC_R11_SNORM: + decodefunc = Image_Decode_EAC_R11S_Block; rcoding = PTI_RGBX8; break;*/ case PTI_EAC_RG11: - decodefunc = Image_EAC_RG11U_Decode_Block; + decodefunc = Image_Decode_EAC_RG11U_Block; rcoding = PTI_RGBX8; break; +/* case PTI_EAC_RG11_SNORM: + decodefunc = Image_Decode_EAC_RG11S_Block; + rcoding = PTI_RGBX8; + break;*/ #endif #ifdef DECOMPRESS_S3TC case PTI_BC1_RGB: case PTI_BC1_RGB_SRGB: - decodefunc = Image_BC1_Decode_Block; + decodefunc = Image_Decode_BC1_Block; rcoding = (mips->encoding==PTI_BC1_RGB_SRGB)?PTI_RGBX8_SRGB:PTI_RGBX8; break; case PTI_BC1_RGBA: case PTI_BC1_RGBA_SRGB: - decodefunc = Image_BC1A_Decode_Block; + decodefunc = Image_Decode_BC1A_Block; rcoding = (mips->encoding==PTI_BC1_RGBA_SRGB)?PTI_RGBA8_SRGB:PTI_RGBA8; break; case PTI_BC2_RGBA: case PTI_BC2_RGBA_SRGB: - decodefunc = Image_BC2_Decode_Block; + decodefunc = Image_Decode_BC2_Block; rcoding = (mips->encoding==PTI_BC2_RGBA_SRGB)?PTI_RGBA8_SRGB:PTI_RGBA8; break; #endif #if defined(DECOMPRESS_RGTC) && defined(DECOMPRESS_S3TC) case PTI_BC3_RGBA: case PTI_BC3_RGBA_SRGB: - decodefunc = Image_BC3_Decode_Block; + decodefunc = Image_Decode_BC3_Block; rcoding = (mips->encoding==PTI_BC3_RGBA_SRGB)?PTI_RGBA8_SRGB:PTI_RGBA8; break; #endif #ifdef DECOMPRESS_RGTC - case PTI_BC4_R8_SIGNED: - decodefunc = Image_BC4S_Decode_Block; + case PTI_BC4_R8_SNORM: + decodefunc = Image_Decode_BC4S_Block; rcoding = PTI_RGBX8; break; case PTI_BC4_R8: - decodefunc = Image_BC4U_Decode_Block; + decodefunc = Image_Decode_BC4U_Block; rcoding = PTI_RGBX8; break; - case PTI_BC5_RG8_SIGNED: - decodefunc = Image_BC5S_Decode_Block; + case PTI_BC5_RG8_SNORM: + decodefunc = Image_Decode_BC5S_Block; rcoding = PTI_RGBX8; break; case PTI_BC5_RG8: - decodefunc = Image_BC5U_Decode_Block; + decodefunc = Image_Decode_BC5U_Block; rcoding = PTI_RGBX8; break; #endif @@ -4968,21 +5418,20 @@ static void Image_ChangeFormat(struct pendingtextureinfo *mips, unsigned int fla if (sh_config.texfmt[PTI_RGBA5551]) { for (mip = 0; mip < mips->mipcount; mip++) - Image_8888to5551(mips->mip[mip].data, mips->mip[mip].data, mips->mip[mip].width, mips->mip[mip].height, mips->encoding == PTI_BGRX8); + Image_8888to5551(mips, mip, mips->encoding == PTI_BGRX8); mips->encoding = PTI_RGBA5551; } else { for (mip = 0; mip < mips->mipcount; mip++) - Image_8888to1555(mips->mip[mip].data, mips->mip[mip].data, mips->mip[mip].width, mips->mip[mip].height, mips->encoding == PTI_BGRX8); + Image_8888to1555(mips, mip, mips->encoding == PTI_BGRX8); mips->encoding = PTI_ARGB1555; } } else*/ if (sh_config.texfmt[PTI_RGB565]) { - for (mip = 0; mip < mips->mipcount; mip++) - Image_8888to565(mips->mip[mip].data, mips->mip[mip].data, mips->mip[mip].width, mips->mip[mip].height, mips->encoding == PTI_BGRX8); + Image_8888to565(mips, mips->encoding == PTI_BGRX8); mips->encoding = PTI_RGB565; } } @@ -4992,14 +5441,12 @@ static void Image_ChangeFormat(struct pendingtextureinfo *mips, unsigned int fla { //1-bit alpha is okay for these textures. if (sh_config.texfmt[PTI_RGBA5551]) { - for (mip = 0; mip < mips->mipcount; mip++) - Image_8888to5551(mips->mip[mip].data, mips->mip[mip].data, mips->mip[mip].width, mips->mip[mip].height, mips->encoding == PTI_BGRA8); + Image_8888to5551(mips, mips->encoding == PTI_BGRA8); mips->encoding = PTI_RGBA5551; } else { - for (mip = 0; mip < mips->mipcount; mip++) - Image_8888to1555(mips->mip[mip].data, mips->mip[mip].data, mips->mip[mip].width, mips->mip[mip].height, mips->encoding == PTI_BGRA8); + Image_8888to1555(mips, mips->encoding == PTI_BGRA8); mips->encoding = PTI_ARGB1555; } } @@ -5007,14 +5454,12 @@ static void Image_ChangeFormat(struct pendingtextureinfo *mips, unsigned int fla { if (sh_config.texfmt[PTI_RGBA4444]) { - for (mip = 0; mip < mips->mipcount; mip++) - Image_8888to4444(mips->mip[mip].data, mips->mip[mip].data, mips->mip[mip].width, mips->mip[mip].height, mips->encoding == PTI_BGRA8); + Image_8888to4444(mips, mips->encoding == PTI_BGRA8); mips->encoding = PTI_RGBA4444; } else { - for (mip = 0; mip < mips->mipcount; mip++) - Image_8888toARGB4444(mips->mip[mip].data, mips->mip[mip].data, mips->mip[mip].width, mips->mip[mip].height, mips->encoding == PTI_BGRA8); + Image_8888toARGB4444(mips, mips->encoding == PTI_BGRA8); mips->encoding = PTI_ARGB4444; } } @@ -5030,6 +5475,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag mips->mip[0].width = imgwidth; mips->mip[0].height = imgheight; + mips->mip[0].depth = 1; mips->mipcount = 1; switch(fmt) @@ -5073,7 +5519,13 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag case TF_BGRA32: mips->encoding = PTI_BGRA8; break; - case TF_MIP4_LUM8: + case PTI_A2BGR10: + mips->encoding = PTI_A2BGR10; + break; + case PTI_E5BGR9: + mips->encoding = PTI_E5BGR9; + break; + case TF_MIP4_R8: //8bit indexed data. Image_RoundDimensions(&mips->mip[0].width, &mips->mip[0].height, flags); flags |= IF_NOPICMIP; @@ -5093,6 +5545,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag { mips->mip[i].width = imgwidth>>i; mips->mip[i].height = imgheight>>i; + mips->mip[i].depth = 1; mips->mip[i].datasize = mips->mip[i].width * mips->mip[i].height; mips->mip[i].needfree = false; } @@ -5108,9 +5561,12 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag return true; } //fall through - case TF_LUM8: + case PTI_R8: mips->encoding = PTI_R8; break; + case PTI_L8: + mips->encoding = PTI_L8; + break; case TF_MIP4_SOLID8: //8bit opaque data Image_RoundDimensions(&mips->mip[0].width, &mips->mip[0].height, flags); @@ -5132,6 +5588,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag { mips->mip[i].width = imgwidth>>i; mips->mip[i].height = imgheight>>i; + mips->mip[i].depth = 1; mips->mip[i].datasize = mips->mip[i].width * mips->mip[i].height * 4; mips->mip[i].needfree = false; } @@ -5323,6 +5780,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag { mips->mip[i].width = imgwidth>>i; mips->mip[i].height = imgheight>>i; + mips->mip[i].depth = 1; mips->mip[i].datasize = mips->mip[i].width * mips->mip[i].height * 4; mips->mip[i].needfree = false; } @@ -5453,6 +5911,8 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag case PTI_ARGB1555: case PTI_RGBA4444: case PTI_RGBA5551: + case PTI_A2BGR10: + case PTI_L8A8: //could strip. break; //erk case PTI_BC1_RGBA: mips->encoding = PTI_BC1_RGB; @@ -5498,16 +5958,20 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag case PTI_ASTC_12X10_SRGB: case PTI_ASTC_12X12: case PTI_ASTC_12X12_SRGB: +#ifdef FTE_TARGET_WEB case PTI_WHOLEFILE: - case PTI_LUMINANCE8_ALPHA8: +#endif //erk. meh. break; + case PTI_L8: case PTI_R8: - case PTI_R8_SIGNED: + case PTI_R8_SNORM: case PTI_RG8: - case PTI_RG8_SIGNED: + case PTI_RG8_SNORM: case PTI_RGB565: case PTI_RGB8: + case PTI_BGR8: + case PTI_E5BGR9: case PTI_RGBX8: case PTI_BGRX8: case PTI_RGBX8_SRGB: @@ -5515,33 +5979,34 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag case PTI_BC1_RGB: case PTI_BC1_RGB_SRGB: case PTI_BC4_R8: - case PTI_BC4_R8_SIGNED: + case PTI_BC4_R8_SNORM: case PTI_BC5_RG8: - case PTI_BC5_RG8_SIGNED: - case PTI_BC6_RGBF: - case PTI_BC6_RGBF_SIGNED: + case PTI_BC5_RG8_SNORM: + case PTI_BC6_RGB_UFLOAT: + case PTI_BC6_RGB_SFLOAT: case PTI_ETC1_RGB8: case PTI_ETC2_RGB8: case PTI_ETC2_RGB8_SRGB: case PTI_EAC_R11: - case PTI_EAC_R11_SIGNED: + case PTI_EAC_R11_SNORM: case PTI_EAC_RG11: - case PTI_EAC_RG11_SIGNED: + case PTI_EAC_RG11_SNORM: break; //already no alpha in these formats case PTI_DEPTH16: case PTI_DEPTH24: case PTI_DEPTH32: case PTI_DEPTH24_8: break; + case PTI_EMULATED: case PTI_MAX: break; //stfu } //FIXME: fill alpha channel with 255? } - if (vid.srgb /*&& (flags & IF_SRGB)*/ && !(flags & IF_NOSRGB)) + if ((vid.flags & VID_SRGBAWARE) /*&& (flags & IF_SRGB)*/ && !(flags & IF_NOSRGB)) { //most modern editors write srgb images. //however, that might not be supported. - int nf = PTI_MAX; + uploadfmt_t nf = PTI_MAX; switch(mips->encoding) { case PTI_RGBA8: nf = PTI_RGBA8_SRGB; break; @@ -5557,8 +6022,20 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag case PTI_ETC2_RGB8: nf = PTI_ETC2_RGB8_SRGB; break; case PTI_ETC2_RGB8A1: nf = PTI_ETC2_RGB8A1_SRGB; break; case PTI_ETC2_RGB8A8: nf = PTI_ETC2_RGB8A8_SRGB; break; - //case PTI_ASTC_4X4: nf = PTI_ASTC_4X4_SRGB; break; - //ASTC fixme: more blocksize formats + case PTI_ASTC_4X4: nf = PTI_ASTC_4X4_SRGB; break; + case PTI_ASTC_5X4: nf = PTI_ASTC_5X4_SRGB; break; + case PTI_ASTC_5X5: nf = PTI_ASTC_5X5_SRGB; break; + case PTI_ASTC_6X5: nf = PTI_ASTC_6X5_SRGB; break; + case PTI_ASTC_6X6: nf = PTI_ASTC_6X6_SRGB; break; + case PTI_ASTC_8X5: nf = PTI_ASTC_8X5_SRGB; break; + case PTI_ASTC_8X6: nf = PTI_ASTC_8X6_SRGB; break; + case PTI_ASTC_10X5: nf = PTI_ASTC_10X5_SRGB; break; + case PTI_ASTC_10X6: nf = PTI_ASTC_10X6_SRGB; break; + case PTI_ASTC_8X8: nf = PTI_ASTC_8X8_SRGB; break; + case PTI_ASTC_10X8: nf = PTI_ASTC_10X8_SRGB; break; + case PTI_ASTC_10X10: nf = PTI_ASTC_10X10_SRGB; break; + case PTI_ASTC_12X10: nf = PTI_ASTC_12X10_SRGB; break; + case PTI_ASTC_12X12: nf = PTI_ASTC_12X12_SRGB; break; default: if (freedata) BZ_Free(rgbadata); @@ -5568,23 +6045,34 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag mips->encoding = nf; else { //srgb->linear - int m = mips->mip[0].width*mips->mip[0].height*4; - if (nf >= PTI_BC1_RGB) - { //these formats are weird. we can't just fiddle with the rgbdata + int m = mips->mip[0].width*mips->mip[0].height*mips->mip[0].depth; + + switch(nf) + { + case PTI_RGBA8: nf = PTI_RGBA8_SRGB; break; + case PTI_RGBX8: nf = PTI_RGBX8_SRGB; break; + case PTI_BGRA8: nf = PTI_BGRA8_SRGB; break; + case PTI_BGRX8: nf = PTI_BGRX8_SRGB; break; + m*=4; + for (i = 0; i < m; i+=4) + { + ((qbyte*)rgbadata)[i+0] = 255*Image_LinearFloatFromsRGBFloat(((qbyte*)rgbadata)[i+0] * (1.0/255)); + ((qbyte*)rgbadata)[i+1] = 255*Image_LinearFloatFromsRGBFloat(((qbyte*)rgbadata)[i+1] * (1.0/255)); + ((qbyte*)rgbadata)[i+2] = 255*Image_LinearFloatFromsRGBFloat(((qbyte*)rgbadata)[i+2] * (1.0/255)); + } + break; + case PTI_BC1_RGB: + case PTI_BC1_RGBA: + case PTI_BC2_RGBA: + case PTI_BC3_RGBA: //FIXME: bc1/2/3 has two leading 16bit values per block. + default: + //these formats are weird. we can't just fiddle with the rgbdata //FIXME: etc2 has all sorts of weird encoding tables... if (freedata) BZ_Free(rgbadata); return false; } - if (mips->type == PTI_3D) - m *= mips->mip[0].height; - for (i = 0; i < m; i+=4) - { - ((qbyte*)rgbadata)[i+0] = 255*Image_LinearFloatFromsRGBFloat(((qbyte*)rgbadata)[i+0] * (1.0/255)); - ((qbyte*)rgbadata)[i+1] = 255*Image_LinearFloatFromsRGBFloat(((qbyte*)rgbadata)[i+1] * (1.0/255)); - ((qbyte*)rgbadata)[i+2] = 255*Image_LinearFloatFromsRGBFloat(((qbyte*)rgbadata)[i+2] * (1.0/255)); - } } } @@ -5617,6 +6105,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag mips->mip[0].data = rgbadata; mips->mip[0].width = imgwidth; mips->mip[0].height = imgheight; + mips->mip[0].depth = 1; break; } } @@ -5631,10 +6120,13 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag mips->mip[0].data = NULL; /*our 2d input image is interlaced as y0z0,y0z1,y1z0,y1z1 however, hardware uses the more logical y0z0,y1z0,y0z1,y1z1 ordering (xis ordered properly already)*/ - if (mips->mip[0].height*mips->mip[0].height == mips->mip[0].width && (mips->encoding == PTI_RGBA8 || mips->encoding == PTI_RGBX8 || mips->encoding == PTI_BGRA8 || mips->encoding == PTI_BGRX8)) + if (mips->mip[0].height*mips->mip[0].height == mips->mip[0].width && mips->mip[0].depth == 1 && (mips->encoding == PTI_RGBA8 || mips->encoding == PTI_RGBX8 || mips->encoding == PTI_BGRA8 || mips->encoding == PTI_BGRX8)) { int d, r; int size = mips->mip[0].height; + mips->mip[0].width = size; + mips->mip[0].height = size; + mips->mip[0].depth = size; mips->mip[0].data = data3d = BZ_Malloc(size*size*size); for (d = 0; d < size; d++) for (r = 0; r < size; r++) @@ -5685,20 +6177,6 @@ static qboolean Image_LoadRawTexture(texid_t tex, unsigned int flags, void *rawd tex->width = imgwidth; tex->height = imgheight; - //d3d9 needs to reconfigure samplers depending on whether the data is srgb or not. - tex->flags &= ~IF_SRGB; - switch(mips->encoding) - { - case PTI_RGBA8_SRGB: - case PTI_RGBX8_SRGB: - case PTI_BGRA8_SRGB: - case PTI_BGRX8_SRGB: - tex->flags |= IF_SRGB; - break; - default: - break; - } - if (flags & IF_NOWORKER) Image_LoadTextureMips(tex, mips, 0, 0); else @@ -5706,6 +6184,140 @@ static qboolean Image_LoadRawTexture(texid_t tex, unsigned int flags, void *rawd return true; } +#if 1 +//always frees filedata, even on failure. +//also frees the textures fallback data, but only on success +static struct pendingtextureinfo *Image_LoadMipsFromMemory(int flags, const char *iname, char *fname, qbyte *filedata, int filesize) +{ + qboolean hasalpha; + qbyte *rgbadata; + + int imgwidth, imgheight; + + struct pendingtextureinfo *mips = NULL; + + //these formats have special handling, because they cannot be implemented via Read32BitImageFile - they don't result in rgba images. +#ifdef IMAGEFMT_KTX + if (!mips) + mips = Image_ReadKTXFile(flags, fname, filedata, filesize); +#endif +#ifdef IMAGEFMT_PKM + if (!mips) + mips = Image_ReadPKMFile(flags, fname, filedata, filesize); +#endif +#ifdef IMAGEFMT_DDS + if (!mips) + mips = Image_ReadDDSFile(flags, fname, filedata, filesize); +#endif +#ifdef IMAGEFMT_BLP + if (!mips && filedata[0] == 'B' && filedata[1] == 'L' && filedata[2] == 'P' && filedata[3] == '2') + mips = Image_ReadBLPFile(flags, fname, filedata, filesize); +#endif + + //the above formats are assumed to have consumed filedata somehow (probably storing into mips->extradata) + if (mips) + { + Image_ChangeFormat(mips, flags, TF_INVALID); + return mips; + } + + hasalpha = false; + if ((rgbadata = Read32BitImageFile(filedata, filesize, &imgwidth, &imgheight, &hasalpha, fname))) + { + extern cvar_t vid_hardwaregamma; + if (!(flags&IF_NOGAMMA) && !vid_hardwaregamma.value) + BoostGamma(rgbadata, imgwidth, imgheight); + + if (hasalpha) + flags &= ~IF_NOALPHA; + else if (!(flags & IF_NOALPHA)) + { + unsigned int alpha_width, alpha_height, p; + char aname[MAX_QPATH]; + unsigned char *alphadata; + char *alph; + size_t alphsize; + char ext[8]; + COM_StripExtension(fname, aname, sizeof(aname)); + COM_FileExtension(fname, ext, sizeof(ext)); + Q_strncatz(aname, "_alpha.", sizeof(aname)); + Q_strncatz(aname, ext, sizeof(aname)); + if (!strchr(aname, ':') && (alph = COM_LoadFile (aname, 5, &alphsize))) + { + if ((alphadata = Read32BitImageFile(alph, alphsize, &alpha_width, &alpha_height, &hasalpha, aname))) + { + if (alpha_width == imgwidth && alpha_height == imgheight) + { + for (p = 0; p < alpha_width*alpha_height; p++) + { + rgbadata[(p<<2) + 3] = (alphadata[(p<<2) + 0] + alphadata[(p<<2) + 1] + alphadata[(p<<2) + 2])/3; + } + } + BZ_Free(alphadata); + } + BZ_Free(alph); + } + } + + mips = Z_Malloc(sizeof(*mips)); + mips->type = (flags & IF_3DMAP)?PTI_3D:PTI_2D; + if (Image_GenMip0(mips, flags, rgbadata, NULL, imgwidth, imgheight, TF_RGBA32, true)) + { + Image_GenerateMips(mips, flags); + Image_ChangeFormat(mips, flags, TF_RGBA32); + BZ_Free(filedata); + return mips; + } + Z_Free(mips); + BZ_Free(rgbadata); + } +#ifdef FTE_TARGET_WEB + else if (1) + { + struct pendingtextureinfo *mips; + mips = Z_Malloc(sizeof(*mips)); + mips->type = (flags & IF_3DMAP)?PTI_3D:PTI_2D; + mips->mipcount = 1; + mips->encoding = PTI_WHOLEFILE; + mips->extrafree = NULL; + mips->mip[0].width = 1; + mips->mip[0].height = 1; + mips->mip[0].depth = 1; + mips->mip[0].data = filedata; + mips->mip[0].datasize = filesize; + mips->mip[0].needfree = true; + //width+height are not yet known. bah. + return mips; + } +#endif + else + Con_Printf("Unable to read file %s (format unsupported)\n", fname); + + BZ_Free(filedata); + return NULL; +} + +//always frees filedata, even on failure. +//also frees the textures fallback data, but only on success +qboolean Image_LoadTextureFromMemory(texid_t tex, int flags, const char *iname, char *fname, qbyte *filedata, int filesize) +{ + struct pendingtextureinfo *mips = Image_LoadMipsFromMemory(flags, iname, fname, filedata, filesize); + if (mips) + { + BZ_Free(tex->fallbackdata); + tex->fallbackdata = NULL; + + tex->width = mips->mip[0].width; + tex->height = mips->mip[0].height; + if (flags & IF_NOWORKER) + Image_LoadTextureMips(tex, mips, 0, 0); + else + COM_AddWork(WG_MAIN, Image_LoadTextureMips, tex, mips, 0, 0); + return true; + } + return false; +} +#else //always frees filedata, even on failure. //also frees the textures fallback data, but only on success qboolean Image_LoadTextureFromMemory(texid_t tex, int flags, const char *iname, char *fname, qbyte *filedata, int filesize) @@ -5808,6 +6420,7 @@ qboolean Image_LoadTextureFromMemory(texid_t tex, int flags, const char *iname, mips->extrafree = NULL; mips->mip[0].width = 1; mips->mip[0].height = 1; + mips->mip[0].depth = 1; mips->mip[0].data = filedata; mips->mip[0].datasize = filesize; mips->mip[0].needfree = true; @@ -5825,6 +6438,7 @@ qboolean Image_LoadTextureFromMemory(texid_t tex, int flags, const char *iname, BZ_Free(filedata); return false; } +#endif struct pendingtextureinfo *Image_LoadCubemapTextureData(const char *nicename, char *subpath, unsigned int texflags) { @@ -5914,6 +6528,7 @@ struct pendingtextureinfo *Image_LoadCubemapTextureData(const char *nicename, ch mips->mip[i].datasize = width*height*4; mips->mip[i].width = width; mips->mip[i].height = height; + mips->mip[i].depth = 1; mips->mip[i].needfree = true; BZ_Free(buf); @@ -6194,7 +6809,16 @@ static void Image_LoadHiResTextureWorker(void *ctx, void *data, size_t a, size_t for(altname = tex->ident;altname;altname = nextalt) { struct pendingtextureinfo *mips = NULL; - static const char *cubeexts[] = {"", ".ktx", ".dds"}; + static const char *cubeexts[] = + { + "" +#ifdef IMAGEFMT_KTX + , ".ktx" +#endif +#ifdef IMAGEFMT_DDS + , ".dds" +#endif + }; nextalt = strchr(altname, ':'); if (nextalt) @@ -6501,7 +7125,7 @@ image_t *Image_GetTexture(const char *identifier, const char *subpath, unsigned pb = 4*256; b *= 1; break; - case TF_LUM8: + case PTI_R8: case TF_SOLID8: case TF_TRANS8: case TF_TRANS8_FULLBRIGHT: @@ -6521,7 +7145,7 @@ image_t *Image_GetTexture(const char *identifier, const char *subpath, unsigned case TF_MIP4_8PAL24: case TF_MIP4_8PAL24_T255: pb = 3*256; - case TF_MIP4_LUM8: + case TF_MIP4_R8: case TF_MIP4_SOLID8: b = (fallbackwidth>>0)*(fallbackheight>>0) + (fallbackwidth>>1)*(fallbackheight>>1) + @@ -6595,6 +7219,10 @@ void Image_Upload (texid_t tex, uploadfmt_t fmt, void *data, void *palette, in struct pendingtextureinfo mips; size_t i; + //skip if we're not actually changing the data/size/format. + if (!data && tex->format == fmt && tex->width == width && tex->height == height && tex->depth == 1) + return; + mips.extrafree = NULL; mips.type = (flags & IF_3DMAP)?PTI_3D:PTI_2D; if (!Image_GenMip0(&mips, flags, data, palette, width, height, fmt, false)) @@ -6602,8 +7230,10 @@ void Image_Upload (texid_t tex, uploadfmt_t fmt, void *data, void *palette, in Image_GenerateMips(&mips, flags); Image_ChangeFormat(&mips, flags, fmt); rf->IMG_LoadTextureMips(tex, &mips); + tex->format = fmt; tex->width = width; tex->height = height; + tex->depth = 1; tex->status = TEX_LOADED; for (i = 0; i < mips.mipcount; i++) diff --git a/engine/client/in_generic.c b/engine/client/in_generic.c index daf0edbd..a2824ebe 100644 --- a/engine/client/in_generic.c +++ b/engine/client/in_generic.c @@ -976,7 +976,6 @@ void IN_MoveJoystick(struct joy_s *joy, float *movements, int pnum, float framet void IN_Move (float *movements, int pnum, float frametime) { int i; - INS_Move(movements, pnum); for (i = 0; i < MAXPOINTERS; i++) IN_MoveMouse(&ptr[i], movements, pnum, frametime); diff --git a/engine/client/in_morphos.c b/engine/client/in_morphos.c index 25b288cc..b79621e2 100644 --- a/engine/client/in_morphos.c +++ b/engine/client/in_morphos.c @@ -216,7 +216,7 @@ void INS_Commands(void) void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, unsigned int *qdevid)) { } -void INS_Move (float *movements, int pnum) +void INS_Move (void) { } diff --git a/engine/client/in_sdl.c b/engine/client/in_sdl.c index cf14af19..f388f41b 100644 --- a/engine/client/in_sdl.c +++ b/engine/client/in_sdl.c @@ -1011,7 +1011,7 @@ void INS_ReInit (void) } //stubs, all the work is done in Sys_SendKeyEvents -void INS_Move(float *movements, int pnum) +void INS_Move(void) { } void INS_Init (void) diff --git a/engine/client/in_win.c b/engine/client/in_win.c index 33f823e1..34075f12 100644 --- a/engine/client/in_win.c +++ b/engine/client/in_win.c @@ -305,7 +305,7 @@ void INS_RawInput_DeInit(void); // forward-referenced functions void INS_StartupJoystick (void); -void INS_JoyMove (float *movements, int pnum); +void INS_JoyMove (void); /* =========== @@ -1333,7 +1333,7 @@ void INS_MouseEvent (int mstate) INS_MouseMove =========== */ -void INS_MouseMove (float *movements, int pnum) +void INS_MouseMove (void) { #ifdef AVAIL_DINPUT if (dinput && mouseactive) @@ -1426,12 +1426,12 @@ void INS_MouseMove (float *movements, int pnum) INS_Move =========== */ -void INS_Move (float *movements, int pnum) +void INS_Move (void) { if (vid.activeapp && !Minimized) { - INS_MouseMove (movements, pnum); - INS_JoyMove (movements, pnum); + INS_MouseMove (); + INS_JoyMove (); } else INS_Accumulate(); @@ -2132,39 +2132,17 @@ static qboolean INS_ReadJoystick (struct wjoy_s *joy) return false; } -static void INS_JoyMovePtr (struct wjoy_s *joy, float *movements, int pnum) -{ - int wpnum; - - /*each device will be processed when its player comes to be processed*/ - wpnum = cl.splitclients; - if (wpnum < 1) - wpnum = 1; - if (cl_forceseat.ival) - wpnum = (cl_forceseat.ival-1) % wpnum; - else - wpnum = joy->devid % wpnum; - if (wpnum != pnum) - return; - - - // collect the joystick data, if possible - if (INS_ReadJoystick (joy) != true) - { - return; - } -} /* =========== INS_JoyMove =========== */ -void INS_JoyMove (float *movements, int pnum) +void INS_JoyMove (void) { unsigned int idx; for (idx = 0; idx < joy_count; idx++) { - INS_JoyMovePtr(&wjoy[idx], movements, pnum); + INS_ReadJoystick(&wjoy[idx]); } } diff --git a/engine/client/input.h b/engine/client/input.h index b6305d98..20c4cea8 100644 --- a/engine/client/input.h +++ b/engine/client/input.h @@ -53,7 +53,7 @@ void IN_Accelerometer(unsigned int devid, float x, float y, float z); void IN_Gyroscope(unsigned int devid, float pitch, float yaw, float roll); //system-specific functions -void INS_Move (float *movements, int pnum); +void INS_Move (void); void INS_Accumulate (void); void INS_ClearStates (void); void INS_ReInit (void); diff --git a/engine/client/m_download.c b/engine/client/m_download.c index 6bfec3c9..df67cd15 100644 --- a/engine/client/m_download.c +++ b/engine/client/m_download.c @@ -373,11 +373,11 @@ void PM_ValidatePackage(package_t *p) searchpathfuncs_t *archive; if (!Q_strcasecmp(COM_FileExtension(n, buf, sizeof(buf)), "pak")) - archive = FSPAK_LoadArchive(pf, n, NULL); + archive = FSPAK_LoadArchive(pf, NULL, n, n, NULL); else { #ifdef AVAIL_ZLIB //assume zip/pk3/pk4/apk/etc - archive = FSZIP_LoadArchive(pf, n, NULL); + archive = FSZIP_LoadArchive(pf, NULL, n, n, NULL); #else archive = NULL; #endif @@ -1956,7 +1956,7 @@ static void PM_Download_Got(struct dl_download *dl) vfsfile_t *f = FS_OpenVFS(tempname, "rb", p->fsroot); if (f) { - searchpathfuncs_t *archive = FSZIP_LoadArchive(f, tempname, NULL); + searchpathfuncs_t *archive = FSZIP_LoadArchive(f, NULL, tempname, tempname, NULL); if (archive) { p->flags &= ~(DPF_NATIVE|DPF_CACHED|DPF_CORRUPT|DPF_ENABLED); diff --git a/engine/client/m_options.c b/engine/client/m_options.c index 9b3cef4f..bb17d236 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -901,6 +901,7 @@ const char *presetexec[] = "r_glsl_offsetmapping 1;" "r_shadow_realtime_world 1;" "gl_texture_anisotropic_filtering 16;" + "vid_hardwaregamma 6;" //scene gamma }; typedef struct fpsmenuinfo_s @@ -1179,7 +1180,9 @@ void M_Menu_Render_f (void) MB_SLIDER("Water Alpha", r_wateralpha, 0, 1, 0.1, NULL), MB_SLIDER("Viewmodel Alpha", r_drawviewmodel, 0, 1, 0.1, NULL), MB_CHECKBOXCVAR("Poly Blending", gl_cshiftenabled, 0), +#ifdef QWSKINS MB_CHECKBOXCVAR("Disable Colormap", gl_nocolors, 0), +#endif MB_COMBOCVAR("Log Centerprints", scr_logcenterprint, logcenteropts, logcentervalues, "Display centerprints in the console also."), #ifdef GLQUAKE MB_CHECKBOXCVAR("Bloom", r_bloom, 0), @@ -1380,7 +1383,7 @@ void M_Menu_Lighting_f (void) #ifndef MINIMAL extern cvar_t r_vertexlight; #endif - extern cvar_t r_stains, r_shadows, r_loadlits; + extern cvar_t r_stains, r_shadows, r_loadlits, r_lightmap_format; extern cvar_t r_lightstylesmooth, r_nolightdir; #ifdef RTLIGHTS extern cvar_t r_dynamic, r_shadow_realtime_world, r_shadow_realtime_dlight, r_shadow_realtime_dlight_shadows; @@ -1479,6 +1482,34 @@ void M_Menu_Lighting_f (void) NULL }; + static const char *lightmapformatopts[] = + { + "Automatic", + "8bit (Greyscale)", + "8bit (Misaligned)", + "8bit (Aligned)", + "10bit", + "9bit (HDR)", + "Half-Float (HDR)", + "Float (HDR)", + NULL + }; + static const char *lightmapformatvalues[] = + { + "", + "l8", + "rgb8", + "bgrx8", + "rgb10", + "rgb9e5", + "rgba16f", + "rgba32f", +// "rgb4", +// "rgb565", +// "rgba5551", + NULL + }; + int y; menu_t *menu = M_Options_Title(&y, sizeof(lightingmenuinfo_t)); @@ -1535,6 +1566,7 @@ void M_Menu_Lighting_f (void) MB_CMD("Apply Lighting", M_VideoApplyShadowLighting, "Applies set lighting modes and restarts video."), MB_SPACING(4), #endif + MB_COMBOCVAR("Lightmap Format", r_lightmap_format, lightmapformatopts, lightmapformatvalues, "Selects which format to use for lightmaps."), MB_COMBOCVAR("LIT Loading", r_loadlits, loadlitopts, loadlitvalues, "Determines if the engine should use external colored lighting for maps. The generated setting will cause the engine to generate colored lighting for maps that don't have the associated data."), MB_COMBOCVAR("Deluxmapping", r_deluxmapping_cvar, loadlitopts, loadlitvalues, "Controls whether static lighting should respond to lighting directions."), MB_CHECKBOXCVAR("Lightstyle Lerp", r_lightstylesmooth, 0), @@ -2561,6 +2593,23 @@ void M_Menu_Video_f (void) extern cvar_t vid_desktopsettings, vid_conautoscale; extern cvar_t vid_bpp, vid_refreshrate, vid_multisample; + static const char *gammamodeopts[] = { + "Off", + "Auto", + "GLSL", + "Hardware", + "Scene-Only", + NULL + }; + static const char *gammamodevalues[] = { + "0", + "1", + "2", + "3", + "4", + NULL + }; + #ifdef ANDROID extern cvar_t sys_orientation; static const char *orientationopts[] = { @@ -2801,6 +2850,7 @@ void M_Menu_Video_f (void) MB_CMD("Apply Settings", M_VideoApply, "Restart video and apply renderer, display, and 2D resolution options."), MB_SPACING(4), MB_SLIDER("View Size", scr_viewsize, 30, 120, 10, NULL), + MB_COMBOCVAR("Gamma Mode", v_gamma, gammamodeopts, gammamodevalues, "Controls how gamma is applied"), MB_SLIDER("Gamma", v_gamma, 1.5, 0.25, -0.05, NULL), MB_SLIDER("Contrast", v_contrast, 0.8, 3, 0.05, NULL), MB_END() diff --git a/engine/client/merged.h b/engine/client/merged.h index 6912e428..7fc3a701 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -225,6 +225,8 @@ typedef struct image_s int regsequence; int width; //this is the logical size. the physical size is not considered important (except for render targets, which should not be loaded from disk). int height; + int depth; + uploadfmt_t format; int status; //TEX_ unsigned int flags; struct image_s *next; @@ -283,103 +285,12 @@ struct pendingtextureinfo { PTI_2D, PTI_3D, - PTI_CUBEMAP //mips are packed (to make d3d11 happy) + PTI_CUBEMAP, //mips are packed (to make d3d11 happy) + PTI_2D_ARRAY, //looks like a 3d texture, but depth doesn't change. + PTI_CUBEMAP_ARRAY, //looks like PTI_2D_ARRAY, with depth*6 } type; - enum - { - //these formats are specified as direct byte access - PTI_RGBA8, //rgba byte ordering - PTI_RGBX8, //rgb pad byte ordering - PTI_BGRA8, //alpha channel - PTI_BGRX8, //no alpha channel - PTI_RGBA8_SRGB, //rgba byte ordering - PTI_RGBX8_SRGB, //rgb pad byte ordering - PTI_BGRA8_SRGB, //alpha channel - PTI_BGRX8_SRGB, //no alpha channel - //these formats are specified in native endian order - PTI_RGB565, //16bit alphaless format. - PTI_RGBA4444, //16bit format (gl) - PTI_ARGB4444, //16bit format (d3d) - PTI_RGBA5551, //16bit alpha format (gl). - PTI_ARGB1555, //16bit alpha format (d3d). - PTI_RGB8, //24bit packed format. generally not supported - PTI_LUMINANCE8_ALPHA8, //16bit format. - //floating point formats - PTI_RGBA16F, - PTI_RGBA32F, - //small formats. - PTI_R8, - PTI_RG8, //might be useful for normalmaps - PTI_R8_SIGNED, - PTI_RG8_SIGNED, //might be useful for normalmaps - //(desktop/tegra) compressed formats - PTI_BC1_RGB, - PTI_BC1_RGB_SRGB, - PTI_BC1_RGBA, - PTI_BC1_RGBA_SRGB, - PTI_BC2_RGBA, - PTI_BC2_RGBA_SRGB, - PTI_BC3_RGBA, //maybe add a bc3 normalmapswizzle type for d3d9? - PTI_BC3_RGBA_SRGB, - PTI_BC4_R8, - PTI_BC4_R8_SIGNED, - PTI_BC5_RG8, //useful for normalmaps - PTI_BC5_RG8_SIGNED, //useful for normalmaps - PTI_BC6_RGBF, //unsigned (half) floats! - PTI_BC6_RGBF_SIGNED, //signed (half) floats! - PTI_BC7_RGBA, //multimode compression, using as many bits as bc2/bc3 - PTI_BC7_RGBA_SRGB, - //(mobile/intel) compressed formats - PTI_ETC1_RGB8, //limited form - PTI_ETC2_RGB8, //extended form - PTI_ETC2_RGB8A1, - PTI_ETC2_RGB8A8, - PTI_ETC2_RGB8_SRGB, - PTI_ETC2_RGB8A1_SRGB, - PTI_ETC2_RGB8A8_SRGB, - PTI_EAC_R11, //no idea what this might be used for, whatever - PTI_EAC_R11_SIGNED, //no idea what this might be used for, whatever - PTI_EAC_RG11, //useful for normalmaps (calculate blue) - PTI_EAC_RG11_SIGNED, //useful for normalmaps (calculate blue) - //astc... zomg - PTI_ASTC_4X4, - PTI_ASTC_4X4_SRGB, - PTI_ASTC_5X4, - PTI_ASTC_5X4_SRGB, - PTI_ASTC_5X5, - PTI_ASTC_5X5_SRGB, - PTI_ASTC_6X5, - PTI_ASTC_6X5_SRGB, - PTI_ASTC_6X6, - PTI_ASTC_6X6_SRGB, - PTI_ASTC_8X5, - PTI_ASTC_8X5_SRGB, - PTI_ASTC_8X6, - PTI_ASTC_8X6_SRGB, - PTI_ASTC_10X5, - PTI_ASTC_10X5_SRGB, - PTI_ASTC_10X6, - PTI_ASTC_10X6_SRGB, - PTI_ASTC_8X8, - PTI_ASTC_8X8_SRGB, - PTI_ASTC_10X8, - PTI_ASTC_10X8_SRGB, - PTI_ASTC_10X10, - PTI_ASTC_10X10_SRGB, - PTI_ASTC_12X10, - PTI_ASTC_12X10_SRGB, - PTI_ASTC_12X12, - PTI_ASTC_12X12_SRGB, - //weird specialcase mess to take advantage of webgl so we don't need redundant bloat where we're already strugging with potential heap limits - PTI_WHOLEFILE, - //depth formats - PTI_DEPTH16, - PTI_DEPTH24, - PTI_DEPTH32, - PTI_DEPTH24_8, - PTI_MAX, - } encoding; //0 + uploadfmt_t encoding; //0 void *extrafree; int mipcount; struct @@ -388,6 +299,7 @@ struct pendingtextureinfo size_t datasize; int width; int height; + int depth; qboolean needfree; } mip[72]; //enough for a 4096 cubemap. or a really smegging big 2d texture... }; diff --git a/engine/client/p_classic.c b/engine/client/p_classic.c index 47077fea..b5844ced 100644 --- a/engine/client/p_classic.c +++ b/engine/client/p_classic.c @@ -99,11 +99,9 @@ extern cvar_t r_part_density, r_part_classic_expgrav, r_part_classic_opaque; static unsigned int particleframe; -extern qbyte default_quakepal[]; /*for ramps more than anything else*/ static int ramp1[8] = {0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61}; static int ramp2[8] = {0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66}; static int ramp3[8] = {0x6d, 0x6b, 6, 5, 4, 3}; -#define qpal(q) ((default_quakepal[(q)*3+0]<<0) | (default_quakepal[(q)*3+1]<<8) | (default_quakepal[(q)*3+2]<<16)) #ifndef POLYS #define BUFFERVERTS 2048*3 @@ -564,7 +562,7 @@ static void PClassic_DrawParticles(void) if (p->ramp >= 6) p->die = -1; else - p->rgb = qpal(ramp3[(int) p->ramp]); + p->rgb = d_quaketo24srgbtable[ramp3[(int) p->ramp]]; p->vel[2] += grav; break; case pt_explode: @@ -572,7 +570,7 @@ static void PClassic_DrawParticles(void) if (p->ramp >=8) p->die = -1; else - p->rgb = qpal(ramp1[(int) p->ramp]); + p->rgb = d_quaketo24srgbtable[ramp1[(int) p->ramp]]; for (i = 0; i < 3; i++) p->vel[i] += p->vel[i] * dvel; p->vel[2] -= grav*r_part_classic_expgrav.value; @@ -582,7 +580,7 @@ static void PClassic_DrawParticles(void) if (p->ramp >=8) p->die = -1; else - p->rgb = qpal(ramp2[(int) p->ramp]); + p->rgb = d_quaketo24srgbtable[ramp2[(int) p->ramp]]; for (i = 0; i < 3; i++) p->vel[i] -= p->vel[i] * frametime; p->vel[2] -= grav*r_part_classic_expgrav.value; @@ -633,7 +631,7 @@ static void Classic_ParticleExplosion (vec3_t org) active_particles = p; p->die = cl.time + 5; - p->rgb = d_8to24rgbtable[ramp1[0]]; + p->rgb = d_8to24srgbtable[ramp1[0]]; p->ramp = rand() & 3; if (i & 1) { @@ -672,7 +670,7 @@ static void Classic_ParticleExplosion2 (vec3_t org, int colorStart, int colorLen active_particles = p; p->die = cl.time + 0.3; - p->rgb = d_8to24rgbtable[(colorStart + (colorMod % colorLength)) & 255]; + p->rgb = d_8to24srgbtable[(colorStart + (colorMod % colorLength)) & 255]; colorMod++; p->type = pt_blob; @@ -706,7 +704,7 @@ static void Classic_BlobExplosion (vec3_t org) if (i & 1) { p->type = pt_blob; - p->rgb = d_8to24rgbtable[66 + rand() % 6]; + p->rgb = d_8to24srgbtable[66 + rand() % 6]; for (j = 0; j < 3; j++) { p->org[j] = org[j] + ((rand() % 32) - 16); @@ -716,7 +714,7 @@ static void Classic_BlobExplosion (vec3_t org) else { p->type = pt_blob2; - p->rgb = d_8to24rgbtable[150 + rand() % 6]; + p->rgb = d_8to24srgbtable[150 + rand() % 6]; for (j = 0; j < 3; j++) { p->org[j] = org[j] + ((rand() % 32) - 16); @@ -751,7 +749,7 @@ static void Classic_RunParticleEffect (vec3_t org, vec3_t dir, int color, int co active_particles = p; p->die = cl.time + 0.1 * (rand() % 5); - p->rgb = d_8to24rgbtable[(color & ~7) + (rand() & 7)]; + p->rgb = d_8to24srgbtable[(color & ~7) + (rand() & 7)]; if (qwstyle) p->type = pt_grav; //QW else @@ -785,7 +783,7 @@ static void Classic_LavaSplash (vec3_t org) active_particles = p; p->die = cl.time + 2 + (rand() & 31) * 0.02; - p->rgb = d_8to24rgbtable[224 + (rand() & 7)]; + p->rgb = d_8to24srgbtable[224 + (rand() & 7)]; p->type = pt_grav; dir[0] = j * 8 + (rand() & 7); @@ -829,7 +827,7 @@ static void Classic_TeleportSplash (vec3_t org) active_particles = p; p->die = cl.time + 0.2 + (rand() & 7) * 0.02; - p->rgb = d_8to24rgbtable[7 + (rand() & 7)]; + p->rgb = d_8to24srgbtable[7 + (rand() & 7)]; p->type = pt_grav; dir[0] = j * 8; @@ -903,7 +901,7 @@ static void Classic_BrightField (vec3_t org) forward[2] = -sp; p->die = cl.time;// + 0.01; - p->rgb = d_8to24rgbtable[0x6f]; + p->rgb = d_8to24srgbtable[0x6f]; p->type = pt_oneframe; p->org[0] = org[0] + r_avertexnormals[i][0]*dist + forward[0]*beamlength; @@ -1042,20 +1040,20 @@ static float Classic_ParticleTrail (vec3_t start, vec3_t end, float leftover, ef { case GRENADE_TRAIL: p->ramp = (rand() & 3) + 2; - p->rgb = d_8to24rgbtable[ramp3[(int) p->ramp]]; + p->rgb = d_8to24srgbtable[ramp3[(int) p->ramp]]; p->type = pt_fire; for (j = 0; j < 3; j++) p->org[j] = point[j] + ((rand() % 6) - 3); break; case BLOOD_TRAIL: p->type = pt_slowgrav; - p->rgb = d_8to24rgbtable[67 + (rand() & 3)]; + p->rgb = d_8to24srgbtable[67 + (rand() & 3)]; for (j = 0; j < 3; j++) p->org[j] = point[j] + ((rand() % 6) - 3); break; case BIG_BLOOD_TRAIL: p->type = pt_slowgrav; - p->rgb = d_8to24rgbtable[67 + (rand() & 3)]; + p->rgb = d_8to24srgbtable[67 + (rand() & 3)]; for (j = 0; j < 3; j++) p->org[j] = point[j] + ((rand() % 6) - 3); break; @@ -1064,9 +1062,9 @@ static float Classic_ParticleTrail (vec3_t start, vec3_t end, float leftover, ef p->die = cl.time + 0.5; p->type = pt_static; if (type == TRACER1_TRAIL) - p->rgb = d_8to24rgbtable[52 + ((tracercount & 4) << 1)]; + p->rgb = d_8to24srgbtable[52 + ((tracercount & 4) << 1)]; else - p->rgb = d_8to24rgbtable[230 + ((tracercount & 4) << 1)]; + p->rgb = d_8to24srgbtable[230 + ((tracercount & 4) << 1)]; tracercount++; @@ -1083,7 +1081,7 @@ static float Classic_ParticleTrail (vec3_t start, vec3_t end, float leftover, ef } break; case VOOR_TRAIL: - p->rgb = d_8to24rgbtable[9 * 16 + 8 + (rand() & 3)]; + p->rgb = d_8to24srgbtable[9 * 16 + 8 + (rand() & 3)]; p->type = pt_static; p->die = cl.time + 0.3; for (j = 0; j < 3; j++) @@ -1091,7 +1089,7 @@ static float Classic_ParticleTrail (vec3_t start, vec3_t end, float leftover, ef break; case ALT_ROCKET_TRAIL: p->ramp = (rand() & 3); - p->rgb = d_8to24rgbtable[ramp3[(int) p->ramp]]; + p->rgb = d_8to24srgbtable[ramp3[(int) p->ramp]]; p->type = pt_fire; for (j = 0; j < 3; j++) p->org[j] = point[j] + ((rand() % 6) - 3); @@ -1099,7 +1097,7 @@ static float Classic_ParticleTrail (vec3_t start, vec3_t end, float leftover, ef case ROCKET_TRAIL: default: p->ramp = (rand() & 3); - p->rgb = d_8to24rgbtable[ramp3[(int) p->ramp]]; + p->rgb = d_8to24srgbtable[ramp3[(int) p->ramp]]; p->type = pt_fire; for (j = 0; j < 3; j++) p->org[j] = point[j] + ((rand() % 6) - 3); @@ -1124,7 +1122,7 @@ int PClassic_PointFile(int c, vec3_t point) VectorClear (p->vel); p->die = 99999; - p->rgb = d_8to24rgbtable[(-c) & 0xff]; + p->rgb = d_8to24srgbtable[(-c) & 0xff]; p->type = pt_static; VectorCopy(point, p->org); diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 1b757259..72b36b8e 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -931,8 +931,8 @@ static qboolean CopyCSQCEdictToEntity(csqcedict_t *in, entity_t *out) if (ival > 0 && ival <= MAX_CLIENTS) { out->playerindex = ival - 1; - out->topcolour = cl.players[ival-1].ttopcolor; - out->bottomcolour = cl.players[ival-1].tbottomcolor; + out->topcolour = cl.players[ival-1].dtopcolor; + out->bottomcolour = cl.players[ival-1].dbottomcolor; } else if (ival /*>= 1024*/) { @@ -3732,7 +3732,7 @@ static const char *PF_cs_getplayerkey_internal (unsigned int pnum, const char *k // } else if (!strcmp(keyname, "topcolor_rgb")) //packet loss { - unsigned int col = cl.players[pnum].ttopcolor; + unsigned int col = cl.players[pnum].dtopcolor; ret = buffer; if (col < 16) { @@ -3744,7 +3744,7 @@ static const char *PF_cs_getplayerkey_internal (unsigned int pnum, const char *k } else if (!strcmp(keyname, "bottomcolor_rgb")) //packet loss { - unsigned int col = cl.players[pnum].tbottomcolor; + unsigned int col = cl.players[pnum].dbottomcolor; ret = buffer; if (col < 16) { @@ -5289,10 +5289,10 @@ static void QCBUILTIN PF_getentity(pubprogfuncs_t *prinst, struct globalvars_s * AngleVectorsIndex(le->angles, ps->modelindex, NULL, NULL, G_VECTOR(OFS_RETURN)); break; case GE_PANTSCOLOR: - G_FLOAT(OFS_RETURN) = cl.players[entnum-1].tbottomcolor; + G_FLOAT(OFS_RETURN) = cl.players[entnum-1].dbottomcolor; break; case GE_SHIRTCOLOR: - G_FLOAT(OFS_RETURN) = cl.players[entnum-1].ttopcolor; + G_FLOAT(OFS_RETURN) = cl.players[entnum-1].dtopcolor; break; case GE_LIGHT: G_FLOAT(OFS_RETURN) = 0; @@ -5437,13 +5437,13 @@ static void QCBUILTIN PF_getentity(pubprogfuncs_t *prinst, struct globalvars_s * break; case GE_PANTSCOLOR: if (es->colormap <= cl.allocated_client_slots && !(es->dpflags & RENDER_COLORMAPPED)) - G_FLOAT(OFS_RETURN) = cl.players[es->colormap].tbottomcolor; + G_FLOAT(OFS_RETURN) = cl.players[es->colormap].dbottomcolor; else G_FLOAT(OFS_RETURN) = es->colormap & 15; break; case GE_SHIRTCOLOR: if (es->colormap <= cl.allocated_client_slots && !(es->dpflags & RENDER_COLORMAPPED)) - G_FLOAT(OFS_RETURN) = cl.players[es->colormap].ttopcolor; + G_FLOAT(OFS_RETURN) = cl.players[es->colormap].dtopcolor; else G_FLOAT(OFS_RETURN) = es->colormap>>4; break; @@ -6137,6 +6137,7 @@ static struct { {"skel_create", PF_skel_create, 263},//float(float modlindex) skel_create = #263; // (FTE_CSQC_SKELETONOBJECTS) {"skel_build", PF_skel_build, 264},//float(float skel, entity ent, float modelindex, float retainfrac, float firstbone, float lastbone, optional float addition) skel_build = #264; // (FTE_CSQC_SKELETONOBJECTS) + {"skel_build_ptr", PF_skel_build_ptr, 0},//float(float skel, int numblends, __variant *blends, int blendsize) skel_build_ptr = #0; {"skel_get_numbones", PF_skel_get_numbones, 265},//float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) {"skel_get_bonename", PF_skel_get_bonename, 266},//string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) (returns tempstring) {"skel_get_boneparent", PF_skel_get_boneparent, 267},//float(float skel, float bonenum) skel_get_boneparent = #267; // (FTE_CSQC_SKELETONOBJECTS) diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index 182b42cb..a24eba30 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -2812,7 +2812,6 @@ void MP_Draw(void) qboolean MP_Keydown(int key, int unicode, unsigned int devid) { qboolean result = false; - extern qboolean keydown[K_MAX]; #ifdef TEXTEDITOR if (editormodal) @@ -2822,9 +2821,10 @@ qboolean MP_Keydown(int key, int unicode, unsigned int devid) if (setjmp(mp_abort)) return true; -#ifndef QUAKETC +#ifndef NOBUILTINMENUS if (key == 'c') { + extern qboolean keydown[K_MAX]; if (keydown[K_LCTRL] || keydown[K_RCTRL]) { MP_Shutdown(); diff --git a/engine/client/pr_skelobj.c b/engine/client/pr_skelobj.c index 8d89d9ff..e60a484c 100644 --- a/engine/client/pr_skelobj.c +++ b/engine/client/pr_skelobj.c @@ -1946,6 +1946,167 @@ void QCBUILTIN PF_skel_build(pubprogfuncs_t *prinst, struct globalvars_s *pr_glo G_FLOAT(OFS_RETURN) = (skelobj - skelobjects) + 1; } +typedef struct +{ + int sourcemodelindex; + int sourceskel; + int firstbone; + int lastbone; + float prescale; //0 destroys existing data, 1 retains it. + float scale[4]; + int animation[4]; + float animationtime[4]; + + //halflife models + float subblend[2]; + float controllers[5]; +} skelblend_t; +//float(float skel, int numblends, skelblend_t *blenddata, int structsize) skel_build_ptr +void QCBUILTIN PF_skel_build_ptr(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + world_t *w = prinst->parms->user; + int skelidx = G_FLOAT(OFS_PARM0); + int numblends = G_INT(OFS_PARM1); + int blends_qcptr = G_INT(OFS_PARM2); + int structsize = G_INT(OFS_PARM3); + + skelblend_t *fte_restrict blends = (skelblend_t*)(prinst->stringtable+blends_qcptr); + int i, j; + framestate_t fstate; + skelobject_t *skelobj; + + float relationsbuf[MAX_BONES*12]; + float scale; + int numbones, firstbone, lastbone; + model_t *model; + qboolean noadd; + + //default to failure + G_FLOAT(OFS_RETURN) = 0; + + memset(&fstate, 0, sizeof(fstate)); + + skelobj = skel_get(w, skelidx); + if (!skelobj) + return; //couldn't get one, ran out of memory or something? + + if (structsize < sizeof(skelblend_t)) + return; //enforce a minimum size... + + for(; numblends --> 0; blends = (skelblend_t*)((char*)blends + structsize)) + { + noadd = blends->scale[0] == 0 && blends->scale[1] == 0 && blends->scale[2] == 0 && blends->scale[3] == 0; + if (blends->prescale == 1 && noadd) + continue; //does nothing to the model, skip it before wasting too much time. + + if (blends->sourceskel) + { + skelobject_t *srcskel = skel_get(w, blends->sourceskel); + if (!srcskel) + continue; + model = srcskel->model; + if (!model) + continue; //invalid model, can't get a skeleton + fstate.bonecount = numbones = srcskel->numbones; + fstate.bonestate = srcskel->bonematrix; + fstate.skeltype = srcskel->type; + } + else + { + fstate.bonecount = 0; + fstate.bonestate = NULL; + fstate.skeltype = SKEL_RELATIVE; + + if (blends->sourcemodelindex) + model = w->Get_CModel(w, blends->sourcemodelindex); + else + model = w->Get_CModel(w, skelobj->modelindex); + if (!model) + continue; //invalid model, can't get a skeleton + + numbones = Mod_GetNumBones(model, false); + if (!numbones) + continue; //this isn't a skeletal model. + } + + firstbone = blends->firstbone-1; + lastbone = blends->lastbone-1; + + if (lastbone < 0) + lastbone = numbones; + if (lastbone > numbones) + lastbone = numbones; + if (firstbone < 0) + firstbone = 0; + if (lastbone < firstbone) + lastbone = firstbone; + + fstate.g[FS_REG].endbone = 0x7fffffff; + for (i = 0; i < 4; i++) + { + fstate.g[FS_REG].frame[i] = blends->animation[i]; + fstate.g[FS_REG].frametime[i] = blends->animationtime[i]; + fstate.g[FS_REG].lerpweight[i] = blends->scale[i]; + } +#ifdef HALFLIFEMODELS + fstate.g[FS_REG].subblendfrac = blends->subblend[0]; + fstate.g[FS_REG].subblend2frac = blends->subblend[1]; + fstate.bonecontrols[0] = blends->controllers[0]; + fstate.bonecontrols[1] = blends->controllers[1]; + fstate.bonecontrols[2] = blends->controllers[2]; + fstate.bonecontrols[3] = blends->controllers[3]; + fstate.bonecontrols[4] = blends->controllers[4]; +#endif + + if (skelobj->type != SKEL_RELATIVE) + { + if (firstbone > 0 || lastbone < skelobj->numbones || blends->prescale) + { + Con_Printf("skel_build on non-relative skeleton\n"); + return; + } + skelobj->type = SKEL_RELATIVE; //entire model will get replaced, convert it. + } + if (noadd) + { + if (blends->prescale == 0) + memset(skelobj->bonematrix+firstbone*12, 0, sizeof(float)*12); + else + { //just rescale the existing bones + scale = blends->prescale; + for (i = firstbone; i < lastbone; i++) + { + for (j = 0; j < 12; j++) + skelobj->bonematrix[i*12+j] *= scale; + } + } + } + else if (blends->prescale == 0) //new data only. directly replace the existing data + Mod_GetBoneRelations(model, firstbone, lastbone, &fstate, skelobj->bonematrix); + else + { + if (blends->prescale != 1) + { //rescale the existing bones + scale = blends->prescale; + for (i = firstbone; i < lastbone; i++) + { + for (j = 0; j < 12; j++) + skelobj->bonematrix[i*12+j] *= scale; + } + } + + Mod_GetBoneRelations(model, firstbone, lastbone, &fstate, relationsbuf); + for (i = firstbone; i < lastbone; i++) + { + for (j = 0; j < 12; j++) + skelobj->bonematrix[i*12+j] += relationsbuf[i*12+j]; + } + } + } + + G_FLOAT(OFS_RETURN) = (skelobj - skelobjects) + 1; +} + //float(float skel) skel_get_numbones (FTE_CSQC_SKELETONOBJECTS) void QCBUILTIN PF_skel_get_numbones (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { diff --git a/engine/client/quakedef.h b/engine/client/quakedef.h index 97d876f8..3decbeb8 100644 --- a/engine/client/quakedef.h +++ b/engine/client/quakedef.h @@ -202,6 +202,7 @@ extern "C" { #define max(a,b) ((a) > (b) ? (a) : (b)) #define min(a,b) ((a) < (b) ? (a) : (b)) #endif +#define max3(a,b,c) max(max(a,b),c) //msvcrt lacks any and all c99 support. #if defined(_WIN32) diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index b389da86..93930572 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -355,7 +355,7 @@ void R2D_Init(void) "{\n" "map $whiteimage\n" "blendfunc gl_dst_color gl_zero\n" - "rgbgen const $r_menutint\n" + "rgbgen srgb $r_menutint\n" "}\n" #else "if gl_menutint_shader != 0\n" @@ -369,7 +369,7 @@ void R2D_Init(void) "{\n" "map $whiteimage\n" "blendfunc gl_dst_color gl_zero\n" - "rgbgen const $r_menutint\n" + "rgbgen srgb $r_menutint\n" "}\n" "endif\n" #endif @@ -1300,18 +1300,15 @@ void R2D_BrightenScreen (void) if (v_contrast.value < 0.5) v_contrast.value = 0.5; - if (r2d_canhwgamma) + if (r2d_canhwgamma || vid_hardwaregamma.ival == 4) return; TRACE(("R2D_BrightenScreen: brightening\n")); - if (v_gamma.value != 1 && shader_gammacb->prog) + if ((v_gamma.value != 1 || v_contrast.value > 3) && shader_gammacb->prog) { //this should really be done properly, with render-to-texture R2D_ImageColours (v_gamma.value, v_contrast.value, v_brightness.value, 1); - if (qrenderer == QR_OPENGL) - R2D_Image(0, 0, vid.width, vid.height, 0, 1, 1, 0, shader_gammacb); - else - R2D_Image(0, 0, vid.width, vid.height, 0, 0, 1, 1, shader_gammacb); + R2D_Image(0, 0, vid.width, vid.height, 0, 0, 1, 1, shader_gammacb); } else { diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index c6accf88..07f0c0c1 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -49,6 +49,13 @@ unsigned *blocklights; lightmapinfo_t **lightmap; int numlightmaps; +static const float rgb9e5tab[32] = { //multipliers for the 9-bit mantissa, according to the biased mantissa + //aka: pow(2, biasedexponent - bias-bits) where bias is 15 and bits is 9 + 1.0/(1<<24), 1.0/(1<<23), 1.0/(1<<22), 1.0/(1<<21), 1.0/(1<<20), 1.0/(1<<19), 1.0/(1<<18), 1.0/(1<<17), + 1.0/(1<<16), 1.0/(1<<15), 1.0/(1<<14), 1.0/(1<<13), 1.0/(1<<12), 1.0/(1<<11), 1.0/(1<<10), 1.0/(1<<9), + 1.0/(1<<8), 1.0/(1<<7), 1.0/(1<<6), 1.0/(1<<5), 1.0/(1<<4), 1.0/(1<<3), 1.0/(1<<2), 1.0/(1<<1), + 1.0, 1.0*(1<<1), 1.0*(1<<2), 1.0*(1<<3), 1.0*(1<<4), 1.0*(1<<5), 1.0*(1<<6), 1.0*(1<<7), +}; extern mleaf_t *r_vischain; // linked list of visible leafs @@ -56,7 +63,8 @@ extern cvar_t r_stains; extern cvar_t r_loadlits; extern cvar_t r_stainfadetime; extern cvar_t r_stainfadeammount; -extern cvar_t gl_lightmap_nearest; +extern cvar_t r_lightmap_nearest; +extern cvar_t r_lightmap_format; static int lightmap_shift; int Surf_LightmapShift (model_t *model) @@ -623,12 +631,6 @@ static void Surf_BuildDeluxMap (model_t *wmodel, msurface_t *surf, qbyte *dest, goto store; } - if (wmodel->engineflags & MDLF_RGBLIGHTING) - deluxmap = surf->samples - wmodel->lightdata + wmodel->deluxdata; - else - deluxmap = (surf->samples - wmodel->lightdata)*3 + wmodel->deluxdata; - - // clear to no light for (i=0 ; iengineflags & MDLF_RGBLIGHTING) + switch(wmodel->lightmaps.fmt) { + case LM_E5BGR9: deluxmap = surf->samples - wmodel->lightdata + wmodel->deluxdata; - - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; - maps++) + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) + { + scale = d_lightstylevalue[surf->styles[maps]]; + for (i=0 ; i>0)&0x1ff),((lm>>9)&0x1ff),((lm>>18)&0x1ff)) * scale * (rgb9e5tab[lm>>27]*(1<<7)); + blocknormals[i][0] += intensity*(deluxmap[i*3+0]-127); + blocknormals[i][1] += intensity*(deluxmap[i*3+1]-127); + blocknormals[i][2] += intensity*(deluxmap[i*3+2]-127); + } + lightmap += size*4; // skip to next lightmap + deluxmap += size*3; + } + break; + case LM_RGB8: + deluxmap = surf->samples - wmodel->lightdata + wmodel->deluxdata; + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; for (i=0 ; isamples - wmodel->lightdata)*3 + wmodel->deluxdata; - - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; - maps++) + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; for (i=0 ; i= 0.5) + { //positive exponent + while (m >= (1<<(e)) && e < 30-15) //don't do nans. + e++; + } + else + { //negative exponent... + while (m < 1/(1<<-e) && e > -15) //don't do denormals. + e--; + } + + scale = pow(2, e-9); + scale *= (1<>23)&0xff) - 127; + if (e < -15) + return 0; //too small exponent, treat it as a 0 denormal + if (e > 15) + m = 0; //infinity instead of a nan + else + m = (u.u&((1<<23)-1))>>13; + return ((e+15)<<10) | m; +} +static void Surf_PackRGB16F(void *result, int r, int g, int b, int one) +{ +#if 0 + //bulldozer+ or skylake+ supposedly. which means I can't test it, which means I can't enable it. + __v4sf rgba = (__v4sf){r, g, b, one} / (float)one; + union + { + __v8hi v; + __v4hi i; + } tmp; + //vcvtps2ph writes either a 64bit mem location, or the lower half of an xmm register. unfortunately ts still an xmm register, and that's 128bit. + //the __vXhi weirdness is because half-floats just don't work anywhere but conversions so __vXhf would cause all sorts of compiler errors, is the theory + tmp.v = __builtin_ia32_vcvtps2ph(rgba, 1); + *(__v4hi*)result = tmp.i; +#else + ((unsigned short*)result)[0] = Surf_GenHalf(r / (float)one); + ((unsigned short*)result)[1] = Surf_GenHalf(g / (float)one); + ((unsigned short*)result)[2] = Surf_GenHalf(b / (float)one); + ((unsigned short*)result)[3] = Surf_GenHalf(1.0);//0x0f<<10; //a standard ieee float should have all but the lead bit set of its exponent, and its mantissa 0. +#endif +} +static void Surf_PackRGB32F(void *result, int r, int g, int b, int one) +{ + ((float*)result)[0] = r/(float)one; + ((float*)result)[1] = g/(float)one; + ((float*)result)[2] = b/(float)one; + ((float*)result)[3] = 1.0; +} + /*any sane compiler will inline and split this, removing the stainsrc stuff just unpacks the internal lightmap block into texture info ready for upload merges stains and oversaturates overbrights. */ -static void Surf_StoreLightmap(qbyte *dest, unsigned int *bl, int smax, int tmax, unsigned int shift, enum lm_mode lm_mode, stmap *stainsrc, unsigned int lmwidth) +static void Surf_StoreLightmap_RGB(qbyte *dest, unsigned int *bl, int smax, int tmax, unsigned int shift, stmap *stainsrc, unsigned int lmwidth) { - int r, g, b, t, m; + int r, g, b, m; unsigned int i, j; int stride; - switch (lm_mode) + switch(lightmap_fmt) { - case bgra4_os: - stride = lmwidth*4 - (smax<<2); + default: + Sys_Error("Bad lightmap_fmt\n"); + break; + case PTI_A2BGR10: + stride = (lmwidth-smax)<<2; + + shift -= 2; + + for (i=0 ; i> shift; + g = *bl++ >> shift; + b = *bl++ >> shift; + + if (stainsrc) // merge in stain + { + r = (127+r*(*stainsrc++)) >> 8; + g = (127+g*(*stainsrc++)) >> 8; + b = (127+b*(*stainsrc++)) >> 8; + } + + // quake 2 method, scale highest down to + // maintain hue + m = max(max(r, g), b); + if (m > 1023) + { + r *= 1023.0/m; + g *= 1023.0/m; + b *= 1023.0/m; + } + + *(unsigned int*)dest = (3<<30) | ((b&0x3ff)<<20) | ((g&0x3ff)<<10) | (r&0x3ff); + dest += 4; + } + if (stainsrc) + stainsrc += (lmwidth - smax)*3; + } + break; + case PTI_E5BGR9: + stride = (lmwidth-smax)<<2; + + //5bit shared exponent, with bias of 15. + for (i=0 ; i> 8; + g = (127+g*(*stainsrc++)) >> 8; + b = (127+b*(*stainsrc++)) >> 8; + } + + *(unsigned int*)dest = Surf_PackE5BRG9(r,g,b,shift+8); + dest += 4; + } + if (stainsrc) + stainsrc += (lmwidth - smax)*3; + } + break; + case PTI_RGBA16F: + stride = (lmwidth-smax)<<3; + for (i=0 ; i> 8; + g = (127+g*(*stainsrc++)) >> 8; + b = (127+b*(*stainsrc++)) >> 8; + } + + Surf_PackRGB16F(dest, r,g,b,1<<(shift+8)); + dest += 8; + } + if (stainsrc) + stainsrc += (lmwidth - smax)*3; + } + break; + case PTI_RGBA32F: + stride = (lmwidth-smax)<<4; + for (i=0 ; i> 8; + g = (127+g*(*stainsrc++)) >> 8; + b = (127+b*(*stainsrc++)) >> 8; + } + + Surf_PackRGB32F(dest, r,g,b,1<<(shift+8)); + dest += sizeof(float)*4; + } + if (stainsrc) + stainsrc += (lmwidth - smax)*3; + } + break; + case PTI_RGBX8: + case PTI_RGBA8: + stride = (lmwidth-smax)<<2; + + for (i=0 ; i> shift; + g = *bl++ >> shift; + b = *bl++ >> shift; + + if (stainsrc) // merge in stain + { + r = (127+r*(*stainsrc++)) >> 8; + g = (127+g*(*stainsrc++)) >> 8; + b = (127+b*(*stainsrc++)) >> 8; + } + + // quake 2 method, scale highest down to + // maintain hue + m = max(max(r, g), b); + if (m > 255) + { + r *= 255.0/m; + g *= 255.0/m; + b *= 255.0/m; + } + + dest[0] = r; + dest[1] = g; + dest[2] = b; + dest[3] = 255; + + dest += 4; + } + if (stainsrc) + stainsrc += (lmwidth - smax)*3; + } + break; + case PTI_BGRX8: + case PTI_BGRA8: + stride = (lmwidth-smax)<<2; for (i=0 ; i> shift; + g = *bl++ >> shift; + b = *bl++ >> shift; + + if (stainsrc) // merge in stain + { + r = (127+r*(*stainsrc++)) >> 8; + g = (127+g*(*stainsrc++)) >> 8; + b = (127+b*(*stainsrc++)) >> 8; + } + + // quake 2 method, scale highest down to + // maintain hue + m = max(max(r, g), b); + if (m > 255) + { + r *= 255.0/m; + g *= 255.0/m; + b *= 255.0/m; + } + + *(unsigned short*)dest = (b>>3) | ((g>>2)<<5) | ((r>>3)<<11); + dest += 2; + } + if (stainsrc) + stainsrc += (lmwidth - smax)*3; + } + break; + case PTI_RGBA4444: + stride = (lmwidth-smax)<<1; + + for (i=0 ; i> shift; + g = *bl++ >> shift; + b = *bl++ >> shift; + + if (stainsrc) // merge in stain + { + r = (127+r*(*stainsrc++)) >> 8; + g = (127+g*(*stainsrc++)) >> 8; + b = (127+b*(*stainsrc++)) >> 8; + } + + // quake 2 method, scale highest down to + // maintain hue + m = max(max(r, g), b); + if (m > 255) + { + r *= 255.0/m; + g *= 255.0/m; + b *= 255.0/m; + } + + *(unsigned short*)dest = ((r>>4)<<12) | ((g>>4)<<8) | ((b>>4)<<4) | 0x000f; + dest += 2; + } + if (stainsrc) + stainsrc += (lmwidth - smax)*3; + } + break; + case PTI_RGBA5551: + stride = (lmwidth-smax)<<1; + + for (i=0 ; i> shift; + g = *bl++ >> shift; + b = *bl++ >> shift; + + if (stainsrc) // merge in stain + { + r = (127+r*(*stainsrc++)) >> 8; + g = (127+g*(*stainsrc++)) >> 8; + b = (127+b*(*stainsrc++)) >> 8; + } + + // quake 2 method, scale highest down to + // maintain hue + m = max(max(r, g), b); + if (m > 255) + { + r *= 255.0/m; + g *= 255.0/m; + b *= 255.0/m; + } + + *(unsigned short*)dest = ((r>>3)<<11) | ((g>>3)<<6) | ((b>>3)<<1) | 0x0001; + dest += 2; + } + if (stainsrc) + stainsrc += (lmwidth - smax)*3; + } + break; + case PTI_ARGB4444: + stride = (lmwidth-smax)<<1; + + for (i=0 ; i> shift; + g = *bl++ >> shift; + b = *bl++ >> shift; + + if (stainsrc) // merge in stain + { + r = (127+r*(*stainsrc++)) >> 8; + g = (127+g*(*stainsrc++)) >> 8; + b = (127+b*(*stainsrc++)) >> 8; + } + + // quake 2 method, scale highest down to + // maintain hue + m = max(max(r, g), b); + if (m > 255) + { + r *= 255.0/m; + g *= 255.0/m; + b *= 255.0/m; + } + + *(unsigned short*)dest = 0xf000 | ((r>>4)<<8) | ((g>>4)<<4) | ((b>>4)<<0); + dest += 2; + } + if (stainsrc) + stainsrc += (lmwidth - smax)*3; + } + break; + case PTI_ARGB1555: + stride = (lmwidth-smax)<<1; + + for (i=0 ; i> shift; + g = *bl++ >> shift; + b = *bl++ >> shift; + + if (stainsrc) // merge in stain + { + r = (127+r*(*stainsrc++)) >> 8; + g = (127+g*(*stainsrc++)) >> 8; + b = (127+b*(*stainsrc++)) >> 8; + } + + // quake 2 method, scale highest down to + // maintain hue + m = max(max(r, g), b); + if (m > 255) + { + r *= 255.0/m; + g *= 255.0/m; + b *= 255.0/m; + } + + *(unsigned short*)dest = 0x8000 | ((r>>3)<<10) | ((g>>3)<<5) | ((b>>3)<<0); + dest += 2; + } + if (stainsrc) + stainsrc += (lmwidth - smax)*3; + } + break; + case PTI_RGB8: stride = lmwidth*3 - (smax*3); for (i=0 ; i>= shift; - if (t > 255) - t = 255; - dest[j] = t; - } + t = *bl++; + t >>= shift; + if (t > 255) + t = 255; + dest[j] = t; } - break; - default: - Sys_Error ("Bad lightmap format"); } } @@ -879,19 +1295,18 @@ R_BuildLightMap Combine and scale multiple lightmaps into the 8.8 format in blocklights =============== */ -static void Surf_BuildLightMap (msurface_t *surf, qbyte *dest, qbyte *deluxdest, stmap *stainsrc, int shift, int ambient, unsigned int lmwidth) +static void Surf_BuildLightMap (model_t *currentmodel, msurface_t *surf, qbyte *dest, qbyte *deluxdest, stmap *stainsrc, int shift, int ambient, unsigned int lmwidth, int *d_lightstylevalue) { int smax, tmax; int t; - int i, j; + int i; size_t size; qbyte *lightmap; + unsigned scalergb[3]; unsigned scale; int maps; unsigned *bl; - //int stride = LMBLOCK_WIDTH*lightmap_bytes; //warning: unused variable ‘stride’ - shift += 7; // increase to base value surf->cached_dlight = (surf->dlightframe == r_framecount); @@ -902,6 +1317,7 @@ static void Surf_BuildLightMap (msurface_t *surf, qbyte *dest, qbyte *deluxdest, if (size > maxblocksize) { //fixme: fill in? + //Threading: this should not be a problem, all surfaces should have been built from the main thead at map load so it should have maxed it there. BZ_Free(blocklights); BZ_Free(blocknormals); @@ -913,7 +1329,7 @@ static void Surf_BuildLightMap (msurface_t *surf, qbyte *dest, qbyte *deluxdest, if (currentmodel->deluxdata) Surf_BuildDeluxMap(currentmodel, surf, deluxdest, lmwidth, blocknormals); - if (lightmap_fmt != TF_LUM8) + if (lightmap_fmt != PTI_L8) { // set to full bright if no light data if (ambient < 0) @@ -972,111 +1388,74 @@ static void Surf_BuildLightMap (msurface_t *surf, qbyte *dest, qbyte *deluxdest, // add all the lightmaps if (lightmap) { - if (currentmodel->fromgame == fg_quake3) //rgb + if (currentmodel->fromgame == fg_quake3) + Sys_Error("Surf_BuildLightMap: q3bsp"); + switch(currentmodel->lightmaps.fmt) { - /*q3 lightmaps are meant to be pre-built - this code is misguided, and ought never be executed anyway. - */ - bl = blocklights; - for (i = 0; i < tmax; i++) + case LM_E5BGR9: + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { - for (j = 0; j < smax; j++) - { - bl[0] = 255*lightmap[(i*lmwidth+j)*3]; - bl[1] = 255*lightmap[(i*lmwidth+j)*3+1]; - bl[2] = 255*lightmap[(i*lmwidth+j)*3+2]; - bl+=3; - } - } - } - else if (currentmodel->engineflags & MDLF_RGBLIGHTING) //rgb - { - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; - maps++) - { - scale = d_lightstylevalue[surf->styles[maps]]; - surf->cached_light[maps] = scale; // 8.8 fraction + surf->cached_light[maps] = scale = d_lightstylevalue[surf->styles[maps]]; // 8.8 fraction surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colourkey; - if (scale) { - if (cl_lightstyle[surf->styles[maps]].colours[0] == 1 && cl_lightstyle[surf->styles[maps]].colours[1] == 1 && cl_lightstyle[surf->styles[maps]].colours[2] == 1) //hopefully a faster alternative. + VectorScale(cl_lightstyle[surf->styles[maps]].colours, scale, scalergb); + for (i=0 ; i>27]*(1<<7); + blocklights[i*3+0] += scalergb[0] * e * ((l>> 0)&0x1ff); + blocklights[i*3+1] += scalergb[1] * e * ((l>> 9)&0x1ff); + blocklights[i*3+2] += scalergb[2] * e * ((l>>18)&0x1ff); } - else + } + lightmap += size*4; // skip to next lightmap + } + break; + case LM_RGB8: + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) + { + surf->cached_light[maps] = scale = d_lightstylevalue[surf->styles[maps]]; + surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colourkey; + if (scale) + { + VectorScale(cl_lightstyle[surf->styles[maps]].colours, scale, scalergb); + bl = blocklights; + for (i=0 ; istyles[maps]].colours[0]) - { - scale = d_lightstylevalue[surf->styles[maps]] * cl_lightstyle[surf->styles[maps]].colours[0]; - for (i=0 ; istyles[maps]].colours[1]) - { - scale = d_lightstylevalue[surf->styles[maps]] * cl_lightstyle[surf->styles[maps]].colours[1]; - for (i=0 ; istyles[maps]].colours[2]) - { - scale = d_lightstylevalue[surf->styles[maps]] * cl_lightstyle[surf->styles[maps]].colours[2]; - for (i=0 ; istyles[maps] != 255 ; maps++) { - scale = d_lightstylevalue[surf->styles[maps]]; - surf->cached_light[maps] = scale; // 8.8 fraction + surf->cached_light[maps] = scale = d_lightstylevalue[surf->styles[maps]]; // 8.8 fraction surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colourkey; - - if (cl_lightstyle[surf->styles[maps]].colours[0] == 1 && cl_lightstyle[surf->styles[maps]].colours[1] == 1 && cl_lightstyle[surf->styles[maps]].colours[2] == 1) //hopefully a faster alternative. + if (scale) { + VectorScale(cl_lightstyle[surf->styles[maps]].colours, scale, scalergb); bl = blocklights; for (i=0 ; istyles[maps]].colours[0]) - { - scale = d_lightstylevalue[surf->styles[maps]] * cl_lightstyle[surf->styles[maps]].colours[0]; - for (i=0, bl = blocklights; istyles[maps]].colours[1]) - { - scale = d_lightstylevalue[surf->styles[maps]] * cl_lightstyle[surf->styles[maps]].colours[1]; - for (i=0, bl = blocklights+1; istyles[maps]].colours[2]) - { - scale = d_lightstylevalue[surf->styles[maps]] * cl_lightstyle[surf->styles[maps]].colours[2]; - for (i=0, bl = blocklights+2; istained) stainsrc = NULL; - switch(lightmap_fmt) - { - default: - Sys_Error("Bad lightmap_fmt\n"); - case TF_BGRA32: - Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, bgra4_os, stainsrc, lmwidth); - break; -// case TF_RGBA32: -// Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, rgba4, stainsrc, lmwidth); -// break; - case TF_RGB24: - Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, rgb3_os, stainsrc, lmwidth); - break; - } + Surf_StoreLightmap_RGB(dest, blocklights, smax, tmax, shift, stainsrc, lmwidth); } else { - // set to full bright if no light data - if (!surf->samples || !currentmodel->lightdata) - { - for (i=0 ; icached_light[0] = d_lightstylevalue[0]; - surf->cached_colour[0] = cl_lightstyle[0].colourkey; - } - else if (r_fullbright.ival) + // set to full bright if no light data + if (r_fullbright.ival || !currentmodel->lightdata) { for (i=0 ; icached_light[0] = d_lightstylevalue[0]; + surf->cached_colour[0] = cl_lightstyle[0].colourkey; + } + //surfaces with no light data on lit maps are black + else if (!surf->samples) + { + for (i=0 ; icached_light[0] = d_lightstylevalue[0]; + surf->cached_colour[0] = cl_lightstyle[0].colourkey; } else { @@ -1128,21 +1495,35 @@ static void Surf_BuildLightMap (msurface_t *surf, qbyte *dest, qbyte *deluxdest, // add all the lightmaps if (lightmap) { - if (currentmodel->engineflags & MDLF_RGBLIGHTING) //rgb - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; - maps++) + switch(currentmodel->lightmaps.fmt) + { + case LM_E5BGR9: + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { - scale = d_lightstylevalue[surf->styles[maps]]/3; + scale = d_lightstylevalue[surf->styles[maps]]; surf->cached_light[maps] = scale; // 8.8 fraction surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colourkey; for (i=0 ; i>0)&0x1ff),((lm>>9)&0x1ff),((lm>>18)&0x1ff)) * scale * (rgb9e5tab[lm>>27]*(1<<7)); + } + lightmap += size*4; // skip to next lightmap + } + break; + case LM_RGB8: + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) + { + scale = d_lightstylevalue[surf->styles[maps]]; + surf->cached_light[maps] = scale; // 8.8 fraction + surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colourkey; + for (i=0 ; istyles[maps] != 255 ; - maps++) + break; + case LM_L8: + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; surf->cached_light[maps] = scale; // 8.8 fraction @@ -1151,13 +1532,15 @@ static void Surf_BuildLightMap (msurface_t *surf, qbyte *dest, qbyte *deluxdest, blocklights[i] += lightmap[i] * scale; lightmap += size; // skip to next lightmap } + break; + } } // add all the dynamic lights if (surf->dlightframe == r_framecount) Surf_AddDynamicLights (surf); } - Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, lum, stainsrc, lmwidth); + Surf_StoreLightmap_Grey(dest, blocklights, smax, tmax, shift, stainsrc, lmwidth); } } @@ -1169,6 +1552,7 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, qbyte int i, j; size_t size; qbyte *lightmap; + unsigned scalergb[3]; unsigned scale; int maps; unsigned *bl; @@ -1197,7 +1581,7 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, qbyte if (wmodel->deluxdata) Surf_BuildDeluxMap(wmodel, surf, deluxdest, lmwidth, blocknormals); - if (lightmap_fmt != TF_LUM8) + if (lightmap_fmt != PTI_L8) { // set to full bright if no light data if (ambient < 0) @@ -1273,112 +1657,79 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, qbyte } } } - else if (wmodel->engineflags & MDLF_RGBLIGHTING) //rgb + else switch(cl.worldmodel->lightmaps.fmt) { - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; - maps++) + case LM_E5BGR9: + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { - scale = d_lightstylevalue[surf->styles[maps]]; - surf->cached_light[maps] = scale; // 8.8 fraction + surf->cached_light[maps] = scale = d_lightstylevalue[surf->styles[maps]]; // 8.8 fraction surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colourkey; - if (scale) { - if (cl_lightstyle[surf->styles[maps]].colours[0] == 1 && cl_lightstyle[surf->styles[maps]].colours[1] == 1 && cl_lightstyle[surf->styles[maps]].colours[2] == 1) //hopefully a faster alternative. + VectorScale(cl_lightstyle[surf->styles[maps]].colours, scale, scalergb); + for (i=0 ; i>27]*(1<<7); + blocklights[i*3+0] += scalergb[0] * e * ((l>> 0)&0x1ff); + blocklights[i*3+1] += scalergb[1] * e * ((l>> 9)&0x1ff); + blocklights[i*3+2] += scalergb[2] * e * ((l>>18)&0x1ff); } - else + } + lightmap += size*4; // skip to next lightmap + } + break; + case LM_RGB8: + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) + { + surf->cached_light[maps] = scale = d_lightstylevalue[surf->styles[maps]]; + surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colourkey; + if (scale) + { + VectorScale(cl_lightstyle[surf->styles[maps]].colours, scale, scalergb); + bl = blocklights; + for (i=0 ; istyles[maps]].colours[0]) - { - scale = d_lightstylevalue[surf->styles[maps]] * cl_lightstyle[surf->styles[maps]].colours[0]; - for (i=0 ; istyles[maps]].colours[1]) - { - scale = d_lightstylevalue[surf->styles[maps]] * cl_lightstyle[surf->styles[maps]].colours[1]; - for (i=0 ; istyles[maps]].colours[2]) - { - scale = d_lightstylevalue[surf->styles[maps]] * cl_lightstyle[surf->styles[maps]].colours[2]; - for (i=0 ; istyles[maps] != 255 ; maps++) { - scale = d_lightstylevalue[surf->styles[maps]]; - surf->cached_light[maps] = scale; // 8.8 fraction + surf->cached_light[maps] = scale = d_lightstylevalue[surf->styles[maps]]; // 8.8 fraction surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colourkey; - - if (cl_lightstyle[surf->styles[maps]].colours[0] == 1 && cl_lightstyle[surf->styles[maps]].colours[1] == 1 && cl_lightstyle[surf->styles[maps]].colours[2] == 1) //hopefully a faster alternative. + if (scale) { + VectorScale(cl_lightstyle[surf->styles[maps]].colours, scale, scalergb); bl = blocklights; for (i=0 ; istyles[maps]].colours[0]) - { - scale = d_lightstylevalue[surf->styles[maps]] * cl_lightstyle[surf->styles[maps]].colours[0]; - for (i=0, bl = blocklights; istyles[maps]].colours[1]) - { - scale = d_lightstylevalue[surf->styles[maps]] * cl_lightstyle[surf->styles[maps]].colours[1]; - for (i=0, bl = blocklights+1; istyles[maps]].colours[2]) - { - scale = d_lightstylevalue[surf->styles[maps]] * cl_lightstyle[surf->styles[maps]].colours[2]; - for (i=0, bl = blocklights+2; istained) stainsrc = NULL; - switch(lightmap_fmt) - { - default: - Sys_Error("Bad lightmap_fmt\n"); - break; - case TF_BGRA32: - Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, bgra4_os, stainsrc, lmwidth); - break; - case TF_RGB24: - Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, rgb3_os, stainsrc, lmwidth); - break; - } + Surf_StoreLightmap_RGB(dest, blocklights, smax, tmax, shift, stainsrc, lmwidth); } else { @@ -1406,21 +1757,35 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, qbyte // add all the lightmaps if (lightmap) { - if (wmodel->engineflags & MDLF_RGBLIGHTING) //rgb - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; - maps++) + switch(cl.worldmodel->lightmaps.fmt) + { + case LM_E5BGR9: + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { - scale = d_lightstylevalue[surf->styles[maps]]/3; + scale = d_lightstylevalue[surf->styles[maps]]; surf->cached_light[maps] = scale; // 8.8 fraction surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colourkey; for (i=0 ; i>0)&0x1ff),((lm>>9)&0x1ff),((lm>>18)&0x1ff)) * scale * (rgb9e5tab[lm>>27]*(1<<7)); + } + lightmap += size*4; // skip to next lightmap + } + break; + case LM_RGB8: + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) + { + scale = d_lightstylevalue[surf->styles[maps]]; + surf->cached_light[maps] = scale; // 8.8 fraction + surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colourkey; + for (i=0 ; istyles[maps] != 255 ; - maps++) + break; + case LM_L8: + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; surf->cached_light[maps] = scale; // 8.8 fraction @@ -1429,10 +1794,12 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, qbyte blocklights[i] += lightmap[i] * scale; lightmap += size; // skip to next lightmap } + break; + } } } - Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, lum, stainsrc, lmwidth); + Surf_StoreLightmap_Grey(dest, blocklights, smax, tmax, shift, stainsrc, lmwidth); } } #endif @@ -1534,7 +1901,7 @@ dynamic: base += (fa->light_t[0] * lm->width + fa->light_s[0]) * lightmap_bytes; stainbase = lm->stainmaps; stainbase += (fa->light_t[0] * lm->width + fa->light_s[0]) * 3; - Surf_BuildLightMap (fa, base, luxbase, stainbase, lightmap_shift, r_ambient.value*255, lm->width); + Surf_BuildLightMap (currentmodel, fa, base, luxbase, stainbase, lightmap_shift, r_ambient.value*255, lm->width, d_lightstylevalue); RSpeedEnd(RSPEED_DYNAMIC); } @@ -1693,7 +2060,7 @@ dynamic: base += (fa->light_t[0] * lm->width + fa->light_s[0]) * lightmap_bytes; stainbase = lm->stainmaps; stainbase += (fa->light_t[0] * lm->width + fa->light_s[0]) * 3; - Surf_BuildLightMap (fa, base, luxbase, stainbase, lightmap_shift, -1-ambient, lm->width); + Surf_BuildLightMap (currentmodel, fa, base, luxbase, stainbase, lightmap_shift, -1-ambient, lm->width, d_lightstylevalue); RSpeedEnd(RSPEED_DYNAMIC); } @@ -3252,45 +3619,123 @@ void Surf_Clear(model_t *mod) maxblocksize = 0; } +uploadfmt_t Surf_NameToFormat(const char *nam) +{ + static uploadfmt_t tab[] = {PTI_L8, PTI_RGB8, PTI_BGRA8, PTI_A2BGR10, PTI_E5BGR9, PTI_RGBA16F, PTI_RGBA32F, PTI_RGB565, PTI_RGBA4444, PTI_RGBA5551}; + int idx = atoi(nam)-1; + if (idx>=0 && idx < countof(tab)) + return tab[idx]; + + if (!Q_strcasecmp(nam, "e5bgr9") || !Q_strcasecmp(nam, "rgb9e5")) + return PTI_E5BGR9; + if (!Q_strcasecmp(nam, "a2bgr10") || !Q_strcasecmp(nam, "rgb10a2") || !Q_strcasecmp(nam, "rgb10")) + return PTI_A2BGR10; + if (!Q_strcasecmp(nam, "rgba32f")) + return PTI_RGBA32F; + if (!Q_strcasecmp(nam, "rgba16f")) + return PTI_RGBA16F; +// if (!Q_strcasecmp(nam, "rgba8s")) +// return PTI_RGBA8_SIGNED; + if (!Q_strcasecmp(nam, "rgb565") || !Q_strcasecmp(nam, "rgb5")) + return PTI_RGB565; + if (!Q_strcasecmp(nam, "rgba4444") || !Q_strcasecmp(nam, "rgba4")) + return PTI_RGBA4444; + if (!Q_strcasecmp(nam, "rgba5551") || !Q_strcasecmp(nam, "rgba51")) + return PTI_RGBA5551; + if (!Q_strcasecmp(nam, "argb4444")) + return PTI_ARGB4444; + if (!Q_strcasecmp(nam, "argb1555")) + return PTI_ARGB1555; + if (!Q_strcasecmp(nam, "rgbx8") || !Q_strcasecmp(nam, "bgrx8") || !Q_strcasecmp(nam, "rgba8") || !Q_strcasecmp(nam, "bgra8")) + return PTI_BGRX8; + if (!Q_strcasecmp(nam, "rgb8") || !Q_strcasecmp(nam, "bgr8")) + return PTI_RGB8; + if (!Q_strcasecmp(nam, "l8")) + return PTI_L8; + if (*nam) + Con_Printf("Unknown lightmap format: %s\n", nam); + return TF_INVALID; +} + //pick fastest mode for lightmap data void Surf_LightmapMode(void) { - switch(qrenderer) + lightmap_fmt = Surf_NameToFormat(r_lightmap_format.string); + if (!sh_config.texfmt[lightmap_fmt]) { - default: -// case QR_VULKAN: -// case QR_SOFTWARE: -// case QR_DIRECT3D8: -// case QR_DIRECT3D9: -// case QR_DIRECT3D11: - lightmap_fmt = TF_BGRA32; - break; -#ifdef GLQUAKE - case QR_OPENGL: - /*favour bgra if the gpu supports it, otherwise use rgb only if it'll be used*/ - if (gl_config.gles) - lightmap_fmt = TF_RGB24; //rgb24 is a guarenteed supported format, where bgr24 or rgbx32 are not. - else if (gl_config.glversion >= 1.2) - lightmap_fmt = TF_BGRA32; //the more common case - else if (cl.worldmodel->fromgame == fg_quake3 || (cl.worldmodel->engineflags & MDLF_RGBLIGHTING) || cl.worldmodel->deluxdata || r_loadlits.value) - lightmap_fmt = TF_RGB24; //ooold gl driver, but we need rgb lighting + qboolean hdr = (vid.flags&VID_SRGBAWARE), rgb = false; + + if (lightmap_fmt != TF_INVALID) + Con_Printf("lightmap format %s not supported by renderer\n", r_lightmap_format.string); + + if (cl.worldmodel) + { + switch (cl.worldmodel->lightmaps.fmt) + { + case LM_E5BGR9: + hdr = rgb = true; + break; + case LM_RGB8: + rgb = true; + break; + case LM_L8: + break; + } + if (cl.worldmodel->deluxdata) + rgb = true; + } + + if (sh_config.texfmt[PTI_E5BGR9] && hdr) + lightmap_fmt = PTI_E5BGR9; + else if (sh_config.texfmt[PTI_RGBA16F] && hdr) + lightmap_fmt = PTI_RGBA16F; + else if (sh_config.texfmt[PTI_RGBA32F] && hdr) + lightmap_fmt = PTI_RGBA32F; + else if (sh_config.texfmt[PTI_A2BGR10] && rgb) + lightmap_fmt = PTI_A2BGR10; + else if (sh_config.texfmt[PTI_L8] && !rgb) + lightmap_fmt = PTI_L8; + else if (sh_config.texfmt[PTI_BGRX8]) + lightmap_fmt = PTI_BGRX8; + else if (sh_config.texfmt[PTI_RGB8]) + lightmap_fmt = PTI_RGB8; else - lightmap_fmt = TF_LUM8; //oldskool! - break; -#endif + lightmap_fmt = PTI_RGBX8; + } + Con_DPrintf("Using lightmap format %s\n", Image_FormatName(lightmap_fmt)); + switch(lightmap_fmt) { + case PTI_RGBA32F: + lightmap_bytes = 4*sizeof(float); + break; + case PTI_RGBA16F: + lightmap_bytes = 4*sizeof(short); + break; default: - case TF_BGRA32: - lightmap_bytes = 4; + case PTI_A2BGR10: + case PTI_E5BGR9: + case PTI_RGBA8: + case PTI_RGBX8: + case PTI_BGRA8: + case PTI_BGRX8: + lightmap_bytes = 4*sizeof(qbyte); break; - case TF_RGB24: - lightmap_bytes = 3; + case PTI_RGB8: + case PTI_BGR8: + lightmap_bytes = 3*sizeof(qbyte); break; - case TF_LUM8: - lightmap_bytes = 1; + case PTI_RGB565: + case PTI_RGBA4444: + case PTI_RGBA5551: + case PTI_ARGB4444: + case PTI_ARGB1555: + lightmap_bytes = sizeof(short); + break; + case PTI_L8: + lightmap_bytes = 1*sizeof(qbyte); break; } } @@ -3320,7 +3765,7 @@ int Surf_NewLightmaps(int count, int width, int height, qboolean deluxe) if (deluxe && ((i - numlightmaps)&1)) { - lightmap[i] = Z_Malloc(sizeof(*lightmap[i]) + (sizeof(qbyte)*4)*width*height); + lightmap[i] = Z_Malloc(sizeof(*lightmap[i]) + (sizeof(qbyte)*lightmap_bytes)*width*height); lightmap[i]->width = width; lightmap[i]->height = height; lightmap[i]->lightmaps = (qbyte*)(lightmap[i]+1); @@ -3329,11 +3774,11 @@ int Surf_NewLightmaps(int count, int width, int height, qboolean deluxe) } else { - lightmap[i] = Z_Malloc(sizeof(*lightmap[i]) + (sizeof(qbyte)*4 + sizeof(stmap)*3)*width*height); + lightmap[i] = Z_Malloc(sizeof(*lightmap[i]) + (sizeof(qbyte)*lightmap_bytes + sizeof(stmap)*3)*width*height); lightmap[i]->width = width; lightmap[i]->height = height; lightmap[i]->lightmaps = (qbyte*)(lightmap[i]+1); - lightmap[i]->stainmaps = (stmap*)(lightmap[i]->lightmaps+4*width*height); + lightmap[i]->stainmaps = (stmap*)(lightmap[i]->lightmaps+lightmap_bytes*width*height); lightmap[i]->hasdeluxe = deluxe; } @@ -3389,7 +3834,7 @@ int Surf_NewExternalLightmaps(int count, char *filepattern, qboolean deluxe) Q_snprintfz(nname, sizeof(nname), filepattern, i - numlightmaps); - TEXASSIGN(lightmap[i]->lightmap_texture, R_LoadHiResTexture(nname, NULL, (gl_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR)|IF_NOMIPMAP)); + TEXASSIGN(lightmap[i]->lightmap_texture, R_LoadHiResTexture(nname, NULL, (r_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR)|IF_NOMIPMAP)); if (lightmap[i]->lightmap_texture->status == TEX_LOADING) COM_WorkerPartialSync(lightmap[i]->lightmap_texture, &lightmap[i]->lightmap_texture->status, TEX_LOADING); lightmap[i]->width = lightmap[i]->lightmap_texture->width; @@ -3519,7 +3964,16 @@ void Surf_BuildModelLightmaps (model_t *m) default: Sys_Error("Bad lightmap_fmt\n"); break; - case TF_BGRA32: + case PTI_A2BGR10: + for (; src < stop; dst += 4, src += 3) + *(unsigned int*)dst = (0x3<<30) | (src[2]<<22) | (src[1]<<12) | (src[0]<<2); + break; + case PTI_E5BGR9: + for (; src < stop; dst += 4, src += 3) + *(unsigned int*)dst = Surf_PackE5BRG9(src[0], src[1], src[2], 8); + break; + case PTI_BGRA8: + case PTI_BGRX8: for (; src < stop; dst += 4, src += 3) { dst[0] = src[2]; @@ -3553,6 +4007,12 @@ void Surf_BuildModelLightmaps (model_t *m) dst[2] = src[2]; } break; + case PTI_L8: + for (; src < stop; dst += 1, src += 3) + { + dst[0] = max(max(src[0], src[1]), src[2]); + } + break; } } } @@ -3595,11 +4055,11 @@ void Surf_BuildModelLightmaps (model_t *m) else deluxemap = NULL; - Surf_BuildLightMap (surf, + Surf_BuildLightMap (currentmodel, surf, lm->lightmaps + (surf->light_t[j] * lm->width + surf->light_s[j]) * lightmap_bytes, deluxemap, lm->stainmaps + (surf->light_t[j] * lm->width + surf->light_s[j]) * 3, - shift, r_ambient.value*255, lm->width); + shift, r_ambient.value*255, lm->width, d_lightstylevalue); } } } diff --git a/engine/client/render.h b/engine/client/render.h index 206f74cd..c0997de2 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -167,10 +167,12 @@ typedef struct int nummappings; int maxmappings; qbyte geomset[MAX_GEOMSETS]; //allows selecting a single set of geometry from alternatives. this might be a can of worms. +#ifdef QWSKINS char qwskinname[MAX_QPATH]; struct qwskin_s *qwskin; unsigned int q1upper; //Q1UNSPECIFIED unsigned int q1lower; //Q1UNSPECIFIED +#endif struct { char surface[MAX_QPATH]; @@ -414,7 +416,7 @@ enum imageflags IF_NOGAMMA = 1<<9, IF_3DMAP = 1<<10, /*waning - don't test directly*/ IF_CUBEMAP = 1<<11, /*waning - don't test directly*/ - IF_TEXTYPE = (1<<10) | (1<<11), /*0=2d, 1=3d, 2=cubeface, 3=?*/ + IF_TEXTYPE = (1<<10) | (1<<11), /*0=2d, 1=3d, 2=cubeface, 3=2d array texture*/ IF_TEXTYPESHIFT = 10, /*0=2d, 1=3d, 2-7=cubeface*/ IF_MIPCAP = 1<<12, IF_PREMULTIPLYALPHA = 1<<13, //rgb *= alpha @@ -449,7 +451,8 @@ void Image_Upload (texid_t tex, uploadfmt_t fmt, void *data, void *palette, in void Image_Purge(void); //purge any textures which are not needed any more (releases memory, but doesn't give null pointers). void Image_Init(void); void Image_Shutdown(void); -void Image_BlockSizeForEncoding(unsigned int encoding, unsigned int *blockbytes, unsigned int *blockwidth, unsigned int *blockheight); +void Image_BlockSizeForEncoding(uploadfmt_t encoding, unsigned int *blockbytes, unsigned int *blockwidth, unsigned int *blockheight); +const char *Image_FormatName(uploadfmt_t encoding); image_t *Image_LoadTexture (const char *identifier, int width, int height, uploadfmt_t fmt, void *data, unsigned int flags); @@ -645,7 +648,9 @@ extern cvar_t r_lightstylesmooth_limit; extern cvar_t r_lightstylespeed; extern cvar_t r_lightstylescale; extern cvar_t r_lightmap_scale; +#ifdef QWSKINS extern cvar_t gl_nocolors; +#endif extern cvar_t gl_load24bit; extern cvar_t gl_finish; diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 54b1d4fa..720feec6 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -38,7 +38,9 @@ qboolean vid_isfullscreen; #define VKRENDEREROPTIONS "Vulkan-Specific Renderer Options" unsigned int d_8to24rgbtable[256]; +unsigned int d_8to24srgbtable[256]; unsigned int d_8to24bgrtable[256]; +unsigned int d_quaketo24srgbtable[256]; extern int gl_anisotropy_factor; @@ -76,8 +78,8 @@ cvar_t vid_vsync = CVARAF ("vid_vsync", "0", "vid_wait", CVAR_ARCHIVE); #endif -cvar_t _windowed_mouse = CVARF ("_windowed_mouse","1", - CVAR_ARCHIVE); +cvar_t _windowed_mouse = CVARF ("in_windowed_mouse","1", + CVAR_ARCHIVE); //renamed this, because of freecs users complaining that it doesn't work. I don't personally see why you'd want it set to 0, but that's winquake's default so boo hiss to that. cvar_t con_ocranaleds = CVAR ("con_ocranaleds", "2"); @@ -86,7 +88,9 @@ cvar_t cl_cursorscale = CVAR ("cl_cursor_scale", "1.0"); cvar_t cl_cursorbiasx = CVAR ("cl_cursor_bias_x", "0.0"); cvar_t cl_cursorbiasy = CVAR ("cl_cursor_bias_y", "0.0"); +#ifdef QWSKINS cvar_t gl_nocolors = CVARF ("gl_nocolors", "0", CVAR_ARCHIVE); +#endif cvar_t gl_part_flame = CVARFD ("gl_part_flame", "1", CVAR_ARCHIVE, "Enable particle emitting from models. Mainly used for torch and flame effects."); //opengl library, blank means try default. @@ -158,6 +162,7 @@ cvar_t r_lightstylesmooth_limit = CVAR ("r_lightstylesmooth_limit", "2"); cvar_t r_lightstylespeed = CVAR ("r_lightstylespeed", "10"); cvar_t r_lightstylescale = CVAR ("r_lightstylescale", "1"); cvar_t r_lightmap_scale = CVARFD ("r_shadow_realtime_nonworld_lightmaps", "1", 0, "Scaler for lightmaps used when not using realtime world lighting. Probably broken."); +cvar_t r_hdr_framebuffer = CVARFD("r_hdr_framebuffer", "0", CVAR_ARCHIVE, "If enabled, the map will be rendered into a high-precision image framebuffer. This avoids issues with shaders that contribute more than 1 in any single pass (like overbrights)."); cvar_t r_hdr_irisadaptation = CVARF ("r_hdr_irisadaptation", "0", CVAR_ARCHIVE); cvar_t r_hdr_irisadaptation_multiplier = CVAR ("r_hdr_irisadaptation_multiplier", "2"); cvar_t r_hdr_irisadaptation_minvalue = CVAR ("r_hdr_irisadaptation_minvalue", "0.5"); @@ -207,8 +212,9 @@ cvar_t r_waterwarp = CVARFD ("r_waterwarp", "1", cvar_t r_replacemodels = CVARFD ("r_replacemodels", IFMINIMAL("","md3 md2"), CVAR_ARCHIVE, "A list of filename extensions to attempt to use instead of mdl."); -cvar_t gl_lightmap_nearest = CVARFD ("gl_lightmap_nearest", "0", CVAR_ARCHIVE, "Use nearest sampling for lightmaps. This will give a more blocky look. Meaningless when gl_lightmap_average is enabled."); -cvar_t gl_lightmap_average = CVARFD ("gl_lightmap_average", "0", CVAR_ARCHIVE, "Determine lightmap values based upon the center of the polygon. This will give a more buggy look, quite probably."); +cvar_t r_lightmap_nearest = CVARFD ("gl_lightmap_nearest", "0", CVAR_ARCHIVE, "Use nearest sampling for lightmaps. This will give a more blocky look. Meaningless when gl_lightmap_average is enabled."); +cvar_t r_lightmap_average = CVARFD ("gl_lightmap_average", "0", CVAR_ARCHIVE, "Determine lightmap values based upon the center of the polygon. This will give a more buggy look, quite probably."); +cvar_t r_lightmap_format = CVARFD ("r_lightmap_format", "", CVAR_ARCHIVE|CVAR_RENDERERCALLBACK, "Overrides the default texture format used for lightmaps. rgb9e5 is a good choice for HDR."); //otherwise it would defeat the point. cvar_t scr_allowsnap = CVARF ("scr_allowsnap", "1", @@ -440,11 +446,12 @@ cvar_t r_vertexdlights = CVARD ("r_vertexdlights", "0", "Determine model li cvar_t vid_preservegamma = CVARD ("vid_preservegamma", "0", "Restore initial hardware gamma ramps when quitting."); cvar_t vid_hardwaregamma = CVARFD ("vid_hardwaregamma", "1", - CVAR_ARCHIVE | CVAR_RENDERERLATCH, "Use hardware gamma ramps. 0=ugly texture-based gamma, 1=glsl(windowed) or hardware(fullscreen), 2=always glsl, 3=always hardware gamma (disabled if hardware doesn't support)."); + CVAR_ARCHIVE | CVAR_RENDERERLATCH, "Use hardware gamma ramps. 0=ugly texture-based gamma, 1=glsl(windowed) or hardware(fullscreen), 2=always glsl, 3=always hardware gamma (disabled if hardware doesn't support), 4=scene-only gamma."); cvar_t vid_desktopgamma = CVARFD ("vid_desktopgamma", "0", CVAR_ARCHIVE | CVAR_RENDERERLATCH, "Apply gamma ramps upon the desktop rather than the window."); cvar_t r_fog_exp2 = CVARD ("r_fog_exp2", "1", "Expresses how fog fades with distance. 0 (matching DarkPlaces's default) is typically more realistic, while 1 (matching FitzQuake and others) is more common."); +cvar_t r_fog_permutation = CVARFD ("r_fog_permutation", "1", CVAR_SHADERSYSTEM, "Renders fog using a material permutation. 0 plays nicer with q3 shaders, but 1 is otherwise a better choice."); extern cvar_t gl_dither; cvar_t gl_screenangle = CVAR("gl_screenangle", "0"); @@ -487,7 +494,9 @@ void GLRenderer_Init(void) Cvar_Register (&gl_affinemodels, GLRENDEREROPTIONS); Cvar_Register (&gl_nohwblend, GLRENDEREROPTIONS); +#ifdef QWSKINS Cvar_Register (&gl_nocolors, GLRENDEREROPTIONS); +#endif Cvar_Register (&gl_finish, GLRENDEREROPTIONS); Cvar_Register (&gl_lateswap, GLRENDEREROPTIONS); Cvar_Register (&gl_lerpimages, GLRENDEREROPTIONS); @@ -524,6 +533,7 @@ void GLRenderer_Init(void) Cvar_Register (&gl_overbright_all, GRAPHICALNICETIES); Cvar_Register (&gl_dither, GRAPHICALNICETIES); Cvar_Register (&r_fog_exp2, GLRENDEREROPTIONS); + Cvar_Register (&r_fog_permutation, GLRENDEREROPTIONS); Cvar_Register (&r_tessellation, GRAPHICALNICETIES); Cvar_Register (&gl_ati_truform_type, GRAPHICALNICETIES); @@ -548,8 +558,9 @@ void GLRenderer_Init(void) Cvar_Register (&gl_menutint_shader, GLRENDEREROPTIONS); - Cvar_Register (&gl_lightmap_nearest, GLRENDEREROPTIONS); - Cvar_Register (&gl_lightmap_average, GLRENDEREROPTIONS); + Cvar_Register (&r_lightmap_nearest, GLRENDEREROPTIONS); + Cvar_Register (&r_lightmap_average, GLRENDEREROPTIONS); + Cvar_Register (&r_lightmap_format, GLRENDEREROPTIONS); } #endif @@ -824,6 +835,7 @@ void Renderer_Init(void) Cvar_Register(&r_lightstylescale, GRAPHICALNICETIES); Cvar_Register(&r_lightmap_scale, GRAPHICALNICETIES); + Cvar_Register(&r_hdr_framebuffer, GRAPHICALNICETIES); Cvar_Register(&r_hdr_irisadaptation, GRAPHICALNICETIES); Cvar_Register(&r_hdr_irisadaptation_multiplier, GRAPHICALNICETIES); Cvar_Register(&r_hdr_irisadaptation_minvalue, GRAPHICALNICETIES); @@ -1253,7 +1265,9 @@ void R_ShutdownRenderer(qboolean devicetoo) CL_AllowIndependantSendCmd(false); //FIXME: figure out exactly which parts are going to affect the model loading. +#ifdef QWSKINS Skin_FlushAll(); +#endif P_Shutdown(); Mod_Shutdown(false); @@ -1301,6 +1315,7 @@ void R_ShutdownRenderer(qboolean devicetoo) void R_GenPaletteLookup(void) { + extern qbyte default_quakepal[]; int r,g,b,i; unsigned char *pal = host_basepal; for (i=0 ; i<256 ; i++) @@ -1311,12 +1326,16 @@ void R_GenPaletteLookup(void) pal += 3; d_8to24rgbtable[i] = (255<<24) + (r<<0) + (g<<8) + (b<<16); + d_8to24srgbtable[i] = (255<<24) + (SRGBb(r)<<0) + (SRGBb(g)<<8) + (SRGBb(b)<<16); d_8to24bgrtable[i] = (255<<24) + (b<<0) + (g<<8) + (r<<16); } d_8to24rgbtable[255] &= 0xffffff; // 255 is transparent + d_8to24srgbtable[255] &= 0xffffff; // 255 is transparent d_8to24bgrtable[255] &= 0xffffff; // 255 is transparent -} + for (i=0 ; i<256 ; i++) + d_quaketo24srgbtable[i] = (255<<24) | (SRGBb(default_quakepal[(i)*3+0])<<0) | (SRGBb(default_quakepal[(i)*3+1])<<8) | (SRGBb(default_quakepal[(i)*3+2])<<16); +} qboolean R_ApplyRenderer (rendererstate_t *newr) { double time; @@ -1384,7 +1403,7 @@ qboolean R_ApplyRenderer_Load (rendererstate_t *newr) #endif if (newr) if (!r_forceheadless || newr->renderer->rtype != QR_HEADLESS) - Con_TPrintf("Setting mode %i*%i*%i*%i %s\n", newr->width, newr->height, newr->bpp, newr->rate, newr->renderer->description); + Con_TPrintf("Setting mode %i*%i %ibpp %ihz %s%s\n", newr->width, newr->height, newr->bpp, newr->rate, newr->srgb?"SRGB ":"", newr->renderer->description); vid.fullbright=0; @@ -1439,12 +1458,12 @@ qboolean R_ApplyRenderer_Load (rendererstate_t *newr) vid.fullbright = 0; //transparent colour doesn't count. q2colormap: - R_GenPaletteLookup(); TRACE(("dbg: R_ApplyRenderer: Palette loaded\n")); if (newr) { + vid.flags = 0; vid.gammarampsize = 256; //make a guess. if (!VID_Init(newr, host_basepal)) { @@ -1453,6 +1472,9 @@ TRACE(("dbg: R_ApplyRenderer: Palette loaded\n")); } TRACE(("dbg: R_ApplyRenderer: vid applied\n")); + //update palettes now that we know whether srgb is to be used etc + R_GenPaletteLookup(); + r_softwarebanding = false; r_deluxmapping = false; r_lightprepass = false; @@ -2025,7 +2047,7 @@ void R_SetRenderer_f (void) } if (newr.renderer->rtype != QR_HEADLESS && !strstr(param, "headless")) //don't save headless in the vid_renderer cvar via the setrenderer command. 'setrenderer headless;vid_restart' can then do what is most sane. - Cvar_Set(&vid_renderer, param); + Cvar_ForceSet(&vid_renderer, param); if (!r_blockvidrestart) R_RestartRenderer(&newr); diff --git a/engine/client/sbar.c b/engine/client/sbar.c index 1fb9162e..b7e7adc5 100644 --- a/engine/client/sbar.c +++ b/engine/client/sbar.c @@ -2224,8 +2224,10 @@ void Sbar_DrawScoreboard (playerview_t *pv) if (Key_Dest_Has(~kdm_game)) return; +#ifdef CSQC_DAT if (CSQC_DrawScores(pv)) return; +#endif #ifndef CLIENTONLY /*no scoreboard in single player (if you want bots, set deathmatch)*/ @@ -2776,8 +2778,10 @@ void Sbar_Draw (playerview_t *pv) qboolean minidmoverlay; extern cvar_t scr_centersbar; +#ifdef CSQC_DAT if (CSQC_DrawHud(pv)) return; +#endif headsup = !(cl_sbar.value || (scr_viewsize.value<100)); if ((sb_updates >= vid.numpages) && !headsup) diff --git a/engine/client/screen.h b/engine/client/screen.h index 251d49e1..f8c71253 100644 --- a/engine/client/screen.h +++ b/engine/client/screen.h @@ -85,42 +85,144 @@ enum fs_relative; typedef enum uploadfmt { - TF_INVALID, - TF_RGBA32, /*rgba byte order*/ - TF_BGRA32, /*bgra byte order*/ - TF_RGBX32, /*rgb byte order, with extra wasted byte after blue*/ - TF_BGRX32, /*rgb byte order, with extra wasted byte after blue*/ - TF_RGB24, /*rgb byte order, no alpha channel nor pad, and regular top down*/ - TF_BGR24, /*bgr byte order, no alpha channel nor pad, and regular top down*/ - TF_BGR24_FLIP, /*bgr byte order, no alpha channel nor pad, and bottom up*/ - TF_LUM8, /*8bit greyscale image*/ - TF_MIP4_LUM8, /*8bit 4-mip greyscale image*/ - TF_MIP4_SOLID8, /*8bit 4-mip image in default palette*/ - TF_MIP4_8PAL24, /*8bit 4-mip image with included palette*/ - TF_MIP4_8PAL24_T255,/*8bit 4-mip image with included palette where index 255 is alpha 0*/ - TF_SOLID8, /*8bit quake-palette image*/ - TF_TRANS8, /*8bit quake-palette image, index 255=transparent*/ - TF_TRANS8_FULLBRIGHT, /*fullbright 8 - fullbright texels have alpha 255, everything else 0*/ - TF_HEIGHT8, /*image data is greyscale, convert to a normalmap and load that, uploaded alpha contains the original heights*/ - TF_HEIGHT8PAL, /*source data is palette values rather than actual heights, generate a fallback heightmap*/ - TF_H2_T7G1, /*8bit data, odd indexes give greyscale transparence*/ - TF_H2_TRANS8_0, /*8bit data, 0 is transparent, not 255*/ - TF_H2_T4A4, /*8bit data, weird packing*/ + PTI_INVALID, - /*this block requires a palette*/ - TF_PALETTES, - TF_8PAL24, - TF_8PAL32, + //these formats are specified as direct byte access (listed in byte order, aka big-endian 0xrrggbbaa order) + PTI_RGBA8, //rgba byte ordering + PTI_RGBX8, //rgb pad byte ordering + PTI_BGRA8, //alpha channel + PTI_BGRX8, //no alpha channel + PTI_RGBA8_SRGB, //rgba byte ordering + PTI_RGBX8_SRGB, //rgb pad byte ordering + PTI_BGRA8_SRGB, //alpha channel + PTI_BGRX8_SRGB, //no alpha channel + PTI_RGB8, //24bit packed format. generally not supported + PTI_BGR8, //24bit packed format. generally not supported + PTI_L8, //8bit format (legacy more than anything else). luminance gets flooded to all RGB channels. might be supported using swizzles. + PTI_L8A8, //16bit format (legacy more than anything else). L=luminance + //small formats. + PTI_R8, //used for paletted data + PTI_RG8, //might be useful for normalmaps + PTI_R8_SNORM, + PTI_RG8_SNORM, //might be useful for normalmaps + //floating point formats + PTI_RGBA16F, + PTI_RGBA32F, + //packed/misaligned formats: these are specified in native endian order (high bits listed first because that's how things are represented in hex), so may need byte swapping... + PTI_A2BGR10, //mostly for rendertargets, might also be useful for overbight lightmaps. + PTI_E5BGR9, //mostly for fancy lightmaps + PTI_RGB565, //16bit alphaless format. + PTI_RGBA4444, //16bit format (gl) + PTI_ARGB4444, //16bit format (d3d) + PTI_RGBA5551, //16bit alpha format (gl). + PTI_ARGB1555, //16bit alpha format (d3d). + //(desktop/tegra) compressed formats + PTI_BC1_RGB, + PTI_BC1_RGB_SRGB, + PTI_BC1_RGBA, + PTI_BC1_RGBA_SRGB, + PTI_BC2_RGBA, + PTI_BC2_RGBA_SRGB, + PTI_BC3_RGBA, //maybe add a bc3 normalmapswizzle type for d3d9? + PTI_BC3_RGBA_SRGB, + PTI_BC4_R8, + PTI_BC4_R8_SNORM, + PTI_BC5_RG8, //useful for normalmaps + PTI_BC5_RG8_SNORM, //useful for normalmaps + PTI_BC6_RGB_UFLOAT, //unsigned (half) floats! + PTI_BC6_RGB_SFLOAT, //signed (half) floats! + PTI_BC7_RGBA, //multimode compression, using as many bits as bc2/bc3 + PTI_BC7_RGBA_SRGB, + //(mobile/intel) compressed formats + PTI_ETC1_RGB8, //limited form + PTI_ETC2_RGB8, //extended form + PTI_ETC2_RGB8A1, + PTI_ETC2_RGB8A8, + PTI_ETC2_RGB8_SRGB, + PTI_ETC2_RGB8A1_SRGB, + PTI_ETC2_RGB8A8_SRGB, + PTI_EAC_R11, //no idea what this might be used for, whatever + PTI_EAC_R11_SNORM, //no idea what this might be used for, whatever + PTI_EAC_RG11, //useful for normalmaps (calculate blue) + PTI_EAC_RG11_SNORM, //useful for normalmaps (calculate blue) + //astc... zomg + PTI_ASTC_4X4, + PTI_ASTC_4X4_SRGB, + PTI_ASTC_5X4, + PTI_ASTC_5X4_SRGB, + PTI_ASTC_5X5, + PTI_ASTC_5X5_SRGB, + PTI_ASTC_6X5, + PTI_ASTC_6X5_SRGB, + PTI_ASTC_6X6, + PTI_ASTC_6X6_SRGB, + PTI_ASTC_8X5, + PTI_ASTC_8X5_SRGB, + PTI_ASTC_8X6, + PTI_ASTC_8X6_SRGB, + PTI_ASTC_10X5, + PTI_ASTC_10X5_SRGB, + PTI_ASTC_10X6, + PTI_ASTC_10X6_SRGB, + PTI_ASTC_8X8, + PTI_ASTC_8X8_SRGB, + PTI_ASTC_10X8, + PTI_ASTC_10X8_SRGB, + PTI_ASTC_10X10, + PTI_ASTC_10X10_SRGB, + PTI_ASTC_12X10, + PTI_ASTC_12X10_SRGB, + PTI_ASTC_12X12, + PTI_ASTC_12X12_SRGB, - /*for render targets*/ - TF_DEPTH16, - TF_DEPTH24, - TF_DEPTH32, - TF_RGBA16F, - TF_RGBA32F, + //depth formats + PTI_DEPTH16, + PTI_DEPTH24, + PTI_DEPTH32, + PTI_DEPTH24_8, - /*for weird systems where the gl driver needs to do the decode (read: webgl)*/ - TF_SYSTEMDECODE + TF_BGR24_FLIP, /*bgr byte order, no alpha channel nor pad, and bottom up*/ + TF_MIP4_R8, /*8bit 4-mip greyscale image*/ + TF_MIP4_SOLID8, /*8bit 4-mip image in default palette*/ + TF_MIP4_8PAL24, /*8bit 4-mip image with included palette*/ + TF_MIP4_8PAL24_T255,/*8bit 4-mip image with included palette where index 255 is alpha 0*/ + TF_SOLID8, /*8bit quake-palette image*/ + TF_TRANS8, /*8bit quake-palette image, index 255=transparent*/ + TF_TRANS8_FULLBRIGHT, /*fullbright 8 - fullbright texels have alpha 255, everything else 0*/ + TF_HEIGHT8, /*image data is greyscale, convert to a normalmap and load that, uploaded alpha contains the original heights*/ + TF_HEIGHT8PAL, /*source data is palette values rather than actual heights, generate a fallback heightmap*/ + TF_H2_T7G1, /*8bit data, odd indexes give greyscale transparence*/ + TF_H2_TRANS8_0, /*8bit data, 0 is transparent, not 255*/ + TF_H2_T4A4, /*8bit data, weird packing*/ + + /*this block requires an explicit (separate) palette*/ + TF_8PAL24, + TF_8PAL32, + +#ifdef FTE_TARGET_WEB + //weird specialcase mess to take advantage of webgl so we don't need redundant bloat where we're already strugging with potential heap limits + PTI_WHOLEFILE, +#endif + + PTI_MAX, + + TF_INVALID = PTI_INVALID, + TF_DEPTH16 = PTI_DEPTH16, + TF_DEPTH24 = PTI_DEPTH24, + TF_DEPTH32 = PTI_DEPTH32, + TF_RGBA16F = PTI_RGBA16F, + TF_RGBA32F = PTI_RGBA32F, + TF_RGBA32 = PTI_RGBA8, /*rgba byte order*/ + TF_BGRA32 = PTI_BGRA8, /*bgra byte order*/ + TF_RGBX32 = PTI_RGBX8, /*rgb byte order, with extra wasted byte after blue*/ + TF_BGRX32 = PTI_BGRX8, /*rgb byte order, with extra wasted byte after blue*/ + TF_RGB24 = PTI_RGB8, /*rgb byte order, no alpha channel nor pad, and regular top down*/ + TF_BGR24 = PTI_BGR8, /*bgr byte order, no alpha channel nor pad, and regular top down*/ + TF_LUM8 = PTI_L8, + TF_R8 = PTI_R8 + + //these are emulated formats. this 'case' value allows drivers to easily ignore them +#define PTI_EMULATED TF_INVALID:case TF_BGR24_FLIP:case TF_MIP4_R8:case TF_MIP4_SOLID8:case TF_MIP4_8PAL24:case TF_MIP4_8PAL24_T255:case TF_SOLID8:case TF_TRANS8:case TF_TRANS8_FULLBRIGHT:case TF_HEIGHT8:case TF_HEIGHT8PAL:case TF_H2_T7G1:case TF_H2_TRANS8_0:case TF_H2_T4A4:case TF_8PAL24:case TF_8PAL32 } uploadfmt_t; qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void **buffer, int numbuffers, int bytestride, int width, int height, enum uploadfmt fmt); @@ -185,6 +287,33 @@ void PR_ReleaseFonts(unsigned int purgeowner); //for menu/csqc void PR_ReloadFonts(qboolean reload); /*end fonts*/ +//normally we're not srgb aware, which means that while the intensity may APPEAR linear, it actually isn't. +fte_inline float M_SRGBToLinear(float x, float mag) +{ + x /= mag; + if (x <= 0.04045f) + x = x * (1.0f / 12.92f); + else + x = pow(( x + 0.055f) * (1.0f / 1.055f), 2.4f); + x *= mag; + return x; +} +fte_inline float M_LinearToSRGB(float x, float mag) +{ + x /= mag; + if (x <= 0.00031308) + x = 12.92 * x; + else + x = 1.055*pow(x,(float)(1.0 / 2.4) ) - 0.055; + x *= mag; + return x; +} +//macros that are used to explicitly state that a value is srgb, and convert to linear as needed. +#define SRGBf(x) ((vid.flags&VID_SRGBAWARE)?M_SRGBToLinear(x,1):x) +#define SRGBb(x) ((vid.flags&VID_SRGBAWARE)?(unsigned char)M_SRGBToLinear(x,255):x) +#define SRGB3(x,y,z) SRGBf(x),SRGBf(y),SRGBf(z) +#define SRGBA(x,y,z,w) SRGBf(x),SRGBf(y),SRGBf(z),w + void R_NetgraphInit(void); void R_NetGraph (void); void R_FrameTimeGraph (int frametime); diff --git a/engine/client/skin.c b/engine/client/skin.c index 071baa38..304c8f1b 100644 --- a/engine/client/skin.c +++ b/engine/client/skin.c @@ -19,8 +19,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" -#include "glquake.h" +#ifdef QWSKINS cvar_t baseskin = CVAR("baseskin", ""); cvar_t noskins = CVAR("noskins", "0"); @@ -618,5 +618,27 @@ void Skin_FlushSkin(char *name) } } } +#else +void Skin_FlushPlayers(void) +{ +} +//required for the qw protocol (server stuffcmds 'skins' to get the client to send 'begin'. *sigh* +void Skin_Skins_f (void) +{ + if (cls.state == ca_disconnected) + { + Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0)); + return; + } + R_GAliasFlushSkinCache(false); + +// if (Cmd_FromServer()) + { + SCR_SetLoadingStage(LS_NONE); + + CL_SendClientCommand(true, "begin %i", cl.servercount); + } +} +#endif diff --git a/engine/client/sys_droid.c b/engine/client/sys_droid.c index 43098856..b36155a3 100644 --- a/engine/client/sys_droid.c +++ b/engine/client/sys_droid.c @@ -84,7 +84,7 @@ JNIEXPORT jstring JNICALL Java_com_fteqw_FTEDroidEngine_getpreferedorientation(J } /*the java passes in all input directly via a 'UI' thread. we don't need to poll it at all*/ -void INS_Move(float *movements, int pnum) +void INS_Move(void) { } void INS_Commands(void) diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index 3087078b..d03b85ba 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -64,7 +64,7 @@ void Sys_Init (void){} //safe, stub is fine. used to register system-speci void Sys_Shutdown(void){} //safe qboolean Sys_RandomBytes(qbyte *string, int len){return false;} qboolean Sys_GetDesktopParameters(int *width, int *height, int *bpp, int *refreshrate){return false;} -void INS_Move(float *movements, int pnum){} //safe +void INS_Move(void){} //safe void INS_Commands(void){} //safe void INS_Init(void){} //safe. should be xinput2 I guess. nothing else is actually supported. touchscreens don't really count. void INS_ReInit(void){} //safe diff --git a/engine/client/sys_xdk.c b/engine/client/sys_xdk.c index 2ba3a3c4..1d9aa802 100644 --- a/engine/client/sys_xdk.c +++ b/engine/client/sys_xdk.c @@ -148,18 +148,18 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (QDECL *func)( } /*consoles don't tend to need system clipboards, so this is fully internal to our engine*/ -#define SYS_CLIPBOARD_SIZE 256 -static char clipboard_buffer[SYS_CLIPBOARD_SIZE] = {0}; -char *Sys_GetClipboard(void) -{ - return clipboard_buffer; -} -void Sys_CloseClipboard(char *bf) -{ -} -void Sys_SaveClipboard(char *text) -{ - Q_strncpyz(clipboard_buffer, text, SYS_CLIPBOARD_SIZE); +#define SYS_CLIPBOARD_SIZE 256 +static char clipboard_buffer[SYS_CLIPBOARD_SIZE] = {0}; +char *Sys_GetClipboard(void) +{ + return clipboard_buffer; +} +void Sys_CloseClipboard(char *bf) +{ +} +void Sys_SaveClipboard(char *text) +{ + Q_strncpyz(clipboard_buffer, text, SYS_CLIPBOARD_SIZE); } /*dynamic library stubs*/ @@ -225,7 +225,7 @@ void INS_Shutdown (void) void INS_ReInit (void) { } -void INS_Move(float *movements, int pnum) +void INS_Move(void) { //accululates system-specific inputs on a per-seat basis. } diff --git a/engine/client/teamplay.c b/engine/client/teamplay.c index a31d9bf4..0dedf84e 100644 --- a/engine/client/teamplay.c +++ b/engine/client/teamplay.c @@ -1,384 +1,4 @@ /* - - Teamplay.c - Contains various console stuff for improving the performance of a team... - Cheats I hear you say?... - - Personally, I'd rather call it a hack job. - Most of it is dependant upon specific mod types - TF. - - - As far as split screen goes, this is all relative to player 0. We don't provide more than one say command. + replaced by zqtp.c (read: teamplay.c ported from zquake instead, with later fuhquake+ezquake additions, the ravages of time can be merciless) */ -#include "quakedef.h" - -#if 0 //ndef ZQUAKETEAMPLAY - -cvar_t tp_name_armortype_ga = {"tp_name_armortype_ga", "g"}; -cvar_t tp_name_armortype_ya = {"tp_name_armortype_ya", "y"}; -cvar_t tp_name_armortype_ra = {"tp_name_armortype_ra", "r"}; -cvar_t tp_name_none = {"tp_name_none", ""}; - - -#define translatetext(i) #i - - - -/////////////////////////////////////////////////////////////////// -//Macros. - -char *TP_ClassForTFSkin(void) -{ - char *skin; - skin = Info_ValueForKey(cls.userinfo, "skin"); - if (!*skin) - return "Classless"; - if (skin[0] != 't' && skin[1] != 'f' && skin[2] != '_') - return skin; - if (!strcmp(skin, "tf_sold")) - return translatetext(TLTP_CLASS_SOLIDER); - if (!strcmp(skin, "tf_demo")) - return translatetext(TLTP_CLASS_DEMOGUY); - if (!strcmp(skin, "tf_eng")) - return translatetext(TLTP_CLASS_ENGINEER); - if (!strcmp(skin, "tf_snipe")) - return translatetext(TLTP_CLASS_SNIPER); - if (!strcmp(skin, "tf_hwguy")) - return translatetext(TLTP_CLASS_HWGUY); - if (!strcmp(skin, "tf_medic")) - return translatetext(TLTP_CLASS_MEDIC); - if (!strcmp(skin, "tf_pyro")) - return translatetext(TLTP_CLASS_PYRO); - if (!strcmp(skin, "tf_scout")) - return translatetext(TLTP_CLASS_SCOUT); - if (!strcmp(skin, "tf_spy")) - return translatetext(TLTP_CLASS_SPY); - - return skin; -} - -void *TP_ArmourType(void) -{ - if (cl.stats[0][STAT_ITEMS] & IT_ARMOR1) - return tp_name_armortype_ga.string; - else if (cl.stats[0][STAT_ITEMS] & IT_ARMOR2) - return tp_name_armortype_ya.string; - else if (cl.stats[0][STAT_ITEMS] & IT_ARMOR3) - return tp_name_armortype_ra.string; - else - return tp_name_none.string; -} - - - - - - - -/////////////////////////////////////////////////////////////////// -//Locs - -typedef struct location_s { - vec3_t pos; - struct location_s *next; - char name[0]; -} location_t; -location_t *location; - -char LocationLevel[64]; - -void CL_LoadLocs(void) -{ - location_t *newloc; - vec3_t pos; - - char *file; - char *end; - char name[MAX_QPATH]; -// if (!strcmp(LocationLevel, cl.model_name[1])) -// return; - - while(location) - { - newloc = location->next; - Z_Free(location); - location = newloc; - } - - strcpy(LocationLevel, cl.model_name[1]); - - COM_StripExtension(COM_SkipPath(LocationLevel), name); - file = COM_LoadTempFile(va("locs/%s.loc", name)); - - if (!file) - return; - for(;;) - { - file = COM_Parse(file); - pos[0] = atof(com_token)/8; - file = COM_Parse(file); - pos[1] = atof(com_token)/8; - file = COM_Parse(file); - pos[2] = atof(com_token)/8; - - while(*file && *file <= '\0') - file++; - - if (!file) - return; - end = strchr(file, '\n'); - if (!end) - { - end = file + strlen(file); - } - newloc = Z_Malloc(sizeof(location_t) + end-file+1); - newloc->next = location; - location = newloc; - - Q_strncpyz(newloc->name, file, end-file); - VectorCopy(pos, newloc->pos); - - - if (!*end) - return; - file = end+1; - } -} - -char *CL_LocationName(float *pos) -{ - location_t *loc; - vec3_t dir; - char *best; - float dist, bestdist; - - CL_LoadLocs(); - - if (!location) - return "somewhere"; - - //get the initial one - best = location->name; - VectorSubtract(location->pos, pos, dir); - bestdist = VectorNormalize(dir); - - //check for a closer one. - for (loc = location->next; loc; loc=loc->next) - { - VectorSubtract(loc->pos, pos, dir); - dist = VectorNormalize(dir); - if (dist < bestdist) - { - best = loc->name; - bestdist = dist; - } - } - - return best; -} - - - -////////////////////////////////////////////////////////// -//Commands -#define INVIS_CHAR1 12 -#define INVIS_CHAR2 138 -#define INVIS_CHAR3 160 - -/* -=============== -CL_Say - -Handles both say and say_team -=============== -*/ - -void CL_Say_f (void) -{ - char output[8192]; - char string[256]; - char *msg; - int c; - output[0] = '\0'; - if (cls.state == ca_disconnected || cls.demoplayback) - { -#ifndef CLIENT_ONLY - if (sv.state) - SV_ConSay_f(); - else -#endif - Con_TPrintf ("Can't \"%s\", not connected\n", Cmd_Argv(0)); - return; - } - - if (!strcmp("sayone", Cmd_Argv(0))) - { - if (strcmp(Info_ValueForKey(cl.serverinfo, "*distrib"), DISTRIBUTION) || atoi(Info_ValueForKey(cl.serverinfo, "*ver")) < PRE_SAYONE) - { - Con_Printf ("%s is only available with server support\n", Cmd_Argv(0)); - return; - } - } - - Q_strncpyz(output, Cmd_Argv(0), sizeof(string)); - for (msg = output; *msg; msg++) - if (*msg >= 'A' && *msg <= 'Z') - *msg = *msg - 'A' + 'a'; - - msg = Cmd_Args(); - - if (Cmd_Argc() > 1) - { - Q_strncatz(output, " \"", sizeof(output)); - - while(*msg) - { - c = *msg; - - if (c == '%') - { - char *message = NULL; - msg++; - - if (message == NULL) - switch(*msg) - { - case 'n': - Q_strncatz(output, name.string, sizeof(output)); - msg++; - continue; - case 'h': - Q_strncatz(output, va("%i", cl.stats[0][STAT_HEALTH]), sizeof(output)); - msg++; - continue; - case 'a': - Q_strncatz(output, va("%i", cl.stats[0][STAT_ARMOR]), sizeof(output)); - msg++; - continue; - case 'A': - Q_strncatz(output, TP_ArmourType(), sizeof(output)); - msg++; - continue; - case 'l': - Q_strncatz(output, CL_LocationName(cl.simorg[0]), sizeof(output)); - msg++; - continue; - case 'S': - Q_strncatz(output, TP_ClassForTFSkin(), sizeof(output)); - msg++; - continue; - case '%': - c = '%'; - break; - default: - c = '%'; - msg--; - break; - } - } - else if (c == '$') - { - msg++; - switch(*msg) - { - case '\\': c = 0x0D; break; - case ':': c = 0x0A; break; - case '[': c = 0x10; break; - case ']': c = 0x11; break; - case 'G': c = 0x86; break; - case 'R': c = 0x87; break; - case 'Y': c = 0x88; break; - case 'B': c = 0x89; break; - case '(': c = 0x80; break; - case '=': c = 0x81; break; - case ')': c = 0x82; break; - case 'a': c = 0x83; break; - case '<': c = 0x1d; break; - case '-': c = 0x1e; break; - case '>': c = 0x1f; break; - case ',': c = 0x1c; break; - case '.': c = 0x9c; break; - case 'b': c = 0x8b; break; - case 'c': - case 'd': c = 0x8d; break; - case '$': c = '$'; break; - case '^': c = '^'; break; - case 'x': - c = INVIS_CHAR1; - break; - case 'y': - c = INVIS_CHAR2; - break; - case 'z': - c = INVIS_CHAR3; - break; - default: - msg--; - break; - } - - } - - Q_strncatz(output, va("%c", c), sizeof(output)); - - msg++; - } - Q_strncatz(output, "\"", sizeof(output)); - } - - CL_SendClientCommand("%s", output); -} - -void TP_Init(void) -{ -} - -void TP_CheckPickupSound(char *s, vec3_t org) -{ -} - - -#endif - -qboolean TP_SoundTrigger(char *message) //if there is a trigger there, play it. Return true if we found one, stripping off the file (it's neater that way). -{ - char *strip; - char *lineend = NULL; - char soundname[128]; - int filter = 0; - - for (strip = message+strlen(message)-1; *strip && strip >= message; strip--) - { - if (*strip == '#') - filter++; - if (*strip == ':') - break; //if someone says just one word, we can take any tidles in their name to be a voice command - if (*strip == '\n') - lineend = strip; - else if (*strip <= ' ') - { - if (filter == 0 || filter == 1) //allow one space in front of a filter. - { - filter++; - continue; - } - break; - } - else if (*strip == '~') - { - //looks like a trigger, whoopie! - if (lineend-strip > sizeof(soundname)-1) - { - Con_Printf("Sound trigger's file-name was too long\n"); - return false; - } - Q_strncpyz(soundname, strip+1, lineend-strip); - memmove(strip, lineend, strlen(lineend)+1); - - Cbuf_AddText(va("play %s\n", soundname), RESTRICT_LOCAL); - return true; - } - } - return false; -} diff --git a/engine/client/vid.h b/engine/client/vid.h index 43e4c599..cd6a5557 100644 --- a/engine/client/vid.h +++ b/engine/client/vid.h @@ -46,7 +46,7 @@ typedef struct { int fullscreen; //0 = windowed. 1 = fullscreen (mode changes). 2 = borderless+maximized qboolean stereo; qboolean srgb; - int bpp; + int bpp; //16, 24(aka 32), 30, and 48 are meaningful int rate; int wait; //-1 = default, 0 = off, 1 = on, 2 = every other int multisample; //for opengl antialiasing (which requires context stuff) @@ -72,6 +72,15 @@ typedef struct int maxheight; //vid.pixelheight or so } pxrect_t; +//srgb colourspace displays smoother visual gradients, but its more of an illusion than anything else. +// +#define VID_SRGBAWARE (1u<<0) //we need to convert input srgb values to actual linear values (requires vid_reload to change...) +#define VID_SRGB_FB_LINEAR (1u<<1) //framebuffer is linear (either the presentation engine is linear, or the blend unit is faking it) +#define VID_SRGB_FB_FAKED (1u<<2) //renderer is faking it with a linear texture +#define VID_SRGB_CAPABLE (1u<<3) //we can toggle VID_SRGB_FB_LINEARISED on or off. +#define VID_FP16 (1u<<4) //use 16bit currentrender etc to avoid banding +#define VID_SRGB_FB (VID_SRGB_FB_LINEAR|VID_SRGB_FB_FAKED) + typedef struct { qboolean activeapp; @@ -89,7 +98,7 @@ typedef struct unsigned height; /*virtual 2d screen height*/ int numpages; - qboolean srgb; /*we're forcing linear fragment shaders, both inputs and outputs (and not using srgb as a gamma hack)*/ + unsigned int flags; //VID_* flags unsigned rotpixelwidth; /*width after rotation in pixels*/ unsigned rotpixelheight; /*pixel after rotation in pixels*/ @@ -103,7 +112,9 @@ typedef struct extern viddef_t vid; // global video state extern unsigned int d_8to24rgbtable[256]; +extern unsigned int d_8to24srgbtable[256]; extern unsigned int d_8to24bgrtable[256]; +extern unsigned int d_quaketo24srgbtable[256]; #ifdef GLQUAKE //called when gamma ramps need to be reapplied diff --git a/engine/client/zqtp.c b/engine/client/zqtp.c index 212d95f3..22206e9a 100644 --- a/engine/client/zqtp.c +++ b/engine/client/zqtp.c @@ -1917,6 +1917,7 @@ char *TP_MapName (void) return host_mapname.string; } +#ifdef QWSKINS /* ============================================================================= TEAMCOLOR & ENEMYCOLOR @@ -2131,6 +2132,7 @@ static void TP_EnemyColor_f (void) CL_NewTranslation(i); } } +#endif //=================================================================== @@ -3700,15 +3702,16 @@ void TP_Init (void) Cmd_AddCommand ("loadloc", TP_LoadLocFile_f); Cmd_AddCommand ("filter", TP_MsgFilter_f); Cmd_AddCommand ("msg_trigger", TP_MsgTrigger_f); +#ifdef QWSKINS Cmd_AddCommand ("teamcolor", TP_TeamColor_f); Cmd_AddCommand ("enemycolor", TP_EnemyColor_f); - Cmd_AddCommand ("tp_took", TP_Took_f); - Cmd_AddCommand ("tp_pickup", TP_Pickup_f); - Cmd_AddCommand ("tp_point", TP_Point_f); - Cmd_AddCommand ("colourise", TP_Colourise_f); //uk Cmd_AddCommand ("colorize", TP_Colourise_f); //us //Cmd_AddCommand ("colorise", TP_Colourise_f); //piss off both. +#endif + Cmd_AddCommand ("tp_took", TP_Took_f); + Cmd_AddCommand ("tp_pickup", TP_Pickup_f); + Cmd_AddCommand ("tp_point", TP_Point_f); TP_InitMacros(); } @@ -3888,5 +3891,44 @@ void CL_SayTeam_f (void) CL_Say (true, NULL); } +qboolean TP_SoundTrigger(char *message) //if there is a trigger there, play it. Return true if we found one, stripping off the file (it's neater that way). +{ + char *strip; + char *lineend = NULL; + char soundname[128]; + int filter = 0; + for (strip = message+strlen(message)-1; *strip && strip >= message; strip--) + { + if (*strip == '#') + filter++; + if (*strip == ':') + break; //if someone says just one word, we can take any tidles in their name to be a voice command + if (*strip == '\n') + lineend = strip; + else if (*strip <= ' ') + { + if (filter == 0 || filter == 1) //allow one space in front of a filter. + { + filter++; + continue; + } + break; + } + else if (*strip == '~') + { + //looks like a trigger, whoopie! + if (lineend-strip > sizeof(soundname)-1) + { + Con_Printf("Sound trigger's file-name was too long\n"); + return false; + } + Q_strncpyz(soundname, strip+1, lineend-strip); + memmove(strip, lineend, strlen(lineend)+1); + Cbuf_AddText(va("play %s\n", soundname), RESTRICT_LOCAL); + return true; + } + } + return false; +} diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index 6498b8fd..4eedf3c0 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -81,6 +81,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define STRINGIFY2(s) #s #define STRINGIFY(s) STRINGIFY2(s) +#define QWSKINS //disables qw .pcx skins, as well as enemy/team colour forcing. + #ifdef CONFIG_FILE_NAME //yup, C89 allows this (doesn't like C's token concat though). #include STRINGIFY(CONFIG_FILE_NAME) diff --git a/engine/common/cmd.c b/engine/common/cmd.c index c162b340..b9f9fd6b 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -3830,7 +3830,7 @@ void Cmd_WriteConfig_f(void) return; } - VFS_WRITE(f, "// FTE config file\n\n", 20); + VFS_PRINTF(f, "// %s config file\n\n", *fs_gamename.string?fs_gamename.string:FULLENGINENAME); #ifndef SERVERONLY Key_WriteBindings (f); IN_WriteButtons(f, all); diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index 762b1f3f..bcdabf43 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -1010,7 +1010,7 @@ static qboolean Alias_BuildSkelLerps(skellerps_t *lerps, struct framestateregion int l = 0; galiasanimation_t *g; unsigned int b; - float totalweight = 0; + float totalweight = 0, dropweight = 0; #ifndef SERVERONLY extern cvar_t r_nolerp; #endif @@ -1028,12 +1028,18 @@ static qboolean Alias_BuildSkelLerps(skellerps_t *lerps, struct framestateregion if (inf->numanimations) frame = 0; else + { + dropweight += fs->lerpweight[b]; continue;//frame = (unsigned)frame%inf->groups; + } } g = &inf->ofsanimations[frame]; if (!g->numposes) + { + dropweight += fs->lerpweight[b]; continue; //err... + } mlerp = time*g->rate; frame1=mlerp; @@ -1053,7 +1059,10 @@ static qboolean Alias_BuildSkelLerps(skellerps_t *lerps, struct framestateregion if (lerps->skeltype == SKEL_IDENTITY) lerps->skeltype = g->skeltype; else if (lerps->skeltype != g->skeltype) + { + dropweight += fs->lerpweight[b]; continue; //oops, can't cope with mixed blend types + } if (frame1 == frame2) mlerp = 0; @@ -1087,15 +1096,15 @@ static qboolean Alias_BuildSkelLerps(skellerps_t *lerps, struct framestateregion mlerp = lerps->frac[b]; } } - lerps->frac[0] = 1; + lerps->frac[0] = totalweight+dropweight; lerps->pose[0] = lerps->pose[frame1]; l = 1; } else #endif - if (l && totalweight != 1) + if (l && totalweight && dropweight) { //don't rescale if some animation got dropped. - totalweight = 1 / totalweight; + totalweight = (totalweight+dropweight) / totalweight; for (b = 0; b < l; b++) { lerps->frac[b] *= totalweight; @@ -6948,7 +6957,7 @@ static void IQM_ImportArrayF(const qbyte *base, const struct iqmvertexarray *src } } -const void *IQM_FindExtension(const char *buffer, const char *extname, int index, size_t *extsize) +static const void *IQM_FindExtension(const char *buffer, size_t buffersize, const char *extname, int index, size_t *extsize) { struct iqmheader *h = (struct iqmheader *)buffer; const char *strings = buffer + h->ofs_text; @@ -6956,6 +6965,8 @@ const void *IQM_FindExtension(const char *buffer, const char *extname, int index int i; for (i = 0, ext = (struct iqmextension*)(buffer + h->ofs_extensions); i < h->num_extensions; i++, ext = (struct iqmextension*)(buffer + ext->ofs_extensions)) { + if ((char*)ext > buffer+buffersize || ext->name > h->num_text || ext->ofs_data+ext->num_data>buffersize) + break; if (!Q_strcasecmp(strings + ext->name, extname) && index-->=0) { *extsize = ext->num_data; @@ -6997,7 +7008,7 @@ static void Mod_CleanWeights(const char *modelname, size_t numverts, vec4_t *owe } } if (problemfound) - Con_Printf(CON_ERROR"%s has invalid vertex weights. Verticies will probably be attached to the wrong bones\n", modelname); + Con_DPrintf(CON_ERROR"%s has invalid vertex weights. Verticies will probably be attached to the wrong bones\n", modelname); } galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, size_t fsize) @@ -7360,7 +7371,7 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, size_t fsi extsize = 0; } else - fteevents = IQM_FindExtension(buffer, "FTE_EVENT", 0, &extsize); + fteevents = IQM_FindExtension(buffer, fsize, "FTE_EVENT", 0, &extsize); if (fteevents && !(extsize % sizeof(*fteevents))) { galiasevent_t *oevent, **link; @@ -7400,7 +7411,7 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, size_t fsi else AddPointToBounds(vec3_origin, mod->mins, mod->maxs); - ftemesh = IQM_FindExtension(buffer, "FTE_MESH", 0, &extsize); + ftemesh = IQM_FindExtension(buffer, fsize, "FTE_MESH", 0, &extsize); if (!extsize || extsize != sizeof(*ftemesh)*h->num_meshes) ftemesh = NULL; //erk. @@ -7496,7 +7507,7 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, size_t fsi if (!noweights) { if (!IQM_ImportArray4B(buffer, &vbone, oindex, h->num_vertexes, h->num_joints)) - Con_Printf(CON_WARNING "Invalid bone indexes detected inside %s\n", mod->name); + Con_DPrintf(CON_WARNING "Invalid bone indexes detected inside %s\n", mod->name); IQM_ImportArrayF(buffer, &vweight, (float*)oweight, 4, h->num_vertexes, defaultweight); Mod_CleanWeights(mod->name, h->num_vertexes, oweight, oindex); } diff --git a/engine/common/common.c b/engine/common/common.c index 80b9a6c9..8da12440 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -27,6 +27,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. //by adding 'extern' to one definition of a function in a translation unit, then the definition in that TU is NOT considered an inline definition. meaning non-inlined references in other TUs can link to it instead of their own if needed. fte_inlinebody conchar_t *Font_Decode(conchar_t *start, unsigned int *codeflags, unsigned int *codepoint); +fte_inlinebody float M_SRGBToLinear(float x, float mag); +fte_inlinebody float M_LinearToSRGB(float x, float mag); // These 4 libraries required for the version command diff --git a/engine/common/common.h b/engine/common/common.h index 6ada721a..7171dba4 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -67,8 +67,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define FTE_WORDSIZE 32 #else #ifdef __LP64__ - #define qintptr_t long - #define qint64_t long + #define qintptr_t long int + #define qint64_t long int #define FTE_WORDSIZE 64 #elif __WORDSIZE == 64 #define qintptr_t long long diff --git a/engine/common/config_wastes.h b/engine/common/config_wastes.h index 9224aaa6..06678251 100644 --- a/engine/common/config_wastes.h +++ b/engine/common/config_wastes.h @@ -24,7 +24,7 @@ //#define D3D9QUAKE //#define GLQUAKE #undef D3D11QUAKE -#if defined(WIN32) +#if defined(WIN32) && !defined(D3D8QUAKE) #define D3D8QUAKE #endif #undef VKQUAKE @@ -99,6 +99,7 @@ #undef USE_SQLITE //sql-database-as-file support #undef QUAKESTATS //defines STAT_HEALTH etc. if omitted, you'll need to provide that functionality yourself. #undef QUAKEHUD //support for drawing the vanilla hud. +#undef QWSKINS //disabling this means no qw .pcx skins nor enemy/team skin/colour forcing #undef SVRANKING //legacy server-side ranking system. #undef RAGDOLL //ragdoll support. requires RBE support. #undef HUFFNETWORK //crappy network compression. probably needs reseeding. diff --git a/engine/common/fs.c b/engine/common/fs.c index e896eff8..4655169a 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -51,11 +51,11 @@ struct { void *module; const char *extension; - searchpathfuncs_t *(QDECL *OpenNew)(vfsfile_t *file, const char *desc, const char *prefix); + searchpathfuncs_t *(QDECL *OpenNew)(vfsfile_t *file, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix); qboolean loadscan; } searchpathformats[64]; -int FS_RegisterFileSystemType(void *module, const char *extension, searchpathfuncs_t *(QDECL *OpenNew)(vfsfile_t *file, const char *desc, const char *prefix), qboolean loadscan) +int FS_RegisterFileSystemType(void *module, const char *extension, searchpathfuncs_t *(QDECL *OpenNew)(vfsfile_t *file, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix), qboolean loadscan) { unsigned int i; for (i = 0; i < sizeof(searchpathformats)/sizeof(searchpathformats[0]); i++) @@ -2315,7 +2315,7 @@ searchpathfuncs_t *FS_GetOldPath(searchpath_t **oldpaths, const char *dir, unsig } typedef struct { - searchpathfuncs_t *(QDECL *OpenNew)(vfsfile_t *file, const char *desc, const char *prefix); + searchpathfuncs_t *(QDECL *OpenNew)(vfsfile_t *file, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix); searchpath_t **oldpaths; const char *parentdesc; const char *puredesc; @@ -2357,7 +2357,7 @@ static int QDECL FS_AddWildDataFiles (const char *descriptor, qofs_t size, time_ if (!vfs) return true; } - newpak = param->OpenNew (vfs, pakfile, ""); + newpak = param->OpenNew (vfs, funcs, descriptor, pakfile, ""); if (!newpak) { VFS_CLOSE(vfs); @@ -2375,7 +2375,7 @@ static int QDECL FS_AddWildDataFiles (const char *descriptor, qofs_t size, time_ return true; } -searchpathfuncs_t *FS_OpenPackByExtension(vfsfile_t *f, const char *pakname) +searchpathfuncs_t *FS_OpenPackByExtension(vfsfile_t *f, searchpathfuncs_t *parent, const char *filename, const char *pakname) { searchpathfuncs_t *pak; int j; @@ -2387,7 +2387,7 @@ searchpathfuncs_t *FS_OpenPackByExtension(vfsfile_t *f, const char *pakname) continue; if (!strcmp(ext, searchpathformats[j].extension)) { - pak = searchpathformats[j].OpenNew(f, pakname, ""); + pak = searchpathformats[j].OpenNew(f, parent, filename, pakname, ""); if (pak) return pak; Con_Printf("Unable to open %s - corrupt?\n", pakname); @@ -2475,7 +2475,7 @@ void FS_AddHashedPackage(searchpath_t **oldpaths, const char *parentpath, const } if (vfs) - handle = searchpathformats[fmt].OpenNew (vfs, lname, pakprefix?pakprefix:""); + handle = searchpathformats[fmt].OpenNew (vfs, search?search->handle:NULL, pakpath, lname, pakprefix?pakprefix:""); if (!handle && vfs) VFS_CLOSE(vfs); //erk } @@ -2538,6 +2538,7 @@ static void FS_AddDataFiles(searchpath_t **oldpaths, const char *purepath, const char pakfile[MAX_OSPATH]; char logicalpaths[MAX_OSPATH]; //with a slash char purefile[MAX_OSPATH]; + char logicalfile[MAX_OSPATH]; unsigned int keptflags; vfsfile_t *vfs; flocation_t loc; @@ -2605,27 +2606,27 @@ static void FS_AddDataFiles(searchpath_t **oldpaths, const char *purepath, const if (!search->handle->FindFile(search->handle, &loc, pakfile, NULL)) break; //not found.. - snprintf (pakfile, sizeof(pakfile), "%spak%i.%s", logicalpaths, i, extension); + snprintf (logicalfile, sizeof(pakfile), "%spak%i.%s", logicalpaths, i, extension); snprintf (purefile, sizeof(purefile), "%s/pak%i.%s", purepath, i, extension); for (existing = com_searchpaths; existing; existing = existing->next) { - if (!Q_strcasecmp(existing->logicalpath, pakfile)) //assumption: first member of structure is a char array + if (!Q_strcasecmp(existing->logicalpath, logicalfile)) //assumption: first member of structure is a char array break; //already loaded (base paths?) } if (!existing) { - handle = FS_GetOldPath(oldpaths, pakfile, &keptflags); + handle = FS_GetOldPath(oldpaths, logicalfile, &keptflags); if (!handle) { vfs = search->handle->OpenVFS(search->handle, &loc, "rb"); if (!vfs) break; - handle = searchpathformats[j].OpenNew (vfs, pakfile, ""); + handle = searchpathformats[j].OpenNew (vfs, search->handle, pakfile, logicalfile, ""); if (!handle) break; } - FS_AddPathHandle(oldpaths, purefile, pakfile, handle, "", SPF_COPYPROTECTED|pflags|keptflags, (unsigned int)-1); + FS_AddPathHandle(oldpaths, purefile, logicalfile, handle, "", SPF_COPYPROTECTED|pflags|keptflags, (unsigned int)-1); } } } @@ -2790,7 +2791,7 @@ void FS_AddGameDirectory (searchpath_t **oldpaths, const char *puredir, const ch // handle = FS_GetOldPath(oldpaths, dir, &keptflags); if (!handle) - handle = VFSOS_OpenPath(NULL, dir, ""); + handle = VFSOS_OpenPath(NULL, NULL, dir, dir, ""); FS_AddPathHandle(oldpaths, puredir, dir, handle, "", flags|keptflags, loadstuff); } @@ -3332,7 +3333,7 @@ vfsfile_t *CL_OpenFileInPackage(searchpathfuncs_t *search, char *name) f = (search?search:loc.search->handle)->OpenVFS(search?search:loc.search->handle, &loc, "rb"); if (f) { - searchpathfuncs_t *newsearch = searchpathformats[i].OpenNew(f, name, ""); + searchpathfuncs_t *newsearch = searchpathformats[i].OpenNew(f, search?search:loc.search->handle, name, name, ""); if (newsearch) { f = CL_OpenFileInPackage(newsearch, end+1); @@ -3429,7 +3430,7 @@ qboolean CL_ListFilesInPackage(searchpathfuncs_t *search, char *name, int (QDECL f = (search?search:loc.search->handle)->OpenVFS(search?search:loc.search->handle, &loc, "rb"); if (f) { - searchpathfuncs_t *newsearch = searchpathformats[i].OpenNew(f, name, ""); + searchpathfuncs_t *newsearch = searchpathformats[i].OpenNew(f, search?search:loc.search->handle, name, name, ""); if (newsearch) { ret = CL_ListFilesInPackage(newsearch, end+1, func, parm, cb.nameprefix); @@ -3586,7 +3587,7 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags) const char *pakname = com_argv[i+1]; searchpathfuncs_t *pak; vfsfile_t *vfs = VFSOS_Open(pakname, "rb"); - pak = FS_OpenPackByExtension(vfs, pakname); + pak = FS_OpenPackByExtension(vfs, NULL, pakname, pakname); if (pak) //logically should have SPF_EXPLICIT set, but that would give it a worse gamedir depth FS_AddPathHandle(&oldpaths, "", pakname, pak, "", SPF_COPYPROTECTED, reloadflags); i = COM_CheckNextParm ("-basepack", i); @@ -3615,7 +3616,7 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags) //paths equal to '*' actually result in loading packages without an actual gamedir. note that this does not imply that we can write anything. if (!strcmp(dir, "*")) { - searchpathfuncs_t *handle = VFSOS_OpenPath(NULL, com_gamepath, ""); + searchpathfuncs_t *handle = VFSOS_OpenPath(NULL, NULL, com_gamepath, com_gamepath, ""); searchpath_t *search = (searchpath_t*)Z_Malloc (sizeof(searchpath_t)); search->flags = 0; search->handle = handle; @@ -3814,7 +3815,7 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags) continue; if (!strcmp(ext, searchpathformats[i].extension)) { - handle = searchpathformats[i].OpenNew (vfs, local, ""); + handle = searchpathformats[i].OpenNew (vfs, NULL, local, local, ""); if (!handle) break; sp = FS_AddPathHandle(&oldpaths, pname, local, handle, "", SPF_COPYPROTECTED|SPF_UNTRUSTED|SPF_TEMPORARY, (unsigned int)-1); @@ -4670,7 +4671,7 @@ static void FS_PackageDownloaded(struct dl_download *dl) if (fspdl_extracttype == X_UNZIP || fspdl_extracttype == X_MULTIUNZIP) //if zip... { //archive - searchpathfuncs_t *archive = FSZIP_LoadArchive(VFSOS_Open(fspdl_temppath, "rb"), dl->url, ""); + searchpathfuncs_t *archive = FSZIP_LoadArchive(VFSOS_Open(fspdl_temppath, "rb"), NULL, dl->url, dl->url, ""); if (archive) { flocation_t loc; @@ -5153,7 +5154,7 @@ ftemanifest_t *FS_ReadDefaultManifest(char *newbasedir, size_t newbasedirsize, q const char *pakname = com_argv[i+1]; searchpathfuncs_t *pak; vfsfile_t *vfs = VFSOS_Open(pakname, "rb"); - pak = FS_OpenPackByExtension(vfs, pakname); + pak = FS_OpenPackByExtension(vfs, NULL, pakname, pakname); if (pak) { flocation_t loc; @@ -5665,7 +5666,7 @@ int FS_EnumerateKnownGames(qboolean (*callback)(void *usr, ftemanifest_t *man), const char *pakname = com_argv[i+1]; searchpathfuncs_t *pak; vfsfile_t *vfs = VFSOS_Open(pakname, "rb"); - pak = FS_OpenPackByExtension(vfs, pakname); + pak = FS_OpenPackByExtension(vfs, NULL, pakname, pakname); if (pak) { pak->EnumerateFiles(pak, "*.fmf", FS_EnumerateFMFs, &e); @@ -6122,14 +6123,14 @@ void COM_InitFilesystem (void) //this is at the bottom of the file to ensure these globals are not used elsewhere -extern searchpathfuncs_t *(QDECL VFSOS_OpenPath) (vfsfile_t *file, const char *desc, const char *prefix); +/*extern searchpathfuncs_t *(QDECL VFSOS_OpenPath) (vfsfile_t *file, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix); #if 1//def AVAIL_ZLIB -extern searchpathfuncs_t *(QDECL FSZIP_LoadArchive) (vfsfile_t *packhandle, const char *desc, const char *prefix); +extern searchpathfuncs_t *(QDECL FSZIP_LoadArchive) (vfsfile_t *packhandle, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix); #endif -extern searchpathfuncs_t *(QDECL FSPAK_LoadArchive) (vfsfile_t *packhandle, const char *desc, const char *prefix); +extern searchpathfuncs_t *(QDECL FSPAK_LoadArchive) (vfsfile_t *packhandle, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix); #ifdef PACKAGE_DOOMWAD -extern searchpathfuncs_t *(QDECL FSDWD_LoadArchive) (vfsfile_t *packhandle, const char *desc, const char *prefix); -#endif +extern searchpathfuncs_t *(QDECL FSDWD_LoadArchive) (vfsfile_t *packhandle, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix); +#endif*/ void FS_RegisterDefaultFileSystems(void) { #ifdef PACKAGE_DZIP diff --git a/engine/common/fs.h b/engine/common/fs.h index 1eb59131..a9ead967 100644 --- a/engine/common/fs.h +++ b/engine/common/fs.h @@ -57,15 +57,15 @@ struct searchpathfuncs_s //the stdio filesystem is special as that's the starting point of the entire filesystem //warning: the handle is known to be a string pointer to the dir name -extern searchpathfuncs_t *(QDECL VFSOS_OpenPath) (vfsfile_t *file, const char *desc, const char *prefix); -extern searchpathfuncs_t *(QDECL FSZIP_LoadArchive) (vfsfile_t *packhandle, const char *desc, const char *prefix); -extern searchpathfuncs_t *(QDECL FSPAK_LoadArchive) (vfsfile_t *packhandle, const char *desc, const char *prefix); -extern searchpathfuncs_t *(QDECL FSDWD_LoadArchive) (vfsfile_t *packhandle, const char *desc, const char *prefix); -extern searchpathfuncs_t *(QDECL FSDZ_LoadArchive) (vfsfile_t *file, const char *desc, const char *prefix); +extern searchpathfuncs_t *(QDECL VFSOS_OpenPath) (vfsfile_t *file, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix); +extern searchpathfuncs_t *(QDECL FSZIP_LoadArchive) (vfsfile_t *file, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix); +extern searchpathfuncs_t *(QDECL FSPAK_LoadArchive) (vfsfile_t *file, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix); +extern searchpathfuncs_t *(QDECL FSDWD_LoadArchive) (vfsfile_t *file, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix); +extern searchpathfuncs_t *(QDECL FSDZ_LoadArchive) (vfsfile_t *file, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix); vfsfile_t *QDECL VFSOS_Open(const char *osname, const char *mode); vfsfile_t *FS_DecompressGZip(vfsfile_t *infile, vfsfile_t *outfile); -int FS_RegisterFileSystemType(void *module, const char *extension, searchpathfuncs_t *(QDECL *OpenNew)(vfsfile_t *file, const char *desc, const char *prefix), qboolean loadscan); +int FS_RegisterFileSystemType(void *module, const char *extension, searchpathfuncs_t *(QDECL *OpenNew)(vfsfile_t *file, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix), qboolean loadscan); void FS_UnRegisterFileSystemType(int idx); void FS_UnRegisterFileSystemModule(void *module); diff --git a/engine/common/fs_dzip.c b/engine/common/fs_dzip.c index d706f197..356a1769 100644 --- a/engine/common/fs_dzip.c +++ b/engine/common/fs_dzip.c @@ -1352,7 +1352,7 @@ Loads the header and directory, adding the files at the beginning of the list so they override previous pack files. ================= */ -searchpathfuncs_t *QDECL FSDZ_LoadArchive (vfsfile_t *file, const char *desc, const char *prefix) +searchpathfuncs_t *QDECL FSDZ_LoadArchive (vfsfile_t *file, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix) { dpackheader_t header; int i; diff --git a/engine/common/fs_pak.c b/engine/common/fs_pak.c index f667f93c..e639ba4a 100644 --- a/engine/common/fs_pak.c +++ b/engine/common/fs_pak.c @@ -309,7 +309,7 @@ Loads the header and directory, adding the files at the beginning of the list so they override previous pack files. ================= */ -searchpathfuncs_t *QDECL FSPAK_LoadArchive (vfsfile_t *file, const char *desc, const char *prefix) +searchpathfuncs_t *QDECL FSPAK_LoadArchive (vfsfile_t *file, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix) { dpackheader_t header; int i; diff --git a/engine/common/fs_stdio.c b/engine/common/fs_stdio.c index 99dd5786..5e98f2ea 100644 --- a/engine/common/fs_stdio.c +++ b/engine/common/fs_stdio.c @@ -336,7 +336,7 @@ static qboolean QDECL FSSTDIO_FileStat (searchpathfuncs_t *handle, flocation_t * } -searchpathfuncs_t *QDECL FSSTDIO_OpenPath(vfsfile_t *mustbenull, const char *desc, const char *prefix) +searchpathfuncs_t *QDECL FSSTDIO_OpenPath(vfsfile_t *mustbenull, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix) { stdiopath_t *np; int dlen = strlen(desc); diff --git a/engine/common/fs_win32.c b/engine/common/fs_win32.c index 2c809987..86dd017b 100644 --- a/engine/common/fs_win32.c +++ b/engine/common/fs_win32.c @@ -226,6 +226,8 @@ static int QDECL VFSW32_ReadBytes (struct vfsfile_s *file, void *buffer, int byt { if (intfile->offset+bytestoread > intfile->length) bytestoread = intfile->length-intfile->offset; + if (bytestoread < 0) + bytestoread = 0; //shouldn't happen... memcpy(buffer, (char*)intfile->mmap + intfile->offset, bytestoread); intfile->offset += bytestoread; @@ -327,6 +329,7 @@ static vfsfile_t *QDECL VFSW32_OpenInternal(vfsw32path_t *handle, const char *qu qboolean write = !!strchr(mode, 'w'); qboolean append = !!strchr(mode, 'a'); qboolean text = !!strchr(mode, 't'); + //qboolean persistent = !!strchr(mode, 'p'); //save to long-term storage write |= append; create = write; if (strchr(mode, '+')) @@ -642,7 +645,7 @@ static qboolean QDECL VFSW32_MkDir(searchpathfuncs_t *handle, const char *filena return true; } -searchpathfuncs_t *QDECL VFSW32_OpenPath(vfsfile_t *mustbenull, const char *desc, const char *prefix) +searchpathfuncs_t *QDECL VFSW32_OpenPath(vfsfile_t *mustbenull, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix) { vfsw32path_t *np; int dlen = strlen(desc); diff --git a/engine/common/fs_zip.c b/engine/common/fs_zip.c index 926cbefd..8e409f35 100644 --- a/engine/common/fs_zip.c +++ b/engine/common/fs_zip.c @@ -513,6 +513,7 @@ typedef struct { fsbucket_t bucket; char name[MAX_QPATH]; + unsigned int disknum; qofs_t localpos; //location of local header qofs_t filelen; //uncompressed size time_t mtime; @@ -522,7 +523,7 @@ typedef struct #define ZFL_DEFLATED 1 //need to use zlib #define ZFL_STORED 2 //direct access is okay #define ZFL_SYMLINK 4 //file is a symlink -#define ZFL_CORRUPT 8 //file is corrupt or otherwise unreadable. +#define ZFL_CORRUPT 8 //file is corrupt or otherwise unreadable (usually just means we don't support reading it rather than actually corrupt, but hey). #define ZFL_WEAKENCRYPT 16 //traditional zip encryption @@ -534,6 +535,12 @@ typedef struct zipfile_s unsigned int numfiles; zpackfile_t *files; + //spanned zips are weird. + //the starting zip is usually the last one, but should be null to simplify ref tracking. + unsigned int thisdisk; + unsigned int numspans; + struct zipfile_s **spans; + //info about the underlying file void *mutex; qofs_t curpos; //cache position to avoid excess seeks @@ -555,6 +562,7 @@ static void QDECL FSZIP_GetPathDetails(searchpathfuncs_t *handle, char *out, siz } static void QDECL FSZIP_ClosePath(searchpathfuncs_t *handle) { + size_t s; qboolean stillopen; zipfile_t *zip = (void*)handle; @@ -566,6 +574,15 @@ static void QDECL FSZIP_ClosePath(searchpathfuncs_t *handle) return; //not free yet VFS_CLOSE(zip->raw); + for (s = 0; s < zip->numspans; s++) + { + if (zip->spans[s]) + { + zip->spans[s]->pub.ClosePath(&zip->spans[s]->pub); + zip->spans[s] = NULL; + } + } + Z_Free(zip->spans); Sys_DestroyMutex(zip->mutex); if (zip->files) Z_Free(zip->files); @@ -1074,6 +1091,22 @@ static vfsfile_t *QDECL FSZIP_OpenVFS(searchpathfuncs_t *handle, flocation_t *lo if (flags & ZFL_CORRUPT) return NULL; + if (zip->thisdisk != pf->disknum) + { + if (pf->disknum >= zip->numspans) + { + Con_Printf("file %s has oob disk number\n", pf->name); + return NULL; + } + zip = zip->spans[pf->disknum]; + if (!zip) + { + zip = (void*)handle; + Con_Printf("spanned zip %s lacks segment %u for file %s\n", zip->filename, pf->disknum+1, pf->name); + return NULL; + } + } + vfsz = Z_Malloc(sizeof(vfszip_t)); vfsz->parent = zip; @@ -1093,6 +1126,7 @@ static vfsfile_t *QDECL FSZIP_OpenVFS(searchpathfuncs_t *handle, flocation_t *lo if (!FSZIP_ValidateLocalHeader(zip, pf, &vfsz->startpos, &datasize)) { + Con_Printf("file %s:%s is incompatible or inconsistent with zip central directory\n", zip->filename, pf->name); Z_Free(vfsz); return NULL; } @@ -1152,6 +1186,11 @@ static vfsfile_t *QDECL FSZIP_OpenVFS(searchpathfuncs_t *handle, flocation_t *lo //infozip utf-8 name override. //other 'extra' fields. +//split archives: +//central directory must be stored exclusively inside the initial zip. +//files on other parts will fail to load. +//individual files must not be split over files + struct zipinfo { unsigned int thisdisk; //this disk number @@ -1164,7 +1203,7 @@ struct zipinfo unsigned int zip64_centraldirend_disk; //zip64 weirdness qofs_t zip64_centraldirend_offset; - unsigned int zip64_diskcount; + unsigned int diskcount; qofs_t zip64_eocdsize; unsigned short zip64_version_madeby; unsigned short zip64_version_needed; @@ -1315,7 +1354,7 @@ static qboolean FSZIP_ValidateLocalHeader(zipfile_t *zip, zpackfile_t *zfile, qo } localstart += local.extra_len; *datastart = localstart; //this is the end of the local block, and the start of the data block (well, actually, should be encryption, but we don't support that). - *datasize = local.csize; + *datasize = local.csize; //FIXME: this is often masked. use the central directory's value instead. if (local.gpflags & (1u<<3)) { @@ -1333,6 +1372,9 @@ static qboolean FSZIP_ValidateLocalHeader(zipfile_t *zip, zpackfile_t *zfile, qo //FIXME: with pure paths, we still don't bother checking the crc (again, would require decompressing the entire file in advance). + if (localstart+local.csize > zip->rawsize) + return false; //FIXME: proper spanned zips fragment compressed data over multiple spans, but we don't support that + if (local.cmethod == 0) return (zfile->flags & (ZFL_STORED|ZFL_CORRUPT|ZFL_DEFLATED)) == ZFL_STORED; if (local.cmethod == 8) @@ -1342,6 +1384,7 @@ static qboolean FSZIP_ValidateLocalHeader(zipfile_t *zip, zpackfile_t *zfile, qo static qboolean FSZIP_ReadCentralEntry(zipfile_t *zip, qbyte *data, struct zipcentralentry *entry) { + struct tm t; entry->flags = 0; entry->fname = ""; entry->fnane_len = 0; @@ -1375,7 +1418,14 @@ static qboolean FSZIP_ReadCentralEntry(zipfile_t *zip, qbyte *data, struct zipce entry->fname = data+entry->cesize; entry->cesize += entry->fnane_len; - entry->mtime = 0; + memset(&t, 0, sizeof(t)); + t.tm_mday = (entry->lastmodfiledate&0x001f)>>0; + t.tm_mon = (entry->lastmodfiledate&0x01e0)>>5; + t.tm_year = ((entry->lastmodfiledate&0xfe00)>>9) + (1980 - 1900); + t.tm_sec = ((entry->lastmodfiletime&0x001f)>>0)*2; + t.tm_min = (entry->lastmodfiletime&0x07e0)>>5; + t.tm_hour = (entry->lastmodfiletime&0xf800)>>11; + entry->mtime = mktime(&t); //parse extra if (entry->extra_len) @@ -1553,6 +1603,7 @@ static qboolean FSZIP_EnumerateCentralDirectory(zipfile_t *zip, struct zipinfo * if (!FSZIP_ReadCentralEntry(zip, centraldir+ofs, &entry) || ofs + entry.cesize > info->centraldir_size) break; + f->disknum = entry.disknum; f->crc = entry.crc32; //copy out the filename and lowercase it @@ -1662,6 +1713,8 @@ static qboolean FSZIP_FindEndCentralDirectory(zipfile_t *zip, struct zipinfo *in info->centraldir_offset = LittleU4FromPtr(magic+16); info->commentlength = LittleU2FromPtr(magic+20); + info->diskcount = info->thisdisk+1; //zips are normally opened via the last file. + result = true; break; } @@ -1685,13 +1738,7 @@ static qboolean FSZIP_FindEndCentralDirectory(zipfile_t *zip, struct zipinfo *in info->zip64_centraldirend_disk = LittleU4FromPtr(magic+4); info->zip64_centraldirend_offset = LittleU8FromPtr(magic+8); - info->zip64_diskcount = LittleU4FromPtr(magic+16); - - if (info->zip64_diskcount != 1 || info->zip64_centraldirend_disk != 0) - { - Con_Printf("zip: archive is spanned\n"); - return false; - } + info->diskcount = LittleU4FromPtr(magic+16); VFS_SEEK(zip->raw, info->zip64_centraldirend_offset); VFS_READ(zip->raw, z64eocd, sizeof(z64eocd)); @@ -1730,11 +1777,17 @@ static qboolean FSZIP_FindEndCentralDirectory(zipfile_t *zip, struct zipinfo *in result = false; } + if (info->diskcount < 1 || info->zip64_centraldirend_disk != info->thisdisk) + { + Con_Printf("zip: archive is spanned\n"); + return false; + } + break; } } - if (info->thisdisk || info->centraldir_startdisk || info->centraldir_numfiles_disk != info->centraldir_numfiles_all) + if (info->thisdisk != info->centraldir_startdisk || info->centraldir_numfiles_disk != info->centraldir_numfiles_all) { Con_Printf("zip: archive is spanned\n"); result = false; @@ -1758,7 +1811,7 @@ Loads the header and directory, adding the files at the beginning of the list so they override previous pack files. ================= */ -searchpathfuncs_t *QDECL FSZIP_LoadArchive (vfsfile_t *packhandle, const char *desc, const char *prefix) +searchpathfuncs_t *QDECL FSZIP_LoadArchive (vfsfile_t *packhandle, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix) { zipfile_t *zip; struct zipinfo info; @@ -1788,7 +1841,7 @@ searchpathfuncs_t *QDECL FSZIP_LoadArchive (vfsfile_t *packhandle, const char *d } //now read it. - if (!FSZIP_EnumerateCentralDirectory(zip, &info, prefix) && !info.zip64_diskcount) + if (!FSZIP_EnumerateCentralDirectory(zip, &info, prefix)) { //uh oh... the central directory wasn't where it was meant to be! //assuming that the endofcentraldir is packed at the true end of the centraldir (and that we're not zip64 and thus don't have an extra block), then we can guess based upon the offset difference @@ -1801,6 +1854,54 @@ searchpathfuncs_t *QDECL FSZIP_LoadArchive (vfsfile_t *packhandle, const char *d } } + zip->thisdisk = info.thisdisk; + if (info.diskcount > 1) + { + if (parent && filename) + { + zipfile_t *szip; + unsigned int s; + flocation_t loc; + char splitname[MAX_OSPATH]; + char *ext; + zip->numspans = info.diskcount; + zip->spans = Z_Malloc(info.diskcount*sizeof(*zip->spans)); + for(s = 0; s < zip->numspans; s++) + { + if (info.thisdisk == s) + continue; //would be weird. + + Q_strncpyz(splitname, filename, sizeof(splitname)); + ext = strrchr(splitname, '.'); + if (ext) + { + ext++; + if (*ext) + ext++; //skip the first letter of the extension + } + else + ext = splitname + strlen(splitname); + Q_snprintfz(ext, sizeof(splitname)-(ext-splitname), *ext?"%02u":"%03u", s+1); + if (parent->FindFile(parent, &loc, splitname, NULL) != FF_FOUND) + continue; + packhandle = parent->OpenVFS(parent, &loc, "rb"); + if (!packhandle) + continue; + + zip->spans[s] = szip = Z_Malloc(sizeof(zipfile_t)); + szip->thisdisk = s; + Q_strncpyz(szip->filename, splitname, sizeof(szip->filename)); + szip->raw = packhandle; + szip->rawsize = VFS_GETLEN(szip->raw); + szip->references = 1; + szip->mutex = Sys_CreateMutex(); + szip->pub.ClosePath = FSZIP_ClosePath; + } + } + else + Con_TPrintf ("spanned zip \"%s\" with no path info\n", desc); + } + zip->references = 1; zip->mutex = Sys_CreateMutex(); diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index 90ca2e2e..0d200a7b 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -2227,6 +2227,7 @@ static qboolean CModQ3_LoadVertexes (model_t *mod, qbyte *mod_base, lump_t *l) int i, count, j; vec2_t *lmout, *stout; vec4_t *cout; + extern cvar_t gl_overbright; extern qbyte lmgamma[256]; in = (void *)(mod_base + l->fileofs); @@ -2243,6 +2244,8 @@ static qboolean CModQ3_LoadVertexes (model_t *mod, qbyte *mod_base, lump_t *l) return false; } + BuildLightMapGammaTable(1, 1<<(2-gl_overbright.ival)); + out = ZG_Malloc(&mod->memgroup, count*sizeof(*out)); stout = ZG_Malloc(&mod->memgroup, count*sizeof(*stout)); lmout = ZG_Malloc(&mod->memgroup, count*sizeof(*lmout)); @@ -2274,9 +2277,9 @@ static qboolean CModQ3_LoadVertexes (model_t *mod, qbyte *mod_base, lump_t *l) stout[i][j] = LittleFloat ( ((float *)in->texcoords)[j] ); lmout[i][j] = LittleFloat ( ((float *)in->texcoords)[j+2] ); } - cout[i][0] = lmgamma[in->color[0]]/255.0f; - cout[i][1] = lmgamma[in->color[1]]/255.0f; - cout[i][2] = lmgamma[in->color[2]]/255.0f; + cout[i][0] = (lmgamma[in->color[0]]<color[1]]<color[2]]<color[3]/255.0f; } @@ -3490,7 +3493,7 @@ static void CModQ3_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l) extern cvar_t gl_overbright; extern qbyte lmgamma[256]; - loadmodel->engineflags &= ~MDLF_RGBLIGHTING; + loadmodel->lightmaps.fmt = LM_L8; //round up the samples, in case the last one is partial. maps = ((samples+mapsize-1)&~(mapsize-1)) / mapsize; @@ -3506,7 +3509,7 @@ static void CModQ3_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l) loadmodel->engineflags |= MDLF_NEEDOVERBRIGHT; - loadmodel->engineflags |= MDLF_RGBLIGHTING; + loadmodel->lightmaps.fmt = LM_RGB8; if (loadmodel->lightmaps.deluxemapping) maps /= 2; @@ -4125,6 +4128,7 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole //q3 maps have built in 4-fold overbright. //if we're not rendering with that, we need to brighten the lightmaps in order to keep the darker parts the same brightness. we loose the 2 upper bits. those bright areas become uniform and indistinct. //this is used for both the lightmap AND vertex lighting + //FIXME: when not using overbrights, we suffer a loss of precision. gl_overbright.flags |= CVAR_RENDERERLATCH; BuildLightMapGammaTable(1, (1<<(2-gl_overbright.ival))); diff --git a/engine/common/mathlib.h b/engine/common/mathlib.h index f0f20654..3288497a 100644 --- a/engine/common/mathlib.h +++ b/engine/common/mathlib.h @@ -25,6 +25,12 @@ typedef vec_t vec3_t[3]; typedef vec_t vec4_t[4]; typedef vec_t vec5_t[5]; +typedef int ivec_t; +typedef ivec_t ivec2_t[2]; +typedef ivec_t ivec3_t[3]; +typedef ivec_t ivec4_t[4]; +typedef ivec_t ivec5_t[5]; + /*16-byte aligned vectors, for auto-vectorising, should propogate to structs sse and altivec can unroll loops using aligned reads, which should be faster... 4 at once. */ diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index a8858c0d..1c9c768d 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -104,7 +104,7 @@ cvar_t net_enable_webrtcbroker = CVARD("net_enable_webrtcbroker", "1", "If 1, tc #endif #ifndef SERVERONLY -static void cl_delay_packets_Announce(cvar_t *var, char *oldval) +static void QDECL cl_delay_packets_Announce(cvar_t *var, char *oldval) { if (cls.state >= ca_connected && cl.fpd & FPD_ANOUNCE_FAKE_LAG) Cbuf_AddText(va("say Fake lag now %ims\n", var->ival), RESTRICT_LOCAL); @@ -2850,6 +2850,7 @@ qboolean FTENET_Datagram_GetPacket(ftenet_generic_connection_t *con) return false; fromlen = sizeof(from); + ((struct sockaddr*)&from)->sa_family = AF_UNSPEC; ret = recvfrom (con->thesocket, (char *)net_message_buffer, sizeof(net_message_buffer), 0, (struct sockaddr*)&from, &fromlen); if (ret == -1) @@ -2876,7 +2877,7 @@ qboolean FTENET_Datagram_GetPacket(ftenet_generic_connection_t *con) unsigned int curtime = Sys_Milliseconds(); if (curtime-resettime >= 5000 || err == NET_ECONNRESET) //throttle prints to once per 5 secs (even if they're about different clients, yay ddos) { - if (err == NET_ECONNABORTED) + if (((struct sockaddr*)&from)->sa_family != AF_UNSPEC) Con_TPrintf ("Connection lost or aborted (%s)\n", NET_AdrToString (adr, sizeof(adr), &net_from)); //server died/connection lost. else Con_TPrintf ("Connection lost or aborted\n"); //server died/connection lost. @@ -2896,8 +2897,10 @@ qboolean FTENET_Datagram_GetPacket(ftenet_generic_connection_t *con) return false; } - - Con_Printf ("NET_GetPacket: Error (%i): %s\n", err, strerror(err)); + if (((struct sockaddr*)&from)->sa_family != AF_UNSPEC) + Con_Printf ("NET_GetPacket: Error (%i): %s (%s)\n", err, strerror(err), NET_AdrToString (adr, sizeof(adr), &net_from)); + else + Con_Printf ("NET_GetPacket: Error (%i): %s\n", err, strerror(err)); return false; } SockadrToNetadr (&from, &net_from); @@ -2905,7 +2908,7 @@ qboolean FTENET_Datagram_GetPacket(ftenet_generic_connection_t *con) net_message.packing = SZ_RAWBYTES; net_message.currentbit = 0; net_message.cursize = ret; - if (net_message.cursize == sizeof(net_message_buffer) ) + if (net_message.cursize >= sizeof(net_message_buffer) ) { Con_TPrintf ("Warning: Oversize packet from %s\n", NET_AdrToString (adr, sizeof(adr), &net_from)); return false; diff --git a/engine/common/plugin.c b/engine/common/plugin.c index aa0d4a2d..5982df6c 100644 --- a/engine/common/plugin.c +++ b/engine/common/plugin.c @@ -1234,8 +1234,8 @@ qintptr_t VARGS Plug_FS_Open(void *offset, quintptr_t mask, const qintptr_t *arg } qintptr_t VARGS Plug_FS_Seek(void *offset, quintptr_t mask, const qintptr_t *arg) { - unsigned int handle = arg[0]; - unsigned int low = arg[1], high = arg[2]; + unsigned int handle = VM_LONG(arg[0]); + unsigned int low = VM_LONG(arg[1]), high = VM_LONG(arg[2]); pluginstream_t *stream; if (handle >= pluginstreamarraylen) @@ -1249,7 +1249,7 @@ qintptr_t VARGS Plug_FS_Seek(void *offset, quintptr_t mask, const qintptr_t *arg qintptr_t VARGS Plug_FS_GetLength(void *offset, quintptr_t mask, const qintptr_t *arg) { - unsigned int handle = arg[0]; + unsigned int handle = VM_LONG(arg[0]); unsigned int *low = VM_POINTER(arg[1]), *high = VM_POINTER(arg[2]); pluginstream_t *stream; qofs_t size; diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 3d876c34..ba17fbce 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -6359,27 +6359,25 @@ void PR_ProgsAdded(pubprogfuncs_t *prinst, int newprogs, const char *modulename) extern cvar_t language; if (!prinst || newprogs < 0) return; - if (*language.string) + + Q_strncpyz(lang, language.string, sizeof(lang)); + while ((h = strchr(lang, '-'))) + *h = '_'; + for(;;) { - Q_strncpyz(lang, language.string, sizeof(lang)); - while ((h = strchr(lang, '-'))) - *h = '_'; - for(;;) - { - if (!*lang) - break; - if (!f) - f = FS_OpenVFS(va("%s.%s.po", modulename, lang), "rb", FS_GAME); - if (!f2) - f2 = FS_OpenVFS(va("common.%s.po", lang), "rb", FS_GAME); - if (f && f2) - break; - h = strchr(lang, '_'); - if (h) - *h = 0; - else - break; - } + if (!f) + f = FS_OpenVFS(va("%s.%s.po", modulename, *lang?lang:"default"), "rb", FS_GAME); + if (!f2) + f2 = FS_OpenVFS(va("common.%s.po", *lang?lang:"default"), "rb", FS_GAME); + if (f && f2) + break; + if (!*lang) + break; + h = strchr(lang, '_'); + if (h) + *h = 0; + else + break; } if (f || f2) diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index fa1233bc..0e0677b5 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -247,6 +247,7 @@ void QCBUILTIN PF_setattachment(pubprogfuncs_t *prinst, struct globalvars_s *pr_ void QCBUILTIN PF_skel_ragedit(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_skel_create (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_skel_build (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); + void QCBUILTIN PF_skel_build_ptr (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_skel_get_numbones (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_skel_get_bonename (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_skel_get_boneparent (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); diff --git a/engine/common/protocol.h b/engine/common/protocol.h index 4a94163b..30431f58 100644 --- a/engine/common/protocol.h +++ b/engine/common/protocol.h @@ -1330,8 +1330,9 @@ typedef struct q1usercmd_s #define RDF_CUSTOMPOSTPROC (1u<<19) #define RDF_ANTIALIAS (1u<<20) //fxaa, or possibly even just fsaa #define RDF_RENDERSCALE (1u<<21) +#define RDF_SCENEGAMMA (1u<<22) -#define RDF_ALLPOSTPROC (RDF_BLOOM|RDF_FISHEYE|RDF_WATERWARP|RDF_CUSTOMPOSTPROC|RDF_ANTIALIAS) //these flags require rendering to an fbo for the various different post-processing shaders. +#define RDF_ALLPOSTPROC (RDF_BLOOM|RDF_FISHEYE|RDF_WATERWARP|RDF_CUSTOMPOSTPROC|RDF_ANTIALIAS|RDF_SCENEGAMMA) //these flags require rendering to an fbo for the various different post-processing shaders. diff --git a/engine/common/qvm.c b/engine/common/qvm.c index cc75593d..3a5828dc 100644 --- a/engine/common/qvm.c +++ b/engine/common/qvm.c @@ -67,7 +67,7 @@ struct vm_s { void *hInst; // native - qintptr_t (EXPORT_FN *vmMain)(qintptr_t command, qintptr_t arg0, qintptr_t arg1, qintptr_t arg2, qintptr_t arg3, qintptr_t arg4, qintptr_t arg5, qintptr_t arg6); + qintptr_t (EXPORT_FN *vmMain)(qintptr_t command, qintptr_t arg0, qintptr_t arg1, qintptr_t arg2, qintptr_t arg3, qintptr_t arg4, qintptr_t arg5, qintptr_t arg6, qintptr_t arg7); }; //this is a bit weird. qvm plugins always come from $basedir/$mod/plugins/$foo.qvm @@ -1143,7 +1143,7 @@ qintptr_t VARGS VM_Call(vm_t *vm, qintptr_t instruction, ...) switch(vm->type) { case VM_NATIVE: - return vm->vmMain(instruction, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6]); + return vm->vmMain(instruction, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7]); case VM_BYTECODE: return QVM_ExecVM(vm->hInst, instruction, arg[0]&0xffffffff, arg[1]&0xffffffff, arg[2]&0xffffffff, arg[3]&0xffffffff, arg[4]&0xffffffff, arg[5]&0xffffffff, arg[6]&0xffffffff, arg[7]&0xffffffff); diff --git a/engine/d3d/d3d11_backend.c b/engine/d3d/d3d11_backend.c index 7ee6dfdd..8b148e91 100644 --- a/engine/d3d/d3d11_backend.c +++ b/engine/d3d/d3d11_backend.c @@ -13,7 +13,7 @@ extern ID3D11DepthStencilView *fb_backdepthstencil; extern cvar_t r_shadow_realtime_world_lightmaps; extern cvar_t gl_overbright; -extern cvar_t r_portalrecursion; +extern cvar_t r_portalrecursion, r_wireframe; extern cvar_t r_polygonoffset_shadowmap_offset, r_polygonoffset_shadowmap_factor; @@ -137,7 +137,7 @@ typedef struct vec3_t e_light_ambient; float pad1; vec3_t e_light_dir; float pad2; vec3_t e_light_mul; float pad3; -} cbuf_view_t; +} dx11_cbuf_view_t; typedef struct { @@ -147,7 +147,7 @@ typedef struct vec3_t l_lightcolourscale; float l_lightradius; vec4_t l_shadowmapproj; vec2_t l_shadowmapscale; vec2_t pad3; -} cbuf_light_t; +} dx11_cbuf_light_t; //entity-specific constant-buffer typedef struct @@ -163,7 +163,7 @@ typedef struct vec4_t e_lowercolour; vec4_t e_colourmod; vec4_t e_glowmod; -} cbuf_entity_t; +} dx11_cbuf_entity_t; //vertex attributes typedef struct @@ -175,7 +175,7 @@ typedef struct vec3_t sdir; vec3_t tdir; byte_vec4_t colorsb; -} vbovdata_t; +} dx11_vbovdata_t; enum { @@ -794,7 +794,7 @@ void D3D11BE_Init(void) for (i = 0; i < NUMECBUFFERS; i++) { bd.Usage = D3D11_USAGE_DYNAMIC; - bd.ByteWidth = sizeof(cbuf_entity_t); + bd.ByteWidth = sizeof(dx11_cbuf_entity_t); bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; bd.MiscFlags = 0; @@ -803,7 +803,7 @@ void D3D11BE_Init(void) return; } bd.Usage = D3D11_USAGE_DYNAMIC; - bd.ByteWidth = sizeof(cbuf_view_t); + bd.ByteWidth = sizeof(dx11_cbuf_view_t); bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; bd.MiscFlags = 0; @@ -812,7 +812,7 @@ void D3D11BE_Init(void) return; bd.Usage = D3D11_USAGE_DYNAMIC; - bd.ByteWidth = sizeof(cbuf_light_t); + bd.ByteWidth = sizeof(dx11_cbuf_light_t); bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; bd.MiscFlags = 0; @@ -1006,19 +1006,19 @@ static texid_t T_Gen_CurrentRender(void) { if (!shaderstate.currentrender) shaderstate.currentrender = Image_CreateTexture("***$currentrender***", NULL, 0); - if (!shaderstate.currentrender) - return r_nulltex; //err + if (shaderstate.currentrender) + { + shaderstate.currentrender->width = tdesc.Width; + shaderstate.currentrender->height = tdesc.Height; - shaderstate.currentrender->width = tdesc.Width; - shaderstate.currentrender->height = tdesc.Height; + tdesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; + tdesc.CPUAccessFlags = 0; - tdesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; - tdesc.CPUAccessFlags = 0; - - if (shaderstate.currentrender->ptr) - ID3D11Texture2D_Release((ID3D11Texture2D*)shaderstate.currentrender->ptr); - shaderstate.currentrender->ptr = NULL; - ID3D11Device_CreateTexture2D(pD3DDev11, &tdesc, NULL, (ID3D11Texture2D**)&shaderstate.currentrender->ptr); + if (shaderstate.currentrender->ptr) + ID3D11Texture2D_Release((ID3D11Texture2D*)shaderstate.currentrender->ptr); + shaderstate.currentrender->ptr = NULL; + ID3D11Device_CreateTexture2D(pD3DDev11, &tdesc, NULL, (ID3D11Texture2D**)&shaderstate.currentrender->ptr); + } } ID3D11DeviceContext_CopyResource(d3ddevctx, (ID3D11Resource*)shaderstate.currentrender->ptr, (ID3D11Resource*)backbuf); @@ -1026,6 +1026,8 @@ static texid_t T_Gen_CurrentRender(void) ID3D11ShaderResourceView_Release((ID3D11ShaderResourceView*)shaderstate.currentrender->ptr2); shaderstate.currentrender->ptr2 = NULL; + ID3D11Texture2D_Release(backbuf); + return shaderstate.currentrender; } @@ -1470,7 +1472,7 @@ static void BE_GenerateColourMods(unsigned int vertcount, const shaderpass_t *pa { shaderstate.stream_buffer[D3D11_BUFF_COL] = shaderstate.batchvbo->colours[0].d3d.buff; shaderstate.stream_offset[D3D11_BUFF_COL] = shaderstate.batchvbo->colours[0].d3d.offs; - shaderstate.stream_stride[D3D11_BUFF_COL] = sizeof(vbovdata_t); + shaderstate.stream_stride[D3D11_BUFF_COL] = sizeof(dx11_vbovdata_t); shaderstate.stream_rgbaf = false; } else @@ -1989,6 +1991,10 @@ static void D3D11BE_Cull(unsigned int cullflags, int depthbias, float depthfacto else if (cullflags) cullflags ^= r_refdef.flipcull; +#define SHADER_CULL_WIREFRAME SHADER_NODRAW //borrow a flag... + if (shaderstate.mode == BEM_WIREFRAME) + cullflags |= SHADER_CULL_WIREFRAME; + if (shaderstate.curcull != cullflags || shaderstate.depthbias != depthbias || shaderstate.depthfactor != depthfactor) { shaderstate.curcull = cullflags; @@ -2022,7 +2028,7 @@ static void D3D11BE_Cull(unsigned int cullflags, int depthbias, float depthfacto rasterdesc.SlopeScaledDepthBias = shaderstate.depthfactor; rasterdesc.DepthBiasClamp = 0.0f; rasterdesc.DepthClipEnable = true; - rasterdesc.FillMode = 0?D3D11_FILL_WIREFRAME:D3D11_FILL_SOLID; + rasterdesc.FillMode = (shaderstate.curcull&SHADER_CULL_WIREFRAME)?D3D11_FILL_WIREFRAME:D3D11_FILL_SOLID; rasterdesc.FrontCounterClockwise = false; rasterdesc.MultisampleEnable = false; rasterdesc.ScissorEnable = true; @@ -2091,6 +2097,15 @@ static void BE_DrawMeshChain_Internal(void) case BEM_STANDARD: altshader = shaderstate.curshader; break; + case BEM_WIREFRAME: + altshader = R_RegisterShader("wireframe", SUF_NONE, + "{\n" + "{\n" + "map $whiteimage\n" + "}\n" + "}\n" + ); + break; } if (!altshader) return; @@ -2193,7 +2208,7 @@ static void BE_DrawMeshChain_Internal(void) { shaderstate.stream_buffer[D3D11_BUFF_POS] = shaderstate.batchvbo->coord.d3d.buff; shaderstate.stream_offset[D3D11_BUFF_POS] = shaderstate.batchvbo->coord.d3d.offs; - shaderstate.stream_stride[D3D11_BUFF_POS] = sizeof(vbovdata_t); + shaderstate.stream_stride[D3D11_BUFF_POS] = sizeof(dx11_vbovdata_t); } else { @@ -2262,17 +2277,17 @@ static void BE_DrawMeshChain_Internal(void) { shaderstate.stream_buffer[D3D11_BUFF_COL] = shaderstate.batchvbo->colours[0].d3d.buff; shaderstate.stream_offset[D3D11_BUFF_COL] = shaderstate.batchvbo->colours[0].d3d.offs; - shaderstate.stream_stride[D3D11_BUFF_COL] = sizeof(vbovdata_t); + shaderstate.stream_stride[D3D11_BUFF_COL] = sizeof(dx11_vbovdata_t); shaderstate.stream_rgbaf = false; shaderstate.stream_buffer[D3D11_BUFF_TC] = shaderstate.batchvbo->texcoord.d3d.buff; shaderstate.stream_offset[D3D11_BUFF_TC] = shaderstate.batchvbo->texcoord.d3d.offs; - shaderstate.stream_stride[D3D11_BUFF_TC] = sizeof(vbovdata_t); + shaderstate.stream_stride[D3D11_BUFF_TC] = sizeof(dx11_vbovdata_t); shaderstate.stream_buffer[D3D11_BUFF_LMTC] = shaderstate.batchvbo->lmcoord[0].d3d.buff; shaderstate.stream_offset[D3D11_BUFF_LMTC] = shaderstate.batchvbo->lmcoord[0].d3d.offs; - shaderstate.stream_stride[D3D11_BUFF_LMTC] = sizeof(vbovdata_t); + shaderstate.stream_stride[D3D11_BUFF_LMTC] = sizeof(dx11_vbovdata_t); shaderstate.stream_buffer[D3D11_BUFF_NORM] = shaderstate.batchvbo->normals.d3d.buff; shaderstate.stream_offset[D3D11_BUFF_NORM] = shaderstate.batchvbo->normals.d3d.offs; - shaderstate.stream_stride[D3D11_BUFF_NORM] = sizeof(vbovdata_t); + shaderstate.stream_stride[D3D11_BUFF_NORM] = sizeof(dx11_vbovdata_t); } else { @@ -2398,13 +2413,13 @@ static void BE_DrawMeshChain_Internal(void) { shaderstate.stream_buffer[D3D11_BUFF_TC] = shaderstate.batchvbo->lmcoord[0].d3d.buff; shaderstate.stream_offset[D3D11_BUFF_TC] = shaderstate.batchvbo->lmcoord[0].d3d.offs; - shaderstate.stream_stride[D3D11_BUFF_TC] = sizeof(vbovdata_t); + shaderstate.stream_stride[D3D11_BUFF_TC] = sizeof(dx11_vbovdata_t); } else if (p->tcgen == TC_GEN_BASE) { shaderstate.stream_buffer[D3D11_BUFF_TC] = shaderstate.batchvbo->texcoord.d3d.buff; shaderstate.stream_offset[D3D11_BUFF_TC] = shaderstate.batchvbo->texcoord.d3d.offs; - shaderstate.stream_stride[D3D11_BUFF_TC] = sizeof(vbovdata_t); + shaderstate.stream_stride[D3D11_BUFF_TC] = sizeof(dx11_vbovdata_t); } else { @@ -2516,7 +2531,7 @@ void D3D11BE_GenBatchVBOs(vbo_t **vbochain, batch_t *firstbatch, batch_t *stopba ID3D11Buffer *vbuff; ID3D11Buffer *ebuff; index_t *vboedata, *vboedatastart; - vbovdata_t *vbovdata, *vbovdatastart; + dx11_vbovdata_t *vbovdata, *vbovdatastart; D3D11_BUFFER_DESC vbodesc; D3D11_BUFFER_DESC ebodesc; D3D11_SUBRESOURCE_DATA srd; @@ -2765,14 +2780,14 @@ static float projgltod3d[16] = }; static void D3D11BE_SetupViewCBuffer(void) { - cbuf_view_t *cbv; + dx11_cbuf_view_t *cbv; D3D11_MAPPED_SUBRESOURCE msr; if (FAILED(ID3D11DeviceContext_Map(d3ddevctx, (ID3D11Resource*)shaderstate.vcbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &msr))) { Con_Printf("BE_RotateForEntity: failed to map constant buffer\n"); return; } - cbv = (cbuf_view_t*)msr.pData; + cbv = (dx11_cbuf_view_t*)msr.pData; //we internally use gl-style projection matricies. //gl's viewport is based upon -1 to 1 depth. @@ -2807,14 +2822,14 @@ void D3D11BE_Set2D(void) void D3D11BE_SetupLightCBuffer(dlight_t *l, vec3_t colour) { extern cvar_t gl_specular; - cbuf_light_t *cbl; + dx11_cbuf_light_t *cbl; D3D11_MAPPED_SUBRESOURCE msr; if (FAILED(ID3D11DeviceContext_Map(d3ddevctx, (ID3D11Resource*)shaderstate.lcbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &msr))) { Con_Printf("BE_RotateForEntity: failed to map constant buffer\n"); return; } - cbl = (cbuf_light_t*)msr.pData; + cbl = (dx11_cbuf_light_t*)msr.pData; cbl->l_lightradius = l->radius; @@ -2871,7 +2886,7 @@ static void BE_RotateForEntity (const entity_t *e, const model_t *mod) float ndr; float modelinv[16]; float *m = shaderstate.m_model; - cbuf_entity_t *cbe; + dx11_cbuf_entity_t *cbe; D3D11_MAPPED_SUBRESOURCE msr; shaderstate.ecbufferidx = (shaderstate.ecbufferidx + 1) & (NUMECBUFFERS-1); if (FAILED(ID3D11DeviceContext_Map(d3ddevctx, (ID3D11Resource*)shaderstate.ecbuffers[shaderstate.ecbufferidx], 0, D3D11_MAP_WRITE_DISCARD, 0, &msr))) @@ -2879,7 +2894,7 @@ static void BE_RotateForEntity (const entity_t *e, const model_t *mod) Con_Printf("BE_RotateForEntity: failed to map constant buffer\n"); return; } - cbe = (cbuf_entity_t*)msr.pData; + cbe = (dx11_cbuf_entity_t*)msr.pData; shaderstate.curentity = e; @@ -3053,7 +3068,10 @@ static void BE_RotateForEntity (const entity_t *e, const model_t *mod) R_FetchPlayerColour(e->topcolour, cbe->e_uppercolour); R_FetchPlayerColour(e->bottomcolour, cbe->e_lowercolour); R_FetchPlayerColour(e->bottomcolour, cbe->e_colourmod); - VectorCopy(e->shaderRGBAf, cbe->e_colourmod); + if (shaderstate.flags & BEF_FORCECOLOURMOD) + Vector4Copy(e->shaderRGBAf, cbe->e_colourmod); + else + Vector4Set(cbe->e_colourmod, 1, 1, 1, e->shaderRGBAf[3]); VectorCopy(e->glowmod, cbe->e_glowmod);cbe->e_glowmod[3] = 1; //various stuff in modelspace @@ -3688,6 +3706,13 @@ void D3D11BE_DrawWorld (batch_t **worldbatches) RSpeedRemark(); D3D11BE_SubmitMeshes(worldbatches, batches, SHADER_SORT_SEETHROUGH+1, SHADER_SORT_COUNT); RSpeedEnd(RSPEED_TRANSPARENTS); + + if (r_wireframe.ival) + { + D3D11BE_SelectMode(BEM_WIREFRAME); + D3D11BE_SubmitMeshes(worldbatches, batches, SHADER_SORT_PORTAL, SHADER_SORT_NEAREST); + D3D11BE_SelectMode(BEM_STANDARD); + } } else { diff --git a/engine/d3d/d3d11_image.c b/engine/d3d/d3d11_image.c index 42b277cd..82f6303c 100644 --- a/engine/d3d/d3d11_image.c +++ b/engine/d3d/d3d11_image.c @@ -132,6 +132,7 @@ qboolean D3D11_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mi tdesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; tdesc.CPUAccessFlags = (mips->mip[0].data)?0:D3D11_CPU_ACCESS_WRITE; tdesc.MiscFlags = 0; + tdesc.Format = DXGI_FORMAT_UNKNOWN; if (tex->flags & IF_RENDERTARGET) { @@ -145,16 +146,20 @@ qboolean D3D11_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mi tdesc.ArraySize *= 6; tdesc.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE; } - else if (mips->type == PTI_3D) +// else if (mips->type == PTI_2D_ARRAY) +// { +// tdesc.ArraySize *= mips->mip[0].depth; +// } + else if (mips->type != PTI_2D) return false; //nyi //d3d11.1 formats #define DXGI_FORMAT_B4G4R4A4_UNORM 115 + //dxgi formats are expressed in little-endian bit order. byte-aligned formats are always in byte order and are thus little-endian even on big-endian machines. + //so byte aligned have the same order, while misligned need reversed order. switch(mips->encoding) { - default: - return false; case PTI_DEPTH16: tdesc.Format = DXGI_FORMAT_D16_UNORM; tdesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; @@ -174,18 +179,24 @@ qboolean D3D11_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mi case PTI_RGB565: tdesc.Format = DXGI_FORMAT_B5G6R5_UNORM; break; -// case PTI_RGBA5551: -// tdesc.Format = DXGI_FORMAT_A1B5G5R5_UNORM; -// break; case PTI_ARGB1555: tdesc.Format = DXGI_FORMAT_B5G5R5A1_UNORM; break; - case PTI_RGBA4444: - tdesc.Format = DXGI_FORMAT_B4G4R4A4_UNORM; + case PTI_RGBA5551: +// tdesc.Format = DXGI_FORMAT_A1B5G5R5_UNORM; break; -// case PTI_ARGB4444: + case PTI_ARGB4444: + tdesc.Format = DXGI_FORMAT_B4G4R4A4_UNORM; //DX11.1 + break; + case PTI_RGBA4444: // tdesc.Format = DXGI_FORMAT_A4B4G4R4_UNORM; -// break; + break; + case PTI_RGB8: +// tdesc.Format = DXGI_FORMAT_R8G8B8_UNORM; + break; + case PTI_BGR8: +// tdesc.Format = DXGI_FORMAT_B8G8R8_UNORM; + break; case PTI_RGBA8: tdesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; break; @@ -198,6 +209,12 @@ qboolean D3D11_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mi case PTI_BGRX8: tdesc.Format = DXGI_FORMAT_B8G8R8X8_UNORM; break; + case PTI_A2BGR10: //mostly for rendertargets, might also be useful for overbight lightmaps. + tdesc.Format = DXGI_FORMAT_R10G10B10A2_UNORM; + break; + case PTI_E5BGR9: + tdesc.Format = DXGI_FORMAT_R9G9B9E5_SHAREDEXP; + break; case PTI_RGBA8_SRGB: tdesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; @@ -235,19 +252,19 @@ qboolean D3D11_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mi case PTI_BC4_R8: tdesc.Format = DXGI_FORMAT_BC4_UNORM; break; - case PTI_BC4_R8_SIGNED: + case PTI_BC4_R8_SNORM: tdesc.Format = DXGI_FORMAT_BC4_SNORM; break; case PTI_BC5_RG8: tdesc.Format = DXGI_FORMAT_BC5_UNORM; break; - case PTI_BC5_RG8_SIGNED: + case PTI_BC5_RG8_SNORM: tdesc.Format = DXGI_FORMAT_BC5_SNORM; break; - case PTI_BC6_RGBF: + case PTI_BC6_RGB_UFLOAT: tdesc.Format = DXGI_FORMAT_BC6H_UF16; break; - case PTI_BC6_RGBF_SIGNED: + case PTI_BC6_RGB_SFLOAT: tdesc.Format = DXGI_FORMAT_BC6H_SF16; break; case PTI_BC7_RGBA: @@ -256,6 +273,77 @@ qboolean D3D11_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mi case PTI_BC7_RGBA_SRGB: tdesc.Format = DXGI_FORMAT_BC7_UNORM_SRGB; break; + + case PTI_RGBA16F: + tdesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; + break; + case PTI_RGBA32F: + tdesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + break; + case PTI_L8: //UNSUPPORTED + case PTI_R8: + tdesc.Format = DXGI_FORMAT_R8_UNORM; + break; + case PTI_L8A8: //UNSUPPORTED + case PTI_RG8: + tdesc.Format = DXGI_FORMAT_R8G8_UNORM; + break; + case PTI_R8_SNORM: + tdesc.Format = DXGI_FORMAT_R8_SNORM; + break; + case PTI_RG8_SNORM: + tdesc.Format = DXGI_FORMAT_R8G8_SNORM; + break; + + case PTI_ETC1_RGB8: //not invented here... + case PTI_ETC2_RGB8: + case PTI_ETC2_RGB8A1: + case PTI_ETC2_RGB8A8: + case PTI_ETC2_RGB8_SRGB: + case PTI_ETC2_RGB8A1_SRGB: + case PTI_ETC2_RGB8A8_SRGB: + case PTI_EAC_R11: + case PTI_EAC_R11_SNORM: + case PTI_EAC_RG11: + case PTI_EAC_RG11_SNORM: + case PTI_ASTC_4X4: //not invented here... + case PTI_ASTC_4X4_SRGB: + case PTI_ASTC_5X4: + case PTI_ASTC_5X4_SRGB: + case PTI_ASTC_5X5: + case PTI_ASTC_5X5_SRGB: + case PTI_ASTC_6X5: + case PTI_ASTC_6X5_SRGB: + case PTI_ASTC_6X6: + case PTI_ASTC_6X6_SRGB: + case PTI_ASTC_8X5: + case PTI_ASTC_8X5_SRGB: + case PTI_ASTC_8X6: + case PTI_ASTC_8X6_SRGB: + case PTI_ASTC_10X5: + case PTI_ASTC_10X5_SRGB: + case PTI_ASTC_10X6: + case PTI_ASTC_10X6_SRGB: + case PTI_ASTC_8X8: + case PTI_ASTC_8X8_SRGB: + case PTI_ASTC_10X8: + case PTI_ASTC_10X8_SRGB: + case PTI_ASTC_10X10: + case PTI_ASTC_10X10_SRGB: + case PTI_ASTC_12X10: + case PTI_ASTC_12X10_SRGB: + case PTI_ASTC_12X12: + case PTI_ASTC_12X12_SRGB: +#ifdef FTE_TARGET_WEB + case PTI_WHOLEFILE: //basically webgl only... +#endif + case PTI_MAX: //not actually valid... + case PTI_EMULATED: //not hardware-compatible. + break; + } + if (tdesc.Format == DXGI_FORMAT_UNKNOWN) + { + return false; } Image_BlockSizeForEncoding(mips->encoding, &blockbytes, &blockwidth, &blockheight); @@ -284,13 +372,13 @@ qboolean D3D11_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mi } void D3D11_UploadLightmap(lightmapinfo_t *lm) { - extern cvar_t gl_lightmap_nearest; + extern cvar_t r_lightmap_nearest; struct pendingtextureinfo mips; image_t *tex; lm->modified = false; if (!TEXVALID(lm->lightmap_texture)) { - lm->lightmap_texture = Image_CreateTexture("***lightmap***", NULL, (gl_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR)); + lm->lightmap_texture = Image_CreateTexture("***lightmap***", NULL, (r_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR)); if (!lm->lightmap_texture) return; } @@ -305,15 +393,22 @@ void D3D11_UploadLightmap(lightmapinfo_t *lm) mips.mip[0].datasize = lm->width*lm->height*4; switch (lightmap_fmt) { - case TF_BGRA32: + default: + case PTI_A2BGR10: + case PTI_E5BGR9: + case PTI_RGBA16F: + case PTI_RGBA32F: + mips.encoding = lightmap_fmt; + break; + case PTI_BGRA8: mips.encoding = PTI_BGRX8; break; - case TF_RGBA32: + case PTI_RGBA8: mips.encoding = PTI_RGBX8; break; - default: - Sys_Error("D3D11_UploadLightmap: Unsupported format"); - return; + case PTI_L8: + mips.encoding = PTI_R8; //FIXME: unspported + break; } mips.mipcount = 1; D3D11_LoadTextureMips(tex, &mips); diff --git a/engine/d3d/d3d8_backend.c b/engine/d3d/d3d8_backend.c index ee8dec19..f7c57ba2 100644 --- a/engine/d3d/d3d8_backend.c +++ b/engine/d3d/d3d8_backend.c @@ -454,9 +454,6 @@ void D3D8BE_Reset(qboolean before) /*force all state to change, thus setting a known state*/ shaderstate.shaderbits = ~0; BE_ApplyShaderBits(0); - - - Surf_BuildLightmaps(); } } @@ -2658,7 +2655,7 @@ static void BE_UploadLightmaps(qboolean force) if (lightmap[i]->modified) { - extern cvar_t gl_lightmap_nearest; + extern cvar_t r_lightmap_nearest; IDirect3DTexture8 *tex; D3DLOCKED_RECT lock; RECT rect; @@ -2667,7 +2664,7 @@ static void BE_UploadLightmaps(qboolean force) int w; if (!TEXLOADED(lm->lightmap_texture)) - lm->lightmap_texture = Image_CreateTexture("***lightmap***", NULL, (gl_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR)|IF_NOMIPMAP); + lm->lightmap_texture = Image_CreateTexture("***lightmap***", NULL, (r_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR)|IF_NOMIPMAP); tex = lm->lightmap_texture->ptr; if (!tex) { diff --git a/engine/d3d/d3d8_image.c b/engine/d3d/d3d8_image.c index 2b4d453e..aec29426 100644 --- a/engine/d3d/d3d8_image.c +++ b/engine/d3d/d3d8_image.c @@ -30,12 +30,15 @@ qboolean D3D8_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip qbyte *fte_restrict out, *fte_restrict in; int x, y, i; D3DLOCKED_RECT lock; - D3DFORMAT fmt; + D3DFORMAT fmt = D3DFMT_UNKNOWN; D3DSURFACE_DESC desc; IDirect3DTexture8 *dt; qboolean swap = false; unsigned int blockwidth, blockheight, blockbytes = 1; + if (mips->type != PTI_2D) + return false; //fixme: cube and volumes should work + switch(mips->encoding) { case PTI_RGB565: @@ -80,9 +83,12 @@ qboolean D3D8_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip fmt = D3DFMT_DXT5; break; + case PTI_EMULATED: default: //no idea - return false; + break; } + if (fmt == D3DFMT_UNKNOWN) + return false; Image_BlockSizeForEncoding(mips->encoding, &blockbytes, &blockwidth, &blockheight); diff --git a/engine/d3d/d3d_backend.c b/engine/d3d/d3d_backend.c index c644d4d3..5d518552 100644 --- a/engine/d3d/d3d_backend.c +++ b/engine/d3d/d3d_backend.c @@ -654,9 +654,6 @@ void D3D9BE_Reset(qboolean before) /*force all state to change, thus setting a known state*/ shaderstate.shaderbits = ~0; BE_ApplyShaderBits(0); - - - Surf_BuildLightmaps(); } } @@ -3080,7 +3077,7 @@ static void BE_UploadLightmaps(qboolean force) if (lightmap[i]->modified) { - extern cvar_t gl_lightmap_nearest; + extern cvar_t r_lightmap_nearest; IDirect3DTexture9 *tex; D3DLOCKED_RECT lock; RECT rect; @@ -3089,11 +3086,42 @@ static void BE_UploadLightmaps(qboolean force) int w; if (!TEXLOADED(lm->lightmap_texture)) - lm->lightmap_texture = Image_CreateTexture("***lightmap***", NULL, (gl_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR)|IF_NOMIPMAP); + lm->lightmap_texture = Image_CreateTexture("***lightmap***", NULL, (r_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR)|IF_NOMIPMAP); tex = lm->lightmap_texture->ptr; if (!tex) { - IDirect3DDevice9_CreateTexture(pD3DDev9, lm->width, lm->height, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &tex, NULL); + switch(lightmap_fmt) + { + default: + break; + case PTI_BGRA8: + IDirect3DDevice9_CreateTexture(pD3DDev9, lm->width, lm->height, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &tex, NULL); + break; + case PTI_BGRX8: + IDirect3DDevice9_CreateTexture(pD3DDev9, lm->width, lm->height, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &tex, NULL); + break; + case PTI_RGB565: + IDirect3DDevice9_CreateTexture(pD3DDev9, lm->width, lm->height, 1, 0, D3DFMT_R5G6B5, D3DPOOL_MANAGED, &tex, NULL); + break; + case PTI_ARGB4444: + IDirect3DDevice9_CreateTexture(pD3DDev9, lm->width, lm->height, 1, 0, D3DFMT_A4R4G4B4, D3DPOOL_MANAGED, &tex, NULL); + break; + case PTI_ARGB1555: + IDirect3DDevice9_CreateTexture(pD3DDev9, lm->width, lm->height, 1, 0, D3DFMT_A1R5G5B5, D3DPOOL_MANAGED, &tex, NULL); + break; + case PTI_A2BGR10: + IDirect3DDevice9_CreateTexture(pD3DDev9, lm->width, lm->height, 1, 0, D3DFMT_A2B10G10R10, D3DPOOL_MANAGED, &tex, NULL); + break; + case PTI_L8: + IDirect3DDevice9_CreateTexture(pD3DDev9, lm->width, lm->height, 1, 0, D3DFMT_L8, D3DPOOL_MANAGED, &tex, NULL); + break; + case PTI_RGBA16F: + IDirect3DDevice9_CreateTexture(pD3DDev9, lm->width, lm->height, 1, 0, D3DFMT_A16B16G16R16F, D3DPOOL_MANAGED, &tex, NULL); + break; + case PTI_RGBA32F: + IDirect3DDevice9_CreateTexture(pD3DDev9, lm->width, lm->height, 1, 0, D3DFMT_A32B32G32R32F, D3DPOOL_MANAGED, &tex, NULL); + break; + } if (!tex) continue; lm->lightmap_texture->ptr = tex; diff --git a/engine/d3d/d3d_image.c b/engine/d3d/d3d_image.c index 45afa3b4..3846dea1 100644 --- a/engine/d3d/d3d_image.c +++ b/engine/d3d/d3d_image.c @@ -23,7 +23,7 @@ qboolean D3D9_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip qbyte *fte_restrict out, *fte_restrict in; int x, y, i; D3DLOCKED_RECT lock; - D3DFORMAT fmt; + D3DFORMAT fmt = D3DFMT_UNKNOWN; D3DSURFACE_DESC desc; IDirect3DBaseTexture9 *dbt; qboolean swap = false; @@ -65,6 +65,10 @@ qboolean D3D9_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip fmt = D3DFMT_X8R8G8B8; break; + case PTI_A2BGR10: + fmt = D3DFMT_A2B10G10R10; + break; + //too lazy to support these for now case PTI_BC1_RGB_SRGB: case PTI_BC1_RGBA_SRGB: //d3d doesn't distinguish between these @@ -84,9 +88,12 @@ qboolean D3D9_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip //bc4-7 not supported on d3d9. //etc2 have no chance. - default: //no idea - return false; + case PTI_EMULATED: //no idea + default: + break; } + if (fmt == D3DFMT_UNKNOWN) + return false; Image_BlockSizeForEncoding(mips->encoding, &blockbytes, &blockwidth, &blockheight); @@ -136,7 +143,7 @@ qboolean D3D9_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip IDirect3DCubeTexture9_UnlockRect(dt, i%6, i/6); } } - else + else if (mips->type == PTI_2D) { IDirect3DTexture9 *dt; if (FAILED(IDirect3DDevice9_CreateTexture(pD3DDev9, mips->mip[0].width, mips->mip[0].height, mips->mipcount, 0, fmt, D3DPOOL_MANAGED, &dt, NULL))) @@ -180,6 +187,8 @@ qboolean D3D9_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip IDirect3DTexture9_UnlockRect(dt, i); } } + else + dbt = NULL; D3D9_DestroyTexture(tex); tex->ptr = dbt; diff --git a/engine/d3d/vid_d3d.c b/engine/d3d/vid_d3d.c index 3d5096b2..2b118afd 100644 --- a/engine/d3d/vid_d3d.c +++ b/engine/d3d/vid_d3d.c @@ -444,7 +444,7 @@ static LRESULT WINAPI D3D9_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA static void D3D9_VID_SwapBuffers(void) { - if (d3dpp.Windowed && (vid_srgb.ival==1 || vid.srgb)) + if (vid.flags&VID_SRGB_FB_FAKED) { IDirect3DSwapChain9 *swapchain; IDirect3DDevice9_GetSwapChain(pD3DDev9, 0, &swapchain); @@ -526,6 +526,8 @@ static qboolean initD3D9Device(HWND hWnd, rendererstate_t *info, unsigned int de { if (info->bpp == 16) d3dpp.BackBufferFormat = D3DFMT_R5G6B5; + else if (info->bpp == 30) + d3dpp.BackBufferFormat = D3DFMT_A2R10G10B10; else d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8; } @@ -580,6 +582,8 @@ static qboolean initD3D9Device(HWND hWnd, rendererstate_t *info, unsigned int de vid.numpages = d3dpp.BackBufferCount; + vid.flags = VID_SRGB_CAPABLE; + if (d3dpp.Windowed) //fullscreen we get positioned automagically. { //windowed, we get positioned at 0,0... which is often going to be on the wrong screen //the user can figure it out from here @@ -619,6 +623,10 @@ static qboolean initD3D9Device(HWND hWnd, rendererstate_t *info, unsigned int de {PTI_RGB565, D3DFMT_R5G6B5, D3DUSAGE_QUERY_FILTER}, {PTI_ARGB1555, D3DFMT_A1R5G5B5, D3DUSAGE_QUERY_FILTER}, {PTI_ARGB4444, D3DFMT_A4R4G4B4, D3DUSAGE_QUERY_FILTER}, + {PTI_A2BGR10, D3DFMT_A2B10G10R10, D3DUSAGE_QUERY_FILTER}, + {PTI_RGBA16F, D3DFMT_A16B16G16R16F, D3DUSAGE_QUERY_FILTER}, + {PTI_RGBA32F, D3DFMT_A32B32G32R32F, D3DUSAGE_QUERY_FILTER}, + {PTI_L8, D3DFMT_L8, D3DUSAGE_QUERY_FILTER}, {PTI_BGRX8_SRGB, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER|D3DUSAGE_QUERY_SRGBREAD}, {PTI_BGRA8_SRGB, D3DFMT_A8R8G8B8, D3DUSAGE_QUERY_FILTER|D3DUSAGE_QUERY_SRGBREAD}, @@ -639,10 +647,10 @@ static qboolean initD3D9Device(HWND hWnd, rendererstate_t *info, unsigned int de //fixme: the engine kinda insists on rgba textures, which d3d9 does NOT support. //we currently have some swapping, so these load, just slowly. - sh_config.texfmt[PTI_RGBX8] = sh_config.texfmt[PTI_BGRX8]; - sh_config.texfmt[PTI_RGBA8] = sh_config.texfmt[PTI_BGRA8]; - sh_config.texfmt[PTI_RGBX8_SRGB] = sh_config.texfmt[PTI_BGRX8_SRGB]; - sh_config.texfmt[PTI_RGBA8_SRGB] = sh_config.texfmt[PTI_BGRA8_SRGB]; + sh_config.texfmt[PTI_RGBX8] |= sh_config.texfmt[PTI_BGRX8]; + sh_config.texfmt[PTI_RGBA8] |= sh_config.texfmt[PTI_BGRA8]; + sh_config.texfmt[PTI_RGBX8_SRGB] |= sh_config.texfmt[PTI_BGRX8_SRGB]; + sh_config.texfmt[PTI_RGBA8_SRGB] |= sh_config.texfmt[PTI_BGRA8_SRGB]; return true; //successful } @@ -975,7 +983,7 @@ static qboolean (D3D9_SCR_UpdateScreen) (void) return false; // not initialized yet } - if (d3d_resized && d3dpp.Windowed) + if (d3d_resized/* && d3dpp.Windowed*/) { extern cvar_t vid_conautoscale, vid_conwidth; d3d_resized = false; @@ -998,7 +1006,11 @@ static qboolean (D3D9_SCR_UpdateScreen) (void) if (vid_srgb.modified) { vid_srgb.modified = false; - IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_SRGBWRITEENABLE, (vid_srgb.ival==1 || vid.srgb) && !d3dpp.Windowed); + vid.flags &= VID_SRGB_FB; + if ((vid.flags & VID_SRGBAWARE) || vid_srgb.ival) + vid.flags |= (d3dpp.Windowed)?VID_SRGB_FB_FAKED:VID_SRGB_FB_LINEAR; + + IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_SRGBWRITEENABLE, !!(vid.flags&VID_SRGB_FB_LINEAR)); } switch (IDirect3DDevice9_TestCooperativeLevel(pD3DDev9)) @@ -1168,8 +1180,14 @@ static qboolean (D3D9_SCR_UpdateScreen) (void) static void (D3D9_Draw_Init) (void) { - vid.srgb = vid_srgb.ival>1; - IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_SRGBWRITEENABLE, (vid_srgb.ival==1 || vid.srgb) && !d3dpp.Windowed); + { + vid_srgb.modified = false; + vid.flags &= VID_SRGB_FB; + if ((vid.flags & VID_SRGBAWARE) || vid_srgb.ival) + vid.flags |= (d3dpp.Windowed)?VID_SRGB_FB_FAKED:VID_SRGB_FB_LINEAR; + + IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_SRGBWRITEENABLE, !!(vid.flags&VID_SRGB_FB_LINEAR)); + } R2D_Init(); } diff --git a/engine/d3d/vid_d3d11.c b/engine/d3d/vid_d3d11.c index 68bd0b77..6d956140 100644 --- a/engine/d3d/vid_d3d11.c +++ b/engine/d3d/vid_d3d11.c @@ -7,6 +7,8 @@ #include "renderque.h" #include "resource.h" +#define FUCKDXGI + #define COBJMACROS #include @@ -144,14 +146,14 @@ static void D3D11_PresentOrCrash(void) { extern cvar_t vid_vsync; RSpeedMark(); - HRESULT hr = IDXGISwapChain_Present(d3dswapchain, vid_vsync.ival, 0); + HRESULT hr = IDXGISwapChain_Present(d3dswapchain, max(0,vid_vsync.ival), 0); if (FAILED(hr)) Sys_Error("IDXGISwapChain_Present: %s\n", D3D_NameForResult(hr)); RSpeedEnd(RSPEED_PRESENT); } -typedef enum {MS_WINDOWED, MS_FULLSCREEN, MS_FULLDIB, MS_UNINIT} modestate_t; -static modestate_t modestate; +typedef enum {MS_WINDOWED, MS_FULLSCREEN, MS_FULLWINDOW, MS_UNINIT} dx11modestate_t; +static dx11modestate_t modestate; //FIXME: need to push/pop render targets like gl does, to not harm shadowmaps/refraction/etc. void D3D11_ApplyRenderTargets(qboolean usedepth) @@ -285,7 +287,7 @@ static qboolean D3D11AppActivate(BOOL fActive, BOOL minimize) return true; } - +#ifndef FUCKDXGI static void D3D11_DoResize(void) { d3d_resized = true; @@ -312,14 +314,30 @@ static void D3D11_DoResize(void) resetd3dbackbuffer(vid.pixelwidth, vid.pixelheight); D3D11BE_Reset(false); } +#endif +static void ClearAllStates (void) +{ + int i; + +// send an up event for each key, to make sure the server clears them all + for (i=0 ; i<256 ; i++) + { + Key_Event (0, i, 0, false); + } + + Key_ClearStates (); + INS_ClearStates (); +} static LRESULT WINAPI D3D11_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LONG lRet = 0; - int fActive, fMinimized, temp; + int temp; extern unsigned int uiWheelMessage; +#ifndef FUCKDXGI extern qboolean keydown[K_MAX]; +#endif if ( uMsg == uiWheelMessage ) uMsg = WM_MOUSEWHEEL; @@ -327,11 +345,24 @@ static LRESULT WINAPI D3D11_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR switch (uMsg) { #if 1 -/* case WM_KILLFOCUS: - if (modestate == MS_FULLDIB) + case WM_KILLFOCUS: + if (modestate == MS_FULLWINDOW) ShowWindow(mainwindow, SW_SHOWMINNOACTIVE); + D3D11AppActivate(false, false); break; -*/ + + case WM_SETFOCUS: + if (modestate == MS_FULLWINDOW) + ShowWindow(mainwindow, SW_SHOWMAXIMIZED); + D3D11AppActivate(true, false); + + if (modestate == MS_FULLSCREEN && d3dswapchain) + IDXGISwapChain_SetFullscreenState(d3dswapchain, vid.activeapp, (vid.activeapp)?d3dscreen:NULL); + Cvar_ForceCallback(&v_gamma); + + ClearAllStates (); + break; + // case WM_CREATE: // break; @@ -342,6 +373,7 @@ static LRESULT WINAPI D3D11_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR case WM_KEYDOWN: case WM_SYSKEYDOWN: +#ifndef FUCKDXGI if (keydown[K_LALT] && wParam == '\r') { if (d3dscreen) @@ -402,7 +434,9 @@ static LRESULT WINAPI D3D11_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR D3D11_DoResize(); Cvar_ForceCallback(&v_gamma); } - else if (!vid_initializing) + else +#endif + if (!vid_initializing) INS_TranslateKeyEvent (wParam, lParam, true, 0, false); break; @@ -555,31 +589,6 @@ static LRESULT WINAPI D3D11_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR break; - case WM_ACTIVATE: - fActive = LOWORD(wParam); - fMinimized = (BOOL) HIWORD(wParam); - if (!D3D11AppActivate(!(fActive == WA_INACTIVE), fMinimized)) - break;//so, urm, tell me microsoft, what changed? - - if (modestate == MS_FULLDIB) - ShowWindow(mainwindow, SW_SHOWNORMAL); - - if (modestate == MS_FULLSCREEN) - { - if (d3dswapchain) - { - IDXGISwapChain_SetFullscreenState(d3dswapchain, vid.activeapp, d3dscreen); - D3D11_DoResize(); - } - } - Cvar_ForceCallback(&v_gamma); - - // fix the leftover Alt from any Alt-Tab or the like that switched us away -// ClearAllStates (); - - lRet = 1; - break; - case WM_DESTROY: { // if (dibwindow) @@ -791,7 +800,17 @@ static qboolean initD3D11Device(HWND hWnd, rendererstate_t *info, PFN_D3D11_CREA scd.BufferDesc.RefreshRate.Numerator = 0; scd.BufferDesc.RefreshRate.Denominator = 0; scd.BufferCount = 1+info->triplebuffer; //back buffer count - scd.BufferDesc.Format = info->srgb?DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:DXGI_FORMAT_R8G8B8A8_UNORM; //32bit colour + if (info->srgb) + { + if (info->srgb >= 3) //fixme: detect properly. + scd.BufferDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; //on nvidia, outputs linear rgb to srgb devices, which means info->srgb is effectively set + else + scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + } + else if (info->bpp == 30) //fixme: detect properly. + scd.BufferDesc.Format = DXGI_FORMAT_R10G10B10A2_UNORM; + else + scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; scd.OutputWindow = hWnd; scd.SampleDesc.Count = d3d11multisample_count = max(1, info->multisample); //as we're starting up windowed (and switching to fullscreen after), the frontbuffer is handled by windows. @@ -856,29 +875,65 @@ static qboolean initD3D11Device(HWND hWnd, rendererstate_t *info, PFN_D3D11_CREA #define DXGI_FORMAT_B4G4R4A4_UNORM 115 //why does d3d11 have no rgbx format? anyone else think that weird? - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B5G6R5_UNORM, &support); sh_config.texfmt[PTI_RGB565] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B5G5R5A1_UNORM, &support); sh_config.texfmt[PTI_ARGB1555] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B4G4R4A4_UNORM, &support); sh_config.texfmt[PTI_ARGB4444] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_R8G8B8A8_UNORM, &support); sh_config.texfmt[PTI_RGBA8] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B8G8R8A8_UNORM, &support); sh_config.texfmt[PTI_BGRA8] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B8G8R8X8_UNORM, &support); sh_config.texfmt[PTI_BGRX8] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, &support); sh_config.texfmt[PTI_RGBA8_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, &support); sh_config.texfmt[PTI_BGRA8_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B8G8R8X8_UNORM_SRGB, &support); sh_config.texfmt[PTI_BGRX8_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC1_UNORM, &support); sh_config.texfmt[PTI_BC1_RGBA] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC2_UNORM, &support); sh_config.texfmt[PTI_BC2_RGBA] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC3_UNORM, &support); sh_config.texfmt[PTI_BC3_RGBA] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC1_UNORM_SRGB, &support); sh_config.texfmt[PTI_BC1_RGBA_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC2_UNORM_SRGB, &support); sh_config.texfmt[PTI_BC2_RGBA_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC3_UNORM_SRGB, &support); sh_config.texfmt[PTI_BC3_RGBA_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC4_UNORM, &support); sh_config.texfmt[PTI_BC4_R8] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC4_SNORM, &support); sh_config.texfmt[PTI_BC4_R8_SIGNED] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC5_UNORM, &support); sh_config.texfmt[PTI_BC5_RG8] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC5_SNORM, &support); sh_config.texfmt[PTI_BC5_RG8_SIGNED] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC6H_UF16, &support); sh_config.texfmt[PTI_BC6_RGBF] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC6H_SF16, &support); sh_config.texfmt[PTI_BC6_RGBF_SIGNED] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC7_UNORM, &support); sh_config.texfmt[PTI_BC7_RGBA] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC7_UNORM_SRGB, &support); sh_config.texfmt[PTI_BC7_RGBA_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B5G6R5_UNORM, &support))) //crippled to win8+ only. + sh_config.texfmt[PTI_RGB565] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B5G5R5A1_UNORM, &support))) //crippled to win8+ only. + sh_config.texfmt[PTI_ARGB1555] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B4G4R4A4_UNORM, &support))) //crippled to win8+ only. + sh_config.texfmt[PTI_ARGB4444] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_R8G8B8A8_UNORM, &support))) + sh_config.texfmt[PTI_RGBA8] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, &support))) + sh_config.texfmt[PTI_RGBA8_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_R10G10B10A2_UNORM, &support))) + sh_config.texfmt[PTI_A2BGR10] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D) && !!(support & D3D11_FORMAT_SUPPORT_RENDER_TARGET); + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, &support))) + sh_config.texfmt[PTI_E5BGR9] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_R16G16B16A16_FLOAT, &support))) + sh_config.texfmt[PTI_RGBA16F] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D) && !!(support & D3D11_FORMAT_SUPPORT_RENDER_TARGET); + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_R32G32B32A32_FLOAT, &support))) + sh_config.texfmt[PTI_RGBA32F] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D) && !!(support & D3D11_FORMAT_SUPPORT_RENDER_TARGET); + + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B8G8R8A8_UNORM, &support))) + sh_config.texfmt[PTI_BGRA8] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, &support))) + sh_config.texfmt[PTI_BGRA8_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B8G8R8X8_UNORM, &support))) + sh_config.texfmt[PTI_BGRX8] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B8G8R8X8_UNORM_SRGB, &support))) + sh_config.texfmt[PTI_BGRX8_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + + //compressed formats + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC1_UNORM, &support))) + sh_config.texfmt[PTI_BC1_RGBA] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC1_UNORM_SRGB, &support))) + sh_config.texfmt[PTI_BC1_RGBA_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC2_UNORM, &support))) + sh_config.texfmt[PTI_BC2_RGBA] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC2_UNORM_SRGB, &support))) + sh_config.texfmt[PTI_BC2_RGBA_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC3_UNORM, &support))) + sh_config.texfmt[PTI_BC3_RGBA] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC3_UNORM_SRGB, &support))) + sh_config.texfmt[PTI_BC3_RGBA_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC4_UNORM, &support))) + sh_config.texfmt[PTI_BC4_R8] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC4_SNORM, &support))) + sh_config.texfmt[PTI_BC4_R8_SNORM] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC5_UNORM, &support))) + sh_config.texfmt[PTI_BC5_RG8] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC5_SNORM, &support))) + sh_config.texfmt[PTI_BC5_RG8_SNORM] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC6H_UF16, &support))) + sh_config.texfmt[PTI_BC6_RGB_UFLOAT] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC6H_SF16, &support))) + sh_config.texfmt[PTI_BC6_RGB_SFLOAT] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC7_UNORM, &support))) + sh_config.texfmt[PTI_BC7_RGBA] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + if (SUCCEEDED(ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC7_UNORM_SRGB, &support))) + sh_config.texfmt[PTI_BC7_RGBA_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); //these formats are not officially supported as specified, but noone cares sh_config.texfmt[PTI_RGBX8] = sh_config.texfmt[PTI_RGBA8]; @@ -886,7 +941,22 @@ static qboolean initD3D11Device(HWND hWnd, rendererstate_t *info, PFN_D3D11_CREA sh_config.texfmt[PTI_BC1_RGB] = sh_config.texfmt[PTI_BC1_RGBA]; sh_config.texfmt[PTI_BC1_RGB_SRGB] = sh_config.texfmt[PTI_BC1_RGBA_SRGB]; - vid.srgb = info->srgb>1; + switch(scd.BufferDesc.Format) + { + case DXGI_FORMAT_R16G16B16A16_FLOAT: + vid.flags |= VID_SRGB_FB_LINEAR|VID_FP16; //these are apparently linear already. + break; + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + vid.flags |= VID_SRGB_FB_LINEAR; //effectively linear. + break; + default: + //non-linear formats. + break; + } + if ((vid.flags & VID_SRGB_FB) && info->srgb != 1) + vid.flags |= VID_SRGBAWARE; vid.numpages = scd.BufferCount; if (!D3D11Shader_Init(flevel)) @@ -987,15 +1057,30 @@ static qboolean D3D11_VID_Init(rendererstate_t *info, unsigned char *palette) RegisterClass(&wc); - modestate = info->fullscreen?MS_FULLSCREEN:MS_WINDOWED; + if (info->fullscreen/* == 2*/) + modestate = MS_FULLWINDOW; + else if (info->fullscreen) + modestate = MS_FULLSCREEN; //FIXME: I'm done with fighting dxgi. I'm just going to pick the easy method that doesn't end up with totally fucked up behaviour. + else + modestate = MS_WINDOWED; - wstyle = WS_OVERLAPPEDWINDOW; - - rect.left = (GetSystemMetrics(SM_CXSCREEN) - width) / 2; - rect.top = (GetSystemMetrics(SM_CYSCREEN) - height) / 2; - rect.right = rect.left+width; - rect.bottom = rect.top+height; - AdjustWindowRectEx(&rect, wstyle, FALSE, 0); + if (modestate == MS_FULLWINDOW) + { + wstyle = WS_POPUP; + rect.right = GetSystemMetrics(SM_CXSCREEN); + rect.bottom = GetSystemMetrics(SM_CYSCREEN); + rect.left = 0; + rect.top = 0; + } + else + { + wstyle = WS_OVERLAPPEDWINDOW; + rect.left = (GetSystemMetrics(SM_CXSCREEN) - width) / 2; + rect.top = (GetSystemMetrics(SM_CYSCREEN) - height) / 2; + rect.right = rect.left+width; + rect.bottom = rect.top+height; + AdjustWindowRectEx(&rect, wstyle, FALSE, 0); + } mainwindow = CreateWindow(CLASSNAME, "Direct3D11", wstyle, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, NULL, NULL, NULL, NULL); // Try as specified. @@ -1010,16 +1095,16 @@ static qboolean D3D11_VID_Init(rendererstate_t *info, unsigned char *palette) return false; } - if (info->fullscreen) + vid.pixelwidth = width; + vid.pixelheight = height; + + if (modestate == MS_FULLSCREEN) { if (!d3dscreen) IDXGISwapChain_GetContainingOutput(d3dswapchain, &d3dscreen); IDXGISwapChain_SetFullscreenState(d3dswapchain, true, d3dscreen); } - vid.pixelwidth = width; - vid.pixelheight = height; - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); @@ -1028,7 +1113,10 @@ static qboolean D3D11_VID_Init(rendererstate_t *info, unsigned char *palette) CL_UpdateWindowTitle(); - ShowWindow(mainwindow, SW_SHOWNORMAL); + if (modestate == MS_FULLWINDOW) + ShowWindow(mainwindow, SW_SHOWMAXIMIZED); + else + ShowWindow(mainwindow, SW_SHOWNORMAL); vid.width = vid.pixelwidth; vid.height = vid.pixelheight; diff --git a/engine/d3d/vid_d3d8.c b/engine/d3d/vid_d3d8.c index 5310fd8e..a6081cb4 100644 --- a/engine/d3d/vid_d3d8.c +++ b/engine/d3d/vid_d3d8.c @@ -827,8 +827,6 @@ static qboolean D3D8_VID_Init(rendererstate_t *info, unsigned char *palette) vid.width = width; vid.height = height; - vid.srgb = false; - vid_initializing = false; IDirect3DDevice8_SetRenderState(pD3DDev8, D3DRS_LIGHTING, FALSE); diff --git a/engine/dotnet2005/droid.vcproj b/engine/dotnet2005/droid.vcproj index 4c009e2d..7d680d33 100644 --- a/engine/dotnet2005/droid.vcproj +++ b/engine/dotnet2005/droid.vcproj @@ -43,7 +43,7 @@ > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2747,6 +2949,24 @@ PreprocessorDefinitions="" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c index 1dcfb0b7..c7f6689a 100644 --- a/engine/gl/gl_alias.c +++ b/engine/gl/gl_alias.c @@ -61,6 +61,7 @@ struct cctx_s }; void Mod_FlushSkin(skinid_t id) { +#ifdef QWSKINS skinfile_t *sk; id--; if (id >= numregisteredskins) @@ -69,6 +70,7 @@ void Mod_FlushSkin(skinid_t id) if (!sk) return; sk->qwskin = NULL; +#endif } void Mod_WipeSkin(skinid_t id, qboolean force) { @@ -268,8 +270,10 @@ skinid_t Mod_ReadSkinFile(const char *skinname, const char *skintext) skin->refcount++; skin->maxmappings = 4; Q_strncpyz(skin->skinname, skinname, sizeof(skin->skinname)); +#ifdef QWSKINS skin->q1lower = Q1UNSPECIFIED; skin->q1upper = Q1UNSPECIFIED; +#endif while(skintext) { @@ -359,6 +363,7 @@ skinid_t Mod_ReadSkinFile(const char *skinname, const char *skintext) { //ignore it. matches q3. } +#ifdef QWSKINS else if (!strcmp(com_token, "qwskin")) { skintext = COM_ParseToken(skintext, NULL); @@ -380,6 +385,7 @@ skinid_t Mod_ReadSkinFile(const char *skinname, const char *skintext) else skin->q1upper = atoi(com_token); } +#endif else { while(*skintext == ' ' || *skintext == '\t') @@ -591,18 +597,16 @@ void R_GAliasFlushSkinCache(qboolean final) static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, entity_t *e, texnums_t **forcedtex) { galiasskin_t *skins; +#ifdef QWSKINS shader_t *shader; qwskin_t *plskin = NULL; - int frame; unsigned int subframe; - extern int cl_playerindex; //so I don't have to strcmp - - unsigned int tc, bc, pc; - qboolean forced; + unsigned int tc = e->topcolour, bc = e->bottomcolour, pc; qboolean generateupperlower = false; - - tc = e->topcolour; - bc = e->bottomcolour; + qboolean forced; + extern int cl_playerindex; //so I don't have to strcmp +#endif + int frame; *forcedtex = NULL; /*q3 .skin files*/ @@ -629,13 +633,15 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e *forcedtex = &sk->mappings[fallback].texnums; return sk->mappings[fallback].shader; } - if (!sk->qwskin && *sk->qwskinname) - sk->qwskin = Skin_Lookup(sk->qwskinname); +#ifdef QWSKINS if (sk->q1lower != Q1UNSPECIFIED) bc = e->bottomcolour = sk->q1lower; if (sk->q1upper != Q1UNSPECIFIED) tc = e->topcolour = sk->q1upper; + if (!sk->qwskin && *sk->qwskinname) + sk->qwskin = Skin_Lookup(sk->qwskinname); plskin = sk->qwskin; +#endif } } else if (inf->geomset < MAX_GEOMSETS && 0 != inf->geomid) @@ -655,7 +661,7 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e } } - +#ifdef QWSKINS if ((e->model->engineflags & MDLF_NOTREPLACEMENTS) && !ruleset_allow_sensitive_texture_replacements.ival) forced = true; else @@ -1069,7 +1075,7 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e cm->texnum.paletted = R_LoadTexture(va("paletted$%x$%x$%i$%i$%i$%s", tc, bc, cm->skinnum, subframe, pc, cm->name), - scaled_width, scaled_height, TF_LUM8, pixels8, IF_NEAREST|IF_NOMIPMAP); + scaled_width, scaled_height, PTI_R8, pixels8, IF_NEAREST|IF_NOMIPMAP); } @@ -1160,7 +1166,7 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e return shader; } } - +#endif if (!inf->numskins) return NULL; @@ -1487,19 +1493,28 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel) } } - m = max(max(ambientlight[0], ambientlight[1]), ambientlight[2]); - if (m > 255) + switch(lightmap_fmt) { - ambientlight[0] *= 255.0/m; - ambientlight[1] *= 255.0/m; - ambientlight[2] *= 255.0/m; - } - m = max(max(shadelight[0], shadelight[1]), shadelight[2]); - if (m > 128) - { - shadelight[0] *= 128.0/m; - shadelight[1] *= 128.0/m; - shadelight[2] *= 128.0/m; + case PTI_E5BGR9: + case PTI_RGBA16F: + case PTI_RGBA32F: + break; + default: + m = max(max(ambientlight[0], ambientlight[1]), ambientlight[2]); + if (m > 255) + { + ambientlight[0] *= 255.0/m; + ambientlight[1] *= 255.0/m; + ambientlight[2] *= 255.0/m; + } + m = max(max(shadelight[0], shadelight[1]), shadelight[2]); + if (m > 128) + { + shadelight[0] *= 128.0/m; + shadelight[1] *= 128.0/m; + shadelight[2] *= 128.0/m; + } + break; } //MORE HUGE HACKS! WHEN WILL THEY CEASE! @@ -1664,6 +1679,7 @@ void R_GAlias_GenerateBatches(entity_t *e, batch_t **batches) return; clmodel = e->model; +#ifdef QWSKINS /*switch model if we're the player model, and the player skin says a new model*/ { extern int cl_playerindex; @@ -1674,6 +1690,7 @@ void R_GAlias_GenerateBatches(entity_t *e, batch_t **batches) clmodel = e->model; //oops, never mind } } +#endif if (!(e->flags & RF_WEAPONMODEL) #ifdef SKELETALMODELS diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 13f1f5a6..56268f5f 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -1176,7 +1176,12 @@ static void T_Gen_CurrentRender(int tmu) qglGenTextures(1, &shaderstate.temptexture->num); } GL_MTBind(tmu, GL_TEXTURE_2D, shaderstate.temptexture); - qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, vwidth, vheight, 0); + if (vid.flags&VID_FP16) + qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, 0, 0, vwidth, vheight, 0); + else if (vid.flags&VID_SRGBAWARE) + qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA_EXT, 0, 0, vwidth, vheight, 0); + else + qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, vwidth, vheight, 0); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -1377,6 +1382,7 @@ static float *FTableForFunc ( unsigned int func ) { switch (func) { + default: case SHADER_FUNC_SIN: return r_sintable; @@ -1391,10 +1397,10 @@ static float *FTableForFunc ( unsigned int func ) case SHADER_FUNC_INVERSESAWTOOTH: return r_inversesawtoothtable; - } - //bad values allow us to crash (so I can debug em) - return NULL; + case SHADER_FUNC_NOISE: + return NULL; + } } void Shader_LightPass(const char *shortname, shader_t *s, const void *args) @@ -1506,9 +1512,16 @@ void GLBE_DestroyFBOs(void) void GLBE_Shutdown(void) { + size_t u; GLBE_FBO_Destroy(&shaderstate.fbo_2dfbo); GLBE_DestroyFBOs(); + for (u = 0; u < countof(shaderstate.programfixedemu); u++) + { + Shader_ReleaseGeneric(shaderstate.programfixedemu[u]); + shaderstate.programfixedemu[u] = NULL; + } + BZ_Free(shaderstate.wbatches); shaderstate.wbatches = NULL; shaderstate.maxwbatches = 0; @@ -1624,7 +1637,11 @@ void GLBE_Init(void) memset(&shaderstate.streamebo, 0, sizeof(shaderstate.streamebo)); memset(&shaderstate.streamvao, 0, sizeof(shaderstate.streamvao)); //only do this where we have to. - if (qglBufferDataARB && gl_config_nofixedfunc) + if (qglBufferDataARB && gl_config_nofixedfunc +#ifndef FTE_TARGET_WEB + && !gl_config_gles +#endif + ) { qglGenBuffersARB(sizeof(shaderstate.streamvbo)/sizeof(shaderstate.streamvbo[0]), shaderstate.streamvbo); qglGenBuffersARB(sizeof(shaderstate.streamebo)/sizeof(shaderstate.streamebo[0]), shaderstate.streamebo); @@ -1919,7 +1936,7 @@ static void GenerateTCMods3(const shaderpass_t *pass, int passnum) if (src != texcoordarray[passnum]+mesh->vbofirstvert*3) { //this shouldn't actually ever be true - memcpy(texcoordarray[passnum]+mesh->vbofirstvert*3, src, 8*mesh->numvertexes); + memcpy(texcoordarray[passnum]+mesh->vbofirstvert*3, src, sizeof(vec3_t)*mesh->numvertexes); } } shaderstate.pendingtexcoordparts[passnum] = 3; @@ -3046,6 +3063,8 @@ static void BE_SubmitMeshChain(qboolean usetesselation) index_t *fte_restrict ilst; //FIXME: this should be cached for multiple-pass shaders. GL_SelectEBO(0); + //FIXME: use a coherant persistently mapped buffer. + mesh = shaderstate.meshes[0]; startv = mesh->vbofirstvert; endv = startv + mesh->numvertexes; @@ -5245,7 +5264,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist) shaderstate.tex_ripplemap[r_refdef.recurse]->width = r_refdef.pxrect.width; shaderstate.tex_ripplemap[r_refdef.recurse]->height = r_refdef.pxrect.height; GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_ripplemap[r_refdef.recurse]); - qglTexImage2D(GL_TEXTURE_2D, 0, /*(gl_config.glversion>3.1)?GL_RGBA8_SNORM:*/GL_RGBA16F_ARB, r_refdef.pxrect.width, r_refdef.pxrect.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + qglTexImage2D(GL_TEXTURE_2D, 0, /*(gl_config.glversion>3.1)?GL_RGBA8_SNORM:*/GL_RGBA16F_ARB, r_refdef.pxrect.width, r_refdef.pxrect.height, 0, GL_RGBA, GL_HALF_FLOAT, NULL); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -5304,20 +5323,6 @@ static void BE_UpdateLightmaps(void) { lightmapinfo_t *lm; int lmidx; - int glformat, gltype; - int internalformat = /*vid.srgb?GL_SRGB8_ALPHA8_EXT:*/GL_RGBA; - switch (lightmap_fmt) - { - case TF_INVALID: return; - default: Sys_Error("Bad lightmap_fmt\n"); return; - case TF_BGRA32: glformat = GL_BGRA_EXT; gltype = GL_UNSIGNED_INT_8_8_8_8_REV; break; -// case TF_RGBA32: glformat = GL_RGBA; gltype = GL_UNSIGNED_INT_8_8_8_8_REV; break; -// case TF_BGR24: glformat = GL_BGR_EXT; gltype = GL_UNSIGNED_BYTE; break; - case TF_RGB24: glformat = GL_RGB; gltype = GL_UNSIGNED_BYTE; break; - case TF_LUM8: glformat = GL_LUMINANCE;gltype = GL_UNSIGNED_BYTE; break; - } - if (gl_config.gles) - internalformat = glformat; for (lmidx = 0; lmidx < numlightmaps; lmidx++) { @@ -5335,18 +5340,26 @@ static void BE_UpdateLightmaps(void) #endif if (!TEXVALID(lm->lightmap_texture)) { - extern cvar_t gl_lightmap_nearest; - TEXASSIGN(lm->lightmap_texture, Image_CreateTexture(va("***lightmap %i***", lmidx), NULL, (gl_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR)|IF_NOMIPMAP)); + extern cvar_t r_lightmap_nearest; + TEXASSIGN(lm->lightmap_texture, Image_CreateTexture(va("***lightmap %i***", lmidx), NULL, (r_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR)|IF_NOMIPMAP)); qglGenTextures(1, &lm->lightmap_texture->num); GL_MTBind(0, GL_TEXTURE_2D, lm->lightmap_texture); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - qglTexImage2D(GL_TEXTURE_2D, 0, internalformat, lm->width, lm->height, 0, glformat, gltype, lm->lightmaps); + qglTexImage2D(GL_TEXTURE_2D, 0, gl_config.formatinfo[lightmap_fmt].internalformat, lm->width, lm->height, 0, gl_config.formatinfo[lightmap_fmt].format, gl_config.formatinfo[lightmap_fmt].type, lm->lightmaps); + + if (gl_config.glversion >= (gl_config.gles?3.0:3.3)) + { + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, gl_config.formatinfo[lightmap_fmt].swizzle_r); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, gl_config.formatinfo[lightmap_fmt].swizzle_g); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, gl_config.formatinfo[lightmap_fmt].swizzle_b); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, gl_config.formatinfo[lightmap_fmt].swizzle_a); + } } else { GL_MTBind(0, GL_TEXTURE_2D, lm->lightmap_texture); - qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, t, lm->width, b-t, glformat, gltype, lm->lightmaps+t*lm->width*lightmap_bytes); + qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, t, lm->width, b-t, gl_config.formatinfo[lightmap_fmt].format, gl_config.formatinfo[lightmap_fmt].type, lm->lightmaps+t*lm->width*lightmap_bytes); } lm->modified = false; lm->rectchange.l = lm->width; @@ -5839,7 +5852,7 @@ void GLBE_DrawLightPrePass(void) { //gles3 ifmt = GL_RGBA16F_ARB; dfmt = GL_RGBA; - dtype = GL_FLOAT; + dtype = GL_HALF_FLOAT; } else ifmt = GL_RGBA16F_ARB; @@ -6118,7 +6131,7 @@ void GLBE_DrawWorld (batch_t **worldbatches) RSpeedEnd(RSPEED_TRANSPARENTS); #ifndef GLSLONLY - if (r_refdef.globalfog.density && !gl_config.arb_shader_objects) + if (r_refdef.globalfog.density && (!gl_config.arb_shader_objects || !r_fog_permutation.ival)) { //fixed function-only. with global fog. that means we need to hack something in. //FIXME: should really be doing this on a per-shader basis, for custom shaders that don't use glsl BE_SelectMode(BEM_FOG); diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index e3721b9e..cf0906be 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -43,6 +43,8 @@ static int gl_filter_mip[3]; //everything else int gl_mipcap_min = 0; int gl_mipcap_max = 1000; +void Image_WriteKTXFile(const char *filename, struct pendingtextureinfo *mips); + void GL_DestroyTexture(texid_t tex) { if (!tex) @@ -52,6 +54,326 @@ void GL_DestroyTexture(texid_t tex) tex->num = 0; } +#define glfmtsw(qfmt,sz,in,fm,ty,cf,sr,sg,sb,sa) \ + do { \ + gl_config.formatinfo[qfmt].sizedformat = sz; \ + gl_config.formatinfo[qfmt].cformat = cf; \ + gl_config.formatinfo[qfmt].internalformat = in; \ + gl_config.formatinfo[qfmt].format = fm; \ + gl_config.formatinfo[qfmt].type = ty; \ + gl_config.formatinfo[qfmt].swizzle_r = sr; \ + gl_config.formatinfo[qfmt].swizzle_g = sg; \ + gl_config.formatinfo[qfmt].swizzle_b = sb; \ + gl_config.formatinfo[qfmt].swizzle_a = sa; \ + sh_config.texfmt[qfmt] = true; \ + } while(0) + +#define glfmt(qfmt,sz,in,fm,ty) glfmtsw(qfmt, sz, in, fm, ty, 0, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA) +#define glfmtc(qfmt,sz,in,fm,ty,cf) glfmtsw(qfmt, sz, in, fm, ty, cf, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA) +#define glfmtb(qfmt,in) glfmtsw(qfmt, in, in, 0, 0, 0, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA) + +#ifndef GL_RGB565 +#define GL_RGB565 0x8D62 +#endif + +void GL_SetupFormats(void) +{ + int tc_ru = 0, tc_rs = 0, tc_rgu = 0, tc_rgs = 0, tc_rgb = 0, tc_rgba1 = 0, tc_rgba8 = 0, tc_srgb = 0, tc_srgba8 = 0; + + qboolean bc1=false, bc2=false, bc3=false, bc45=false, bc67=false; + float ver = gl_config.glversion; + qboolean srgb = (gl_config.glversion >= (gl_config_gles?3.0:2.1)) || GL_CheckExtension("GL_EXT_texture_sRGB"); + + if (gl_config_gles && ver >= 3.0 && ver <= 3.3) + ver = 3.3; //treat gles3.0 as desktop 3.3, they're roughly equivelent in feature set. + + if (GL_CheckExtension("GL_EXT_texture_compression_s3tc")) + bc1=bc2=bc3=true; + if ((!gl_config_gles && ver >= 3.0) || GL_CheckExtension("GL_ARB_texture_compression_rgtc") || GL_CheckExtension("GL_EXT_texture_compression_rgtc")) + bc45 = true; + if ((!gl_config.gles && ver >= 4.2) || GL_CheckExtension("GL_ARB_texture_compression_bptc")) + bc67 = true; + + if (bc45) + tc_ru = GL_COMPRESSED_RED_RGTC1; + if (bc45) + tc_rs = GL_COMPRESSED_SIGNED_RED_RGTC1; + if (bc45) + tc_rgu = GL_COMPRESSED_RG_RGTC2; + if (bc45) + tc_rgs = GL_COMPRESSED_SIGNED_RG_RGTC2; + + if (bc1) + tc_rgb = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + if (bc1) + tc_srgb = GL_COMPRESSED_SRGB_S3TC_DXT1_EXT; + if (bc3) + tc_rgba8 = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + if (bc3) + tc_srgba8 = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; + if (bc1) + tc_rgba1 = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; +// if (bc1) +// tc_srgba1 = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; + + bc1 |= GL_CheckExtension("GL_EXT_texture_compression_dxt1"); + bc2 |= GL_CheckExtension("GL_ANGLE_texture_compression_dxt3"); + bc3 |= GL_CheckExtension("GL_ANGLE_texture_compression_dxt5"); + + /*else if (sh_config.texfmt[PTI_ETC2_RGB8A8]) + { //these are probably a bad choice... + tc_ru = GL_COMPRESSED_R11_EAC; + tc_rgu = GL_COMPRESSED_RG11_EAC; + tc_rgb = GL_COMPRESSED_RGB8_ETC2; + tc_rgba = GL_COMPRESSED_RGBA8_ETC2_EAC; + }*/ + +#ifdef FTE_TARGET_WEB + glfmt(PTI_WHOLEFILE, 0, 0, 0, 0); +// sh_config.texfmt[PTI_WHOLEFILE] = true; +#endif + + if (gl_config_gles) + { + //pre-3 gles doesn't support sized formats, and only a limited number of them too + glfmtc(PTI_RGB8, GL_RGB, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, tc_rgb); + glfmtc(PTI_RGBA8, GL_RGBA, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, tc_rgba8); + glfmt(PTI_L8A8, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE); + glfmt(PTI_L8, GL_LUMINANCE, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE); +// glfmt(PTI_RGBA8, GL_ALPHA, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE); + + if (!gl_config.webgl_ie) + { //these should work on all gles2+webgl1 devices, but microsoft doesn't give a shit. + glfmtc(PTI_RGB565, GL_RGB, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, tc_rgb); +// glfmtc(PTI_RGBA4444,GL_RGBA, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, tc_rgba8); +// glfmtc(PTI_RGBA5551,GL_RGBA, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, tc_rgba1); + } + if (GL_CheckExtension("GL_OES_texture_half_float")) + glfmtc(PTI_RGBA16F, GL_RGBA, GL_RGBA, GL_RGBA, GL_HALF_FLOAT_OES, 0); //not to be confused with GL_HALF_FLOAT[_ARB] which has a different value + if (GL_CheckExtension("GL_OES_texture_float")) + glfmtc(PTI_RGBA32F, GL_RGBA, GL_RGBA, GL_RGBA, GL_FLOAT, 0); + + if (GL_CheckExtension("GL_OES_depth_texture")) + { //16+32, not 24. + glfmt(PTI_DEPTH16, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT); + glfmt(PTI_DEPTH32, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT); + } + + if (GL_CheckExtension("GL_EXT_texture_format_BGRA8888")) + glfmtc(PTI_BGRA8, GL_BGRA_EXT, GL_BGRA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE, tc_rgba8); + if (GL_CheckExtension("GL_EXT_texture_type_2_10_10_10_REV")) + glfmtc(PTI_BGRA8, GL_RGBA, GL_RGBA, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, tc_rgba8); + } + if (!gl_config_gles || ver >= 3.0) + { + if (ver >= 1.4 || GL_CheckExtension("GL_ARB_depth_texture")) + { //depth formats + glfmt(PTI_DEPTH16, GL_DEPTH_COMPONENT16_ARB, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT); + glfmt(PTI_DEPTH24, GL_DEPTH_COMPONENT24_ARB, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT/*FIXME*/); + if (gl_config_gles)// || ver >= 3.0) + glfmt(PTI_DEPTH32, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_FLOAT); + else + glfmt(PTI_DEPTH32, GL_DEPTH_COMPONENT32_ARB, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_FLOAT); + } +// if (ver >= 3.0) +// glfmt(PTI_DEPTH32, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_FLOAT); + if (GL_CheckExtension("GL_EXT_packed_depth_stencil")) + glfmt(PTI_DEPTH24_8,GL_DEPTH24_STENCIL8_EXT, GL_DEPTH_STENCIL_EXT, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT); + + glfmtc(PTI_RGBA8, GL_RGBA8, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, tc_rgba8); + if (srgb) + glfmtc(PTI_RGBA8_SRGB, GL_SRGB8_ALPHA8_EXT,GL_SRGB_ALPHA_EXT, GL_RGBA, GL_UNSIGNED_BYTE, tc_srgba8); + if (!gl_config_gles) + { + if (ver >= 3.3) //I'm paranoid about performance, so lets swizzle the alpha to 1 to make the alignment explicit. + glfmtsw(PTI_RGBX8, GL_RGBA8, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, tc_rgb, GL_RED, GL_GREEN, GL_BLUE, GL_ONE); + else + glfmtc(PTI_RGBX8, GL_RGB8, GL_RGB, GL_RGBA, GL_UNSIGNED_BYTE, tc_rgb); + if (srgb) + glfmtc(PTI_RGBX8_SRGB, GL_SRGB8_EXT, GL_SRGB_EXT, GL_RGBA, GL_UNSIGNED_BYTE, tc_srgb); + } + if (ver >= 1.2 && !gl_config_gles) + { + glfmt(PTI_BGR8, GL_RGB8, GL_RGB, GL_BGR_EXT, GL_UNSIGNED_BYTE); + glfmtc(PTI_BGRX8, GL_RGB8, GL_RGB, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, tc_rgb); + glfmtc(PTI_BGRA8, GL_RGBA8, GL_RGBA, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, tc_rgba8); + if (srgb) + { + glfmtc(PTI_BGRX8_SRGB, GL_SRGB8_EXT, GL_SRGB_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE, tc_srgb); + glfmtc(PTI_BGRA8_SRGB, GL_SRGB8_ALPHA8_EXT,GL_SRGB_ALPHA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE, tc_srgba8); + } + } + else if (ver >= 3.3) + { + glfmtsw(PTI_BGR8, GL_RGB8, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, 0, GL_BLUE, GL_GREEN, GL_RED, GL_ONE); + glfmtsw(PTI_BGRX8, GL_RGB8, GL_RGB, GL_RGBA, GL_UNSIGNED_BYTE, tc_rgb, GL_BLUE, GL_GREEN, GL_RED, GL_ONE); + glfmtsw(PTI_BGRA8, GL_RGBA8, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, tc_rgba8, GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA); + if (srgb) + { + glfmtc(PTI_BGRX8_SRGB, GL_SRGB8_EXT, GL_SRGB_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE, tc_srgb); + glfmtc(PTI_BGRA8_SRGB, GL_SRGB8_ALPHA8_EXT,GL_SRGB_ALPHA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE, tc_srgba8); + } + } + if (ver >= 3.0 || GL_CheckExtension("GL_EXT_texture_shared_exponent")) + glfmt(PTI_E5BGR9, GL_RGB9_E5, GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV); + if (ver >= 3.0 || GL_CheckExtension("GL_EXT_packed_pixels")) //so gl1.2 then. + glfmt(PTI_A2BGR10, GL_RGB10_A2, GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV); + if (ver >= 3.0 || GL_CheckExtension("GL_ARB_texture_rg")) + { + glfmtc(PTI_R8, GL_R8, GL_RED, GL_RED, GL_UNSIGNED_BYTE, tc_ru); + glfmtc(PTI_RG8, GL_RG8, GL_RG, GL_RG, GL_UNSIGNED_BYTE, tc_rs); + } + if (ver >= 3.1 || (GL_CheckExtension("GL_EXT_texture_snorm") && GL_CheckExtension("GL_ARB_texture_rg"))) + { + glfmtc(PTI_R8_SNORM, GL_R8_SNORM, GL_R8_SNORM, GL_RED, GL_BYTE, tc_rgu); + glfmtc(PTI_RG8_SNORM, GL_RG8_SNORM, GL_RG8_SNORM, GL_RG, GL_BYTE, tc_rgs); + } + + if (ver >= 3.0) + { + glfmtc(PTI_RGBA16F, GL_RGBA16F_ARB, GL_RGBA, GL_RGBA, GL_HALF_FLOAT, 0); + glfmtc(PTI_RGBA32F, GL_RGBA32F_ARB, GL_RGBA, GL_RGBA, GL_FLOAT, 0); + } + if (ver >= 1.2 && !gl_config_gles) + { + glfmtc(PTI_RGBA4444, GL_RGBA4, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, tc_srgba8); + glfmtc(PTI_RGBA5551, GL_RGB5_A1, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, tc_rgba1); + + glfmtc(PTI_ARGB4444, GL_RGBA4, GL_RGBA, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV, tc_srgba8); + glfmtc(PTI_ARGB1555, GL_RGB5_A1, GL_RGBA, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV, tc_rgba1); + } + if (gl_config_gles || ver > 4.1) //rgb565 was a gles thing, desktop gl just has a 555 internal format despite the 565 data... + glfmtc(PTI_RGB565, GL_RGB565, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, tc_rgb); + else + glfmtc(PTI_RGB565, GL_RGB5, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, tc_rgb); + glfmt(PTI_RGB8, GL_RGB8, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE); + if (!gl_config_nofixedfunc) + { //if we have fixed function, then we still have proper support. the driver can emulate with swizzles if it wants. + glfmtc(PTI_L8, GL_LUMINANCE8, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE, tc_ru); + glfmtc(PTI_L8A8, GL_LUMINANCE8_ALPHA8,GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, tc_rgu); + } + else if (ver >= 3.3) + { //can emulate them with swizzles. + glfmtsw(PTI_L8, GL_R8, GL_RED, GL_RED, GL_UNSIGNED_BYTE, tc_ru, GL_RED, GL_RED, GL_RED, GL_ONE); + glfmtsw(PTI_L8A8, GL_RG8, GL_RG, GL_RG, GL_UNSIGNED_BYTE, tc_rgu, GL_RED, GL_RED, GL_RED, GL_GREEN); + } + } + + //block compresion formats. + if (bc1) + { + glfmtb(PTI_BC1_RGB, GL_COMPRESSED_RGB_S3TC_DXT1_EXT); + glfmtb(PTI_BC1_RGBA, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT); + if (srgb) + { + glfmtb(PTI_BC1_RGB_SRGB, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT); + glfmtb(PTI_BC1_RGBA_SRGB, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT); + } + } + if (bc2) + { + glfmtb(PTI_BC2_RGBA, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT); + if (srgb) + glfmtb(PTI_BC2_RGBA_SRGB, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT); + } + if (bc3) + { + glfmtb(PTI_BC3_RGBA, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT); + if (srgb) + glfmtb(PTI_BC3_RGBA_SRGB, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT); + } + if (bc45) + { + glfmtb(PTI_BC4_R8, GL_COMPRESSED_RED_RGTC1); + glfmtb(PTI_BC4_R8_SNORM, GL_COMPRESSED_SIGNED_RED_RGTC1); + glfmtb(PTI_BC5_RG8, GL_COMPRESSED_RG_RGTC2); + glfmtb(PTI_BC5_RG8_SNORM, GL_COMPRESSED_SIGNED_RG_RGTC2); + } + if (bc67) + { + glfmtb(PTI_BC6_RGB_UFLOAT, GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB); + glfmtb(PTI_BC6_RGB_SFLOAT, GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB); + glfmtb(PTI_BC7_RGBA, GL_COMPRESSED_RGBA_BPTC_UNORM_ARB); + glfmtb(PTI_BC7_RGBA_SRGB, GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB); + } + +#ifdef FTE_TARGET_WEB + if (GL_CheckExtension("WEBGL_compressed_texture_etc")) +#else + if ((gl_config.gles && gl_config.glversion >= 3.0) || (!gl_config.gles && (gl_config.glversion >= 4.3 || GL_CheckExtension("GL_ARB_ES3_compatibility")))) +#endif + { + glfmtb(PTI_ETC1_RGB8, GL_COMPRESSED_RGB8_ETC2); + glfmtb(PTI_ETC2_RGB8, GL_COMPRESSED_RGB8_ETC2); + glfmtb(PTI_ETC2_RGB8A1, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2); + glfmtb(PTI_ETC2_RGB8A8, GL_COMPRESSED_RGBA8_ETC2_EAC); + glfmtb(PTI_ETC2_RGB8_SRGB, GL_COMPRESSED_SRGB8_ETC2); + glfmtb(PTI_ETC2_RGB8A1_SRGB, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2); + glfmtb(PTI_ETC2_RGB8A8_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC); + glfmtb(PTI_EAC_R11, GL_COMPRESSED_R11_EAC); + glfmtb(PTI_EAC_R11_SNORM, GL_COMPRESSED_SIGNED_R11_EAC); + glfmtb(PTI_EAC_RG11, GL_COMPRESSED_RG11_EAC); + glfmtb(PTI_EAC_RG11_SNORM, GL_COMPRESSED_SIGNED_RG11_EAC); + } + else + { + if (GL_CheckExtension("GL_OES_compressed_ETC1_RGB8_texture")) + glfmtb(PTI_ETC1_RGB8, GL_ETC1_RGB8_OES); + if (GL_CheckExtension("GL_OES_compressed_ETC2_RGB8_texture")) + glfmtb(PTI_ETC2_RGB8, GL_COMPRESSED_RGB8_ETC2); + if (GL_CheckExtension("GL_OES_compressed_ETC2_sRGB8_texture")) + glfmtb(PTI_ETC2_RGB8_SRGB, GL_COMPRESSED_SRGB8_ETC2); + if (GL_CheckExtension("GL_OES_compressed_ETC2_punchthroughA_RGBA8_texture")) + glfmtb(PTI_ETC2_RGB8A1, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2); + if (GL_CheckExtension("GL_OES_compressed_ETC2_punchthroughA_sRGB8_alpha_texture")) + glfmtb(PTI_ETC2_RGB8A1_SRGB, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2); + if (GL_CheckExtension("GL_OES_compressed_ETC2_RGBA8_texture")) + glfmtb(PTI_ETC2_RGB8A8, GL_COMPRESSED_RGBA8_ETC2_EAC); + if (GL_CheckExtension("GL_OES_compressed_ETC2_sRGB8_alpha8_texture")) + glfmtb(PTI_ETC2_RGB8A8_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC); + if (GL_CheckExtension("GL_OES_compressed_EAC_R11_unsigned_texture")) + glfmtb(PTI_EAC_R11, GL_COMPRESSED_R11_EAC); + if (GL_CheckExtension("GL_OES_compressed_EAC_R11_signed_texture")) + glfmtb(PTI_EAC_R11_SNORM, GL_COMPRESSED_SIGNED_R11_EAC); + if (GL_CheckExtension("GL_OES_compressed_EAC_RG11_unsigned_texture")) + glfmtb(PTI_EAC_RG11, GL_COMPRESSED_RG11_EAC); + if (GL_CheckExtension("GL_OES_compressed_EAC_RG11_signed_texture")) + glfmtb(PTI_EAC_RG11_SNORM, GL_COMPRESSED_SIGNED_RG11_EAC); + } + + if (GL_CheckExtension("GL_KHR_texture_compression_astc_ldr") || (gl_config_gles && gl_config.glversion >= 3.2)) + { //astc ldr profile is a core part of gles 3.2 + glfmtb(PTI_ASTC_4X4, GL_COMPRESSED_RGBA_ASTC_4x4_KHR); + glfmtb(PTI_ASTC_4X4_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR); + glfmtb(PTI_ASTC_5X4, GL_COMPRESSED_RGBA_ASTC_5x4_KHR); + glfmtb(PTI_ASTC_5X4_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR); + glfmtb(PTI_ASTC_5X5, GL_COMPRESSED_RGBA_ASTC_5x5_KHR); + glfmtb(PTI_ASTC_5X5_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR); + glfmtb(PTI_ASTC_6X5, GL_COMPRESSED_RGBA_ASTC_6x5_KHR); + glfmtb(PTI_ASTC_6X5_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR); + glfmtb(PTI_ASTC_6X6, GL_COMPRESSED_RGBA_ASTC_6x6_KHR); + glfmtb(PTI_ASTC_6X6_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR); + glfmtb(PTI_ASTC_8X5, GL_COMPRESSED_RGBA_ASTC_8x5_KHR); + glfmtb(PTI_ASTC_8X5_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR); + glfmtb(PTI_ASTC_8X6, GL_COMPRESSED_RGBA_ASTC_8x6_KHR); + glfmtb(PTI_ASTC_8X6_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR); + glfmtb(PTI_ASTC_10X5, GL_COMPRESSED_RGBA_ASTC_10x5_KHR); + glfmtb(PTI_ASTC_10X5_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR); + glfmtb(PTI_ASTC_10X6, GL_COMPRESSED_RGBA_ASTC_10x6_KHR); + glfmtb(PTI_ASTC_10X6_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR); + glfmtb(PTI_ASTC_8X8, GL_COMPRESSED_RGBA_ASTC_8x8_KHR); + glfmtb(PTI_ASTC_8X8_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR); + glfmtb(PTI_ASTC_10X8, GL_COMPRESSED_RGBA_ASTC_10x8_KHR); + glfmtb(PTI_ASTC_10X8_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR); + glfmtb(PTI_ASTC_10X10, GL_COMPRESSED_RGBA_ASTC_10x10_KHR); + glfmtb(PTI_ASTC_10X10_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR); + glfmtb(PTI_ASTC_12X10, GL_COMPRESSED_RGBA_ASTC_12x10_KHR); + glfmtb(PTI_ASTC_12X10_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR); + glfmtb(PTI_ASTC_12X12, GL_COMPRESSED_RGBA_ASTC_12x12_KHR); + glfmtb(PTI_ASTC_12X12_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR); + } +} + /* =============== Draw_Init @@ -59,6 +381,32 @@ Draw_Init */ void GLDraw_Init (void) { + extern cvar_t scr_showloading; + extern cvar_t vid_srgb; + if ((vid.flags & VID_SRGB_CAPABLE) && gl_config.arb_framebuffer_srgb) + { //srgb-capable + if (!vid_srgb.ival) + { //srgb not wanted... + qglDisable(GL_FRAMEBUFFER_SRGB); + vid.flags &= ~VID_SRGB_FB_LINEAR; + } + else if (vid_srgb.ival > 1) + { //full srgb wanted + qglEnable(GL_FRAMEBUFFER_SRGB); + vid.flags |= VID_SRGB_FB_LINEAR; + } + else + { //srgb wanted only for the framebuffer, for gamma tricks. + vid.flags |= VID_SRGB_FB_LINEAR; + qglEnable(GL_FRAMEBUFFER_SRGB); + } + } + if ((vid.flags & VID_SRGB_FB) && vid_srgb.ival != 1) + vid.flags |= VID_SRGBAWARE; + else + vid.flags &= ~VID_SRGBAWARE; + + //figure out which extra features we can support on these drivers. r_deluxmapping = r_deluxmapping_cvar.ival; r_lightprepass = r_lightprepass_cvar.ival && sh_config.progs_supported; @@ -66,33 +414,30 @@ void GLDraw_Init (void) if (gl_config.gles && gl_config.glversion < 3.0) r_softwarebanding = false; - if (gl_config.arb_framebuffer_srgb) - { - extern cvar_t vid_srgb; - vid.srgb = vid_srgb.ival>1; - if (vid.srgb) - qglEnable(GL_FRAMEBUFFER_SRGB); - } - else - vid.srgb = false; + GL_SetupFormats(); R2D_Init(); qglDisable(GL_SCISSOR_TEST); GL_Set2D(false); - qglClearColor(0, 0, 0, 1); - qglClear(GL_COLOR_BUFFER_BIT); + if (scr_showloading.ival) { mpic_t *pic = R2D_SafeCachePic ("gfx/loading.lmp"); - if (pic) - R2D_ScalePic ( ((int)vid.width - pic->width)/2, - ((int)vid.height - 48 - pic->height)/2, pic->width, pic->height, pic); - } + if (pic && R_GetShaderSizes(pic, NULL, NULL, true)) + { //if its too big for the screen, letterbox it. + qglClearColor(0, 0, 0, 1); + qglClear(GL_COLOR_BUFFER_BIT); + if (pic->width > vid.width || pic->height > vid.height) + R2D_Letterbox(0, 0, vid.width, vid.height, pic, pic->width, pic->height); + else //otherwise draw it centred + R2D_ScalePic ( ((int)vid.width - pic->width)/2, ((int)vid.height - 48 - pic->height)/2, pic->width, pic->height, pic); + } - if (R2D_Flush) - R2D_Flush(); - VID_SwapBuffers(); + if (R2D_Flush) + R2D_Flush(); + VID_SwapBuffers(); + } GL_SetupSceneProcessingTextures(); @@ -128,9 +473,10 @@ void GLDraw_DeInit (void) #ifdef RTLIGHTS Sh_Shutdown(); #endif - Shader_Shutdown(); GLBE_Shutdown(); //to release its images. + Shader_Shutdown(); + Image_Shutdown(); } @@ -281,7 +627,6 @@ static void GL_Texturemode_Apply(GLenum targ, unsigned int flags) qglTexParameterf(targ, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1); } } - qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips) { static int cubeface[] = @@ -294,9 +639,9 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips) GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB }; int targ, targface; - int i, j; + int i, j, ifmt; int nummips = mips->mipcount; - int encoding = mips->encoding; + uploadfmt_t encoding = mips->encoding; qboolean compress; @@ -311,9 +656,6 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips) if (encoding == PTI_BGRX8) encoding = PTI_BGRA8; } - - if (!tex->num) - qglGenTextures(1, &tex->num); switch((tex->flags & IF_TEXTYPE) >> IF_TEXTYPESHIFT) { @@ -327,10 +669,27 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips) case 2: targ = GL_TEXTURE_CUBE_MAP_ARB; break; + case 3: + targ = GL_TEXTURE_2D_ARRAY; + break; } GL_MTBind(0, targ, tex); + if (tex->num && qglTexStorage2D) + { + qglDeleteTextures(1, &tex->num); + qglGenTextures(1, &tex->num); + GL_MTBind(0, targ, tex); + qglBindTexture (targ, tex->num); //GL_MTBind caches, which is problematic when things are getting deleted. + } + else + { + if (!tex->num) + qglGenTextures(1, &tex->num); + GL_MTBind(0, targ, tex); + } + if (tex->flags&IF_CLAMP) { if (gl_config.glversion < 1.2 && !gl_config_gles) @@ -394,265 +753,225 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips) // tex->width = mips->mip[0].width; // tex->height = mips->mip[0].height; GL_Texturemode_Apply(targ, tex->flags); - if (targ == GL_TEXTURE_3D) + +#ifdef FTE_TARGET_WEB + if (encoding == PTI_WHOLEFILE) { - targface = targ; - for (i = 0; i < nummips; i++) + emscriptenfte_gl_loadtexturefile(tex->num, &tex->width, &tex->height, mips->mip[i].data, mips->mip[i].datasize); + return true; + } +#endif + + //arb_texture_compression is core in gl1.3 + //gles doesn't support autocompression as of gles3. + //only autocompress if we have actually have data (gl errors otherwise). + if (gl_config.arb_texture_compression && mips->mip[0].data && !(tex->flags & IF_RENDERTARGET)) + compress = !!gl_compress.ival; + else + compress = false; + if (compress & gl_config.formatinfo[encoding].cformat) + ifmt = gl_config.formatinfo[encoding].cformat; + else + ifmt = gl_config.formatinfo[encoding].sizedformat; + + if (!ifmt) + return false; + + if (gl_config.formatinfo[encoding].swizzle_r != GL_RED || gl_config.formatinfo[encoding].swizzle_g != GL_GREEN || + gl_config.formatinfo[encoding].swizzle_b != GL_BLUE || gl_config.formatinfo[encoding].swizzle_a != GL_ALPHA) + { + qglTexParameteri(targ, GL_TEXTURE_SWIZZLE_R, gl_config.formatinfo[encoding].swizzle_r); + qglTexParameteri(targ, GL_TEXTURE_SWIZZLE_G, gl_config.formatinfo[encoding].swizzle_g); + qglTexParameteri(targ, GL_TEXTURE_SWIZZLE_B, gl_config.formatinfo[encoding].swizzle_b); + qglTexParameteri(targ, GL_TEXTURE_SWIZZLE_A, gl_config.formatinfo[encoding].swizzle_a); + } + + if (targ == GL_TEXTURE_3D || targ == GL_TEXTURE_2D_ARRAY) + { + //FIXME: support array textures properly + if (qglTexStorage3D) { - int size = mips->mip[i].height; - switch(encoding) + if (tex->flags & IF_TEXTYPE) + qglTexStorage3D(targ, nummips/countof(cubeface), ifmt, mips->mip[0].width, mips->mip[0].height, mips->mip[0].depth); + else + qglTexStorage3D(targ, nummips, ifmt, mips->mip[0].width, mips->mip[0].height, mips->mip[0].depth); + + for (i = 0; i < nummips; i++) { - case PTI_RGBX8: - qglTexImage3D(targface, i, GL_RGB, size, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, mips->mip[i].data); - break; - case PTI_RGBA8: - qglTexImage3D(targface, i, GL_RGBA, size, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, mips->mip[i].data); - break; - case PTI_BGRX8: - qglTexImage3D(targface, i, GL_RGB, size, size, size, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data); - break; - default: - case PTI_BGRA8: - qglTexImage3D(targface, i, GL_RGBA, size, size, size, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data); - break; - case PTI_RGBA4444: - qglTexImage3D(targface, i, GL_RGBA, size, size, size, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, mips->mip[i].data); - break; - case PTI_RGBA5551: - qglTexImage3D(targface, i, GL_RGBA, size, size, size, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, mips->mip[i].data); - break; - case PTI_RGB565: - qglTexImage3D(targface, i, GL_RGB, size, size, size, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, mips->mip[i].data); - break; + if (!mips->mip[i].data) //already specified by gltexstorage + continue; + + if (gl_config.formatinfo[encoding].type) + qglTexSubImage3D (targ, i, 0, 0, 0, mips->mip[i].width, mips->mip[i].height, mips->mip[0].depth, gl_config.formatinfo[encoding].format, gl_config.formatinfo[encoding].type, mips->mip[i].data); + else + qglCompressedTexSubImage3D (targ, i, 0, 0, 0, mips->mip[i].width, mips->mip[i].height, mips->mip[0].depth, ifmt, mips->mip[i].datasize, mips->mip[i].data); + } + } + else + { + for (i = 0; i < nummips; i++) + { + if (gl_config.formatinfo[encoding].type) + qglTexImage3D (targ, i, ifmt, mips->mip[i].width, mips->mip[i].height, mips->mip[0].depth, 0, gl_config.formatinfo[encoding].format, gl_config.formatinfo[encoding].type, mips->mip[i].data); + else + qglCompressedTexImage3DARB (targ, i, ifmt, mips->mip[i].width, mips->mip[i].height, mips->mip[0].depth, 0, mips->mip[i].datasize, mips->mip[i].data); } } } else { - //2d or cubemaps - for (i = 0; i < nummips; i++) - { - //arb_texture_compression is core in gl1.3 - //gles doesn't support autocompression as of gles3. - //only autocompress if we have actually have data (gl errors otherwise). - if (gl_config.arb_texture_compression && mips->mip[i].data) - compress = !!gl_compress.ival; - else - compress = false; - + if (qglTexStorage2D) + { //FIXME: destroy the old texture if (tex->flags & IF_TEXTYPE) - { - targface = cubeface[i%countof(cubeface)]; - j = i/countof(cubeface); - } + qglTexStorage2D(targ, nummips/countof(cubeface), ifmt, mips->mip[0].width, mips->mip[0].height); else + qglTexStorage2D(targ, nummips, ifmt, mips->mip[0].width, mips->mip[0].height); + + for (i = 0; i < nummips; i++) { - targface = targ; - j = i; - } - switch(encoding) - { - case PTI_WHOLEFILE: - case PTI_MAX: -#ifdef FTE_TARGET_WEB - if (!i) - emscriptenfte_gl_loadtexturefile(tex->num, &tex->width, &tex->height, mips->mip[i].data, mips->mip[i].datasize); -#endif - break; - case PTI_DEPTH16: - qglTexImage2D(targface, j, gl_config.gles?GL_DEPTH_COMPONENT:GL_DEPTH_COMPONENT16_ARB, mips->mip[i].width, mips->mip[i].height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, mips->mip[i].data); - break; - case PTI_DEPTH24: - qglTexImage2D(targface, j, gl_config.gles?GL_DEPTH_COMPONENT:GL_DEPTH_COMPONENT24_ARB, mips->mip[i].width, mips->mip[i].height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, mips->mip[i].data); - break; - case PTI_DEPTH32: - qglTexImage2D(targface, j, gl_config.gles?GL_DEPTH_COMPONENT:GL_DEPTH_COMPONENT32_ARB, mips->mip[i].width, mips->mip[i].height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, mips->mip[i].data); - break; - case PTI_DEPTH24_8: - qglTexImage2D(targface, j, GL_DEPTH24_STENCIL8_EXT, mips->mip[i].width, mips->mip[i].height, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, mips->mip[i].data); - break; - //32bit formats - case PTI_RGBX8: - qglTexImage2D(targface, j, compress?GL_COMPRESSED_RGB_ARB:GL_RGB, mips->mip[i].width, mips->mip[i].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, mips->mip[i].data); - break; - case PTI_RGBA8: - qglTexImage2D(targface, j, compress?GL_COMPRESSED_RGBA_ARB:GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, mips->mip[i].data); - break; - case PTI_BGRX8: - qglTexImage2D(targface, j, compress?GL_COMPRESSED_RGB_ARB:GL_RGB, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data); - break; - case PTI_BGRA8: - qglTexImage2D(targface, j, compress?GL_COMPRESSED_RGBA_ARB:GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data); - break; - case PTI_RGBX8_SRGB: - qglTexImage2D(targface, j, compress?GL_COMPRESSED_SRGB_EXT:GL_SRGB_EXT, mips->mip[i].width, mips->mip[i].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, mips->mip[i].data); - break; - case PTI_RGBA8_SRGB: - qglTexImage2D(targface, j, compress?GL_COMPRESSED_SRGB_ALPHA_EXT:GL_SRGB_ALPHA_EXT, mips->mip[i].width, mips->mip[i].height, 0, gl_config.gles?GL_SRGB_ALPHA_EXT:GL_RGBA, GL_UNSIGNED_BYTE, mips->mip[i].data); - break; - case PTI_BGRX8_SRGB: - qglTexImage2D(targface, j, compress?GL_COMPRESSED_SRGB_EXT:GL_SRGB_EXT, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data); - break; - case PTI_BGRA8_SRGB: - qglTexImage2D(targface, j, compress?GL_COMPRESSED_SRGB_ALPHA_EXT:GL_SRGB_ALPHA_EXT, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data); - break; - - case PTI_RGBA16F: - qglTexImage2D(targface, j, GL_RGBA16F_ARB, mips->mip[i].width, mips->mip[i].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, mips->mip[i].data); - break; - case PTI_RGBA32F: - qglTexImage2D(targface, j, GL_RGBA32F_ARB, mips->mip[i].width, mips->mip[i].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, mips->mip[i].data); - break; - //16bit formats - case PTI_RGBA4444: - qglTexImage2D(targface, j, compress?GL_COMPRESSED_RGBA_ARB:GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, mips->mip[i].data); - break; - case PTI_RGBA5551: - qglTexImage2D(targface, j, compress?GL_COMPRESSED_RGBA_ARB:GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, mips->mip[i].data); - break; - case PTI_ARGB4444: - qglTexImage2D(targface, j, compress?GL_COMPRESSED_RGBA_ARB:GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV, mips->mip[i].data); - break; - case PTI_ARGB1555: - qglTexImage2D(targface, j, compress?GL_COMPRESSED_RGBA_ARB:GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV, mips->mip[i].data); - break; - case PTI_RGB565: - qglTexImage2D(targface, j, compress?GL_COMPRESSED_RGBA_ARB:GL_RGB, mips->mip[i].width, mips->mip[i].height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, mips->mip[i].data); - break; - - //legacy formats - case PTI_RGB8: -#ifdef GLESONLY - return false; -#else - qglTexImage2D(targface, j, GL_RGB8, mips->mip[i].width, mips->mip[i].height, 0, GL_RGB, GL_UNSIGNED_BYTE, mips->mip[i].data); - break; -#endif - case PTI_LUMINANCE8_ALPHA8: -#ifdef GLESONLY - return false; -#else - qglTexImage2D(targface, j, GL_LUMINANCE8_ALPHA8, mips->mip[i].width, mips->mip[i].height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, mips->mip[i].data); - break; -#endif - //s3tc (desktop) compressed formats - case PTI_BC1_RGB: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - case PTI_BC1_RGBA: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - case PTI_BC2_RGBA: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - case PTI_BC3_RGBA: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - case PTI_BC1_RGB_SRGB: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - case PTI_BC1_RGBA_SRGB: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - case PTI_BC2_RGBA_SRGB: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - case PTI_BC3_RGBA_SRGB: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - //atin/rgtc (desktop) compressed formats (derived from bc3's alpha channel) - case PTI_BC4_R8: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RED_RGTC1, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - case PTI_BC4_R8_SIGNED: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SIGNED_RED_RGTC1, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - case PTI_BC5_RG8: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RG_RGTC2, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - case PTI_BC5_RG8_SIGNED: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SIGNED_RG_RGTC2, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - //bptc desktop formats - case PTI_BC6_RGBF: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - case PTI_BC6_RGBF_SIGNED: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - case PTI_BC7_RGBA: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - case PTI_BC7_RGBA_SRGB: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - //(mobile) compressed formats - case PTI_ETC1_RGB8: - case PTI_ETC2_RGB8: - //etc2 is a superset of etc1. we distinguish only for hardware that cannot recognise etc2's 'invalid' encodings - if (sh_config.texfmt[PTI_ETC2_RGB8]) - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGB8_ETC2, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); + if (tex->flags & IF_TEXTYPE) + { //cubemap face + targface = cubeface[i%countof(cubeface)]; + j = i/countof(cubeface); + } else - qglCompressedTexImage2DARB(targface, j, GL_ETC1_RGB8_OES, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - case PTI_ETC2_RGB8A1: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - case PTI_ETC2_RGB8A8: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA8_ETC2_EAC, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - case PTI_ETC2_RGB8_SRGB: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB8_ETC2, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - case PTI_ETC2_RGB8A1_SRGB: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - case PTI_ETC2_RGB8A8_SRGB: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - case PTI_EAC_R11: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_R11_EAC, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - case PTI_EAC_R11_SIGNED: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SIGNED_R11_EAC, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - case PTI_EAC_RG11: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RG11_EAC, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - case PTI_EAC_RG11_SIGNED: - qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SIGNED_RG11_EAC, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); - break; - //astc variations... - case PTI_ASTC_4X4: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_4x4_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_4X4_SRGB: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_5X4: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_5x4_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_5X4_SRGB: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_5X5: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_5x5_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_5X5_SRGB: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_6X5: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_6x5_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_6X5_SRGB: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_6X6: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_6x6_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_6X6_SRGB: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_8X5: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_8x5_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_8X5_SRGB: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_8X6: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_8x6_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_8X6_SRGB: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_10X5: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_10x5_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_10X5_SRGB: qglCompressedTexImage2DARB(targface, j,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_10X6: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_10x6_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_10X6_SRGB: qglCompressedTexImage2DARB(targface, j,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_8X8: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_8x8_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_8X8_SRGB: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_10X8: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_10x8_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_10X8_SRGB: qglCompressedTexImage2DARB(targface, j,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_10X10: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_10x10_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_10X10_SRGB: qglCompressedTexImage2DARB(targface, j,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_12X10: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_12x10_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_12X10_SRGB: qglCompressedTexImage2DARB(targface, j,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_12X12: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_12x12_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_ASTC_12X12_SRGB: qglCompressedTexImage2DARB(targface, j,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + { //2d + targface = targ; + j = i; + } + + if (!mips->mip[i].data) //already specified by gltexstorage, don't bother wiping it or anything. + continue; + + if (gl_config.formatinfo[encoding].type) + qglTexSubImage2D (targface, j, 0, 0, mips->mip[i].width, mips->mip[i].height, gl_config.formatinfo[encoding].format, gl_config.formatinfo[encoding].type, mips->mip[i].data); + else + qglCompressedTexSubImage2D (targface, j, 0, 0, mips->mip[i].width, mips->mip[i].height, ifmt, mips->mip[i].datasize, mips->mip[i].data); } } + else + { + for (i = 0; i < nummips; i++) + { + if (tex->flags & IF_TEXTYPE) + { //cubemap face + targface = cubeface[i%countof(cubeface)]; + j = i/countof(cubeface); + } + else + { //2d + targface = targ; + j = i; + } + + if (gl_config.formatinfo[encoding].type) + qglTexImage2D (targface, j, ifmt, mips->mip[i].width, mips->mip[i].height, 0, gl_config.formatinfo[encoding].format, gl_config.formatinfo[encoding].type, mips->mip[i].data); + else + qglCompressedTexImage2DARB (targface, j, ifmt, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); + } + } + +#ifdef IMAGEFMT_KTX + if (compress && gl_compress.ival>1 && gl_config.formatinfo[encoding].type) + { + GLint fmt; + GLint csize; + struct pendingtextureinfo out = {mips->type}; + out.type = mips->type; + out.mipcount = mips->mipcount; + out.encoding = 0; + out.extrafree = NULL; + + qglGetTexLevelParameteriv(targ, 0, GL_TEXTURE_INTERNAL_FORMAT, &fmt); + + switch(fmt) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: out.encoding = PTI_BC1_RGB; break; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: out.encoding = PTI_BC1_RGBA; break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: out.encoding = PTI_BC2_RGBA; break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: out.encoding = PTI_BC3_RGBA; break; + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: out.encoding = PTI_BC1_RGB_SRGB; break; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: out.encoding = PTI_BC1_RGBA_SRGB; break; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: out.encoding = PTI_BC2_RGBA_SRGB; break; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: out.encoding = PTI_BC3_RGBA_SRGB; break; + case GL_COMPRESSED_RED_RGTC1: out.encoding = PTI_BC4_R8; break; + case GL_COMPRESSED_SIGNED_RED_RGTC1: out.encoding = PTI_BC4_R8_SNORM; break; + case GL_COMPRESSED_RG_RGTC2: out.encoding = PTI_BC5_RG8; break; + case GL_COMPRESSED_SIGNED_RG_RGTC2: out.encoding = PTI_BC5_RG8_SNORM; break; + case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB: out.encoding = PTI_BC6_RGB_UFLOAT; break; + case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB: out.encoding = PTI_BC6_RGB_SFLOAT; break; + case GL_COMPRESSED_RGBA_BPTC_UNORM_ARB: out.encoding = PTI_BC7_RGBA; break; + case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB: out.encoding = PTI_BC7_RGBA_SRGB; break; + case GL_ETC1_RGB8_OES: out.encoding = PTI_ETC1_RGB8; break; + case GL_COMPRESSED_RGB8_ETC2: out.encoding = PTI_ETC2_RGB8; break; + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: out.encoding = PTI_ETC2_RGB8A1; break; + case GL_COMPRESSED_RGBA8_ETC2_EAC: out.encoding = PTI_ETC2_RGB8A8; break; + case GL_COMPRESSED_SRGB8_ETC2: out.encoding = PTI_ETC2_RGB8_SRGB; break; + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: out.encoding = PTI_ETC2_RGB8A1_SRGB; break; + case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: out.encoding = PTI_ETC2_RGB8A8_SRGB; break; + case GL_COMPRESSED_R11_EAC: out.encoding = PTI_EAC_R11; break; + case GL_COMPRESSED_SIGNED_R11_EAC: out.encoding = PTI_EAC_R11_SNORM; break; + case GL_COMPRESSED_RG11_EAC: out.encoding = PTI_EAC_RG11; break; + case GL_COMPRESSED_SIGNED_RG11_EAC: out.encoding = PTI_EAC_RG11_SNORM; break; + case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: out.encoding = PTI_ASTC_4X4; break; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: out.encoding = PTI_ASTC_4X4_SRGB; break; + case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: out.encoding = PTI_ASTC_5X4; break; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: out.encoding = PTI_ASTC_5X4_SRGB; break; + case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: out.encoding = PTI_ASTC_5X5; break; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: out.encoding = PTI_ASTC_5X5_SRGB; break; + case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: out.encoding = PTI_ASTC_6X5; break; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: out.encoding = PTI_ASTC_6X5_SRGB; break; + case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: out.encoding = PTI_ASTC_6X6; break; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: out.encoding = PTI_ASTC_6X6_SRGB; break; + case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: out.encoding = PTI_ASTC_8X5; break; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: out.encoding = PTI_ASTC_8X5_SRGB; break; + case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: out.encoding = PTI_ASTC_8X6; break; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: out.encoding = PTI_ASTC_8X6_SRGB; break; + case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: out.encoding = PTI_ASTC_10X5; break; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: out.encoding = PTI_ASTC_10X5_SRGB; break; + case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: out.encoding = PTI_ASTC_10X6; break; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: out.encoding = PTI_ASTC_10X6_SRGB; break; + case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: out.encoding = PTI_ASTC_8X8; break; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: out.encoding = PTI_ASTC_8X8_SRGB; break; + case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: out.encoding = PTI_ASTC_10X8; break; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: out.encoding = PTI_ASTC_10X8_SRGB; break; + case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: out.encoding = PTI_ASTC_10X10; break; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: out.encoding = PTI_ASTC_10X10_SRGB; break; + case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: out.encoding = PTI_ASTC_12X10; break; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: out.encoding = PTI_ASTC_12X10_SRGB; break; + case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: out.encoding = PTI_ASTC_12X12; break; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: out.encoding = PTI_ASTC_12X12_SRGB; break; + } + + if (out.encoding) + { + for (i = 0; i < nummips; i++) + { + if (tex->flags & IF_TEXTYPE) + { //cubemap face + targface = cubeface[i%countof(cubeface)]; + j = i/countof(cubeface); + } + else + { //2d + targface = targ; + j = i; + } + + qglGetTexLevelParameteriv(targ, j, GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB, &csize); + out.mip[i].datasize = csize; + out.mip[i].data = BZ_Malloc(csize); + out.mip[i].needfree = true; + out.mip[i].width = mips->mip[i].width; + out.mip[i].height = mips->mip[i].height; + out.mip[i].depth = mips->mip[i].depth; + qglGetCompressedTexImageARB(targ, j, out.mip[i].data); + } + + Image_WriteKTXFile(va("textures/%s.ktx", tex->ident), &out); + } + } +#endif } return true; diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index 8fbd91a0..7c2a30a3 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -329,7 +329,6 @@ static qboolean curfont_scaled; extern cvar_t r_font_linear; - //^Ue2XX static struct { @@ -1855,6 +1854,17 @@ struct font_s *Font_LoadFont(float vheight, const char *fontfilename) } } + if (vid.flags&VID_SRGBAWARE) + { + f->tint[0] = M_SRGBToLinear(f->tint[0], 1); + f->tint[1] = M_SRGBToLinear(f->tint[1], 1); + f->tint[2] = M_SRGBToLinear(f->tint[2], 1); + + f->alttint[0] = M_SRGBToLinear(f->alttint[0], 1); + f->alttint[1] = M_SRGBToLinear(f->alttint[1], 1); + f->alttint[2] = M_SRGBToLinear(f->alttint[2], 1); + } + #ifdef PACKAGE_DOOMWAD if (!*fontfilename) { @@ -2662,6 +2672,13 @@ int Font_DrawChar(int px, int py, unsigned int charflags, unsigned int codepoint rgba[3] = 255; } + if (vid.flags&VID_SRGBAWARE) + { + rgba[0] = M_SRGBToLinear(rgba[0], 255); + rgba[1] = M_SRGBToLinear(rgba[1], 255); + rgba[2] = M_SRGBToLinear(rgba[2], 255); + } + col = (charflags&CON_BGMASK)>>CON_BGSHIFT; if (charflags & CON_NONCLEARBG) { diff --git a/engine/gl/gl_heightmap.c b/engine/gl/gl_heightmap.c index 25f2daec..7153cf33 100644 --- a/engine/gl/gl_heightmap.c +++ b/engine/gl/gl_heightmap.c @@ -5774,9 +5774,43 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e) for (numverts = 0, numindicies = 0; i < hm->numbrushes; i++, br++) { //if a single batch has too many verts, cut it off before it overflows our maximum batch size, and hope we don't get a really really complex brush. - if (numverts > 0xf000 || numindicies > 0xf000) + if (numverts >= 0xf000 || numindicies >= 0xf000) break; + if (br->patch && br->patch->tex == bt && lmnum == -1) + { + int x, y; + index_t r1, r2; + + for (y = 0, r1 = numverts, r2 = 0; y < br->patch->ypoints; y++) + { + for (x = 0; x < br->patch->xpoints; x++, r1++, r2++) + { + VectorCopy(br->patch->verts[r2].v, arrays->coord[r1]); + Vector2Copy(br->patch->verts[r2].tc, arrays->texcoord[r1]); + VectorCopy(br->patch->verts[r2].norm, arrays->normal[r1]); + VectorCopy(br->patch->verts[r2].sdir, arrays->svector[r1]); + VectorCopy(br->patch->verts[r2].tdir, arrays->tvector[r1]); + + Vector2Copy(br->patch->verts[r2].tc, arrays->lmcoord[r1]); + } + } + for (y = 0, r1 = numverts, r2 = r1 + br->patch->xpoints; y < br->patch->ypoints-1; y++) + { + for (x = 0; x < br->patch->xpoints-1; x++, r1++, r2++) + { + arrays->index[numindicies++] = r1; + arrays->index[numindicies++] = r1+1; + arrays->index[numindicies++] = r2; + + arrays->index[numindicies++] = r1+1; + arrays->index[numindicies++] = r2+1; + arrays->index[numindicies++] = r2; + } + r1++; r2++; + } + numverts += br->patch->ypoints*br->patch->xpoints; + } for (j = 0; j < br->numplanes; j++) { if (br->faces[j].tex == bt && !br->selected && br->faces[j].lightmap == lmnum) @@ -6915,27 +6949,58 @@ void QCBUILTIN PF_brush_findinvolume(pubprogfuncs_t *prinst, struct globalvars_s void Terr_WriteBrushInfo(vfsfile_t *file, brushes_t *br) { + //valve 220 format: + //{ //( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname [x y z d] [x y z d] rotation sscale tscale + //} float *point[3]; - int i; + int i, x, y; VFS_PRINTF(file, "\n{"); - for (i = 0; i < br->numplanes; i++) + if (br->patch) { - point[0] = br->faces[i].points[0]; - point[1] = br->faces[i].points[1]; - point[2] = br->faces[i].points[2]; - - //%.9g is 'meant' to be lossless for a standard ieee single-precision float. (%.17g for a double) - VFS_PRINTF(file, "\n( %.9g %.9g %.9g ) ( %.9g %.9g %.9g ) ( %.9g %.9g %.9g ) \"%s\" [ %.9g %.9g %.9g %.9g ] [ %.9g %.9g %.9g %.9g ] 0 1 1", - point[0][0], point[0][1], point[0][2], - point[1][0], point[1][1], point[1][2], - point[2][0], point[2][1], point[2][2], - br->faces[i].tex?br->faces[i].tex->shadername:"", - br->faces[i].stdir[0][0], br->faces[i].stdir[0][1], br->faces[i].stdir[0][2], br->faces[i].stdir[0][3], - br->faces[i].stdir[1][0], br->faces[i].stdir[1][1], br->faces[i].stdir[1][2], br->faces[i].stdir[1][3] - ); + VFS_PRINTF(file, "\n\tpatchDef2\n\t{\n\t\"%s\"\n\t( %.9g %.9g %.9g %.9g %.9g )\n\t(\t\n", + br->patch->tex?br->patch->tex->shadername:"", + 0.0/*xoffset*/, + 0.0/*yoffset*/, + 0.0/*rotation*/, + 1.0/*xscale*/, + 1.0/*yscale*/); + for (y = 0; y < br->patch->ypoints; y++) + { + VFS_PRINTF(file, "\t\t( "); + for (x = 0; x < br->patch->xpoints; x++) + { + VFS_PRINTF(file, "( %.9g %.9g %.9g %.9g %.9g )", br->patch->verts[x + y*br->patch->xpoints].v[0], + br->patch->verts[x + y*br->patch->xpoints].v[1], + br->patch->verts[x + y*br->patch->xpoints].v[2], + br->patch->verts[x + y*br->patch->xpoints].tc[0], + br->patch->verts[x + y*br->patch->xpoints].tc[1]); + } + VFS_PRINTF(file, " )"); + } + VFS_PRINTF(file, " )\n\t}\n"); } + else + { + for (i = 0; i < br->numplanes; i++) + { + point[0] = br->faces[i].points[0]; + point[1] = br->faces[i].points[1]; + point[2] = br->faces[i].points[2]; + + //%.9g is 'meant' to be lossless for a standard ieee single-precision float. (%.17g for a double) + VFS_PRINTF(file, "\n( %.9g %.9g %.9g ) ( %.9g %.9g %.9g ) ( %.9g %.9g %.9g ) \"%s\" [ %.9g %.9g %.9g %.9g ] [ %.9g %.9g %.9g %.9g ] 0 1 1", + point[0][0], point[0][1], point[0][2], + point[1][0], point[1][1], point[1][2], + point[2][0], point[2][1], point[2][2], + br->faces[i].tex?br->faces[i].tex->shadername:"", + br->faces[i].stdir[0][0], br->faces[i].stdir[0][1], br->faces[i].stdir[0][2], br->faces[i].stdir[0][3], + br->faces[i].stdir[1][0], br->faces[i].stdir[1][1], br->faces[i].stdir[1][2], br->faces[i].stdir[1][3] + ); + } + } + VFS_PRINTF(file, "\n}"); } void Terr_WriteMapFile(vfsfile_t *file, model_t *mod) @@ -7219,12 +7284,14 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities) } else if (inbrush && !strcmp(token, "patchDef2")) { + vec5_t pvert[64][64]; + int x, y; entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); - /*validate {*/ + if (strcmp(token, "{")) {Con_Printf(CON_ERROR "%s: invalid patch\n", mod->name);return false;} entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); /*parse texture name*/ entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); - /*validate (*/ + if (strcmp(token, "(")) {Con_Printf(CON_ERROR "%s: invalid patch\n", mod->name);return false;} entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); /*xoffset = atof(token);*/ entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); @@ -7236,46 +7303,53 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities) entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); /*yscale = atof(token);*/ entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); - /*validate )*/ + if (strcmp(token, ")")) {Con_Printf(CON_ERROR "%s: invalid patch\n", mod->name);return false;} entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); - /*validate (*/ + if (strcmp(token, "(")) {Con_Printf(CON_ERROR "%s: invalid patch\n", mod->name);return false;} entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); + y = 0; while (!strcmp(token, "(")) { entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); + x = 0; while (!strcmp(token, "(")) { entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); - //x = atof(token); + pvert[y][x][0] = atof(token); entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); - //y = atof(token); + pvert[y][x][1] = atof(token); entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); - //z = atof(token); + pvert[y][x][2] = atof(token); entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); - //s = atof(token); + pvert[y][x][3] = atof(token); entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); - //t = atof(token); + pvert[y][x][4] = atof(token); entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); - /*validate )*/ + if (strcmp(token, ")")) {Con_Printf(CON_ERROR "%s: invalid patch\n", mod->name);return false;} entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); + if (x < countof(pvert[y])-1) + x++; } - /*validate )*/ + if (strcmp(token, ")")) {Con_Printf(CON_ERROR "%s: invalid patch\n", mod->name);return false;} entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); + if (y < countof(pvert)-1) + y++; } - /*validate )*/ + if (strcmp(token, ")")) {Con_Printf(CON_ERROR "%s: invalid patch\n", mod->name);return false;} entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); - /*validate }*/ + if (strcmp(token, "}")) {Con_Printf(CON_ERROR "%s: invalid patch\n", mod->name);return false;} } else if (inbrush) { //parse a plane - //Quake: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname 0 -32 rotation sscale tscale - //hexen2: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname 0 -32 rotation sscale tscale utterlypointless + //Quake: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname soffset toffset rotation sscale tscale + //hexen2:( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname soffset toffset rotation sscale tscale utterlypointless //Valve: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname [x y z d] [x y z d] rotation sscale tscale //fte : ( px py pz pd ) texname [sx sy sz sd] [tx ty tz td] 0 1 1 - //q3 : (( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) common/caulk common/caulk rotation sscale tscale detailcontents unused unused + //q3 : ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) common/caulk common/caulk rotation sscale tscale detailcontents unused unused + //doom3: brushdef3 { ( px py pz pd ) ( ( x y z ) ( x y z ) ) texture detailcontents unused unused } brushtex_t *bt; vec3_t d1,d2; vec3_t points[3]; @@ -7331,7 +7405,7 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities) else if (!Q_strncasecmp(token, "*sky", 4)) brushcontents = FTECONTENTS_SKY; else if (!Q_strcasecmp(token, "clip")) - brushcontents = FTECONTENTS_PLAYERCLIP; + brushcontents = FTECONTENTS_PLAYERCLIP|FTECONTENTS_MONSTERCLIP; else brushcontents = FTECONTENTS_SOLID; diff --git a/engine/gl/gl_hlmdl.c b/engine/gl/gl_hlmdl.c index 195fe49d..9ee6959a 100644 --- a/engine/gl/gl_hlmdl.c +++ b/engine/gl/gl_hlmdl.c @@ -657,7 +657,7 @@ void HL_SetupBones(hlmodel_t *model, int seqnum, int firstbone, int lastbone, fl if (sequence->hasblendseq>1) { int bf0, bf1; - int bweights; + unsigned int bweights; struct { int frame; @@ -766,6 +766,7 @@ void HL_SetupBones(hlmodel_t *model, int seqnum, int firstbone, int lastbone, fl } if (frame1 != frame2) { + //bweights can be 0-4 here.. for (i = 0; i < bweights; i++) { blend[bweights+i].frame = frame2; diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index be5c2be4..cb8dbaca 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -31,7 +31,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. extern cvar_t r_shadow_bumpscale_basetexture; extern cvar_t r_replacemodels; -extern cvar_t gl_lightmap_average; +extern cvar_t r_lightmap_average; cvar_t mod_loadentfiles = CVAR("sv_loadentfiles", "1"); cvar_t mod_loadentfiles_dir = CVAR("sv_loadentfiles_dir", ""); cvar_t mod_external_vis = CVARD("mod_external_vis", "1", "Attempt to load .vis patches for quake maps, allowing transparent water to work properly."); @@ -1670,15 +1670,17 @@ Mod_LoadLighting void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean interleaveddeluxe, lightmapoverrides_t *overrides) { qboolean luxtmp = true; + qboolean exptmp = true; qboolean littmp = true; - qbyte *luxdata = NULL; - qbyte *litdata = NULL; - qbyte *lumdata = NULL; + qbyte *luxdata = NULL; //rgb8 + qbyte *expdata = NULL; //e5bgr9 (hdr!) + qbyte *litdata = NULL; //xyz8 + qbyte *lumdata = NULL; //l8 qbyte *out; unsigned int samples; extern cvar_t gl_overbright; - loadmodel->engineflags &= ~MDLF_RGBLIGHTING; + loadmodel->lightmaps.fmt = LM_L8; //q3 maps have built in 4-fold overbright. //if we're not rendering with that, we need to brighten the lightmaps in order to keep the darker parts the same brightness. we loose the 2 upper bits. those bright areas become uniform and indistinct. @@ -1687,9 +1689,8 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean gl_overbright.flags |= CVAR_RENDERERLATCH; BuildLightMapGammaTable(1, (1<<(2-gl_overbright.ival))); } - else - //lit file light intensity is made to match the world's light intensity. - BuildLightMapGammaTable(1, 1); + else //lit file light intensity is made to match the world's light intensity. + BuildLightMapGammaTable(1, 1); loadmodel->lightdata = NULL; loadmodel->deluxdata = NULL; @@ -1707,17 +1708,23 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean samples >>= 1; if (!samples) { - litdata = Q1BSPX_FindLump("RGBLIGHTING", &samples); - samples /= 3; + expdata = Q1BSPX_FindLump("LIGHTING_E5BGR9", &samples); //expressed as a big-endian packed int - 0xEBGR type thing, except misaligned and 32bit. + samples /= 4; if (!samples) - return; + { + litdata = Q1BSPX_FindLump("RGBLIGHTING", &samples); //RGB packed data + samples /= 3; + if (!samples) + return; + } } #ifndef SERVERONLY - if (!litdata && r_loadlits.value) + if (!expdata && !litdata && r_loadlits.value) { char *litnames[] = { "%s.lit2", + "%s.hdr", "%s.lit", "lits/%s.lit2", "lits/%s.lit" @@ -1765,22 +1772,31 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean if (litdata && litsize >= 8) { //validate it, if we loaded one. + int litver = LittleLong(*(int *)&litdata[4]); if (litdata[0] != 'Q' || litdata[1] != 'L' || litdata[2] != 'I' || litdata[3] != 'T') { litdata = NULL; Con_Printf("lit \"%s\" isn't a lit\n", litname); } - else if (LittleLong(*(int *)&litdata[4]) == 1 && l->filelen && samples*3 != (litsize-8)) + else if (litver == 1) { + if (l->filelen && samples*3 != (litsize-8)) + { + litdata = NULL; + Con_Printf("lit \"%s\" doesn't match level. Ignored.\n", litname); + } + else + litdata += 8; //header+version + } + else if (litver == 0x10001) + { + if (l->filelen && samples*4 != (litsize-8)) + Con_Printf("lit \"%s\" doesn't match level. Ignored.\n", litname); + else + expdata = litdata+8; //header+version litdata = NULL; - Con_Printf("lit \"%s\" doesn't match level. Ignored.\n", litname); } - else if (LittleLong(*(int *)&litdata[4]) == 1) - { - //header+version - litdata += 8; - } - else if (LittleLong(*(int *)&litdata[4]) == 2 && overrides) + else if (litver == 2 && overrides) { qlit2_t *ql2 = (qlit2_t*)litdata; unsigned int *offsets = (unsigned int*)(ql2+1); @@ -1822,15 +1838,22 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean } } - littmp = false; + exptmp = littmp = false; if (!litdata) { int size; /*FIXME: bspx support for extents+lmscale, may require style+offset lumps too, not sure what to do here*/ - litdata = Q1BSPX_FindLump("RGBLIGHTING", &size); - if (size != samples*3) - litdata = NULL; - littmp = true; + expdata = Q1BSPX_FindLump("LIGHTING_E5BGR9", &size); + exptmp = true; + if (size != samples*4) + { + expdata = NULL; + + litdata = Q1BSPX_FindLump("RGBLIGHTING", &size); + littmp = true; + if (size != samples*3) + litdata = NULL; + } } else if (!inhibitvalidation) { @@ -2011,36 +2034,42 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean overrides->styles = NULL; } } - + if (luxdata && luxtmp) { - loadmodel->engineflags |= MDLF_RGBLIGHTING; loadmodel->deluxdata = ZG_Malloc(&loadmodel->memgroup, samples*3); memcpy(loadmodel->deluxdata, luxdata, samples*3); } else if (luxdata) - { loadmodel->deluxdata = luxdata; - } else if (interleaveddeluxe) loadmodel->deluxdata = ZG_Malloc(&loadmodel->memgroup, samples*3); - if (litdata && littmp) + if (expdata) { - loadmodel->engineflags |= MDLF_RGBLIGHTING; - loadmodel->lightdata = ZG_Malloc(&loadmodel->memgroup, samples*3); - /*the memcpy is below*/ - samples*=3; + loadmodel->lightmaps.fmt = LM_E5BGR9; + loadmodel->lightdatasize = samples*4; + if (exptmp) + { + loadmodel->lightdata = ZG_Malloc(&loadmodel->memgroup, samples*4); + memcpy(loadmodel->lightdata, expdata, samples*4); + } + else + loadmodel->lightdata = expdata; + return; } else if (litdata) { - loadmodel->engineflags |= MDLF_RGBLIGHTING; - loadmodel->lightdata = litdata; + loadmodel->lightmaps.fmt = LM_RGB8; + if (littmp) + loadmodel->lightdata = ZG_Malloc(&loadmodel->memgroup, samples*3); /*the memcpy is below*/ + else + loadmodel->lightdata = litdata; samples*=3; } else if (lumdata) { - loadmodel->engineflags &= ~MDLF_RGBLIGHTING; + loadmodel->lightmaps.fmt = LM_L8; loadmodel->lightdata = ZG_Malloc(&loadmodel->memgroup, samples); litdata = lumdata; } @@ -2071,7 +2100,7 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean } #ifndef SERVERONLY - if ((loadmodel->engineflags & MDLF_RGBLIGHTING) && r_lightmap_saturation.value != 1.0f) + if ((loadmodel->lightmaps.fmt == LM_RGB8) && r_lightmap_saturation.value != 1.0f) SaturateR8G8B8(loadmodel->lightdata, l->filelen, r_lightmap_saturation.value); #endif } @@ -2362,7 +2391,7 @@ void ModQ1_Batches_BuildQ1Q2Poly(model_t *mod, msurface_t *surf, builddata_t *co } #ifndef SERVERONLY - if (gl_lightmap_average.ival) + if (r_lightmap_average.ival) { for (sty = 0; sty < 1; sty++) { @@ -3716,6 +3745,8 @@ static qboolean Mod_LoadFaces (model_t *loadmodel, qbyte *mod_base, lump_t *l, l char buf[64]; lightmapoverrides_t overrides; + int lofsscale = 1; + memset(&overrides, 0, sizeof(overrides)); lmscale = atoi(Mod_ParseWorldspawnKey(loadmodel, "lightmap_scale", buf, sizeof(buf))); @@ -3757,6 +3788,22 @@ static qboolean Mod_LoadFaces (model_t *loadmodel, qbyte *mod_base, lump_t *l, l Mod_LoadLighting (loadmodel, mod_base, lightlump, false, &overrides); + switch(loadmodel->lightmaps.fmt) + { + case LM_E5BGR9: + lofsscale = 4; + break; + case LM_RGB8: + lofsscale = 3; + break; + default: + case LM_L8: + lofsscale = 1; + break; + } + if (loadmodel->fromgame == fg_halflife) + lofsscale /= 3; //halflife has rgb offsets already (this should drop to 1, preserving any misaligned offsets... + for ( surfnum=0 ; surfnumstyles[i] = overrides.styles[surfnum*4+i]; CalcSurfaceExtents (loadmodel, out); - if (lofs != (unsigned int)-1 && (loadmodel->engineflags & MDLF_RGBLIGHTING) && loadmodel->fromgame != fg_halflife) - lofs *= 3; + if (lofs != (unsigned int)-1) + lofs *= lofsscale; lend = lofs+(out->extents[0]+1)*(out->extents[1]+1); if (lofs > loadmodel->lightdatasize || lend < lofs) out->samples = NULL; //should includes -1 @@ -4824,6 +4871,7 @@ void ModBrush_LoadGLStuff(void *ctx, void *data, size_t a, size_t b) } } +#if defined(Q3BSPS) || defined(RFBSPS) if (mod->fromgame == fg_quake3) { if (mod->lightmaps.deluxemapping && mod->lightmaps.deluxemapping_modelspace) @@ -4850,7 +4898,10 @@ void ModBrush_LoadGLStuff(void *ctx, void *data, size_t a, size_t b) } mod->textures[2*mod->numtexinfo]->shader = R_RegisterShader_Flare("noshader"); } - else if (mod->fromgame == fg_quake2) + else +#endif +#ifdef Q2BSPS + if (mod->fromgame == fg_quake2) { COM_FileBase (mod->name, loadname, sizeof(loadname)); for(a = 0; a < mod->numtextures; a++) @@ -4866,11 +4917,12 @@ void ModBrush_LoadGLStuff(void *ctx, void *data, size_t a, size_t b) // maps |= SHADER_HASNORMALMAP; if (gl_specular.ival) maps |= SHADER_HASGLOSS; - R_BuildLegacyTexnums(mod->textures[a]->shader, mod->textures[a]->name, loadname, maps, 0, TF_MIP4_SOLID8, mod->textures[a]->width, mod->textures[a]->height, mod->textures[a]->mips, mod->textures[a]->palette); + R_BuildLegacyTexnums(mod->textures[a]->shader, mod->textures[a]->name, loadname, maps, 0, TF_MIP4_8PAL24, mod->textures[a]->width, mod->textures[a]->height, mod->textures[a]->mips, mod->textures[a]->palette); BZ_Free(mod->textures[a]->mips[0]); } } else +#endif { COM_FileBase (mod->name, loadname, sizeof(loadname)); if (!strncmp(loadname, "b_", 2)) diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index f87c893d..4a1b3e01 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -423,7 +423,7 @@ typedef struct msurface_s qbyte styles[MAXQ1LIGHTMAPS]; qbyte vlstyles[MAXRLIGHTMAPS]; int cached_light[MAXQ1LIGHTMAPS]; // values currently used in lightmap - int cached_colour[MAXQ1LIGHTMAPS]; + int cached_colour[MAXQ1LIGHTMAPS]; // values currently used in lightmap qboolean cached_dlight; // true if dynamic light in cache #ifndef NOSTAINS qboolean stained; @@ -997,6 +997,14 @@ typedef struct model_s int width; //x size of lightmaps int height; //y size of lightmaps int surfstyles; //numbers of style per surface. + enum { + //vanilla used byte values, with 255 being a value of about 2. + //float/hdr formats use 1 to mean 1, however. + //internally, we still use integers for lighting, with .7 bits of extra precision. + LM_L8, + LM_RGB8, + LM_E5BGR9 + } fmt; qboolean deluxemapping; //lightmaps are interleaved with deluxemap data (lightmap indicies should only be even values) qboolean deluxemapping_modelspace; //deluxemaps are in modelspace - we need different glsl. } lightmaps; @@ -1018,7 +1026,7 @@ typedef struct model_s #define MDLF_EMITREPLACE 0x0001 // particle effect engulphs model (don't draw) #define MDLF_EMITFORWARDS 0x0002 #define MDLF_NODEFAULTTRAIL 0x0004 -#define MDLF_RGBLIGHTING 0x0008 +//#define MDLF_RGBLIGHTING 0x0008 #define MDLF_PLAYER 0x0010 // players have specific lighting values #define MDLF_FLAME 0x0020 // can be excluded with r_drawflame, fullbright render hack #define MDLF_DOCRC 0x0040 // model needs CRC built diff --git a/engine/gl/gl_rlight.c b/engine/gl/gl_rlight.c index 01940ab5..1034227a 100644 --- a/engine/gl/gl_rlight.c +++ b/engine/gl/gl_rlight.c @@ -1541,30 +1541,39 @@ static int GLRecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end) r = 0; if (lightmap) { - if (cl.worldmodel->engineflags & MDLF_RGBLIGHTING) + switch(cl.worldmodel->lightmaps.fmt) { - lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)*3; + case LM_E5BGR9: + lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)<<2; + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) + { + unsigned int l = *(unsigned int*)lightmap; + scale = d_lightstylevalue[surf->styles[maps]]; + scale *= pow(2, (int)(l>>27)-15-9+7); - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; - maps++) + r += max3(((l>> 0)&0x1ff), ((l>> 9)&0x1ff), ((l>>18)&0x1ff)) * scale; + + lightmap += ((surf->extents[0]>>surf->lmshift)+1) * ((surf->extents[1]>>surf->lmshift)+1)<<2; + } + break; + case LM_RGB8: + lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)*3; + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; - r += (lightmap[0]+lightmap[1]+lightmap[2]) * scale / 3; + r += max3(lightmap[0],lightmap[1],lightmap[2]) * scale; lightmap += ((surf->extents[0]>>surf->lmshift)+1) * ((surf->extents[1]>>surf->lmshift)+1)*3; } - - } - else - { + break; + case LM_L8: lightmap += dt * ((surf->extents[0]>>surf->lmshift)+1) + ds; - - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; - maps++) + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; r += *lightmap * scale; lightmap += ((surf->extents[0]>>surf->lmshift)+1) * ((surf->extents[1]>>surf->lmshift)+1); } + break; } r >>= 8; @@ -1703,14 +1712,39 @@ static float *GLRecursiveLightPoint3C (model_t *mod, mnode_t *node, vec3_t start overbright = 1/255.0f; if (mod->deluxdata) { - if (mod->engineflags & MDLF_RGBLIGHTING) + switch(mod->lightmaps.fmt) { + case LM_E5BGR9: + deluxmap = ((surf->samples - mod->lightdata)>>2)*3 + mod->deluxdata; + + lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)<<2; + deluxmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)<<4; + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) + { + unsigned int lm = *(unsigned int*)lightmap; + scale = d_lightstylevalue[surf->styles[maps]]*overbright; + scale *= pow(2, (int)(lm>>27)-15-9+8); + + l[0] += ((lm>> 0)&0x1ff) * scale * cl_lightstyle[surf->styles[maps]].colours[0]; + l[1] += ((lm>> 9)&0x1ff) * scale * cl_lightstyle[surf->styles[maps]].colours[1]; + l[2] += ((lm>>18)&0x1ff) * scale * cl_lightstyle[surf->styles[maps]].colours[2]; + + l[3] += (deluxmap[0]-127)*scale; + l[4] += (deluxmap[1]-127)*scale; + l[5] += (deluxmap[2]-127)*scale; + + lightmap += ((surf->extents[0]>>surf->lmshift)+1) * + ((surf->extents[1]>>surf->lmshift)+1)<<2; + deluxmap += ((surf->extents[0]>>surf->lmshift)+1) * + ((surf->extents[1]>>surf->lmshift)+1) * 3; + } + break; + case LM_RGB8: deluxmap = surf->samples - mod->lightdata + mod->deluxdata; lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)*3; deluxmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)*3; - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; - maps++) + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]*overbright; @@ -1727,16 +1761,13 @@ static float *GLRecursiveLightPoint3C (model_t *mod, mnode_t *node, vec3_t start deluxmap += ((surf->extents[0]>>surf->lmshift)+1) * ((surf->extents[1]>>surf->lmshift)+1) * 3; } - - } - else - { + break; + case LM_L8: deluxmap = (surf->samples - mod->lightdata)*3 + mod->deluxdata; lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds); deluxmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)*3; - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; - maps++) + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]*overbright; @@ -1753,16 +1784,33 @@ static float *GLRecursiveLightPoint3C (model_t *mod, mnode_t *node, vec3_t start deluxmap += ((surf->extents[0]>>surf->lmshift)+1) * ((surf->extents[1]>>surf->lmshift)+1) * 3; } + break; } } else { - if (mod->engineflags & MDLF_RGBLIGHTING) + switch(mod->lightmaps.fmt) { + case LM_E5BGR9: + lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)<<2; + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) + { + unsigned int lm = *(unsigned int*)lightmap; + scale = d_lightstylevalue[surf->styles[maps]]*overbright; + scale *= pow(2, (int)(lm>>27)-15-9+8); + + l[0] += ((lm>> 0)&0x1ff) * scale * cl_lightstyle[surf->styles[maps]].colours[0]; + l[1] += ((lm>> 9)&0x1ff) * scale * cl_lightstyle[surf->styles[maps]].colours[1]; + l[2] += ((lm>>18)&0x1ff) * scale * cl_lightstyle[surf->styles[maps]].colours[2]; + + lightmap += ((surf->extents[0]>>surf->lmshift)+1) * + ((surf->extents[1]>>surf->lmshift)+1)<<2; + } + break; + case LM_RGB8: lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)*3; - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; - maps++) + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]*overbright; @@ -1773,13 +1821,10 @@ static float *GLRecursiveLightPoint3C (model_t *mod, mnode_t *node, vec3_t start lightmap += ((surf->extents[0]>>surf->lmshift)+1) * ((surf->extents[1]>>surf->lmshift)+1) * 3; } - - } - else - { + break; + case LM_L8: lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds); - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; - maps++) + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]*overbright; @@ -1790,6 +1835,7 @@ static float *GLRecursiveLightPoint3C (model_t *mod, mnode_t *node, vec3_t start lightmap += ((surf->extents[0]>>surf->lmshift)+1) * ((surf->extents[1]>>surf->lmshift)+1); } + break; } } } @@ -1849,9 +1895,9 @@ void GLQ1BSP_LightPointValues(model_t *model, vec3_t point, vec3_t res_diffuse, } else { - res_diffuse[0] = r[0]*2; - res_diffuse[1] = r[1]*2; - res_diffuse[2] = r[2]*2; + res_diffuse[0] = r[0]; + res_diffuse[1] = r[1]; + res_diffuse[2] = r[2]; /*bright on one side, dark on the other, but not too dark*/ res_ambient[0] = r[0]/2; diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index ac84299a..cce767df 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -33,6 +33,7 @@ void R_RenderBrushPoly (msurface_t *fa); extern int gl_stencilbits; +FTEPFNGLCOMPRESSEDTEXIMAGE3DARBPROC qglCompressedTexImage3DARB; FTEPFNGLCOMPRESSEDTEXIMAGE2DARBPROC qglCompressedTexImage2DARB; FTEPFNGLGETCOMPRESSEDTEXIMAGEARBPROC qglGetCompressedTexImageARB; @@ -60,6 +61,7 @@ extern cvar_t r_stereo_separation; extern cvar_t r_stereo_convergence; extern cvar_t r_stereo_method; extern cvar_t r_postprocshader, r_fxaa; +extern cvar_t r_hdr_framebuffer; extern cvar_t gl_screenangle; @@ -88,6 +90,7 @@ extern cvar_t scr_fov; shader_t *scenepp_rescaled; shader_t *scenepp_antialias; shader_t *scenepp_waterwarp; +shader_t *scenepp_gamma; // post processing stuff texid_t sceneblur_texture; @@ -143,19 +146,34 @@ void GL_InitSceneProcessingShaders (void) GL_InitSceneProcessingShaders_WaterWarp(); } + scenepp_gamma = R_RegisterShader("fte_scenegamma", 0, + "{\n" + "program defaultgammacb\n" + "affine\n" + "{\n" + "map $sourcecolour\n" + "nodepthtest\n" + "}\n" + "}\n" + ); + scenepp_rescaled = R_RegisterShader("fte_rescaler", 0, "{\n" "program default2d\n" + "affine\n" "{\n" "map $sourcecolour\n" + "nodepthtest\n" "}\n" "}\n" ); scenepp_antialias = R_RegisterShader("fte_ppantialias", 0, "{\n" "program fxaa\n" + "affine\n" "{\n" "map $sourcecolour\n" + "nodepthtest\n" "}\n" "}\n" ); @@ -641,14 +659,6 @@ void R_SetupGL (float stereooffset, int i) qglDisable(GL_DITHER); } } - if (vid_srgb.modified && !gl_config_gles) - { - vid_srgb.modified = false; - if (vid_srgb.ival == 1 || vid.srgb) - qglEnable(GL_FRAMEBUFFER_SRGB); //specifies that the glsl is writing colours in the linear colour space, even if the framebuffer is not sRGB. - else - qglDisable(GL_FRAMEBUFFER_SRGB); - } } void Surf_SetupFrame(void); @@ -1846,6 +1856,7 @@ void GLR_RenderView (void) shader_t *custompostproc = NULL; float renderscale; //extreme, but whatever int oldfbo = 0; + qboolean forcedfb = false; checkglerror(); @@ -1873,9 +1884,7 @@ void GLR_RenderView (void) r_refdef.flags &= ~(RDF_ALLPOSTPROC|RDF_RENDERSCALE); if (dofbo || (r_refdef.flags & RDF_NOWORLDMODEL)) - { renderscale = 1; - } else { renderscale = r_renderscale.value; @@ -1917,10 +1926,21 @@ void GLR_RenderView (void) if (!(r_refdef.flags & RDF_NOWORLDMODEL) && r_fxaa.ival) //overlays will have problems. r_refdef.flags |= RDF_ANTIALIAS; + if (!(r_refdef.flags & RDF_NOWORLDMODEL) && r_hdr_framebuffer.ival && !(vid.flags & VID_FP16)) //primary use of this cvar is to fix q3shader overbrights (so bright lightmaps can oversaturate then drop below 1 by modulation with the lightmap + forcedfb = true; + if (vid_hardwaregamma.ival == 4 && (v_gamma.value != 1 || v_contrast.value != 1 || v_brightness.value != 0)) + r_refdef.flags |= RDF_SCENEGAMMA; + //disable stuff if its simply not supported. if (dofbo || !gl_config.arb_shader_objects || !gl_config.ext_framebuffer_objects || !sh_config.texture_non_power_of_two_pic) + { + forcedfb &= !dofbo && gl_config.ext_framebuffer_objects && sh_config.texture_non_power_of_two_pic; r_refdef.flags &= ~(RDF_ALLPOSTPROC); //block all of this stuff - + } + if (dofbo) + forcedfb = false; + else if (r_renderscale.value != 1) + forcedfb = true; BE_Scissor(NULL); if (dofbo) @@ -1969,9 +1989,10 @@ void GLR_RenderView (void) flags |= FBO_RB_DEPTH; oldfbo = GLBE_FBO_Update(&fbo_gameview, flags, col, mrt, depth, vid.fbpwidth, vid.fbpheight, 0); } - else if ((r_refdef.flags & (RDF_ALLPOSTPROC)) || renderscale != 1) + else if ((r_refdef.flags & (RDF_ALLPOSTPROC)) || forcedfb) { unsigned int rtflags = IF_NOMIPMAP|IF_CLAMP|IF_RENDERTARGET; + enum uploadfmt fmt; r_refdef.flags |= RDF_RENDERSCALE; @@ -2008,7 +2029,16 @@ void GLR_RenderView (void) vid.fbvwidth = vid.fbpwidth; vid.fbvheight = vid.fbpheight; - sourcetex = R2D_RT_Configure("rt/$lastgameview", vid.fbpwidth, vid.fbpheight, /*(r_refdef.flags&RDF_BLOOM)?TF_RGBA16F:*/TF_RGBA32, rtflags); + fmt = PTI_RGBA8; + if ((r_refdef.flags&RDF_SCENEGAMMA)||(vid.flags&(VID_SRGBAWARE|VID_FP16))||r_hdr_framebuffer.ival) + { //gamma ramps really need higher colour precision, otherwise the entire thing looks terrible. + if (sh_config.texfmt[PTI_RGBA16F]) + fmt = PTI_RGBA16F; + else if (sh_config.texfmt[PTI_A2BGR10]) + fmt = PTI_A2BGR10; + } + + sourcetex = R2D_RT_Configure("rt/$lastgameview", vid.fbpwidth, vid.fbpheight, fmt, rtflags); oldfbo = GLBE_FBO_Update(&fbo_gameview, FBO_RB_DEPTH, &sourcetex, 1, r_nulltex, vid.fbpwidth, vid.fbpheight, 0); dofbo = true; @@ -2095,13 +2125,19 @@ void GLR_RenderView (void) // SCENE POST PROCESSING - if (renderscale != 1 && !(r_refdef.flags & RDF_ALLPOSTPROC)) + if (forcedfb && !(r_refdef.flags & RDF_ALLPOSTPROC)) { GLBE_FBO_Sources(sourcetex, r_nulltex); R2D_Image(r_refdef.vrect.x, r_refdef.vrect.y, r_refdef.vrect.width, r_refdef.vrect.height, 0, 1, 1, 0, scenepp_rescaled); } else { + if (r_refdef.flags & RDF_SCENEGAMMA) + { + R2D_ImageColours (v_gamma.value, v_contrast.value, v_brightness.value, 1); + sourcetex = R_RenderPostProcess (sourcetex, RDF_SCENEGAMMA, scenepp_gamma, "rt/$gammaed"); + R2D_ImageColours (1, 1, 1, 1); + } sourcetex = R_RenderPostProcess (sourcetex, RDF_WATERWARP, scenepp_waterwarp, "rt/$waterwarped"); sourcetex = R_RenderPostProcess (sourcetex, RDF_CUSTOMPOSTPROC, custompostproc, "rt/$postproced"); sourcetex = R_RenderPostProcess (sourcetex, RDF_ANTIALIAS, scenepp_antialias, "rt/$antialiased"); diff --git a/engine/gl/gl_rsurf.c b/engine/gl/gl_rsurf.c index 1140e302..2f0fe04e 100644 --- a/engine/gl/gl_rsurf.c +++ b/engine/gl/gl_rsurf.c @@ -26,7 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "renderque.h" #include -extern cvar_t gl_lightmap_nearest; +extern cvar_t r_lightmap_nearest; void GLBE_ClearVBO(vbo_t *vbo, qboolean dataonly) { @@ -543,11 +543,11 @@ void GLBE_UploadAllLightmaps(void) continue; lm->modified = false; if (!TEXVALID(lm->lightmap_texture)) - TEXASSIGN(lm->lightmap_texture, Image_CreateTexture(va("***lightmap %i***", i), NULL, (gl_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR)|IF_NOMIPMAP)); + TEXASSIGN(lm->lightmap_texture, Image_CreateTexture(va("***lightmap %i***", i), NULL, (r_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR)|IF_NOMIPMAP)); if (!lm->lightmap_texture->num) qglGenTextures(1, &lm->lightmap_texture->num); GL_MTBind(0, GL_TEXTURE_2D, lm->lightmap_texture); - if (gl_lightmap_nearest.ival) + if (r_lightmap_nearest.ival) { qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -557,15 +557,17 @@ void GLBE_UploadAllLightmaps(void) qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } - switch(lightmap_fmt) //bgra32, rgba32, rgb24, lum8 + + qglTexImage2D(GL_TEXTURE_2D, 0, gl_config.formatinfo[lightmap_fmt].internalformat, lm->width, lm->height, 0, gl_config.formatinfo[lightmap_fmt].format, gl_config.formatinfo[lightmap_fmt].type, lightmap[i]->lightmaps); + + if (gl_config.glversion >= (gl_config.gles?3.0:3.3)) { - default: Sys_Error("Bad lightmap_fmt\n"); break; - case TF_BGRA32: qglTexImage2D(GL_TEXTURE_2D, 0, /*vid.srgb?GL_SRGB8_ALPHA8_EXT:*/GL_RGBA, lm->width, lm->height, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV,lightmap[i]->lightmaps); break; -// case TF_RGBA32: qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, lm->width, lm->height, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV,lightmap[i]->lightmaps); break; -// case TF_BGR24: qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, lm->width, lm->height, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, lightmap[i]->lightmaps); break; - case TF_RGB24: qglTexImage2D(GL_TEXTURE_2D, 0, /*vid.srgb?GL_SRGB8_EXT:*/GL_RGB, lm->width, lm->height, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmap[i]->lightmaps); break; - case TF_LUM8: qglTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, lm->width, lm->height, 0, GL_LUMINANCE,GL_UNSIGNED_BYTE, lightmap[i]->lightmaps); break; + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, gl_config.formatinfo[lightmap_fmt].swizzle_r); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, gl_config.formatinfo[lightmap_fmt].swizzle_g); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, gl_config.formatinfo[lightmap_fmt].swizzle_b); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, gl_config.formatinfo[lightmap_fmt].swizzle_a); } + //for completeness. lm->lightmap_texture->width = lm->width; lm->lightmap_texture->height = lm->height; diff --git a/engine/gl/gl_screen.c b/engine/gl/gl_screen.c index b66a851c..093d5915 100644 --- a/engine/gl/gl_screen.c +++ b/engine/gl/gl_screen.c @@ -64,6 +64,7 @@ qboolean GLSCR_UpdateScreen (void) int uimenu; qboolean nohud; qboolean noworld; + extern cvar_t vid_srgb; r_refdef.pxrect.maxheight = vid.pixelheight; @@ -71,6 +72,31 @@ qboolean GLSCR_UpdateScreen (void) R2D_Font_Changed(); + if (vid_srgb.modified) + { + vid_srgb.modified = false; + + //vid_srgb can be changed between 0 and 1, but other values need texture reloads. do that without too much extra weirdness. + if ((vid.flags & VID_SRGB_CAPABLE) && gl_config.arb_framebuffer_srgb) + { //srgb-capable + if (vid_srgb.ival > 1 && (vid.flags & VID_SRGBAWARE)) + { //full srgb wanted (and textures are loaded) + qglEnable(GL_FRAMEBUFFER_SRGB); + vid.flags |= VID_SRGB_FB_LINEAR; + } + else if (vid_srgb.ival==1 || (vid.flags & VID_SRGBAWARE)) + { //srgb wanted only for the framebuffer, for gamma tricks. + qglEnable(GL_FRAMEBUFFER_SRGB); + vid.flags |= VID_SRGB_FB_LINEAR; + } + else + { //srgb not wanted... + qglDisable(GL_FRAMEBUFFER_SRGB); + vid.flags &= ~VID_SRGB_FB_LINEAR; + } + } + } + if (!scr_initialized || !con_initialized) { return false; // not initialized yet diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 58090a8d..e9801037 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -661,6 +661,16 @@ static void Shader_ParseFunc (shader_t *shader, char **ptr, shaderfunc_t *func) func->type = SHADER_FUNC_INVERSESAWTOOTH; else if (!Q_stricmp (token, "noise")) func->type = SHADER_FUNC_NOISE; + else if (!Q_stricmp (token, "distanceramp")) //QFusion + { + func->type = SHADER_FUNC_CONSTANT; //not supported... + Shader_ParseFloat (shader, ptr, 0); + Shader_ParseFloat (shader, ptr, 0); + Shader_ParseFloat (shader, ptr, 0); + Shader_ParseFloat (shader, ptr, 0); + Vector4Set(func->args, 255, 255, 255, 255); + return; + } func->args[0] = Shader_ParseFloat (shader, ptr, 0); func->args[1] = Shader_ParseFloat (shader, ptr, 0); @@ -1254,42 +1264,49 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip } } } - else if (!strncmp(script, "!!cvardf", 8)) + else if (!strncmp(script, "!!cvardf", 8) || !strncmp(script, "!!cvard3", 8) || !strncmp(script, "!!cvard4", 8) || !strncmp(script, "!!cvard_srgb", 11)) { - script += 8; - while (*script == ' ' || *script == '\t') - script++; - end = script; - while ((*end >= 'A' && *end <= 'Z') || (*end >= 'a' && *end <= 'z') || (*end >= '0' && *end <= '9') || *end == '_') - end++; - if (nummodifiers < MAXMODIFIERS && end - script < 64) + qboolean srgb = false; + float div = 1; + char type = script[7]; + script+=8; + if (type == '_') { - cvar_t *var; - char namebuf[64]; - char valuebuf[64]; - memcpy(namebuf, script, end - script); - namebuf[end - script] = 0; - while (*end == ' ' || *end == '\t') - end++; - if (*end == '=') + if (*script == 's') { - script = ++end; - while (*end && *end != '\n' && *end != '\r' && end < script+sizeof(namebuf)-1) - end++; - memcpy(valuebuf, script, end - script); - valuebuf[end - script] = 0; + srgb = true; + script+=1; } - else - strcpy(valuebuf, "0"); - var = Cvar_Get(namebuf, valuebuf, CVAR_SHADERSYSTEM, "GLSL Variables"); - if (var) - permutationdefines[nummodifiers++] = Z_StrDup(va("#define %s %g\n", namebuf, var->value)); + + if (!strncmp(script, "rgba", 4)) + { + type = '4'; + script+=4; + } + else if (!strncmp(script, "rgb", 3)) + { + type = '3'; + script+=3; + } + else if (!strncmp(script, "rg", 2)) + { + type = '2'; + script+=2; + } + else if (!strncmp(script, "r", 1) || !strncmp(script, "f", 1)) + { + type = 'f'; + script+=1; + } + + if (!strncmp(script, "_b", 2)) + { + div = 255; + script+=2; + } + else if (!strncmp(script, "_", 1)) + div = strtod(script, &script); } - script = end; - } - else if (!strncmp(script, "!!cvard3", 8)) - { - script += 8; while (*script == ' ' || *script == '\t') script++; end = script; @@ -1316,40 +1333,26 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip strcpy(valuebuf, "0"); var = Cvar_Get(namebuf, valuebuf, CVAR_SHADERSYSTEM, "GLSL Variables"); if (var) - permutationdefines[nummodifiers++] = Z_StrDup(va("#define %s %s(%g,%g,%g)\n", namebuf, ((qrenderer == QR_OPENGL)?"vec3":"float3"), var->vec4[0], var->vec4[1], var->vec4[2])); - } - script = end; - } - else if (!strncmp(script, "!!cvard4", 8)) - { - script += 8; - while (*script == ' ' || *script == '\t') - script++; - end = script; - while ((*end >= 'A' && *end <= 'Z') || (*end >= 'a' && *end <= 'z') || (*end >= '0' && *end <= '9') || *end == '_') - end++; - if (nummodifiers < MAXMODIFIERS && end - script < 64) - { - cvar_t *var; - char namebuf[64]; - char valuebuf[64]; - memcpy(namebuf, script, end - script); - namebuf[end - script] = 0; - while (*end == ' ' || *end == '\t') - end++; - if (*end == '=') { - script = ++end; - while (*end && *end != '\n' && *end != '\r' && end < script+sizeof(namebuf)-1) - end++; - memcpy(valuebuf, script, end - script); - valuebuf[end - script] = 0; + if (srgb) + { + if (type == '4') + permutationdefines[nummodifiers++] = Z_StrDup(va("#define %s %s(%g,%g,%g,%g)\n", namebuf, ((qrenderer == QR_OPENGL)?"vec4":"float4"), SRGBf(var->vec4[0]/div), SRGBf(var->vec4[1]/div), SRGBf(var->vec4[2]/div), var->vec4[3]/div)); + else if (type == '3') + permutationdefines[nummodifiers++] = Z_StrDup(va("#define %s %s(%g,%g,%g)\n", namebuf, ((qrenderer == QR_OPENGL)?"vec3":"float3"), SRGBf(var->vec4[0]/div), SRGBf(var->vec4[1]/div), SRGBf(var->vec4[2]/div))); + else + permutationdefines[nummodifiers++] = Z_StrDup(va("#define %s %g\n", namebuf, SRGBf(var->value/div))); + } + else + { + if (type == '4') + permutationdefines[nummodifiers++] = Z_StrDup(va("#define %s %s(%g,%g,%g,%g)\n", namebuf, ((qrenderer == QR_OPENGL)?"vec4":"float4"), var->vec4[0]/div, var->vec4[1]/div, var->vec4[2]/div, var->vec4[3]/div)); + else if (type == '3') + permutationdefines[nummodifiers++] = Z_StrDup(va("#define %s %s(%g,%g,%g)\n", namebuf, ((qrenderer == QR_OPENGL)?"vec3":"float3"), var->vec4[0]/div, var->vec4[1]/div, var->vec4[2]/div)); + else + permutationdefines[nummodifiers++] = Z_StrDup(va("#define %s %g\n", namebuf, var->value/div)); + } } - else - strcpy(valuebuf, "0"); - var = Cvar_Get(namebuf, valuebuf, CVAR_SHADERSYSTEM, "GLSL Variables"); - if (var) - permutationdefines[nummodifiers++] = Z_StrDup(va("#define %s %s(%g,%g,%g,%g)\n", namebuf, ((qrenderer == QR_OPENGL)?"vec4":"float4"), var->vec4[0], var->vec4[1], var->vec4[2], var->vec4[3])); } script = end; } @@ -1449,6 +1452,9 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip else blobfile = NULL; + if (!r_fog_permutation.ival) + nopermutation |= PERMUTATION_BIT_FOG; + if (blobfile) { unsigned int magic; @@ -3118,6 +3124,17 @@ static void Shaderpass_RGBGen (shader_t *shader, shaderpass_t *pass, char **ptr) Shader_ParseVector (shader, ptr, pass->rgbgen_func.args); } + else if (!Q_stricmp (token, "srgb") || !Q_stricmp (token, "srgbconst")) + { + pass->rgbgen = RGB_GEN_CONST; + pass->rgbgen_func.type = SHADER_FUNC_CONSTANT; + + Shader_ParseVector (shader, ptr, pass->rgbgen_func.args); + + pass->rgbgen_func.args[0] = SRGBf(pass->rgbgen_func.args[0]); + pass->rgbgen_func.args[1] = SRGBf(pass->rgbgen_func.args[1]); + pass->rgbgen_func.args[2] = SRGBf(pass->rgbgen_func.args[2]); + } else if (!Q_stricmp (token, "topcolor")) pass->rgbgen = RGB_GEN_TOPCOLOR; else if (!Q_stricmp (token, "bottomcolor")) @@ -3962,7 +3979,7 @@ char *Shader_Skip ( char *ptr ) tok = COM_ParseExt (&ptr, true, true); } - for (brace_count = 1; brace_count > 0 ; ptr++) + for (brace_count = 1; brace_count > 0; ) { tok = COM_ParseExt (&ptr, true, true); @@ -4809,7 +4826,7 @@ void Shader_Finish (shader_t *s) "sort sky\n" "{\n" "map $whiteimage\n" - "rgbgen const $r_fastskycolour\n" + "rgbgen srgb $r_fastskycolour\n" "}\n" "surfaceparm nodlight\n" "}\n" @@ -5536,6 +5553,35 @@ void QDECL R_BuildDefaultTexnums(texnums_t *src, shader_t *shader) } } +#if 0//def Q2BSPS +static qbyte *ReadRGBA8ImageFile(const char *fname, const char *subpath, int *width, int *height) +{ + qboolean hasalpha; + qofs_t filesize; + qbyte *img, *filedata = NULL; + char *patterns[] = + { + "*overrides/%s.tga", + "*overrides/%s.jpg", + "textures/%s.tga", + "textures/%s.jpg", + }; + char nname[MAX_QPATH]; + size_t p; + for (p = 0; p < countof(patterns) && !filedata; p++) + { + if (*patterns[p] == '*') + Q_snprintfz(nname, sizeof(nname), patterns[p]+1, COM_SkipPath(fname)); + else + Q_snprintfz(nname, sizeof(nname), patterns[p], fname); + filedata = FS_MallocFile(nname, FS_GAME, &filesize); + } + img = filedata?Read32BitImageFile(filedata, filesize, width, height, &hasalpha, fname):NULL; + BZ_Free(filedata); + return img; +} +#endif + //call this with some fallback textures to directly load some textures void QDECL R_BuildLegacyTexnums(shader_t *shader, const char *fallbackname, const char *subpath, unsigned int loadflags, unsigned int imageflags, uploadfmt_t basefmt, size_t width, size_t height, qbyte *mipdata[4], qbyte *palette) { @@ -5634,6 +5680,62 @@ void QDECL R_BuildLegacyTexnums(shader_t *shader, const char *fallbackname, cons { COM_StripExtension(tex->mapname, mapname, sizeof(mapname)); +#if 0//def Q2BSPS + if (gl_load24bit.ival == 2) + { + qbyte *base; + int basewidth, baseheight; + qbyte *norm; + int normwidth, normheight; + qbyte tmp; + int x, y; + base = ReadRGBA8ImageFile(imagename, subpath, &basewidth, &baseheight); + //base contains diffuse RGB, and height + if (base) + { + tex->base = Image_GetTexture(va("%s_diff", imagename), subpath, imageflags|IF_NOREPLACE, base, NULL, basewidth, baseheight, TF_RGBX32); //queues the texture creation. + norm = ReadRGBA8ImageFile(va("%s_bump", imagename), subpath, &normwidth, &normheight); + if (norm) + { + if (normwidth != basewidth || normheight != baseheight) + { + //sucks... + tex->bump = Image_GetTexture(va("%s_norm", imagename), subpath, imageflags|IF_NOREPLACE, norm, NULL, normwidth, normheight, TF_RGBX32); //queues the texture creation. + } + else + { + //so we have a base texture, and normalmap + //we already uploaded the diffuse, so now we can just pretend that the base is the specularmap. + //we just need to swap the two alpha channels. + for (y = 0; y < baseheight; y++) + { + for (x = 0; x < basewidth; x++) + { + tmp = base[(x+y*basewidth)*4+3]; + base[(x+y*basewidth)*4+3] = norm[(x+y*basewidth)*4+3]; + norm[(x+y*basewidth)*4+3] = ((x+y)&1)*255;//tmp; + } + } + tex->bump = Image_GetTexture(va("%s_norm", imagename), subpath, imageflags|IF_NOREPLACE, norm, NULL, normwidth, normheight, TF_RGBA32); //queues the texture creation. + tex->specular = Image_GetTexture(va("%s_spec", imagename), subpath, imageflags|IF_NOREPLACE, base, NULL, basewidth, baseheight, TF_RGBA32); //queues the texture creation. + } + BZ_Free(norm); + } + else + { + //generate a height8 image from the alpha channel. we can do it in place + for (y = 0; y < baseheight; y++) + { + for (x = 0; x < basewidth; x++) + base[(x+y*basewidth)] = base[(x+y*basewidth)*4+3]; + } + tex->bump = Image_GetTexture(va("%s_norm", imagename), subpath, imageflags|IF_NOREPLACE, base, NULL, basewidth, baseheight, TF_HEIGHT8); + } + BZ_Free(base); + } + } +#endif + /*dlights/realtime lighting needs some stuff*/ if (loadflags & SHADER_HASDIFFUSE) { @@ -5663,7 +5765,7 @@ void QDECL R_BuildLegacyTexnums(shader_t *shader, const char *fallbackname, cons if (!TEXVALID(tex->paletted) && *mapname) tex->paletted = R_LoadHiResTexture(va("%s_pal", mapname), NULL, imageflags|IF_NEAREST); if (!TEXVALID(tex->paletted)) - tex->paletted = Image_GetTexture(va("%s_pal", imagename), subpath, imageflags|IF_NEAREST, mipdata[0], palette, width, height, (basefmt==TF_MIP4_SOLID8)?TF_MIP4_LUM8:TF_LUM8); + tex->paletted = Image_GetTexture(va("%s_pal", imagename), subpath, imageflags|IF_NEAREST|IF_NOSRGB, mipdata[0], palette, width, height, (basefmt==TF_MIP4_SOLID8)?TF_MIP4_R8:TF_R8); } imageflags |= IF_LOWPRIORITY; @@ -5768,7 +5870,7 @@ void Shader_DefaultBSPLM(const char *shortname, shader_t *s, const void *args) "{\n" "map $lightmap\n" "tcgen lightmap\n" - "rgbgen const 255 255 255\n" + "rgbgen srgb 255 255 255\n" "}\n" "}\n" ); @@ -5780,7 +5882,7 @@ void Shader_DefaultBSPLM(const char *shortname, shader_t *s, const void *args) "{\n" "map $lightmap\n" "tcgen lightmap\n" - "rgbgen const $r_floorcolour\n" + "rgbgen srgb $r_floorcolour\n" "}\n" "}\n" ); @@ -6021,7 +6123,7 @@ char *Shader_DefaultBSPWater(shader_t *s, const char *shortname, char *buffer, s // "program defaultfill\n" "{\n" "map $whiteimage\n" - "rgbgen const $r_fastturbcolour\n" + "rgbgen srgb $r_fastturbcolour\n" "}\n" "surfaceparm nodlight\n" "surfaceparm nomarks\n" @@ -6220,7 +6322,7 @@ void Shader_DefaultBSPQ1(const char *shortname, shader_t *s, const void *args) "sort sky\n" "{\n" "map $whiteimage\n" - "rgbgen const $r_fastskycolour\n" + "rgbgen srgb $r_fastskycolour\n" "}\n" "surfaceparm nodlight\n" "}\n" @@ -6921,7 +7023,36 @@ static char *Shader_DecomposeSubPass(char *o, shaderpass_t *p, qboolean simple) case T_GEN_SINGLEMAP: if (p->anim_frames[0]) { - sprintf(o, "singlemap \"%s\" %ix%i", p->anim_frames[0]->ident, p->anim_frames[0]->width, p->anim_frames[0]->height); + unsigned int flags = p->anim_frames[0]->flags; + sprintf(o, "singlemap \"%s\" %ix%i%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", p->anim_frames[0]->ident, p->anim_frames[0]->width, p->anim_frames[0]->height, + (p->anim_frames[0]->status == TEX_FAILED)?" FAILED":"", + (flags&IF_CLAMP)?" clamp":"", + (flags&IF_NOMIPMAP)?" nomipmap":"", + (flags&IF_NEAREST)?" nearest":"", + (flags&IF_LINEAR)?" linear":"", + (flags&IF_UIPIC)?" uipic":"", + (flags&IF_SRGB)?" srgb":"", + + (flags&IF_NOPICMIP)?" nopicmip":"", + (flags&IF_NOALPHA)?" noalpha":"", + (flags&IF_NOGAMMA)?" noalpha":"", + (flags&IF_TEXTYPE)?" non-2d":"", + (flags&IF_MIPCAP)?"":" nomipcap", + (flags&IF_PREMULTIPLYALPHA)?" premultiply":"", + + (flags&IF_NOSRGB)?" nosrgb":"", + + (flags&IF_PALETTIZE)?" palettize":"", + (flags&IF_NOPURGE)?" nopurge":"", + (flags&IF_HIGHPRIORITY)?" highpri":"", + (flags&IF_LOWPRIORITY)?" lowpri":"", + (flags&IF_LOADNOW)?" loadnow":"", + (flags&IF_TRYBUMP)?" trybump":"", + (flags&IF_RENDERTARGET)?" rendertarget":"", + (flags&IF_EXACTEXTENSION)?" exactext":"", + (flags&IF_NOREPLACE)?" noreplace":"", + (flags&IF_NOWORKER)?" noworker":"" + ); } else sprintf(o, "singlemap "); diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index 5e9a9c2d..ac8cd6c8 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -3445,7 +3445,7 @@ void Sh_PreGenerateLights(void) shadowtype = SMT_STENCILVOLUME; //shadowless and lights with an ambient term pass through walls, so need to affect EVERY leaf withing the sphere. - if (shadowtype == SMT_SHADOWLESS || dl->lightcolourscales[0]) + if ((shadowtype == SMT_SHADOWLESS || dl->lightcolourscales[0]) && cl.worldmodel->funcs.ClustersInSphere) lvis = cl.worldmodel->funcs.ClustersInSphere(cl.worldmodel, dl->origin, dl->radius, &lvisb2, NULL); else { //other lights only want to use the source leaf's pvs (clamped by the sphere) diff --git a/engine/gl/gl_terrain.h b/engine/gl/gl_terrain.h index 8024b0b6..9c386e0c 100644 --- a/engine/gl/gl_terrain.h +++ b/engine/gl/gl_terrain.h @@ -265,9 +265,23 @@ typedef struct unsigned int id; //networked/gamecode id. unsigned int axialplanes; //+x,+y,+z,-x,-y,-z. used for bevel stuff. unsigned int numplanes; - qboolean selected; //different shader stuff + unsigned char selected:1; //different shader stuff vec4_t *planes; vec3_t mins, maxs; //for optimisation and stuff + struct patchdata_s + { //unlit, always... + brushtex_t *tex; + unsigned short xpoints; + unsigned short ypoints; + struct + { + vec3_t v; + vec2_t tc; + vec3_t norm; + vec3_t sdir; + vec3_t tdir; + } verts[1]; //x+(y*xpoints) + } *patch; struct brushface_s { brushtex_t *tex; @@ -277,8 +291,8 @@ typedef struct unsigned short lmscale; int lightmap; unsigned short lmbase[2]; //min st coord of the lightmap atlas, in texels. - unsigned int relight:1; - unsigned int relit:1; + unsigned short relight:1; + unsigned short relit:1; int lmbias[2]; unsigned short lmextents[2]; qbyte *lightdata; diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index 1f2cb660..a841540e 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -153,6 +153,7 @@ void (APIENTRY *qglTexEnvi) (GLenum target, GLenum pname, GLint param); void (APIENTRY *qglTexGeni) (GLenum coord, GLenum pname, GLint param); void (APIENTRY *qglTexGenfv) (GLenum coord, GLenum pname, const GLfloat *param); void (APIENTRY *qglTexImage3D) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +void (APIENTRY *qglTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); void (APIENTRY *qglTranslatef) (GLfloat x, GLfloat y, GLfloat z); void (APIENTRY *qglVertex2f) (GLfloat x, GLfloat y); void (APIENTRY *qglVertex3f) (GLfloat x, GLfloat y, GLfloat z); @@ -190,6 +191,11 @@ GLboolean (APIENTRY *qglUnmapBufferARB)(GLenum target); void *(APIENTRY *qglMapBufferRange)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); #endif +void (APIENTRY *qglTexStorage2D)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); //gl4.2 +void (APIENTRY *qglTexStorage3D)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); //gl4.2 +void (APIENTRY *qglCompressedTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); //gl1.3 +void (APIENTRY *qglCompressedTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); //gl1.3 + void (APIENTRY *qglGenVertexArrays)(GLsizei n, GLuint *arrays); void (APIENTRY *qglBindVertexArray)(GLuint vaoarray); @@ -342,7 +348,6 @@ void (APIENTRY myGLDEBUGPROCAMD)(GLenum source, } #endif - int gl_mtexarbable=0; //max texture units qboolean gl_mtexable = false; @@ -779,17 +784,26 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) if (gl_config.gles) { //GL_ARB_texture_compression is not quite supported in gles, but works for custom compressed formats (like etc2). qglCompressedTexImage2DARB = (void *)getglext("glCompressedTexImage2D"); + qglCompressedTexImage3DARB = (void *)getglext("glCompressedTexImage3D"); + qglCompressedTexSubImage2D = (void *)getglext("glCompressedTexSubImage2D"); + qglCompressedTexSubImage3D = (void *)getglext("glCompressedTexSubImage3D"); qglGetCompressedTexImageARB = NULL; } else if (!gl_config.gles && gl_config.glversion > 1.3) { //GL_ARB_texture_compression is core in gl1.3 qglCompressedTexImage2DARB = (void *)getglext("glCompressedTexImage2D"); + qglCompressedTexImage3DARB = (void *)getglext("glCompressedTexImage3D"); + qglCompressedTexSubImage2D = (void *)getglext("glCompressedTexSubImage2D"); + qglCompressedTexSubImage3D = (void *)getglext("glCompressedTexSubImage3D"); qglGetCompressedTexImageARB = (void *)getglext("glGetCompressedTexImage"); gl_config.arb_texture_compression = true; } else if (GL_CheckExtension("GL_ARB_texture_compression")) { qglCompressedTexImage2DARB = (void *)getglext("glCompressedTexImage2DARB"); + qglCompressedTexImage3DARB = (void *)getglext("glCompressedTexImage3DARB"); + qglCompressedTexSubImage2D = (void *)getglext("glCompressedTexSubImage2DARB"); + qglCompressedTexSubImage3D = (void *)getglext("glCompressedTexSubImage3DARB"); qglGetCompressedTexImageARB = (void *)getglext("glGetCompressedTexImageARB"); if (!qglCompressedTexImage2DARB || !qglGetCompressedTexImageARB) @@ -835,6 +849,11 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) qglLockArraysEXT = (void *)getglext("glLockArraysEXT"); qglUnlockArraysEXT = (void *)getglext("glUnlockArraysEXT"); } + else + { + qglLockArraysEXT = NULL; + qglUnlockArraysEXT = NULL; + } /*various combiner features*/ gl_config.tex_env_combine = GL_CheckExtension("GL_EXT_texture_env_combine"); @@ -1095,12 +1114,24 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) else gl_config.geometryshaders = false; + if ((!gl_config.gles && gl_config.glversion >= 4.2) || + ( gl_config.gles && gl_config.glversion >= 3.0)) + { //from gles3.0 or gl4.2 onwards + qglTexStorage2D = getglext("glTexStorage2D"); + qglTexStorage3D = getglext("glTexStorage3D"); + } + else + { + qglTexStorage2D = NULL; + qglTexStorage3D = NULL; + } + #ifdef GL_STATIC gl_config.ext_framebuffer_objects = true; //exists as core in gles2 #else if ((gl_config.gles && gl_config.glversion >= 2) || //exists as core in gles2 (!gl_config.gles && gl_config.glversion >= 3) || //exists as core in gl3 - GL_CheckExtension("GL_ARB_framebuffer_object")) //exists as an extension in gl2 + GL_CheckExtension("GL_ARB_framebuffer_object")) //exists as an extension in gl2 (defined in terms of gl3 so no ARB postfix needed) { gl_config.ext_framebuffer_objects = true; qglGenFramebuffersEXT = (void *)getglext("glGenFramebuffers"); @@ -2783,6 +2814,7 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name)) qglTexGeni = (void *)getglcore("glTexGeni"); qglTexGenfv = (void *)getglcore("glTexGenfv"); qglTexImage3D = (void *)getglext("glTexImage3D"); + qglTexSubImage3D = (void *)getglext("glTexSubImage3D"); qglTranslatef = (void *)getglcore("glTranslatef"); qglVertex2f = (void *)getglcore("glVertex2f"); qglVertex3f = (void *)getglcore("glVertex3f"); @@ -2899,75 +2931,6 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name)) sh_config.texture2d_maxsize = 256; //early minidrivers might not implement this, but anything else should. qglGetIntegerv(GL_MAX_TEXTURE_SIZE, &sh_config.texture2d_maxsize); - //always supported - sh_config.texfmt[PTI_RGBA8] = true; - if (GL_CheckExtension("GL_EXT_texture_compression_s3tc")) - { - sh_config.texfmt[PTI_BC1_RGB] = true; - sh_config.texfmt[PTI_BC1_RGBA] = true; - sh_config.texfmt[PTI_BC2_RGBA] = true; - sh_config.texfmt[PTI_BC3_RGBA] = true; - } - else if (gl_config.gles) - { - sh_config.texfmt[PTI_BC1_RGB] = - sh_config.texfmt[PTI_BC1_RGBA] = GL_CheckExtension("GL_EXT_texture_compression_dxt1"); - sh_config.texfmt[PTI_BC2_RGBA] = GL_CheckExtension("GL_ANGLE_texture_compression_dxt3"); - sh_config.texfmt[PTI_BC3_RGBA] = GL_CheckExtension("GL_ANGLE_texture_compression_dxt5"); - } - if (GL_CheckExtension("GL_ARB_texture_compression_rgtc") || GL_CheckExtension("GL_EXT_texture_compression_rgtc")) - { - sh_config.texfmt[PTI_BC4_R8] = true; - sh_config.texfmt[PTI_BC4_R8_SIGNED] = true; - sh_config.texfmt[PTI_BC5_RG8] = true; - sh_config.texfmt[PTI_BC5_RG8_SIGNED] = true; - } - if ((!gl_config.gles && gl_config.glversion >= 4.2) || GL_CheckExtension("GL_ARB_texture_compression_bptc")) - sh_config.texfmt[PTI_BC6_RGBF] = sh_config.texfmt[PTI_BC6_RGBF_SIGNED] = - sh_config.texfmt[PTI_BC7_RGBA] = sh_config.texfmt[PTI_BC7_RGBA_SRGB] = true; - -#ifdef FTE_TARGET_WEB - if (GL_CheckExtension("WEBGL_compressed_texture_etc")) -#else - if ((gl_config.gles && gl_config.glversion >= 3.0) || (!gl_config.gles && (gl_config.glversion >= 4.3 || GL_CheckExtension("GL_ARB_ES3_compatibility")))) -#endif - { //gles3 and gl4.3 have mandatory support for etc2. probably desktop drivers will pre-decompress, but whatever. - //webgl tries to cater to d3d, so doesn't support this gles3 feature, because browser writers are lazy. - //warning: while support is mandatory, it may just be a driver trick with the hardware using uncompressed data. - sh_config.texfmt[PTI_ETC1_RGB8] = true; - - sh_config.texfmt[PTI_ETC2_RGB8] = true; - sh_config.texfmt[PTI_ETC2_RGB8A1] = true; - sh_config.texfmt[PTI_ETC2_RGB8A8] = true; - sh_config.texfmt[PTI_EAC_R11] = true; - sh_config.texfmt[PTI_EAC_R11_SIGNED] = true; - sh_config.texfmt[PTI_EAC_RG11] = true; - sh_config.texfmt[PTI_EAC_RG11_SIGNED] = true; - } - else - { - sh_config.texfmt[PTI_ETC1_RGB8] = GL_CheckExtension("GL_OES_compressed_ETC1_RGB8_texture"); - - sh_config.texfmt[PTI_ETC2_RGB8] = GL_CheckExtension("GL_OES_compressed_ETC2_RGB8_texture"); //or OES_compressed_ETC2_sRGB8_texture... - sh_config.texfmt[PTI_ETC2_RGB8A1] = GL_CheckExtension("GL_OES_compressed_ETC2_punchthroughA_RGBA8_texture"); //or OES_compressed_ETC2_punchthroughA_sRGB8_alpha_texture... - sh_config.texfmt[PTI_ETC2_RGB8A8] = GL_CheckExtension("GL_OES_compressed_ETC2_RGBA8_texture"); //or OES_compressed_ETC2_sRGB8_alpha8_texture - sh_config.texfmt[PTI_EAC_R11] = GL_CheckExtension("GL_OES_compressed_EAC_R11_unsigned_texture"); - sh_config.texfmt[PTI_EAC_R11_SIGNED] = GL_CheckExtension("GL_OES_compressed_EAC_R11_signed_texture"); - sh_config.texfmt[PTI_EAC_RG11] = GL_CheckExtension("GL_OES_compressed_EAC_RG11_unsigned_texture"); - sh_config.texfmt[PTI_EAC_RG11_SIGNED] = GL_CheckExtension("GL_OES_compressed_EAC_RG11_signed_texture"); - } - sh_config.texfmt[PTI_ETC1_RGB8] |= sh_config.texfmt[PTI_ETC2_RGB8]; - - if (GL_CheckExtension("GL_KHR_texture_compression_astc_ldr")) - { //24 different formats... - //hdr profile adds 3d slices, and support for the hdr subblocks (ldr-only will decode them as fixed-colour errors) - //full profile adds 3d blocks - //we don't do 3d astc textures, so the api doesn't change. either the gpu supports the data or parts get decoded as fixed colours, which is still better than our crappy fallback texture. - int gah; - for (gah = PTI_ASTC_4X4; gah <= PTI_ASTC_12X12_SRGB; gah++) - sh_config.texfmt[gah] = true; - } - /*note regarding GL_COMPRESSED_TEXTURE_FORMATS: nvidia lists bc1-3, oes paletted, etc2, astc, astc_srgb. so the only listed formats that the hardware actually supports are bc1-3. @@ -2977,21 +2940,6 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name)) if (gl_config.gles) { - qboolean srgb = false;//TEST ME GL_CheckExtension("GL_EXT_sRGB"); - - sh_config.texfmt[PTI_RGBX8] = sh_config.texfmt[PTI_RGBA8]; //FIXME: this is faked with PTI_RGBA8 - - sh_config.texfmt[PTI_RGB565] = !gl_config.webgl_ie; //ie sucks and doesn't support things that webgl requires it to support. - sh_config.texfmt[PTI_RGBA4444] = !gl_config.webgl_ie; - sh_config.texfmt[PTI_RGBA5551] = !gl_config.webgl_ie; - sh_config.texfmt[PTI_BGRX8] = sh_config.texfmt[PTI_BGRA8] = false; - -// sh_config.texfmt[PTI_RGBX8_SRGB] = sh_config.texfmt[PTI_RGBX8] && srgb; - sh_config.texfmt[PTI_RGBA8_SRGB] = sh_config.texfmt[PTI_RGBA8] && srgb; -// sh_config.texfmt[PTI_BGRX8_SRGB] = sh_config.texfmt[PTI_BGRX8] && srgb; - sh_config.texfmt[PTI_BGRA8_SRGB] = sh_config.texfmt[PTI_BGRA8] && srgb; - vid.srgb = info->srgb && srgb; - sh_config.minver = 100; if (gl_config.glversion >= 3.1) sh_config.maxver = 310; @@ -3009,45 +2957,10 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name)) } else { - GLint srgb = gl_config.glversion >= 2.1 || GL_CheckExtension("GL_EXT_texture_sRGB"); //became core in gl 2.1 sh_config.can_mipcap = gl_config.glversion >= 1.2; sh_config.havecubemaps = gl_config.glversion >= 1.3; //cubemaps AND clamp-to-edge. - sh_config.texfmt[PTI_RGBX8] = true; //proper support - - //these require stuff like GL_UNSIGNED_SHORT_5_5_5_1 etc, which needs gl 1.2+ - if (gl_config.glversion >= 1.2) - { - //16bit formats - sh_config.texfmt[PTI_RGB565] = true; - sh_config.texfmt[PTI_RGBA4444] = true; - sh_config.texfmt[PTI_RGBA5551] = true; - //bgr formats - if (GL_CheckExtension("GL_EXT_bgra")) - { - //32bit formats - sh_config.texfmt[PTI_BGRX8] = true; - sh_config.texfmt[PTI_BGRA8] = true; - //16bit formats - sh_config.texfmt[PTI_ARGB4444] = true; - sh_config.texfmt[PTI_ARGB1555] = true; - } - } - if (!gl_config.gles && (gl_config.glversion >= 1.4 || GL_CheckExtension("GL_ARB_depth_texture"))) - { //depth formats - sh_config.texfmt[PTI_DEPTH16] = true; - sh_config.texfmt[PTI_DEPTH24] = true; - sh_config.texfmt[PTI_DEPTH32] = true; - } - else if (gl_config.gles && GL_CheckExtension("GL_OES_depth_texture")) - { //16+32, not 24. - sh_config.texfmt[PTI_DEPTH16] = true; - sh_config.texfmt[PTI_DEPTH32] = true; - } - if (GL_CheckExtension("GL_EXT_packed_depth_stencil")) - sh_config.texfmt[PTI_DEPTH24_8] = true; - if (gl_config.nofixedfunc) { //core contexts don't normally support glsl < 140 (such glsl versions have lots of compat syntax still, which will not function on core. drivers might accept it anyway, but yeah, lots of crap that shouldn't work) //FIXME: GL_NUM_SHADING_LANGUAGE_VERSIONS and GL_SHADING_LANGUAGE_VERSION might allow for earlier versions. @@ -3068,18 +2981,6 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name)) sh_config.blobpath = "glsl/%s.blob"; sh_config.progpath = "glsl/%s.glsl"; sh_config.shadernamefmt = "%s_glsl"; - - sh_config.texfmt[PTI_RGBX8_SRGB] = sh_config.texfmt[PTI_RGBX8] && srgb; - sh_config.texfmt[PTI_RGBA8_SRGB] = sh_config.texfmt[PTI_RGBA8] && srgb; - sh_config.texfmt[PTI_BGRX8_SRGB] = sh_config.texfmt[PTI_BGRX8] && srgb; - sh_config.texfmt[PTI_BGRA8_SRGB] = sh_config.texfmt[PTI_BGRA8] && srgb; - sh_config.texfmt[PTI_BC1_RGB_SRGB] = sh_config.texfmt[PTI_BC1_RGB] && srgb; - sh_config.texfmt[PTI_BC1_RGBA_SRGB] = sh_config.texfmt[PTI_BC1_RGBA] && srgb; - sh_config.texfmt[PTI_BC2_RGBA_SRGB] = sh_config.texfmt[PTI_BC2_RGBA] && srgb; - sh_config.texfmt[PTI_BC3_RGBA_SRGB] = sh_config.texfmt[PTI_BC3_RGBA] && srgb; - sh_config.texfmt[PTI_ETC2_RGB8_SRGB] = sh_config.texfmt[PTI_ETC2_RGB8] && srgb; - sh_config.texfmt[PTI_ETC2_RGB8A1_SRGB] = sh_config.texfmt[PTI_ETC2_RGB8A1] && srgb; - sh_config.texfmt[PTI_ETC2_RGB8A8_SRGB] = sh_config.texfmt[PTI_ETC2_RGB8A8] && srgb; } sh_config.texturecube_maxsize = 0; @@ -3111,6 +3012,8 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name)) sh_config.env_add = gl_config.env_add; } + GL_SetupFormats(); + return true; } diff --git a/engine/gl/gl_videgl.c b/engine/gl/gl_videgl.c index e9971026..9ee3b302 100644 --- a/engine/gl/gl_videgl.c +++ b/engine/gl/gl_videgl.c @@ -208,6 +208,12 @@ qboolean EGL_Init (rendererstate_t *info, unsigned char *palette, EGLNativeWindo EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; + EGLint wndattrib[] = + { +// EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_LINEAR_KHR, + + EGL_NONE + }; EGLint contextattr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, //requires EGL 1.3 @@ -256,7 +262,7 @@ qboolean EGL_Init (rendererstate_t *info, unsigned char *palette, EGLNativeWindo return false; } - eglsurf = qeglCreateWindowSurface(egldpy, cfg, window, NULL); + eglsurf = qeglCreateWindowSurface(egldpy, cfg, window, info->srgb?wndattrib:NULL); if (eglsurf == EGL_NO_SURFACE) { Con_Printf(CON_ERROR "EGL: eglCreateWindowSurface failed: %x\n", qeglGetError()); diff --git a/engine/gl/gl_vidlinuxglx.c b/engine/gl/gl_vidlinuxglx.c index e1b4509f..7357b2d7 100644 --- a/engine/gl/gl_vidlinuxglx.c +++ b/engine/gl/gl_vidlinuxglx.c @@ -132,6 +132,8 @@ qboolean X11_CheckFeature(const char *featurename, qboolean defaultval) struct _XrmHashBucketRec; +typedef int (*qXErrorHandler) (Display*, XErrorEvent*); + static struct { void *lib; @@ -187,6 +189,8 @@ static struct int (*pXWarpPointer)(Display *display, Window src_w, Window dest_w, int src_x, int src_y, unsigned int src_width, unsigned int src_height, int dest_x, int dest_y); Status (*pXMatchVisualInfo)(Display *display, int screen, int depth, int class, XVisualInfo *vinfo_return); + qXErrorHandler (*pXSetErrorHandler)(XErrorHandler); + #define XI_RESOURCENAME "FTEQW" #define XI_RESOURCECLASS "FTEQW" char *(*pXSetLocaleModifiers)(char *modifier_list); @@ -207,6 +211,15 @@ static struct XIM inputmethod; } x11; +static int X11_ErrorHandler(Display *dpy, XErrorEvent *e) +{ + char msg[80]; +// XGetErrorText(dpy, e->error_code, msg, sizeof(msg)); + *msg = 0; + Con_Printf(CON_ERROR "XLib Error %d (%s): request %d.%d\n", e->error_code, msg, e->request_code, e->minor_code); + return 0; //ignored. +} + static qboolean x11_initlib(void) { static dllfunction_t x11_functable[] = @@ -276,6 +289,11 @@ static qboolean x11_initlib(void) //these ones are extensions, and the reason we're doing this. if (x11.lib) { + x11.pXSetErrorHandler = Sys_GetAddressForName(x11.lib, "XSetErrorHandler"); + + if (x11.pXSetErrorHandler) + x11.pXSetErrorHandler(X11_ErrorHandler); + //raw input (yay mouse deltas) x11.pXGetEventData = Sys_GetAddressForName(x11.lib, "XGetEventData"); x11.pXFreeEventData = Sys_GetAddressForName(x11.lib, "XFreeEventData"); @@ -1253,68 +1271,382 @@ char clipboard_buffer[SYS_CLIPBOARD_SIZE]; /*-----------------------------------------------------------------------*/ #ifdef GLQUAKE -static dllhandle_t *gllibrary; +static struct +{ + dllhandle_t *gllibrary; -XVisualInfo* (*qglXChooseVisual) (Display *dpy, int screen, int *attribList); -void (*qglXSwapBuffers) (Display *dpy, GLXDrawable drawable); -Bool (*qglXMakeCurrent) (Display *dpy, GLXDrawable drawable, GLXContext ctx); -GLXContext (*qglXCreateContext) (Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct); -void (*qglXDestroyContext) (Display *dpy, GLXContext ctx); -void *(*qglXGetProcAddress) (char *name); + const char *glxextensions; + + XVisualInfo* (*ChooseVisual) (Display *dpy, int screen, int *attribList); + void (*SwapBuffers) (Display *dpy, GLXDrawable drawable); + Bool (*MakeCurrent) (Display *dpy, GLXDrawable drawable, GLXContext ctx); + GLXContext (*CreateContext) (Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct); + void (*DestroyContext) (Display *dpy, GLXContext ctx); + + const char * (*QueryExtensionsString)(Display * dpy, int screen); + void *(*GetProcAddress) (char *name); + + GLXFBConfig *(*ChooseFBConfig)(Display *dpy, int screen, const int *attrib_list, int *nelements); + int (*GetFBConfigAttrib)(Display *dpy, GLXFBConfig config, int attribute, int * value); + XVisualInfo *(*GetVisualFromFBConfig)(Display *dpy, GLXFBConfig config); + GLXContext (*CreateContextAttribs)(Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list); +} glx; void GLX_CloseLibrary(void) { - Sys_CloseLibrary(gllibrary); - gllibrary = NULL; -} - -qboolean GLX_InitLibrary(char *driver) -{ - dllfunction_t funcs[] = - { - {(void*)&qglXChooseVisual, "glXChooseVisual"}, - {(void*)&qglXSwapBuffers, "glXSwapBuffers"}, - {(void*)&qglXMakeCurrent, "glXMakeCurrent"}, - {(void*)&qglXCreateContext, "glXCreateContext"}, - {(void*)&qglXDestroyContext, "glXDestroyContext"}, - {NULL, NULL} - }; - - if (driver && *driver) - gllibrary = Sys_LoadLibrary(driver, funcs); - else - gllibrary = NULL; -#ifdef __CYGWIN__ - if (!gllibrary) - gllibrary = Sys_LoadLibrary("cygGL-1.dll", funcs); -#endif - if (!gllibrary) //I hate this. - gllibrary = Sys_LoadLibrary("libGL.so.1", funcs); - if (!gllibrary) - gllibrary = Sys_LoadLibrary("libGL", funcs); - if (!gllibrary) - return false; - - qglXGetProcAddress = Sys_GetAddressForName(gllibrary, "glXGetProcAddress"); - if (!qglXGetProcAddress) - qglXGetProcAddress = Sys_GetAddressForName(gllibrary, "glXGetProcAddressARB"); - - return true; + Sys_CloseLibrary(glx.gllibrary); + glx.gllibrary = NULL; } void *GLX_GetSymbol(char *name) { void *symb; - if (qglXGetProcAddress) - symb = qglXGetProcAddress(name); + if (glx.GetProcAddress) + symb = glx.GetProcAddress(name); else symb = NULL; if (!symb) - symb = Sys_GetAddressForName(gllibrary, name); + symb = Sys_GetAddressForName(glx.gllibrary, name); return symb; } + +qboolean GLX_InitLibrary(char *driver) +{ + dllfunction_t funcs[] = + { + {(void*)&glx.ChooseVisual, "glXChooseVisual"}, + {(void*)&glx.SwapBuffers, "glXSwapBuffers"}, + {(void*)&glx.MakeCurrent, "glXMakeCurrent"}, + {(void*)&glx.CreateContext, "glXCreateContext"}, + {(void*)&glx.DestroyContext, "glXDestroyContext"}, + {NULL, NULL} + }; + memset(&glx, 0, sizeof(glx)); + + if (driver && *driver) + glx.gllibrary = Sys_LoadLibrary(driver, funcs); + else + glx.gllibrary = NULL; +#ifdef __CYGWIN__ + if (!glx.gllibrary) + glx.gllibrary = Sys_LoadLibrary("cygGL-1.dll", funcs); +#endif + if (!glx.gllibrary) //I hate this. + glx.gllibrary = Sys_LoadLibrary("libGL.so.1", funcs); + if (!glx.gllibrary) + glx.gllibrary = Sys_LoadLibrary("libGL", funcs); + if (!glx.gllibrary) + return false; + + glx.GetProcAddress = GLX_GetSymbol("glXGetProcAddress"); + if (!glx.GetProcAddress) + glx.GetProcAddress = GLX_GetSymbol("glXGetProcAddressARB"); + glx.QueryExtensionsString = GLX_GetSymbol("glXQueryExtensionsString"); + + glx.ChooseFBConfig = GLX_GetSymbol("glXChooseFBConfig"); + glx.GetFBConfigAttrib = GLX_GetSymbol("glXGetFBConfigAttrib"); + glx.GetVisualFromFBConfig = GLX_GetSymbol("glXGetVisualFromFBConfig"); + glx.CreateContextAttribs = GLX_GetSymbol("glXCreateContextAttribsARB"); + + return true; +} + +#ifndef GLX_RGBA_FLOAT_BIT +#define GLX_RGBA_FLOAT_BIT 0x00000004 +#endif +#ifndef GLX_CONTEXT_OPENGL_NO_ERROR_ARB +#define GLX_CONTEXT_OPENGL_NO_ERROR_ARB 0x31B3 +#endif + +qboolean GLX_CheckExtension(const char *ext) +{ + const char *e = glx.glxextensions, *n; + size_t el = strlen(ext); + while(e && *e) + { + while (*e == ' ') + e++; + n = strchr(e, ' '); + if (!n) + n = n+strlen(e); + + if (n-e == el && !strncmp(ext, e, el)) + { + Con_DPrintf("GLX: Found %s\n", ext); + return true; + } + e = n; + } + Con_DPrintf("GLX: Missing %s\n", ext); + return false; +} + +//Since GLX1.3 (equivelent to gl1.2) +GLXFBConfig GLX_GetFBConfig(rendererstate_t *info) +{ + int attrib[32]; + int n, i; + int numconfigs; + GLXFBConfig *fbconfigs; + + qboolean hassrgb, hasmultisample, hasfloats; + + if (glx.QueryExtensionsString) + glx.glxextensions = glx.QueryExtensionsString(vid_dpy, scrnum); + + if (!glx.ChooseFBConfig || !glx.GetVisualFromFBConfig) + { + Con_Printf("Missing function pointer\n"); + return NULL; + } + if (!glx.CreateContextAttribs) + { + Con_Printf("Missing CreateContextAttribs\n"); + return NULL; //don't worry about it + } + + hassrgb = GLX_CheckExtension("GLX_ARB_framebuffer_sRGB"); + hasmultisample = GLX_CheckExtension("GLX_ARB_multisample"); + hasfloats = GLX_CheckExtension("GLX_ARB_fbconfig_float"); + + //do it in a loop, mostly to disable extensions that are unlikely to be supported on various glx implementations. + for (i = 0; i < (16<<1); i++) + { + n = 0; + //attrib[n++] = GLX_LEVEL; attrib[n++] = 0; //overlays + attrib[n++] = GLX_DOUBLEBUFFER; attrib[n++] = True; + if (!(i&1)) + { + if (!info->stereo) + continue; + attrib[n++] = GLX_STEREO; attrib[n++] = True; + } + if (!(i&2)) + { + if (!info->srgb || !hassrgb) + continue; + attrib[n++] = GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB; attrib[n++] = True; + } + //attrib[n++] = GLX_AUX_BUFFERS; attrib[n++] = 0; + + + if (!(i&4)) + { + if (info->srgb <= 2 || !hasfloats) + continue; //skip fp16 framebuffers + attrib[n++] = GLX_RENDER_TYPE; attrib[n++] = GLX_RGBA_FLOAT_BIT; + attrib[n++] = GLX_RED_SIZE; attrib[n++] = info->bpp?info->bpp/3:4; + attrib[n++] = GLX_GREEN_SIZE; attrib[n++] = info->bpp?info->bpp/3:4; + attrib[n++] = GLX_BLUE_SIZE; attrib[n++] = info->bpp?info->bpp/3:4; + } + else + { + if (info->bpp > 24) + { + attrib[n++] = GLX_RED_SIZE; attrib[n++] = 8; + attrib[n++] = GLX_GREEN_SIZE; attrib[n++] = 8; + attrib[n++] = GLX_BLUE_SIZE; attrib[n++] = 8; + } + else + { + attrib[n++] = GLX_RED_SIZE; attrib[n++] = info->bpp?info->bpp/3:4; + attrib[n++] = GLX_GREEN_SIZE; attrib[n++] = info->bpp?info->bpp/3:4; + attrib[n++] = GLX_BLUE_SIZE; attrib[n++] = info->bpp?info->bpp/3:4; + } + } + //attrib[n++] = GLX_ALPHA_SIZE; attrib[n++] = GLX_DONT_CARE; + attrib[n++] = GLX_DEPTH_SIZE; attrib[n++] = 16; + attrib[n++] = GLX_STENCIL_SIZE; attrib[n++] = (i&16)?0:4; + + if (!(i&8)) + { + if (!info->multisample || !hasmultisample) + continue; + attrib[n++] = GLX_SAMPLE_BUFFERS_ARB; attrib[n++] = True; + attrib[n++] = GLX_SAMPLES_ARB, attrib[n++] = info->multisample; + } + + //attrib[n++] = GLX_ACCUM_RED_SIZE; attrib[n++] = 0; + //attrib[n++] = GLX_ACCUM_GREEN_SIZE; attrib[n++] = 0; + //attrib[n++] = GLX_ACCUM_BLUE_SIZE; attrib[n++] = 0; + //attrib[n++] = GLX_ACCUM_ALPHA_SIZE; attrib[n++] = 0; + + attrib[n++] = GLX_DRAWABLE_TYPE; attrib[n++] = GLX_WINDOW_BIT; + attrib[n++] = GLX_X_RENDERABLE; attrib[n++] = True; + //attrib[n++] = GLX_X_VISUAL_TYPE; attrib[n++] = info->srgb?GLX_TRUE_COLOR:GLX_DIRECT_COLOR; + //attrib[n++] = GLX_CONFIG_CAVEAT; attrib[n++] = GLX_DONT_CARE; GLX_NONE||GLX_SLOW_CONFIG||GLX_NON_CONFORMANT_CONFIG + //attrib[n++] = GLX_TRANSPARENT_TYPE;attrib[n++] = GLX_NONE; + //attrib[n++] = GLX_TRANSPARENT_ALPHA_VALUE;attrib[n++] = 0; + attrib[n++] = None; + + numconfigs = 0; + fbconfigs = glx.ChooseFBConfig(vid_dpy, scrnum, attrib, &numconfigs); + if (fbconfigs) + { + if (numconfigs) + { + GLXFBConfig r = fbconfigs[0]; + x11.pXFree(fbconfigs); + return r; + } + x11.pXFree(fbconfigs); + } + } + return NULL; +} +//for GLX<1.3 +XVisualInfo *GLX_GetVisual(rendererstate_t *info) +{ + XVisualInfo *visinfo; + int attrib[32]; + int numattrib, i; + + //do it in a loop, mostly to disable extensions that are unlikely to be supported on various glx implementations. + for (i = 0; i < (8<<1); i++) + { + numattrib = 0; + attrib[numattrib++] = GLX_RGBA; + attrib[numattrib++] = GLX_DOUBLEBUFFER; + if (!(i&1)) + { + if (!info->stereo) + continue; + attrib[numattrib++] = GLX_STEREO; + } + if (!(i&2)) + { + if (!info->srgb) + continue; + attrib[numattrib++] = GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB; + } + if (!(i&4)) + { + if (!info->multisample) + continue; + attrib[numattrib++] = GLX_SAMPLE_BUFFERS_ARB; attrib[numattrib++] = info->multisample; + } + if (!(i&8)) + { + attrib[numattrib++] = GLX_STENCIL_SIZE; attrib[numattrib++] = 4; + } + attrib[numattrib++] = GLX_RED_SIZE; attrib[numattrib++] = 4; + attrib[numattrib++] = GLX_GREEN_SIZE; attrib[numattrib++] = 4; + attrib[numattrib++] = GLX_BLUE_SIZE; attrib[numattrib++] = 4; + attrib[numattrib++] = GLX_DEPTH_SIZE; attrib[numattrib++] = 16; + attrib[numattrib++] = None; + + visinfo = glx.ChooseVisual(vid_dpy, scrnum, attrib); + if (visinfo) + return visinfo; + } + return NULL; +} + +qboolean GLX_Init(rendererstate_t *info, GLXFBConfig fbconfig, XVisualInfo *visinfo) +{ + extern cvar_t vid_gl_context_version; + extern cvar_t vid_gl_context_forwardcompatible; + extern cvar_t vid_gl_context_compatibility; + extern cvar_t vid_gl_context_debug; + extern cvar_t vid_gl_context_es; + extern cvar_t vid_gl_context_robustness; +// extern cvar_t vid_gl_context_selfreset; + extern cvar_t vid_gl_context_noerror; + + if (fbconfig && glx.CreateContextAttribs) + { + unsigned int majorver=1, minorver=1; + unsigned profile = 0; + unsigned contextflags = 0; + int attrib[16*2+1]; + int n, val; + char *ver; + + ver = vid_gl_context_version.string; + if (!*ver && vid_gl_context_es.ival && GLX_CheckExtension("GLX_EXT_create_context_es_profile")) + ver = vid_gl_context_es.string; + if (!*ver && !vid_gl_context_compatibility.ival && *vid_gl_context_compatibility.string) + ver = "3.2"; //if the user explicitly disabled compat, then they'll want a version that actually supports doing so. + + majorver = strtoul(ver, &ver, 10); + if (*ver == '.') + minorver = strtoul(ver+1, &ver, 10); + else + minorver = 0; + + //some weirdness for you: + //3.0 simply marked stuff as deprecated, without removing it. + //3.1 removed it (moved to the optional GL_ARB_compatibility extension, which shouldn't be supported in a forward-compatible context). + //3.2 added the concept of profiles. + + if (vid_gl_context_debug.ival) + contextflags |= GLX_CONTEXT_DEBUG_BIT_ARB; + if (vid_gl_context_forwardcompatible.ival) //treat this as a dev/debug thing. + contextflags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + if (vid_gl_context_robustness.ival && GLX_CheckExtension("GLX_ARB_create_context_robustness")) + contextflags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; + + if (vid_gl_context_es.ival && GLX_CheckExtension("GLX_EXT_create_context_es_profile")) + profile = GLX_CONTEXT_ES_PROFILE_BIT_EXT; + else if (majorver>3 || (majorver==3&&minorver>=2)) + { //profiles only started with 3.2 + if (vid_gl_context_compatibility.ival) + profile = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; + else + profile = GLX_CONTEXT_CORE_PROFILE_BIT_ARB; + } + else + profile = 0; + + n = 0; + if (majorver || minorver) + { + attrib[n++] = GLX_CONTEXT_MAJOR_VERSION_ARB; attrib[n++] = majorver; + attrib[n++] = GLX_CONTEXT_MINOR_VERSION_ARB; attrib[n++] = minorver; + } + if (contextflags) + { + attrib[n++] = GLX_CONTEXT_FLAGS_ARB; attrib[n++] = contextflags; + } + if (profile) + { + attrib[n++] = GLX_CONTEXT_PROFILE_MASK_ARB; attrib[n++] = profile; + } + if (vid_gl_context_noerror.ival && GLX_CheckExtension("GLX_ARB_create_context_no_error")) + { + attrib[n++] = GLX_CONTEXT_OPENGL_NO_ERROR_ARB; attrib[n++] = !vid_gl_context_robustness.ival && !vid_gl_context_debug.ival; + } + attrib[n++] = None; + + if (glx.GetFBConfigAttrib) + { + if (glx.GetFBConfigAttrib(vid_dpy, fbconfig, GLX_RENDER_TYPE, &val) && val == GLX_RGBA_FLOAT_BIT) + vid.flags |= VID_FP16; //other things need to be 16bit too, to avoid loss of precision. + if (glx.GetFBConfigAttrib(vid_dpy, fbconfig, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, &val) && val) + vid.flags |= VID_SRGB_CAPABLE; //can use srgb properly, without faking it etc. + } + + ctx = glx.CreateContextAttribs(vid_dpy, fbconfig, NULL, True, attrib); + } + else + ctx = glx.CreateContext(vid_dpy, visinfo, NULL, True); + if (!ctx) + { + Con_Printf("Failed to create GLX context.\n"); + return false; + } + + if (!glx.MakeCurrent(vid_dpy, vid_window, ctx)) + { + Con_Printf("glXMakeCurrent failed\n"); + return false; + } + + //okay, we have a context, now init OpenGL-proper. + return GL_Init(info, &GLX_GetSymbol); +} #endif static void X_ShutdownUnicode(void) @@ -2082,7 +2414,7 @@ void GLVID_Shutdown(void) case PSL_GLX: if (ctx) { - qglXDestroyContext(vid_dpy, ctx); + glx.DestroyContext(vid_dpy, ctx); ctx = NULL; } break; @@ -2393,7 +2725,7 @@ void GLVID_SwapBuffers (void) case PSL_GLX: //we don't need to flush, XSawpBuffers does it for us. //chances are, it's version is more suitable anyway. At least there's the chance that it might be. - qglXSwapBuffers(vid_dpy, vid_window); + glx.SwapBuffers(vid_dpy, vid_window); break; #endif #ifdef VKQUAKE @@ -2414,11 +2746,19 @@ void X_StoreIcon(Window wnd) Atom proptype = x11.pXInternAtom(vid_dpy, "CARDINAL", false); size_t filesize; - qbyte *filedata = FS_LoadMallocFile("icon.png", &filesize); + qbyte *filedata = NULL; +#ifdef AVAIL_PNGLIB if (!filedata) - FS_LoadMallocFile("icon.tga", &filesize); + filedata = FS_LoadMallocFile("icon.png", &filesize); +#endif if (!filedata) - FS_LoadMallocFile("icon.jpg", &filesize); + filedata = FS_LoadMallocFile("icon.tga", &filesize); +#ifdef AVAIL_JPEGLIB + if (!filedata) + filedata = FS_LoadMallocFile("icon.jpg", &filesize); +#endif + if (!filedata) + filedata = FS_LoadMallocFile("icon.ico", &filesize); if (filedata) { int imagewidth, imageheight; @@ -2638,22 +2978,13 @@ qboolean X11VID_Init (rendererstate_t *info, unsigned char *palette, int psl) int width = info->width; //can override these if vmode isn't available int height = info->height; int rate = info->rate; -#ifdef GLQUAKE - int attrib[] = { - GLX_RGBA, - GLX_RED_SIZE, 4, - GLX_GREEN_SIZE, 4, - GLX_BLUE_SIZE, 4, - GLX_DOUBLEBUFFER, - GLX_DEPTH_SIZE, 16, - GLX_STENCIL_SIZE, 4, - None - }; -#endif #if defined(USE_EGL) || defined(VKQUAKE) XVisualInfo vinfodef; #endif XVisualInfo *visinfo; +#ifdef GLQUAKE + GLXFBConfig fbconfig = NULL; +#endif qboolean fullscreen = false; if (!x11_initlib()) @@ -2780,10 +3111,16 @@ qboolean X11VID_Init (rendererstate_t *info, unsigned char *palette, int psl) break; #endif case PSL_GLX: - visinfo = qglXChooseVisual(vid_dpy, scrnum, attrib); + fbconfig = GLX_GetFBConfig(info); + if (fbconfig) + visinfo = glx.GetVisualFromFBConfig(vid_dpy, fbconfig); + else + visinfo = GLX_GetVisual(info); if (!visinfo) { - Sys_Error("X11VID_Init: Error couldn't get an RGB, Double-buffered, Depth visual\n"); + Con_Printf("X11VID_Init: Error couldn't get an RGB, Double-buffered, Depth visual\n"); + GLVID_Shutdown(); + return false; } break; #endif @@ -2841,7 +3178,7 @@ qboolean X11VID_Init (rendererstate_t *info, unsigned char *palette, int psl) if (rampsize > countof(vm.originalramps[0])) { vm.originalapplied = false; - Con_Printf("Gamma ramps are not of 256 components (but %i).\n", rampsize); + Con_Printf("Gamma ramps have more than %zi entries (%i).\n", countof(vm.originalramps[0]), rampsize); } else { @@ -2855,23 +3192,11 @@ qboolean X11VID_Init (rendererstate_t *info, unsigned char *palette, int psl) { #ifdef GLQUAKE case PSL_GLX: - ctx = qglXCreateContext(vid_dpy, visinfo, NULL, True); - if (!ctx) + if (!GLX_Init(info, fbconfig, visinfo)) { - Con_Printf("Failed to create GLX context.\n"); GLVID_Shutdown(); return false; } - - if (!qglXMakeCurrent(vid_dpy, vid_window, ctx)) - { - Con_Printf("glXMakeCurrent failed\n"); - GLVID_Shutdown(); - return false; - } - - if (!GL_Init(info, &GLX_GetSymbol)) - return false; break; #ifdef USE_EGL case PSL_EGL: @@ -3083,7 +3408,7 @@ void Force_CenterView_f (void) //these are done from the x11 event handler. we don't support evdev. -void INS_Move(float *movements, int pnum) +void INS_Move(void) { } void INS_Commands(void) diff --git a/engine/gl/gl_vidmacos.c b/engine/gl/gl_vidmacos.c index 3d818925..aa14bea8 100644 --- a/engine/gl/gl_vidmacos.c +++ b/engine/gl/gl_vidmacos.c @@ -208,7 +208,7 @@ void INS_Commands (void) void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, unsigned int *qdevid)) { } -void INS_Move (float *movements, int pnum) +void INS_Move (void) { } diff --git a/engine/gl/gl_vidnt.c b/engine/gl/gl_vidnt.c index 81648a48..7c2d7611 100644 --- a/engine/gl/gl_vidnt.c +++ b/engine/gl/gl_vidnt.c @@ -264,6 +264,12 @@ static HGLRC (APIENTRY *qwglCreateContextAttribsARB)(HDC hDC, HGLRC hShareContex #define WGL_DEPTH_BITS_ARB 0x2022 #define WGL_STENCIL_BITS_ARB 0x2023 #define WGL_FULL_ACCELERATION_ARB 0x2027 +#define WGL_PIXEL_TYPE_ARB 0x2013 +#define WGL_TYPE_RGBA_ARB 0x202B +#define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0 +#define WGL_RED_BITS_ARB 0x2015 +#define WGL_GREEN_BITS_ARB 0x2017 +#define WGL_BLUE_BITS_ARB 0x2019 @@ -1263,9 +1269,9 @@ static qboolean VID_SetFullDIBMode (rendererstate_t *info) SendMessage (dibwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon); if (modestate == MS_FULLWINDOW) - ShowWindow (dibwindow, SW_SHOWMAXIMIZED); + ShowWindow (dibwindow, SW_HIDE);//SW_SHOWMAXIMIZED); else - ShowWindow (dibwindow, SW_SHOWDEFAULT); + ShowWindow (dibwindow, SW_HIDE);//SW_SHOWDEFAULT); UpdateWindow (dibwindow); // Because we have set the background brush for the window to NULL @@ -1487,6 +1493,16 @@ static int GLVID_SetMode (rendererstate_t *info, unsigned char *palette) return false; } } + else + { + TRACE(("dbg: GLVID_SetMode: unable to create window\n")); + return false; + } + + if (modestate == MS_FULLWINDOW) + ShowWindow (dibwindow, SW_SHOWMAXIMIZED); + else + ShowWindow (dibwindow, SW_SHOWDEFAULT); if (!GL_Init(info, getglfunc)) return false; @@ -1509,7 +1525,7 @@ static int GLVID_SetMode (rendererstate_t *info, unsigned char *palette) stat = EGL_Init (info, palette, mainwindow, maindc); if (stat) - if (GL_Init(info, &EGL_Proc)) + if (!GL_Init(info, &EGL_Proc)) return false; } break; @@ -1558,6 +1574,7 @@ static int GLVID_SetMode (rendererstate_t *info, unsigned char *palette) #ifndef NPFTE /*I don't like this, but if we */ + Sleep (100); while (PeekMessage (&msg, mainwindow, 0, 0, PM_REMOVE)) { TranslateMessage (&msg); @@ -1572,6 +1589,14 @@ static int GLVID_SetMode (rendererstate_t *info, unsigned char *palette) SetForegroundWindow (mainwindow); + Sleep (100); + while (PeekMessage (&msg, mainwindow, 0, 0, PM_REMOVE)) + { + TranslateMessage (&msg); + DispatchMessage (&msg); + } + Sleep (100); + // fix the leftover Alt from any Alt-Tab or the like that switched us away ClearAllStates (); @@ -1778,6 +1803,9 @@ static qboolean WGL_CheckExtension(char *extname) qboolean VID_AttachGL (rendererstate_t *info) { //make sure we can get a valid renderer. + int iAttributeNames[2]; + FLOAT fAttributeValues[countof(iAttributeNames)]; + do { TRACE(("dbg: VID_AttachGL: GLInitialise\n")); @@ -1981,6 +2009,14 @@ qboolean VID_AttachGL (rendererstate_t *info) TRACE(("dbg: VID_AttachGL: qwglSwapIntervalEXT\n")); qwglSwapIntervalEXT(vid_vsync.value); } + + vid.flags = 0; + iAttributeNames[0] = WGL_PIXEL_TYPE_ARB; + iAttributeNames[1] = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB; + if (qwglGetPixelFormatAttribfvARB && qwglGetPixelFormatAttribfvARB(maindc, currentpixelformat, 0, 1, iAttributeNames+0, fAttributeValues+0) && fAttributeValues[0] == WGL_TYPE_RGBA_FLOAT_ARB) + vid.flags |= VID_FP16 | VID_SRGB_FB_LINEAR; + if (qwglGetPixelFormatAttribfvARB && qwglGetPixelFormatAttribfvARB(maindc, currentpixelformat, 0, 1, iAttributeNames+1, fAttributeValues+1) && fAttributeValues[1] == TRUE) + vid.flags |= VID_SRGB_CAPABLE; return true; } #endif @@ -2153,6 +2189,7 @@ qboolean GLVID_ApplyGammaRamps (unsigned int gammarampsize, unsigned short *ramp { case 0: //never use hardware/glsl gamma case 2: //ALWAYS use glsl gamma + case 4: //scene-only gamma return false; default: case 1: //no hardware gamma when windowed @@ -2244,7 +2281,7 @@ void GLVID_Shutdown (void) #ifdef USE_WGL static BOOL CheckForcePixelFormat(rendererstate_t *info) { - if (qwglChoosePixelFormatARB && (info->multisample || info->srgb)) + if (qwglChoosePixelFormatARB && (info->multisample || info->srgb || info->bpp==30)) { HDC hDC; int valid; @@ -2257,8 +2294,44 @@ static BOOL CheckForcePixelFormat(rendererstate_t *info) iAttribute[iAttributes++] = WGL_DRAW_TO_WINDOW_ARB; iAttribute[iAttributes++] = GL_TRUE; iAttribute[iAttributes++] = WGL_SUPPORT_OPENGL_ARB; iAttribute[iAttributes++] = GL_TRUE; iAttribute[iAttributes++] = WGL_ACCELERATION_ARB; iAttribute[iAttributes++] = WGL_FULL_ACCELERATION_ARB; - iAttribute[iAttributes++] = WGL_COLOR_BITS_ARB; iAttribute[iAttributes++] = (info->bpp>24)?24:info->bpp; -// iAttribute[iAttributes++] = WGL_ALPHA_BITS_ARB; iAttribute[iAttributes++] = 4; + + if (info->srgb>=3 && modestate != MS_WINDOWED) + { //half-float backbuffers! + + //'as has been the case since Windows Vista, fp16 swap chains are expected to have linear color data' + //if we try using WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, then we won't actually get a pixelformat. + //we just have to assume that its a linear colour space. + + //we ONLY use this fullscreen, because its totally fucked on nvidia otherwise. + //when windowed, its an scRGB image but with and srgb capable false, when fullscreen its always linear until something else takes focus... + //so if windowed or unfocused or whatever, we would need to use custom glsl to fix the gamma settings. + + //additionally, a single program using floats will disable the desktop compositor, which can be a bit jarring. + + iAttribute[iAttributes++] = WGL_PIXEL_TYPE_ARB; iAttribute[iAttributes++] = WGL_TYPE_RGBA_FLOAT_ARB; + iAttribute[iAttributes++] = WGL_RED_BITS_ARB; iAttribute[iAttributes++] = 16; + iAttribute[iAttributes++] = WGL_GREEN_BITS_ARB; iAttribute[iAttributes++] = 16; + iAttribute[iAttributes++] = WGL_BLUE_BITS_ARB; iAttribute[iAttributes++] = 16; + } + else + { + if (info->srgb) + { + iAttribute[iAttributes++] = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB; iAttribute[iAttributes++] = info->bpp<=32; + } + if (info->bpp==30) + { //10-bit backbuffers! + // iAttribute[iAttributes++] = WGL_PIXEL_TYPE_ARB; iAttribute[iAttributes++] = WGL_TYPE_RGBA_FLOAT_ARB; + iAttribute[iAttributes++] = WGL_RED_BITS_ARB; iAttribute[iAttributes++] = 10; + iAttribute[iAttributes++] = WGL_GREEN_BITS_ARB; iAttribute[iAttributes++] = 10; + iAttribute[iAttributes++] = WGL_BLUE_BITS_ARB; iAttribute[iAttributes++] = 10; + } + else + { + iAttribute[iAttributes++] = WGL_COLOR_BITS_ARB; iAttribute[iAttributes++] = (info->bpp>24)?24:info->bpp; + } + } +// iAttribute[iAttributes++] = WGL_ALPHA_BITS_ARB; iAttribute[iAttributes++] = 2; iAttribute[iAttributes++] = WGL_DEPTH_BITS_ARB; iAttribute[iAttributes++] = 16; iAttribute[iAttributes++] = WGL_STENCIL_BITS_ARB; iAttribute[iAttributes++] = 8; iAttribute[iAttributes++] = WGL_DOUBLE_BUFFER_ARB; iAttribute[iAttributes++] = GL_TRUE; @@ -2268,10 +2341,6 @@ static BOOL CheckForcePixelFormat(rendererstate_t *info) iAttribute[iAttributes++] = WGL_SAMPLE_BUFFERS_ARB; iAttribute[iAttributes++] = GL_TRUE; iAttribute[iAttributes++] = WGL_SAMPLES_ARB, iAttribute[iAttributes++] = info->multisample; // Check For 4x Multisampling } - if (info->srgb) - { - iAttribute[iAttributes++] = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB; iAttribute[iAttributes++] = GL_TRUE; - } iAttribute[iAttributes++] = 0; iAttribute[iAttributes++] = 0; @@ -2318,7 +2387,7 @@ static BOOL CheckForcePixelFormat(rendererstate_t *info) {"WGL_SUPPORT_OPENGL", WGL_SUPPORT_OPENGL_ARB}, {"WGL_DOUBLE_BUFFER", WGL_DOUBLE_BUFFER_ARB}, {"WGL_STEREO", WGL_STEREO_ARB}, - {"WGL_PIXEL_TYPE", 0x2013}, + {"WGL_PIXEL_TYPE", WGL_PIXEL_TYPE_ARB}, {"WGL_COLOR_BITS", WGL_COLOR_BITS_ARB}, {"WGL_RED_BITS", 0x2015}, {"WGL_RED_SHIFT", 0x2016}, @@ -2352,9 +2421,7 @@ static BOOL CheckForcePixelFormat(rendererstate_t *info) {"WGL_COLORSPACE_EXT", 0x309D}, //WGL_EXT_colorspace //stuff my drivers don't support -// {"WGL_TYPE_RGBA_FLOAT_ARB", 0x21A0}, // {"WGL_DEPTH_FLOAT_EXT", 0x2040}, -// {"WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT",0x20A8}, //EXT_packed_float }; int iAttributeNames[countof(iAttributeTable)]; float fAttributeValues[countof(iAttributeTable)]; @@ -2380,7 +2447,11 @@ static BOOL CheckForcePixelFormat(rendererstate_t *info) Sys_Printf("%s: WGL_COLORSPACE_SRGB\n", iAttributeTable[j].name); else if (iAttributeTable[j].id == 0x309D && fAttributeValues[j] == 0x308A) Sys_Printf("%s: WGL_COLORSPACE_LINEAR\n", iAttributeTable[j].name); - else if (iAttributeTable[j].id == 0x202E) + else if (iAttributeTable[j].id == WGL_PIXEL_TYPE_ARB && fAttributeValues[j] == WGL_TYPE_RGBA_FLOAT_ARB) + Sys_Printf("%s: WGL_TYPE_RGBA_FLOAT_ARB\n", iAttributeTable[j].name); + else if (iAttributeTable[j].id == WGL_PIXEL_TYPE_ARB && fAttributeValues[j] == 0x20A8) + Sys_Printf("%s: WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT\n", iAttributeTable[j].name); + else if (iAttributeTable[j].id == 0x202E || iAttributeTable[j].id == WGL_PIXEL_TYPE_ARB) Sys_Printf("%s: %#x\n", iAttributeTable[j].name, (int)fAttributeValues[j]); else Sys_Printf("%s: %g\n", iAttributeTable[j].name, fAttributeValues[j]); @@ -2482,7 +2553,7 @@ static BOOL bSetupPixelFormat(HDC hDC, rendererstate_t *info) 0, // no accumulation buffer 0, 0, 0, 0, // accum bits ignored #ifndef RTLIGHTS - 32, // 32-bit z-buffer + 24, // 24-bit z-buffer 0, // 0 stencil, don't need it unless we're using rtlights #else 24, // 24-bit z-buffer @@ -2501,50 +2572,27 @@ static BOOL bSetupPixelFormat(HDC hDC, rendererstate_t *info) if (info->bpp == 15 || info->bpp == 16) pfd.cColorBits = 16; - if (shouldforcepixelformat && qwglChoosePixelFormatARB) //the extra && is paranoia + if (shouldforcepixelformat && qwglChoosePixelFormatARB && + qDescribePixelFormat(hDC, forcepixelformat, sizeof(pfd), &pfd) && + qSetPixelFormat(hDC, forcepixelformat, &pfd)) //the extra && is paranoia { shouldforcepixelformat = false; currentpixelformat = forcepixelformat; } + else if ((currentpixelformat = qChoosePixelFormat(hDC, &pfd)) && qDescribePixelFormat(hDC, currentpixelformat, sizeof(pfd), &pfd) && qSetPixelFormat(hDC, currentpixelformat, &pfd)) + ; //we got our desired pixel format, or close enough else { - if ((currentpixelformat = qChoosePixelFormat(hDC, &pfd))) - { - TRACE(("dbg: ChoosePixelFormat 1: worked\n")); - - if (qSetPixelFormat(hDC, currentpixelformat, &pfd)) - { - TRACE(("dbg: bSetupPixelFormat: we can use the stencil buffer. woot\n")); - qDescribePixelFormat(hDC, currentpixelformat, sizeof(pfd), &pfd); - FixPaletteInDescriptor(hDC, &pfd); - - if ((pfd.dwFlags & PFD_GENERIC_FORMAT) && !(pfd.dwFlags & PFD_GENERIC_ACCELERATED)) - { - Con_Printf(CON_WARNING "WARNING: software-rendered opengl context\nPlease install appropriate graphics drivers, or try d3d rendering instead\n"); - } - else if (pfd.dwFlags & PFD_SWAP_COPY) - Con_Printf(CON_WARNING "WARNING: buffer swaps will use copy operations\n"); - return TRUE; - } - } - TRACE(("dbg: ChoosePixelFormat 1: no stencil buffer for us\n")); - pfd.cStencilBits = 0; - - if ( (currentpixelformat = qChoosePixelFormat(hDC, &pfd)) == 0 ) + if ((currentpixelformat = qChoosePixelFormat(hDC, &pfd)) && qDescribePixelFormat(hDC, currentpixelformat, sizeof(pfd), &pfd) && qSetPixelFormat(hDC, currentpixelformat, &pfd)) + ; + else { - Con_Printf("bSetupPixelFormat: ChoosePixelFormat failed (%i)\n", (int)GetLastError()); + Con_Printf("Unable to find suitable pixel format: %i\n", (int)GetLastError()); return FALSE; } } - - qDescribePixelFormat(hDC, currentpixelformat, sizeof(pfd), &pfd); - - if (qSetPixelFormat(hDC, currentpixelformat, &pfd) == FALSE) - { - Con_Printf("bSetupPixelFormat: SetPixelFormat failed (%i)\n", (int)GetLastError()); - return FALSE; - } + shouldforcepixelformat = false; if ((pfd.dwFlags & PFD_GENERIC_FORMAT) && !(pfd.dwFlags & PFD_GENERIC_ACCELERATED)) { @@ -2599,6 +2647,8 @@ static qboolean GLAppActivate(BOOL fActive, BOOL minimize) { static BOOL sound_active; +// Con_Printf("GLAppActivate: %i %i\n", fActive, minimize); + if (vid.activeapp == fActive && Minimized == minimize) return false; //so windows doesn't crash us over and over again. @@ -2746,18 +2796,16 @@ void MainThreadWndProc(void *ctx, void *data, size_t msg, size_t ex) break; case WM_SIZE: case WM_MOVE: - Cvar_ForceCallback(&vid_conautoscale); //FIXME: thread + Cvar_ForceCallback(&vid_conautoscale); break; case WM_KILLFOCUS: - GLAppActivate(FALSE, Minimized);//FIXME: thread - if (modestate == MS_FULLDIB) - ShowWindow(mainwindow, SW_SHOWMINNOACTIVE); - ClearAllStates (); //FIXME: thread + GLAppActivate(FALSE, Minimized); + ClearAllStates (); break; case WM_SETFOCUS: - if (!GLAppActivate(TRUE, Minimized))//FIXME: thread + if (!GLAppActivate(TRUE, Minimized)) break; - ClearAllStates (); //FIXME: thread + ClearAllStates (); break; #ifdef HAVE_CDPLAYER @@ -2807,10 +2855,10 @@ static LONG WINAPI GLMainWndProc ( COM_AddWork(WG_MAIN, MainThreadWndProc, NULL, NULL, uMsg, 0); #else GLAppActivate(FALSE, Minimized);//FIXME: thread - if (modestate == MS_FULLDIB) - ShowWindow(mainwindow, SW_SHOWMINNOACTIVE); ClearAllStates (); //FIXME: thread #endif + if (modestate == MS_FULLDIB) + ShowWindow(mainwindow, SW_SHOWMINNOACTIVE); break; case WM_SETFOCUS: #ifdef WTHREAD diff --git a/engine/gl/gl_vidsdl.c b/engine/gl/gl_vidsdl.c index ba17678f..4497fa41 100644 --- a/engine/gl/gl_vidsdl.c +++ b/engine/gl/gl_vidsdl.c @@ -153,7 +153,10 @@ static qboolean SDLVID_Init (rendererstate_t *info, unsigned char *palette, r_qr if (info->stereo) SDL_GL_SetAttribute(SDL_GL_STEREO, 1); -#if 0//SDL_MAJOR_VERSION >= 2 + if (info->srgb) + SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 1); + +#if SDL_MAJOR_VERSION >= 2 //FIXME: this stuff isn't part of info. //this means it shouldn't be exposed to the menu or widely advertised. if (*vid_gl_context_version.string) @@ -245,12 +248,26 @@ static qboolean SDLVID_Init (rendererstate_t *info, unsigned char *palette, r_qr #ifdef OPENGL_SDL if (qrenderer == QR_OPENGL) { + int srgb; sdlcontext = SDL_GL_CreateContext(sdlwindow); if (!sdlcontext) { - Con_Printf("Couldn't initialize GL context: %s\n", SDL_GetError()); - return false; + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0); + sdlcontext = SDL_GL_CreateContext(sdlwindow); + if (!sdlcontext) + { + Con_Printf("Couldn't initialize GL context: %s\n", SDL_GetError()); + return false; + } } + + srgb = 0; + SDL_GL_GetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, &srgb); + if (srgb) + vid.flags |= VID_SRGB_CAPABLE; } #endif diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index 4d48c843..364319af 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -156,6 +156,7 @@ typedef void (APIENTRY *PRIORTEXFUNCPTR)(GLsizei, const GLuint *, const GLclampf *); typedef void (APIENTRY *TEXSUBIMAGEPTR)(int, int, int, int, int, int, int, int, void *); typedef void (APIENTRY *FTEPFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data); +typedef void (APIENTRY *FTEPFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); typedef void (APIENTRY *FTEPFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, const GLvoid* img); typedef void (APIENTRY *FTEPFNGLPNTRIANGLESIATIPROC)(GLenum pname, GLint param); typedef void (APIENTRY *FTEPFNGLPNTRIANGLESFATIPROC)(GLenum pname, GLfloat param); @@ -198,6 +199,7 @@ extern TEXSUBIMAGEPTR TexSubImage2DFunc; extern void (APIENTRY *qglStencilOpSeparateATI) (GLenum face, GLenum fail, GLenum zfail, GLenum zpass); #endif extern FTEPFNGLCOMPRESSEDTEXIMAGE2DARBPROC qglCompressedTexImage2DARB; +extern FTEPFNGLCOMPRESSEDTEXIMAGE3DARBPROC qglCompressedTexImage3DARB; extern FTEPFNGLGETCOMPRESSEDTEXIMAGEARBPROC qglGetCompressedTexImageARB; extern FTEPFNGLPNTRIANGLESIATIPROC qglPNTrianglesiATI; extern FTEPFNGLPNTRIANGLESFATIPROC qglPNTrianglesfATI; @@ -205,6 +207,19 @@ extern void (APIENTRY *qglPatchParameteriARB)(GLenum pname, GLint value); //core qboolean GL_CheckExtension(char *extname); +struct glfmt_s +{ + int sizedformat; //texstorage + int cformat; //sized format used when gl_compress is set + int internalformat; //used instead of internal format when gl_compress is set, or 0 + int format; //0 for compressed data + int type; //0 for compressed data + int swizzle_r; + int swizzle_g; + int swizzle_b; + int swizzle_a; +}; + typedef struct { float glversion; int maxglslversion; @@ -236,6 +251,8 @@ typedef struct { qboolean ext_packed_depth_stencil; qboolean arb_depth_clamp; int ext_texture_filter_anisotropic; + + struct glfmt_s formatinfo[PTI_MAX]; } gl_config_t; extern gl_config_t gl_config; @@ -245,6 +262,7 @@ extern float gldepthmin, gldepthmax; void GL_UpdateFiltering(image_t *imagelist, int filtermip[3], int filterpic[3], int mipcap[2], float anis); qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips); void GL_DestroyTexture(texid_t tex); +void GL_SetupFormats(void); /* typedef struct @@ -996,6 +1014,7 @@ extern void (APIENTRY *qglTexGeniv) (GLenum coord, GLenum pname, const GLint *pa extern void (APIENTRY *qglTexImage1D) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); extern void (APIENTRY *qglTexImage3D) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); extern void (APIENTRY *qglTexSubImage1D) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +extern void (APIENTRY *qglTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); extern void (APIENTRY *qglTranslated) (GLdouble x, GLdouble y, GLdouble z); extern void (APIENTRY *qglTranslatef) (GLfloat x, GLfloat y, GLfloat z); @@ -1060,6 +1079,11 @@ extern void (APIENTRY *qglVertexPointer) (GLint size, GLenum type, GLsizei strid extern void (APIENTRY *qglGenVertexArrays)(GLsizei n, GLuint *arrays); extern void (APIENTRY *qglBindVertexArray)(GLuint vaoarray); +extern void (APIENTRY *qglTexStorage2D)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); //gl4.2 +extern void (APIENTRY *qglTexStorage3D)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); //gl4.2 +extern void (APIENTRY *qglCompressedTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); //gl1.3 +extern void (APIENTRY *qglCompressedTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); //gl1.3 + //glslang helper api diff --git a/engine/gl/glsupp.h b/engine/gl/glsupp.h index 1a4fdb63..23559df6 100644 --- a/engine/gl/glsupp.h +++ b/engine/gl/glsupp.h @@ -44,30 +44,40 @@ extern qlpMTex2FUNC qglMultiTexCoord2fARB; ./gl/gl_draw.c:3251: error: for each function it appears in.) */ #ifndef GL_EXT_bgra -#define GL_BGR_EXT 0x80E0 /*core in opengl 1.2*/ -#define GL_BGRA_EXT 0x80E1 +#define GL_BGR_EXT 0x80E0 /*core in opengl 1.2*/ +#define GL_BGRA_EXT 0x80E1 #endif #ifndef GL_UNSIGNED_INT_8_8_8_8_REV -#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 /*opengl 1.2*/ +#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 /*opengl 1.2*/ +#endif +#ifndef GL_UNSIGNED_INT_2_10_10_10_REV +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 /*opengl 1.2*/ +#endif +#ifndef GL_UNSIGNED_INT_5_9_9_9_REV +#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E /*opengl 3.0*/ #endif - #ifndef GL_UNSIGNED_SHORT_4_4_4_4_REV -#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 #endif #ifndef GL_UNSIGNED_SHORT_1_5_5_5_REV -#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 #endif #ifndef GL_UNSIGNED_SHORT_4_4_4_4 -#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 #endif #ifndef GL_UNSIGNED_SHORT_5_5_5_1 -#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 #endif #ifndef GL_UNSIGNED_SHORT_5_6_5 -#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#endif +#ifndef GL_HALF_FLOAT +#define GL_HALF_FLOAT 0x140B /*GL_ARB_half_float_pixel*/ +#endif +#ifndef GL_HALF_FLOAT_OES +#define GL_HALF_FLOAT_OES 0x8D61 /*GL_OES_texture_half_float*/ #endif - #ifndef GL_ARB_multitexture #define GL_ARB_multitexture 1 @@ -124,6 +134,11 @@ extern qlpMTex2FUNC qglMultiTexCoord2fARB; #define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB 0x851C #endif +#ifndef GL_TEXTURE_2D_ARRAY //gl 3.0 or GL_EXT_texture_array +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#endif + + #ifndef GL_ARB_depth_texture #define GL_ARB_depth_texture #define GL_DEPTH_COMPONENT16_ARB 0x81A5 @@ -132,6 +147,9 @@ extern qlpMTex2FUNC qglMultiTexCoord2fARB; #define GL_TEXTURE_DEPTH_SIZE_ARB 0x884A #define GL_DEPTH_TEXTURE_MODE_ARB 0x884B #endif +#ifndef GL_DEPTH_COMPONENT32F +#define GL_DEPTH_COMPONENT32F 0x8CAC +#endif //GL_OES_depth_texture adds this because gles otherwise lacks it. #ifndef GL_UNSIGNED_INT @@ -655,6 +673,24 @@ typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F #endif /* GL_EXT_texture_sRGB */ +#ifndef GL_RG +#define GL_RG 0x8227 +#define GL_RGB9_E5 0x8C3D /*opengl 3.0*/ +#define GL_R8 0x8229 /*opengl 3.0*/ +#define GL_RG8 0x822B /*opengl 3.0*/ +#endif +#ifndef GL_RG8_SNORM +#define GL_R8_SNORM 0x8F94 /*opengl 3.1*/ +#define GL_RG8_SNORM 0x8F95 /*opengl 3.1*/ +#endif + +#ifndef GL_TEXTURE_SWIZZLE_R +#define GL_TEXTURE_SWIZZLE_R 0x8E42 +#define GL_TEXTURE_SWIZZLE_G 0x8E43 +#define GL_TEXTURE_SWIZZLE_B 0x8E44 +#define GL_TEXTURE_SWIZZLE_A 0x8E45 +#endif + #ifndef GL_ETC1_RGB8_OES #define GL_ETC1_RGB8_OES 0x8D64 //4*4 blocks of 8 bytes #endif diff --git a/engine/gl/r_bishaders.h b/engine/gl/r_bishaders.h index 0879cafe..acac005d 100644 --- a/engine/gl/r_bishaders.h +++ b/engine/gl/r_bishaders.h @@ -7423,7 +7423,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "attribute vec4 v_colour;\n" "void main ()\n" "{\n" -"tc = v_texcoord;\n" +"tc = vec2(v_texcoord.s, 1.0-v_texcoord.t);\n" "vc = v_colour;\n" "gl_Position = ftetransform();\n" "}\n" @@ -7656,8 +7656,8 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #endif #ifdef GLQUAKE {QR_OPENGL, 110, "drawflat_wall", -"!!cvarv r_floorcolor\n" -"!!cvarv r_wallcolor\n" +"!!cvard_srgb_b r_floorcolor\n" +"!!cvard_srgb_b r_wallcolor\n" "!!permu FOG\n" //this is for the '286' preset walls, and just draws lightmaps coloured based upon surface normals. @@ -7668,12 +7668,10 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "attribute vec3 v_normal;\n" "attribute vec2 v_lmcoord;\n" "varying vec2 lm;\n" -"uniform vec3 cvar_r_wallcolor;\n" -"uniform vec3 cvar_r_floorcolor;\n" "uniform vec4 e_lmscale;\n" "void main ()\n" "{\n" -"col = vec4(e_lmscale.rgb/255.0 * ((v_normal.z < 0.73)?cvar_r_wallcolor:cvar_r_floorcolor), e_lmscale.a);\n" +"col = vec4(e_lmscale.rgb * ((v_normal.z < 0.73)?r_wallcolor:r_floorcolor), e_lmscale.a);\n" "lm = v_lmcoord;\n" "gl_Position = ftetransform();\n" "}\n" @@ -10202,7 +10200,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #ifdef GLQUAKE {QR_OPENGL, 110, "menutint", "!!cvari r_menutint_inverse\n" -"!!cvarv r_menutint\n" +"!!cvard_srgb r_menutint\n" "#ifdef VERTEX_SHADER\n" "attribute vec2 v_texcoord;\n" @@ -10218,7 +10216,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#ifdef FRAGMENT_SHADER\n" "varying vec2 texcoord;\n" -"uniform vec3 cvar_r_menutint;\n" "uniform sampler2D s_t0;\n" "uniform int cvar_r_menutint_inverse;\n" "const vec3 lumfactors = vec3(0.299, 0.587, 0.114);\n" @@ -10228,7 +10225,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "vec3 texcolor = texture2D(s_t0, texcoord).rgb;\n" "float luminance = dot(lumfactors, texcolor);\n" "texcolor = vec3(luminance, luminance, luminance);\n" -"texcolor *= cvar_r_menutint;\n" +"texcolor *= r_menutint;\n" "texcolor = (cvar_r_menutint_inverse > 0) ? (invertvec - texcolor) : texcolor;\n" "gl_FragColor = vec4(texcolor, 1.0);\n" "}\n" diff --git a/engine/gl/shader.h b/engine/gl/shader.h index e847d843..b3336a66 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -370,6 +370,8 @@ enum{ }; #define PERMUTATIONS (1u< void QCC_Canonicalize(char *fullname, size_t fullnamesize, const char *newfile, const char *base); +//package formats: +//pakzip - files are uncompressed, with both a pak header and a zip trailer, allowing it to be read as either type of file. +//zip - standard zips +//spanned zip - the full list of files is written into a separate central-directory-only zip, the actual file data comes from regular zips named foo.z##/.p## instead of foo.zip/foo.pk3 + /* dataset common { @@ -46,6 +51,9 @@ texa0 } */ +#define quint64_t long long +#define qofs_t size_t + #define countof(x) (sizeof(x)/sizeof((x)[0])) struct pkgctx_s @@ -55,8 +63,10 @@ struct pkgctx_s char *listfile; + pbool test; pbool readoldpacks; char gamepath[MAX_PATH]; + char sourcepath[MAX_PATH]; time_t buildtime; //skips the file if its listed in one of these packages, unless the modification time on disk is newer. @@ -68,9 +78,14 @@ struct pkgctx_s struct { char name[128]; - size_t size; -// unsigned int zcrc; -// timestamp; + + unsigned short zmethod; + unsigned int zcrc; + qofs_t zhdrofs; + qofs_t rawsize; + qofs_t zipsize; + unsigned short dostime; + unsigned short dosdate; } *file; } *oldpacks; @@ -85,6 +100,10 @@ struct pkgctx_s char code[128]; char filename[128]; struct file_s *files; + + pbool usediffs; + unsigned int numparts; + struct oldpack_s *oldparts; } *outputs; char name[1]; @@ -126,16 +145,31 @@ struct pkgctx_s char name[128]; struct file_s *nextwrite; struct rule_s *rule; + unsigned int zdisk; + unsigned short zmethod; unsigned int zcrc; - unsigned int zhdrofs; - unsigned int pakofs; - unsigned int rawsize; - unsigned int zipsize; + qofs_t zhdrofs; + qofs_t pakofs; + qofs_t rawsize; + qofs_t zipsize; + unsigned short dostime; + unsigned short dosdate; + time_t timestamp; } write; } *files; } *classes; }; +#ifdef _WIN32 +static time_t filetime_to_timet(FILETIME ft) +{ + ULARGE_INTEGER ull; + ull.LowPart = ft.dwLowDateTime; + ull.HighPart = ft.dwHighDateTime; + return ull.QuadPart / 10000000ULL - 11644473600ULL; +} +#endif + static struct rule_s *PKG_FindRule(struct pkgctx_s *ctx, char *code) { struct rule_s *o; @@ -304,7 +338,7 @@ static void PKG_ReplaceString(char *str, char *find, char *newpart) str = oldpart+nlen; } } -static void PKG_CreateOutput(struct pkgctx_s *ctx, struct dataset_s *s, const char *code, const char *filename) +static void PKG_CreateOutput(struct pkgctx_s *ctx, struct dataset_s *s, const char *code, const char *filename, pbool diff) { char path[MAX_PATH]; char date[64]; @@ -331,12 +365,13 @@ static void PKG_CreateOutput(struct pkgctx_s *ctx, struct dataset_s *s, const ch o = malloc(sizeof(*o)); memset(o, 0, sizeof(*o)); strcpy(o->code, code); + o->usediffs = diff; QCC_Canonicalize(o->filename, sizeof(o->filename), path, ctx->gamepath); o->next = s->outputs; s->outputs = o; } -static void PKG_ParseOutput(struct pkgctx_s *ctx) +static void PKG_ParseOutput(struct pkgctx_s *ctx, pbool diff) { struct dataset_s *s; char name[128]; @@ -352,7 +387,7 @@ static void PKG_ParseOutput(struct pkgctx_s *ctx) if (PKG_GetStringToken(ctx, prop, sizeof(prop))) { s = PKG_GetDataset(ctx, "core"); - PKG_CreateOutput(ctx, s, name, prop); + PKG_CreateOutput(ctx, s, name, prop, diff); } else { @@ -370,7 +405,7 @@ static void PKG_ParseOutput(struct pkgctx_s *ctx) *e = 0; s = PKG_GetDataset(ctx, prop); if (PKG_GetStringToken(ctx, fname, sizeof(fname))) - PKG_CreateOutput(ctx, s, name, fname); + PKG_CreateOutput(ctx, s, name, fname, diff); else ctx->messagecallback(ctx->userctx, "Output '%s[%s]' filename omitted\n", name, prop); } @@ -555,9 +590,10 @@ static void PKG_ParseRule(struct pkgctx_s *ctx) r->next = ctx->rules; ctx->rules = r; } -static void PKG_AddClassFile(struct pkgctx_s *ctx, struct class_s *c, const char *fname) +static void PKG_AddClassFile(struct pkgctx_s *ctx, struct class_s *c, const char *fname, time_t mtime) { struct file_s *f; + struct tm *t; if (strlen(fname) >= sizeof(f->name)) { @@ -568,6 +604,10 @@ static void PKG_AddClassFile(struct pkgctx_s *ctx, struct class_s *c, const char f = malloc(sizeof(*f)); memset(f, 0, sizeof(*f)); strcpy(f->name, fname); + f->write.timestamp = mtime; + t = localtime(&f->write.timestamp); + f->write.dostime = (t->tm_sec>>1)|(t->tm_min<<5)|(t->tm_hour<<11); + f->write.dosdate = (t->tm_mday<<0)|(t->tm_mon<<5)|((t->tm_year+1900-1980)<<9); f->next = c->files; c->files = f; } @@ -577,7 +617,7 @@ static void PKG_AddClassFiles(struct pkgctx_s *ctx, struct class_s *c, const cha WIN32_FIND_DATA fd; HANDLE h; char basepath[MAX_PATH]; - QCC_Canonicalize(basepath, sizeof(basepath), fname, ctx->gamepath); + QCC_Canonicalize(basepath, sizeof(basepath), fname, ctx->sourcepath); h = FindFirstFile(basepath, &fd); if (h == INVALID_HANDLE_VALUE) ctx->messagecallback(ctx->userctx, "wildcard string '%s' found no files\n", fname); @@ -586,7 +626,7 @@ static void PKG_AddClassFiles(struct pkgctx_s *ctx, struct class_s *c, const cha do { QCC_Canonicalize(basepath, sizeof(basepath), fd.cFileName, fname); - PKG_AddClassFile(ctx, c, basepath); + PKG_AddClassFile(ctx, c, basepath, filetime_to_timet(fd.ftLastWriteTime)); } while(FindNextFile(h, &fd)); } #else @@ -693,10 +733,10 @@ static void PKG_ParseClass(struct pkgctx_s *ctx, char *output) } else if (strchr(prop, '.')) { - if (strchr(prop, '*') || strchr(prop, '?')) +// if (strchr(prop, '*') || strchr(prop, '?')) PKG_AddClassFiles(ctx, c, prop); - else - PKG_AddClassFile(ctx, c, prop); +// else +// PKG_AddClassFile(ctx, c, prop); } else ctx->messagecallback(ctx->userctx, "Class '%s' has unknown property '%s'\n", name, prop); @@ -724,10 +764,10 @@ static void PKG_ParseClassFiles(struct pkgctx_s *ctx, struct class_s *c) if (!strcmp(prop, ";")) continue; - if (strchr(prop, '*') || strchr(prop, '?')) +// if (strchr(prop, '*') || strchr(prop, '?')) PKG_AddClassFiles(ctx, c, prop); - else - PKG_AddClassFile(ctx, c, prop); +// else +// PKG_AddClassFile(ctx, c, prop); } } } @@ -774,9 +814,9 @@ static unsigned int PKG_DeflateToFile(FILE *f, unsigned int rawsize, void *in, i strm.next_out = out; strm.avail_out = sizeof(out); } + deflateEnd(&strm); fwrite(out, 1, sizeof(out) - strm.avail_out, f); i+=sizeof(out) - strm.avail_out; - deflateEnd(&strm); return i; } #endif @@ -836,7 +876,8 @@ static void *PKG_OpenSourceFile(struct pkgctx_s *ctx, struct file_s *file, size_ *fsize = 0; - QCC_Canonicalize(fullname, sizeof(fullname), file->name, ctx->gamepath); + QCC_Canonicalize(fullname, sizeof(fullname), file->name, ctx->sourcepath); + strcpy(file->write.name, file->name); f = fopen(fullname, "rb"); if (!f) @@ -847,7 +888,6 @@ static void *PKG_OpenSourceFile(struct pkgctx_s *ctx, struct file_s *file, size_ else ctx->messagecallback(ctx->userctx, "\t\tCompressing %s\n", file->name); - strcpy(file->write.name, file->name); if (rule) { data = strrchr(file->write.name, '.'); @@ -873,7 +913,7 @@ static void *PKG_OpenSourceFile(struct pkgctx_s *ctx, struct file_s *file, size_ //delete temp file... fclose(f); - QCC_Canonicalize(tempname, sizeof(tempname), file->write.name, ctx->gamepath); + QCC_Canonicalize(tempname, sizeof(tempname), file->write.name, ctx->sourcepath); f = fopen(tempname, "rb"); if (f) { @@ -958,20 +998,22 @@ static void *PKG_OpenSourceFile(struct pkgctx_s *ctx, struct file_s *file, size_ return data; } -static void PKG_WritePackageData(struct pkgctx_s *ctx, struct output_s *out) +static void PKG_WritePackageData(struct pkgctx_s *ctx, struct output_s *out, unsigned int index, pbool directoryonly) { //helpers to deal with misaligned data. writes little-endian. -#define misbyte(ptr,ofs,data) ((unsigned char*)(ptr))[ofs] = (data)&0xff; -#define misshort(ptr,ofs,data) misbyte((ptr),(ofs),(data));misbyte((ptr),(ofs)+1,(data)>>8); -#define misint(ptr,ofs,data) misshort((ptr),(ofs),(data));misshort((ptr),(ofs)+2,(data)>>16); - int num=0; - int ofs; +#define misbyte(ptr,ofs,data) ((unsigned char*)(ptr))[ofs] = (data)&0xff +#define misshort(ptr,ofs,data) do{misbyte((ptr),(ofs),(data));misbyte((ptr),(ofs)+1,(data)>>8);}while(0) +#define misint(ptr,ofs,data) do{misshort((ptr),(ofs),(data));misshort((ptr),(ofs)+2,(data)>>16);}while(0) +#define misint64(ptr,ofs,data) do{misint((ptr),(ofs),(data));misint((ptr),(ofs)+4,((quint64_t)(data))>>32);}while(0) + qofs_t num=0; pbool pak = false; int startofs = 0; struct file_s *f; char centralheader[46+sizeof(f->write.name)]; - int centraldirsize; + qofs_t centraldirsize; + qofs_t centraldirofs; + qofs_t z64eocdofs; char *filedata; @@ -984,18 +1026,35 @@ static void PKG_WritePackageData(struct pkgctx_s *ctx, struct output_s *out) } pakheader = {"PACK", 0, 0}; char *ext; +#define GPF_TRAILINGSIZE (1u<<3) +#define GPF_UTF8 (1u<<11) #ifdef AVAIL_ZLIB #define compmethod (pak?0:8)/*Z_DEFLATED*/ #else #define compmethod 0/*Z_RAW*/ #endif - if (!compmethod) + if (!compmethod && !directoryonly) pak = true; //might as well boost compat... ext = strrchr(out->filename, '.'); - if (ext && !QC_strcasecmp(ext, ".pak")) + if (ext && !QC_strcasecmp(ext, ".pak") && !index) pak = true; - outf = fopen(out->filename, "wb"); + if (out->usediffs && !directoryonly) + { + char newname[MAX_PATH]; + memcpy(newname, out->filename, sizeof(newname)); + if (ext) + { + ext = newname+(ext-out->filename); + ext+=1; + if (*ext) + ext++; + QC_snprintfz(ext, sizeof(newname)-(ext-newname), "%02u", index+1); + } + outf = fopen(newname, "wb"); + } + else + outf = fopen(out->filename, "wb"); if (!outf) { ctx->messagecallback(ctx->userctx, "Unable to open %s\n", out->filename); @@ -1005,58 +1064,94 @@ static void PKG_WritePackageData(struct pkgctx_s *ctx, struct output_s *out) if (pak) //reserve space for the pak header fwrite(&pakheader, 1, sizeof(pakheader), outf); - for (f = out->files; f ; f=f->write.nextwrite) + if (!directoryonly) { - char header[32+sizeof(f->write.name)]; - size_t fnamelen = strlen(f->write.name); - - filedata = PKG_OpenSourceFile(ctx, f, &f->write.rawsize); - if (!filedata) + for (f = out->files; f ; f=f->write.nextwrite) { - ctx->messagecallback(ctx->userctx, "Unable to open %s\n", f->name); - } + char header[32+sizeof(f->write.name)]; + size_t fnamelen = strlen(f->write.name); + size_t hofs; + unsigned short gpflags = GPF_UTF8; - f->write.zcrc = QC_encodecrc(f->write.rawsize, filedata); - misint (header, 0, 0x04034b50); - misshort(header, 4, 0);//minver - misshort(header, 6, 0);//general purpose flags - misshort(header, 8, 0);//compression method, 0=store, 8=deflate - misshort(header, 10, 0);//lastmodfiletime - misshort(header, 12, 0);//lastmodfiledate - misint (header, 14, f->write.zcrc);//crc32 - misint (header, 18, f->write.rawsize);//compressed size - misint (header, 22, f->write.rawsize);//uncompressed size - misshort(header, 26, fnamelen);//filename length - misshort(header, 28, 0);//extradata length - strcpy(header+30, f->write.name); + if (index != f->write.zdisk) + continue; //not in this disk... - f->write.zhdrofs = ftell(outf); - fwrite(header, 1, 30+fnamelen, outf); + filedata = PKG_OpenSourceFile(ctx, f, &f->write.rawsize); + if (!filedata) + { + ctx->messagecallback(ctx->userctx, "Unable to open %s\n", f->name); + } + + f->write.zcrc = QC_encodecrc(f->write.rawsize, filedata); + misint (header, 0, 0x04034b50); + misshort(header, 4, 45);//minver + misshort(header, 6, gpflags);//general purpose flags + misshort(header, 8, 0);//compression method, 0=store, 8=deflate + misshort(header, 10, f->write.dostime);//lastmodfiletime + misshort(header, 12, f->write.dosdate);//lastmodfiledate + misint (header, 14, f->write.zcrc);//crc32 + misint (header, 18, f->write.rawsize);//compressed size + misint (header, 22, f->write.rawsize);//uncompressed size + misshort(header, 26, fnamelen);//filename length + misshort(header, 28, 0);//extradata length + strcpy(header+30, f->write.name); + hofs = 30+fnamelen; + + misshort(header, 28, hofs-(30+fnamelen));//extradata length + f->write.zhdrofs = ftell(outf); + fwrite(header, 1, hofs, outf); #ifdef AVAIL_ZLIB - if (compmethod == 2 || compmethod == 8) - { - size_t end; - f->write.pakofs = 0; + if (f->write.rawsize && (compmethod == 2 || compmethod == 8)) + { + gpflags |= 1u<<1; + f->write.pakofs = 0; - f->write.zipsize = PKG_DeflateToFile(outf, f->write.rawsize, filedata, compmethod); - - misshort(header, 8, compmethod);//compression method, 0=store, 8=deflate - misint (header, 18, f->write.zipsize); - - end = ftell(outf); - fseek(outf, f->write.zhdrofs, SEEK_SET); - fwrite(header, 1, 30+fnamelen, outf); - fseek(outf, end, SEEK_SET); - } - else + f->write.zmethod = compmethod; + f->write.zipsize = PKG_DeflateToFile(outf, f->write.rawsize, filedata, compmethod); + } + else #endif - { - f->write.pakofs = ftell(outf); - f->write.zipsize = fwrite(filedata, 1, f->write.rawsize, outf); + { + f->write.zmethod = 0; + f->write.pakofs = ftell(outf); + f->write.zipsize = fwrite(filedata, 1, f->write.rawsize, outf); + } + + //update the header + misshort(header, 8, f->write.zmethod);//compression method, 0=store, 8=deflate + if (f->write.zipsize > 0xffffffff) + { + misint (header, 18, 0xffffffff);//compressed size + gpflags |= GPF_TRAILINGSIZE; + } + else + misint (header, 18, f->write.zipsize);//compressed size + if (f->write.rawsize > 0xffffffff) + { + misint (header, 22, 0xffffffff);//compressed size + gpflags |= GPF_TRAILINGSIZE; + } + else + misint (header, 22, f->write.rawsize);//compressed size + misshort(header, 6, gpflags);//general purpose flags + + fseek(outf, f->write.zhdrofs, SEEK_SET); + fwrite(header, 1, hofs, outf); + fseek(outf, 0, SEEK_END); + + if (gpflags & GPF_TRAILINGSIZE) //if (gpflags & GPF_TRAILINGSIZE) + { + misint (header, 0, 0x08074b50); + misint (header, 4, f->write.zcrc); + misint64(header, 8, f->write.zipsize); + misint64(header, 16, f->write.rawsize); + fwrite(header, 1, 24, outf); + } + + free(filedata); + num++; } - free(filedata); - num++; } if (pak) @@ -1067,15 +1162,14 @@ static void PKG_WritePackageData(struct pkgctx_s *ctx, struct output_s *out) unsigned int size; unsigned int offset; } pakentry; - //prepare the header - pakheader.tabbytes = num * sizeof(pakentry); pakheader.tabofs = ftell(outf); - fseek(outf, 0, SEEK_SET); - fwrite(&pakheader, 1, sizeof(pakheader), outf); - //now go and write the file table. - fseek(outf, pakheader.tabofs, SEEK_SET); + + //write the pak file table. for (f = out->files,num=0; f ; f=f->write.nextwrite) { + if (index != f->write.zdisk) + continue; //not in this disk... + memset(&pakentry, 0, sizeof(pakentry)); QC_strlcpy(pakentry.name, f->write.name, sizeof(pakentry.name)); pakentry.size = (f->write.pakofs==0)?0:f->write.rawsize; @@ -1083,43 +1177,106 @@ static void PKG_WritePackageData(struct pkgctx_s *ctx, struct output_s *out) fwrite(&pakentry, 1, sizeof(pakentry), outf); num++; } + + //replace the pak header, then return to the end of the file for the zip end-of-central-directory + pakheader.tabbytes = num * sizeof(pakentry); + fseek(outf, 0, SEEK_SET); + fwrite(&pakheader, 1, sizeof(pakheader), outf); + fseek(outf, 0, SEEK_END); } - ofs = ftell(outf); + centraldirofs = ftell(outf); for (f = out->files,num=0; f ; f=f->write.nextwrite) { + size_t hofs; size_t fnamelen; + if (!directoryonly && index != f->write.zdisk) + continue; + fnamelen = strlen(f->write.name); misint (centralheader, 0, 0x02014b50); - misshort(centralheader, 4, 0);//ourver - misshort(centralheader, 6, 0);//minver - misshort(centralheader, 8, 0);//general purpose flags - misshort(centralheader, 10, compmethod);//compression method, 0=store, 8=deflate - misshort(centralheader, 12, 0);//lastmodfiletime - misshort(centralheader, 14, 0);//lastmodfiledate + misshort(centralheader, 4, (3<<8)|63);//ourver + misshort(centralheader, 6, 45);//minver + misshort(centralheader, 8, GPF_UTF8);//general purpose flags + misshort(centralheader, 10, f->write.rawsize?compmethod:0);//compression method, 0=store, 8=deflate + misshort(centralheader, 12, f->write.dostime);//lastmodfiletime + misshort(centralheader, 14, f->write.dosdate);//lastmodfiledate misint (centralheader, 16, f->write.zcrc);//crc32 misint (centralheader, 20, f->write.zipsize);//compressed size misint (centralheader, 24, f->write.rawsize);//uncompressed size misshort(centralheader, 28, fnamelen);//filename length misshort(centralheader, 30, 0);//extradata length misshort(centralheader, 32, 0);//comment length - misshort(centralheader, 34, 0);//first disk number + misshort(centralheader, 34, f->write.zdisk);//first disk number misshort(centralheader, 36, 0);//internal file attribs misint (centralheader, 38, 0);//external file attribs misint (centralheader, 42, f->write.zhdrofs);//local header offset strcpy(centralheader+46, f->write.name); - fwrite(centralheader, 1, 46 + fnamelen, outf); + + hofs = 46+fnamelen; + if (f->write.zdisk >= 0xffff || f->write.zhdrofs >= 0xffffffff || f->write.rawsize >= 0xffffffff || f->write.zipsize >= 0xffffffff) + { + misshort(centralheader, hofs, 0x0001);//zip64 tagid + misshort(centralheader, hofs+2, 0x0001);//zip64 tag size + hofs+=4; + if (f->write.rawsize >= 0xffffffff) + { + misint64(centralheader, hofs, f->write.rawsize);//uncompressed size + hofs += 8; + } + if (f->write.zipsize >= 0xffffffff) + { + misint64(centralheader, hofs, f->write.zipsize);//compressed size + hofs += 8; + } + if (f->write.zhdrofs >= 0xffffffff) + { + misint64(centralheader, hofs, f->write.zhdrofs);//localheader offset + hofs += 8; + } + if (f->write.zdisk >= 0xffff) + { + misint (centralheader, hofs, f->write.zdisk);//compressed size + hofs += 4; + } + } + misshort(centralheader, 30, hofs-(46+fnamelen));//extradata length + + fwrite(centralheader, 1, hofs, outf); num++; } + centraldirsize = ftell(outf)-centraldirofs; - centraldirsize = ftell(outf)-ofs; + //zip64 end of central dir + z64eocdofs = ftell(outf); + misint (centralheader, 0, 0x06064b50); + misint64(centralheader, 4, (qofs_t)(56-16)); + misshort(centralheader, 12, (3<<8)|63); //ver made by = unix|appnote ver + misshort(centralheader, 14, 45); //ver needed + misint (centralheader, 16, index); //thisdisk number + misint (centralheader, 20, index); //centraldir start disk + misint64(centralheader, 24, num); //centraldir entry count (disk) + misint64(centralheader, 32, num); //centraldir entry count (total) + misint64(centralheader, 40, centraldirsize);//centraldir entry bytes + misint64(centralheader, 48, centraldirofs); //centraldir start offset + fwrite(centralheader, 1, 56, outf); + + //zip64 end of central dir locator + misint (centralheader, 0, 0x07064b50); + misint (centralheader, 4, index); //centraldir first disk + misint64(centralheader, 8, z64eocdofs); + misint (centralheader, 16, index+1); //total disk count + fwrite(centralheader, 1, 20, outf); + +// centraldirofs = ftell(outf) - centraldirofs; + //write zip end-of-central-directory misint (centralheader, 0, 0x06054b50); - misshort(centralheader, 4, 0); //this disk number - misshort(centralheader, 6, 0); //centraldir first disk - misshort(centralheader, 8, num); //centraldir entries - misshort(centralheader, 10, num); //total centraldir entries - misint (centralheader, 12, centraldirsize); //centraldir size - misint (centralheader, 16, ofs); //centraldir offset + misshort(centralheader, 4, (index > 0xffff)? 0xffff:index); //this disk number + misshort(centralheader, 6, (index > 0xffff)? 0xffff:index); //centraldir first disk + misshort(centralheader, 8, (num > 0xffff)? 0xffff:num); //centraldir entries + misshort(centralheader, 10, (num > 0xffff)? 0xffff:num); //total centraldir entries + misint (centralheader, 12, (centraldirsize>0xffffffff)?0xffffffff:centraldirsize); //centraldir size + misint (centralheader, 16, (centraldirofs >0xffffffff)?0xffffffff:centraldirofs); //centraldir offset misshort(centralheader, 20, 0); //comment length fwrite(centralheader, 1, 22, outf); @@ -1161,13 +1318,19 @@ static void PKG_ReadPackContents(struct pkgctx_s *ctx, struct oldpack_s *old) if (f) { //find end-of-central-dir + //assume no comment fseek(f, -22, SEEK_END); fread(header, 1, 22, f); if (header[0] == 'P' && header[1] == 'K' && header[2] == 5 && header[3] == 6) { + //thisdisk = shortfromptr(header+4); + //centraldirstart = shortfromptr(header+6); old->numfiles = shortfromptr(header+8); + //numfiles_all = shortfromptr(header+10); + //centaldirsize = shortfromptr(header+12); foffset = longfromptr(header+16); + //commentength = shortfromptr(header+20); old->file = malloc(sizeof(*old->file)*old->numfiles); @@ -1175,13 +1338,30 @@ static void PKG_ReadPackContents(struct pkgctx_s *ctx, struct oldpack_s *old) fseek(f, foffset, SEEK_SET); for(u = 0; u < old->numfiles; u++) { + unsigned int extra_len, comment_len; fread(header, 1, 46, f); //zcrc @ 16 - old->file[u].size = longfromptr(header+24); + + //version_madeby = shortfromptr(header+4); + //version_needed = shortfromptr(header+6); + //gflags = shortfromptr(header+8); + old->file[u].zmethod = shortfromptr(header+10); + old->file[u].dostime = shortfromptr(header+12); + old->file[u].dosdate = shortfromptr(header+12); + old->file[u].zcrc = longfromptr(header+16); + old->file[u].zipsize = longfromptr(header+20); + old->file[u].rawsize = longfromptr(header+24); namelen = shortfromptr(header+28); + extra_len = shortfromptr(header+30); + comment_len = shortfromptr(header+32); + //disknum = shortfromptr(header+34); + //iattributes = shortfromptr(header+36); + //eattributes = longfromptr(header+38); + //localheaderoffset = longfromptr(header+42); + fread(old->file[u].name, 1, namelen, f); old->file[u].name[namelen] = 0; - i = shortfromptr(header+30)+shortfromptr(header+32); + i = extra_len+comment_len; if (i) fseek(f, i, SEEK_CUR); } @@ -1208,7 +1388,7 @@ static void PKG_ReadPackContents(struct pkgctx_s *ctx, struct oldpack_s *old) for (u = 0; u < old->numfiles; u++) { strcpy(old->file[u].name, files[u].name); - old->file[u].size = files[u].size; + old->file[u].rawsize = files[u].size; } free(files); } @@ -1221,17 +1401,26 @@ static void PKG_ReadPackContents(struct pkgctx_s *ctx, struct oldpack_s *old) } } -static pbool PKG_FileIsModified(struct pkgctx_s *ctx, const char *filename) +static pbool PKG_FileIsModified(struct pkgctx_s *ctx, struct oldpack_s *old, struct file_s *file) { - struct oldpack_s *old; size_t u; - for (old = ctx->oldpacks; old; old = old->next) + + for (u = 0; u < old->numfiles; u++) { - for (u = 0; u < old->numfiles; u++) + //should check filesize etc, but rules and extension changes make that messy + if (!strcmp(old->file[u].name, file->name)) { - if (!strcmp(old->file[u].name, filename)) + if(file->write.dosdate < old->file[u].dosdate || (file->write.dosdate == old->file[u].dosdate && file->write.dostime <= old->file[u].dostime)) { - ctx->messagecallback(ctx->userctx, "\t%s already contains %s\n", old->filename, filename); + file->write.zmethod = old->file[u].zmethod; + //char name[128]; + file->write.zcrc = old->file[u].zcrc; + file->write.zhdrofs = old->file[u].zhdrofs; + file->write.pakofs = 0; + file->write.rawsize = old->file[u].rawsize; + file->write.zipsize = old->file[u].zipsize; + file->write.dostime = old->file[u].dostime; + file->write.dosdate = old->file[u].dosdate; return false; } } @@ -1256,6 +1445,14 @@ static void PKG_WriteDataset(struct pkgctx_s *ctx, struct dataset_s *set) { //fixme: strip any wildcarded paks that match an output, to avoid weirdness. PKG_ReadPackContents(ctx, old); } + + for (out = set->outputs; out; out = out->next) + { + if(out->usediffs) + { //FIXME: look for old parts + + } + } } ctx->messagecallback(ctx->userctx, "Building dataset %s\n", set->name); @@ -1285,13 +1482,32 @@ static void PKG_WriteDataset(struct pkgctx_s *ctx, struct dataset_s *set) for (file = cls->files; file; file = file->next) { - if (!PKG_FileIsModified(ctx, file->name)) - continue; -// ctx->messagecallback(ctx->userctx, "\t\tFile %s, rule %s\n", file->name, rule?rule->name:""); + for (old = ctx->oldpacks; old; old = old->next) + { + if (!PKG_FileIsModified(ctx, old, file)) + break; + } + if (old) + { + ctx->messagecallback(ctx->userctx, "\t\tFile %s found inside %s\n", file->name, old->filename); + file->write.zdisk = ~0u; + } + else + { +// ctx->messagecallback(ctx->userctx, "\t\tFile %s, rule %s\n", file->name, rule?rule->name:""); - file->write.nextwrite = out->files; - file->write.rule = rule; - out->files = file; + file->write.zdisk = out->numparts; + + for (old = out->oldparts; old; old = old->next) + { + if (!PKG_FileIsModified(ctx, old, file)) + break; + } + + file->write.nextwrite = out->files; + file->write.rule = rule; + out->files = file; + } } } @@ -1302,9 +1518,25 @@ static void PKG_WriteDataset(struct pkgctx_s *ctx, struct dataset_s *set) ctx->messagecallback(ctx->userctx, "\tOutput %s[%s] \"%s\" has no files\n", out->code, set->name, out->filename); continue; } - - ctx->messagecallback(ctx->userctx, "\tGenerating %s[%s] \"%s\"\n", out->code, set->name, out->filename); - PKG_WritePackageData(ctx, out); + + if (ctx->test) + { + for (file = out->files; file; file = file->write.nextwrite) + { + if (file->write.rule) + ctx->messagecallback(ctx->userctx, "\t\tFile %s has changed (rule %s)\n", file->name, file->write.rule->name); + else + ctx->messagecallback(ctx->userctx, "\t\tFile %s has changed\n", file->name); + } + } + else + { + ctx->messagecallback(ctx->userctx, "\tGenerating %s[%s] \"%s\"\n", out->code, set->name, out->filename); + PKG_WritePackageData(ctx, out, out->numparts, false); + } + + if(out->usediffs) + PKG_WritePackageData(ctx, out, out->numparts+1, true); } } void Packager_WriteDataset(struct pkgctx_s *ctx, char *setname) @@ -1324,31 +1556,40 @@ void Packager_WriteDataset(struct pkgctx_s *ctx, char *setname) PKG_WriteDataset(ctx, dataset); } } -struct pkgctx_s *Packager_Create(void (*messagecallback)(void *userctx, char *message), void *userctx) +struct pkgctx_s *Packager_Create(void (*messagecallback)(void *userctx, char *message, ...), void *userctx) { struct pkgctx_s *ctx; ctx = malloc(sizeof(*ctx)); memset(ctx, 0, sizeof(*ctx)); ctx->messagecallback = messagecallback; ctx->userctx = userctx; + ctx->test = false; time(&ctx->buildtime); return ctx; } -void Packager_Parse(struct pkgctx_s *ctx, char *scriptname) +void Packager_ParseText(struct pkgctx_s *ctx, char *scripttext) { - size_t remaining = 0; - char *file = QCC_ReadFile(scriptname, NULL, NULL, &remaining); char cmd[128]; - strcpy(ctx->gamepath, scriptname); - - ctx->listfile = file; + ctx->listfile = scripttext; while (PKG_GetToken(ctx, cmd, sizeof(cmd), true)) { // if (!strcmp(cmd, "dataset")) // PKG_ParseDataset(ctx); if (!strcmp(cmd, "output")) - PKG_ParseOutput(ctx); + PKG_ParseOutput(ctx, false); + else if (!strcmp(cmd, "diffoutput") || !strcmp(cmd, "splitoutput")) + PKG_ParseOutput(ctx, true); + else if (!strcmp(cmd, "inputdir")) + { + char old[MAX_PATH]; + memcpy(old, ctx->sourcepath, sizeof(old)); + if (PKG_GetStringToken(ctx, cmd, sizeof(cmd))) + { + QC_strlcat(cmd, "/", sizeof(cmd)); + QCC_Canonicalize(ctx->sourcepath, sizeof(ctx->sourcepath), cmd, old); + } + } else if (!strcmp(cmd, "rule")) PKG_ParseRule(ctx); else if (!strcmp(cmd, "class")) @@ -1379,6 +1620,15 @@ void Packager_Parse(struct pkgctx_s *ctx, char *scriptname) break; } } +} + +void Packager_ParseFile(struct pkgctx_s *ctx, char *scriptname) +{ + size_t remaining = 0; + char *file = qccprogfuncs->funcs.parms->ReadFile(scriptname, NULL, NULL, &remaining); + strcpy(ctx->gamepath, scriptname); + strcpy(ctx->sourcepath, scriptname); + Packager_ParseText(ctx, file); free(file); } diff --git a/engine/qclib/pr_multi.c b/engine/qclib/pr_multi.c index e463528d..08d622ad 100644 --- a/engine/qclib/pr_multi.c +++ b/engine/qclib/pr_multi.c @@ -267,7 +267,10 @@ int PDECL QC_RegisterFieldVar(pubprogfuncs_t *ppf, unsigned int type, char *name */ if (prinst.field[i].type != ev_vector || type != ev_float) { - printf("Field type mismatch on \"%s\". %i != %i\n", name, prinst.field[i].type, type); + if (prinst.field[i].type == ev_string && type == ev_float && !strcmp(name, "message")) + ; //hexen2 uses floats here instead of strings. + else + printf("Field type mismatch on \"%s\". %i != %i\n", name, prinst.field[i].type, type); continue; } } diff --git a/engine/qclib/pr_x86.c b/engine/qclib/pr_x86.c index 043bc348..a8c16ea9 100644 --- a/engine/qclib/pr_x86.c +++ b/engine/qclib/pr_x86.c @@ -1550,7 +1550,7 @@ LOADREG(glob + op[i].b, REG_EDI); } } - if(1)//failed) + if(failed) { free(jit->statementjumps); //[MAX_STATEMENTS] free(jit->statementoffsets); //[MAX_STATEMENTS] diff --git a/engine/qclib/qcc.h b/engine/qclib/qcc.h index 713e03ec..d93a3afc 100644 --- a/engine/qclib/qcc.h +++ b/engine/qclib/qcc.h @@ -1107,8 +1107,9 @@ int WriteSourceFiles(qcc_cachedsourcefile_t *filelist, int h, pbool sourceaswell struct pkgctx_s; -struct pkgctx_s *Packager_Create(void (*messagecallback)(void *userctx, char *message), void *userctx); -void Packager_Parse(struct pkgctx_s *ctx, char *scriptname); +struct pkgctx_s *Packager_Create(void (*messagecallback)(void *userctx, char *message, ...), void *userctx); +void Packager_ParseFile(struct pkgctx_s *ctx, char *scriptfilename); +void Packager_ParseText(struct pkgctx_s *ctx, char *scripttext); void Packager_WriteDataset(struct pkgctx_s *ctx, char *setname); void Packager_Destroy(struct pkgctx_s *ctx); diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index 20208cfe..1d4a60d5 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -675,6 +675,21 @@ pbool QCC_PR_FalsePreProcessorIf(pbool hadtrue, int originalline) pr_source_line++; } } + +#if 0 +static void QCC_PR_PackagerMessage(void *userctx, char *message, ...) +{ + va_list argptr; + char string[1024]; + + va_start (argptr,message); + QC_vsnprintf (string,sizeof(string)-1,message,argptr); + va_end (argptr); + + printf ("%s", string); +} +#endif + /* ============== QCC_PR_Precompiler @@ -857,6 +872,24 @@ pbool QCC_PR_Precompiler(void) QCC_PR_ParseWarning(WARN_STRINGTOOLONG, "Copyright message is too long\n"); QC_strlcpy(QCC_copyright, msg, sizeof(QCC_copyright)-1); } + else if (!strncmp(directive, "package", 7)) + { + pr_file_p=directive+7; + + QCC_PR_SkipToEndOfLine(true); + +#if 0 + if (!autoprototype) + { + struct pkgctx_s *ctx = Packager_Create(QCC_PR_PackagerMessage, NULL); + Packager_ParseText(ctx, pr_file_p); + Packager_WriteDataset(ctx, NULL); + Packager_Destroy(ctx); + } +#endif + + pr_file_p += strlen(pr_file_p); + } else if (!strncmp(directive, "pack", 4)) { ifmode = 0; diff --git a/engine/qclib/qccgui.c b/engine/qclib/qccgui.c index 789ad75b..6c300f97 100644 --- a/engine/qclib/qccgui.c +++ b/engine/qclib/qccgui.c @@ -1706,7 +1706,7 @@ void GenericMenu(WPARAM wParam) GUIprintf(""); ctx = Packager_Create(Packager_MessageCallback, NULL); - Packager_Parse(ctx, "packages.src"); + Packager_ParseFile(ctx, "packages.src"); Packager_WriteDataset(ctx, NULL); Packager_Destroy(ctx); } @@ -6986,18 +6986,18 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin {FVIRTKEY, VK_F12, IDM_GOTODEF}, {FSHIFT|FVIRTKEY, VK_F12, IDM_RETURNDEF} }; + int mode; ghInstance= hInstance; - GUI_SetDefaultOpts(); - GUI_ParseCommandLine(lpCmdLine); - strcpy(enginebinary, ""); strcpy(enginebasedir, ""); strcpy(enginecommandline, ""); - if(strstr(lpCmdLine, "-stdout") || strstr(lpCmdLine, "--version")) + GUI_SetDefaultOpts(); + mode = GUI_ParseCommandLine(lpCmdLine); + + if(mode == 1) { - GUI_ParseCommandLine(lpCmdLine); RunCompiler(lpCmdLine, false); return 0; } diff --git a/engine/qclib/qccguistuff.c b/engine/qclib/qccguistuff.c index 5c7aebc5..048e1ffd 100644 --- a/engine/qclib/qccguistuff.c +++ b/engine/qclib/qccguistuff.c @@ -443,11 +443,12 @@ void GUI_LoadConfig(void) //this function takes the windows specified commandline and strips out all the options menu items. -void GUI_ParseCommandLine(char *args) +int GUI_ParseCommandLine(char *args) { int paramlen=0; int l, p; char *next; + int mode = 0; if (!*args) { @@ -531,7 +532,15 @@ void GUI_ParseCommandLine(char *args) parameters[paramlen+next-args] = '\0'; l = strlen(parameters+paramlen)+1; - if (!strnicmp(parameters+paramlen, "-O", 2) || !strnicmp(parameters+paramlen, "/O", 2)) + if (!strnicmp(parameters+paramlen, "-stdout", 7) || !strnicmp(parameters+paramlen, "--version", 9)) + { + mode = 1; + } + /*else if (!strnicmp(parameters+paramlen, "-zippatch", 9)) + { + mode = 2; + }*/ + else if (!strnicmp(parameters+paramlen, "-O", 2) || !strnicmp(parameters+paramlen, "/O", 2)) { //strip out all -O fl_nondfltopts = true; if (parameters[paramlen+2]) @@ -751,6 +760,7 @@ void GUI_ParseCommandLine(char *args) parameters[paramlen-1] = '\0'; else *parameters = '\0'; + return mode; } void GUI_SetDefaultOpts(void) diff --git a/engine/server/net_preparse.c b/engine/server/net_preparse.c index 2cd12b72..b2466718 100644 --- a/engine/server/net_preparse.c +++ b/engine/server/net_preparse.c @@ -691,10 +691,11 @@ void NPP_NQFlush(void) else bufferlen-=1; break; + case svc_updatefrags: + break; //ignore these. case svc_print: case svcdp_skybox: - case svc_setfrags: bufferlen = 0; break; case svc_updatename: diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index d4d9e47f..e89b9bb2 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -10359,8 +10359,24 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"ftoi", PF_ftoi, 0, 0, 0, 0, D("int(float)", "Converts the given float into a true integer without depending on extended qcvm instructions.")}, {"itof", PF_itof, 0, 0, 0, 0, D("float(int)", "Converts the given true integer into a float without depending on extended qcvm instructions.")}, + #define qcskelblend \ + "typedef struct\n{\n" \ + "\tint sourcemodelindex; /*frame data will be imported from this model, bones must be compatible*/\n" \ + "\tint reserved;\n" \ + "\tint firstbone;\n" \ + "\tint lastbone;\n" \ + "\tfloat prescale; /*0 destroys existing data, 1 retains it*/\n"\ + "\tfloat scale[4]; /*you'll need to do lerpfrac manually*/\n" \ + "\tint animation[4];\n" \ + "\tfloat animationtime[4];\n" \ + "\t/*halflife models*/\n" \ + "\tfloat subblend[2];\n" \ + "\tfloat controllers[5];\n" \ + "} skelblend_t;\n" + {"skel_create", PF_skel_create, 0, 0, 0, 263, D("float(float modlindex, optional float useabstransforms)", "Allocates a new uninitiaised skeletal object, with enough bone info to animate the given model.\neg: self.skeletonobject = skel_create(self.modelindex);")}, // (FTE_CSQC_SKELETONOBJECTS) - {"skel_build", PF_skel_build, 0, 0, 0, 264, D("float(float skel, entity ent, float modelindex, float retainfrac, float firstbone, float lastbone, optional float addfrac)", "Animation data (according to the entity's frame info) is pulled from the specified model and blended into the specified skeletal object.\nIf retainfrac is set to 0 on the first call and 1 on the others, you can blend multiple animations together according to the addfrac value. The final weight should be 1. Other values will result in scaling and/or other weirdness. You can use firstbone and lastbone to update only part of the skeletal object, to allow legs to animate separately from torso, use 0 for both arguments to specify all, as bones are 1-based.")}, // (FTE_CSQC_SKELETONOBJECTS) + {"skel_build", PF_skel_build, 0, 0, 0, 264, D(qcskelblend"float(float skel, entity ent, float modelindex, float retainfrac, float firstbone, float lastbone, optional float addfrac)", "Animation data (according to the entity's frame info) is pulled from the specified model and blended into the specified skeletal object.\nIf retainfrac is set to 0 on the first call and 1 on the others, you can blend multiple animations together according to the addfrac value. The final weight should be 1. Other values will result in scaling and/or other weirdness. You can use firstbone and lastbone to update only part of the skeletal object, to allow legs to animate separately from torso, use 0 for both arguments to specify all, as bones are 1-based.")}, // (FTE_CSQC_SKELETONOBJECTS) + {"skel_build_ptr", PF_skel_build_ptr, 0, 0, 0, 0, D("float(float skel, int numblends, skelblend_t *weights, int structsize)", "Like skel_build, but slightly simpler.")}, {"skel_get_numbones",PF_skel_get_numbones,0, 0, 0, 265, D("float(float skel)", "Retrives the number of bones in the model. The valid range is 1<=bone<=numbones.")}, // (FTE_CSQC_SKELETONOBJECTS) {"skel_get_bonename",PF_skel_get_bonename,0, 0, 0, 266, D("string(float skel, float bonenum)", "Retrieves the name of the specified bone. Mostly only for debugging.")}, // (FTE_CSQC_SKELETONOBJECTS) (returns tempstring) {"skel_get_boneparent",PF_skel_get_boneparent,0,0, 0, 267, D("float(float skel, float bonenum)", "Retrieves which bone this bone's position is relative to. Bone 0 refers to the entity's position rather than an actual bone")}, // (FTE_CSQC_SKELETONOBJECTS) diff --git a/engine/server/server.h b/engine/server/server.h index 88d0c95c..2f93e657 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -194,7 +194,7 @@ typedef struct qbyte nqmulticast_buf[MAX_NQMSGLEN]; #endif - +#ifdef Q2SERVER sizebuf_t q2datagram; qbyte q2datagram_buf[MAX_Q2DATAGRAM]; @@ -203,6 +203,7 @@ typedef struct sizebuf_t q2multicast; qbyte q2multicast_buf[MAX_Q2MSGLEN]; +#endif // the master buffer is used for building log packets sizebuf_t master; diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index 10fc4466..743690fa 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -817,6 +817,10 @@ void SV_Map_f (void) svprogfuncs->restoreent(svprogfuncs, host_client->spawninfo, &j, host_client->edict); host_client->istobeloaded = true; host_client->state=cs_connected; + if (host_client->spectator) + sv.spawned_observer_slots++; + else + sv.spawned_client_slots++; } if (host_client->controller) diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 146f7d3c..290a3221 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -1675,13 +1675,15 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents, sv.skipbprintclient = host_client; pr_global_struct->time = sv.world.physicstime; pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv_player); - PR_ExecuteProgram (svprogfuncs, pr_global_struct->ClientConnect); + if (pr_global_ptrs->ClientConnect) + PR_ExecuteProgram (svprogfuncs, pr_global_struct->ClientConnect); sv.skipbprintclient = NULL; // actually spawn the player pr_global_struct->time = sv.world.physicstime; pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv_player); - PR_ExecuteProgram (svprogfuncs, pr_global_struct->PutClientInServer); + if (pr_global_ptrs->PutClientInServer) + PR_ExecuteProgram (svprogfuncs, pr_global_struct->PutClientInServer); sv.spawned_client_slots++; // send notification to all clients diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 7e99cc7f..8c39395e 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -1965,12 +1965,12 @@ void SV_Begin_Core(client_t *split) else { #ifndef NOLEGACY - sv_player->xv->clientcolors = host_client->playercolor; + sv_player->xv->clientcolors = split->playercolor; if (progstype != PROG_QW) { //some redundant things, purely for dp compat eval_t *eval; edict_t *ent = split->edict; - sv_player->v->team = host_client->playercolor&15; + sv_player->v->team = split->playercolor&15; eval = svprogfuncs->GetEdictFieldValue(svprogfuncs, ent, "playermodel", ev_string, NULL); if (eval) diff --git a/engine/shaders/glsl/defaultgammacb.glsl b/engine/shaders/glsl/defaultgammacb.glsl index daa6da8c..8a671636 100644 --- a/engine/shaders/glsl/defaultgammacb.glsl +++ b/engine/shaders/glsl/defaultgammacb.glsl @@ -9,7 +9,7 @@ attribute vec2 v_texcoord; attribute vec4 v_colour; void main () { - tc = v_texcoord; + tc = vec2(v_texcoord.s, 1.0-v_texcoord.t); vc = v_colour; gl_Position = ftetransform(); } diff --git a/engine/shaders/glsl/drawflat_wall.glsl b/engine/shaders/glsl/drawflat_wall.glsl index 94d66572..070b5271 100644 --- a/engine/shaders/glsl/drawflat_wall.glsl +++ b/engine/shaders/glsl/drawflat_wall.glsl @@ -1,5 +1,5 @@ -!!cvarv r_floorcolor -!!cvarv r_wallcolor +!!cvard_srgb_b r_floorcolor +!!cvard_srgb_b r_wallcolor !!permu FOG //this is for the '286' preset walls, and just draws lightmaps coloured based upon surface normals. @@ -10,12 +10,10 @@ varying vec4 col; attribute vec3 v_normal; attribute vec2 v_lmcoord; varying vec2 lm; -uniform vec3 cvar_r_wallcolor; -uniform vec3 cvar_r_floorcolor; uniform vec4 e_lmscale; void main () { - col = vec4(e_lmscale.rgb/255.0 * ((v_normal.z < 0.73)?cvar_r_wallcolor:cvar_r_floorcolor), e_lmscale.a); + col = vec4(e_lmscale.rgb * ((v_normal.z < 0.73)?r_wallcolor:r_floorcolor), e_lmscale.a); lm = v_lmcoord; gl_Position = ftetransform(); } diff --git a/engine/shaders/glsl/menutint.glsl b/engine/shaders/glsl/menutint.glsl index 58f43e08..5fc06306 100644 --- a/engine/shaders/glsl/menutint.glsl +++ b/engine/shaders/glsl/menutint.glsl @@ -1,5 +1,5 @@ !!cvari r_menutint_inverse -!!cvarv r_menutint +!!cvard_srgb r_menutint #ifdef VERTEX_SHADER attribute vec2 v_texcoord; @@ -15,7 +15,6 @@ #ifdef FRAGMENT_SHADER varying vec2 texcoord; - uniform vec3 cvar_r_menutint; uniform sampler2D s_t0; uniform int cvar_r_menutint_inverse; const vec3 lumfactors = vec3(0.299, 0.587, 0.114); @@ -25,7 +24,7 @@ vec3 texcolor = texture2D(s_t0, texcoord).rgb; float luminance = dot(lumfactors, texcolor); texcolor = vec3(luminance, luminance, luminance); - texcolor *= cvar_r_menutint; + texcolor *= r_menutint; texcolor = (cvar_r_menutint_inverse > 0) ? (invertvec - texcolor) : texcolor; gl_FragColor = vec4(texcolor, 1.0); } diff --git a/engine/sw/sw_image.c b/engine/sw/sw_image.c index 7bd8f70e..ab071ee7 100644 --- a/engine/sw/sw_image.c +++ b/engine/sw/sw_image.c @@ -48,7 +48,7 @@ qboolean SW_LoadTextureMips (texid_t tex, const struct pendingtextureinfo *mips if (mips->type != PTI_2D) return false; - //ensure we reject any s3tc encodings + //only accept formats that actually make sense here. switch(mips->encoding) { case PTI_RGBA8: diff --git a/engine/vk/vk_backend.c b/engine/vk/vk_backend.c index 1a9859b4..f0aa4ab5 100644 --- a/engine/vk/vk_backend.c +++ b/engine/vk/vk_backend.c @@ -1750,7 +1750,7 @@ static void T_Gen_CurrentRender(void) if (img->width != vid.fbpwidth || img->height != vid.fbpheight) { //FIXME: free the old image when its safe to do so. - *img = VK_CreateTexture2DArray(vid.fbpwidth, vid.fbpheight, 1, 1, PTI_BGRA8, PTI_2D, true); + *img = VK_CreateTexture2DArray(vid.fbpwidth, vid.fbpheight, 1, 1, -vk.backbufformat, PTI_2D, true); if (!img->sampler) VK_CreateSampler(shaderstate.tex_currentrender->flags, img); @@ -4032,14 +4032,14 @@ void VKBE_ClearVBO(vbo_t *vbo, qboolean dataonly) void VK_UploadLightmap(lightmapinfo_t *lm) { - extern cvar_t gl_lightmap_nearest; + extern cvar_t r_lightmap_nearest; struct pendingtextureinfo mips; image_t *tex; lm->modified = false; if (!TEXVALID(lm->lightmap_texture)) { - lm->lightmap_texture = Image_CreateTexture("***lightmap***", NULL, (gl_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR)); + lm->lightmap_texture = Image_CreateTexture("***lightmap***", NULL, (r_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR)); if (!lm->lightmap_texture) return; } @@ -4086,13 +4086,22 @@ void VK_UploadLightmap(lightmapinfo_t *lm) mips.mip[0].needfree = false; mips.mip[0].width = lm->width; mips.mip[0].height = lm->height; + mips.mip[0].depth = 1; switch(lightmap_fmt) { - case TF_BGRA32: + default: + case PTI_A2BGR10: + case PTI_E5BGR9: + case PTI_RGBA16F: + case PTI_RGBA32F: + case PTI_L8: + mips.encoding = lightmap_fmt; + break; + case PTI_BGRA8: mips.encoding = PTI_BGRX8; break; - default: - Sys_Error("Unsupported encoding\n"); + case TF_BGR24: //shouldn't happen + mips.encoding = PTI_R8; break; } mips.mipcount = 1; diff --git a/engine/vk/vk_init.c b/engine/vk/vk_init.c index 6894fb8e..cd59a3a1 100644 --- a/engine/vk/vk_init.c +++ b/engine/vk/vk_init.c @@ -15,9 +15,11 @@ extern cvar_t vk_nv_glsl_shader; extern cvar_t vk_nv_dedicated_allocation; extern cvar_t vk_khr_dedicated_allocation; extern cvar_t vk_khr_push_descriptor; -extern cvar_t vid_srgb, vid_vsync, vid_triplebuffer, r_stereo_method, vid_multisample; +extern cvar_t vid_srgb, vid_vsync, vid_triplebuffer, r_stereo_method, vid_multisample, vid_bpp; void R2D_Console_Resize(void); +extern qboolean scr_con_forcedraw; + #ifndef MULTITHREAD #define Sys_LockConditional(c) #define Sys_UnlockConditional(c) @@ -294,7 +296,7 @@ static qboolean VK_CreateSwapChain(void) if (vk.swapchain || vk.backbuf_count) VK_DestroySwapChain(); - vk.backbufformat = (vid.srgb||vid_srgb.ival)?VK_FORMAT_B8G8R8A8_SRGB:VK_FORMAT_B8G8R8A8_UNORM; + vk.backbufformat = ((vid.flags&VID_SRGBAWARE)||vid_srgb.ival)?VK_FORMAT_B8G8R8A8_SRGB:VK_FORMAT_B8G8R8A8_UNORM; vk.backbuf_count = 4; swapinfo.imageExtent.width = vid.pixelwidth; @@ -383,6 +385,33 @@ static qboolean VK_CreateSwapChain(void) } else { //using vulkan's presentation engine. + int BOOST_UNORM, BOOST_SNORM, BOOST_SRGB, BOOST_UFLOAT, BOOST_SFLOAT; + + if (vid_srgb.ival > 2) + { //favour float formats, then srgb, then unorms + BOOST_UNORM = 0; + BOOST_SNORM = 0; + BOOST_SRGB = 128; + BOOST_UFLOAT = 256; + BOOST_SFLOAT = 256; + } + else if (vid_srgb.ival) + { + BOOST_UNORM = 0; + BOOST_SNORM = 0; + BOOST_SRGB = 256; + BOOST_UFLOAT = 128; + BOOST_SFLOAT = 128; + } + else + { + BOOST_UNORM = 256; + BOOST_SNORM = 256; + BOOST_SRGB = 0; + BOOST_UFLOAT = 128; + BOOST_SFLOAT = 128; + } + VkAssert(vkGetPhysicalDeviceSurfaceFormatsKHR(vk.gpu, vk.surface, &fmtcount, NULL)); surffmts = malloc(sizeof(VkSurfaceFormatKHR)*fmtcount); VkAssert(vkGetPhysicalDeviceSurfaceFormatsKHR(vk.gpu, vk.surface, &fmtcount, surffmts)); @@ -440,7 +469,7 @@ static qboolean VK_CreateSwapChain(void) priority = (vk.vsync?2:0) + 1; break; case VK_PRESENT_MODE_FIFO_RELAXED_KHR: - priority = (vk.vsync?2:0) + 2; //strict vsync results in weird juddering if rtlights etc caues framerates to drop below the refreshrate + priority = (vk.vsync?2:0) + 2; //strict vsync results in weird juddering if rtlights etc caues framerates to drop below the refreshrate. and nvidia just suck with vsync, so I'm not taking any chances. break; } if (priority > curpri) @@ -455,33 +484,75 @@ static qboolean VK_CreateSwapChain(void) Con_Printf("Warning: vulkan graphics driver does not support VK_PRESENT_MODE_IMMEDIATE_KHR.\n"); vk.srgbcapable = false; - swapinfo.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; - swapinfo.imageFormat = (vid.srgb||vid_srgb.ival)?VK_FORMAT_B8G8R8A8_SRGB:VK_FORMAT_B8G8R8A8_UNORM; + swapinfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + swapinfo.imageFormat = VK_FORMAT_UNDEFINED; for (i = 0, curpri = 0; i < fmtcount; i++) { uint32_t priority = 0; + switch(surffmts[i].format) { case VK_FORMAT_B8G8R8A8_UNORM: case VK_FORMAT_R8G8B8A8_UNORM: - priority = 4+!(vid.srgb||vid_srgb.ival); + case VK_FORMAT_A8B8G8R8_UNORM_PACK32: + priority = ((vid_bpp.ival>=24)?24:11)+BOOST_UNORM; + break; + case VK_FORMAT_B8G8R8A8_SNORM: + case VK_FORMAT_R8G8B8A8_SNORM: + case VK_FORMAT_A8B8G8R8_SNORM_PACK32: + priority = ((vid_bpp.ival>=21)?21:2)+BOOST_SNORM; break; case VK_FORMAT_B8G8R8A8_SRGB: case VK_FORMAT_R8G8B8A8_SRGB: - priority = 4+!!(vid.srgb||vid_srgb.ival); + case VK_FORMAT_A8B8G8R8_SRGB_PACK32: + priority = ((vid_bpp.ival>=24)?24:11)+BOOST_SRGB; vk.srgbcapable = true; break; + case VK_FORMAT_A2B10G10R10_UNORM_PACK32: + case VK_FORMAT_A2R10G10B10_UNORM_PACK32: + priority = ((vid_bpp.ival==30)?30:10)+BOOST_UNORM; + break; + + case VK_FORMAT_B10G11R11_UFLOAT_PACK32: + priority = ((vid_srgb.ival>=3||vid_bpp.ival==32)?32:11)+BOOST_UFLOAT; + break; case VK_FORMAT_R16G16B16A16_SFLOAT: //16bit per-channel formats + priority = ((vid_srgb.ival>=3||vid_bpp.ival>=48)?48:9)+BOOST_SFLOAT; + break; + case VK_FORMAT_R16G16B16A16_UNORM: + priority = ((vid_srgb.ival>=3||vid_bpp.ival>=48)?48:9)+BOOST_UNORM; + break; case VK_FORMAT_R16G16B16A16_SNORM: - priority = 3; + priority = ((vid_srgb.ival>=3||vid_bpp.ival>=48)?48:9)+BOOST_SFLOAT; break; case VK_FORMAT_R32G32B32A32_SFLOAT: //32bit per-channel formats - priority = 2; + priority = ((vid_bpp.ival>=47)?96:8)+BOOST_SFLOAT; break; - default: //16 bit formats (565). + + case VK_FORMAT_B5G6R5_UNORM_PACK16: + case VK_FORMAT_R5G6B5_UNORM_PACK16: + priority = 16+BOOST_UNORM; + break; + case VK_FORMAT_R4G4B4A4_UNORM_PACK16: + case VK_FORMAT_B4G4R4A4_UNORM_PACK16: + priority = 12+BOOST_UNORM; + break; + case VK_FORMAT_A1R5G5B5_UNORM_PACK16: + case VK_FORMAT_R5G5B5A1_UNORM_PACK16: + case VK_FORMAT_B5G5R5A1_UNORM_PACK16: + priority = 15+BOOST_UNORM; + break; + + default: //no idea, use as lowest priority. priority = 1; break; } + + if (surffmts[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR && //sRGB + surffmts[i].colorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT && //scRGB + surffmts[i].colorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT) //linear vaugely like sRGB + priority += 512; //always favour supported colour spaces. + if (priority > curpri) { curpri = priority; @@ -490,6 +561,16 @@ static qboolean VK_CreateSwapChain(void) } } + if (swapinfo.imageFormat == VK_FORMAT_UNDEFINED) + { //if we found this format then it means the drivers don't really give a damn. pick a real format. + if (vid_srgb.ival > 2 && swapinfo.imageColorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT) + swapinfo.imageFormat = VK_FORMAT_R16G16B16A16_SFLOAT; + else if (vid_srgb.ival) + swapinfo.imageFormat = VK_FORMAT_R8G8B8A8_SRGB; + else + swapinfo.imageFormat = VK_FORMAT_R8G8B8A8_UNORM; + } + if (vk.backbufformat != swapinfo.imageFormat) { VK_DestroyRenderPass(); @@ -497,6 +578,27 @@ static qboolean VK_CreateSwapChain(void) } vk.backbufformat = swapinfo.imageFormat; + //VK_COLORSPACE_SRGB_NONLINEAR means the presentation engine will interpret the image as SRGB whether its a UNORM or SRGB format or not. + //an SRGB format JUST means rendering converts linear->srgb and does not apply to the presentation engine. + vid.flags &= ~VID_SRGB_FB; + if (swapinfo.imageColorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT) + vid.flags |= VID_SRGB_FB_LINEAR; + else + { + switch(vk.backbufformat) + { + case VK_FORMAT_R8G8B8_SRGB: + case VK_FORMAT_B8G8R8_SRGB: + case VK_FORMAT_B8G8R8A8_SRGB: + case VK_FORMAT_R8G8B8A8_SRGB: + case VK_FORMAT_A8B8G8R8_SRGB_PACK32: + vid.flags |= VID_SRGB_FB_LINEAR; + break; + default: + break; //non-srgb (or compressed) + } + } + free(presentmode); free(surffmts); @@ -767,11 +869,6 @@ static qboolean VK_CreateSwapChain(void) void VK_Draw_Init(void) { - qboolean srgb = vid_srgb.ival > 1 && vk.srgbcapable; - if (vid.srgb != srgb) - vid_srgb.modified = true; - vid.srgb = srgb; - R2D_Init(); } void VK_Draw_Shutdown(void) @@ -863,7 +960,7 @@ void VK_UpdateFiltering(image_t *imagelist, int filtermip[3], int filterpic[3], } } -vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t layers, uint32_t mips, unsigned int encoding, unsigned int type, qboolean rendertarget) +vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t layers, uint32_t mips, uploadfmt_t encoding, unsigned int type, qboolean rendertarget) { vk_image_t ret; #ifdef USE_STAGING_BUFFERS @@ -877,7 +974,7 @@ vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t lay VkImageCreateInfo ici = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; VkDedicatedAllocationImageCreateInfoNV nv_daici = {VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV}; - VkFormat format; + VkFormat format = VK_FORMAT_UNDEFINED;; ret.width = width; ret.height = height; @@ -887,22 +984,31 @@ vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t lay ret.type = type; ret.layout = staging?VK_IMAGE_LAYOUT_PREINITIALIZED:VK_IMAGE_LAYOUT_UNDEFINED; - //16bit formats. - switch(encoding) + //vulkan expresses packed formats in terms of native endian (if big-endian, then everything makes sense), non-packed formats are expressed in byte order (consistent with big-endian). + //PTI formats are less well-defined... + if ((int)encoding < 0) + format = -(int)encoding; + else switch(encoding) { - case PTI_RGB565: format = VK_FORMAT_R5G6B5_UNORM_PACK16; break; - case PTI_RGBA4444: format = VK_FORMAT_R4G4B4A4_UNORM_PACK16; break; - case PTI_ARGB4444: format = VK_FORMAT_B4G4R4A4_UNORM_PACK16; break; //fixme: this seems wrong... - case PTI_RGBA5551: format = VK_FORMAT_R5G5B5A1_UNORM_PACK16; break; - case PTI_ARGB1555: format = VK_FORMAT_A1R5G5B5_UNORM_PACK16; break; + //16bit formats. + case PTI_RGB565: format = VK_FORMAT_R5G6B5_UNORM_PACK16; break; + case PTI_RGBA4444: format = VK_FORMAT_R4G4B4A4_UNORM_PACK16; break; + case PTI_ARGB4444: /*format = VK_FORMAT_A4R4G4B4_UNORM_PACK16;*/ break; + case PTI_RGBA5551: format = VK_FORMAT_R5G5B5A1_UNORM_PACK16; break; + case PTI_ARGB1555: format = VK_FORMAT_A1R5G5B5_UNORM_PACK16; break; //float formats - case PTI_RGBA16F: format = VK_FORMAT_R16G16B16A16_SFLOAT; break; - case PTI_RGBA32F: format = VK_FORMAT_R32G32B32A32_SFLOAT; break; + case PTI_RGBA16F: format = VK_FORMAT_R16G16B16A16_SFLOAT; break; + case PTI_RGBA32F: format = VK_FORMAT_R32G32B32A32_SFLOAT; break; //weird formats - case PTI_R8: format = VK_FORMAT_R8_UNORM; break; - case PTI_RG8: format = VK_FORMAT_R8G8_UNORM; break; - case PTI_R8_SIGNED: format = VK_FORMAT_R8_SNORM; break; - case PTI_RG8_SIGNED: format = VK_FORMAT_R8G8_SNORM; break; + case PTI_R8: format = VK_FORMAT_R8_UNORM; break; + case PTI_RG8: format = VK_FORMAT_R8G8_UNORM; break; + case PTI_R8_SNORM: format = VK_FORMAT_R8_SNORM; break; + case PTI_RG8_SNORM: format = VK_FORMAT_R8G8_SNORM; break; + case PTI_A2BGR10: format = VK_FORMAT_A2B10G10R10_UNORM_PACK32; break; + case PTI_E5BGR9: format = VK_FORMAT_E5B9G9R9_UFLOAT_PACK32; break; + //swizzled/legacy formats + case PTI_L8: format = VK_FORMAT_R8_UNORM; break; + case PTI_L8A8: format = VK_FORMAT_R8G8_UNORM; break; //compressed formats case PTI_BC1_RGB: format = VK_FORMAT_BC1_RGB_UNORM_BLOCK; break; case PTI_BC1_RGB_SRGB: format = VK_FORMAT_BC1_RGB_SRGB_BLOCK; break; @@ -913,11 +1019,11 @@ vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t lay case PTI_BC3_RGBA: format = VK_FORMAT_BC3_UNORM_BLOCK; break; case PTI_BC3_RGBA_SRGB: format = VK_FORMAT_BC3_SRGB_BLOCK; break; case PTI_BC4_R8: format = VK_FORMAT_BC4_UNORM_BLOCK; break; - case PTI_BC4_R8_SIGNED: format = VK_FORMAT_BC4_SNORM_BLOCK; break; + case PTI_BC4_R8_SNORM: format = VK_FORMAT_BC4_SNORM_BLOCK; break; case PTI_BC5_RG8: format = VK_FORMAT_BC5_UNORM_BLOCK; break; - case PTI_BC5_RG8_SIGNED: format = VK_FORMAT_BC5_SNORM_BLOCK; break; - case PTI_BC6_RGBF: format = VK_FORMAT_BC6H_UFLOAT_BLOCK; break; - case PTI_BC6_RGBF_SIGNED: format = VK_FORMAT_BC6H_SFLOAT_BLOCK; break; + case PTI_BC5_RG8_SNORM: format = VK_FORMAT_BC5_SNORM_BLOCK; break; + case PTI_BC6_RGB_UFLOAT: format = VK_FORMAT_BC6H_UFLOAT_BLOCK; break; + case PTI_BC6_RGB_SFLOAT: format = VK_FORMAT_BC6H_SFLOAT_BLOCK; break; case PTI_BC7_RGBA: format = VK_FORMAT_BC7_UNORM_BLOCK; break; case PTI_BC7_RGBA_SRGB: format = VK_FORMAT_BC7_SRGB_BLOCK; break; case PTI_ETC1_RGB8: format = VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; break; //vulkan doesn't support etc1, but etc2 is a superset so its all okay. @@ -928,9 +1034,9 @@ vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t lay case PTI_ETC2_RGB8A8: format = VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK; break; case PTI_ETC2_RGB8A8_SRGB: format = VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK; break; case PTI_EAC_R11: format = VK_FORMAT_EAC_R11_UNORM_BLOCK; break; - case PTI_EAC_R11_SIGNED: format = VK_FORMAT_EAC_R11_SNORM_BLOCK; break; + case PTI_EAC_R11_SNORM: format = VK_FORMAT_EAC_R11_SNORM_BLOCK; break; case PTI_EAC_RG11: format = VK_FORMAT_EAC_R11G11_UNORM_BLOCK; break; - case PTI_EAC_RG11_SIGNED: format = VK_FORMAT_EAC_R11G11_SNORM_BLOCK; break; + case PTI_EAC_RG11_SNORM: format = VK_FORMAT_EAC_R11G11_SNORM_BLOCK; break; case PTI_ASTC_4X4: format = VK_FORMAT_ASTC_4x4_UNORM_BLOCK; break; case PTI_ASTC_4X4_SRGB: format = VK_FORMAT_ASTC_4x4_SRGB_BLOCK; break; @@ -976,11 +1082,21 @@ vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t lay case PTI_BGRX8: format = VK_FORMAT_B8G8R8A8_UNORM; break; case PTI_RGBA8: case PTI_RGBX8: format = VK_FORMAT_R8G8B8A8_UNORM; break; - default: - Sys_Error("VK_CreateTexture2DArray: Unrecognised image encoding: %u\n", encoding); - format = VK_FORMAT_UNDEFINED; + //misaligned formats + case PTI_RGB8: format = VK_FORMAT_R8G8B8_UNORM; break; + case PTI_BGR8: format = VK_FORMAT_B8G8R8_UNORM; break; + + //unsupported 'formats' + case PTI_MAX: +#ifdef FTE_TARGET_WEB + case PTI_WHOLEFILE: +#endif + case PTI_EMULATED: break; } + if (format == VK_FORMAT_UNDEFINED) //no default case means warnings for unsupported formats above. + Sys_Error("VK_CreateTexture2DArray: Unrecognised image encoding: %u\n", encoding); + ici.flags = (ret.type==PTI_CUBEMAP)?VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT:0; ici.imageType = VK_IMAGE_TYPE_2D; ici.format = format; @@ -1038,10 +1154,39 @@ vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t lay viewInfo.image = ret.image; viewInfo.viewType = (ret.type==PTI_CUBEMAP)?VK_IMAGE_VIEW_TYPE_CUBE:VK_IMAGE_VIEW_TYPE_2D; viewInfo.format = format; - viewInfo.components.r = VK_COMPONENT_SWIZZLE_R; - viewInfo.components.g = VK_COMPONENT_SWIZZLE_G; - viewInfo.components.b = VK_COMPONENT_SWIZZLE_B; - viewInfo.components.a = (encoding == PTI_RGBX8 || encoding == PTI_BGRX8)?VK_COMPONENT_SWIZZLE_ONE:VK_COMPONENT_SWIZZLE_A; + switch(encoding) + { + //formats that explicitly drop the alpha + case PTI_BC1_RGB: + case PTI_BC1_RGB_SRGB: + case PTI_RGBX8: + case PTI_RGBX8_SRGB: + case PTI_BGRX8: + case PTI_BGRX8_SRGB: + viewInfo.components.r = VK_COMPONENT_SWIZZLE_R; + viewInfo.components.g = VK_COMPONENT_SWIZZLE_G; + viewInfo.components.b = VK_COMPONENT_SWIZZLE_B; + viewInfo.components.a = VK_COMPONENT_SWIZZLE_ONE; + break; + case PTI_L8: //must be an R8 texture + viewInfo.components.r = VK_COMPONENT_SWIZZLE_R; + viewInfo.components.g = VK_COMPONENT_SWIZZLE_R; + viewInfo.components.b = VK_COMPONENT_SWIZZLE_R; + viewInfo.components.a = VK_COMPONENT_SWIZZLE_ONE; + break; + case PTI_L8A8: //must be an RG8 texture + viewInfo.components.r = VK_COMPONENT_SWIZZLE_R; + viewInfo.components.g = VK_COMPONENT_SWIZZLE_R; + viewInfo.components.b = VK_COMPONENT_SWIZZLE_R; + viewInfo.components.a = VK_COMPONENT_SWIZZLE_G; + break; + default: + viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + break; + } viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; viewInfo.subresourceRange.baseMipLevel = 0; viewInfo.subresourceRange.levelCount = mips; @@ -1162,6 +1307,33 @@ void VK_FencedSync(void *work) struct vk_fencework *w = work; VK_FencedSubmit(w); +#ifdef MULTITHREAD + //okay, this is crazy, but it ensures that the work was submitted BEFORE the WaitForFence call. + //we should probably come up with a better sync method. + if (vk.submitthread) + { + qboolean nnsc = vk.neednewswapchain; + vk.neednewswapchain = true; + Sys_LockConditional(vk.submitcondition); //annoying, but required for it to be reliable with respect to other things. + Sys_ConditionSignal(vk.submitcondition); + Sys_UnlockConditional(vk.submitcondition); + Sys_WaitOnThread(vk.submitthread); + vk.submitthread = NULL; + + while (vk.work) + { + Sys_LockConditional(vk.submitcondition); + VK_Submit_DoWork(); + Sys_UnlockConditional(vk.submitcondition); + } + + //we know all work is synced now... + + vk.neednewswapchain = nnsc; + vk.submitthread = Sys_CreateThread("vksubmission", VK_Submit_Thread, NULL, THREADP_HIGHEST, 0); + } +#endif + //fixme: waiting for the fence while it may still be getting created by the worker is unsafe. vkWaitForFences(vk.device, 1, &w->fence, VK_FALSE, UINT64_MAX); } @@ -1230,12 +1402,13 @@ qboolean VK_LoadTextureMips (texid_t tex, const struct pendingtextureinfo *mips) uint32_t blockbytes; uint32_t layers; uint32_t mipcount = mips->mipcount; - if (mips->type != PTI_2D && mips->type != PTI_CUBEMAP) + if (mips->type != PTI_2D && mips->type != PTI_CUBEMAP)// && mips->type != PTI_2D_ARRAY) return false; if (!mipcount || mips->mip[0].width == 0 || mips->mip[0].height == 0) return false; layers = (mips->type == PTI_CUBEMAP)?6:1; + layers *= mips->mip[0].depth; if (layers == 1 && mipcount > 1) { //npot mipmapped textures are awkward. @@ -2357,6 +2530,7 @@ void VKVID_QueueGetRGBData (void (*gotrgbdata) (void *rgbdata, intptr_t bytest capt = VK_AtFrameEnd(VKVID_CopiedRGBData, NULL, sizeof(*capt)); capt->gotrgbdata = gotrgbdata; + //FIXME: vkCmdBlitImage the image to convert it from half-float or whatever to a format that our screenshot etc code can cope with. capt->imageformat = TF_BGRA32; capt->imagestride = vk.frame->backbuf->colour.width*4; //vulkan is top-down, so this should be positive. capt->imagewidth = vk.frame->backbuf->colour.width; @@ -2401,32 +2575,54 @@ void VKVID_QueueGetRGBData (void (*gotrgbdata) (void *rgbdata, intptr_t bytest char *VKVID_GetRGBInfo (int *bytestride, int *truevidwidth, int *truevidheight, enum uploadfmt *fmt) { - //with vulkan, we need to create a staging image to write into, submit a copy, wait for completion, map the copy, copy that out, free the staging. - //its enough to make you pitty anyone that writes opengl drivers. + //in order to deal with various backbuffer formats (like half-float) etc, we play safe and blit the framebuffer to a safe format. + //we then transfer that into a buffer that we can then directly read. + //and then we allocate a C buffer that we then copy it into... + //so yeah, 3 copies. life sucks. + //blit requires support for VK_IMAGE_USAGE_TRANSFER_DST_BIT on our image, which means we need optimal, which means we can't directly map it, which means we need the buffer copy too. + //this might be relaxed on mobile, but who really takes screenshots on mobiles anyway?!? anyway, video capture shouldn't be using this either way so top performance isn't a concern if (VK_SCR_GrabBackBuffer()) { + VkImageLayout framebufferlayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;//vk.frame->backbuf->colour.layout; + void *imgdata, *outdata; struct vk_fencework *fence = VK_FencedBegin(NULL, 0); - VkImageCopy icpy; VkImage tempimage; VkDeviceMemory tempmemory; - VkImageSubresource subres = {0}; - VkSubresourceLayout layout; - + VkBufferCreateInfo bci = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; + VkBuffer tempbuffer; + VkDeviceMemory tempbufmemory; VkMemoryRequirements mem_reqs; VkMemoryAllocateInfo memAllocInfo = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; VkImageCreateInfo ici = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; + //VkFormatProperties vkfmt; + ici.flags = 0; ici.imageType = VK_IMAGE_TYPE_2D; - ici.format = VK_FORMAT_B8G8R8A8_UNORM; + /*vkGetPhysicalDeviceFormatProperties(vk.gpu, VK_FORMAT_B8G8R8_UNORM, &vkfmt); + if ((vkfmt.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT) && (vkfmt.optimalTilingFeatures & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR)) + { //if we can do BGR, then use it, because that's what most PC file formats use, like tga. + //we don't really want alpha data anyway. + if (vid.flags & VID_SRGB_FB) + ici.format = VK_FORMAT_B8G8R8_SRGB; + else + ici.format = VK_FORMAT_B8G8R8_UNORM; + } + else*/ + { //otherwise lets just get bgra data. + if (vid.flags & VID_SRGB_FB) + ici.format = VK_FORMAT_B8G8R8A8_SRGB; + else + ici.format = VK_FORMAT_B8G8R8A8_UNORM; + } ici.extent.width = vid.pixelwidth; ici.extent.height = vid.pixelheight; ici.extent.depth = 1; ici.mipLevels = 1; ici.arrayLayers = 1; ici.samples = VK_SAMPLE_COUNT_1_BIT; - ici.tiling = VK_IMAGE_TILING_LINEAR; - ici.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; + ici.tiling = VK_IMAGE_TILING_OPTIMAL; + ici.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT; ici.sharingMode = VK_SHARING_MODE_EXCLUSIVE; ici.queueFamilyIndexCount = 0; ici.pQueueFamilyIndices = NULL; @@ -2434,58 +2630,101 @@ char *VKVID_GetRGBInfo (int *bytestride, int *truevidwidth, int *truevidheight VkAssert(vkCreateImage(vk.device, &ici, vkallocationcb, &tempimage)); vkGetImageMemoryRequirements(vk.device, tempimage, &mem_reqs); memAllocInfo.allocationSize = mem_reqs.size; - memAllocInfo.memoryTypeIndex = vk_find_memory_require(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + memAllocInfo.memoryTypeIndex = vk_find_memory_require(mem_reqs.memoryTypeBits, 0); VkAssert(vkAllocateMemory(vk.device, &memAllocInfo, vkallocationcb, &tempmemory)); VkAssert(vkBindImageMemory(vk.device, tempimage, tempmemory, 0)); + bci.flags = 0; + bci.size = vid.pixelwidth*vid.pixelheight*4; + bci.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; + bci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + bci.queueFamilyIndexCount = 0; + bci.pQueueFamilyIndices = NULL; + + VkAssert(vkCreateBuffer(vk.device, &bci, vkallocationcb, &tempbuffer)); + vkGetBufferMemoryRequirements(vk.device, tempbuffer, &mem_reqs); + memAllocInfo.allocationSize = mem_reqs.size; + memAllocInfo.memoryTypeIndex = vk_find_memory_try(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT|VK_MEMORY_PROPERTY_HOST_CACHED_BIT); + if (memAllocInfo.memoryTypeIndex == ~0u) + memAllocInfo.memoryTypeIndex = vk_find_memory_require(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + VkAssert(vkAllocateMemory(vk.device, &memAllocInfo, vkallocationcb, &tempbufmemory)); + VkAssert(vkBindBufferMemory(vk.device, tempbuffer, tempbufmemory, 0)); - set_image_layout(fence->cbuf, vk.frame->backbuf->colour.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT); + set_image_layout(fence->cbuf, vk.frame->backbuf->colour.image, VK_IMAGE_ASPECT_COLOR_BIT, framebufferlayout, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT); set_image_layout(fence->cbuf, tempimage, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, 0, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT); + { + VkImageBlit iblt; + iblt.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + iblt.srcSubresource.mipLevel = 0; + iblt.srcSubresource.baseArrayLayer = 0; + iblt.srcSubresource.layerCount = 1; + iblt.srcOffsets[0].x = 0; + iblt.srcOffsets[0].y = 0; + iblt.srcOffsets[0].z = 0; + iblt.srcOffsets[1].x = vid.pixelwidth; + iblt.srcOffsets[1].y = vid.pixelheight; + iblt.srcOffsets[1].z = 1; + iblt.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + iblt.dstSubresource.mipLevel = 0; + iblt.dstSubresource.baseArrayLayer = 0; + iblt.dstSubresource.layerCount = 1; + iblt.dstOffsets[0].x = 0; + iblt.dstOffsets[0].y = 0; + iblt.dstOffsets[0].z = 0; + iblt.dstOffsets[1].x = vid.pixelwidth; + iblt.dstOffsets[1].y = vid.pixelheight; + iblt.dstOffsets[1].z = 1; + vkCmdBlitImage(fence->cbuf, vk.frame->backbuf->colour.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, tempimage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &iblt, VK_FILTER_LINEAR); + } + set_image_layout(fence->cbuf, vk.frame->backbuf->colour.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT, framebufferlayout, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT); + set_image_layout(fence->cbuf, tempimage, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT); - //fixme: transition layouts! - icpy.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - icpy.srcSubresource.mipLevel = 0; - icpy.srcSubresource.baseArrayLayer = 0; - icpy.srcSubresource.layerCount = 1; - icpy.srcOffset.x = 0; - icpy.srcOffset.y = 0; - icpy.srcOffset.z = 0; - icpy.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - icpy.dstSubresource.mipLevel = 0; - icpy.dstSubresource.baseArrayLayer = 0; - icpy.dstSubresource.layerCount = 1; - icpy.dstOffset.x = 0; - icpy.dstOffset.y = 0; - icpy.dstOffset.z = 0; - icpy.extent.width = vid.pixelwidth; - icpy.extent.height = vid.pixelheight; - icpy.extent.depth = 1; - vkCmdCopyImage(fence->cbuf, vk.frame->backbuf->colour.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, tempimage, VK_IMAGE_LAYOUT_GENERAL, 1, &icpy); + { + VkBufferImageCopy icpy; + icpy.bufferOffset = 0; + icpy.bufferRowLength = 0; //packed + icpy.bufferImageHeight = 0; //packed + icpy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + icpy.imageSubresource.mipLevel = 0; + icpy.imageSubresource.baseArrayLayer = 0; + icpy.imageSubresource.layerCount = 1; + icpy.imageOffset.x = 0; + icpy.imageOffset.y = 0; + icpy.imageOffset.z = 0; + icpy.imageExtent.width = ici.extent.width; + icpy.imageExtent.height = ici.extent.height; + icpy.imageExtent.depth = 1; - set_image_layout(fence->cbuf, vk.frame->backbuf->colour.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT); - set_image_layout(fence->cbuf, tempimage, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_HOST_READ_BIT); + vkCmdCopyImageToBuffer(fence->cbuf, tempimage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, tempbuffer, 1, &icpy); + } VK_FencedSync(fence); - outdata = BZ_Malloc(4*vid.pixelwidth*vid.pixelheight); //FIXME: this sucks. - *fmt = PTI_BGRA8; - *bytestride = vid.pixelwidth*4; - *truevidwidth = vid.pixelwidth; - *truevidheight = vid.pixelheight; + outdata = BZ_Malloc(4*ici.extent.width*ici.extent.height); + if (ici.format == VK_FORMAT_B8G8R8_SRGB || ici.format == VK_FORMAT_B8G8R8_UNORM) + *fmt = PTI_BGR8; + else if (ici.format == VK_FORMAT_R8G8B8_SRGB || ici.format == VK_FORMAT_R8G8B8_UNORM) + *fmt = PTI_RGB8; + else if (ici.format == VK_FORMAT_R8G8B8A8_SRGB || ici.format == VK_FORMAT_R8G8B8A8_UNORM) + *fmt = PTI_RGBA8; + else + *fmt = PTI_BGRA8; + *bytestride = ici.extent.width*4; + *truevidwidth = ici.extent.width; + *truevidheight = ici.extent.height; - subres.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - subres.mipLevel = 0; - subres.arrayLayer = 0; - vkGetImageSubresourceLayout(vk.device, tempimage, &subres, &layout); - VkAssert(vkMapMemory(vk.device, tempmemory, 0, mem_reqs.size, 0, &imgdata)); - memcpy(outdata, imgdata, 4*vid.pixelwidth*vid.pixelheight); - vkUnmapMemory(vk.device, tempmemory); + VkAssert(vkMapMemory(vk.device, tempbufmemory, 0, 4*ici.extent.width*ici.extent.height, 0, &imgdata)); + memcpy(outdata, imgdata, 4*ici.extent.width*ici.extent.height); + vkUnmapMemory(vk.device, tempbufmemory); vkDestroyImage(vk.device, tempimage, vkallocationcb); vkFreeMemory(vk.device, tempmemory, vkallocationcb); + vkDestroyBuffer(vk.device, tempbuffer, vkallocationcb); + vkFreeMemory(vk.device, tempbufmemory, vkallocationcb); + return outdata; } return NULL; @@ -2606,7 +2845,7 @@ static void VK_PaintScreen(void) } } -// scr_con_forcedraw = false; + scr_con_forcedraw = false; if (noworld) { extern char levelshotname[]; @@ -2616,8 +2855,8 @@ static void VK_PaintScreen(void) R2D_ScalePic(0, 0, vid.width, vid.height, R2D_SafeCachePic (levelshotname)); else if (scr_con_current != vid.height) R2D_ConsoleBackground(0, vid.height, true); -// else -// scr_con_forcedraw = true; + else + scr_con_forcedraw = true; nohud = true; } @@ -2757,7 +2996,7 @@ qboolean VK_SCR_GrabBackBuffer(void) imgbarrier.pNext = NULL; imgbarrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; imgbarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - imgbarrier.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; //'Alternately, oldLayout can be VK_IMAGE_LAYOUT_UNDEFINED, if the image’s contents need not be preserved.' + imgbarrier.oldLayout = vk.rendertarg->colour.layout; //'Alternately, oldLayout can be VK_IMAGE_LAYOUT_UNDEFINED, if the image’s contents need not be preserved.' imgbarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; imgbarrier.image = vk.frame->backbuf->colour.image; imgbarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; @@ -2774,6 +3013,7 @@ qboolean VK_SCR_GrabBackBuffer(void) imgbarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; vk.frame->backbuf->firstuse = false; } + vk.rendertarg->colour.layout = imgbarrier.newLayout; vkCmdPipelineBarrier(vk.rendertarg->cbuf, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1, &imgbarrier); } { @@ -3012,6 +3252,7 @@ qboolean VK_SCR_UpdateScreen (void) imgbarrier.srcQueueFamilyIndex = vk.queuefam[0]; imgbarrier.dstQueueFamilyIndex = vk.queuefam[1]; vkCmdPipelineBarrier(vk.rendertarg->cbuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, NULL, 0, NULL, 1, &imgbarrier); + vk.rendertarg->colour.layout = imgbarrier.newLayout; } // vkCmdWriteTimestamp(vk.rendertarg->cbuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, querypool, vk.bufferidx*2+1); @@ -3357,32 +3598,37 @@ void VK_CheckTextureFormats(void) unsigned int needextra; } texfmt[] = { - {PTI_RGBA8, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, - {PTI_RGBX8, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, - {PTI_BGRA8, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, - {PTI_BGRX8, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_RGBA8, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_RGBX8, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_BGRA8, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_BGRX8, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, - {PTI_RGBA8_SRGB, VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT|VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, - {PTI_RGBX8_SRGB, VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT|VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, - {PTI_BGRA8_SRGB, VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT|VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, - {PTI_BGRX8_SRGB, VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT|VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, + {PTI_RGB8, VK_FORMAT_R8G8B8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_BGR8, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, - {PTI_RGB565, VK_FORMAT_R5G6B5_UNORM_PACK16, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, - {PTI_RGBA4444, VK_FORMAT_R4G4B4A4_UNORM_PACK16, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, - {PTI_ARGB4444, VK_FORMAT_B4G4R4A4_UNORM_PACK16, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, - {PTI_RGBA5551, VK_FORMAT_R5G5B5A1_UNORM_PACK16, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, - {PTI_ARGB1555, VK_FORMAT_A1R5G5B5_UNORM_PACK16, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, - {PTI_RGBA16F, VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT|VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT|VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT}, - {PTI_RGBA32F, VK_FORMAT_R32G32B32A32_SFLOAT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT|VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT|VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT}, - {PTI_R8, VK_FORMAT_R8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, - {PTI_RG8, VK_FORMAT_R8G8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, - {PTI_R8_SIGNED, VK_FORMAT_R8_SNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, - {PTI_RG8_SIGNED, VK_FORMAT_R8G8_SNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, + {PTI_RGBA8_SRGB, VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT|VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, + {PTI_RGBX8_SRGB, VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT|VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, + {PTI_BGRA8_SRGB, VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT|VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, + {PTI_BGRX8_SRGB, VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT|VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, - {PTI_DEPTH16, VK_FORMAT_D16_UNORM, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT}, - {PTI_DEPTH24, VK_FORMAT_X8_D24_UNORM_PACK32, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT}, - {PTI_DEPTH32, VK_FORMAT_D32_SFLOAT, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT}, - {PTI_DEPTH24_8, VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT}, + {PTI_E5BGR9, VK_FORMAT_E5B9G9R9_UFLOAT_PACK32, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT|VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, + {PTI_A2BGR10, VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT|VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, + {PTI_RGB565, VK_FORMAT_R5G6B5_UNORM_PACK16, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_RGBA4444, VK_FORMAT_R4G4B4A4_UNORM_PACK16, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, +// {PTI_ARGB4444, VK_FORMAT_A4R4G4B4_UNORM_PACK16, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_RGBA5551, VK_FORMAT_R5G5B5A1_UNORM_PACK16, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ARGB1555, VK_FORMAT_A1R5G5B5_UNORM_PACK16, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_RGBA16F, VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT|VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT|VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT}, + {PTI_RGBA32F, VK_FORMAT_R32G32B32A32_SFLOAT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT|VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT|VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT}, + {PTI_R8, VK_FORMAT_R8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, + {PTI_RG8, VK_FORMAT_R8G8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, + {PTI_R8_SNORM, VK_FORMAT_R8_SNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, + {PTI_RG8_SNORM, VK_FORMAT_R8G8_SNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, + + {PTI_DEPTH16, VK_FORMAT_D16_UNORM, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT}, + {PTI_DEPTH24, VK_FORMAT_X8_D24_UNORM_PACK32, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT}, + {PTI_DEPTH32, VK_FORMAT_D32_SFLOAT, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT}, + {PTI_DEPTH24_8, VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT}, {PTI_BC1_RGB, VK_FORMAT_BC1_RGB_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, {PTI_BC1_RGBA, VK_FORMAT_BC1_RGBA_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, @@ -3393,11 +3639,11 @@ void VK_CheckTextureFormats(void) {PTI_BC2_RGBA_SRGB, VK_FORMAT_BC2_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, {PTI_BC3_RGBA_SRGB, VK_FORMAT_BC3_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, {PTI_BC4_R8, VK_FORMAT_BC4_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, - {PTI_BC4_R8_SIGNED, VK_FORMAT_BC4_SNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_BC4_R8_SNORM, VK_FORMAT_BC4_SNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, {PTI_BC5_RG8, VK_FORMAT_BC5_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, - {PTI_BC5_RG8_SIGNED, VK_FORMAT_BC5_SNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, - {PTI_BC6_RGBF, VK_FORMAT_BC6H_UFLOAT_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, - {PTI_BC6_RGBF_SIGNED, VK_FORMAT_BC6H_SFLOAT_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_BC5_RG8_SNORM, VK_FORMAT_BC5_SNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_BC6_RGB_UFLOAT, VK_FORMAT_BC6H_UFLOAT_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_BC6_RGB_SFLOAT, VK_FORMAT_BC6H_SFLOAT_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, {PTI_BC7_RGBA, VK_FORMAT_BC7_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, {PTI_BC7_RGBA_SRGB, VK_FORMAT_BC7_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, {PTI_ETC1_RGB8, VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, //vulkan doesn't support etc1 (but that's okay, because etc2 is a superset). @@ -3408,9 +3654,9 @@ void VK_CheckTextureFormats(void) {PTI_ETC2_RGB8A1_SRGB, VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, {PTI_ETC2_RGB8A8_SRGB, VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, {PTI_EAC_R11, VK_FORMAT_EAC_R11_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, - {PTI_EAC_R11_SIGNED, VK_FORMAT_EAC_R11_SNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_EAC_R11_SNORM, VK_FORMAT_EAC_R11_SNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, {PTI_EAC_RG11, VK_FORMAT_EAC_R11G11_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, - {PTI_EAC_RG11_SIGNED, VK_FORMAT_EAC_R11G11_SNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_EAC_RG11_SNORM, VK_FORMAT_EAC_R11G11_SNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, {PTI_ASTC_4X4, VK_FORMAT_ASTC_4x4_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, {PTI_ASTC_4X4_SRGB, VK_FORMAT_ASTC_4x4_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, {PTI_ASTC_5X4, VK_FORMAT_ASTC_5x4_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, @@ -4032,6 +4278,8 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre } #endif } + if (info->srgb != 1 && (vid.flags & VID_SRGB_FB)) + vid.flags |= VID_SRGBAWARE; return true; } void VK_Shutdown(void) diff --git a/engine/vk/vkrenderer.h b/engine/vk/vkrenderer.h index 4f361e4b..bf35e9ed 100644 --- a/engine/vk/vkrenderer.h +++ b/engine/vk/vkrenderer.h @@ -447,7 +447,7 @@ struct stagingbuf size_t size; VkBufferUsageFlags usage; }; -vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t layers, uint32_t mips, unsigned int encoding, unsigned int type, qboolean rendertarget); +vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t layers, uint32_t mips, uploadfmt_t encoding, unsigned int type, qboolean rendertarget); void set_image_layout(VkCommandBuffer cmd, VkImage image, VkImageAspectFlags aspectMask, VkImageLayout old_image_layout, VkAccessFlags srcaccess, VkImageLayout new_image_layout, VkAccessFlags dstaccess); void VK_CreateSampler(unsigned int flags, vk_image_t *img); void *VKBE_CreateStagingBuffer(struct stagingbuf *n, size_t size, VkBufferUsageFlags usage); diff --git a/engine/web/gl_vidweb.c b/engine/web/gl_vidweb.c index 64f78118..e33ea2ac 100644 --- a/engine/web/gl_vidweb.c +++ b/engine/web/gl_vidweb.c @@ -360,7 +360,7 @@ void INS_Shutdown (void) void INS_ReInit (void) { } -void INS_Move(float *movements, int pnum) +void INS_Move(void) { } void INS_Init (void) diff --git a/plugins/plugin.c b/plugins/plugin.c index da7dfa2b..2e87cc48 100644 --- a/plugins/plugin.c +++ b/plugins/plugin.c @@ -9,25 +9,24 @@ typedef struct } exports_t; extern exports_t exports[16]; -qintptr_t NATIVEEXPORT vmMain( qintptr_t command, qintptr_t arg0, qintptr_t arg1, qintptr_t arg2, qintptr_t arg3, qintptr_t arg4, qintptr_t arg5, qintptr_t arg6, qintptr_t arg7, qintptr_t arg8, qintptr_t arg9, qintptr_t arg10, qintptr_t arg11 ) +qintptr_t NATIVEEXPORT vmMain( qintptr_t command, qintptr_t arg0, qintptr_t arg1, qintptr_t arg2, qintptr_t arg3, qintptr_t arg4, qintptr_t arg5, qintptr_t arg6, qintptr_t arg7/*, qintptr_t arg8, qintptr_t arg9, qintptr_t arg10, qintptr_t arg11*/) { - qintptr_t ret; - qintptr_t args[12]; - args[0] = arg0; - args[1] = arg1; - args[2] = arg2; - args[3] = arg3; - args[4] = arg4; - args[5] = arg5; - args[6] = arg6; - args[7] = arg7; - args[8] = arg8; - args[9] = arg9; - args[10] = arg10; - args[11] = arg11; -// return exports[command].func(args); - ret = exports[command].func(args); - return ret; + qintptr_t args[] = + { + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, +// arg8, +// arg9, +// arg10, +// arg11, + }; + return exports[command].func(args); } @@ -42,7 +41,7 @@ BUILTINR(funcptr_t, Plug_GetEngineFunction, (const char *funcname)); #undef ARGNAMES #define ARGNAMES ,funcname,expnum -BUILTINR(int, Plug_ExportToEngine, (const char *funcname, int expnum)); +BUILTINR(int, Plug_ExportToEngine, (const char *funcname, quintptr_t expnum)); #undef ARGNAMES #ifndef Q3_VM @@ -60,7 +59,7 @@ BUILTIN(void, Con_Print, (const char *text)); //on to main console. #undef ARGNAMES #define ARGNAMES ,conname,flags -BUILTINR(qhandle_t, Con_POpen, (const char *conname, unsigned int flags)); +BUILTINR(qhandle_t, Con_POpen, (const char *conname, quintptr_t flags)); #undef ARGNAMES #define ARGNAMES ,conname,text BUILTIN(void, Con_SubPrint, (const char *conname, const char *text)); //on to named sub console (creating it too). @@ -78,7 +77,7 @@ BUILTIN(void, Con_SetActive, (const char *conname)); BUILTIN(void, Con_Destroy, (const char *conname)); #undef ARGNAMES #define ARGNAMES ,connum,conname,connamelen -BUILTIN(void, Con_NameForNum, (int connum, char *conname, int connamelen)); +BUILTIN(void, Con_NameForNum, (qintptr_t connum, char *conname, quintptr_t connamelen)); #undef ARGNAMES #define ARGNAMES ,conname,attribname BUILTINR(float, Con_GetConsoleFloat, (const char *conname, const char *attribname)); @@ -87,7 +86,7 @@ BUILTINR(float, Con_GetConsoleFloat, (const char *conname, const char *attribnam BUILTIN(void, Con_SetConsoleFloat, (const char *conname, const char *attribname, float newvalue)); #undef ARGNAMES #define ARGNAMES ,conname,attribname,value,valuesize -BUILTINR(int, Con_GetConsoleString, (const char *conname, const char *attribname, const char *value, unsigned int valuesize)); +BUILTINR(int, Con_GetConsoleString, (const char *conname, const char *attribname, const char *value, quintptr_t valuesize)); #undef ARGNAMES #define ARGNAMES ,conname,attribname,newvalue BUILTIN(void, Con_SetConsoleString, (const char *conname, const char *attribname, const char *newvalue)); @@ -97,7 +96,7 @@ BUILTIN(void, Con_SetConsoleString, (const char *conname, const char *attribname BUILTIN(void, Sys_Error, (const char *message)); //abort the entire engine. #undef ARGNAMES #define ARGNAMES -BUILTINR(unsigned int, Sys_Milliseconds, (void)); //get the time the engine has been running. +BUILTINR(quintptr_t, Sys_Milliseconds, (void)); //get the time the engine has been running. #undef ARGNAMES #define ARGNAMES ,buffer @@ -127,7 +126,7 @@ BUILTIN(void, Cvar_SetString, (const char *name, const char *value)); //set a cv BUILTIN(void, Cvar_SetFloat, (const char *name, float value)); //set a cvar float #undef ARGNAMES #define ARGNAMES ,name,retstring,sizeofretstring -BUILTINR(qboolean, Cvar_GetString, (const char *name, char *retstring, int sizeofretstring)); //retrieve a cvar string +BUILTINR(qboolean, Cvar_GetString, (const char *name, char *retstring, quintptr_t sizeofretstring)); //retrieve a cvar string #undef ARGNAMES #define ARGNAMES ,name BUILTINR(float, Cvar_GetFloat, (const char *name)); //get a cvar's value diff --git a/plugins/plugin.h b/plugins/plugin.h index c6f7c939..f451bc15 100644 --- a/plugins/plugin.h +++ b/plugins/plugin.h @@ -199,20 +199,20 @@ EBUILTIN(void *, Plug_GetNativePointer, (const char *funcname)); #endif EBUILTIN(void, Con_Print, (const char *text)); //on to main console. -EBUILTIN(qhandle_t, Con_POpen, (const char *conname, unsigned int flags)); +EBUILTIN(qhandle_t, Con_POpen, (const char *conname, quintptr_t flags)); EBUILTIN(void, Con_SubPrint, (const char *subname, const char *text)); //on to sub console. EBUILTIN(void, Con_RenameSub, (const char *oldname, const char *newname)); //rename a console. EBUILTIN(int, Con_IsActive, (const char *conname)); EBUILTIN(void, Con_SetActive, (const char *conname)); EBUILTIN(void, Con_Destroy, (const char *conname)); -EBUILTIN(void, Con_NameForNum, (int connum, char *conname, int connamelen)); +EBUILTIN(void, Con_NameForNum, (qintptr_t connum, char *conname, quintptr_t connamelen)); EBUILTIN(float, Con_GetConsoleFloat, (const char *conname, const char *attribname)); EBUILTIN(void, Con_SetConsoleFloat, (const char *conname, const char *attribname, float newvalue)); -EBUILTIN(int, Con_GetConsoleString, (const char *conname, const char *attribname, const char *value, unsigned int valuesize)); +EBUILTIN(int, Con_GetConsoleString, (const char *conname, const char *attribname, const char *value, quintptr_t valuesize)); EBUILTIN(void, Con_SetConsoleString, (const char *conname, const char *attribname, const char *newvalue)); EBUILTIN(void, Sys_Error, (const char *message)); //abort the entire engine. -EBUILTIN(unsigned int, Sys_Milliseconds, ()); +EBUILTIN(quintptr_t, Sys_Milliseconds, ()); EBUILTIN(int, Cmd_AddCommand, (const char *buffer)); //abort the entire engine. EBUILTIN(void, Cmd_Args, (char *buffer, int bufsize)); //abort the entire engine. @@ -223,7 +223,7 @@ EBUILTIN(void, Cmd_Tokenize, (const char *msg)); //abort the entire engine. EBUILTIN(void, Cvar_SetString, (const char *name, const char *value)); EBUILTIN(void, Cvar_SetFloat, (const char *name, float value)); -EBUILTIN(qboolean, Cvar_GetString, (const char *name, char *retstring, int sizeofretstring)); +EBUILTIN(qboolean, Cvar_GetString, (const char *name, char *retstring, quintptr_t sizeofretstring)); EBUILTIN(float, Cvar_GetFloat, (const char *name)); EBUILTIN(qhandle_t, Cvar_Register, (const char *name, const char *defaultval, int flags, const char *grouphint)); EBUILTIN(int, Cvar_Update, (qhandle_t handle, int *modificationcount, char *stringv, float *floatv)); //stringv is 256 chars long, don't expect this function to do anything if modification count is unchanged.