mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-24 21:02:26 +00:00
Support connecting subnodes to servers over tcp (instead of depending on fork).
Fixed up the -netquake / -spasm / -fitz args slightly, should actually be usable now. sv_mintic 0 is now treated as 0.013 when using nqplayerphysics, to try to make it smoother for nq clients. Preparing for astc's volume formats. Mostly for completeness, I was bored. Disabled for now because nothing supports them anyway. Fix broken mousewheel in SDL2 builds. Fix configs not getting loaded following initial downloads in the web port/etc. Make the near-cloud layer of q1 scrolling sky fully opaque by default (like vanilla). Sky fog now ignores depth, treating it as an infinite distance. Fix turbs not responding to fog. r_fullbright no longer needs vid_reload to take effect (and more efficient now). Tweaked the audio code to use an format enum instead of byte width, just with the same values still, primarily to clean up loaders that deal with S32 vs F32, or U8 vs S8. Added a cvar to control whether to use threads for the qcgc. Still disabled by default but no longer requires engine recompiles to enable! git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5683 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
7e66608b36
commit
4c2066601a
74 changed files with 2355 additions and 1294 deletions
|
@ -299,7 +299,7 @@ ELSEIF(${UNIX}) #linux(ish)
|
|||
NAMES ossaudio
|
||||
)
|
||||
IF(OSSAUDIO_LIBRARY)
|
||||
SET(FTE_LIBS ${FTE_LIBS} ${OSSAUDIO_LIBRARY})
|
||||
SET(FTE_LIBS ${FTE_LIBS} ${OSSAUDIO_LIBRARY})
|
||||
ENDIF()
|
||||
|
||||
#on linux, use wayland.
|
||||
|
@ -307,13 +307,21 @@ ELSEIF(${UNIX}) #linux(ish)
|
|||
WAYLAND_CLIENT_LIBRARY
|
||||
NAMES wayland-client libwayland-client
|
||||
)
|
||||
FIND_LIBRARY(
|
||||
HAVE_XKBCOMMON
|
||||
NAMES xkbcommon
|
||||
)
|
||||
IF(NOT HAVE_XKBCOMMON)
|
||||
MESSAGE(WARNING "xkbcommon library not found, needed for wayland to be usable.")
|
||||
UNSET(WAYLAND_CLIENT_LIBRARY)
|
||||
ENDIF()
|
||||
IF(WAYLAND_CLIENT_LIBRARY)
|
||||
SET(FTE_DEFINES ${FTE_DEFINES};WAYLANDQUAKE;USE_EGL)
|
||||
SET(FTE_ARCH_FILES ${FTE_ARCH_FILES}
|
||||
engine/gl/gl_vidwayland.c
|
||||
)
|
||||
ELSE()
|
||||
MESSAGE(WARNING "Wayland library NOT available")
|
||||
MESSAGE(WARNING "Wayland library NOT available. X11 will live forever anyway.")
|
||||
IF(NOT X11_FOUND)
|
||||
MESSAGE(WARNING "No renderers supported!")
|
||||
SET(FTE_NO_RENDERERS 1)
|
||||
|
|
|
@ -3012,23 +3012,9 @@ void CL_QTVPlay_f (void)
|
|||
connrequest = strchrrev(connrequest, '@');
|
||||
if (connrequest)
|
||||
host = connrequest+1;
|
||||
#ifdef HAVE_SSL
|
||||
if (!strncmp(host, "tls://", 6))
|
||||
{
|
||||
char *colon;
|
||||
Q_strncpyz(qtvhostname, host+6, sizeof(qtvhostname));
|
||||
colon = strchr(qtvhostname, ':');
|
||||
newf = FS_OpenTCP(qtvhostname, 27599);
|
||||
if (colon) *colon = 0;
|
||||
newf = FS_OpenSSL(qtvhostname, newf, false);
|
||||
if (colon) *colon = ':';
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Q_strncpyz(qtvhostname, host, sizeof(qtvhostname));
|
||||
newf = FS_OpenTCP(qtvhostname, 27599);
|
||||
}
|
||||
Q_strncpyz(qtvhostname, host, sizeof(qtvhostname));
|
||||
newf = FS_OpenTCP(qtvhostname, 27599, false);
|
||||
|
||||
|
||||
if (!newf)
|
||||
{
|
||||
|
@ -3142,7 +3128,7 @@ void CL_QTVList_f (void)
|
|||
{
|
||||
char *connrequest;
|
||||
vfsfile_t *newf;
|
||||
newf = FS_OpenTCP(qtvhostname, 27599);
|
||||
newf = FS_OpenTCP(qtvhostname, 27599, false);
|
||||
|
||||
if (!newf)
|
||||
{
|
||||
|
@ -3176,7 +3162,7 @@ void CL_QTVDemos_f (void)
|
|||
{
|
||||
char *connrequest;
|
||||
vfsfile_t *newf;
|
||||
newf = FS_OpenTCP(Cmd_Argv(1), 27599);
|
||||
newf = FS_OpenTCP(Cmd_Argv(1), 27599, false);
|
||||
|
||||
if (!newf)
|
||||
{
|
||||
|
|
|
@ -3828,7 +3828,7 @@ void CL_TransitionEntities (void)
|
|||
frac = (servertime-packold->servertime)/(packnew->servertime-packold->servertime);
|
||||
|
||||
// if (!cl.paused)
|
||||
// Con_Printf("%f %f %f (%f) (%i) %f %f %f\n", packold->servertime, servertime, packnew->servertime, frac, newff, cl.oldgametime, servertime, cl.gametime);
|
||||
// Con_DPrintf("%f %s%f^7 %f (%f) (%i) %f %s%f^7 %f\n", packold->servertime, (servertime<packold->servertime||packnew->servertime<servertime)?"^1":"",servertime, packnew->servertime, frac, newff, cl.oldgametime, (servertime<cl.oldgametime||cl.gametime<servertime)?"^3":"", servertime, cl.gametime);
|
||||
|
||||
CL_TransitionPacketEntities(newff, packnew, packold, frac, servertime);
|
||||
|
||||
|
|
|
@ -894,7 +894,7 @@ void CL_CheckForResend (void)
|
|||
connectinfo.subprotocol = CPNQ_DP7;
|
||||
}
|
||||
else if (!strcmp(lbp, "qss") ||
|
||||
(progstype != PROG_QW && progstype != PROG_H2)) //h2 depends on various extensions and doesn't really match either protocol, but we go for qw because that gives us all sorts of extensions.
|
||||
(progstype != PROG_QW && progstype != PROG_H2 && sv.state!=ss_clustermode)) //h2 depends on various extensions and doesn't really match either protocol, but we go for qw because that gives us all sorts of extensions.
|
||||
{
|
||||
connectinfo.protocol = CP_NETQUAKE;
|
||||
connectinfo.subprotocol = CPNQ_FITZ666;
|
||||
|
@ -5545,6 +5545,7 @@ done:
|
|||
man->updateurl = Z_StrDup(f->fname);
|
||||
// if (f->flags & HRF_DOWNLOADED)
|
||||
man->blockupdate = true;
|
||||
//man->security = MANIFEST_SECURITY_DEFAULT;
|
||||
BZ_Free(fdata);
|
||||
FS_ChangeGame(man, true, true);
|
||||
}
|
||||
|
@ -6386,18 +6387,18 @@ void CL_StartCinematicOrMenu(void)
|
|||
|
||||
if (!sv_state && !cls.demoinfile && !cls.state && !*cls.servername)
|
||||
{
|
||||
if (qrenderer > QR_NONE && !Key_Dest_Has(kdm_menu))
|
||||
if (qrenderer > QR_NONE && !Key_Dest_Has(~kdm_game))
|
||||
{
|
||||
#ifndef NOBUILTINMENUS
|
||||
if (!cls.state && !Key_Dest_Has(kdm_menu) && !*FS_GetGamedir(false))
|
||||
if (!cls.state && !Key_Dest_Has(~kdm_game) && !*FS_GetGamedir(false))
|
||||
M_Menu_Mods_f();
|
||||
#endif
|
||||
if (!cls.state && !Key_Dest_Has(kdm_menu) && cl_demoreel.ival)
|
||||
if (!cls.state && !Key_Dest_Has(~kdm_game) && cl_demoreel.ival)
|
||||
{
|
||||
cls.demonum = 0;
|
||||
CL_NextDemo();
|
||||
}
|
||||
if (!cls.state && !Key_Dest_Has(kdm_menu))
|
||||
if (!cls.state && !Key_Dest_Has(~kdm_game))
|
||||
//if we're (now) meant to be using csqc for menus, make sure that its running.
|
||||
if (!CSQC_UnconnectedInit())
|
||||
M_ToggleMenu_f();
|
||||
|
|
|
@ -5671,19 +5671,23 @@ static void CL_SetStatString (int pnum, int stat, char *value)
|
|||
|
||||
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
|
||||
{
|
||||
/* extern int cls_lastto;
|
||||
cl.players[cls_lastto].statsstr[stat]=value;
|
||||
extern int cls_lastto;
|
||||
//Z_Free(cl.players[cls_lastto].statsstr[stat]);
|
||||
//cl.players[cls_lastto].statsstr[stat]=Z_StrDup(value);
|
||||
|
||||
for (pnum = 0; pnum < cl.splitclients; pnum++)
|
||||
if (spec_track[pnum] == cls_lastto)
|
||||
cl.statsstr[pnum][stat] = value;*/
|
||||
if (cl.playerview[pnum].cam_spec_track == cls_lastto && cl.playerview[pnum].cam_state != CAM_FREECAM)
|
||||
{
|
||||
if (cl.playerview[pnum].statsstr[stat])
|
||||
Z_Free(cl.playerview[pnum].statsstr[stat]);
|
||||
cl.playerview[pnum].statsstr[stat] = Z_StrDup(value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cl.playerview[pnum].statsstr[stat])
|
||||
Z_Free(cl.playerview[pnum].statsstr[stat]);
|
||||
cl.playerview[pnum].statsstr[stat] = Z_Malloc(strlen(value)+1);
|
||||
strcpy(cl.playerview[pnum].statsstr[stat], value);
|
||||
cl.playerview[pnum].statsstr[stat] = Z_StrDup(value);
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
|
|
@ -621,11 +621,12 @@ void CL_CalcClientTime(void)
|
|||
extern float olddemotime;
|
||||
cl.servertime = olddemotime;
|
||||
}
|
||||
//q2 has no drifting.
|
||||
//q3 always drifts.
|
||||
//nq+qw code can drift
|
||||
//q2 has no drifting (our code can't cope with picking anything beyond old/new snapshots, and frankly its 10fps which is horrendous enough as it is).
|
||||
//q3 always drifts (gamecode does snapshot selection).
|
||||
//qw code can drift (but oh noes! my latency!)
|
||||
//FIXME: nq code should be able to drift, but is apparently buggy somewhere and ends up uncomfortably stuttery right now.
|
||||
//default is to drift in demos+SP but not live (oh noes! added latency!)
|
||||
if (cls.protocol == CP_QUAKE2 || (cls.protocol != CP_QUAKE3 && (!cl_lerp_smooth.ival || (cl_lerp_smooth.ival == 2 && !(cls.demoplayback || cl.allocated_client_slots == 1 || cl.playerview[0].spectator))) && cls.demoplayback != DPB_MVD))
|
||||
if (cls.protocol == CP_QUAKE2 || cls.protocol==CP_NETQUAKE/*FIXME*/ || (cls.protocol != CP_QUAKE3 && (!cl_lerp_smooth.ival || (cl_lerp_smooth.ival == 2 && !(cls.demoplayback || cl.allocated_client_slots == 1 || cl.playerview[0].spectator))) && cls.demoplayback != DPB_MVD))
|
||||
{ //no drift logic
|
||||
float f;
|
||||
f = cl.gametime - cl.oldgametime;
|
||||
|
@ -671,6 +672,8 @@ void CL_CalcClientTime(void)
|
|||
else
|
||||
{
|
||||
cl.servertime -= 0.02*(max - cl.servertime);
|
||||
if (cl.servertime < cl.time)
|
||||
cl.servertime = cl.time;
|
||||
}
|
||||
}
|
||||
if (cl.servertime < min)
|
||||
|
|
|
@ -661,6 +661,7 @@ int SCR_DrawCenterString (vrect_t *rect, cprint_t *p, struct font_s *font)
|
|||
int remaining;
|
||||
shader_t *pic;
|
||||
int ch;
|
||||
int mousex,mousey;
|
||||
|
||||
conchar_t *line_start[MAX_CPRINT_LINES];
|
||||
conchar_t *line_end[MAX_CPRINT_LINES];
|
||||
|
@ -726,6 +727,7 @@ int SCR_DrawCenterString (vrect_t *rect, cprint_t *p, struct font_s *font)
|
|||
}
|
||||
}
|
||||
|
||||
Font_BeginString(font, mousecursor_x, mousecursor_y, &mousex, &mousey);
|
||||
Font_BeginString(font, rect->x, y, &left, &top);
|
||||
Font_BeginString(font, rect->x+rect->width, rect->y+rect->height, &right, &bottom);
|
||||
linecount = Font_LineBreaks(p->string, p->string + p->charcount, (p->flags & CPRINT_NOWRAP)?0x7fffffff:(right - left), MAX_CPRINT_LINES, line_start, line_end);
|
||||
|
@ -776,9 +778,9 @@ int SCR_DrawCenterString (vrect_t *rect, cprint_t *p, struct font_s *font)
|
|||
else
|
||||
x = left + (right - left - Font_LineWidth(line_start[l], line_end[l]))/2;
|
||||
|
||||
if (mousecursor_y >= y && mousecursor_y < y+ch)
|
||||
if (mousey >= y && mousey < y+ch)
|
||||
{
|
||||
p->cursorchar = Font_CharAt(mousecursor_x - x, line_start[l], line_end[l]);
|
||||
p->cursorchar = Font_CharAt(mousex - x, line_start[l], line_end[l]);
|
||||
}
|
||||
|
||||
remaining -= line_end[l]-line_start[l];
|
||||
|
@ -2869,7 +2871,7 @@ void SCR_ScreenShot_Cubemap_f(void)
|
|||
{{-90, 0, 0}, "_up"}
|
||||
};
|
||||
const char *ext;
|
||||
unsigned int bb, bw, bh;
|
||||
unsigned int bb, bw, bh, bd;
|
||||
|
||||
if (!cls.state || !cl.worldmodel || cl.worldmodel->loadstate != MLS_LOADED)
|
||||
{
|
||||
|
@ -2917,8 +2919,8 @@ void SCR_ScreenShot_Cubemap_f(void)
|
|||
break;
|
||||
if (!bb)
|
||||
{
|
||||
Image_BlockSizeForEncoding(fmt, &bb, &bw, &bh);
|
||||
if (!bb || bw != 1 || bh != 1 || fbwidth != fbheight)
|
||||
Image_BlockSizeForEncoding(fmt, &bb, &bw, &bh, &bd);
|
||||
if (!bb || bw != 1 || bh != 1 || bd != 1 || fbwidth != fbheight)
|
||||
{ //erk, no block compression here...
|
||||
BZ_Free(facedata);
|
||||
break; //zomgwtfbbq
|
||||
|
@ -2999,7 +3001,7 @@ void SCR_ScreenShot_Cubemap_f(void)
|
|||
buffer = SCR_ScreenShot_Capture(fbwidth, fbheight, &stride, &fmt, true, false);
|
||||
if (buffer)
|
||||
{
|
||||
Image_BlockSizeForEncoding(fmt, &bb, &bw, &bh);
|
||||
Image_BlockSizeForEncoding(fmt, &bb, &bw, &bh, &bd);
|
||||
if (sides[i].horizontalflip)
|
||||
{
|
||||
int y, x, p;
|
||||
|
|
|
@ -206,6 +206,9 @@ static image_t *imagelist;
|
|||
|
||||
#ifdef DECOMPRESS_ASTC
|
||||
#define ASTC_PUBLIC
|
||||
#ifdef ASTC3D
|
||||
#define ASTC_WITH_3D
|
||||
#endif
|
||||
#include "image_astc.h"
|
||||
#endif
|
||||
|
||||
|
@ -1707,7 +1710,7 @@ int Image_WritePNG (const char *filename, enum fs_relative fsroot, int compressi
|
|||
qbyte stereochunk = 0; //cross-eyed
|
||||
png_unknown_chunk unknowns = {"sTER", &stereochunk, sizeof(stereochunk), PNG_HAVE_PLTE};
|
||||
|
||||
int bw,bh,chanbits;
|
||||
int bw,bh,bd,chanbits;
|
||||
qboolean havepad, bgr;
|
||||
int colourtype;
|
||||
|
||||
|
@ -1776,7 +1779,7 @@ int Image_WritePNG (const char *filename, enum fs_relative fsroot, int compressi
|
|||
default:
|
||||
return false;
|
||||
}
|
||||
Image_BlockSizeForEncoding(fmt, &pxsize, &bw, &bh);
|
||||
Image_BlockSizeForEncoding(fmt, &pxsize, &bw, &bh, &bd);
|
||||
|
||||
if (!FS_NativePath(filename, fsroot, name, sizeof(name)))
|
||||
return false;
|
||||
|
@ -4311,7 +4314,7 @@ static qbyte *ReadXCFFile(const qbyte *filedata, size_t len, const char *fname,
|
|||
{
|
||||
size_t offs;
|
||||
struct xcf_s ctx;
|
||||
unsigned int bb,bw,bh;
|
||||
unsigned int bb,bw,bh,bd;
|
||||
if (len < 14 || strncmp(filedata, "gimp xcf ", 9) || filedata[13])
|
||||
return NULL;
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
|
@ -4361,7 +4364,7 @@ static qbyte *ReadXCFFile(const qbyte *filedata, size_t len, const char *fname,
|
|||
//channels
|
||||
|
||||
//without any layers, its fully transparent
|
||||
Image_BlockSizeForEncoding(ctx.outformat, &bb,&bw,&bh); //just for the bb...
|
||||
Image_BlockSizeForEncoding(ctx.outformat, &bb,&bw,&bh,&bd); //just for the bb...
|
||||
ctx.flat = Z_Malloc(ctx.width*ctx.height*bb);
|
||||
*format = ctx.outformat;
|
||||
*width = ctx.width;
|
||||
|
@ -4752,7 +4755,7 @@ typedef struct
|
|||
} ktxheader_t;
|
||||
qboolean Image_WriteKTXFile(const char *filename, enum fs_relative fsroot, struct pendingtextureinfo *mips)
|
||||
{
|
||||
unsigned int bb,bw,bh;
|
||||
unsigned int bb,bw,bh,bd;
|
||||
vfsfile_t *file;
|
||||
ktxheader_t header = {{0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A}, 0x04030201/*endianness*/,
|
||||
0/*type*/, 1/*typesize*/, 0/*format*/, 0/*internalformat*/,
|
||||
|
@ -4798,7 +4801,7 @@ qboolean Image_WriteKTXFile(const char *filename, enum fs_relative fsroot, struc
|
|||
return false;
|
||||
}
|
||||
|
||||
Image_BlockSizeForEncoding(mips->encoding, &bb, &bw, &bh);
|
||||
Image_BlockSizeForEncoding(mips->encoding, &bb, &bw, &bh, &bd);
|
||||
|
||||
switch(mips->encoding)
|
||||
{
|
||||
|
@ -4871,6 +4874,39 @@ qboolean Image_WriteKTXFile(const char *filename, enum fs_relative fsroot, struc
|
|||
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;
|
||||
#ifdef ASTC3D
|
||||
case PTI_ASTC_3X3X3_HDR:
|
||||
case PTI_ASTC_3X3X3_LDR: header.glinternalformat = 0x93C0/*GL_COMPRESSED_RGBA_ASTC_3x3x3_OES*/; break;
|
||||
case PTI_ASTC_4X3X3_HDR:
|
||||
case PTI_ASTC_4X3X3_LDR: header.glinternalformat = 0x93C1/*GL_COMPRESSED_RGBA_ASTC_4x3x3_OES*/; break;
|
||||
case PTI_ASTC_4X4X3_HDR:
|
||||
case PTI_ASTC_4X4X3_LDR: header.glinternalformat = 0x93C2/*GL_COMPRESSED_RGBA_ASTC_4x4x3_OES*/; break;
|
||||
case PTI_ASTC_4X4X4_HDR:
|
||||
case PTI_ASTC_4X4X4_LDR: header.glinternalformat = 0x93C3/*GL_COMPRESSED_RGBA_ASTC_4x4x5_OES*/; break;
|
||||
case PTI_ASTC_5X4X4_HDR:
|
||||
case PTI_ASTC_5X4X4_LDR: header.glinternalformat = 0x93C4/*GL_COMPRESSED_RGBA_ASTC_5x4x4_OES*/; break;
|
||||
case PTI_ASTC_5X5X4_HDR:
|
||||
case PTI_ASTC_5X5X4_LDR: header.glinternalformat = 0x93C5/*GL_COMPRESSED_RGBA_ASTC_5x5x4_OES*/; break;
|
||||
case PTI_ASTC_5X5X5_HDR:
|
||||
case PTI_ASTC_5X5X5_LDR: header.glinternalformat = 0x93C6/*GL_COMPRESSED_RGBA_ASTC_5x5x5_OES*/; break;
|
||||
case PTI_ASTC_6X5X5_HDR:
|
||||
case PTI_ASTC_6X5X5_LDR: header.glinternalformat = 0x93C7/*GL_COMPRESSED_RGBA_ASTC_6x5x5_OES*/; break;
|
||||
case PTI_ASTC_6X6X5_HDR:
|
||||
case PTI_ASTC_6X6X5_LDR: header.glinternalformat = 0x93C8/*GL_COMPRESSED_RGBA_ASTC_6x6x5_OES*/; break;
|
||||
case PTI_ASTC_6X6X6_HDR:
|
||||
case PTI_ASTC_6X6X6_LDR: header.glinternalformat = 0x93C9/*GL_COMPRESSED_RGBA_ASTC_6x6x6_OES*/; break;
|
||||
case PTI_ASTC_3X3X3_SRGB: header.glinternalformat = 0x93E0/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES*/; break;
|
||||
case PTI_ASTC_4X3X3_SRGB: header.glinternalformat = 0x93E1/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES*/; break;
|
||||
case PTI_ASTC_4X4X3_SRGB: header.glinternalformat = 0x93E2/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES*/; break;
|
||||
case PTI_ASTC_4X4X4_SRGB: header.glinternalformat = 0x93E3/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES*/; break;
|
||||
case PTI_ASTC_5X4X4_SRGB: header.glinternalformat = 0x93E4/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES*/; break;
|
||||
case PTI_ASTC_5X5X4_SRGB: header.glinternalformat = 0x93E5/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES*/; break;
|
||||
case PTI_ASTC_5X5X5_SRGB: header.glinternalformat = 0x93E6/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES*/; break;
|
||||
case PTI_ASTC_6X5X5_SRGB: header.glinternalformat = 0x93E7/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES*/; break;
|
||||
case PTI_ASTC_6X6X5_SRGB: header.glinternalformat = 0x93E8/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES*/; break;
|
||||
case PTI_ASTC_6X6X6_SRGB: header.glinternalformat = 0x93E9/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES*/; break;
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
@ -4938,7 +4974,7 @@ qboolean Image_WriteKTXFile(const char *filename, enum fs_relative fsroot, struc
|
|||
unsigned int browbytes = bb * ((mips->mip[mipnum].width+bw-1)/bh);
|
||||
unsigned int padbytes = (browbytes&3)?4-(browbytes&3):0;
|
||||
unsigned int brows = (mips->mip[mipnum].height+bh-1)/bh;
|
||||
unsigned int blayers = (mips->mip[mipnum].depth+1-1)/1;
|
||||
unsigned int blayers = (mips->mip[mipnum].depth+bd-1)/bd;
|
||||
if (mips->mip[mipnum].datasize != browbytes*brows*blayers)
|
||||
{ //should probably be a sys_error
|
||||
Con_Printf("WriteKTX mip %u missized\n", (unsigned)mipnum);
|
||||
|
@ -4994,7 +5030,7 @@ static struct pendingtextureinfo *Image_ReadKTXFile(unsigned int flags, const ch
|
|||
int encoding = TF_INVALID;
|
||||
const qbyte *fileend = filedata + filesize;
|
||||
|
||||
unsigned int blockwidth, blockheight, blockbytes;
|
||||
unsigned int blockwidth, blockheight, blockdepth, blockbytes;
|
||||
|
||||
if (filesize < sizeof(ktxheader_t) || memcmp(filedata, magic, sizeof(magic)))
|
||||
return NULL; //not a ktx file
|
||||
|
@ -5204,7 +5240,7 @@ static struct pendingtextureinfo *Image_ReadKTXFile(unsigned int flags, const ch
|
|||
if (nummips * header.numberoffaces > countof(mips->mip))
|
||||
nummips = countof(mips->mip) / header.numberoffaces;
|
||||
|
||||
Image_BlockSizeForEncoding(encoding, &blockbytes, &blockwidth, &blockheight);
|
||||
Image_BlockSizeForEncoding(encoding, &blockbytes, &blockwidth, &blockheight, &blockdepth);
|
||||
|
||||
w = header.pixelwidth;
|
||||
h = max(1, header.pixelheight);
|
||||
|
@ -5222,7 +5258,8 @@ static struct pendingtextureinfo *Image_ReadKTXFile(unsigned int flags, const ch
|
|||
|
||||
browbytes = blockbytes * ((w+blockwidth-1)/blockwidth);
|
||||
padbytes = (browbytes & 3)?4-(browbytes&3):0;
|
||||
rows = ((h+blockheight-1)/blockheight)*d;
|
||||
rows = ((h+blockheight-1)/blockheight)*
|
||||
((d+blockdepth-1)/blockdepth);
|
||||
if (datasize != (browbytes+padbytes) * rows)
|
||||
{
|
||||
Con_Printf("%s: mip %i does not match expected size (%u, required %u)\n", fname, mipnum, datasize, (browbytes+padbytes) * rows);
|
||||
|
@ -5289,7 +5326,7 @@ static struct pendingtextureinfo *Image_ReadKTXFile(unsigned int flags, const ch
|
|||
}
|
||||
|
||||
#ifdef ASTC_WITH_HDRTEST
|
||||
if (encoding >= PTI_ASTC_4X4_LDR && encoding <= PTI_ASTC_12X12_LDR)
|
||||
if (encoding >= PTI_ASTC_4X4_LDR && encoding < PTI_ASTC_4X4_SRGB)
|
||||
{
|
||||
int face;
|
||||
for (face = 0; face < header.numberoffaces; face++)
|
||||
|
@ -5311,7 +5348,7 @@ static struct pendingtextureinfo *Image_ReadKTXFile(unsigned int flags, const ch
|
|||
static struct pendingtextureinfo *Image_ReadASTCFile(unsigned int flags, const char *fname, qbyte *filedata, size_t filesize)
|
||||
{
|
||||
struct pendingtextureinfo *mips;
|
||||
int encoding = PTI_INVALID, blockbytes, blockwidth, blockheight;
|
||||
int encoding = PTI_INVALID, blockbytes, blockwidth, blockheight, blockdepth;
|
||||
static const struct {
|
||||
int w, h, d;
|
||||
int fmt;
|
||||
|
@ -5331,6 +5368,18 @@ static struct pendingtextureinfo *Image_ReadASTCFile(unsigned int flags, const c
|
|||
{10,10,1,PTI_ASTC_10X10_LDR},
|
||||
{12,10,1,PTI_ASTC_12X10_LDR},
|
||||
{12,12,1,PTI_ASTC_12X12_LDR},
|
||||
#ifdef ASTC3D
|
||||
{3,3,3,PTI_ASTC_3X3X3_LDR},
|
||||
{4,3,3,PTI_ASTC_4X3X3_LDR},
|
||||
{4,4,3,PTI_ASTC_4X4X3_LDR},
|
||||
{4,4,4,PTI_ASTC_4X4X4_LDR},
|
||||
{5,4,4,PTI_ASTC_5X4X4_LDR},
|
||||
{5,5,4,PTI_ASTC_5X5X4_LDR},
|
||||
{5,5,5,PTI_ASTC_5X5X5_LDR},
|
||||
{6,5,5,PTI_ASTC_6X5X5_LDR},
|
||||
{6,6,5,PTI_ASTC_6X6X5_LDR},
|
||||
{6,6,6,PTI_ASTC_6X6X6_LDR},
|
||||
#endif
|
||||
};
|
||||
int i;
|
||||
int size[3] = {
|
||||
|
@ -5347,8 +5396,8 @@ static struct pendingtextureinfo *Image_ReadASTCFile(unsigned int flags, const c
|
|||
}
|
||||
if (!encoding)
|
||||
return NULL; //block size not known
|
||||
Image_BlockSizeForEncoding(encoding, &blockbytes, &blockwidth, &blockheight);
|
||||
if (16+((size[0]+blockwidth-1)/blockwidth)*((size[1]+blockheight-1)/blockheight)*blockbytes != filesize)
|
||||
Image_BlockSizeForEncoding(encoding, &blockbytes, &blockwidth, &blockheight, &blockdepth);
|
||||
if (16+blockbytes*((size[0]+blockwidth-1)/blockwidth)*((size[1]+blockheight-1)/blockheight)*((size[2]+blockdepth-1)/blockdepth) != filesize)
|
||||
return NULL; //err, not the right size!
|
||||
|
||||
mips = Z_Malloc(sizeof(*mips));
|
||||
|
@ -5377,7 +5426,7 @@ static struct pendingtextureinfo *Image_ReadASTCFile(unsigned int flags, const c
|
|||
static struct pendingtextureinfo *Image_ReadPKMFile(unsigned int flags, const char *fname, qbyte *filedata, size_t filesize)
|
||||
{
|
||||
struct pendingtextureinfo *mips;
|
||||
unsigned int encoding, blockbytes, blockwidth, blockheight;
|
||||
unsigned int encoding, blockbytes, blockwidth, blockheight, blockdepth;
|
||||
unsigned short ver, dfmt;
|
||||
unsigned short datawidth, dataheight;
|
||||
unsigned short imgwidth, imgheight;
|
||||
|
@ -5424,7 +5473,7 @@ static struct pendingtextureinfo *Image_ReadPKMFile(unsigned int flags, const ch
|
|||
else
|
||||
return NULL;
|
||||
|
||||
Image_BlockSizeForEncoding(encoding, &blockbytes, &blockwidth, &blockheight);
|
||||
Image_BlockSizeForEncoding(encoding, &blockbytes, &blockwidth, &blockheight, &blockdepth);
|
||||
if (16+((datawidth+blockwidth-1)/blockwidth)*((dataheight+blockheight-1)/blockheight)*blockbytes != filesize)
|
||||
return NULL; //err, not the right size!
|
||||
|
||||
|
@ -5483,7 +5532,7 @@ static struct pendingtextureinfo *Image_ReadDDSFile(unsigned int flags, const ch
|
|||
int mipnum;
|
||||
int datasize;
|
||||
unsigned int w, h, d;
|
||||
unsigned int blockwidth, blockheight, blockbytes;
|
||||
unsigned int blockwidth, blockheight, blockdepth, blockbytes;
|
||||
struct pendingtextureinfo *mips;
|
||||
int encoding;
|
||||
int layers = 1, layer;
|
||||
|
@ -5491,6 +5540,7 @@ static struct pendingtextureinfo *Image_ReadDDSFile(unsigned int flags, const ch
|
|||
|
||||
ddsheader_t fmtheader;
|
||||
dds10header_t fmt10header;
|
||||
qbyte *fileend = filedata + filesize;
|
||||
|
||||
if (filesize < sizeof(fmtheader) || *(int*)filedata != (('D'<<0)|('D'<<8)|('S'<<16)|(' '<<24)))
|
||||
return NULL;
|
||||
|
@ -5764,10 +5814,31 @@ static struct pendingtextureinfo *Image_ReadDDSFile(unsigned int flags, const ch
|
|||
if ((fmtheader.ddsCaps[1] & 0x200) && (fmtheader.ddsCaps[1] & 0xfc00) != 0xfc00)
|
||||
return NULL; //cubemap without all 6 faces defined.
|
||||
|
||||
Image_BlockSizeForEncoding(encoding, &blockbytes, &blockwidth, &blockheight);
|
||||
Image_BlockSizeForEncoding(encoding, &blockbytes, &blockwidth, &blockheight, &blockdepth);
|
||||
if (!blockbytes)
|
||||
return NULL; //werid/unsupported
|
||||
|
||||
if (fmtheader.dwFlags & 8)
|
||||
{ //explicit pitch flag. we don't support any padding, so this check exists just to be sure none is required.
|
||||
w = max(1, fmtheader.dwWidth);
|
||||
if (fmtheader.dwPitchOrLinearSize != blockbytes*(w+blockwidth-1)/blockwidth)
|
||||
return NULL;
|
||||
}
|
||||
if (fmtheader.dwFlags & 0x80000)
|
||||
{ //linear size flag. we don't support any padding, so this check exists just to be sure none is required.
|
||||
//linear-size of the top-level mip.
|
||||
size_t linearsize;
|
||||
w = max(1, fmtheader.dwWidth);
|
||||
h = max(1, fmtheader.dwHeight);
|
||||
d = max(1, fmtheader.dwDepth);
|
||||
linearsize = ((w+blockwidth-1)/blockwidth)*
|
||||
((h+blockheight-1)/blockheight)*
|
||||
((d+blockdepth-1)/blockdepth)*
|
||||
blockbytes;
|
||||
if (fmtheader.dwPitchOrLinearSize != linearsize)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fmtheader.ddsCaps[1] & 0x200)
|
||||
{
|
||||
if (fmt10header.arraysize % 6) //weird number of faces.
|
||||
|
@ -5815,7 +5886,7 @@ static struct pendingtextureinfo *Image_ReadDDSFile(unsigned int flags, const ch
|
|||
{ //can just use the data without copying.
|
||||
for (mipnum = 0; mipnum < nummips; mipnum++)
|
||||
{
|
||||
datasize = ((w+blockwidth-1)/blockwidth) * ((h+blockheight-1)/blockheight) * (d) * blockbytes;
|
||||
datasize = ((w+blockwidth-1)/blockwidth) * ((h+blockheight-1)/blockheight) * ((d+blockdepth-1)/blockdepth) * blockbytes;
|
||||
|
||||
mips->mip[mipnum].data = filedata;
|
||||
mips->mip[mipnum].datasize = datasize;
|
||||
|
@ -5829,13 +5900,19 @@ static struct pendingtextureinfo *Image_ReadDDSFile(unsigned int flags, const ch
|
|||
d = max(1, d>>1);
|
||||
}
|
||||
mips->mipcount = mipnum;
|
||||
|
||||
if (filedata > fileend)
|
||||
{ //overflow... corrupt dds?
|
||||
Z_Free(mips);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ //we need to copy stuff in order to pack it properly. :(
|
||||
//allocate space and calc mip sizes
|
||||
for (mipnum = 0; mipnum < nummips; mipnum++)
|
||||
{
|
||||
datasize = ((w+blockwidth-1)/blockwidth) * ((h+blockheight-1)/blockheight) * (layers*d) * blockbytes;
|
||||
datasize = ((w+blockwidth-1)/blockwidth) * ((h+blockheight-1)/blockheight) * (layers*((d+blockdepth-1)/blockdepth)) * blockbytes;
|
||||
mips->mip[mipnum].data = BZ_Malloc(datasize);
|
||||
mips->mip[mipnum].datasize = datasize;
|
||||
mips->mip[mipnum].width = w;
|
||||
|
@ -5853,6 +5930,13 @@ static struct pendingtextureinfo *Image_ReadDDSFile(unsigned int flags, const ch
|
|||
for (mipnum = 0; mipnum < nummips; mipnum++)
|
||||
{
|
||||
datasize = mips->mip[mipnum].datasize/layers;
|
||||
if (filedata+datasize > fileend)
|
||||
{ //overflow... corrupt dds?
|
||||
for (mipnum = 0; mipnum < nummips; mipnum++)
|
||||
Z_Free(mips->mip[mipnum].data);
|
||||
Z_Free(mips);
|
||||
return NULL;
|
||||
}
|
||||
memcpy((qbyte*)mips->mip[mipnum].data+datasize*layer, filedata, datasize);
|
||||
filedata += datasize;
|
||||
}
|
||||
|
@ -5874,10 +5958,10 @@ qboolean Image_WriteDDSFile(const char *filename, enum fs_relative fsroot, struc
|
|||
ddsheader_t h9={0};
|
||||
int *endian;
|
||||
|
||||
unsigned int blockbytes, blockwidth, blockheight;
|
||||
unsigned int blockbytes, blockwidth, blockheight, blockdepth;
|
||||
unsigned int arraysize;
|
||||
|
||||
Image_BlockSizeForEncoding(mips->encoding, &blockbytes, &blockwidth, &blockheight);
|
||||
Image_BlockSizeForEncoding(mips->encoding, &blockbytes, &blockwidth, &blockheight, &blockdepth);
|
||||
|
||||
h9.dwSize = sizeof(h9);
|
||||
h9.ddpfPixelFormat.dwSize = sizeof(h9.ddpfPixelFormat);
|
||||
|
@ -5889,7 +5973,10 @@ qboolean Image_WriteDDSFile(const char *filename, enum fs_relative fsroot, struc
|
|||
if (blockwidth != 1 || blockheight != 1)
|
||||
{
|
||||
h9.dwFlags |= 0x80000; //LINEARSIZE
|
||||
h9.dwPitchOrLinearSize = ((mips->mip[0].width+blockwidth-1)/blockwidth)*((mips->mip[0].height+blockheight-1)/blockheight)*blockbytes;
|
||||
h9.dwPitchOrLinearSize = ((mips->mip[0].width+blockwidth-1)/blockwidth)*
|
||||
((mips->mip[0].height+blockheight-1)/blockheight)*
|
||||
(mips->type==PTI_3D?((mips->mip[0].depth+blockdepth-1)/blockdepth):1)*
|
||||
blockbytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -6135,6 +6222,38 @@ qboolean Image_WriteDDSFile(const char *filename, enum fs_relative fsroot, struc
|
|||
case PTI_ASTC_12X12_HDR: //hdr allows more endpoint modes.
|
||||
case PTI_ASTC_12X12_LDR: h10.dxgiformat = 0xba/*DXGI_FORMAT_ASTC_12X12_UNORM*/; break;
|
||||
case PTI_ASTC_12X12_SRGB: h10.dxgiformat = 0xbb/*DXGI_FORMAT_ASTC_12X12_SRGB*/; break;
|
||||
#ifdef ASTC3D
|
||||
case PTI_ASTC_3X3X3_HDR:
|
||||
case PTI_ASTC_4X3X3_HDR:
|
||||
case PTI_ASTC_4X4X3_HDR:
|
||||
case PTI_ASTC_4X4X4_HDR:
|
||||
case PTI_ASTC_5X4X4_HDR:
|
||||
case PTI_ASTC_5X5X4_HDR:
|
||||
case PTI_ASTC_5X5X5_HDR:
|
||||
case PTI_ASTC_6X5X5_HDR:
|
||||
case PTI_ASTC_6X6X5_HDR:
|
||||
case PTI_ASTC_6X6X6_HDR:
|
||||
case PTI_ASTC_3X3X3_LDR:
|
||||
case PTI_ASTC_4X3X3_LDR:
|
||||
case PTI_ASTC_4X4X3_LDR:
|
||||
case PTI_ASTC_4X4X4_LDR:
|
||||
case PTI_ASTC_5X4X4_LDR:
|
||||
case PTI_ASTC_5X5X4_LDR:
|
||||
case PTI_ASTC_5X5X5_LDR:
|
||||
case PTI_ASTC_6X5X5_LDR:
|
||||
case PTI_ASTC_6X6X5_LDR:
|
||||
case PTI_ASTC_6X6X6_LDR:
|
||||
case PTI_ASTC_3X3X3_SRGB:
|
||||
case PTI_ASTC_4X3X3_SRGB:
|
||||
case PTI_ASTC_4X4X3_SRGB:
|
||||
case PTI_ASTC_4X4X4_SRGB:
|
||||
case PTI_ASTC_5X4X4_SRGB:
|
||||
case PTI_ASTC_5X5X4_SRGB:
|
||||
case PTI_ASTC_5X5X5_SRGB:
|
||||
case PTI_ASTC_6X5X5_SRGB:
|
||||
case PTI_ASTC_6X6X5_SRGB:
|
||||
case PTI_ASTC_6X6X6_SRGB: return false; //no dxgi format assigned that we know of
|
||||
#endif
|
||||
|
||||
case PTI_RGBX8: DX9FMT(32,0x000000ff,0x0000ff00,0x00ff0000,0x00000000,DX9RGB); break; //WARNING: buggy in gimp (ends up alpha=0)
|
||||
case PTI_RGB8: DX9FMT(24,0x000000ff,0x0000ff00,0x00ff0000,0x00000000,DX9RGB); break;
|
||||
|
@ -10260,17 +10379,17 @@ static void Image_Decode_BC7_Block(qbyte *fte_restrict in, pixel32_t *fte_restri
|
|||
#ifdef ASTC_WITH_LDR
|
||||
static void Image_Decode_ASTC_LDR_U8_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int stride, uploadfmt_t fmt)
|
||||
{
|
||||
int bw, bh, blockbytes;
|
||||
Image_BlockSizeForEncoding(fmt, &blockbytes, &bw, &bh);
|
||||
ASTC_Decode_LDR8(in, out->v, stride, bw, bh);
|
||||
int bw, bh, bd, blockbytes;
|
||||
Image_BlockSizeForEncoding(fmt, &blockbytes, &bw, &bh, &bd);
|
||||
ASTC_Decode_LDR8(in, out->v, stride, 0/*w*h*/, bw, bh, bd);
|
||||
}
|
||||
#endif
|
||||
#ifdef ASTC_WITH_HDR
|
||||
static void Image_Decode_ASTC_HDR_HF_Block(qbyte *fte_restrict in, pixel64_t *fte_restrict out, int stride, uploadfmt_t fmt)
|
||||
{
|
||||
int bw, bh, blockbytes;
|
||||
Image_BlockSizeForEncoding(fmt, &blockbytes, &bw, &bh);
|
||||
ASTC_Decode_HDR(in, out->v, stride, bw, bh);
|
||||
int bw, bh, bd, blockbytes;
|
||||
Image_BlockSizeForEncoding(fmt, &blockbytes, &bw, &bh, &bd);
|
||||
ASTC_Decode_HDR(in, out->v, stride, 0/*w*h*/, bw, bh, bd);
|
||||
}
|
||||
|
||||
/*static unsigned int RGB16F_to_E5BGR9(unsigned short Cr, unsigned short Cg, unsigned short Cb)
|
||||
|
@ -10354,9 +10473,9 @@ static void Image_Decode_L8_Block(qbyte *fte_restrict in, pixel32_t *fte_restric
|
|||
Vector4Set(out->v, in[0], in[0], in[0], 0xff);
|
||||
}
|
||||
|
||||
void Image_BlockSizeForEncoding(uploadfmt_t 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 *blockdepth)
|
||||
{
|
||||
unsigned int b = 0, w = 1, h = 1;
|
||||
unsigned int b = 0, w = 1, h = 1, d = 1;
|
||||
switch(encoding)
|
||||
{
|
||||
case PTI_RGB565:
|
||||
|
@ -10513,6 +10632,39 @@ void Image_BlockSizeForEncoding(uploadfmt_t encoding, unsigned int *blockbytes,
|
|||
case PTI_ASTC_12X12_SRGB:
|
||||
case PTI_ASTC_12X12_LDR: w = 12; h = 12; b = 16; break;
|
||||
|
||||
#ifdef ASTC3D
|
||||
case PTI_ASTC_3X3X3_HDR:
|
||||
case PTI_ASTC_3X3X3_SRGB:
|
||||
case PTI_ASTC_3X3X3_LDR: w = 3; h = 3; d = 3; b = 16; break;
|
||||
case PTI_ASTC_4X3X3_HDR:
|
||||
case PTI_ASTC_4X3X3_SRGB:
|
||||
case PTI_ASTC_4X3X3_LDR: w = 4; h = 3; d = 3; b = 16; break;
|
||||
case PTI_ASTC_4X4X3_HDR:
|
||||
case PTI_ASTC_4X4X3_SRGB:
|
||||
case PTI_ASTC_4X4X3_LDR: w = 4; h = 4; d = 3; b = 16; break;
|
||||
case PTI_ASTC_4X4X4_HDR:
|
||||
case PTI_ASTC_4X4X4_SRGB:
|
||||
case PTI_ASTC_4X4X4_LDR: w = 4; h = 4; d = 4; b = 16; break;
|
||||
case PTI_ASTC_5X4X4_HDR:
|
||||
case PTI_ASTC_5X4X4_SRGB:
|
||||
case PTI_ASTC_5X4X4_LDR: w = 5; h = 4; d = 4; b = 16; break;
|
||||
case PTI_ASTC_5X5X4_HDR:
|
||||
case PTI_ASTC_5X5X4_SRGB:
|
||||
case PTI_ASTC_5X5X4_LDR: w = 5; h = 5; d = 4; b = 16; break;
|
||||
case PTI_ASTC_5X5X5_HDR:
|
||||
case PTI_ASTC_5X5X5_SRGB:
|
||||
case PTI_ASTC_5X5X5_LDR: w = 5; h = 5; d = 5; b = 16; break;
|
||||
case PTI_ASTC_6X5X5_HDR:
|
||||
case PTI_ASTC_6X5X5_SRGB:
|
||||
case PTI_ASTC_6X5X5_LDR: w = 6; h = 5; d = 5; b = 16; break;
|
||||
case PTI_ASTC_6X6X5_HDR:
|
||||
case PTI_ASTC_6X6X5_SRGB:
|
||||
case PTI_ASTC_6X6X5_LDR: w = 6; h = 6; d = 5; b = 16; break;
|
||||
case PTI_ASTC_6X6X6_HDR:
|
||||
case PTI_ASTC_6X6X6_SRGB:
|
||||
case PTI_ASTC_6X6X6_LDR: w = 6; h = 6; d = 6; b = 16; break;
|
||||
#endif
|
||||
|
||||
case PTI_EMULATED:
|
||||
#ifdef FTE_TARGET_WEB
|
||||
case PTI_WHOLEFILE: //UNKNOWN!
|
||||
|
@ -10524,6 +10676,7 @@ void Image_BlockSizeForEncoding(uploadfmt_t encoding, unsigned int *blockbytes,
|
|||
*blockbytes = b;
|
||||
*blockwidth = w;
|
||||
*blockheight = h;
|
||||
*blockdepth = d;
|
||||
}
|
||||
|
||||
qboolean Image_FormatHasAlpha(uploadfmt_t encoding)
|
||||
|
@ -10641,6 +10794,38 @@ qboolean Image_FormatHasAlpha(uploadfmt_t encoding)
|
|||
case PTI_ASTC_12X12_HDR:
|
||||
case PTI_ASTC_12X12_SRGB:
|
||||
case PTI_ASTC_12X12_LDR:
|
||||
#ifdef ASTC3D
|
||||
case PTI_ASTC_3X3X3_HDR:
|
||||
case PTI_ASTC_3X3X3_SRGB:
|
||||
case PTI_ASTC_3X3X3_LDR:
|
||||
case PTI_ASTC_4X3X3_HDR:
|
||||
case PTI_ASTC_4X3X3_SRGB:
|
||||
case PTI_ASTC_4X3X3_LDR:
|
||||
case PTI_ASTC_4X4X3_HDR:
|
||||
case PTI_ASTC_4X4X3_SRGB:
|
||||
case PTI_ASTC_4X4X3_LDR:
|
||||
case PTI_ASTC_4X4X4_HDR:
|
||||
case PTI_ASTC_4X4X4_SRGB:
|
||||
case PTI_ASTC_4X4X4_LDR:
|
||||
case PTI_ASTC_5X4X4_HDR:
|
||||
case PTI_ASTC_5X4X4_SRGB:
|
||||
case PTI_ASTC_5X4X4_LDR:
|
||||
case PTI_ASTC_5X5X4_HDR:
|
||||
case PTI_ASTC_5X5X4_SRGB:
|
||||
case PTI_ASTC_5X5X4_LDR:
|
||||
case PTI_ASTC_5X5X5_HDR:
|
||||
case PTI_ASTC_5X5X5_SRGB:
|
||||
case PTI_ASTC_5X5X5_LDR:
|
||||
case PTI_ASTC_6X5X5_HDR:
|
||||
case PTI_ASTC_6X5X5_SRGB:
|
||||
case PTI_ASTC_6X5X5_LDR:
|
||||
case PTI_ASTC_6X6X5_HDR:
|
||||
case PTI_ASTC_6X6X5_SRGB:
|
||||
case PTI_ASTC_6X6X5_LDR:
|
||||
case PTI_ASTC_6X6X6_HDR:
|
||||
case PTI_ASTC_6X6X6_SRGB:
|
||||
case PTI_ASTC_6X6X6_LDR:
|
||||
#endif
|
||||
return true;
|
||||
|
||||
case PTI_EMULATED:
|
||||
|
@ -10766,6 +10951,38 @@ const char *Image_FormatName(uploadfmt_t fmt)
|
|||
case PTI_ASTC_12X12_HDR: return "ASTC_12X12_HDR";
|
||||
case PTI_ASTC_12X12_SRGB: return "ASTC_12X12_SRGB";
|
||||
case PTI_ASTC_12X12_LDR: return "ASTC_12X12_LDR";
|
||||
#ifdef ASTC3D
|
||||
case PTI_ASTC_3X3X3_HDR: return "ASTC_3X3X3_HDR";
|
||||
case PTI_ASTC_3X3X3_SRGB: return "ASTC_3X3X3_SRGB";
|
||||
case PTI_ASTC_3X3X3_LDR: return "ASTC_3X3X3_LDR";
|
||||
case PTI_ASTC_4X3X3_HDR: return "ASTC_4X3X3_HDR";
|
||||
case PTI_ASTC_4X3X3_SRGB: return "ASTC_4X3X3_SRGB";
|
||||
case PTI_ASTC_4X3X3_LDR: return "ASTC_4X3X3_LDR";
|
||||
case PTI_ASTC_4X4X3_HDR: return "ASTC_4X4X3_HDR";
|
||||
case PTI_ASTC_4X4X3_SRGB: return "ASTC_4X4X3_SRGB";
|
||||
case PTI_ASTC_4X4X3_LDR: return "ASTC_4X4X3_LDR";
|
||||
case PTI_ASTC_4X4X4_HDR: return "ASTC_4X4X4_HDR";
|
||||
case PTI_ASTC_4X4X4_SRGB: return "ASTC_4X4X4_SRGB";
|
||||
case PTI_ASTC_4X4X4_LDR: return "ASTC_4X4X4_LDR";
|
||||
case PTI_ASTC_5X4X4_HDR: return "ASTC_5X4X4_HDR";
|
||||
case PTI_ASTC_5X4X4_SRGB: return "ASTC_5X4X4_SRGB";
|
||||
case PTI_ASTC_5X4X4_LDR: return "ASTC_5X4X4_LDR";
|
||||
case PTI_ASTC_5X5X4_HDR: return "ASTC_5X5X4_HDR";
|
||||
case PTI_ASTC_5X5X4_SRGB: return "ASTC_5X5X4_SRGB";
|
||||
case PTI_ASTC_5X5X4_LDR: return "ASTC_5X5X4_LDR";
|
||||
case PTI_ASTC_5X5X5_HDR: return "ASTC_5X5X5_HDR";
|
||||
case PTI_ASTC_5X5X5_SRGB: return "ASTC_5X5X5_SRGB";
|
||||
case PTI_ASTC_5X5X5_LDR: return "ASTC_5X5X5_LDR";
|
||||
case PTI_ASTC_6X5X5_HDR: return "ASTC_6X5X5_HDR";
|
||||
case PTI_ASTC_6X5X5_SRGB: return "ASTC_6X5X5_SRGB";
|
||||
case PTI_ASTC_6X5X5_LDR: return "ASTC_6X5X5_LDR";
|
||||
case PTI_ASTC_6X6X5_HDR: return "ASTC_6X6X5_HDR";
|
||||
case PTI_ASTC_6X6X5_SRGB: return "ASTC_6X6X5_SRGB";
|
||||
case PTI_ASTC_6X6X5_LDR: return "ASTC_6X6X5_LDR";
|
||||
case PTI_ASTC_6X6X6_HDR: return "ASTC_6X6X6_HDR";
|
||||
case PTI_ASTC_6X6X6_SRGB: return "ASTC_6X6X6_SRGB";
|
||||
case PTI_ASTC_6X6X6_LDR: return "ASTC_6X6X6_LDR";
|
||||
#endif
|
||||
|
||||
#ifdef FTE_TARGET_WEB
|
||||
case PTI_WHOLEFILE: return "Whole File";
|
||||
|
@ -10803,10 +11020,10 @@ static pixel32_t *Image_Block_Decode(qbyte *fte_restrict in, size_t insize, int
|
|||
int sizediff;
|
||||
int rows, columns, layers;
|
||||
|
||||
unsigned int blockbytes, blockwidth, blockheight;
|
||||
Image_BlockSizeForEncoding(encoding, &blockbytes, &blockwidth, &blockheight);
|
||||
unsigned int blockbytes, blockwidth, blockheight, blockdepth;
|
||||
Image_BlockSizeForEncoding(encoding, &blockbytes, &blockwidth, &blockheight, &blockdepth);
|
||||
|
||||
if (blockwidth > TMPBLOCKSIZE || blockheight > TMPBLOCKSIZE)
|
||||
if (blockwidth > TMPBLOCKSIZE || blockheight > TMPBLOCKSIZE || blockdepth != 1)
|
||||
Sys_Error("Image_Block_Decode only supports up to %u*%u blocks.\n", TMPBLOCKSIZE,TMPBLOCKSIZE);
|
||||
|
||||
sizediff = insize - blockbytes*((w+blockwidth-1)/blockwidth)*((h+blockheight-1)/blockheight)*d;
|
||||
|
@ -10872,13 +11089,13 @@ static pixel64_t *Image_Block_Decode64(qbyte *fte_restrict in, size_t insize, in
|
|||
int sizediff;
|
||||
int rows, columns, layers;
|
||||
|
||||
unsigned int blockbytes, blockwidth, blockheight;
|
||||
Image_BlockSizeForEncoding(encoding, &blockbytes, &blockwidth, &blockheight);
|
||||
unsigned int blockbytes, blockwidth, blockheight, blockdepth;
|
||||
Image_BlockSizeForEncoding(encoding, &blockbytes, &blockwidth, &blockheight, &blockdepth);
|
||||
|
||||
if (blockwidth > TMPBLOCKSIZE || blockheight > TMPBLOCKSIZE)
|
||||
Sys_Error("Image_Block_Decode only supports up to %u*%u blocks.\n", TMPBLOCKSIZE,TMPBLOCKSIZE);
|
||||
if (blockwidth > TMPBLOCKSIZE || blockheight > TMPBLOCKSIZE || blockdepth != 1)
|
||||
Sys_Error("Image_Block_Decode only supports up to %u*%u*%u blocks.\n", TMPBLOCKSIZE,TMPBLOCKSIZE,1);
|
||||
|
||||
sizediff = insize - blockbytes*((w+blockwidth-1)/blockwidth)*((h+blockheight-1)/blockheight)*d;
|
||||
sizediff = insize - blockbytes*((w+blockwidth-1)/blockwidth)*((h+blockheight-1)/blockheight)*((d+blockdepth-1)/blockdepth);
|
||||
if (sizediff)
|
||||
{
|
||||
Con_Printf("Image_Block_Decode: %s data size is %u, expected %u\n\n", Image_FormatName(encoding), (unsigned int)insize, (unsigned int)(insize-sizediff));
|
||||
|
@ -10892,8 +11109,9 @@ static pixel64_t *Image_Block_Decode64(qbyte *fte_restrict in, size_t insize, in
|
|||
rows *= blockheight;
|
||||
columns = w/blockwidth;
|
||||
columns *= blockwidth;
|
||||
layers = d;
|
||||
for (z = 0; z < layers; z++)
|
||||
layers = d/blockdepth;
|
||||
layers *= blockdepth;
|
||||
for (z = 0; z < layers; z+=blockdepth)
|
||||
{
|
||||
for (y = 0; y < rows; y+=blockheight, out += w*(blockheight-1))
|
||||
{
|
||||
|
@ -11317,9 +11535,9 @@ void Image_ChangeFormat(struct pendingtextureinfo *mips, qboolean *allowedformat
|
|||
{ //direct3d is annoying, and will reject any block-compressed format with a base mip size that is not a multiple of the block size.
|
||||
//its fine with weirdly sized mips though. I have no idea why there's this restriction, but whatever.
|
||||
//we need to manually decompress in order to correctly handle such images
|
||||
int blockbytes, blockwidth, blockheight;
|
||||
Image_BlockSizeForEncoding(mips->encoding, &blockbytes, &blockwidth, &blockheight);
|
||||
if (!(mips->mip[0].width % blockwidth) && !(mips->mip[0].height % blockheight))
|
||||
int blockbytes, blockwidth, blockheight, blockdepth;
|
||||
Image_BlockSizeForEncoding(mips->encoding, &blockbytes, &blockwidth, &blockheight, &blockdepth);
|
||||
if (!(mips->mip[0].width % blockwidth) && !(mips->mip[0].height % blockheight) && !(mips->mip[0].depth % blockdepth))
|
||||
return;
|
||||
//else encoding isn't supported for this size. fall through.
|
||||
}
|
||||
|
@ -11499,7 +11717,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
|
|||
unsigned int *rgbadata = rawdata;
|
||||
int i;
|
||||
qboolean valid;
|
||||
unsigned int bb, bw, bh;
|
||||
unsigned int bb, bw, bh, bd;
|
||||
|
||||
mips->mip[0].width = imgwidth;
|
||||
mips->mip[0].height = imgheight;
|
||||
|
@ -11516,13 +11734,13 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
|
|||
if (mips->mip[0].width == imgwidth && mips->mip[0].height == imgheight) //make sure its okay
|
||||
{
|
||||
size_t sz = 0;
|
||||
Image_BlockSizeForEncoding(fmt, &bb, &bw, &bh);
|
||||
Image_BlockSizeForEncoding(fmt, &bb, &bw, &bh, &bd);
|
||||
for (i = 0; i < countof(mips->mip) && (imgwidth || imgheight); i++, imgwidth>>=1, imgheight>>=1)
|
||||
{
|
||||
mips->mip[i].width = max(1,imgwidth);
|
||||
mips->mip[i].height = max(1,imgheight);
|
||||
mips->mip[i].depth = 1;
|
||||
mips->mip[i].datasize = bb * ((mips->mip[i].width+bw-1)/bw) * ((mips->mip[i].height+bh-1)/bh);
|
||||
mips->mip[i].datasize = bb * ((mips->mip[i].width+bw-1)/bw) * ((mips->mip[i].height+bh-1)/bh) * ((mips->mip[i].depth+bd-1)/bd);
|
||||
mips->mip[i].needfree = false;
|
||||
sz += mips->mip[i].datasize;
|
||||
}
|
||||
|
@ -12041,6 +12259,38 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
|
|||
case PTI_ASTC_12X12_LDR:
|
||||
case PTI_ASTC_12X12_SRGB:
|
||||
case PTI_ASTC_12X12_HDR:
|
||||
#ifdef ASTC3D
|
||||
case PTI_ASTC_3X3X3_HDR:
|
||||
case PTI_ASTC_3X3X3_SRGB:
|
||||
case PTI_ASTC_3X3X3_LDR:
|
||||
case PTI_ASTC_4X3X3_HDR:
|
||||
case PTI_ASTC_4X3X3_SRGB:
|
||||
case PTI_ASTC_4X3X3_LDR:
|
||||
case PTI_ASTC_4X4X3_HDR:
|
||||
case PTI_ASTC_4X4X3_SRGB:
|
||||
case PTI_ASTC_4X4X3_LDR:
|
||||
case PTI_ASTC_4X4X4_HDR:
|
||||
case PTI_ASTC_4X4X4_SRGB:
|
||||
case PTI_ASTC_4X4X4_LDR:
|
||||
case PTI_ASTC_5X4X4_HDR:
|
||||
case PTI_ASTC_5X4X4_SRGB:
|
||||
case PTI_ASTC_5X4X4_LDR:
|
||||
case PTI_ASTC_5X5X4_HDR:
|
||||
case PTI_ASTC_5X5X4_SRGB:
|
||||
case PTI_ASTC_5X5X4_LDR:
|
||||
case PTI_ASTC_5X5X5_HDR:
|
||||
case PTI_ASTC_5X5X5_SRGB:
|
||||
case PTI_ASTC_5X5X5_LDR:
|
||||
case PTI_ASTC_6X5X5_HDR:
|
||||
case PTI_ASTC_6X5X5_SRGB:
|
||||
case PTI_ASTC_6X5X5_LDR:
|
||||
case PTI_ASTC_6X6X5_HDR:
|
||||
case PTI_ASTC_6X6X5_SRGB:
|
||||
case PTI_ASTC_6X6X5_LDR:
|
||||
case PTI_ASTC_6X6X6_HDR:
|
||||
case PTI_ASTC_6X6X6_SRGB:
|
||||
case PTI_ASTC_6X6X6_LDR:
|
||||
#endif
|
||||
#ifdef FTE_TARGET_WEB
|
||||
case PTI_WHOLEFILE:
|
||||
#endif
|
||||
|
@ -12238,8 +12488,8 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
|
|||
}
|
||||
else
|
||||
mips->mip[0].data = NULL;
|
||||
Image_BlockSizeForEncoding(mips->encoding, &bb, &bw, &bh);
|
||||
mips->mip[0].datasize = ((mips->mip[0].width+bw-1)/bw) * ((mips->mip[0].height+bh-1)/bh) * bb;
|
||||
Image_BlockSizeForEncoding(mips->encoding, &bb, &bw, &bh, &bd);
|
||||
mips->mip[0].datasize = ((mips->mip[0].width+bw-1)/bw) * ((mips->mip[0].height+bh-1)/bh) * ((mips->mip[0].depth+bd-1)/bd) * bb;
|
||||
|
||||
if (mips->type == PTI_3D)
|
||||
{
|
||||
|
@ -12247,7 +12497,7 @@ 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->mip[0].depth == 1 && (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 && (bb==4&&bw==1&&bh==1&&bd==1))
|
||||
{
|
||||
int d, r;
|
||||
int size = mips->mip[0].height;
|
||||
|
@ -12695,9 +12945,9 @@ static struct pendingtextureinfo *Image_LoadCubemapTextureData(const char *nicen
|
|||
if ((data = ReadRawImageFile(buf, filesize, &width, &height, &format, true, fname)))
|
||||
{
|
||||
extern cvar_t vid_hardwaregamma;
|
||||
int bb,bw,bh;
|
||||
Image_BlockSizeForEncoding(format, &bb, &bw, &bh);
|
||||
if (needsflipping && (bw!=1 || bh!=1))
|
||||
int bb,bw,bh, bd;
|
||||
Image_BlockSizeForEncoding(format, &bb, &bw, &bh, &bd);
|
||||
if (needsflipping && (bw!=1 || bh!=1 || bd!=1))
|
||||
/*can't do it*/;
|
||||
else if (width == height && (!mips || width == mips->mip[0].width)) //cubemaps must be square and all the same size (npot is fine though)
|
||||
{ //(skies have a fallback for invalid sizes, but it'll run a bit slower)
|
||||
|
@ -13443,11 +13693,11 @@ image_t *QDECL Image_GetTexture(const char *identifier, const char *subpath, uns
|
|||
break;
|
||||
default:
|
||||
{
|
||||
unsigned int bb, bw, bh;
|
||||
unsigned int bb, bw, bh, bd;
|
||||
unsigned int lev;
|
||||
Image_BlockSizeForEncoding(fallbackfmt&~PTI_FULLMIPCHAIN, &bb, &bw, &bh);
|
||||
Image_BlockSizeForEncoding(fallbackfmt&~PTI_FULLMIPCHAIN, &bb, &bw, &bh, &bd);
|
||||
for (b=0, lev = 0; fallbackwidth>>lev||fallbackheight>>lev; lev++)
|
||||
b += bb * (max(1,fallbackwidth>>lev)+bw-1)/bw * (max(1,fallbackheight>>lev)+bh-1)/bh;
|
||||
b += bb * (max(1,fallbackwidth>>lev)+bw-1)/bw * (max(1,fallbackheight>>lev)+bh-1)/bh;// * (max(1,fallbackdepth>>lev)+bd-1)/bd;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -13727,9 +13977,9 @@ void Image_List_f(void)
|
|||
if (tex->status == TEX_LOADED)
|
||||
{
|
||||
char *type;
|
||||
unsigned int blockbytes, blockwidth, blockheight;
|
||||
Image_BlockSizeForEncoding(tex->format, &blockbytes, &blockwidth, &blockheight);
|
||||
imgmem = blockbytes * (tex->width+blockwidth-1)/blockwidth * (tex->height+blockheight-1)/blockheight * tex->depth;
|
||||
unsigned int blockbytes, blockwidth, blockheight, blockdepth;
|
||||
Image_BlockSizeForEncoding(tex->format, &blockbytes, &blockwidth, &blockheight, &blockdepth);
|
||||
imgmem = blockbytes * (tex->width+blockwidth-1)/blockwidth * (tex->height+blockheight-1)/blockheight * (tex->depth+blockdepth-1)/blockdepth;
|
||||
switch((tex->flags & IF_TEXTYPEMASK)>>IF_TEXTYPESHIFT)
|
||||
{
|
||||
case PTI_2D: type = ""; break;
|
||||
|
@ -13777,7 +14027,7 @@ void Image_Formats_f(void)
|
|||
{
|
||||
size_t i;
|
||||
float bpp;
|
||||
int blockbytes, blockwidth, blockheight;
|
||||
int blockbytes, blockwidth, blockheight, blockdepth;
|
||||
|
||||
#ifdef GLQUAKE
|
||||
if (qrenderer == QR_OPENGL)
|
||||
|
@ -13822,6 +14072,8 @@ void Image_Formats_f(void)
|
|||
Con_Printf( " Non-Power-Of-Two: %s%s\n", sh_config.texture_non_power_of_two?S_COLOR_GREEN"Supported":(sh_config.texture_non_power_of_two_pic?S_COLOR_YELLOW"Limited":S_COLOR_RED"Unsupported"), sh_config.npot_rounddown?" (rounded down)":"");
|
||||
Con_Printf( " Block Size Padding: %s\n", sh_config.texture_allow_block_padding?S_COLOR_GREEN"Supported":S_COLOR_RED"Unsupported");
|
||||
Con_Printf( " Mipcap: %s\n", sh_config.can_mipcap?S_COLOR_GREEN"Supported":S_COLOR_RED"Unsupported");
|
||||
|
||||
Con_Printf( "\n Driver Support:\n");
|
||||
for (i = 0; i < PTI_MAX; i++)
|
||||
{
|
||||
switch(i)
|
||||
|
@ -13831,9 +14083,9 @@ void Image_Formats_f(void)
|
|||
default:
|
||||
break;
|
||||
}
|
||||
Image_BlockSizeForEncoding(i, &blockbytes, &blockwidth, &blockheight);
|
||||
bpp = blockbytes*8.0/(blockwidth*blockheight);
|
||||
Con_Printf("%20s: %s"S_COLOR_GRAY" (%.3g-bpp)\n", Image_FormatName(i), sh_config.texfmt[i]?S_COLOR_GREEN"Enabled":S_COLOR_RED"Disabled", bpp);
|
||||
Image_BlockSizeForEncoding(i, &blockbytes, &blockwidth, &blockheight, &blockdepth);
|
||||
bpp = blockbytes*8.0/(blockwidth*blockheight*blockdepth);
|
||||
Con_Printf("%20s: %s"S_COLOR_GRAY" (%s%.3g-bpp)\n", Image_FormatName(i), sh_config.texfmt[i]?S_COLOR_GREEN"Enabled":S_COLOR_RED"Disabled", (blockdepth!=1)?"3d, ":"", bpp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,16 +12,17 @@
|
|||
|
||||
#define ASTC_WITH_LDR //comment out this line to disable pure-LDR decoding (the hdr code can still be used).
|
||||
#define ASTC_WITH_HDR //comment out this line to disable HDR decoding.
|
||||
#define ASTC_WITH_HDRTEST //comment out this line to disable HDR decoding.
|
||||
#define ASTC_WITH_HDRTEST //comment out this line to disable checking for which profile is needed.
|
||||
//#define ASTC_WITH_3D
|
||||
|
||||
#ifdef ASTC_WITH_LDR
|
||||
ASTC_PUBLIC void ASTC_Decode_LDR8(unsigned char *in, unsigned char *out, int pixstride, int bw,int bh); //generates RGBA8 data (gives error colour for hdr blocks!)
|
||||
ASTC_PUBLIC void ASTC_Decode_LDR8(unsigned char *in, unsigned char *out, int pixstride/*outwidth*/, int layerstride/*outwidth*outheight*/, int bw,int bh,int bd); //generates RGBA8 data (gives error colour for hdr blocks!)
|
||||
#endif
|
||||
#ifdef ASTC_WITH_HDR
|
||||
ASTC_PUBLIC void ASTC_Decode_HDR(unsigned char *in, unsigned short *out, int pixstride, int bw,int bh); //generates RGBA16F data.
|
||||
ASTC_PUBLIC void ASTC_Decode_HDR(unsigned char *in, unsigned short *out, int pixstride/*outwidth*/, int layerstride/*outwidth*outheight*/, int bw,int bh,int bd); //generates RGBA16F data.
|
||||
#endif
|
||||
#ifdef ASTC_WITH_HDRTEST
|
||||
ASTC_PUBLIC int ASTC_BlocksAreHDR(unsigned char *in, size_t datasize, int bw, int bh, int bd); //returns true if n consecutive blocks require the HDR profile.
|
||||
ASTC_PUBLIC int ASTC_BlocksAreHDR(unsigned char *in, size_t datasize, int bw, int bh, int bd); //returns true if n consecutive blocks require the HDR profile (ie: detects when you need to soft-decode for drivers with partial support, as opposed to just always decompressing).
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -38,21 +39,24 @@
|
|||
#if defined(ASTC_WITH_LDR) || defined(ASTC_WITH_HDR)
|
||||
#define ASTC_WITH_DECODE
|
||||
#endif
|
||||
enum
|
||||
enum astc_status_e
|
||||
{
|
||||
ASTC_OKAY,
|
||||
ASTC_ERROR, //validation errors
|
||||
ASTC_UNSUPPORTED_FULL, //volume textures... Note: non-hdr profile errors are per-partition, so not an actual block error.
|
||||
ASTC_RESERVED, //reserved bits. basically an error but might not be in the future.
|
||||
//valid blocks
|
||||
ASTC_OKAY, //we can decode at least part of this normally (hdr endpoints may still result in per-endpoint errors).
|
||||
ASTC_VOID_LDR, //not an error - the block is a single LDR colour, with an RGBA16 colour in the last 8 bytes.
|
||||
ASTC_VOID_HDR //not an error - the block is a single HDR colour, with an RGBA16F colour in the last 8 bytes.
|
||||
ASTC_VOID_HDR, //not an error - the block is a single HDR colour, with an RGBA16F colour in the last 8 bytes.
|
||||
|
||||
//invalid blocks
|
||||
ASTC_ERROR, //validation errors
|
||||
ASTC_UNSUPPORTED, //basically just volume textures
|
||||
ASTC_RESERVED, //reserved bits. basically an error but might not be in the future.
|
||||
};
|
||||
struct astc_block_info
|
||||
{
|
||||
unsigned char *in; //the 16 bytes of the block
|
||||
char blocksize[3];
|
||||
unsigned char blocksize[3]; //block width, height, depth(1 for 2d).
|
||||
|
||||
char status; //0=regular block, -1=error, etc
|
||||
enum astc_status_e status; //block status/type.
|
||||
unsigned char dualplane; //two sets of weights instead of one.
|
||||
unsigned char ccs; //second set applies to this component
|
||||
|
||||
|
@ -68,9 +72,9 @@ struct astc_block_info
|
|||
unsigned short partindex; //used for deciding which partition each pixel belongs in
|
||||
struct astc_part
|
||||
{
|
||||
char mode; //endpoint modes
|
||||
unsigned char mode; //endpoint modes
|
||||
#ifdef ASTC_WITH_HDR
|
||||
char hdr; //endpoint colour mode - &1=rgb, &2=alpha
|
||||
unsigned char hdr; //endpoint colour mode - &1=rgb, &2=alpha
|
||||
#endif
|
||||
int ep[2][4];
|
||||
} part[4];
|
||||
|
@ -164,8 +168,42 @@ static void ASTC_ReadBlockMode(struct astc_block_info *b)
|
|||
b->precision = (s>>(9-3))&(1<<3);//P
|
||||
b->precision |= (s>>4)&1; //p0
|
||||
if (b->blocksize[2] != 1)
|
||||
{ //3d blocks have a different layout
|
||||
b->status = ASTC_UNSUPPORTED_FULL;
|
||||
{ //3d blocks have a different header layout
|
||||
#ifdef ASTC_WITH_3D
|
||||
if (s&3)
|
||||
{
|
||||
b->precision|=(s&3)<<1; //p2, p1
|
||||
b->wcount[0] = ((s>>5)&3)+2, b->wcount[1] = ((s>>7)&3)+2, b->wcount[2] = ((s>>2)&3)+2;
|
||||
}
|
||||
else
|
||||
{
|
||||
b->precision|=(s&0xc)>>1; //p2, p1
|
||||
if ((s&0x180)!=0x180)
|
||||
{
|
||||
b->dualplane = 0; //always single plane.
|
||||
b->precision &= 7; //clear the high precision bit (reused for 'b')
|
||||
if (!(s&0x180))
|
||||
b->wcount[0] = 6, b->wcount[1] = ((s>>9)&3)+2, b->wcount[2] = ((s>>5)&3)+2;
|
||||
else if (!(s&0x80))
|
||||
b->wcount[0] = ((s>>5)&3)+2, b->wcount[1] = 6, b->wcount[2] = ((s>>9)&3)+2;
|
||||
else
|
||||
b->wcount[0] = ((s>>5)&3)+2, b->wcount[1] = ((s>>9)&3)+2, b->wcount[2] = 6;
|
||||
}
|
||||
else if ((s&0x60)!=0x60)
|
||||
{
|
||||
if (!(s&0x60))
|
||||
b->wcount[0] = 6, b->wcount[1] = 2, b->wcount[2] = 2;
|
||||
else if (!(s&0x20))
|
||||
b->wcount[0] = 2, b->wcount[1] = 6, b->wcount[2] = 2;
|
||||
else //40
|
||||
b->wcount[0] = 2, b->wcount[1] = 2, b->wcount[2] = 6;
|
||||
}
|
||||
else
|
||||
b->status = ASTC_RESERVED; //reserved (or void extent, but those were handled above)
|
||||
}
|
||||
#else
|
||||
b->status = ASTC_UNSUPPORTED;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1314,16 +1352,22 @@ static int ASTC_ChoosePartition(int seed, int x, int y, int z, int partitions, i
|
|||
#ifdef ASTC_WITH_LDR
|
||||
//Spits out 8-bit RGBA data for a single block. Any HDR blocks will result in the error colour.
|
||||
//sRGB can be applied by the caller, if needed.
|
||||
ASTC_PUBLIC void ASTC_Decode_LDR8(unsigned char *in, unsigned char *out, int pixstride, int bw, int bh)
|
||||
ASTC_PUBLIC void ASTC_Decode_LDR8(unsigned char *in, unsigned char *out, int pixstride, int layerstride, int bw, int bh, int bd)
|
||||
{
|
||||
struct astc_block_info b;
|
||||
int x, y;
|
||||
int stride = pixstride*4;
|
||||
#ifdef ASTC_WITH_3D
|
||||
int z;
|
||||
layerstride = layerstride*4-(stride*bh);
|
||||
#else
|
||||
if (bd != 1)
|
||||
return; //error!
|
||||
#endif
|
||||
b.in = in;
|
||||
b.blocksize[0] = bw;
|
||||
b.blocksize[1] = bh;
|
||||
b.blocksize[2] = 1;
|
||||
|
||||
b.blocksize[2] = bd;
|
||||
ASTC_ReadBlockMode(&b);
|
||||
|
||||
if (b.status == ASTC_VOID_LDR)
|
||||
|
@ -1347,13 +1391,19 @@ ASTC_PUBLIC void ASTC_Decode_LDR8(unsigned char *in, unsigned char *out, int pix
|
|||
|
||||
if (b.status == ASTC_OKAY)
|
||||
{
|
||||
#define N b.wcount[0]
|
||||
#define M b.wcount[1]
|
||||
int s1=1<<b.dualplane,s2=N<<b.dualplane; //values for 2d blocks (3d blocks will override)
|
||||
int s3=((bd!=1?N*M:0)+N+1)<<b.dualplane; //small variation for 3d blocks.
|
||||
|
||||
int smallblock = (b.blocksize[0]*b.blocksize[1]*b.blocksize[2])<31;
|
||||
int ds = (1024+b.blocksize[0]/2)/(b.blocksize[0]-1);
|
||||
int dt = (1024+b.blocksize[1]/2)/(b.blocksize[1]-1);
|
||||
int planes = 1<<b.dualplane, wstride = b.wcount[0]*planes;
|
||||
int s, t, v0, w, w00,w01,w10,w11;
|
||||
int fs, s, ds = (1024+b.blocksize[0]/2)/(b.blocksize[0]-1);
|
||||
int ft, t, dt = (1024+b.blocksize[1]/2)/(b.blocksize[1]-1);
|
||||
#ifdef ASTC_WITH_3D
|
||||
int fr, r, dr = (1024+b.blocksize[2]/2)/(b.blocksize[2]-1);
|
||||
#endif
|
||||
int v0, w, w00,w01,w10,w11;
|
||||
struct astc_part *p;
|
||||
//int dr = (1024+b.bd/2)/(b.bd-1);
|
||||
|
||||
#ifdef ASTC_WITH_HDR
|
||||
for (x = 0; x < b.partitions; x++)
|
||||
|
@ -1367,26 +1417,73 @@ ASTC_PUBLIC void ASTC_Decode_LDR8(unsigned char *in, unsigned char *out, int pix
|
|||
}
|
||||
#endif
|
||||
|
||||
//for (z = 0; z < bd; z++, out += layerstride-stride*bh)
|
||||
#ifdef ASTC_WITH_3D
|
||||
for (z = 0; z < bd; z++, out += layerstride-stride*bh)
|
||||
#endif
|
||||
{
|
||||
//r = ((dr*z)*(b.nweights[2]-1)+32)>>6;
|
||||
#ifdef ASTC_WITH_3D
|
||||
r = ((dr*z)*(b.wcount[2]-1)+32)>>6;
|
||||
fr=r&0xf;
|
||||
#endif
|
||||
for (y = 0; y < bh; y++, out += stride)
|
||||
{
|
||||
t = ((dt*y)*(b.wcount[1]-1)+32)>>6;
|
||||
ft=t&0xf;
|
||||
for (x = 0; x < bw; x++)
|
||||
{
|
||||
p = &b.part[ASTC_ChoosePartition(b.partindex, x,y,0, b.partitions, smallblock)];
|
||||
s = ((ds*x)*(b.wcount[0]-1)+32)>>6;
|
||||
w11 = ((s&0xf)*(t&0xf)+8) >> 4;
|
||||
w10 = (t&0xf) - w11;
|
||||
w01 = (s&0xf) - w11;
|
||||
w00 = 16 - (s&0xf) - (t&0xf) + w11;
|
||||
fs=s&0xf;
|
||||
#ifdef ASTC_WITH_3D
|
||||
if (bd != 1)
|
||||
{ //3d blocks use simplex interpolation instead of 8-way interpolation. its easier for hardware but more cycles for us.
|
||||
if (fs>fr)
|
||||
{ //figure out which weights/factors to use.
|
||||
if (ft>fr)
|
||||
{
|
||||
if (fs>ft)
|
||||
s1=1, s2=N, w00=16-fs, w01=fs-ft, w10=ft-fr, w11=fr;
|
||||
else
|
||||
s1=N, s2=1, w00=16-ft, w01=ft-fs, w10=fs-fr, w11=fr;
|
||||
}
|
||||
else
|
||||
s1=1, s2=N*M, w00=16-fs, w01=fs-fr, w10=fr-ft, w11=ft;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fs>ft)
|
||||
s1=N*M, s2=1, w00=16-fr, w01=fr-fs, w10=fs-ft, w11=ft;
|
||||
else
|
||||
{
|
||||
if (ft>fr)
|
||||
s1=N, s2=N*M, w00=16-ft, w01=ft-fr, w10=fr-fs, w11=fs;
|
||||
else
|
||||
s1=N*M, s2=N, w00=16-fr, w01=fr-ft, w10=ft-fs, w11=fs;
|
||||
}
|
||||
}
|
||||
|
||||
v0 = (((s>>4))<<b.dualplane)+(((t>>4))*wstride);
|
||||
s1 <<= b.dualplane;
|
||||
s2 <<= b.dualplane;
|
||||
s2+=s1;
|
||||
//s3 = (N*M+N+1)<<b.dualplane;
|
||||
v0 = ((s>>4)+(t>>4)*N+(r>>4)*N*M) << b.dualplane;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
//s1 = 1<<b.dualplane;
|
||||
//s2 = (N)<<b.dualplane;
|
||||
//s3 = (N+1)<<b.dualplane;
|
||||
w11 = (fs*ft+8) >> 4;
|
||||
w10 = ft - w11;
|
||||
w01 = fs - w11;
|
||||
w00 = 16 - fs - ft + w11;
|
||||
v0 = ((s>>4)+(t>>4)*N) << b.dualplane;
|
||||
}
|
||||
w = ( w00*b.weights[v0] +
|
||||
w01*b.weights[v0+planes] +
|
||||
w10*b.weights[v0+wstride] +
|
||||
w11*b.weights[v0+planes+wstride] + 8) >> 4;
|
||||
w01*b.weights[v0+s1] +
|
||||
w10*b.weights[v0+s2] +
|
||||
w11*b.weights[v0+s3] + 8) >> 4;
|
||||
out[(x<<2)+0] = ((64-w)*p->ep[0][0] + w*p->ep[1][0])>>6;
|
||||
out[(x<<2)+1] = ((64-w)*p->ep[0][1] + w*p->ep[1][1])>>6;
|
||||
out[(x<<2)+2] = ((64-w)*p->ep[0][2] + w*p->ep[1][2])>>6;
|
||||
|
@ -1396,9 +1493,9 @@ ASTC_PUBLIC void ASTC_Decode_LDR8(unsigned char *in, unsigned char *out, int pix
|
|||
{ //dual planes has a second set of weights that override a single channel
|
||||
v0++;
|
||||
w = ( w00*b.weights[v0] +
|
||||
w01*b.weights[v0+planes] +
|
||||
w10*b.weights[v0+wstride] +
|
||||
w11*b.weights[v0+planes+wstride] + 8) >> 4;
|
||||
w01*b.weights[v0+s1] +
|
||||
w10*b.weights[v0+s2] +
|
||||
w11*b.weights[v0+s3] + 8) >> 4;
|
||||
out[(x<<2)+b.ccs] = ((64-w)*p->ep[0][b.ccs] + w*p->ep[1][b.ccs])>>6;
|
||||
}
|
||||
}
|
||||
|
@ -1406,15 +1503,18 @@ ASTC_PUBLIC void ASTC_Decode_LDR8(unsigned char *in, unsigned char *out, int pix
|
|||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (y = 0; y < bh; y++, out += stride)
|
||||
for (x = 0; x < bw; x++)
|
||||
{
|
||||
out[(x<<2)+0] = 0xff;
|
||||
out[(x<<2)+1] = 0;
|
||||
out[(x<<2)+2] = 0xff;
|
||||
out[(x<<2)+3] = 0xff;
|
||||
}
|
||||
{ //error colour == magenta
|
||||
#ifdef ASTC_WITH_3D
|
||||
for (z = 0; z < bd; z++, out += layerstride)
|
||||
#endif
|
||||
for (y = 0; y < bh; y++, out += stride)
|
||||
for (x = 0; x < bw; x++)
|
||||
{
|
||||
out[(x<<2)+0] = 0xff;
|
||||
out[(x<<2)+1] = 0;
|
||||
out[(x<<2)+2] = 0xff;
|
||||
out[(x<<2)+3] = 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1457,15 +1557,22 @@ static unsigned short ASTC_GenHalffloat(int hdr, int rawval)
|
|||
}
|
||||
|
||||
//Spits out half-float RGBA data for a single block.
|
||||
ASTC_PUBLIC void ASTC_Decode_HDR(unsigned char *in, unsigned short *out, int pixstride, int bw, int bh)
|
||||
ASTC_PUBLIC void ASTC_Decode_HDR(unsigned char *in, unsigned short *out, int pixstride, int layerstride, int bw, int bh, int bd)
|
||||
{
|
||||
int x, y;
|
||||
int stride = pixstride*4;
|
||||
struct astc_block_info b;
|
||||
#ifdef ASTC_WITH_3D
|
||||
int z;
|
||||
layerstride = layerstride*4-(stride*bh);
|
||||
#else
|
||||
if (bd != 1)
|
||||
return; //error!
|
||||
#endif
|
||||
b.in = in;
|
||||
b.blocksize[0] = bw;
|
||||
b.blocksize[1] = bh;
|
||||
b.blocksize[2] = 1;
|
||||
b.blocksize[2] = bd;
|
||||
|
||||
ASTC_ReadBlockMode(&b);
|
||||
|
||||
|
@ -1503,13 +1610,19 @@ ASTC_PUBLIC void ASTC_Decode_HDR(unsigned char *in, unsigned short *out, int pix
|
|||
|
||||
if (b.status == ASTC_OKAY)
|
||||
{
|
||||
#define N b.wcount[0]
|
||||
#define M b.wcount[1]
|
||||
int s1=1<<b.dualplane,s2=N<<b.dualplane; //values for 2d blocks (3d blocks will override)
|
||||
int s3=((bd!=1?N*M:0)+N+1)<<b.dualplane; //small variation for 3d blocks.
|
||||
|
||||
int smallblock = (b.blocksize[0]*b.blocksize[1]*b.blocksize[2])<31;
|
||||
int ds = (1024+b.blocksize[0]/2)/(b.blocksize[0]-1);
|
||||
int dt = (1024+b.blocksize[1]/2)/(b.blocksize[1]-1);
|
||||
int planes = 1<<b.dualplane, wstride = b.wcount[0]*planes;
|
||||
int s, t, v0, w, w00,w01,w10,w11;
|
||||
int fs, s, ds = (1024+b.blocksize[0]/2)/(b.blocksize[0]-1);
|
||||
int ft, t, dt = (1024+b.blocksize[1]/2)/(b.blocksize[1]-1);
|
||||
#ifdef ASTC_WITH_3D
|
||||
int fr, r, dr = (1024+b.blocksize[2]/2)/(b.blocksize[2]-1);
|
||||
#endif
|
||||
int v0, w, w00,w01,w10,w11;
|
||||
struct astc_part *p;
|
||||
//int dr = (1024+b.bd/2)/(b.bd-1);
|
||||
|
||||
for (x = 0; x < b.partitions; x++)
|
||||
{ //we need to do a little extra processing here
|
||||
|
@ -1528,26 +1641,74 @@ ASTC_PUBLIC void ASTC_Decode_HDR(unsigned char *in, unsigned short *out, int pix
|
|||
}
|
||||
}
|
||||
|
||||
//for (z = 0; z < bd; z++, out += layerstride-stride*bh)
|
||||
#ifdef ASTC_WITH_3D
|
||||
for (z = 0; z < bd; z++, out += layerstride)
|
||||
#endif
|
||||
{
|
||||
//r = ((dr*z)*(b.nweights[2]-1)+32)>>6;
|
||||
#ifdef ASTC_WITH_3D
|
||||
r = ((dr*z)*(b.wcount[2]-1)+32)>>6;
|
||||
fr=s&0xf;
|
||||
#endif
|
||||
for (y = 0; y < bh; y++, out += stride)
|
||||
{
|
||||
t = ((dt*y)*(b.wcount[1]-1)+32)>>6;
|
||||
ft=s&0xf;
|
||||
for (x = 0; x < bw; x++)
|
||||
{
|
||||
p = &b.part[ASTC_ChoosePartition(b.partindex, x,y,0, b.partitions, smallblock)];
|
||||
s = ((ds*x)*(b.wcount[0]-1)+32)>>6;
|
||||
w11 = ((s&0xf)*(t&0xf)+8) >> 4;
|
||||
w10 = (t&0xf) - w11;
|
||||
w01 = (s&0xf) - w11;
|
||||
w00 = 16 - (s&0xf) - (t&0xf) + w11;
|
||||
fs=s&0xf;
|
||||
#ifdef ASTC_WITH_3D
|
||||
if (bd != 1)
|
||||
{ //3d blocks use simplex interpolation instead of 8-way interpolation. its easier for hardware but more cycles for us.
|
||||
if (fs>fr)
|
||||
{ //figure out which weights/factors to use.
|
||||
if (ft>fr)
|
||||
{
|
||||
if (fs>ft)
|
||||
s1=1, s2=N, w00=16-fs, w01=fs-ft, w10=ft-fr, w11=fr;
|
||||
else
|
||||
s1=N, s2=1, w00=16-ft, w01=ft-fs, w10=fs-fr, w11=fr;
|
||||
}
|
||||
else
|
||||
s1=1, s2=N*M, w00=16-fs, w01=fs-fr, w10=fr-ft, w11=ft;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fs>ft)
|
||||
s1=N*M, s2=1, w00=16-fr, w01=fr-fs, w10=fs-ft, w11=ft;
|
||||
else
|
||||
{
|
||||
if (ft>fr)
|
||||
s1=N, s2=N*M, w00=16-ft, w01=ft-fr, w10=fr-fs, w11=fs;
|
||||
else
|
||||
s1=N*M, s2=N, w00=16-fr, w01=fr-ft, w10=ft-fs, w11=fs;
|
||||
}
|
||||
}
|
||||
|
||||
v0 = (((s>>4))<<b.dualplane)+(((t>>4))*wstride);
|
||||
s1 <<= b.dualplane;
|
||||
s2 <<= b.dualplane;
|
||||
s2+=s1;
|
||||
//s3 = (N*M+N+1)<<b.dualplane;
|
||||
v0 = (((s>>4))+((t>>4)*N)+(r>>4)*N*M) << b.dualplane;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
//s1 = 1<<b.dualplane;
|
||||
//s2 = (N)<<b.dualplane;
|
||||
//s3 = (N+1)<<b.dualplane;
|
||||
w11 = (fs*ft+8) >> 4;
|
||||
w10 = ft - w11;
|
||||
w01 = fs - w11;
|
||||
w00 = 16 - fs - ft + w11;
|
||||
|
||||
v0 = (((s>>4))+(t>>4)*N) << b.dualplane;
|
||||
}
|
||||
w = ( w00*b.weights[v0] +
|
||||
w01*b.weights[v0+planes] +
|
||||
w10*b.weights[v0+wstride] +
|
||||
w11*b.weights[v0+planes+wstride] + 8) >> 4;
|
||||
w01*b.weights[v0+s1] +
|
||||
w10*b.weights[v0+s2] +
|
||||
w11*b.weights[v0+s3] + 8) >> 4;
|
||||
out[(x<<2)+0] = ASTC_GenHalffloat(p->hdr&1, ((64-w)*p->ep[0][0] + w*p->ep[1][0])>>6);
|
||||
out[(x<<2)+1] = ASTC_GenHalffloat(p->hdr&1, ((64-w)*p->ep[0][1] + w*p->ep[1][1])>>6);
|
||||
out[(x<<2)+2] = ASTC_GenHalffloat(p->hdr&1, ((64-w)*p->ep[0][2] + w*p->ep[1][2])>>6);
|
||||
|
@ -1557,9 +1718,9 @@ ASTC_PUBLIC void ASTC_Decode_HDR(unsigned char *in, unsigned short *out, int pix
|
|||
{ //dual planes has a second set of weights that override a single channel
|
||||
v0++;
|
||||
w = ( w00*b.weights[v0] +
|
||||
w01*b.weights[v0+planes] +
|
||||
w10*b.weights[v0+wstride] +
|
||||
w11*b.weights[v0+planes+wstride] + 8) >> 4;
|
||||
w01*b.weights[v0+s1] +
|
||||
w10*b.weights[v0+s2] +
|
||||
w11*b.weights[v0+s3] + 8) >> 4;
|
||||
out[(x<<2)+b.ccs] = ASTC_GenHalffloat(p->hdr&(1<<b.ccs), ((64-w)*p->ep[0][b.ccs] + w*p->ep[1][b.ccs])>>6);
|
||||
}
|
||||
}
|
||||
|
@ -1567,15 +1728,18 @@ ASTC_PUBLIC void ASTC_Decode_HDR(unsigned char *in, unsigned short *out, int pix
|
|||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (y = 0; y < bh; y++, out += stride)
|
||||
for (x = 0; x < bw; x++)
|
||||
{
|
||||
out[(x<<2)+0] = 0;//0xf<<10;
|
||||
out[(x<<2)+1] = 0;
|
||||
out[(x<<2)+2] = 0;//0xf<<10;
|
||||
out[(x<<2)+3] = 0xf<<10;
|
||||
}
|
||||
{ //error colour == magenta
|
||||
#ifdef ASTC_WITH_3D
|
||||
for (z = 0; z < bd; z++, out += layerstride)
|
||||
#endif
|
||||
for (y = 0; y < bh; y++, out += stride)
|
||||
for (x = 0; x < bw; x++)
|
||||
{
|
||||
out[(x<<2)+0] = 0xf<<10;
|
||||
out[(x<<2)+1] = 0;
|
||||
out[(x<<2)+2] = 0xf<<10;
|
||||
out[(x<<2)+3] = 0xf<<10;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -330,7 +330,9 @@ static void J_KillAll(void)
|
|||
#endif
|
||||
|
||||
#if SDL_MAJOR_VERSION >= 2
|
||||
unsigned int MySDL_MapKey(unsigned int sdlkey)
|
||||
//FIXME: switch to scancodes rather than keysyms
|
||||
//use SDL_GetKeyName(SDL_GetKeyFromScancode(quaketosdl[qkey])) for keybinds menu
|
||||
unsigned int MySDL_MapKey(SDL_Keycode sdlkey)
|
||||
{
|
||||
switch(sdlkey)
|
||||
{
|
||||
|
@ -740,8 +742,10 @@ static unsigned int tbl_sdltoquakemouse[] =
|
|||
K_MOUSE1,
|
||||
K_MOUSE3,
|
||||
K_MOUSE2,
|
||||
#if SDL_MAJOR_VERSION < 2
|
||||
K_MWHEELUP,
|
||||
K_MWHEELDOWN,
|
||||
#endif
|
||||
K_MOUSE4,
|
||||
K_MOUSE5,
|
||||
K_MOUSE6,
|
||||
|
@ -915,11 +919,38 @@ void Sys_SendKeyEvents(void)
|
|||
IN_MouseMove(event.motion.which, false, event.motion.xrel, event.motion.yrel, 0, 0);
|
||||
break;
|
||||
|
||||
#if SDL_MAJOR_VERSION >= 2
|
||||
case SDL_MOUSEWHEEL:
|
||||
if (event.wheel.direction == SDL_MOUSEWHEEL_FLIPPED)
|
||||
event.wheel.y *= -1;
|
||||
for (; event.wheel.y > 0; event.wheel.y--)
|
||||
{
|
||||
IN_KeyEvent(event.button.which, true, K_MWHEELUP, 0);
|
||||
IN_KeyEvent(event.button.which, false, K_MWHEELUP, 0);
|
||||
}
|
||||
for (; event.wheel.y < 0; event.wheel.y++)
|
||||
{
|
||||
IN_KeyEvent(event.button.which, true, K_MWHEELDOWN, 0);
|
||||
IN_KeyEvent(event.button.which, false, K_MWHEELDOWN, 0);
|
||||
}
|
||||
/* for (; event.wheel.x > 0; event.wheel.x--)
|
||||
{
|
||||
IN_KeyEvent(event.button.which, true, K_MWHEELRIGHT, 0);
|
||||
IN_KeyEvent(event.button.which, false, K_MWHEELRIGHT, 0);
|
||||
}
|
||||
for (; event.wheel.x < 0; event.wheel.x++)
|
||||
{
|
||||
IN_KeyEvent(event.button.which, true, K_MWHEELLEFT, 0);
|
||||
IN_KeyEvent(event.button.which, false, K_MWHEELLEFT, 0);
|
||||
}*/
|
||||
break;
|
||||
#endif
|
||||
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
#if SDL_MAJOR_VERSION >= 2
|
||||
if (event.button.which == SDL_TOUCH_MOUSEID)
|
||||
break; //ignore legacy touch events.
|
||||
break; //ignore legacy touch events. SDL_FINGER* events above will handle it (for multitouch)
|
||||
#endif
|
||||
//Hmm. SDL allows for 255 buttons, but only defines 5...
|
||||
if (event.button.button > sizeof(tbl_sdltoquakemouse)/sizeof(tbl_sdltoquakemouse[0]))
|
||||
|
|
|
@ -60,10 +60,7 @@ qboolean keydown[K_MAX];
|
|||
char *releasecommand[K_MAX][MAX_INDEVS]; //this is the console command to be invoked when the key is released. should free it.
|
||||
qbyte releasecommandlevel[K_MAX][MAX_INDEVS]; //and this is the cbuf level it is to be run at.
|
||||
|
||||
static void QDECL Con_Selectioncolour_Callback(struct cvar_s *var, char *oldvalue);
|
||||
|
||||
extern cvar_t con_displaypossibilities;
|
||||
cvar_t con_selectioncolour = CVARFC("con_selectioncolour", "0", CVAR_RENDERERCALLBACK, Con_Selectioncolour_Callback);
|
||||
cvar_t con_echochat = CVAR("con_echochat", "0");
|
||||
extern cvar_t cl_chatmode;
|
||||
|
||||
|
@ -659,14 +656,6 @@ int Con_ExecuteLine(console_t *con, const char *line)
|
|||
return true;
|
||||
}
|
||||
|
||||
vec3_t sccolor;
|
||||
|
||||
static void QDECL Con_Selectioncolour_Callback(struct cvar_s *var, char *oldvalue)
|
||||
{
|
||||
if (qrenderer != QR_NONE)
|
||||
SCR_StringToRGB(var->string, sccolor, 1);
|
||||
}
|
||||
|
||||
qboolean Key_GetConsoleSelectionBox(console_t *con, int *sx, int *sy, int *ex, int *ey)
|
||||
{
|
||||
*sx = *sy = *ex = *ey = 0;
|
||||
|
@ -2866,13 +2855,12 @@ void Key_Init (void)
|
|||
//
|
||||
// register our functions
|
||||
//
|
||||
Cmd_AddCommandAD ("bind",Key_Bind_f, Key_Bind_c, NULL);
|
||||
Cmd_AddCommandAD ("bind",Key_Bind_f, Key_Bind_c, "Changes the action associated with each keyboard button. Use eg \"bind ctrl+shift+alt+k kill\" for special modifiers (should be used only after more basic modifiers).");
|
||||
Cmd_AddCommand ("in_bind",Key_Bind_f);
|
||||
Cmd_AddCommand ("bindlevel",Key_Bind_f);
|
||||
Cmd_AddCommandAD ("unbind",Key_Unbind_f, Key_Bind_c, NULL);
|
||||
Cmd_AddCommand ("unbindall",Key_Unbindall_f);
|
||||
Cmd_AddCommandD ("unbindall",Key_Unbindall_f, "A dangerous command that forgets ALL your key settings. For use only in default.cfg.");
|
||||
|
||||
Cvar_Register (&con_selectioncolour, "Console variables");
|
||||
Cvar_Register (&con_echochat, "Console variables");
|
||||
}
|
||||
|
||||
|
|
|
@ -207,6 +207,7 @@ static qboolean pkg_updating; //when flagged, further changes are blocked until
|
|||
#else
|
||||
static const qboolean pkg_updating = false;
|
||||
#endif
|
||||
static qboolean pm_packagesinstalled;
|
||||
|
||||
//FIXME: these are allocated for the life of the exe. changing basedir should purge the list.
|
||||
static int numdownloadablelists = 0;
|
||||
|
@ -2459,7 +2460,15 @@ static void PM_PackageEnabled(package_t *p)
|
|||
continue;
|
||||
COM_FileExtension(dep->name, ext, sizeof(ext));
|
||||
if (!stricmp(ext, "pak") || !stricmp(ext, "pk3"))
|
||||
FS_ReloadPackFiles();
|
||||
{
|
||||
if (pm_packagesinstalled)
|
||||
{
|
||||
pm_packagesinstalled = false;
|
||||
FS_ChangeGame(fs_manifest, true, false);
|
||||
}
|
||||
else
|
||||
FS_ReloadPackFiles();
|
||||
}
|
||||
#ifdef PLUGINS
|
||||
if ((p->flags & DPF_PLUGIN) && !Q_strncasecmp(dep->name, PLUGINPREFIX, strlen(PLUGINPREFIX)))
|
||||
Cmd_ExecuteString(va("plug_load %s\n", dep->name), RESTRICT_LOCAL);
|
||||
|
@ -2533,29 +2542,31 @@ static int QDECL PM_ExtractFiles(const char *fname, qofs_t fsize, time_t mtime,
|
|||
}
|
||||
|
||||
static void PM_StartADownload(void);
|
||||
//callback from PM_StartADownload
|
||||
static void PM_Download_Got(struct dl_download *dl)
|
||||
typedef struct
|
||||
{
|
||||
char native[MAX_OSPATH];
|
||||
qboolean successful = dl->status == DL_FINISHED;
|
||||
package_t *p;
|
||||
char *tempname = dl->user_ctx;
|
||||
const enum fs_relative temproot = dl->user_num;
|
||||
qboolean successful;
|
||||
char *tempname; //z_strduped string, so needs freeing.
|
||||
enum fs_relative temproot;
|
||||
char localname[256];
|
||||
char url[256];
|
||||
} pmdownloadedinfo_t;
|
||||
//callback from PM_StartADownload
|
||||
static void PM_Download_Got(int iarg, void *data)
|
||||
{
|
||||
pmdownloadedinfo_t *info = data;
|
||||
char native[MAX_OSPATH];
|
||||
qboolean successful = info->successful;
|
||||
package_t *p;
|
||||
char *tempname = info->tempname;
|
||||
const enum fs_relative temproot = info->temproot;
|
||||
|
||||
for (p = availablepackages; p ; p=p->next)
|
||||
{
|
||||
if (p->download == dl)
|
||||
if (p == info->p)
|
||||
break;
|
||||
}
|
||||
|
||||
if (dl->file)
|
||||
{
|
||||
if (!VFS_CLOSE(dl->file))
|
||||
successful = false;
|
||||
dl->file = NULL;
|
||||
}
|
||||
else
|
||||
successful = false;
|
||||
pm_packagesinstalled=true;
|
||||
|
||||
if (p)
|
||||
{
|
||||
|
@ -2566,7 +2577,7 @@ static void PM_Download_Got(struct dl_download *dl)
|
|||
|
||||
if (!successful)
|
||||
{
|
||||
Con_Printf("Couldn't download %s (from %s)\n", p->name, dl->url);
|
||||
Con_Printf("Couldn't download %s (from %s)\n", p->name, info->url);
|
||||
FS_Remove (tempname, temproot);
|
||||
Z_Free(tempname);
|
||||
PM_StartADownload();
|
||||
|
@ -2732,12 +2743,43 @@ static void PM_Download_Got(struct dl_download *dl)
|
|||
Con_Printf("menu_download: %s has no filename info\n", p->name);
|
||||
}
|
||||
else
|
||||
Con_Printf("menu_download: Can't figure out where %s came from (url: %s)\n", dl->localname, dl->url);
|
||||
Con_Printf("menu_download: Can't figure out where %s came from (url: %s)\n", info->localname, info->url);
|
||||
|
||||
FS_Remove (tempname, temproot);
|
||||
Z_Free(tempname);
|
||||
PM_StartADownload();
|
||||
}
|
||||
static void PM_Download_PreliminaryGot(struct dl_download *dl)
|
||||
{ //this function is annoying.
|
||||
//we're on the mainthread, but we might still be waiting for some other thread to complete
|
||||
//there could be loads of stuff on the callstack. lots of stuff that could get annoyed if we're restarting the entire filesystem, for instance.
|
||||
//so set up a SECOND callback using a different mechanism...
|
||||
|
||||
pmdownloadedinfo_t info;
|
||||
info.tempname = dl->user_ctx;
|
||||
info.temproot = dl->user_num;
|
||||
|
||||
Q_strncpyz(info.url, dl->url, sizeof(info.url));
|
||||
Q_strncpyz(info.localname, dl->localname, sizeof(info.localname));
|
||||
|
||||
for (info.p = availablepackages; info.p ; info.p=info.p->next)
|
||||
{
|
||||
if (info.p->download == dl)
|
||||
break;
|
||||
}
|
||||
|
||||
info.successful = (dl->status == DL_FINISHED);
|
||||
if (dl->file)
|
||||
{
|
||||
if (!VFS_CLOSE(dl->file))
|
||||
info.successful = false;
|
||||
dl->file = NULL;
|
||||
}
|
||||
else
|
||||
info.successful = false;
|
||||
|
||||
Cmd_AddTimer(0, PM_Download_Got, 0, &info, sizeof(info));
|
||||
}
|
||||
|
||||
static char *PM_GetTempName(package_t *p)
|
||||
{
|
||||
|
@ -2956,6 +2998,16 @@ int PM_IsApplying(qboolean listsonly)
|
|||
}
|
||||
|
||||
#ifdef WEBCLIENT
|
||||
static void PM_DownloadsCompleted(int iarg, void *data)
|
||||
{ //if something installed, then make sure everything is reconfigured properly.
|
||||
if (pm_packagesinstalled)
|
||||
{
|
||||
pm_packagesinstalled = false;
|
||||
FS_ChangeGame(fs_manifest, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//looks for the next package that needs downloading, and grabs it
|
||||
static void PM_StartADownload(void)
|
||||
{
|
||||
|
@ -3070,7 +3122,7 @@ static void PM_StartADownload(void)
|
|||
|
||||
if (tmpfile)
|
||||
{
|
||||
p->download = HTTP_CL_Get(mirror, NULL, PM_Download_Got);
|
||||
p->download = HTTP_CL_Get(mirror, NULL, PM_Download_PreliminaryGot);
|
||||
if (!p->download)
|
||||
Con_Printf("Unable to download %s\n", p->name);
|
||||
}
|
||||
|
@ -3100,6 +3152,9 @@ static void PM_StartADownload(void)
|
|||
}
|
||||
}
|
||||
|
||||
if (pkg_updating && !downloading)
|
||||
Cmd_AddTimer(0, PM_DownloadsCompleted, 0, NULL, 0);
|
||||
|
||||
//clear the updating flag once there's no more activity needed
|
||||
pkg_updating = downloading;
|
||||
}
|
||||
|
@ -3244,8 +3299,12 @@ void PM_ApplyChanges(void)
|
|||
//and flag any new/updated ones for a download
|
||||
for (p = availablepackages; p ; p=p->next)
|
||||
{
|
||||
if ((p->flags&DPF_ALLMARKED) && !(p->flags&DPF_ENABLED) && !p->download)
|
||||
p->trymirrors = ~0u;
|
||||
if (!p->download)
|
||||
if (((p->flags & DPF_MANIMARKED) && !(p->flags&DPF_PRESENT)) || //satisfying a manifest merely requires that it be present, not actually enabled.
|
||||
((p->flags&DPF_MARKED) && !(p->flags&DPF_ENABLED))) //actually enabled stuff requires actual enablement
|
||||
{
|
||||
p->trymirrors = ~0u;
|
||||
}
|
||||
}
|
||||
PM_StartADownload(); //and try to do those downloads.
|
||||
#else
|
||||
|
@ -4127,6 +4186,7 @@ typedef struct {
|
|||
char pathprefix[MAX_QPATH];
|
||||
int downloadablessequence;
|
||||
char titletext[128];
|
||||
char applymessage[128]; //so we can change its text to give it focus
|
||||
qboolean populated;
|
||||
} dlmenu_t;
|
||||
|
||||
|
@ -4646,6 +4706,13 @@ static void MD_Download_UpdateStatus(struct emenu_s *m)
|
|||
else
|
||||
Q_snprintfz(info->titletext, sizeof(info->titletext), "Downloads (+%u -%u)", addpackages, rempackages);
|
||||
|
||||
if (pkg_updating)
|
||||
Q_snprintfz(info->applymessage, sizeof(info->applymessage), "Apply (please wait)");
|
||||
else if (addpackages || rempackages)
|
||||
Q_snprintfz(info->applymessage, sizeof(info->applymessage), "%sApply (+%u -%u)", ((int)(realtime*4)&3)?"^a":"", addpackages, rempackages);
|
||||
else
|
||||
Q_snprintfz(info->applymessage, sizeof(info->applymessage), "Apply");
|
||||
|
||||
if (!info->populated)
|
||||
{
|
||||
for (i = 0; i < numdownloadablelists; i++)
|
||||
|
@ -4660,7 +4727,7 @@ static void MD_Download_UpdateStatus(struct emenu_s *m)
|
|||
info->populated = true;
|
||||
MC_AddFrameStart(m, 48);
|
||||
y = 48;
|
||||
b = MC_AddCommand(m, 48, 320-16, y, "Apply", MD_ApplyDownloads);
|
||||
b = MC_AddCommand(m, 48, 320-16, y, info->applymessage, MD_ApplyDownloads);
|
||||
b->rightalign = false;
|
||||
b->common.tooltip = "Enable/Disable/Download/Delete packages to match any changes made (you will be prompted with a list of the changes that will be made).";
|
||||
y+=8;
|
||||
|
|
|
@ -697,7 +697,6 @@ void M_Menu_Audio_f (void)
|
|||
menubulk_t bulk[] = {
|
||||
MB_REDTEXT("Sound Options", true),
|
||||
MB_TEXT("^Ue080^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue082", true),
|
||||
MB_SPACING(8),
|
||||
MB_CONSOLECMD("Restart Sound", "snd_restart\n", "Restart audio systems and apply set options."),
|
||||
MB_SPACING(4),
|
||||
MB_COMBOCVAR("Output Device", snd_device, (const char**)info->outdevdescs, (const char**)info->outdevnames, "Choose which audio driver and device to use."),
|
||||
|
@ -927,6 +926,7 @@ const char *presetexec[] =
|
|||
"seta r_graphics 1;"
|
||||
"seta r_renderscale 1;"
|
||||
"seta gl_texture_anisotropic_filtering 0;"
|
||||
// end '286'
|
||||
|
||||
, // fast options (for deathmatch)
|
||||
"gl_texturemode ln;"
|
||||
|
@ -946,8 +946,10 @@ const char *presetexec[] =
|
|||
"r_lavastyle 1;"
|
||||
"r_nolightdir 0;"
|
||||
"seta gl_simpleitems 0;"
|
||||
// end fast
|
||||
|
||||
, //quakespasm-esque options (for singleplayer faithful).
|
||||
"gl_texturemode2d l.l;"
|
||||
"r_part_density 1;"
|
||||
"gl_polyblend 1;"
|
||||
"r_dynamic 2;"
|
||||
|
@ -973,6 +975,7 @@ const char *presetexec[] =
|
|||
"seta cl_deadbodyfilter 0;"
|
||||
"gl_texture_anisotropic_filtering 4;"
|
||||
"cl_fullpitch 1;maxpitch 90;seta minpitch -90;" //QS has cheaty viewpitch range. some maps require it.
|
||||
// end spasm
|
||||
|
||||
, //vanilla-esque options (for purists).
|
||||
"cl_fullpitch 0;maxpitch \"\";seta minpitch \"\";" //quakespasm is not vanilla
|
||||
|
@ -986,6 +989,7 @@ const char *presetexec[] =
|
|||
"gl_affinemodels 1;"
|
||||
"r_softwarebanding 1;" //ugly software banding.
|
||||
"r_part_classic_square 1;" //blocky baby!
|
||||
// end vanilla
|
||||
|
||||
, // normal (faithful) options, but with content replacement thrown in
|
||||
//#ifdef MINIMAL
|
||||
|
@ -1015,6 +1019,7 @@ const char *presetexec[] =
|
|||
"r_nolerp 0;"
|
||||
"r_noframegrouplerp 0;"
|
||||
"cl_fullpitch 1;maxpitch 90;seta minpitch -90;"
|
||||
//end normal
|
||||
|
||||
, // nice options
|
||||
// "r_stains 0.75;"
|
||||
|
@ -1033,6 +1038,7 @@ const char *presetexec[] =
|
|||
// "gl_detail 1;"
|
||||
"r_lightstylesmooth 1;"
|
||||
"r_deluxemapping 2;"
|
||||
//end 'nice'
|
||||
|
||||
, // realtime options
|
||||
"r_bloom 1;"
|
||||
|
@ -1043,6 +1049,7 @@ const char *presetexec[] =
|
|||
"r_shadow_realtime_world 1;"
|
||||
"gl_texture_anisotropic_filtering 16;"
|
||||
"vid_hardwaregamma 4;" //scene gamma
|
||||
//end 'realtime'
|
||||
};
|
||||
|
||||
typedef struct fpsmenuinfo_s
|
||||
|
@ -1050,18 +1057,21 @@ typedef struct fpsmenuinfo_s
|
|||
menucombo_t *preset;
|
||||
} fpsmenuinfo_t;
|
||||
|
||||
static void ApplyPreset (int presetnum)
|
||||
static void ApplyPreset (int presetnum, qboolean doreload)
|
||||
{
|
||||
int i;
|
||||
//this function is written backwards, to ensure things work properly in configs etc.
|
||||
|
||||
// TODO: work backwards and only set cvars once
|
||||
Cbuf_InsertText("\nfs_restart\nvid_reload\n", RESTRICT_LOCAL, true);
|
||||
if (doreload)
|
||||
{
|
||||
forcesaveprompt = true;
|
||||
Cbuf_InsertText("\nfs_restart\nvid_reload\n", RESTRICT_LOCAL, true);
|
||||
}
|
||||
for (i = presetnum; i >= 0; i--)
|
||||
{
|
||||
Cbuf_InsertText(presetexec[i], RESTRICT_LOCAL, true);
|
||||
}
|
||||
forcesaveprompt = true;
|
||||
}
|
||||
|
||||
void M_Menu_Preset_f (void)
|
||||
|
@ -1124,6 +1134,7 @@ void FPS_Preset_f (void)
|
|||
char *presetfname;
|
||||
char *arg = Cmd_Argv(1);
|
||||
int i;
|
||||
qboolean doreload = true;
|
||||
|
||||
if (!*arg)
|
||||
{
|
||||
|
@ -1131,13 +1142,21 @@ void FPS_Preset_f (void)
|
|||
return;
|
||||
}
|
||||
|
||||
presetfname = va("configs/preset_%s.cfg", arg);
|
||||
if (COM_FCheckExists(presetfname))
|
||||
if (!strncmp(arg, "builtin_", 8))
|
||||
{
|
||||
char buffer[MAX_OSPATH];
|
||||
COM_QuotedString(presetfname, buffer, sizeof(buffer), false);
|
||||
Cbuf_InsertText(va("\nexec %s\nfs_restart\n", buffer), RESTRICT_LOCAL, false);
|
||||
return;
|
||||
arg += 8;
|
||||
doreload = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
presetfname = va("configs/preset_%s.cfg", arg);
|
||||
if (COM_FCheckExists(presetfname))
|
||||
{
|
||||
char buffer[MAX_OSPATH];
|
||||
COM_QuotedString(presetfname, buffer, sizeof(buffer), false);
|
||||
Cbuf_InsertText(va("\nexec %s\nfs_restart\n", buffer), RESTRICT_LOCAL, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!stricmp("hdr", arg))
|
||||
|
@ -1263,7 +1282,7 @@ void FPS_Preset_f (void)
|
|||
{
|
||||
if (!stricmp(presetname[i], arg))
|
||||
{
|
||||
ApplyPreset(i);
|
||||
ApplyPreset(i, doreload);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -3863,7 +3882,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
|
|||
}
|
||||
if (shader->defaulttextures->base)
|
||||
{
|
||||
Draw_FunString(0, y, va("%s: %s (%s)", t, shader->defaulttextures->base->ident, shader->defaulttextures->base->subpath));
|
||||
Draw_FunString(0, y, va("%s: %s (%s)", t, shader->defaulttextures->base->ident, shader->defaulttextures->base->subpath?shader->defaulttextures->base->subpath:""));
|
||||
y+=8;
|
||||
R2D_Image(0, y, shader->defaulttextures->base->width, shader->defaulttextures->base->height, 0, 0, 1, 1, shader);
|
||||
}
|
||||
|
@ -4106,14 +4125,14 @@ static void Mods_Draw(int x, int y, struct menucustom_s *c, struct emenu_s *m)
|
|||
return;
|
||||
if (mod->manifest)
|
||||
{
|
||||
if (mousecursor_y >= y && mousecursor_y < y+8)
|
||||
if (m->selecteditem == (menuoption_t*)c)
|
||||
Draw_AltFunString(x, y, mod->manifest->formalname);
|
||||
else
|
||||
Draw_FunString(x, y, mod->manifest->formalname);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mousecursor_y >= y && mousecursor_y < y+8)
|
||||
if (m->selecteditem == (menuoption_t*)c)
|
||||
Draw_AltFunString(x, y, mod->gamedir);
|
||||
else
|
||||
Draw_FunString(x, y, mod->gamedir);
|
||||
|
@ -4161,8 +4180,8 @@ void M_Menu_Mods_f (void)
|
|||
for (i = 0; i<1 || Mods_GetMod(i); i++)
|
||||
{
|
||||
c = MC_AddCustom(menu, 64, 32+i*8, menu->data, i, NULL);
|
||||
if (!menu->cursoritem)
|
||||
menu->cursoritem = (menuoption_t*)c;
|
||||
// if (!menu->selecteditem)
|
||||
// menu->selecteditem = (menuoption_t*)c;
|
||||
c->common.height = 8;
|
||||
c->draw = Mods_Draw;
|
||||
c->key = Mods_Key;
|
||||
|
|
|
@ -1491,7 +1491,7 @@ static void QCBUILTIN PF_R_AddEntityMask(pubprogfuncs_t *prinst, struct globalva
|
|||
if (csqc_isdarkplaces)
|
||||
{
|
||||
//hopelessly inefficient version for compat with DP.
|
||||
maxe = *prinst->parms->sv_num_edicts;
|
||||
maxe = *prinst->parms->num_edicts;
|
||||
for (e=1; e < maxe; e++)
|
||||
{
|
||||
ent = (void*)EDICT_NUM_PB(prinst, e);
|
||||
|
@ -1522,7 +1522,7 @@ static void QCBUILTIN PF_R_AddEntityMask(pubprogfuncs_t *prinst, struct globalva
|
|||
}
|
||||
else
|
||||
{
|
||||
maxe = *prinst->parms->sv_num_edicts;
|
||||
maxe = *prinst->parms->num_edicts;
|
||||
for (e=1; e < maxe; e++)
|
||||
{
|
||||
ent = (void*)EDICT_NUM_PB(prinst, e);
|
||||
|
@ -3623,7 +3623,7 @@ void CSQC_ResetTrails(void)
|
|||
if (!prinst)
|
||||
return;
|
||||
|
||||
for (i = 0; i < *prinst->parms->sv_num_edicts; i++)
|
||||
for (i = 0; i < *prinst->parms->num_edicts; i++)
|
||||
{
|
||||
ent = (csqcedict_t*)EDICT_NUM_PB(prinst, i);
|
||||
ent->trailstate = NULL;
|
||||
|
@ -7917,9 +7917,12 @@ qboolean CSQC_Init (qboolean anycsqc, const char *csprogsname, unsigned int chec
|
|||
csqcprogparms.autocompile = PR_COMPILEIGNORE;//enum {PR_NOCOMPILE, PR_COMPILENEXIST, PR_COMPILECHANGED, PR_COMPILEALWAYS} autocompile;
|
||||
|
||||
csqcprogparms.gametime = &csqctime;
|
||||
#ifdef MULTITHREAD
|
||||
csqcprogparms.usethreadedgc = pr_gc_threaded.ival;
|
||||
#endif
|
||||
|
||||
csqcprogparms.sv_edicts = (struct edict_s **)&csqc_world.edicts;
|
||||
csqcprogparms.sv_num_edicts = &csqc_world.num_edicts;
|
||||
csqcprogparms.edicts = (struct edict_s **)&csqc_world.edicts;
|
||||
csqcprogparms.num_edicts = &csqc_world.num_edicts;
|
||||
|
||||
csqcprogparms.useeditor = QCEditor;//void (*useeditor) (char *filename, int line, int nump, char **parms);
|
||||
csqcprogparms.user = &csqc_world;
|
||||
|
|
|
@ -886,9 +886,9 @@ void QCBUILTIN PF_CL_uploadimage (pubprogfuncs_t *prinst, struct globalvars_s *p
|
|||
}
|
||||
else
|
||||
{
|
||||
unsigned int blockbytes, blockwidth, blockheight;
|
||||
unsigned int blockbytes, blockwidth, blockheight, blockdepth;
|
||||
//get format info
|
||||
Image_BlockSizeForEncoding(format, &blockbytes, &blockwidth, &blockheight);
|
||||
Image_BlockSizeForEncoding(format, &blockbytes, &blockwidth, &blockheight, &blockdepth);
|
||||
//round up as appropriate
|
||||
blockwidth = ((width+blockwidth-1)/blockwidth)*blockwidth;
|
||||
blockheight = ((height+blockheight-1)/blockheight)*blockheight;
|
||||
|
@ -1718,12 +1718,12 @@ void QCBUILTIN PF_menu_findchain (pubprogfuncs_t *prinst, struct globalvars_s *p
|
|||
menuedict_t *ent, *chain; //note, all edicts share the common header, but don't use it's fields!
|
||||
eval_t *val;
|
||||
|
||||
chain = (menuedict_t *) *prinst->parms->sv_edicts;
|
||||
chain = (menuedict_t *) *prinst->parms->edicts;
|
||||
|
||||
f = G_INT(OFS_PARM0)+prinst->fieldadjust;
|
||||
s = PR_GetStringOfs(prinst, OFS_PARM1);
|
||||
|
||||
for (i = 1; i < *prinst->parms->sv_num_edicts; i++)
|
||||
for (i = 1; i < *prinst->parms->num_edicts; i++)
|
||||
{
|
||||
ent = (menuedict_t *)EDICT_NUM_PB(prinst, i);
|
||||
if (ent->ereftype == ER_FREE)
|
||||
|
@ -1750,12 +1750,12 @@ void QCBUILTIN PF_menu_findchainfloat (pubprogfuncs_t *prinst, struct globalvars
|
|||
menuedict_t *ent, *chain; //note, all edicts share the common header, but don't use it's fields!
|
||||
eval_t *val;
|
||||
|
||||
chain = (menuedict_t *) *prinst->parms->sv_edicts;
|
||||
chain = (menuedict_t *) *prinst->parms->edicts;
|
||||
|
||||
f = G_INT(OFS_PARM0)+prinst->fieldadjust;
|
||||
s = G_FLOAT(OFS_PARM1);
|
||||
|
||||
for (i = 1; i < *prinst->parms->sv_num_edicts; i++)
|
||||
for (i = 1; i < *prinst->parms->num_edicts; i++)
|
||||
{
|
||||
ent = (menuedict_t*)EDICT_NUM_PB(prinst, i);
|
||||
if (ent->ereftype == ER_FREE)
|
||||
|
@ -1779,12 +1779,12 @@ void QCBUILTIN PF_menu_findchainflags (pubprogfuncs_t *prinst, struct globalvars
|
|||
menuedict_t *ent, *chain; //note, all edicts share the common header, but don't use it's fields!
|
||||
eval_t *val;
|
||||
|
||||
chain = (menuedict_t *) *prinst->parms->sv_edicts;
|
||||
chain = (menuedict_t *) *prinst->parms->edicts;
|
||||
|
||||
f = G_INT(OFS_PARM0)+prinst->fieldadjust;
|
||||
s = G_FLOAT(OFS_PARM1);
|
||||
|
||||
for (i = 1; i < *prinst->parms->sv_num_edicts; i++)
|
||||
for (i = 1; i < *prinst->parms->num_edicts; i++)
|
||||
{
|
||||
ent = (menuedict_t*)EDICT_NUM_PB(prinst, i);
|
||||
if (ent->ereftype == ER_FREE)
|
||||
|
@ -2985,9 +2985,12 @@ qboolean MP_Init (void)
|
|||
menuprogparms.autocompile = PR_COMPILEIGNORE;//PR_COMPILEEXISTANDCHANGED;//enum {PR_NOCOMPILE, PR_COMPILENEXIST, PR_COMPILECHANGED, PR_COMPILEALWAYS} autocompile;
|
||||
|
||||
menuprogparms.gametime = &menutime;
|
||||
#ifdef MULTITHREAD
|
||||
menuprogparms.usethreadedgc = pr_gc_threaded.ival;
|
||||
#endif
|
||||
|
||||
menuprogparms.sv_edicts = (struct edict_s **)&menu_edicts;
|
||||
menuprogparms.sv_num_edicts = &num_menu_edicts;
|
||||
menuprogparms.edicts = (struct edict_s **)&menu_edicts;
|
||||
menuprogparms.num_edicts = &num_menu_edicts;
|
||||
|
||||
menuprogparms.useeditor = QCEditor;//void (*useeditor) (char *filename, int line, int nump, char **parms);
|
||||
menuprogparms.user = &menu_world;
|
||||
|
|
|
@ -365,8 +365,8 @@ typedef enum
|
|||
WG_LOADER = 1,
|
||||
WG_COUNT = 2 //main and loaders
|
||||
} wgroup_t;
|
||||
void COM_AddWork(wgroup_t thread, void(*func)(void *ctx, void *data, size_t a, size_t b), void *ctx, void *data, size_t a, size_t b);
|
||||
void COM_InsertWork(wgroup_t tg, void(*func)(void *ctx, void *data, size_t a, size_t b), void *ctx, void *data, size_t a, size_t b);
|
||||
void COM_AddWork(wgroup_t thread, void(*func)(void *ctx, void *data, size_t a, size_t b), void *ctx, void *data, size_t a, size_t b); //low priority
|
||||
void COM_InsertWork(wgroup_t tg, void(*func)(void *ctx, void *data, size_t a, size_t b), void *ctx, void *data, size_t a, size_t b); //high priority
|
||||
qboolean COM_HasWork(void);
|
||||
void COM_WorkerFullSync(void);
|
||||
void COM_DestroyWorkerThread(void);
|
||||
|
|
|
@ -500,7 +500,7 @@ apic_t *R2D_LoadAtlasedPic(const char *name)
|
|||
}
|
||||
|
||||
if (!atlas.tex)
|
||||
atlas.tex = Image_CreateTexture(va("fte_atlas%i", atlasid), NULL, IF_NOMIPMAP);
|
||||
atlas.tex = Image_CreateTexture(va("fte_atlas%i", atlasid), NULL, IF_NOMIPMAP|IF_NOMIPMAP);
|
||||
if (!atlas.shader)
|
||||
{
|
||||
atlas.shader = R_RegisterShader(va("fte_atlas%i", atlasid), SUF_NONE,
|
||||
|
@ -1871,7 +1871,11 @@ texid_t R2D_RT_Configure(const char *id, int width, int height, uploadfmt_t rtfm
|
|||
|
||||
if (rtfmt)
|
||||
{
|
||||
tid->flags = (tid->flags & ~(IF_NEAREST|IF_LINEAR)) | (imageflags & (IF_NEAREST|IF_LINEAR));
|
||||
if (tid->flags != ((tid->flags & ~(IF_NEAREST|IF_LINEAR)) | (imageflags & (IF_NEAREST|IF_LINEAR))))
|
||||
{
|
||||
tid->flags = ((tid->flags & ~(IF_NEAREST|IF_LINEAR)) | (imageflags & (IF_NEAREST|IF_LINEAR)));
|
||||
tid->width = -1;
|
||||
}
|
||||
Image_Upload(tid, rtfmt, NULL, NULL, width, height, imageflags);
|
||||
tid->width = width;
|
||||
tid->height = height;
|
||||
|
|
|
@ -1429,6 +1429,19 @@ static void Surf_BuildLightMap (model_t *currentmodel, msurface_t *surf, int map
|
|||
{
|
||||
for (i=0 ; i<size*3 ; i++)
|
||||
blocklights[i] = r_fullbright.value*255*256;
|
||||
if (!surf->samples)
|
||||
{
|
||||
surf->cached_light[0] = d_lightstylevalue[0];
|
||||
surf->cached_colour[0] = cl_lightstyle[0].colourkey;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++)
|
||||
{
|
||||
surf->cached_light[maps] = d_lightstylevalue[surf->styles[maps]];
|
||||
surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colourkey;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!currentmodel->lightdata)
|
||||
{
|
||||
|
@ -1441,8 +1454,8 @@ static void Surf_BuildLightMap (model_t *currentmodel, msurface_t *surf, int map
|
|||
/*no samples, but map is otherwise lit = pure black*/
|
||||
for (i=0 ; i<size*3 ; i++)
|
||||
blocklights[i] = 0;
|
||||
surf->cached_light[0] = 0;
|
||||
surf->cached_colour[0] = 0;
|
||||
surf->cached_light[0] = d_lightstylevalue[0];
|
||||
surf->cached_colour[0] = cl_lightstyle[0].colourkey;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1556,8 +1569,19 @@ static void Surf_BuildLightMap (model_t *currentmodel, msurface_t *surf, int map
|
|||
{ //r_fullbright is meant to be a scaler.
|
||||
for (i=0 ; i<size ; i++)
|
||||
blocklights[i] = r_fullbright.value*255*256;
|
||||
surf->cached_light[0] = d_lightstylevalue[0];
|
||||
surf->cached_colour[0] = cl_lightstyle[0].colourkey;
|
||||
if (!surf->samples)
|
||||
{
|
||||
surf->cached_light[0] = d_lightstylevalue[0];
|
||||
surf->cached_colour[0] = cl_lightstyle[0].colourkey;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++)
|
||||
{
|
||||
surf->cached_light[maps] = d_lightstylevalue[surf->styles[maps]];
|
||||
surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colourkey;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!currentmodel->lightdata)
|
||||
{ //no scalers here.
|
||||
|
@ -1951,8 +1975,8 @@ void Surf_RenderDynamicLightmaps (msurface_t *fa)
|
|||
// check for lightmap modification
|
||||
if (!fa->samples)
|
||||
{
|
||||
if (fa->cached_light[0] != 0
|
||||
|| fa->cached_colour[0] != 0)
|
||||
if (fa->cached_light[0] != d_lightstylevalue[0]
|
||||
|| fa->cached_colour[0] != cl_lightstyle[0].colourkey)
|
||||
goto dynamic;
|
||||
}
|
||||
else
|
||||
|
@ -1994,8 +2018,8 @@ static void Surf_RenderDynamicLightmaps_Worker (model_t *wmodel, msurface_t *fa,
|
|||
// check for lightmap modification
|
||||
if (!fa->samples)
|
||||
{
|
||||
if (fa->cached_light[0] != 0
|
||||
|| fa->cached_colour[0] != 0)
|
||||
if (fa->cached_light[0] != d_lightstylevalue[0]
|
||||
|| fa->cached_colour[0] != cl_lightstyle[0].colourkey)
|
||||
goto dynamic;
|
||||
}
|
||||
else
|
||||
|
@ -3264,7 +3288,7 @@ void R_GenWorldEBO(void *ctx, void *data, size_t a, size_t b)
|
|||
pvs = es->wmodel->funcs.ClusterPVS(es->wmodel, es->cluster[1], &es->pvs, PVM_MERGE);
|
||||
}
|
||||
else
|
||||
pvs = es->wmodel->funcs.ClusterPVS(es->wmodel, es->cluster[0], &es->pvs, PVM_FAST);
|
||||
pvs = es->wmodel->funcs.ClusterPVS(es->wmodel, es->cluster[0], &es->pvs, PVM_REPLACE);
|
||||
|
||||
#if defined(Q2BSPS) || defined(Q3BSPS)
|
||||
if (es->wmodel->fromgame == fg_quake2 || es->wmodel->fromgame == fg_quake3)
|
||||
|
@ -3361,19 +3385,39 @@ void Surf_DrawWorld (void)
|
|||
#ifdef Q1BSPS
|
||||
else if (currentmodel->fromgame == fg_quake || currentmodel->fromgame == fg_halflife)
|
||||
{
|
||||
int i = cl_max_lightstyles;
|
||||
if (webostate && !webogenerating)
|
||||
for (i = 0; i < cl_max_lightstyles; i++)
|
||||
if (!webogenerating)
|
||||
{
|
||||
qboolean gennew = false;
|
||||
if (!webostate)
|
||||
gennew = true; //generate an initial one, if we can.
|
||||
if (!gennew && webostate)
|
||||
{
|
||||
if (webostate->lightstylevalues[i] != d_lightstylevalue[i])
|
||||
break;
|
||||
int i = cl_max_lightstyles;
|
||||
for (i = 0; i < cl_max_lightstyles; i++)
|
||||
{
|
||||
if (webostate->lightstylevalues[i] != d_lightstylevalue[i])
|
||||
{ //a lightstyle changed. something needs to be rebuilt. FIXME: should probably have a bitmask for whether the lightstyle is relevant...
|
||||
gennew = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (webostate && i == cl_max_lightstyles)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!webogenerating)
|
||||
|
||||
if (!gennew && webostate && (webostate->cluster[0] != r_viewcluster || webostate->cluster[1] != r_viewcluster2))
|
||||
{
|
||||
if (webostate->pvs.buffersize != currentmodel->pvsbytes || r_viewcluster2 != -1)
|
||||
gennew = true; //o.O
|
||||
else if (memcmp(webostate->pvs.buffer, webostate->wmodel->funcs.ClusterPVS(webostate->wmodel, r_viewcluster, NULL, PVM_FAST), currentmodel->pvsbytes))
|
||||
gennew = true;
|
||||
else
|
||||
{ //okay, so the pvs didn't change despite the clusters changing. this happens when using unvised maps or lots of func_detail
|
||||
//just hack the cluster numbers so we don't have to do the memcmp above repeatedly for no reason.
|
||||
webostate->cluster[0] = r_viewcluster;
|
||||
webostate->cluster[1] = r_viewcluster2;
|
||||
}
|
||||
}
|
||||
|
||||
if (gennew)
|
||||
{
|
||||
int i;
|
||||
if (!currentmodel->numbatches)
|
||||
|
@ -3820,8 +3864,8 @@ int Surf_NewLightmaps(int count, int width, int height, uploadfmt_t fmt, qboolea
|
|||
int first = numlightmaps;
|
||||
int i;
|
||||
|
||||
unsigned int pixbytes, pixw, pixh;
|
||||
unsigned int dpixbytes, dpixw, dpixh;
|
||||
unsigned int pixbytes, pixw, pixh, pixd;
|
||||
unsigned int dpixbytes, dpixw, dpixh, dpixd;
|
||||
uploadfmt_t dfmt;
|
||||
|
||||
if (!count)
|
||||
|
@ -3834,8 +3878,8 @@ int Surf_NewLightmaps(int count, int width, int height, uploadfmt_t fmt, qboolea
|
|||
Con_Print("WARNING: Deluxemapping with odd number of lightmaps\n");
|
||||
}
|
||||
|
||||
Image_BlockSizeForEncoding(fmt, &pixbytes, &pixw, &pixh);
|
||||
if (pixw != 1 || pixh != 1)
|
||||
Image_BlockSizeForEncoding(fmt, &pixbytes, &pixw, &pixh, &pixd);
|
||||
if (pixw != 1 || pixh != 1 || pixd != 1)
|
||||
return -1; //compressed formats are unsupported
|
||||
dfmt = PTI_A2BGR10; //favour this one, because it tends to be slightly faster.
|
||||
if (!sh_config.texfmt[dfmt])
|
||||
|
@ -3844,7 +3888,9 @@ int Surf_NewLightmaps(int count, int width, int height, uploadfmt_t fmt, qboolea
|
|||
dfmt = PTI_RGBX8;
|
||||
if (!sh_config.texfmt[dfmt])
|
||||
dfmt = PTI_RGB8;
|
||||
Image_BlockSizeForEncoding(dfmt, &dpixbytes, &dpixw, &dpixh);
|
||||
Image_BlockSizeForEncoding(dfmt, &dpixbytes, &dpixw, &dpixh, &dpixd);
|
||||
if (dpixw != 1 || dpixh != 1 || dpixd != 1)
|
||||
return -1; //compressed formats are unsupported
|
||||
|
||||
Sys_LockMutex(com_resourcemutex);
|
||||
|
||||
|
|
|
@ -478,7 +478,7 @@ void Image_Shutdown(void);
|
|||
void Image_PrintInputFormatVersions(void); //for version info
|
||||
qboolean Image_WriteKTXFile(const char *filename, enum fs_relative fsroot, struct pendingtextureinfo *mips);
|
||||
qboolean Image_WriteDDSFile(const char *filename, enum fs_relative fsroot, struct pendingtextureinfo *mips);
|
||||
void Image_BlockSizeForEncoding(uploadfmt_t 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 *blockdepth);
|
||||
const char *Image_FormatName(uploadfmt_t encoding);
|
||||
qboolean Image_FormatHasAlpha(uploadfmt_t encoding);
|
||||
image_t *Image_LoadTexture (const char *identifier, int width, int height, uploadfmt_t fmt, void *data, unsigned int flags);
|
||||
|
|
|
@ -162,6 +162,7 @@ cvar_t r_dynamic = CVARFD ("r_dynamic", IFMINIMAL("0","1"),
|
|||
cvar_t r_temporalscenecache = CVARFD ("r_temporalscenecache", "0", CVAR_ARCHIVE, "Controls whether to generate+reuse a scene cache over multiple frames. This is generated on a separate thread to avoid any associated costs. This can significantly boost framerates on complex maps, but can also stress the gpu more (performance tradeoff that varies per map). An outdated cache may be used if the cache takes too long to build (eg: lightmap animations), which could cause the odd glitch when moving fast (but retain more consistent framerates - another tradeoff).\n0: Tranditional quake rendering.\n1: Generate+Use the scene cache.");
|
||||
cvar_t r_fastturb = CVARF ("r_fastturb", "0",
|
||||
CVAR_SHADERSYSTEM);
|
||||
cvar_t r_skycloudalpha = CVARFD ("r_skycloudalpha", "1", CVAR_RENDERERLATCH, "Controls how opaque the front layer of legacy scrolling skies should be.");
|
||||
cvar_t r_fastsky = CVARF ("r_fastsky", "0",
|
||||
CVAR_ARCHIVE);
|
||||
cvar_t r_fastskycolour = CVARF ("r_fastskycolour", "0",
|
||||
|
@ -981,6 +982,7 @@ void Renderer_Init(void)
|
|||
Cvar_Register (&r_nolightdir, GRAPHICALNICETIES);
|
||||
|
||||
Cvar_Register (&r_fastturb, GRAPHICALNICETIES);
|
||||
Cvar_Register (&r_skycloudalpha, GRAPHICALNICETIES);
|
||||
Cvar_Register (&r_fastsky, GRAPHICALNICETIES);
|
||||
Cvar_Register (&r_fastskycolour, GRAPHICALNICETIES);
|
||||
Cvar_Register (&r_wateralpha, GRAPHICALNICETIES);
|
||||
|
|
|
@ -161,6 +161,7 @@ typedef enum uploadfmt
|
|||
PTI_EAC_RG11, /*8bpp*/ //useful for normalmaps (calculate blue)
|
||||
PTI_EAC_RG11_SNORM, /*8bpp*/ //useful for normalmaps (calculate blue)
|
||||
//astc... zomg.
|
||||
#define PTI_ASTC_FIRST PTI_ASTC_4X4_LDR
|
||||
PTI_ASTC_4X4_LDR, /*8bpp*/ //ldr/srgb/hdr formats are technically all the same.
|
||||
PTI_ASTC_5X4_LDR, /*6.40*/ //srgb formats are different because of an extra srgb lookup step
|
||||
PTI_ASTC_5X5_LDR, /*5.12*/ //ldr formats are identical to hdr except for the extended colour modes disabled.
|
||||
|
@ -175,6 +176,19 @@ typedef enum uploadfmt
|
|||
PTI_ASTC_10X10_LDR, /*1.28*/
|
||||
PTI_ASTC_12X10_LDR, /*1.07*/
|
||||
PTI_ASTC_12X12_LDR, /*0.89*/
|
||||
// #define ASTC3D
|
||||
#ifdef ASTC3D
|
||||
PTI_ASTC_3X3X3_LDR, /*4.74*/ //astc volume ldr textures are worth tracking only to provide hints to cache them as 8bit instead of 16bit (reducing gpu cache needed).
|
||||
PTI_ASTC_4X3X3_LDR, /*3.56*/
|
||||
PTI_ASTC_4X4X3_LDR, /*2.67*/
|
||||
PTI_ASTC_4X4X4_LDR, /*2.00*/
|
||||
PTI_ASTC_5X4X4_LDR, /*1.60*/
|
||||
PTI_ASTC_5X5X4_LDR, /*1.28*/
|
||||
PTI_ASTC_5X5X5_LDR, /*1.02*/
|
||||
PTI_ASTC_6X5X5_LDR, /*0.85*/
|
||||
PTI_ASTC_6X6X5_LDR, /*0.71*/
|
||||
PTI_ASTC_6X6X6_LDR, /*0.59*/
|
||||
#endif
|
||||
PTI_ASTC_4X4_SRGB,
|
||||
PTI_ASTC_5X4_SRGB,
|
||||
PTI_ASTC_5X5_SRGB,
|
||||
|
@ -189,6 +203,18 @@ typedef enum uploadfmt
|
|||
PTI_ASTC_10X10_SRGB,
|
||||
PTI_ASTC_12X10_SRGB,
|
||||
PTI_ASTC_12X12_SRGB,
|
||||
#ifdef ASTC3D
|
||||
PTI_ASTC_3X3X3_SRGB,
|
||||
PTI_ASTC_4X3X3_SRGB,
|
||||
PTI_ASTC_4X4X3_SRGB,
|
||||
PTI_ASTC_4X4X4_SRGB,
|
||||
PTI_ASTC_5X4X4_SRGB,
|
||||
PTI_ASTC_5X5X4_SRGB,
|
||||
PTI_ASTC_5X5X5_SRGB,
|
||||
PTI_ASTC_6X5X5_SRGB,
|
||||
PTI_ASTC_6X6X5_SRGB,
|
||||
PTI_ASTC_6X6X6_SRGB,
|
||||
#endif
|
||||
PTI_ASTC_4X4_HDR, //these are not strictly necessary, and are likely to be treated identically to the ldr versions, but they may use extra features that the hardware does not support
|
||||
PTI_ASTC_5X4_HDR,
|
||||
PTI_ASTC_5X5_HDR,
|
||||
|
@ -203,8 +229,21 @@ typedef enum uploadfmt
|
|||
PTI_ASTC_10X10_HDR,
|
||||
PTI_ASTC_12X10_HDR,
|
||||
PTI_ASTC_12X12_HDR,
|
||||
#define PTI_ASTC_FIRST PTI_ASTC_4X4_LDR
|
||||
#ifdef ASTC3D
|
||||
PTI_ASTC_3X3X3_HDR,
|
||||
PTI_ASTC_4X3X3_HDR,
|
||||
PTI_ASTC_4X4X3_HDR,
|
||||
PTI_ASTC_4X4X4_HDR,
|
||||
PTI_ASTC_5X4X4_HDR,
|
||||
PTI_ASTC_5X5X4_HDR,
|
||||
PTI_ASTC_5X5X5_HDR,
|
||||
PTI_ASTC_6X5X5_HDR,
|
||||
PTI_ASTC_6X6X5_HDR,
|
||||
PTI_ASTC_6X6X6_HDR,
|
||||
#define PTI_ASTC_LAST PTI_ASTC_6X6X6_HDR
|
||||
#else
|
||||
#define PTI_ASTC_LAST PTI_ASTC_12X12_HDR
|
||||
#endif
|
||||
|
||||
//depth formats
|
||||
PTI_DEPTH16,
|
||||
|
|
|
@ -432,16 +432,16 @@ static qboolean OpenAL_LoadCache(oalinfo_t *oali, unsigned int *bufptr, sfxcache
|
|||
{
|
||||
unsigned int fmt;
|
||||
unsigned int size;
|
||||
switch(sc->width)
|
||||
switch(sc->format)
|
||||
{
|
||||
#ifdef FTE_TARGET_WEB
|
||||
case 0:
|
||||
case QAF_BLOB:
|
||||
palGenBuffers(1, bufptr);
|
||||
emscriptenfte_al_loadaudiofile(*bufptr, sc->data, sc->length);
|
||||
//alIsBuffer will report false until success or failure...
|
||||
return true; //but we do have a 'proper' reference to the buffer.
|
||||
#endif
|
||||
case 1:
|
||||
case QAF_S8:
|
||||
if (sc->numchannels == 2)
|
||||
{
|
||||
fmt = AL_FORMAT_STEREO8;
|
||||
|
@ -453,7 +453,7 @@ static qboolean OpenAL_LoadCache(oalinfo_t *oali, unsigned int *bufptr, sfxcache
|
|||
size = sc->length*1;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
case QAF_S16:
|
||||
if (sc->numchannels == 2)
|
||||
{
|
||||
fmt = AL_FORMAT_STEREO16;
|
||||
|
@ -466,7 +466,7 @@ static qboolean OpenAL_LoadCache(oalinfo_t *oali, unsigned int *bufptr, sfxcache
|
|||
}
|
||||
break;
|
||||
#ifdef MIXER_F32
|
||||
case 4:
|
||||
case QAF_F32:
|
||||
if (!oali->canfloataudio)
|
||||
return false;
|
||||
if (sc->numchannels == 2)
|
||||
|
@ -497,69 +497,70 @@ static qboolean OpenAL_LoadCache(oalinfo_t *oali, unsigned int *bufptr, sfxcache
|
|||
}
|
||||
else if (volume != 1)
|
||||
{
|
||||
if (sc->width == 1)
|
||||
switch(sc->format)
|
||||
{
|
||||
unsigned char *tmp = malloc(size);
|
||||
char *src = sc->data;
|
||||
int i;
|
||||
for (i = 0; i < size; i++)
|
||||
case QAF_S8:
|
||||
{
|
||||
tmp[i] = src[i]*volume+128; //signed->unsigned
|
||||
unsigned char *tmp = malloc(size);
|
||||
char *src = sc->data;
|
||||
int i;
|
||||
for (i = 0; i < size; i++)
|
||||
tmp[i] = src[i]*volume+128; //signed->unsigned
|
||||
palBufferData(*bufptr, fmt, tmp, size, sc->speed);
|
||||
free(tmp);
|
||||
}
|
||||
palBufferData(*bufptr, fmt, tmp, size, sc->speed);
|
||||
free(tmp);
|
||||
}
|
||||
else if (sc->width == 2)
|
||||
{
|
||||
short *tmp = malloc(size);
|
||||
short *src = (short*)sc->data;
|
||||
int i;
|
||||
for (i = 0; i < (size>>1); i++)
|
||||
break;
|
||||
case QAF_S16:
|
||||
{
|
||||
tmp[i] = bound(-32767, src[i]*volume, 32767); //signed.
|
||||
short *tmp = malloc(size);
|
||||
short *src = (short*)sc->data;
|
||||
int i;
|
||||
for (i = 0; i < (size>>1); i++)
|
||||
tmp[i] = bound(-32767, src[i]*volume, 32767); //signed.
|
||||
palBufferData(*bufptr, fmt, tmp, size, sc->speed);
|
||||
free(tmp);
|
||||
}
|
||||
palBufferData(*bufptr, fmt, tmp, size, sc->speed);
|
||||
free(tmp);
|
||||
}
|
||||
break;
|
||||
#ifdef MIXER_F32
|
||||
else if (sc->width == 4)
|
||||
{
|
||||
float *tmp = malloc(size);
|
||||
float *src = (float*)sc->data;
|
||||
int i;
|
||||
for (i = 0; i < (size>>2); i++)
|
||||
case QAF_F32:
|
||||
{
|
||||
tmp[i] = src[i]*volume; //signed. oversaturation isn't my problem
|
||||
float *tmp = malloc(size);
|
||||
float *src = (float*)sc->data;
|
||||
int i;
|
||||
for (i = 0; i < (size>>2); i++)
|
||||
tmp[i] = src[i]*volume; //signed. oversaturation isn't my problem
|
||||
palBufferData(*bufptr, fmt, tmp, size, sc->speed);
|
||||
free(tmp);
|
||||
}
|
||||
palBufferData(*bufptr, fmt, tmp, size, sc->speed);
|
||||
free(tmp);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sc->width == 1)
|
||||
switch(sc->format)
|
||||
{
|
||||
unsigned char *tmp = malloc(size);
|
||||
char *src = sc->data;
|
||||
int i;
|
||||
for (i = 0; i < size; i++)
|
||||
case QAF_S8:
|
||||
{
|
||||
tmp[i] = src[i]+128;
|
||||
unsigned char *tmp = malloc(size);
|
||||
char *src = sc->data;
|
||||
int i;
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
tmp[i] = src[i]+128;
|
||||
}
|
||||
palBufferData(*bufptr, fmt, tmp, size, sc->speed);
|
||||
free(tmp);
|
||||
}
|
||||
palBufferData(*bufptr, fmt, tmp, size, sc->speed);
|
||||
free(tmp);
|
||||
}
|
||||
else if (sc->width == 2 || sc->width == 4)
|
||||
{
|
||||
#if 0
|
||||
short *tmp = malloc(size);
|
||||
memcpy(tmp, sc->data, size);
|
||||
palBufferData(*bufptr, fmt, tmp, size, sc->speed);
|
||||
free(tmp);
|
||||
#else
|
||||
palBufferData(*bufptr, fmt, sc->data, size, sc->speed);
|
||||
break;
|
||||
//case QAF_U8:
|
||||
case QAF_S16:
|
||||
//case QAF_S32:
|
||||
#ifdef MIXER_F32
|
||||
case QAF_F32:
|
||||
#endif
|
||||
palBufferData(*bufptr, fmt, sc->data, size, sc->speed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -833,7 +834,7 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat
|
|||
else
|
||||
{
|
||||
offset = pos - sbuf.soundoffset;
|
||||
sbuf.data += offset * sc->width*sc->numchannels;
|
||||
sbuf.data += offset * QAF_BYTES(sc->format)*sc->numchannels;
|
||||
sbuf.length -= offset;
|
||||
}
|
||||
sbuf.soundoffset = 0;
|
||||
|
@ -852,7 +853,7 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat
|
|||
{ //decoder isn't ready yet, but didn't signal an error/eof. queue a little silence, because that's better than constant micro stutters
|
||||
sfxcache_t silence;
|
||||
silence.speed = snd_speed;
|
||||
silence.width = 2;
|
||||
silence.format = QAF_S16;
|
||||
silence.numchannels = 1;
|
||||
silence.data = NULL;
|
||||
silence.length = 0.1 * silence.speed;
|
||||
|
@ -881,7 +882,7 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat
|
|||
{ //queue 0.1 secs if we're starting/resetting a new stream this is to try to cover up discontinuities caused by packetloss or whatever
|
||||
sfxcache_t silence;
|
||||
silence.speed = snd_speed;
|
||||
silence.width = 2;
|
||||
silence.format = QAF_S16;
|
||||
silence.numchannels = 1;
|
||||
silence.data = NULL;
|
||||
silence.length = 0.1 * silence.speed;
|
||||
|
|
|
@ -3166,18 +3166,25 @@ float S_GetChannelLevel(int entnum, int entchannel)
|
|||
{
|
||||
spos -= scache->soundoffset;
|
||||
spos *= scache->numchannels;
|
||||
switch(scache->width)
|
||||
switch(scache->format)
|
||||
{
|
||||
case 1:
|
||||
case QAF_S8:
|
||||
for (j = 0; j < scache->numchannels; j++) //average the channels
|
||||
result += abs(((signed char*)scache->data)[spos+j]);
|
||||
result /= scache->numchannels*127.0;
|
||||
break;
|
||||
case 2:
|
||||
case QAF_S16:
|
||||
for (j = 0; j < scache->numchannels; j++) //average the channels
|
||||
result += abs(((signed short*)scache->data)[spos+j]);
|
||||
result /= scache->numchannels*32767.0;
|
||||
break;
|
||||
#ifdef MIXER_F32
|
||||
case QAF_F32:
|
||||
for (j = 0; j < scache->numchannels; j++) //average the channels
|
||||
result += fabs(((float*)scache->data)[spos+j]);
|
||||
result /= scache->numchannels;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -4124,14 +4131,14 @@ void S_SoundList_f(void)
|
|||
Con_Printf("?( ) : %s\n", sfx->name);
|
||||
continue;
|
||||
}
|
||||
size = (sc->soundoffset+sc->length)*sc->width*(sc->numchannels);
|
||||
size = (sc->soundoffset+sc->length)*QAF_BYTES(sc->format)*(sc->numchannels);
|
||||
duration = (sc->soundoffset+sc->length) / sc->speed;
|
||||
total += size;
|
||||
if (sfx->loopstart >= 0)
|
||||
Con_Printf ("L");
|
||||
else
|
||||
Con_Printf (" ");
|
||||
Con_Printf("(%2db%2ic) %6i %2is : %s\n",sc->width*8, sc->numchannels, size, duration, sfx->name);
|
||||
Con_Printf("(%2db%2ic) %6i %2is : %s\n",QAF_BYTES(sc->format)*8, sc->numchannels, size, duration, sfx->name);
|
||||
}
|
||||
Con_Printf ("Total resident: %i\n", total);
|
||||
|
||||
|
@ -4179,7 +4186,7 @@ typedef struct {
|
|||
sfx_t *sfx;
|
||||
|
||||
int numchannels;
|
||||
int width;
|
||||
qaudiofmt_t format;
|
||||
int length;
|
||||
void *data;
|
||||
} streaming_t;
|
||||
|
@ -4202,7 +4209,7 @@ sfxcache_t *QDECL S_Raw_Locate(sfx_t *sfx, sfxcache_t *buf, ssamplepos_t start,
|
|||
buf->numchannels = s->numchannels;
|
||||
buf->soundoffset = 0;
|
||||
buf->speed = snd_speed;
|
||||
buf->width = s->width;
|
||||
buf->format = s->format;
|
||||
}
|
||||
if (start >= s->length)
|
||||
return NULL; //eof...
|
||||
|
@ -4226,7 +4233,7 @@ void QDECL S_Raw_Purge(sfx_t *sfx)
|
|||
}
|
||||
|
||||
//streaming audio. //this is useful when there is one source, and the sound is to be played with no attenuation
|
||||
void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels, int width, float volume)
|
||||
void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels, qaudiofmt_t format, float volume)
|
||||
{
|
||||
soundcardinfo_t *si;
|
||||
int i;
|
||||
|
@ -4292,7 +4299,7 @@ void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels,
|
|||
s->sfx->loadstate = SLS_LOADED;
|
||||
|
||||
s->numchannels = channels;
|
||||
s->width = width;
|
||||
s->format = format;
|
||||
s->data = NULL;
|
||||
s->length = 0;
|
||||
|
||||
|
@ -4302,9 +4309,9 @@ void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels,
|
|||
}
|
||||
S_LockMixer();
|
||||
|
||||
if (s->width != width || s->numchannels != channels)
|
||||
if (s->format != format || s->numchannels != channels)
|
||||
{
|
||||
s->width = width;
|
||||
s->format = format;
|
||||
s->numchannels = channels;
|
||||
s->length = 0;
|
||||
Con_Printf("Restarting raw stream\n");
|
||||
|
@ -4352,8 +4359,8 @@ void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels,
|
|||
}
|
||||
}
|
||||
|
||||
newcache = BZ_Malloc((spare+outsamples) * (s->numchannels) * s->width);
|
||||
memcpy(newcache, (qbyte*)s->data + prepadl * (s->numchannels) * s->width, spare * (s->numchannels) * s->width);
|
||||
newcache = BZ_Malloc((spare+outsamples) * (s->numchannels) * QAF_BYTES(s->format));
|
||||
memcpy(newcache, (qbyte*)s->data + prepadl * (s->numchannels) * QAF_BYTES(s->format), spare * (s->numchannels) * QAF_BYTES(s->format));
|
||||
|
||||
BZ_Free(s->data);
|
||||
s->data = newcache;
|
||||
|
@ -4362,15 +4369,15 @@ void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels,
|
|||
|
||||
{
|
||||
extern cvar_t snd_linearresample_stream;
|
||||
short *outpos = (short *)((char*)s->data + spare * (s->numchannels) * s->width);
|
||||
short *outpos = (short *)((char*)s->data + spare * (s->numchannels) * QAF_BYTES(s->format));
|
||||
SND_ResampleStream(data,
|
||||
speed,
|
||||
width,
|
||||
format,
|
||||
channels,
|
||||
samples,
|
||||
outpos,
|
||||
snd_speed,
|
||||
s->width,
|
||||
s->format,
|
||||
s->numchannels,
|
||||
snd_linearresample_stream.ival);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ typedef struct
|
|||
{
|
||||
int format;
|
||||
int rate;
|
||||
int width;
|
||||
int bitwidth;
|
||||
int numchannels;
|
||||
int loopstart;
|
||||
int samples;
|
||||
|
@ -295,7 +295,7 @@ qbyte *S_Alloc (int size);
|
|||
// SND_ResampleStream: takes a sound stream and converts with given parameters. Limited to
|
||||
// 8-16-bit signed conversions and mono-to-mono/stereo-to-stereo conversions.
|
||||
// Not an in-place algorithm.
|
||||
void SND_ResampleStream (void *in, int inrate, int inwidth, int inchannels, int insamps, void *out, int outrate, int outwidth, int outchannels, int resampstyle)
|
||||
void SND_ResampleStream (void *in, int inrate, qaudiofmt_t informat, int inchannels, int insamps, void *out, int outrate, qaudiofmt_t outformat, int outchannels, int resampstyle)
|
||||
{
|
||||
double scale;
|
||||
signed char *in8 = (signed char *)in;
|
||||
|
@ -308,17 +308,17 @@ void SND_ResampleStream (void *in, int inrate, int inwidth, int inchannels, int
|
|||
if (insamps <= 0)
|
||||
return;
|
||||
|
||||
if (inchannels == outchannels && inwidth == outwidth && inrate == outrate)
|
||||
if (inchannels == outchannels && informat == outformat && inrate == outrate)
|
||||
{
|
||||
memcpy(out, in, inwidth*insamps*inchannels);
|
||||
memcpy(out, in, informat*insamps*inchannels);
|
||||
return;
|
||||
}
|
||||
|
||||
if (inchannels == 1 && outchannels == 1)
|
||||
{
|
||||
if (inwidth == 1)
|
||||
if (informat == QAF_S8)
|
||||
{
|
||||
if (outwidth == 1)
|
||||
if (outformat == QAF_S8)
|
||||
{
|
||||
if (inrate < outrate) // upsample
|
||||
{
|
||||
|
@ -336,7 +336,7 @@ void SND_ResampleStream (void *in, int inrate, int inwidth, int inchannels, int
|
|||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
else if (outformat == QAF_S16)
|
||||
{
|
||||
if (inrate == outrate) // quick convert
|
||||
QUICKCONVERT(in8, insamps, out16, 8, 0)
|
||||
|
@ -357,9 +357,9 @@ void SND_ResampleStream (void *in, int inrate, int inwidth, int inchannels, int
|
|||
return;
|
||||
}
|
||||
}
|
||||
else // 16-bit
|
||||
else if (informat == QAF_S16) // 16-bit
|
||||
{
|
||||
if (outwidth == 2)
|
||||
if (outformat == QAF_S16)
|
||||
{
|
||||
if (inrate < outrate) // upsample
|
||||
{
|
||||
|
@ -377,7 +377,7 @@ void SND_ResampleStream (void *in, int inrate, int inwidth, int inchannels, int
|
|||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
else if (outformat == QAF_S8)
|
||||
{
|
||||
if (inrate == outrate) // quick convert
|
||||
QUICKCONVERT(in16, insamps, out8, 0, 8)
|
||||
|
@ -401,9 +401,9 @@ void SND_ResampleStream (void *in, int inrate, int inwidth, int inchannels, int
|
|||
}
|
||||
else if (outchannels == 2 && inchannels == 2)
|
||||
{
|
||||
if (inwidth == 1)
|
||||
if (informat == QAF_S8)
|
||||
{
|
||||
if (outwidth == 1)
|
||||
if (outformat == QAF_S8)
|
||||
{
|
||||
if (inrate < outrate) // upsample
|
||||
{
|
||||
|
@ -419,6 +419,7 @@ void SND_ResampleStream (void *in, int inrate, int inwidth, int inchannels, int
|
|||
else
|
||||
STANDARDRESCALESTEREO(in8, inrate, insamps, out8, outrate, 0, 0)
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -443,9 +444,9 @@ void SND_ResampleStream (void *in, int inrate, int inwidth, int inchannels, int
|
|||
}
|
||||
}
|
||||
}
|
||||
else // 16-bit
|
||||
else if (informat == QAF_S16) // 16-bit
|
||||
{
|
||||
if (outwidth == 2)
|
||||
if (outformat == QAF_S16)
|
||||
{
|
||||
if (inrate < outrate) // upsample
|
||||
{
|
||||
|
@ -462,7 +463,7 @@ void SND_ResampleStream (void *in, int inrate, int inwidth, int inchannels, int
|
|||
STANDARDRESCALESTEREO(in16, inrate, insamps, out16, outrate, 0, 0)
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (outformat == QAF_S8)
|
||||
{
|
||||
if (inrate == outrate) // quick convert
|
||||
{
|
||||
|
@ -489,9 +490,9 @@ void SND_ResampleStream (void *in, int inrate, int inwidth, int inchannels, int
|
|||
#if 0
|
||||
else if (outchannels == 1 && inchannels == 2)
|
||||
{
|
||||
if (inwidth == 1)
|
||||
if (informat == QAF_S8)
|
||||
{
|
||||
if (outwidth == 1)
|
||||
if (outformat == QAF_S8)
|
||||
{
|
||||
if (inrate < outrate) // upsample
|
||||
{
|
||||
|
@ -503,7 +504,7 @@ void SND_ResampleStream (void *in, int inrate, int inwidth, int inchannels, int
|
|||
else // downsample
|
||||
STANDARDRESCALESTEREOTOMONO(in8, inrate, insamps, out8, outrate, 0, 0)
|
||||
}
|
||||
else
|
||||
else if (outformat == QAF_S16)
|
||||
{
|
||||
if (inrate == outrate) // quick convert
|
||||
QUICKCONVERTSTEREOTOMONO(in8, insamps, out16, 8, 0)
|
||||
|
@ -518,9 +519,9 @@ void SND_ResampleStream (void *in, int inrate, int inwidth, int inchannels, int
|
|||
STANDARDRESCALESTEREOTOMONO(in8, inrate, insamps, out16, outrate, 8, 0)
|
||||
}
|
||||
}
|
||||
else // 16-bit
|
||||
else if (informat == QAF_S16) // 16-bit
|
||||
{
|
||||
if (outwidth == 2)
|
||||
if (outformat == QAF_S16)
|
||||
{
|
||||
if (inrate < outrate) // upsample
|
||||
{
|
||||
|
@ -532,7 +533,7 @@ void SND_ResampleStream (void *in, int inrate, int inwidth, int inchannels, int
|
|||
else // downsample
|
||||
STANDARDRESCALESTEREOTOMONO(in16, inrate, insamps, out16, outrate, 0, 0)
|
||||
}
|
||||
else
|
||||
else if (outformat == QAF_S8)
|
||||
{
|
||||
if (inrate == outrate) // quick convert
|
||||
QUICKCONVERTSTEREOTOMONO(in16, insamps, out8, 0, 8)
|
||||
|
@ -556,7 +557,7 @@ void SND_ResampleStream (void *in, int inrate, int inwidth, int inchannels, int
|
|||
ResampleSfx
|
||||
================
|
||||
*/
|
||||
static qboolean ResampleSfx (sfx_t *sfx, int inrate, int inchannels, int inwidth, int insamps, int inloopstart, qbyte *data)
|
||||
static qboolean ResampleSfx (sfx_t *sfx, int inrate, int inchannels, qaudiofmt_t informat, int insamps, int inloopstart, qbyte *data)
|
||||
{
|
||||
extern cvar_t snd_linearresample;
|
||||
extern cvar_t snd_loadasstereo;
|
||||
|
@ -564,17 +565,17 @@ static qboolean ResampleSfx (sfx_t *sfx, int inrate, int inchannels, int inwidth
|
|||
sfxcache_t *sc;
|
||||
int outsamps;
|
||||
int len;
|
||||
int outwidth;
|
||||
qaudiofmt_t outformat;
|
||||
|
||||
scale = snd_speed / (double)inrate;
|
||||
outsamps = insamps * scale;
|
||||
if (loadas8bit.ival < 0)
|
||||
outwidth = 2;
|
||||
outformat = QAF_S16;
|
||||
else if (loadas8bit.ival)
|
||||
outwidth = 1;
|
||||
outformat = QAF_S8;
|
||||
else
|
||||
outwidth = inwidth;
|
||||
len = outsamps * outwidth * inchannels;
|
||||
outformat = informat;
|
||||
len = outsamps * QAF_BYTES(outformat) * inchannels;
|
||||
|
||||
sfx->decoder.buf = sc = BZ_Malloc(sizeof(sfxcache_t) + len);
|
||||
if (!sc)
|
||||
|
@ -583,7 +584,7 @@ static qboolean ResampleSfx (sfx_t *sfx, int inrate, int inchannels, int inwidth
|
|||
}
|
||||
|
||||
sc->numchannels = inchannels;
|
||||
sc->width = outwidth;
|
||||
sc->format = outformat;
|
||||
sc->speed = snd_speed;
|
||||
sc->length = outsamps;
|
||||
sc->soundoffset = 0;
|
||||
|
@ -595,12 +596,12 @@ static qboolean ResampleSfx (sfx_t *sfx, int inrate, int inchannels, int inwidth
|
|||
|
||||
SND_ResampleStream (data,
|
||||
inrate,
|
||||
inwidth,
|
||||
informat,
|
||||
inchannels,
|
||||
insamps,
|
||||
sc->data,
|
||||
sc->speed,
|
||||
sc->width,
|
||||
sc->format,
|
||||
sc->numchannels,
|
||||
snd_linearresample.ival);
|
||||
|
||||
|
@ -611,12 +612,12 @@ static qboolean ResampleSfx (sfx_t *sfx, int inrate, int inchannels, int inwidth
|
|||
nc->data = (qbyte*)(nc+1);
|
||||
SND_ResampleStream (sc->data,
|
||||
sc->speed,
|
||||
sc->width,
|
||||
sc->format,
|
||||
sc->numchannels,
|
||||
outsamps,
|
||||
nc->data,
|
||||
nc->speed*2,
|
||||
nc->width,
|
||||
nc->format,
|
||||
nc->numchannels,
|
||||
false);
|
||||
nc->numchannels *= 2;
|
||||
|
@ -738,22 +739,10 @@ static qboolean QDECL S_LoadDoomSound (sfx_t *s, qbyte *data, size_t datalen, in
|
|||
}
|
||||
#endif
|
||||
|
||||
void S_ShortedLittleFloats(void *p, size_t samples)
|
||||
{
|
||||
short *out = p;
|
||||
float *in = p;
|
||||
int t;
|
||||
while(samples --> 0)
|
||||
{
|
||||
t = LittleFloat(*in++) * 32767;
|
||||
t = bound(-32768, t, 32767);
|
||||
*out++ = t;
|
||||
}
|
||||
}
|
||||
|
||||
static qboolean QDECL S_LoadWavSound (sfx_t *s, qbyte *data, size_t datalen, int sndspeed, qboolean forcedecode)
|
||||
{
|
||||
wavinfo_t info;
|
||||
qaudiofmt_t format;
|
||||
|
||||
if (datalen < 4 || strncmp(data, "RIFF", 4))
|
||||
return false;
|
||||
|
@ -766,22 +755,62 @@ static qboolean QDECL S_LoadWavSound (sfx_t *s, qbyte *data, size_t datalen, int
|
|||
return false;
|
||||
}
|
||||
|
||||
if (info.format == 1 && info.width == 1) //unsigned bytes
|
||||
COM_CharBias(data + info.dataofs, info.samples*info.numchannels);
|
||||
else if (info.format == 1 && info.width == 2) //signed shorts
|
||||
COM_SwapLittleShortBlock((short *)(data + info.dataofs), info.samples*info.numchannels);
|
||||
else if (info.format == 3 && info.width == 4) //signed floats
|
||||
if (info.format == 1 && info.bitwidth == 8) //unsigned bytes
|
||||
{
|
||||
S_ShortedLittleFloats(data + info.dataofs, info.samples*info.numchannels);
|
||||
info.width = 2;
|
||||
COM_CharBias(data + info.dataofs, info.samples*info.numchannels);
|
||||
format = QAF_S8;
|
||||
}
|
||||
else if (info.format == 1 && info.bitwidth == 16) //signed shorts
|
||||
{
|
||||
COM_SwapLittleShortBlock((short *)(data + info.dataofs), info.samples*info.numchannels);
|
||||
format = QAF_S16;
|
||||
}
|
||||
else if (info.format == 1 && info.bitwidth == 32) //24 or 32bit int audio
|
||||
{
|
||||
short *out = (short *)(data + info.dataofs);
|
||||
int *in = (int *)(data + info.dataofs);
|
||||
size_t samples = info.samples*info.numchannels;
|
||||
while(samples --> 0)
|
||||
{ //in place size conversion, so we need to do it forwards.
|
||||
*out++ = LittleLong(*in++)>>16; //just drop the least significant bits.
|
||||
}
|
||||
format = QAF_S16;
|
||||
}
|
||||
#ifdef MIXER_F32
|
||||
else if (info.format == 3 && info.bitwidth == 32) //signed floats
|
||||
{
|
||||
if (bigendian)
|
||||
{
|
||||
size_t i = info.samples*info.numchannels;
|
||||
float *ptr = (float*)(data + info.dataofs);
|
||||
while(i --> 0)
|
||||
ptr[i] = LittleFloat(ptr[i]);
|
||||
}
|
||||
format = QAF_F32;
|
||||
}
|
||||
#else
|
||||
else if (info.format == 3 && info.bitwidth == 4) //signed floats
|
||||
{
|
||||
short *out = (short *)(data + info.dataofs);
|
||||
float *in = (float *)(data + info.dataofs);
|
||||
size_t samples = info.samples*info.numchannels;
|
||||
int t;
|
||||
while(samples --> 0)
|
||||
{ //in place size conversion, so we need to do it forwards.
|
||||
t = LittleFloat(*in++) * 32767;
|
||||
t = bound(-32768, t, 32767);
|
||||
*out++ = t;
|
||||
}
|
||||
format = QAF_S16;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
s->loadstate = SLS_FAILED;
|
||||
switch(info.format)
|
||||
{
|
||||
case 1/*WAVE_FORMAT_PCM*/:
|
||||
case 3/*WAVE_FORMAT_IEEE_FLOAT*/: Con_Printf ("%s has an unsupported width (%i bits).\n", s->name, info.width*8); break;
|
||||
case 3/*WAVE_FORMAT_IEEE_FLOAT*/: Con_Printf ("%s has an unsupported width (%i bits).\n", s->name, info.bitwidth); break;
|
||||
case 6/*WAVE_FORMAT_ALAW*/: Con_Printf ("%s uses unsupported a-law format.\n", s->name); break;
|
||||
case 7/*WAVE_FORMAT_MULAW*/: Con_Printf ("%s uses unsupported mu-law format.\n", s->name); break;
|
||||
case 0xfffe/*WAVE_FORMAT_EXTENSIBLE*/:
|
||||
|
@ -790,7 +819,7 @@ static qboolean QDECL S_LoadWavSound (sfx_t *s, qbyte *data, size_t datalen, int
|
|||
return false;
|
||||
}
|
||||
|
||||
return ResampleSfx (s, info.rate, info.numchannels, info.width, info.samples, info.loopstart, data + info.dataofs);
|
||||
return ResampleSfx (s, info.rate, info.numchannels, format, info.samples, info.loopstart, data + info.dataofs);
|
||||
}
|
||||
|
||||
qboolean QDECL S_LoadOVSound (sfx_t *s, qbyte *data, size_t datalen, int sndspeed, qboolean forcedecode);
|
||||
|
@ -1174,7 +1203,7 @@ static wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength)
|
|||
info.numchannels = GetLittleShort(&ctx);
|
||||
info.rate = GetLittleLong(&ctx);
|
||||
ctx.data_p += 4+2;
|
||||
info.width = GetLittleShort(&ctx) / 8;
|
||||
info.bitwidth = GetLittleShort(&ctx);
|
||||
|
||||
// get cue chunk
|
||||
chunklen = FindChunk(&ctx, "cue ");
|
||||
|
@ -1209,7 +1238,7 @@ static wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength)
|
|||
}
|
||||
|
||||
ctx.data_p += 8;
|
||||
samples = chunklen / info.width /info.numchannels;
|
||||
samples = (chunklen<<3) / info.bitwidth / info.numchannels;
|
||||
|
||||
if (info.samples)
|
||||
{
|
||||
|
|
|
@ -311,8 +311,9 @@ void S_PaintChannels(soundcardinfo_t *sc, int endtime)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (scache->width == 1)
|
||||
switch(scache->format)
|
||||
{
|
||||
case QAF_S8:
|
||||
if (scache->numchannels==2)
|
||||
SND_PaintChannel8_O2I2(ch, scache, ltime-sc->paintedtime, count, rate);
|
||||
else if (sc->sn.numchannels <= 2)
|
||||
|
@ -323,9 +324,8 @@ void S_PaintChannels(soundcardinfo_t *sc, int endtime)
|
|||
SND_PaintChannel8_O6I1(ch, scache, count, rate);
|
||||
else
|
||||
SND_PaintChannel8_O8I1(ch, scache, count, rate);
|
||||
}
|
||||
else if (scache->width == 2)
|
||||
{
|
||||
break;
|
||||
case QAF_S16:
|
||||
if (scache->numchannels==2)
|
||||
SND_PaintChannel16_O2I2(ch, scache, ltime-sc->paintedtime, count, rate);
|
||||
else if (sc->sn.numchannels <= 2)
|
||||
|
@ -336,10 +336,9 @@ void S_PaintChannels(soundcardinfo_t *sc, int endtime)
|
|||
SND_PaintChannel16_O6I1(ch, scache, count, rate);
|
||||
else
|
||||
SND_PaintChannel16_O8I1(ch, scache, count, rate);
|
||||
}
|
||||
break;
|
||||
#ifdef MIXER_F32
|
||||
else if (scache->width == 4)
|
||||
{
|
||||
case QAF_F32:
|
||||
if (scache->numchannels==2)
|
||||
SND_PaintChannel32F_O2I2(ch, scache, ltime-sc->paintedtime, count, rate);
|
||||
else if (sc->sn.numchannels <= 2)
|
||||
|
@ -350,8 +349,9 @@ void S_PaintChannels(soundcardinfo_t *sc, int endtime)
|
|||
SND_PaintChannel32F_O6I1(ch, scache, count, rate);
|
||||
else
|
||||
SND_PaintChannel32F_O8I1(ch, scache, count, rate);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
ltime += count;
|
||||
ch->pos += rate * count;
|
||||
}
|
||||
|
|
|
@ -99,7 +99,7 @@ static float QDECL OV_Query(struct sfx_s *sfx, struct sfxcache_s *buf, char *nam
|
|||
buf->length = dec->pcmtotal;
|
||||
buf->numchannels = dec->srcchannels;
|
||||
buf->speed = dec->srcspeed;
|
||||
buf->width = 2;
|
||||
buf->format = QAF_S16;
|
||||
}
|
||||
if (name)
|
||||
{
|
||||
|
@ -276,7 +276,7 @@ static sfxcache_t *QDECL OV_DecodeSome(struct sfx_s *sfx, struct sfxcache_s *buf
|
|||
buf->length = dec->decodedbytecount / (2 * dec->srcchannels);
|
||||
buf->numchannels = dec->srcchannels;
|
||||
buf->speed = snd_speed;
|
||||
buf->width = 2;
|
||||
buf->format = QAF_S16;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#ifndef __SOUND__
|
||||
#define __SOUND__
|
||||
|
||||
//#define MIXER_F32
|
||||
#define MAXSOUNDCHANNELS 8 //on a per device basis
|
||||
|
||||
//pitch/rate changes require that we track stuff with subsample precision.
|
||||
|
@ -63,12 +64,27 @@ typedef struct sfx_s
|
|||
int loopstart; //-1 or sample index to begin looping at once the sample ends
|
||||
} sfx_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
#ifdef FTE_TARGET_WEB
|
||||
QAF_BLOB=0,
|
||||
#endif
|
||||
QAF_S8=1,
|
||||
//QAF_U8=0x80|1,
|
||||
QAF_S16=2,
|
||||
//QAF_S32=4,
|
||||
#ifdef MIXER_F32
|
||||
QAF_F32=0x80|4,
|
||||
#endif
|
||||
#define QAF_BYTES(v) (v&0x7f) //to make memory allocation easier.
|
||||
} qaudiofmt_t;
|
||||
|
||||
// !!! if this is changed, it much be changed in asm_i386.h too !!!
|
||||
typedef struct sfxcache_s
|
||||
{
|
||||
usamplepos_t length; //sample count
|
||||
unsigned int speed;
|
||||
unsigned int width;
|
||||
qaudiofmt_t format;
|
||||
unsigned int numchannels;
|
||||
usamplepos_t soundoffset; //byte index into the sound
|
||||
qbyte *data; // variable sized
|
||||
|
@ -250,7 +266,7 @@ qboolean S_IsPlayingSomewhere(sfx_t *s);
|
|||
// picks a channel based on priorities, empty slots, number of channels
|
||||
channel_t *SND_PickChannel(soundcardinfo_t *sc, int entnum, int entchannel);
|
||||
|
||||
void SND_ResampleStream (void *in, int inrate, int inwidth, int inchannels, int insamps, void *out, int outrate, int outwidth, int outchannels, int resampstyle);
|
||||
void SND_ResampleStream (void *in, int inrate, qaudiofmt_t inwidth, int inchannels, int insamps, void *out, int outrate, qaudiofmt_t outwidth, int outchannels, int resampstyle);
|
||||
|
||||
// restart entire sound subsystem (doesn't flush old sounds, so make sure that happens)
|
||||
void S_DoRestart (qboolean onlyifneeded);
|
||||
|
@ -258,7 +274,7 @@ void S_DoRestart (qboolean onlyifneeded);
|
|||
void S_Restart_f (void);
|
||||
|
||||
//plays streaming audio
|
||||
void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels, int width, float volume);
|
||||
void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels, qaudiofmt_t width, float volume);
|
||||
|
||||
void CLVC_Poll (void);
|
||||
|
||||
|
|
|
@ -902,14 +902,6 @@ char *Sys_ConsoleInput(void)
|
|||
static char text[256];
|
||||
char *nl;
|
||||
|
||||
#ifdef SUBSERVERS
|
||||
if (SSV_IsSubServer())
|
||||
{
|
||||
SSV_CheckFromMaster();
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (noconinput)
|
||||
return NULL;
|
||||
|
||||
|
@ -1110,10 +1102,14 @@ int main (int c, const char **v)
|
|||
fcntl(STDIN_FILENO, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
|
||||
#endif
|
||||
|
||||
#ifndef CLIENTONLY
|
||||
#ifdef HAVE_SERVER
|
||||
#ifdef SUBSERVERS
|
||||
if (COM_CheckParm("-clusterslave"))
|
||||
isDedicated = nostdout = isClusterSlave = true;
|
||||
{
|
||||
isDedicated = true;
|
||||
nostdout = noconinput = true;
|
||||
SSV_SetupControlPipe(Sys_GetStdInOutStream());
|
||||
}
|
||||
#endif
|
||||
if (COM_CheckParm("-dedicated"))
|
||||
isDedicated = true;
|
||||
|
|
|
@ -868,7 +868,8 @@ int QDECL main(int argc, char **argv)
|
|||
sleeptime = Host_Frame (time);
|
||||
oldtime = newtime;
|
||||
|
||||
Sys_Sleep(sleeptime);
|
||||
if (sleeptime)
|
||||
Sys_Sleep(sleeptime);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1068,17 +1069,14 @@ qboolean Sys_RunInstaller(void)
|
|||
#endif
|
||||
|
||||
#ifdef HAVEAUTOUPDATE
|
||||
//legacy, so old build can still deal with updates properly
|
||||
void Sys_SetUpdatedBinary(const char *fname)
|
||||
//returns true if we could sucessfull overwrite the engine binary.
|
||||
qboolean Sys_SetUpdatedBinary(const char *fname)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
//says whether the system code is able to invoke new binaries properly
|
||||
qboolean Sys_EngineCanUpdate(void)
|
||||
{
|
||||
return false; //nope, nothing here
|
||||
}
|
||||
//invoke the given system-path binary
|
||||
qboolean Sys_EngineWasUpdated(char *newbinary)
|
||||
//says whether the system code is able/allowed to overwrite itself.
|
||||
//(ie: return false if we don't know the binary name or if its write-protected etc)
|
||||
qboolean Sys_EngineMayUpdate(void)
|
||||
{
|
||||
return false; //sorry
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ cmdalias_t *cmd_alias;
|
|||
cvar_t cfg_save_all = CVARFD("cfg_save_all", "", CVAR_ARCHIVE|CVAR_NOTFROMSERVER, "If 1, cfg_save ALWAYS saves all cvars. If 0, cfg_save only ever saves archived cvars. If empty, cfg_save saves all cvars only when an explicit filename was given (ie: when not used internally via quit menu options).");
|
||||
cvar_t cfg_save_auto = CVARFD("cfg_save_auto", "0", CVAR_ARCHIVE|CVAR_NOTFROMSERVER, "If 1, the config will automatically be saved and without prompts. If 0, you'll have to save your config manually (possibly via prompts from the quit menu).");
|
||||
cvar_t cfg_save_infos = CVARFD("cfg_save_infos", "1", CVAR_ARCHIVE|CVAR_NOTFROMSERVER, "If 1, saves userinfo and serverinfo to configs.");
|
||||
cvar_t cfg_save_aliases = CVARFD("cfg_save_aliases", "1", CVAR_ARCHIVE|CVAR_NOTFROMSERVER, "If 1, saves userinfo and serverinfo to configs.");
|
||||
cvar_t cfg_save_aliases = CVARFD("cfg_save_aliases", "1", CVAR_ARCHIVE|CVAR_NOTFROMSERVER, "If 1, saves aliases to configs. Note that aliases sent from servers are assumed to be server-specific and are never saved (and are forgotten on map changes, too).");
|
||||
cvar_t cfg_save_binds = CVARFD("cfg_save_binds", "1", CVAR_ARCHIVE|CVAR_NOTFROMSERVER, "If 1, saves all key bindings to configs.");
|
||||
cvar_t cfg_save_buttons = CVARFD("cfg_save_buttons", "0", CVAR_ARCHIVE|CVAR_NOTFROMSERVER, "If 1, saves the state of things such as +mlook or +forward to configs.");
|
||||
|
||||
|
|
|
@ -613,7 +613,7 @@ qboolean FS_WriteFile (const char *filename, const void *data, int len, enum fs_
|
|||
void *FS_MallocFile(const char *filename, enum fs_relative relativeto, qofs_t *filesize);
|
||||
vfsfile_t *QDECL FS_OpenVFS(const char *filename, const char *mode, enum fs_relative relativeto);
|
||||
vfsfile_t *FS_OpenTemp(void);
|
||||
vfsfile_t *FS_OpenTCP(const char *name, int defaultport);
|
||||
vfsfile_t *FS_OpenTCP(const char *name, int defaultport, qboolean assumetls);
|
||||
|
||||
vfsfile_t *FS_OpenWithFriends(const char *fname, char *sysname, size_t sysnamesize, int numfriends, ...);
|
||||
|
||||
|
@ -705,6 +705,7 @@ typedef struct
|
|||
GAMEDIR_READONLY=1u<<2, //don't write here...
|
||||
GAMEDIR_USEBASEDIR=1u<<3, //packages will be read from the basedir (and homedir), but not other files. path is an empty string.
|
||||
GAMEDIR_STEAMGAME=1u<<4, //finds the game via steam. must also be private+readonly.
|
||||
GAMEDIR_QSHACK=1u<<8,
|
||||
|
||||
GAMEDIR_SPECIAL=GAMEDIR_USEBASEDIR|GAMEDIR_STEAMGAME, //if one of these flags, then the gamedir cannot be simply concatenated to the basedir/homedir.
|
||||
} flags;
|
||||
|
|
|
@ -617,7 +617,10 @@ static qboolean FS_Manifest_ParseTokens(ftemanifest_t *man)
|
|||
else if (!Q_strcasecmp(cmd, "mainconfig"))
|
||||
{
|
||||
Z_Free(man->mainconfig);
|
||||
man->mainconfig = Z_StrDup(Cmd_Argv(1));
|
||||
if (strcmp(".cfg", COM_GetFileExtension(Cmd_Argv(1),NULL)))
|
||||
man->mainconfig = Z_StrDup(va("%s.cfg", Cmd_Argv(1)));
|
||||
else
|
||||
man->mainconfig = Z_StrDup(Cmd_Argv(1));
|
||||
}
|
||||
else if (!Q_strcasecmp(cmd, "defaultexec"))
|
||||
{
|
||||
|
@ -672,6 +675,11 @@ static qboolean FS_Manifest_ParseTokens(ftemanifest_t *man)
|
|||
if (!Q_strcasecmp(cmd, "basegame"))
|
||||
man->gamepath[i].flags |= GAMEDIR_BASEGAME;
|
||||
|
||||
if (*newdir == '/')
|
||||
{
|
||||
newdir++;
|
||||
man->gamepath[i].flags |= GAMEDIR_QSHACK;
|
||||
}
|
||||
if (*newdir == '*')
|
||||
{ //*dir makes the dir 'private' and not networked.
|
||||
newdir++;
|
||||
|
@ -1567,7 +1575,7 @@ fail:
|
|||
else
|
||||
Con_Printf("Failed\n");
|
||||
*/
|
||||
if (found == FF_NOTFOUND || loc->len == -1)
|
||||
if (found == FF_NOTFOUND || found == FF_DIRECTORY || loc->len == -1)
|
||||
{
|
||||
if (lflags & FSLF_DEEPONFAILURE)
|
||||
return 0x7fffffff; //if we're asking for depth, the file is reported to be so far into the filesystem as to be irrelevant.
|
||||
|
@ -2780,6 +2788,8 @@ static searchpathfuncs_t *FS_OpenPackByExtension(vfsfile_t *f, searchpathfuncs_t
|
|||
searchpathfuncs_t *pak;
|
||||
int j;
|
||||
char ext[8];
|
||||
if (!f)
|
||||
return NULL;
|
||||
COM_FileExtension(pakname, ext, sizeof(ext));
|
||||
for (j = 0; j < sizeof(searchpathformats)/sizeof(searchpathformats[0]); j++)
|
||||
{
|
||||
|
@ -2950,6 +2960,8 @@ static void FS_AddDataFiles(searchpath_t **oldpaths, const char *purepath, const
|
|||
flocation_t loc;
|
||||
wildpaks_t wp;
|
||||
filelist_t list = {0};
|
||||
qboolean qshack = (pflags&SPF_QSHACK);
|
||||
pflags &= ~SPF_QSHACK;
|
||||
|
||||
Q_strncpyz(logicalpaths, logicalpath, sizeof(logicalpaths));
|
||||
FS_CleanDir(logicalpaths, sizeof(logicalpaths));
|
||||
|
@ -3005,37 +3017,50 @@ static void FS_AddDataFiles(searchpath_t **oldpaths, const char *purepath, const
|
|||
continue;
|
||||
if (loadstuff & (1<<j))
|
||||
{
|
||||
qboolean okay = true;
|
||||
const char *extension = searchpathformats[j].extension;
|
||||
|
||||
//first load all the numbered pak files
|
||||
for (i=0 ; ; i++)
|
||||
for (i=0 ; okay ; i++)
|
||||
{
|
||||
snprintf (pakfile, sizeof(pakfile), "pak%i.%s", i, extension);
|
||||
fs_finds++;
|
||||
if (!search->handle->FindFile(search->handle, &loc, pakfile, NULL))
|
||||
break; //not found..
|
||||
|
||||
snprintf (logicalfile, sizeof(logicalfile), "%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 (search->handle->FindFile(search->handle, &loc, pakfile, NULL))
|
||||
{
|
||||
if (!Q_strcasecmp(existing->logicalpath, logicalfile)) //assumption: first member of structure is a char array
|
||||
break; //already loaded (base paths?)
|
||||
snprintf (logicalfile, sizeof(logicalfile), "%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, logicalfile)) //assumption: first member of structure is a char array
|
||||
break; //already loaded (base paths?)
|
||||
}
|
||||
if (!existing)
|
||||
{
|
||||
handle = FS_GetOldPath(oldpaths, logicalfile, &keptflags);
|
||||
if (!handle)
|
||||
{
|
||||
vfs = search->handle->OpenVFS(search->handle, &loc, "rb");
|
||||
if (!vfs)
|
||||
break;
|
||||
handle = searchpathformats[j].OpenNew (vfs, search->handle, pakfile, logicalfile, "");
|
||||
if (!handle)
|
||||
break;
|
||||
}
|
||||
FS_AddPathHandle(oldpaths, purefile, logicalfile, handle, "", SPF_COPYPROTECTED|pflags|keptflags, (unsigned int)-1);
|
||||
}
|
||||
}
|
||||
if (!existing)
|
||||
else
|
||||
okay = false;
|
||||
|
||||
if (i == 0 && qshack)
|
||||
{
|
||||
snprintf (pakfile, sizeof(pakfile), "quakespasm.%s", extension);
|
||||
handle = FS_GetOldPath(oldpaths, logicalfile, &keptflags);
|
||||
if (!handle)
|
||||
{
|
||||
vfs = search->handle->OpenVFS(search->handle, &loc, "rb");
|
||||
if (!vfs)
|
||||
break;
|
||||
handle = searchpathformats[j].OpenNew (vfs, search->handle, pakfile, logicalfile, "");
|
||||
if (!handle)
|
||||
break;
|
||||
}
|
||||
FS_AddPathHandle(oldpaths, purefile, logicalfile, handle, "", SPF_COPYPROTECTED|pflags|keptflags, (unsigned int)-1);
|
||||
handle = FS_OpenPackByExtension(VFSOS_Open(pakfile, "rb"), NULL, pakfile, pakfile);
|
||||
if (handle) //logically should have SPF_EXPLICIT set, but that would give it a worse gamedir depth
|
||||
FS_AddPathHandle(oldpaths, "", pakfile, handle, "", SPF_COPYPROTECTED|SPF_PRIVATE, (unsigned int)-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3098,7 +3123,7 @@ static searchpath_t *FS_AddPathHandle(searchpath_t **oldpaths, const char *purep
|
|||
|
||||
//temp packages also do not nest
|
||||
// if (!(flags & SPF_TEMPORARY))
|
||||
FS_AddDataFiles(oldpaths, purepath, logicalpath, search, flags&(SPF_COPYPROTECTED|SPF_UNTRUSTED|SPF_TEMPORARY|SPF_PRIVATE), loadstuff);
|
||||
FS_AddDataFiles(oldpaths, purepath, logicalpath, search, flags&(SPF_COPYPROTECTED|SPF_UNTRUSTED|SPF_TEMPORARY|SPF_PRIVATE|SPF_QSHACK), loadstuff);
|
||||
|
||||
if (flags & SPF_TEMPORARY)
|
||||
{
|
||||
|
@ -3464,7 +3489,7 @@ void COM_Gamedir (const char *dir, const struct gamepacks *packagespaths)
|
|||
#define QUAKESPASMSUCKS "set mod_h2holey_bugged 1\n"
|
||||
#define QCFG "set v_gammainverted 1\nset con_stayhidden 0\nset com_parseutf8 0\nset allow_download_pakcontents 1\nset allow_download_refpackages 0\nset sv_bigcoords \"\"\nmap_autoopenportals 1\n" "sv_port "STRINGIFY(PORT_QWSERVER)" "STRINGIFY(PORT_NQSERVER)"\n" ZFIXHACK EZQUAKECOMPETITIVE QRPCOMPAT QUAKESPASMSUCKS
|
||||
/*NetQuake reconfiguration, to make certain people feel more at home...*/
|
||||
#define NQCFG "//-nohome\ncfg_save_auto 1\n" QCFG "sv_nqplayerphysics 1\ncl_loopbackprotocol auto\ncl_sbar 1\nplug_sbar 0\nsv_port "STRINGIFY(PORT_NQSERVER)"\ncl_defaultport "STRINGIFY(PORT_NQSERVER)"\n"
|
||||
#define NQCFG "//disablehomedir 1\n//mainconfig ftenq\ncfg_save_auto 1\n" QCFG "set sv_nqplayerphysics 1\nset cl_loopbackprotocol auto\ncl_sbar 1\nset plug_sbar 0\nset sv_port "STRINGIFY(PORT_NQSERVER)"\ncl_defaultport "STRINGIFY(PORT_NQSERVER)"\nset m_preset_chosen 1\nset vid_wait 1\n"
|
||||
//nehahra has to be weird with its extra cvars, and buggy fullbrights.
|
||||
#define NEHCFG QCFG "set nospr32 0\nset cutscene 1\nalias startmap_sp \"map nehstart\"\nr_fb_bmodels 0\nr_fb_models 0\n"
|
||||
/*stuff that makes dp-only mods work a bit better*/
|
||||
|
@ -3537,13 +3562,13 @@ const gamemode_info_t gamemode_info[] = {
|
|||
//alternative name, because fmf file install names are messy when a single name is used for registry install path.
|
||||
{"-afterquake", NULL, "FTE-Quake",{"id1/pak0.pak", "id1/quake.rc"}, QCFG,{"id1", "qw", "*fte"}, "AfterQuake", UPDATEURL(Q1) /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/},
|
||||
//netquake-specific quake that avoids qw/ with its nquake fuckups, and disables nqisms
|
||||
{"-netquake", "nq", "FTE-Quake DarkPlaces-Quake",{"id1/pak0.pak", "id1/quake.rc"},NQCFG,{"id1"}, "NetQuake", UPDATEURL(Q1) /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/},
|
||||
{"-netquake", NULL, "FTE-Quake DarkPlaces-Quake",{"id1/pak0.pak", "id1/quake.rc"},NQCFG,{"id1"}, "NetQuake", UPDATEURL(Q1) /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/},
|
||||
//blurgh
|
||||
{"-spasm", NULL, "FTE-Quake DarkPlaces-Quake",{"quakespasm.pak"}, NQCFG"fps_preset spasm\n",{"id1", "*"}, "FauxSpasm", UPDATEURL(Q1) /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/},
|
||||
{"-spasm", NULL, "FTE-Quake DarkPlaces-Quake",{"quakespasm.pak"}, NQCFG"fps_preset builtin_spasm\nset cl_demoreel 0\n",{"/id1"}, "FauxSpasm", UPDATEURL(Q1) /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/},
|
||||
//because we can. 'fps_preset spasm' is hopefully close enough...
|
||||
{"-fitz", NULL, "FTE-Quake DarkPlaces-Quake",{"quakespasm.pak"}, NQCFG"fps_preset spasm\n",{"id1"}, "FauxFitz", UPDATEURL(Q1) /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/},
|
||||
{"-fitz", "nq", "FTE-Quake DarkPlaces-Quake",{"id1/pak0.pak", "id1/quake.rc"},NQCFG"fps_preset builtin_spasm\n",{"id1"}, "FauxFitz", UPDATEURL(Q1) /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/},
|
||||
//because we can
|
||||
{"-tenebrae", NULL, "FTE-Quake DarkPlaces-Quake",{"id1/pak0.pak", "id1/quake.rc"},NQCFG"fps_preset tenebrae\n",{"id1","tenebrae"},"FauxTenebrae", UPDATEURL(Q1) /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/},
|
||||
{"-tenebrae", NULL, "FTE-Quake DarkPlaces-Quake",{"id1/pak0.pak", "id1/quake.rc"},NQCFG"fps_preset builtin_tenebrae\n",{"id1","tenebrae"},"FauxTenebrae", UPDATEURL(Q1) /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/},
|
||||
|
||||
//quake's mission packs should not be favoured over the base game nor autodetected
|
||||
//third part mods also tend to depend upon the mission packs for their huds, even if they don't use any other content.
|
||||
|
@ -4138,6 +4163,8 @@ static void FS_ReloadPackFilesFlags(unsigned int reloadflags)
|
|||
fl |= SPF_WRITABLE;
|
||||
if (fs_manifest->gamepath[i].flags&GAMEDIR_PRIVATE)
|
||||
fl |= SPF_PRIVATE;
|
||||
if (fs_manifest->gamepath[i].flags&GAMEDIR_QSHACK)
|
||||
fl |= SPF_QSHACK;
|
||||
|
||||
if (fs_manifest->gamepath[i].flags&GAMEDIR_USEBASEDIR)
|
||||
{ //for doom - loading packages without an actual gamedir. note that this does not imply that we can write anything.
|
||||
|
@ -4388,6 +4415,8 @@ static void FS_ReloadPackFilesFlags(unsigned int reloadflags)
|
|||
|
||||
while(oldpaths)
|
||||
{
|
||||
fs_restarts++;
|
||||
|
||||
next = oldpaths->next;
|
||||
|
||||
Con_DPrintf("%s is no longer needed\n", oldpaths->logicalpath);
|
||||
|
@ -4444,7 +4473,6 @@ void FS_ReloadPackFiles(void)
|
|||
FS_FLocateFile("gfx/palette.lmp", 0, &paletteloc2);
|
||||
if (paletteloc.search != paletteloc2.search)
|
||||
Cbuf_AddText("vid_reload\n", RESTRICT_LOCAL);
|
||||
|
||||
}
|
||||
|
||||
static void FS_ReloadPackFiles_f(void)
|
||||
|
@ -5006,6 +5034,7 @@ static ftemanifest_t *FS_GenerateLegacyManifest(int game, const char *basedir)
|
|||
{
|
||||
ftemanifest_t *man;
|
||||
size_t j;
|
||||
const char *cexec;
|
||||
|
||||
if (gamemode_info[game].manifestfile)
|
||||
man = FS_Manifest_ReadMem(NULL, basedir, gamemode_info[game].manifestfile);
|
||||
|
@ -5013,9 +5042,15 @@ static ftemanifest_t *FS_GenerateLegacyManifest(int game, const char *basedir)
|
|||
{
|
||||
man = FS_Manifest_Create(NULL, basedir);
|
||||
|
||||
if (gamemode_info[game].customexec && !strncmp(gamemode_info[game].customexec, "//-nohome\n", 10))
|
||||
for (cexec = gamemode_info[game].customexec; cexec[0] == '/' && cexec[1] == '/'; )
|
||||
{
|
||||
Cmd_TokenizeString("disablehomedir 1", false, false);
|
||||
char line[256];
|
||||
char *e = strchr(cexec, '\n');
|
||||
if (!e)
|
||||
break;
|
||||
Q_strncpyz(line, cexec+2, min(e-(cexec+2)+1, sizeof(line)));
|
||||
cexec = e+1;
|
||||
Cmd_TokenizeString(line, false, false);
|
||||
FS_Manifest_ParseTokens(man);
|
||||
}
|
||||
|
||||
|
@ -5379,7 +5414,7 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
|
|||
#ifdef HAVE_CLIENT
|
||||
qboolean allowvidrestart = true;
|
||||
char *vidfile[] = {"gfx.wad", "gfx/conback.lmp", //misc stuff
|
||||
"gfx/palette.lmp", "pics/colormap.pcx"}; //palettes
|
||||
"gfx/palette.lmp", "pics/colormap.pcx", "gfx/conchars.png"}; //palettes
|
||||
searchpathfuncs_t *vidpath[countof(vidfile)];
|
||||
#endif
|
||||
|
||||
|
|
|
@ -99,6 +99,7 @@ struct modlist_s *Mods_GetMod(size_t diridx);
|
|||
#define SPF_PRIVATE 32 //private to the client. ie: the fte dir. name is not networked.
|
||||
#define SPF_WRITABLE 64 //safe to write here. lots of weird rules etc.
|
||||
#define SPF_BASEPATH 128 //part of the basegames, and not the mod gamedir(s).
|
||||
#define SPF_QSHACK 256 //part of the basegames, and not the mod gamedir(s).
|
||||
qboolean FS_LoadPackageFromFile(vfsfile_t *vfs, char *pname, char *localname, int *crc, unsigned int flags);
|
||||
|
||||
#ifdef AVAIL_XZDEC
|
||||
|
|
|
@ -1291,7 +1291,9 @@ const dtlsfuncs_t *SSPI_DTLS_InitClient(void)
|
|||
#endif
|
||||
|
||||
|
||||
#include <ntstatus.h>
|
||||
//#include <ntstatus.h> //windows sucks too much to actually include this. oh well.
|
||||
#define STATUS_SUCCESS ((NTSTATUS)0x00000000)
|
||||
#define STATUS_INVALID_SIGNATURE ((NTSTATUS)0xC000A000)
|
||||
enum hashvalidation_e SSPI_VerifyHash(qbyte *hashdata, size_t hashsize, const char *authority, qbyte *signdata, size_t signsize)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
@ -1303,8 +1305,8 @@ enum hashvalidation_e SSPI_VerifyHash(qbyte *hashdata, size_t hashsize, const ch
|
|||
size_t dersize;
|
||||
|
||||
static const void *(WINAPI *pCertCreateContext) (DWORD dwContextType, DWORD dwEncodingType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCERT_CREATE_CONTEXT_PARA pCreatePara);
|
||||
static WINBOOL (WINAPI *pCryptImportPublicKeyInfoEx2) (DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD dwFlags, void *pvAuxInfo, BCRYPT_KEY_HANDLE *phKey);
|
||||
static WINBOOL (WINAPI *pCertFreeCertificateContext) (PCCERT_CONTEXT pCertContext);
|
||||
static BOOL (WINAPI *pCryptImportPublicKeyInfoEx2) (DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD dwFlags, void *pvAuxInfo, BCRYPT_KEY_HANDLE *phKey);
|
||||
static BOOL (WINAPI *pCertFreeCertificateContext) (PCCERT_CONTEXT pCertContext);
|
||||
static dllhandle_t *crypt32;
|
||||
static dllfunction_t crypt32funcs[] = {
|
||||
{(void**)&pCertCreateContext, "CertCreateContext"},
|
||||
|
|
|
@ -2305,6 +2305,8 @@ vfsfile_t *FS_OpenSSL(const char *peername, vfsfile_t *source, qboolean isserver
|
|||
if (!f)
|
||||
f = SSPI_OpenVFS(hostname, source, isserver);
|
||||
#endif
|
||||
if (!f) //it all failed.
|
||||
VFS_CLOSE(source);
|
||||
return f;
|
||||
}
|
||||
int TLS_GetChannelBinding(vfsfile_t *stream, qbyte *data, size_t *datasize)
|
||||
|
@ -4627,6 +4629,7 @@ qboolean FTENET_TCP_ParseHTTPRequest(ftenet_tcp_connection_t *con, ftenet_tcp_st
|
|||
qboolean sendingweirdness = false;
|
||||
char arg[WCATTR_COUNT][64];
|
||||
|
||||
|
||||
if (!net_enable_http.ival && !net_enable_websockets.ival && !net_enable_rtcbroker.ival)
|
||||
{
|
||||
//we need to respond, firefox will create 10 different connections if we just close it
|
||||
|
@ -5278,6 +5281,25 @@ static enum{
|
|||
|
||||
if (headerscomplete)
|
||||
{
|
||||
#if defined(SUBSERVERS) && defined(HAVE_SERVER)
|
||||
//this is a new subserver node...
|
||||
if (!Q_strncasecmp(st->inbuffer, "NODE", 4))
|
||||
{
|
||||
char tmpbuf[256];
|
||||
#ifdef HAVE_EPOLL
|
||||
//the tcp connection will be handled elsewhere.
|
||||
//make sure we don't get tcp-handler wakeups from this connection.
|
||||
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, st->socketnum, NULL);
|
||||
st->socketnum = INVALID_SOCKET;
|
||||
st->epoll.Polled = NULL;
|
||||
#endif
|
||||
//now try to pass it over
|
||||
MSV_NewNetworkedNode(st->clientstream, st->inbuffer, st->inbuffer+i, st->inlen-i, NET_AdrToString(tmpbuf, sizeof(tmpbuf), &st->remoteaddr));
|
||||
st->clientstream = NULL; //qtv code took it.
|
||||
return FTETCP_KILL;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef MVD_RECORDING
|
||||
//for QTV connections, we just need the method and a blank line. our qtv parser will parse the actual headers.
|
||||
if (!Q_strncasecmp(st->inbuffer, "QTV", 3))
|
||||
|
@ -8453,6 +8475,23 @@ void NET_Init (void)
|
|||
#if defined(HAVE_CLIENT)||defined(HAVE_SERVER)
|
||||
Net_Master_Init();
|
||||
#endif
|
||||
|
||||
#if defined(SUBSERVERS) && defined(HAVE_SERVER)
|
||||
if (isDedicated && !SSV_IsSubServer())
|
||||
{ //-clusterhost address:port password
|
||||
//connects this server to a remote control/gateway server.
|
||||
int i = COM_CheckParm("-clusterhost");
|
||||
if (i && i+2 < com_argc)
|
||||
{
|
||||
vfsfile_t *f = FS_OpenTCP(com_argv[i+1], PORT_DEFAULTSERVER, true);
|
||||
if (!f)
|
||||
Sys_Error("Unable to resolve/connect to cluster host address \"%s\"\n", com_argv[i+1]);
|
||||
VFS_PRINTF(f, "NODE\r\nPassword: \"%s\"\r\n", com_argv[i+2]);
|
||||
SSV_SetupControlPipe(f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_CLIENT
|
||||
void NET_CloseClient(void)
|
||||
|
@ -8949,12 +8988,23 @@ vfsfile_t *FS_WrapTCPSocket(SOCKET sock, qboolean conpending, const char *peerna
|
|||
|
||||
return &newf->funcs;
|
||||
}
|
||||
vfsfile_t *FS_OpenTCP(const char *name, int defaultport)
|
||||
vfsfile_t *FS_OpenTCP(const char *name, int defaultport, qboolean assumetls)
|
||||
{
|
||||
netadr_t adr = {0};
|
||||
if (NET_StringToAdr(name, defaultport, &adr))
|
||||
{
|
||||
return FS_WrapTCPSocket(TCP_OpenStream(&adr), true, name);
|
||||
qboolean wanttls = (adr.prot == NP_TLS || (adr.prot != NP_STREAM && assumetls));
|
||||
vfsfile_t *f;
|
||||
#ifndef HAVE_SSL
|
||||
if (wanttls)
|
||||
return NULL; //don't even make the connection if we can't satisfy it.
|
||||
#endif
|
||||
f = FS_WrapTCPSocket(TCP_OpenStream(&adr), true, name);
|
||||
#ifdef HAVE_SSL
|
||||
if (f && wanttls)
|
||||
f = FS_OpenSSL(name, f, false);
|
||||
#endif
|
||||
return f;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
|
|
|
@ -453,6 +453,6 @@ int TLS_GetChannelBinding(vfsfile_t *stream, qbyte *data, size_t *datasize); //d
|
|||
#ifdef HAVE_PACKET
|
||||
vfsfile_t *FS_WrapTCPSocket(SOCKET socket, qboolean conpending, const char *peername); //conpending allows us to reject any writes until the connection has succeeded. considers the socket owned (so be sure to stop using the direct socket at least before the VFS_CLOSE call).
|
||||
#endif
|
||||
vfsfile_t *FS_OpenTCP(const char *name, int defaultport);
|
||||
vfsfile_t *FS_OpenTCP(const char *name, int defaultport, qboolean assumetls);
|
||||
|
||||
#endif //NETINC_INCLUDED
|
||||
|
|
|
@ -802,7 +802,7 @@ static qhandle_t QDECL Plug_Net_Accept(qhandle_t handle, char *outaddress, int o
|
|||
static qhandle_t QDECL Plug_Net_TCPConnect(const char *remoteip, int remoteport)
|
||||
{
|
||||
int handle;
|
||||
vfsfile_t *stream = FS_OpenTCP(remoteip, remoteport);
|
||||
vfsfile_t *stream = FS_OpenTCP(remoteip, remoteport, false);
|
||||
if (!currentplug || !stream)
|
||||
return -1;
|
||||
handle = Plug_NewStreamHandle(STREAM_VFS);
|
||||
|
|
|
@ -32,6 +32,7 @@ cvar_t pr_brokenfloatconvert = CVAR("pr_brokenfloatconvert", "0");
|
|||
cvar_t pr_fixbrokenqccarrays = CVARFD("pr_fixbrokenqccarrays", "0", CVAR_LATCH, "As part of its nq/qw/h2/csqc support, FTE remaps QC fields to match an internal order. This is a faster way to handle extended fields. However, some QCCs are buggy and don't report all field defs.\n0: do nothing. QCC must be well behaved.\n1: Duplicate engine fields, remap the ones we can to known offsets. This is sufficient for QCCX/FrikQCC mods that use hardcoded or even occasional calculated offsets (fixes ktpro).\n2: Scan the mod for field accessing instructions, and assume those are the fields (and that they don't alias non-fields). This can be used to work around gmqcc's WTFs (fixes xonotic).");
|
||||
cvar_t pr_tempstringcount = CVARD("pr_tempstringcount", "", "Obsolete. Set to 16 if you want to recycle+reuse the same 16 tempstring references and break lots of mods.");
|
||||
cvar_t pr_tempstringsize = CVARD("pr_tempstringsize", "4096", "Obsolete");
|
||||
cvar_t pr_gc_threaded = CVARD("pr_gc_threaded", "0", "Says whether to use a separate thread for tempstring garbage collections. This avoids main-thread stalls but at the expense of more memory usage.");
|
||||
cvar_t pr_sourcedir = CVARD("pr_sourcedir", "src", "Subdirectory where your qc source is located. Used by the internal compiler and qc debugging functionality.");
|
||||
cvar_t pr_enable_uriget = CVARD("pr_enable_uriget", "1", "Allows gamecode to make direct http requests");
|
||||
cvar_t pr_enable_profiling = CVARD("pr_enable_profiling", "0", "Enables profiling support. Will run more slowly. Change the map and then use the profile_ssqc/profile_csqc commands to see the results.");
|
||||
|
@ -88,6 +89,7 @@ void PF_Common_RegisterCvars(void)
|
|||
Cvar_Register (&pr_brokenfloatconvert, cvargroup_progs);
|
||||
Cvar_Register (&pr_tempstringcount, cvargroup_progs);
|
||||
Cvar_Register (&pr_tempstringsize, cvargroup_progs);
|
||||
Cvar_Register (&pr_gc_threaded, cvargroup_progs);
|
||||
#ifdef WEBCLIENT
|
||||
Cvar_Register (&pr_enable_uriget, cvargroup_progs);
|
||||
#endif
|
||||
|
@ -1222,7 +1224,7 @@ void QCBUILTIN PF_findchainflags (pubprogfuncs_t *prinst, struct globalvars_s *p
|
|||
int s;
|
||||
wedict_t *ent, *chain;
|
||||
|
||||
chain = (wedict_t *) *prinst->parms->sv_edicts;
|
||||
chain = (wedict_t *) *prinst->parms->edicts;
|
||||
|
||||
ff = G_INT(OFS_PARM0)+prinst->fieldadjust;
|
||||
s = G_FLOAT(OFS_PARM1);
|
||||
|
@ -1231,7 +1233,7 @@ void QCBUILTIN PF_findchainflags (pubprogfuncs_t *prinst, struct globalvars_s *p
|
|||
else
|
||||
cf = &((comentvars_t*)NULL)->chain - (int*)NULL;
|
||||
|
||||
for (i = 1; i < *prinst->parms->sv_num_edicts; i++)
|
||||
for (i = 1; i < *prinst->parms->num_edicts; i++)
|
||||
{
|
||||
ent = WEDICT_NUM_PB(prinst, i);
|
||||
if (ED_ISFREE(ent))
|
||||
|
@ -1253,7 +1255,7 @@ void QCBUILTIN PF_findchainfloat (pubprogfuncs_t *prinst, struct globalvars_s *p
|
|||
float s;
|
||||
wedict_t *ent, *chain;
|
||||
|
||||
chain = (wedict_t *) *prinst->parms->sv_edicts;
|
||||
chain = (wedict_t *) *prinst->parms->edicts;
|
||||
|
||||
ff = G_INT(OFS_PARM0)+prinst->fieldadjust;
|
||||
s = G_FLOAT(OFS_PARM1);
|
||||
|
@ -1262,7 +1264,7 @@ void QCBUILTIN PF_findchainfloat (pubprogfuncs_t *prinst, struct globalvars_s *p
|
|||
else
|
||||
cf = &((comentvars_t*)NULL)->chain - (int*)NULL;
|
||||
|
||||
for (i = 1; i < *prinst->parms->sv_num_edicts; i++)
|
||||
for (i = 1; i < *prinst->parms->num_edicts; i++)
|
||||
{
|
||||
ent = WEDICT_NUM_PB(prinst, i);
|
||||
if (ED_ISFREE(ent))
|
||||
|
@ -1286,7 +1288,7 @@ void QCBUILTIN PF_findchain (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
|
|||
string_t t;
|
||||
wedict_t *ent, *chain;
|
||||
|
||||
chain = (wedict_t *) *prinst->parms->sv_edicts;
|
||||
chain = (wedict_t *) *prinst->parms->edicts;
|
||||
|
||||
ff = G_INT(OFS_PARM0)+prinst->fieldadjust;
|
||||
s = PR_GetStringOfs(prinst, OFS_PARM1);
|
||||
|
@ -1295,7 +1297,7 @@ void QCBUILTIN PF_findchain (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
|
|||
else
|
||||
cf = &((comentvars_t*)NULL)->chain - (int*)NULL;
|
||||
|
||||
for (i = 1; i < *prinst->parms->sv_num_edicts; i++)
|
||||
for (i = 1; i < *prinst->parms->num_edicts; i++)
|
||||
{
|
||||
ent = WEDICT_NUM_PB(prinst, i);
|
||||
if (ED_ISFREE(ent))
|
||||
|
@ -1325,7 +1327,7 @@ void QCBUILTIN PF_FindFlags (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
|
|||
f = G_INT(OFS_PARM1)+prinst->fieldadjust;
|
||||
s = G_FLOAT(OFS_PARM2);
|
||||
|
||||
for (e++; e < *prinst->parms->sv_num_edicts; e++)
|
||||
for (e++; e < *prinst->parms->num_edicts; e++)
|
||||
{
|
||||
ed = WEDICT_NUM_PB(prinst, e);
|
||||
if (ED_ISFREE(ed))
|
||||
|
@ -1337,7 +1339,7 @@ void QCBUILTIN PF_FindFlags (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
|
|||
}
|
||||
}
|
||||
|
||||
RETURN_EDICT(prinst, *prinst->parms->sv_edicts);
|
||||
RETURN_EDICT(prinst, *prinst->parms->edicts);
|
||||
}
|
||||
|
||||
//entity(entity start, float fld, float match) findfloat = #98
|
||||
|
@ -1357,7 +1359,7 @@ void QCBUILTIN PF_FindFloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
|
|||
f = G_INT(OFS_PARM1)+prinst->fieldadjust;
|
||||
s = G_INT(OFS_PARM2);
|
||||
|
||||
for (e++; e < *prinst->parms->sv_num_edicts; e++)
|
||||
for (e++; e < *prinst->parms->num_edicts; e++)
|
||||
{
|
||||
ed = WEDICT_NUM_PB(prinst, e);
|
||||
if (ED_ISFREE(ed))
|
||||
|
@ -1369,7 +1371,7 @@ void QCBUILTIN PF_FindFloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
|
|||
}
|
||||
}
|
||||
|
||||
RETURN_EDICT(prinst, *prinst->parms->sv_edicts);
|
||||
RETURN_EDICT(prinst, *prinst->parms->edicts);
|
||||
}
|
||||
|
||||
// entity (entity start, .string field, string match) find = #5;
|
||||
|
@ -1390,7 +1392,7 @@ void QCBUILTIN PF_FindString (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
|
|||
return;
|
||||
}
|
||||
|
||||
for (e++ ; e < *prinst->parms->sv_num_edicts ; e++)
|
||||
for (e++ ; e < *prinst->parms->num_edicts ; e++)
|
||||
{
|
||||
ed = WEDICT_NUM_PB(prinst, e);
|
||||
if (ED_ISFREE(ed))
|
||||
|
@ -1405,7 +1407,7 @@ void QCBUILTIN PF_FindString (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
|
|||
}
|
||||
}
|
||||
|
||||
RETURN_EDICT(prinst, *prinst->parms->sv_edicts);
|
||||
RETURN_EDICT(prinst, *prinst->parms->edicts);
|
||||
}
|
||||
|
||||
//Finding
|
||||
|
@ -3263,9 +3265,9 @@ void QCBUILTIN PF_nextent (pubprogfuncs_t *prinst, struct globalvars_s *pr_globa
|
|||
while (1)
|
||||
{
|
||||
i++;
|
||||
if (i == *prinst->parms->sv_num_edicts)
|
||||
if (i == *prinst->parms->num_edicts)
|
||||
{
|
||||
RETURN_EDICT(prinst, *prinst->parms->sv_edicts);
|
||||
RETURN_EDICT(prinst, *prinst->parms->edicts);
|
||||
return;
|
||||
}
|
||||
ent = WEDICT_NUM_PB(prinst, i);
|
||||
|
|
|
@ -71,6 +71,7 @@ extern cvar_t pr_tempstringsize;
|
|||
extern cvar_t pr_tempstringcount;
|
||||
extern cvar_t pr_enable_profiling;
|
||||
extern cvar_t pr_fixbrokenqccarrays;
|
||||
extern cvar_t pr_gc_threaded;
|
||||
|
||||
extern int qcinput_scan;
|
||||
extern int qcinput_unicode;
|
||||
|
|
|
@ -276,82 +276,71 @@ void Sys_Sleep (double seconds)
|
|||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
typedef struct slaveserver_s
|
||||
typedef struct
|
||||
{
|
||||
pubsubserver_t pub;
|
||||
vfsfile_t pub;
|
||||
|
||||
int inpipe;
|
||||
int outpipe;
|
||||
pid_t pid; //so we don't end up with zombie processes
|
||||
|
||||
qbyte inbuffer[2048];
|
||||
int inbufsize;
|
||||
} linsubserver_t;
|
||||
|
||||
static void Sys_InstructSlave(pubsubserver_t *ps, sizebuf_t *cmd)
|
||||
static int QDECL Sys_MSV_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestoread)
|
||||
{
|
||||
//FIXME: this is blocking. this is bad if the target is also blocking while trying to write to us.
|
||||
//FIXME: merge buffering logic with SSV_InstructMaster, and allow for failure if full
|
||||
linsubserver_t *s = (linsubserver_t*)ps;
|
||||
if (s->outpipe == -1)
|
||||
return; //it already died.
|
||||
cmd->data[0] = cmd->cursize & 0xff;
|
||||
cmd->data[1] = (cmd->cursize>>8) & 0xff;
|
||||
write(s->outpipe, cmd->data, cmd->cursize);
|
||||
}
|
||||
|
||||
static int Sys_SubServerRead(pubsubserver_t *ps)
|
||||
{
|
||||
linsubserver_t *s = (linsubserver_t*)ps;
|
||||
|
||||
if (s->inbufsize < sizeof(s->inbuffer) && s->inpipe != -1)
|
||||
linsubserver_t *s = (linsubserver_t*)file;
|
||||
ssize_t avail = read(s->inpipe, buffer, bytestoread);
|
||||
if (!avail)
|
||||
return -1; //EOF
|
||||
if (avail < 0)
|
||||
{
|
||||
ssize_t avail = read(s->inpipe, s->inbuffer+s->inbufsize, sizeof(s->inbuffer)-s->inbufsize);
|
||||
if (!avail)
|
||||
{ //eof
|
||||
close(s->inpipe);
|
||||
close(s->outpipe);
|
||||
Con_Printf("%i:%s has died\n", s->pub.id, s->pub.name);
|
||||
s->inpipe = -1;
|
||||
s->outpipe = -1;
|
||||
waitpid(s->pid, NULL, 0);
|
||||
}
|
||||
else if (avail < 0)
|
||||
{
|
||||
int e = errno;
|
||||
if (e == EAGAIN || e == EWOULDBLOCK)
|
||||
;
|
||||
else
|
||||
perror("subserver read");
|
||||
}
|
||||
int e = errno;
|
||||
if (e == EAGAIN || e == EWOULDBLOCK || e == EINTR)
|
||||
return 0; //no data available
|
||||
else
|
||||
s->inbufsize += avail;
|
||||
}
|
||||
|
||||
if(s->inbufsize >= 2)
|
||||
{
|
||||
unsigned short len = s->inbuffer[0] | (s->inbuffer[1]<<8);
|
||||
if (s->inbufsize >= len && len>=2)
|
||||
{
|
||||
memcpy(net_message.data, s->inbuffer+2, len-2);
|
||||
net_message.cursize = len-2;
|
||||
memmove(s->inbuffer, s->inbuffer+len, s->inbufsize - len);
|
||||
s->inbufsize -= len;
|
||||
MSG_BeginReading (msg_nullnetprim);
|
||||
|
||||
return 1;
|
||||
perror("subserver read");
|
||||
return -1; //some sort of error
|
||||
}
|
||||
}
|
||||
else if (s->inpipe == -1)
|
||||
return -1;
|
||||
return 0;
|
||||
return avail;
|
||||
}
|
||||
static int QDECL Sys_MSV_WriteBytes (struct vfsfile_s *file, const void *buffer, int bytestowrite)
|
||||
{
|
||||
linsubserver_t *s = (linsubserver_t*)file;
|
||||
ssize_t wrote = write(s->outpipe, buffer, bytestowrite);
|
||||
if (!wrote)
|
||||
return -1; //EOF
|
||||
if (wrote < 0)
|
||||
{
|
||||
int e = errno;
|
||||
if (e == EAGAIN || e == EWOULDBLOCK || e == EINTR)
|
||||
return 0; //no space available
|
||||
else
|
||||
{
|
||||
perror("subserver write");
|
||||
return -1; //some sort of error
|
||||
}
|
||||
}
|
||||
return wrote;
|
||||
}
|
||||
static qboolean QDECL Sys_MSV_Close (struct vfsfile_s *file)
|
||||
{
|
||||
linsubserver_t *s = (linsubserver_t*)file;
|
||||
|
||||
close(s->inpipe);
|
||||
close(s->outpipe);
|
||||
s->inpipe = -1;
|
||||
s->outpipe = -1;
|
||||
waitpid(s->pid, NULL, 0);
|
||||
Z_Free(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef SQL
|
||||
#include "sv_sql.h"
|
||||
#endif
|
||||
|
||||
pubsubserver_t *Sys_ForkServer(void)
|
||||
vfsfile_t *Sys_ForkServer(void)
|
||||
{
|
||||
#ifdef SERVERONLY
|
||||
// extern jmp_buf host_abort;
|
||||
|
@ -473,23 +462,29 @@ pubsubserver_t *Sys_ForkServer(void)
|
|||
close(toslave[0]);
|
||||
ctx->outpipe = toslave[1];
|
||||
|
||||
ctx->pub.funcs.InstructSlave = Sys_InstructSlave;
|
||||
ctx->pub.funcs.SubServerRead = Sys_SubServerRead;
|
||||
ctx->pub.ReadBytes = Sys_MSV_ReadBytes;
|
||||
ctx->pub.WriteBytes = Sys_MSV_WriteBytes;
|
||||
ctx->pub.Close = Sys_MSV_Close;
|
||||
return &ctx->pub;
|
||||
}
|
||||
|
||||
void Sys_InstructMaster(sizebuf_t *cmd)
|
||||
{
|
||||
write(STDOUT_FILENO, cmd->data, cmd->cursize);
|
||||
|
||||
//FIXME: handle partial writes.
|
||||
static int QDECL Sys_StdoutWrite (struct vfsfile_s *file, const void *buffer, int bytestowrite)
|
||||
{
|
||||
ssize_t r = write(STDOUT_FILENO, buffer, bytestowrite);
|
||||
if (r == 0 && bytestowrite)
|
||||
return -1; //eof
|
||||
if (r < 0)
|
||||
{
|
||||
int e = errno;
|
||||
if (e == EINTR || e == EAGAIN || e == EWOULDBLOCK)
|
||||
return 0;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void SSV_CheckFromMaster(void)
|
||||
static int QDECL Sys_StdinRead (struct vfsfile_s *file, void *buffer, int bytestoread)
|
||||
{
|
||||
static char inbuffer[1024];
|
||||
static int inbufsize;
|
||||
|
||||
ssize_t r;
|
||||
#if defined(__linux__) && defined(_DEBUG)
|
||||
int fl = fcntl (STDIN_FILENO, F_GETFL, 0);
|
||||
if (!(fl & FNDELAY))
|
||||
|
@ -499,53 +494,28 @@ void SSV_CheckFromMaster(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
for(;;)
|
||||
r = read(STDIN_FILENO, buffer, bytestoread);
|
||||
if (r == 0 && bytestoread)
|
||||
return -1; //eof
|
||||
if (r < 0)
|
||||
{
|
||||
if(inbufsize >= 2)
|
||||
{
|
||||
unsigned short len = inbuffer[0] | (inbuffer[1]<<8);
|
||||
if (inbufsize >= len && len>=2)
|
||||
{
|
||||
memcpy(net_message.data, inbuffer+2, len-2);
|
||||
net_message.cursize = len-2;
|
||||
memmove(inbuffer, inbuffer+len, inbufsize - len);
|
||||
inbufsize -= len;
|
||||
MSG_BeginReading (msg_nullnetprim);
|
||||
|
||||
SSV_ReadFromControlServer();
|
||||
|
||||
continue; //keep trying to handle it
|
||||
}
|
||||
}
|
||||
|
||||
if (inbufsize == sizeof(inbuffer))
|
||||
{ //fatal: we can't easily recover from this.
|
||||
SV_FinalMessage("Cluster message too large\n");
|
||||
Cmd_ExecuteString("quit force", RESTRICT_LOCAL);
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
ssize_t avail = read(STDIN_FILENO, inbuffer+inbufsize, sizeof(inbuffer)-inbufsize);
|
||||
if (!avail)
|
||||
{ //eof
|
||||
SV_FinalMessage("Cluster shut down\n");
|
||||
Cmd_ExecuteString("quit force", RESTRICT_LOCAL);
|
||||
break;
|
||||
}
|
||||
else if (avail < 0)
|
||||
{
|
||||
int e = errno;
|
||||
if (e == EAGAIN || e == EWOULDBLOCK)
|
||||
;
|
||||
else
|
||||
perror("master read");
|
||||
break;
|
||||
}
|
||||
else
|
||||
inbufsize += avail;
|
||||
}
|
||||
int e = errno;
|
||||
if (e == EINTR || e == EAGAIN || e == EWOULDBLOCK)
|
||||
return 0;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
qboolean QDECL Sys_StdinOutClose(vfsfile_t *fs)
|
||||
{
|
||||
Sys_Error("Shutdown\n");
|
||||
}
|
||||
vfsfile_t *Sys_GetStdInOutStream(void)
|
||||
{
|
||||
vfsfile_t *stream = Z_Malloc(sizeof(*stream));
|
||||
stream->WriteBytes = Sys_StdoutWrite;
|
||||
stream->ReadBytes = Sys_StdinRead;
|
||||
stream->Close = Sys_StdinOutClose;
|
||||
return stream;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -460,66 +460,51 @@ void Sys_DestroyConditional(void *condv)
|
|||
#endif
|
||||
|
||||
#ifdef SUBSERVERS
|
||||
typedef struct slaveserver_s
|
||||
typedef struct
|
||||
{
|
||||
pubsubserver_t pub;
|
||||
vfsfile_t pub;
|
||||
|
||||
HANDLE inpipe;
|
||||
HANDLE outpipe;
|
||||
|
||||
qbyte inbuffer[2048];
|
||||
int inbufsize;
|
||||
} winsubserver_t;
|
||||
|
||||
static void Sys_InstructSlave(pubsubserver_t *ps, sizebuf_t *cmd)
|
||||
{
|
||||
//FIXME: this is blocking. this is bad if the target is also blocking while trying to write to us.
|
||||
//FIXME: merge buffering logic with SSV_InstructMaster, and allow for failure if full
|
||||
winsubserver_t *s = (winsubserver_t*)ps;
|
||||
DWORD written = 0;
|
||||
cmd->data[0] = cmd->cursize & 0xff;
|
||||
cmd->data[1] = (cmd->cursize>>8) & 0xff;
|
||||
WriteFile(s->outpipe, cmd->data, cmd->cursize, &written, NULL);
|
||||
}
|
||||
|
||||
static int Sys_SubServerRead(pubsubserver_t *ps)
|
||||
static int QDECL Sys_MSV_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestoread)
|
||||
{
|
||||
winsubserver_t *s = (winsubserver_t*)file;
|
||||
DWORD avail;
|
||||
winsubserver_t *s = (winsubserver_t*)ps;
|
||||
|
||||
//trying to do this stuff without blocking is a real pain.
|
||||
if (!PeekNamedPipe(s->inpipe, NULL, 0, NULL, &avail, NULL))
|
||||
return -1; //EOF
|
||||
if (avail)
|
||||
{
|
||||
CloseHandle(s->inpipe);
|
||||
CloseHandle(s->outpipe);
|
||||
Con_Printf("%i:%s has died\n", s->pub.id, s->pub.name);
|
||||
return -1;
|
||||
}
|
||||
else if (avail)
|
||||
{
|
||||
if (avail > sizeof(s->inbuffer)-1-s->inbufsize)
|
||||
avail = sizeof(s->inbuffer)-1-s->inbufsize;
|
||||
if (ReadFile(s->inpipe, s->inbuffer+s->inbufsize, avail, &avail, NULL))
|
||||
s->inbufsize += avail;
|
||||
}
|
||||
|
||||
if(s->inbufsize >= 2)
|
||||
{
|
||||
unsigned short len = s->inbuffer[0] | (s->inbuffer[1]<<8);
|
||||
if (s->inbufsize >= len && len>=2)
|
||||
{
|
||||
memcpy(net_message.data, s->inbuffer+2, len-2);
|
||||
net_message.cursize = len-2;
|
||||
memmove(s->inbuffer, s->inbuffer+len, s->inbufsize - len);
|
||||
s->inbufsize -= len;
|
||||
MSG_BeginReading (msg_nullnetprim);
|
||||
|
||||
return 1;
|
||||
}
|
||||
if (avail > bytestoread)
|
||||
avail = bytestoread;
|
||||
if (ReadFile(s->inpipe, buffer, avail, &avail, NULL))
|
||||
return avail;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int QDECL Sys_MSV_WriteBytes (struct vfsfile_s *file, const void *buffer, int bytestowrite)
|
||||
{
|
||||
winsubserver_t *s = (winsubserver_t*)file;
|
||||
DWORD wrote = 0;
|
||||
//blocks. life sucks.
|
||||
if (!WriteFile(s->outpipe, buffer, bytestowrite, &wrote, NULL))
|
||||
return -1;
|
||||
return wrote;
|
||||
}
|
||||
static qboolean QDECL Sys_MSV_Close (struct vfsfile_s *file)
|
||||
{
|
||||
winsubserver_t *s = (winsubserver_t*)file;
|
||||
|
||||
pubsubserver_t *Sys_ForkServer(void)
|
||||
CloseHandle(s->inpipe);
|
||||
CloseHandle(s->outpipe);
|
||||
//we already closed any process handles. the child will detect its input became unreadable and take that as a signal to die.
|
||||
Z_Free(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
vfsfile_t *Sys_ForkServer(void)
|
||||
{
|
||||
wchar_t exename[256];
|
||||
wchar_t curdir[256];
|
||||
|
@ -560,8 +545,9 @@ pubsubserver_t *Sys_ForkServer(void)
|
|||
CloseHandle(startinfo.hStdOutput);
|
||||
CloseHandle(startinfo.hStdInput);
|
||||
|
||||
ctx->pub.funcs.InstructSlave = Sys_InstructSlave;
|
||||
ctx->pub.funcs.SubServerRead = Sys_SubServerRead;
|
||||
ctx->pub.ReadBytes = Sys_MSV_ReadBytes;
|
||||
ctx->pub.WriteBytes = Sys_MSV_WriteBytes;
|
||||
ctx->pub.Close = Sys_MSV_Close;
|
||||
return &ctx->pub;
|
||||
}
|
||||
|
||||
|
|
|
@ -471,6 +471,41 @@ void GL_SetupFormats(void)
|
|||
glfmtb(PTI_ASTC_12X10_HDR, GL_COMPRESSED_RGBA_ASTC_12x10_KHR);
|
||||
glfmtb(PTI_ASTC_12X12_HDR, GL_COMPRESSED_RGBA_ASTC_12x12_KHR);
|
||||
}
|
||||
#ifdef ASTC3D
|
||||
if (sh_config.hw_astc >= 3)
|
||||
{ //the full profile gives 3d texture support too
|
||||
glfmtb(PTI_ASTC_3X3X3_LDR, GL_COMPRESSED_RGBA_ASTC_3x3x3_OES);
|
||||
glfmtb(PTI_ASTC_4X3X3_LDR, GL_COMPRESSED_RGBA_ASTC_4x3x3_OES);
|
||||
glfmtb(PTI_ASTC_4X4X3_LDR, GL_COMPRESSED_RGBA_ASTC_4x4x3_OES);
|
||||
glfmtb(PTI_ASTC_4X4X4_LDR, GL_COMPRESSED_RGBA_ASTC_4x4x4_OES);
|
||||
glfmtb(PTI_ASTC_5X4X4_LDR, GL_COMPRESSED_RGBA_ASTC_5x4x4_OES);
|
||||
glfmtb(PTI_ASTC_5X5X4_LDR, GL_COMPRESSED_RGBA_ASTC_5x5x4_OES);
|
||||
glfmtb(PTI_ASTC_5X5X5_LDR, GL_COMPRESSED_RGBA_ASTC_5x5x5_OES);
|
||||
glfmtb(PTI_ASTC_6X5X5_LDR, GL_COMPRESSED_RGBA_ASTC_6x5x5_OES);
|
||||
glfmtb(PTI_ASTC_6X6X5_LDR, GL_COMPRESSED_RGBA_ASTC_6x6x5_OES);
|
||||
glfmtb(PTI_ASTC_6X6X6_LDR, GL_COMPRESSED_RGBA_ASTC_6x6x6_OES);
|
||||
glfmtb(PTI_ASTC_3X3X3_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES);
|
||||
glfmtb(PTI_ASTC_4X3X3_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES);
|
||||
glfmtb(PTI_ASTC_4X4X3_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES);
|
||||
glfmtb(PTI_ASTC_4X4X4_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES);
|
||||
glfmtb(PTI_ASTC_5X4X4_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES);
|
||||
glfmtb(PTI_ASTC_5X5X4_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES);
|
||||
glfmtb(PTI_ASTC_5X5X5_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES);
|
||||
glfmtb(PTI_ASTC_6X5X5_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES);
|
||||
glfmtb(PTI_ASTC_6X6X5_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES);
|
||||
glfmtb(PTI_ASTC_6X6X6_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES);
|
||||
glfmtb(PTI_ASTC_3X3X3_HDR, GL_COMPRESSED_RGBA_ASTC_3x3x3_OES);
|
||||
glfmtb(PTI_ASTC_4X3X3_HDR, GL_COMPRESSED_RGBA_ASTC_4x3x3_OES);
|
||||
glfmtb(PTI_ASTC_4X4X3_HDR, GL_COMPRESSED_RGBA_ASTC_4x4x3_OES);
|
||||
glfmtb(PTI_ASTC_4X4X4_HDR, GL_COMPRESSED_RGBA_ASTC_4x4x4_OES);
|
||||
glfmtb(PTI_ASTC_5X4X4_HDR, GL_COMPRESSED_RGBA_ASTC_5x4x4_OES);
|
||||
glfmtb(PTI_ASTC_5X5X4_HDR, GL_COMPRESSED_RGBA_ASTC_5x5x4_OES);
|
||||
glfmtb(PTI_ASTC_5X5X5_HDR, GL_COMPRESSED_RGBA_ASTC_5x5x5_OES);
|
||||
glfmtb(PTI_ASTC_6X5X5_HDR, GL_COMPRESSED_RGBA_ASTC_6x5x5_OES);
|
||||
glfmtb(PTI_ASTC_6X6X5_HDR, GL_COMPRESSED_RGBA_ASTC_6x6x5_OES);
|
||||
glfmtb(PTI_ASTC_6X6X6_HDR, GL_COMPRESSED_RGBA_ASTC_6x6x6_OES);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -732,7 +767,7 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips)
|
|||
uploadfmt_t encoding = mips->encoding;
|
||||
qboolean compress;
|
||||
qboolean storage = true;
|
||||
unsigned int bb, bw, bh;
|
||||
unsigned int bb, bw, bh, bd;
|
||||
int levels = 0, genlevels;
|
||||
int ttype = (tex->flags & IF_TEXTYPEMASK)>>IF_TEXTYPESHIFT;
|
||||
|
||||
|
@ -901,7 +936,7 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips)
|
|||
qglTexParameteri(targ, GL_TEXTURE_SWIZZLE_A, gl_config.formatinfo[encoding].swizzle_a);
|
||||
}
|
||||
|
||||
Image_BlockSizeForEncoding(encoding, &bb, &bw, &bh);
|
||||
Image_BlockSizeForEncoding(encoding, &bb, &bw, &bh, &bd);
|
||||
switch(bb)
|
||||
{
|
||||
case 3:
|
||||
|
|
|
@ -2682,6 +2682,8 @@ int Font_LineBreaks(conchar_t *start, conchar_t *end, int maxpixelwidth, int max
|
|||
|
||||
for (;;)
|
||||
{
|
||||
if (l >= end)
|
||||
break;
|
||||
n = Font_Decode(l, &codeflags, &codepoint);
|
||||
if (!(codeflags & CON_HIDDEN) && (codepoint != ' '))
|
||||
break;
|
||||
|
|
|
@ -3389,7 +3389,7 @@ static void Mod_LoadMiptex(model_t *loadmodel, texture_t *tx, miptex_t *mt, size
|
|||
for (; extofs < miptexsize; extofs += extsize)
|
||||
{
|
||||
size_t sz, w, h;
|
||||
unsigned int bb,bw,bh;
|
||||
unsigned int bb,bw,bh,bd;
|
||||
int mip;
|
||||
qbyte *extdata = (void*)((qbyte*)mt+extofs);
|
||||
char *extfmt = (char*)(extdata+4);
|
||||
|
@ -3447,7 +3447,7 @@ static void Mod_LoadMiptex(model_t *loadmodel, texture_t *tx, miptex_t *mt, size
|
|||
//alternative textures are usually compressed
|
||||
//this means we insist on a FULL mip chain
|
||||
//npot mips are explicitly round-down (but don't drop to 0 with non-square).
|
||||
Image_BlockSizeForEncoding(newfmt, &bb, &bw, &bh);
|
||||
Image_BlockSizeForEncoding(newfmt, &bb, &bw, &bh, &bd);
|
||||
neww = (extdata[8]<<0)|(extdata[9]<<8)|(extdata[10]<<16)|(extdata[11]<<24);
|
||||
newh = (extdata[12]<<0)|(extdata[13]<<8)|(extdata[14]<<16)|(extdata[15]<<24);
|
||||
for (mip = 0, w=neww, h=newh, sz=0; w || h; mip++, w>>=1,h>>=1)
|
||||
|
|
|
@ -107,6 +107,7 @@ void R_AnimateLight (void)
|
|||
{
|
||||
int i,j;
|
||||
float f;
|
||||
static int fbmodcount;
|
||||
|
||||
|
||||
//if (r_lightstylescale.value > 2)
|
||||
|
@ -121,7 +122,12 @@ void R_AnimateLight (void)
|
|||
i = (int)f;
|
||||
f -= i; //this can require updates at 1000 times a second.. Depends on your framerate of course
|
||||
|
||||
for (j=0 ; j<cl_max_lightstyles ; j++)
|
||||
if (r_fullbright.value)
|
||||
{
|
||||
for (j=0 ; j<cl_max_lightstyles ; j++)
|
||||
d_lightstylevalue[j] = r_fullbright.value*255;
|
||||
}
|
||||
else for (j=0 ; j<cl_max_lightstyles ; j++)
|
||||
{
|
||||
int v1, v2, vd;
|
||||
if (!cl_lightstyle[j].length)
|
||||
|
@ -148,6 +154,18 @@ void R_AnimateLight (void)
|
|||
else
|
||||
d_lightstylevalue[j] = (v1*(1-f) + v2*(f))*22*r_lightstylescale.value;
|
||||
}
|
||||
|
||||
if (r_fullbright.modified != fbmodcount)
|
||||
{
|
||||
fbmodcount = r_fullbright.modified;
|
||||
for (j=0 ; j<cl_max_lightstyles ; j++)
|
||||
{
|
||||
if (r_fullbright.value)
|
||||
cl_lightstyle[j].colourkey = 0xff;
|
||||
else
|
||||
cl_lightstyle[j].colourkey = (int)(cl_lightstyle[j].colours[0]*0x400) ^ (int)(cl_lightstyle[j].colours[1]*0x100000) ^ (int)(cl_lightstyle[j].colours[2]*0x40000000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1640,6 +1640,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
|
|||
var = Cvar_Get(namebuf, valuebuf, CVAR_SHADERSYSTEM, "GLSL Variables");
|
||||
if (var)
|
||||
{
|
||||
var->flags |= CVAR_SHADERSYSTEM;
|
||||
if (srgb)
|
||||
{
|
||||
if (type == '4')
|
||||
|
@ -6459,7 +6460,7 @@ char *Shader_DefaultBSPWater(parsestate_t *ps, const char *shortname, char *buff
|
|||
return (
|
||||
"{\n"
|
||||
"{\n"
|
||||
// "program defaultfill\n"
|
||||
//"program defaultfill\n"
|
||||
"map $whiteimage\n"
|
||||
"rgbgen srgb $r_fastturbcolour\n"
|
||||
"}\n"
|
||||
|
@ -6485,7 +6486,7 @@ char *Shader_DefaultBSPWater(parsestate_t *ps, const char *shortname, char *buff
|
|||
"}\n"
|
||||
"surfaceparm hasdiffuse\n"
|
||||
"}\n"
|
||||
, explicitalpha?"":va("#ALPHA=%g",alpha), alpha, alpha);
|
||||
, (explicitalpha||alpha==1)?"":va("#ALPHA=%g",alpha), alpha, alpha);
|
||||
return buffer;
|
||||
case 2: //refraction of the underwater surface, with a fresnel
|
||||
return (
|
||||
|
|
|
@ -4176,8 +4176,8 @@ qboolean Sh_StencilShadowsActive(void)
|
|||
{
|
||||
#if defined(RTLIGHTS) && !defined(SERVERONLY)
|
||||
//if shadowmapping is forced on all lights then we don't need special depth stuff
|
||||
// if (r_shadow_shadowmapping.ival)
|
||||
// return false;
|
||||
if (r_shadow_shadowmapping.ival)
|
||||
return false;
|
||||
if (isDedicated)
|
||||
return false;
|
||||
return (r_shadow_realtime_dlight.ival && r_shadow_realtime_dlight_shadows.ival) ||
|
||||
|
|
|
@ -1518,7 +1518,11 @@ static const char *glsl_hdrs[] =
|
|||
"uniform vec3 v_eyepos;"
|
||||
"uniform vec4 w_fog[2];\n"
|
||||
"#define w_fogcolour w_fog[0].rgb\n"
|
||||
"#ifdef FOG\n"
|
||||
"#define w_fogalpha w_fog[0].a\n"
|
||||
"#else\n"
|
||||
"#define w_fogalpha 0.0\n"
|
||||
"#endif\n"
|
||||
"#define w_fogdensity w_fog[1].x\n"
|
||||
"#define w_fogdepthbias w_fog[1].y\n"
|
||||
"uniform vec4 w_user[16];\n"
|
||||
|
@ -1796,7 +1800,7 @@ static const char *glsl_hdrs[] =
|
|||
"return vec4(fog3(regularcolour.rgb), 1.0) * regularcolour.a;\n"
|
||||
"}\n"
|
||||
"vec4 fog4additive(in vec4 regularcolour)"
|
||||
"{"
|
||||
"{" //fog function for additive blends
|
||||
"float z = w_fogdensity * gl_FragCoord.z / gl_FragCoord.w;\n"
|
||||
"z = max(0.0,z-w_fogdepthbias);\n"
|
||||
"#if #include \"cvar/r_fog_exp2\"\n"
|
||||
|
@ -1807,7 +1811,7 @@ static const char *glsl_hdrs[] =
|
|||
"return regularcolour * vec4(fac, fac, fac, 1.0);\n"
|
||||
"}\n"
|
||||
"vec4 fog4blend(in vec4 regularcolour)"
|
||||
"{"
|
||||
"{" //fog function for regular alpha blends (uses the blend for fading, to avoid fighting the surface behind)
|
||||
"float z = w_fogdensity * gl_FragCoord.z / gl_FragCoord.w;\n"
|
||||
"z = max(0.0,z-w_fogdepthbias);\n"
|
||||
"#if #include \"cvar/r_fog_exp2\"\n"
|
||||
|
@ -1818,6 +1822,7 @@ static const char *glsl_hdrs[] =
|
|||
"return regularcolour * vec4(1.0, 1.0, 1.0, fac);\n"
|
||||
"}\n"
|
||||
"#else\n"
|
||||
"#define w_fogalpha 0.0\n"
|
||||
/*don't use macros for this - mesa bugs out*/
|
||||
"vec3 fog3(in vec3 regularcolour) { return regularcolour; }\n"
|
||||
"vec3 fog3additive(in vec3 regularcolour) { return regularcolour; }\n"
|
||||
|
|
|
@ -35,6 +35,7 @@ static void GL_DrawSkyGrid (texnums_t *tex);
|
|||
extern cvar_t gl_skyboxdist;
|
||||
extern cvar_t r_fastsky;
|
||||
extern cvar_t r_fastskycolour;
|
||||
extern cvar_t r_skycloudalpha;
|
||||
|
||||
static shader_t *forcedsky;
|
||||
static shader_t *skyboxface;
|
||||
|
@ -1100,13 +1101,14 @@ void R_InitSky (shader_t *shader, const char *skyname, uploadfmt_t fmt, qbyte *s
|
|||
if (fmt & PTI_FULLMIPCHAIN)
|
||||
{ //input is expected to make sense...
|
||||
qbyte *front, *back;
|
||||
unsigned int bb, bw, bh;
|
||||
unsigned int bb, bw, bh, bd;
|
||||
unsigned int w, h, y;
|
||||
fmt = fmt&~PTI_FULLMIPCHAIN;
|
||||
Image_BlockSizeForEncoding(fmt, &bb, &bw, &bh);
|
||||
Image_BlockSizeForEncoding(fmt, &bb, &bw, &bh, &bd);
|
||||
|
||||
w = (width+bw-1)/bw;
|
||||
h = (height+bh-1)/bh;
|
||||
//d = (depth+bd-1)/bd;
|
||||
|
||||
back = BZ_Malloc(bb*w*2*h);
|
||||
front = back + bb*w*h;
|
||||
|
@ -1162,7 +1164,9 @@ void R_InitSky (shader_t *shader, const char *skyname, uploadfmt_t fmt, qbyte *s
|
|||
((qbyte *)&transpix)[1] = g/(width*height);
|
||||
((qbyte *)&transpix)[2] = b/(width*height);
|
||||
((qbyte *)&transpix)[3] = 0;
|
||||
alphamask = LittleLong(0x7fffffff);
|
||||
alphamask = r_skycloudalpha.value*255;
|
||||
alphamask = ((bound(0, alphamask, 0xff)<<24) | 0x00ffffff);
|
||||
alphamask = LittleLong(alphamask);
|
||||
for (i=0 ; i<height ; i++)
|
||||
for (j=0 ; j<width ; j++)
|
||||
{
|
||||
|
|
|
@ -773,6 +773,28 @@ typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei
|
|||
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC
|
||||
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD
|
||||
#endif
|
||||
#ifndef GL_COMPRESSED_RGBA_ASTC_3x3x3_OES
|
||||
#define GL_COMPRESSED_RGBA_ASTC_3x3x3_OES 0x93C0
|
||||
#define GL_COMPRESSED_RGBA_ASTC_4x3x3_OES 0x93C1
|
||||
#define GL_COMPRESSED_RGBA_ASTC_4x4x3_OES 0x93C2
|
||||
#define GL_COMPRESSED_RGBA_ASTC_4x4x4_OES 0x93C3
|
||||
#define GL_COMPRESSED_RGBA_ASTC_5x4x4_OES 0x93C4
|
||||
#define GL_COMPRESSED_RGBA_ASTC_5x5x4_OES 0x93C5
|
||||
#define GL_COMPRESSED_RGBA_ASTC_5x5x5_OES 0x93C6
|
||||
#define GL_COMPRESSED_RGBA_ASTC_6x5x5_OES 0x93C7
|
||||
#define GL_COMPRESSED_RGBA_ASTC_6x6x5_OES 0x93C8
|
||||
#define GL_COMPRESSED_RGBA_ASTC_6x6x6_OES 0x93C9
|
||||
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES 0x93E0
|
||||
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES 0x93E1
|
||||
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES 0x93E2
|
||||
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES 0x93E3
|
||||
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES 0x93E4
|
||||
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES 0x93E5
|
||||
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES 0x93E6
|
||||
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES 0x93E7
|
||||
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES 0x93E8
|
||||
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES 0x93E9
|
||||
#endif
|
||||
|
||||
#ifndef GL_ARB_pixel_buffer_object
|
||||
#define GL_PIXEL_PACK_BUFFER_ARB 0x88EB
|
||||
|
|
|
@ -363,6 +363,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"!!samps =REFLECT reflect=1\n"
|
||||
"!!samps =RIPPLEMAP ripplemap=2\n"
|
||||
"!!samps =DEPTH refractdepth=3\n"
|
||||
"!!permu FOG\n"
|
||||
|
||||
"#include \"sys/defs.h\"\n"
|
||||
|
||||
|
@ -445,9 +446,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"}\n"
|
||||
"#endif\n"
|
||||
"#ifdef FRAGMENT_SHADER\n"
|
||||
"#ifdef ALPHA\n"
|
||||
"#include \"sys/fog.h\"\n"
|
||||
"#endif\n"
|
||||
|
||||
|
||||
"void main (void)\n"
|
||||
|
@ -536,6 +535,8 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"vec4 ts = texture2D(s_diffuse, ntc);\n"
|
||||
"vec4 surf = fog4blend(vec4(ts.rgb, float(ALPHA)*ts.a));\n"
|
||||
"refr = mix(refr, surf.rgb, surf.a);\n"
|
||||
"#else\n"
|
||||
"refr = fog3(refr); \n"
|
||||
"#endif\n"
|
||||
|
||||
//done
|
||||
|
@ -4159,7 +4160,8 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
#ifdef GLQUAKE
|
||||
{QR_OPENGL, 110, "defaultsky",
|
||||
"!!permu FOG\n"
|
||||
"!!samps 2\n"
|
||||
"!!samps base=0, cloud=1\n"
|
||||
"!!cvardf r_skyfog=0.5\n"
|
||||
"#include \"sys/fog.h\"\n"
|
||||
|
||||
//regular sky shader for scrolling q1 skies
|
||||
|
@ -4184,10 +4186,15 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"dir.z *= 3.0;\n"
|
||||
"dir.xy /= 0.5*length(dir);\n"
|
||||
"tccoord = (dir.xy + e_time*0.03125);\n"
|
||||
"vec3 solid = vec3(texture2D(s_t0, tccoord));\n"
|
||||
"vec3 sky = vec3(texture2D(s_base, tccoord));\n"
|
||||
"tccoord = (dir.xy + e_time*0.0625);\n"
|
||||
"vec4 clouds = texture2D(s_t1, tccoord);\n"
|
||||
"gl_FragColor = vec4(fog3((solid.rgb*(1.0-clouds.a)) + (clouds.a*clouds.rgb)), 1.0);\n"
|
||||
"vec4 clouds = texture2D(s_cloud, tccoord);\n"
|
||||
"sky = (sky.rgb*(1.0-clouds.a)) + (clouds.a*clouds.rgb);\n"
|
||||
"#ifdef FOG\n"
|
||||
"sky.rgb = mix(sky.rgb, w_fogcolour, float(r_skyfog)*w_fogalpha); //flat fog ignoring actual geometry\n"
|
||||
//sky = fog3(sky); //fog according to actual geometry
|
||||
"#endif\n"
|
||||
"gl_FragColor = vec4(sky, 1.0);\n"
|
||||
"}\n"
|
||||
"#endif\n"
|
||||
},
|
||||
|
@ -4643,7 +4650,14 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"void main ()\n"
|
||||
"{\n"
|
||||
"vec4 skybox = textureCube(s_reflectcube, pos);\n"
|
||||
"gl_FragColor = vec4(mix(skybox.rgb, fog3(skybox.rgb), float(r_skyfog)), 1.0);\n"
|
||||
|
||||
//Fun question: should sky be fogged as if infinite, or as if an actual surface?
|
||||
"#if 1\n"
|
||||
"skybox.rgb = mix(skybox.rgb, w_fogcolour_ float(r_skyfog)*w_fogalpha); //flat fog ignoring actual geometry\n"
|
||||
"#else\n"
|
||||
"skybox.rgb = mix(skybox.rgb, fog3(skybox.rgb), float(r_skyfog)); //fog in terms of actual geometry distance\n"
|
||||
"#endif\n"
|
||||
"gl_FragColor = skybox;\n"
|
||||
"}\n"
|
||||
"#endif\n"
|
||||
},
|
||||
|
@ -5617,7 +5631,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"!!ver 100 450\n"
|
||||
"!!permu TESS\n"
|
||||
"!!permu DELUXE\n"
|
||||
"!!permu FULLBRIGHT\n"
|
||||
"!!permu FULLBRIGHT //lumas rather than no lightmaps\n"
|
||||
"!!permu FOG\n"
|
||||
"!!permu LIGHTSTYLED\n"
|
||||
"!!permu BUMP\n"
|
||||
|
@ -5634,7 +5648,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
//diffuse gives us alpha, and prevents dlight from bugging out when there's no diffuse.
|
||||
"!!samps =EIGHTBIT paletted 1\n"
|
||||
"!!samps =SPECULAR specular\n"
|
||||
"!!samps lightmap\n"
|
||||
"!!samps !VERTEXLIT lightmap\n"
|
||||
"!!samps =LIGHTSTYLED lightmap1 lightmap2 lightmap3\n"
|
||||
"!!samps =DELUXE deluxemap\n"
|
||||
"!!samps =LIGHTSTYLED =DELUXE deluxemap1 deluxemap2 deluxemap3\n"
|
||||
|
@ -5885,7 +5899,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
//optional: round the lightmap coords to ensure all pixels within a texel have different lighting values either. it just looks wrong otherwise.
|
||||
//don't bother if its lightstyled, such cases will have unpredictable correlations anyway.
|
||||
//FIXME: this rounding is likely not correct with respect to software rendering. oh well.
|
||||
"#if __VERSION__ >= 130\n"
|
||||
"#if __VERSION__ >= 130 && !defined(VERTEXLIT)\n"
|
||||
"vec2 lmsize = vec2(textureSize(s_lightmap0, 0));\n"
|
||||
"#else\n"
|
||||
"#define lmsize vec2(128.0,2048.0)\n"
|
||||
|
@ -7021,7 +7035,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
{QR_OPENGL, 110, "defaultwarp",
|
||||
"!!ver 100 450\n"
|
||||
"!!permu FOG\n"
|
||||
"!!cvarf r_wateralpha\n"
|
||||
"!!samps diffuse lightmap\n"
|
||||
|
||||
"#include \"sys/defs.h\"\n"
|
||||
|
@ -7030,6 +7043,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
//this is expected to be moderately fast.
|
||||
|
||||
"#include \"sys/fog.h\"\n"
|
||||
|
||||
"varying vec2 tc;\n"
|
||||
"#ifdef LIT\n"
|
||||
"varying vec2 lm0;\n"
|
||||
|
@ -7048,12 +7062,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"}\n"
|
||||
"#endif\n"
|
||||
"#ifdef FRAGMENT_SHADER\n"
|
||||
"#ifndef ALPHA\n"
|
||||
"uniform float cvar_r_wateralpha;\n"
|
||||
"#define USEALPHA cvar_r_wateralpha\n"
|
||||
"#else\n"
|
||||
"#define USEALPHA float(ALPHA)\n"
|
||||
"#endif\n"
|
||||
"void main ()\n"
|
||||
"{\n"
|
||||
"vec2 ntc;\n"
|
||||
|
@ -7065,7 +7073,11 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"ts *= (texture2D(s_lightmap, lm0) * e_lmscale).rgb;\n"
|
||||
"#endif\n"
|
||||
|
||||
"gl_FragColor = fog4blend(vec4(ts, USEALPHA) * e_colourident);\n"
|
||||
"#ifdef ALPHA\n"
|
||||
"gl_FragColor = fog4blend(vec4(ts, float(ALPHA)) * e_colourident);\n"
|
||||
"#else\n"
|
||||
"gl_FragColor = fog4(vec4(ts, 1.0) * e_colourident);\n"
|
||||
"#endif\n"
|
||||
"}\n"
|
||||
"#endif\n"
|
||||
},
|
||||
|
|
|
@ -1116,15 +1116,86 @@ void QCBUILTIN PF_memsetval (pubprogfuncs_t *inst, struct globalvars_s *globals)
|
|||
|
||||
//#define GCTIMINGS
|
||||
|
||||
#ifdef QCGC
|
||||
#define smallbool char
|
||||
static smallbool *PR_QCGC_Mark(void *mem, size_t memsize, size_t numtemps)
|
||||
{
|
||||
unsigned int *str; //the reference we're considering
|
||||
size_t p;
|
||||
smallbool *marked; //just booleans. could compact.
|
||||
marked = malloc(sizeof(*marked) * numtemps);
|
||||
memset(marked, 0, sizeof(*marked) * numtemps);
|
||||
|
||||
//mark everything the qc has access to, even if it isn't even a string!
|
||||
//note that I did try specifically checking only data explicitly marked as a string type, but that was:
|
||||
//a) a smidge slower (lots of extra loops and conditions I guess)
|
||||
//b) doesn't work with pointers/structs (yes, we assume it'll all be aligned).
|
||||
//c) both methods got the same number of false positives in my test (2, probably dead strunzoned references)
|
||||
for (str = mem, p = 0; p < memsize; p+=sizeof(*str), str++)
|
||||
{
|
||||
if ((*str & STRING_SPECMASK) == STRING_TEMP)
|
||||
{
|
||||
unsigned int idx = *str &~ STRING_SPECMASK;
|
||||
if (idx < numtemps)
|
||||
marked[idx] = true;
|
||||
}
|
||||
}
|
||||
return marked;
|
||||
}
|
||||
static size_t PR_QCGC_Sweep(progfuncs_t *progfuncs, smallbool *marked, tempstr_t **tempstrings, unsigned int numtemps)
|
||||
{
|
||||
unsigned int p;
|
||||
unsigned int swept = 0;
|
||||
#ifdef GCTIMINGS
|
||||
unsigned int unswept = 0;
|
||||
unsigned int errors = 0;
|
||||
#endif
|
||||
for (p = 0; p < numtemps; p++)
|
||||
{
|
||||
if (marked[p])
|
||||
{ //still live...
|
||||
#ifdef GCTIMINGS
|
||||
unswept++;
|
||||
|
||||
if (!tempstrings[p])
|
||||
errors++;
|
||||
#endif
|
||||
}
|
||||
else if (tempstrings[p])
|
||||
{ //not marked, but was valid at the time our snapshot was taken
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (tempstrings[p] != prinst.tempstrings[p])
|
||||
{ //something weird happened. tempstrings are supposed to be immutable (at least in length).
|
||||
externs->Sys_Error("tempstring was reallocated while qc was running");
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
swept++;
|
||||
|
||||
//FIXME: Security Race: its possible for a mod to do weird manipulations to access the tempstring while we're still freeing it, allowing it to read something outside of its sandbox.
|
||||
//one option would be to have the main thread bounce it back to the worker after its complete, so we can actually free the memory only after main thread has acknowledged that its tempstrings are nulled.
|
||||
prinst.tempstrings[p] = NULL;
|
||||
|
||||
externs->memfree(tempstrings[p]);
|
||||
}
|
||||
}
|
||||
|
||||
free(marked);
|
||||
|
||||
return swept;
|
||||
}
|
||||
|
||||
#ifdef THREADEDGC
|
||||
#include "quakedef.h"
|
||||
struct qcgccontext_s
|
||||
{
|
||||
int done;
|
||||
size_t clearedtemps; //number of temps that were swept away
|
||||
unsigned int clearedtemps; //number of temps that were swept away
|
||||
progfuncs_t *progfuncs; //careful!
|
||||
|
||||
size_t numtemps; //so it doesn't go stale
|
||||
size_t maxtemps; //so it doesn't go stale
|
||||
tempstr_t **tempstrings;//so we don't get confused over temps added while marking
|
||||
|
||||
size_t memsize;
|
||||
|
@ -1138,91 +1209,39 @@ void PR_QCGC_Done(void *ctx, void *data, size_t a, size_t b)
|
|||
void PR_QCGC_Thread(void *ctx, void *data, size_t a, size_t b)
|
||||
{
|
||||
struct qcgccontext_s *gc = ctx;
|
||||
unsigned int p, r_d;
|
||||
char *marked, *t;
|
||||
unsigned int *str;
|
||||
size_t numtemps = gc->numtemps;
|
||||
progfuncs_t *progfuncs = gc->progfuncs;
|
||||
smallbool *marked;
|
||||
|
||||
#ifdef GCTIMINGS
|
||||
unsigned int r_l;
|
||||
double starttime, markedtime, endtime;
|
||||
starttime = Sys_DoubleTime();
|
||||
#endif
|
||||
|
||||
marked = malloc(sizeof(*marked) * numtemps);
|
||||
memset(marked, 0, sizeof(*marked) * numtemps);
|
||||
|
||||
//mark everything the qc has access to, even if it isn't even a string!
|
||||
//note that I did try specifically checking only data explicitly marked as a string type, but that was:
|
||||
//a) a smidge slower (lots of extra loops and conditions I guess)
|
||||
//b) doesn't work with pointers/structs (yes, we assume it'll all be aligned).
|
||||
//c) both methods got the same number of false positives in my test (2, probably dead strunzoned references)
|
||||
for (str = gc->amem, p = 0; p < gc->memsize; p+=sizeof(*str), str++)
|
||||
{
|
||||
if ((*str & STRING_SPECMASK) == STRING_TEMP)
|
||||
{
|
||||
unsigned int idx = *str &~ STRING_SPECMASK;
|
||||
if (idx < numtemps)
|
||||
marked[idx] = true;
|
||||
}
|
||||
}
|
||||
|
||||
marked = PR_QCGC_Mark(gc->amem, gc->memsize, gc->maxtemps);
|
||||
#ifdef GCTIMINGS
|
||||
markedtime = Sys_DoubleTime();
|
||||
#endif
|
||||
|
||||
//sweep
|
||||
#ifdef GCTIMINGS
|
||||
r_l = 0;
|
||||
#endif
|
||||
r_d = 0;
|
||||
for (p = 0; p < numtemps; p++)
|
||||
{
|
||||
if (marked[p])
|
||||
{
|
||||
#ifdef GCTIMINGS
|
||||
r_l++;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
// prinst.nexttempstring = p;
|
||||
for (; p < numtemps; p++)
|
||||
{
|
||||
if (marked[p])
|
||||
{ //still live...
|
||||
#ifdef GCTIMINGS
|
||||
r_l++;
|
||||
#endif
|
||||
}
|
||||
else if (gc->tempstrings[p])
|
||||
{ //not marked, but was valid at the time our snapshot was taken
|
||||
r_d++;
|
||||
|
||||
//FIXME: Security Race: its possible for a mod to do weird manipulations to access the tempstring while we're still freeing it, allowing it to read something outside of its sandbox.
|
||||
//one option would be to have the main thread bounce it back to the worker after its complete, so we can actually free the memory only after main thread has acknowledged that its tempstrings are nulled.
|
||||
gc->prinst.tempstrings[p] = NULL;
|
||||
|
||||
gc->externs->memfree(gc->tempstrings[p]);
|
||||
}
|
||||
}
|
||||
gc->clearedtemps = r_d;
|
||||
|
||||
free(marked);
|
||||
|
||||
gc->clearedtemps = PR_QCGC_Sweep(progfuncs, marked, gc->tempstrings, gc->maxtemps);
|
||||
#ifdef GCTIMINGS
|
||||
endtime = Sys_DoubleTime();
|
||||
gc->externs->Printf("live: %u, dead: %u, threadtime: mark=%f, sweep=%f, total=%f\n", r_l, r_d, (markedtime - starttime), (endtime - markedtime), endtime-starttime);
|
||||
gc->externs->Printf("live: %u, dead: %u, threadtime: mark=%f, sweep=%f, total=%f\n", prinst.livetemps-gc->clearedtemps, gc->clearedtemps, (markedtime - starttime), (endtime - markedtime), endtime-starttime);
|
||||
#endif
|
||||
|
||||
COM_InsertWork(WG_MAIN, PR_QCGC_Done, gc, NULL, 0, 0);
|
||||
}
|
||||
#endif
|
||||
static void PR_ExpandTempStrings(progfuncs_t *progfuncs, size_t newmax)
|
||||
{
|
||||
tempstr_t **ntable = progfuncs->funcs.parms->memalloc(sizeof(*ntable) * newmax);
|
||||
memcpy(ntable, prinst.tempstrings, sizeof(*ntable) * prinst.maxtempstrings);
|
||||
memset(ntable+prinst.maxtempstrings, 0, sizeof(*ntable) * (newmax-prinst.maxtempstrings));
|
||||
prinst.maxtempstrings = newmax;
|
||||
if (prinst.tempstrings)
|
||||
progfuncs->funcs.parms->memfree(prinst.tempstrings);
|
||||
prinst.tempstrings = ntable;
|
||||
}
|
||||
static string_t PDECL PR_AllocTempStringLen (pubprogfuncs_t *ppf, char **str, unsigned int len)
|
||||
{
|
||||
progfuncs_t *fte_restrict progfuncs = (progfuncs_t *)ppf;
|
||||
tempstr_t **ntable;
|
||||
int newmax;
|
||||
progfuncs_t *progfuncs = (progfuncs_t *)ppf;
|
||||
int i;
|
||||
|
||||
if (!str)
|
||||
|
@ -1230,21 +1249,16 @@ static string_t PDECL PR_AllocTempStringLen (pubprogfuncs_t *ppf, char **str,
|
|||
|
||||
if (prinst.livetemps == prinst.maxtempstrings)
|
||||
{
|
||||
#ifdef THREADEDGC
|
||||
//need to wait for the gc to finish, otherwise it might be wiping freed strings that we're still using.
|
||||
while (prinst.gccontext)
|
||||
{
|
||||
COM_WorkerPartialSync(prinst.gccontext, &prinst.gccontext->done, false);
|
||||
PR_RunGC(progfuncs);
|
||||
}
|
||||
#endif
|
||||
|
||||
newmax = prinst.maxtempstrings*2 + 1024;
|
||||
ntable = progfuncs->funcs.parms->memalloc(sizeof(char*) * newmax);
|
||||
memcpy(ntable, prinst.tempstrings, sizeof(char*) * prinst.maxtempstrings);
|
||||
memset(ntable+prinst.maxtempstrings, 0, sizeof(char*) * (newmax-prinst.maxtempstrings));
|
||||
prinst.maxtempstrings = newmax;
|
||||
if (prinst.tempstrings)
|
||||
progfuncs->funcs.parms->memfree(prinst.tempstrings);
|
||||
prinst.tempstrings = ntable;
|
||||
PR_ExpandTempStrings(progfuncs, prinst.maxtempstrings*2 + 1024);
|
||||
}
|
||||
|
||||
for (i = prinst.nexttempstring; i < prinst.maxtempstrings && prinst.tempstrings[i]; i++)
|
||||
|
@ -1265,15 +1279,18 @@ static string_t PDECL PR_AllocTempStringLen (pubprogfuncs_t *ppf, char **str,
|
|||
|
||||
return (string_t)((unsigned int)i | STRING_TEMP);
|
||||
}
|
||||
pbool PR_RunGC (progfuncs_t *progfuncs)
|
||||
void PR_RunGC (progfuncs_t *progfuncs)
|
||||
{
|
||||
#ifdef THREADEDGC
|
||||
if (!prinst.gccontext)
|
||||
#endif
|
||||
{
|
||||
if (prinst.livetemps < prinst.maxtempstrings/2 || prinst.nexttempstring < prinst.maxtempstrings/2)
|
||||
{ //don't bother yet
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
else
|
||||
#ifdef THREADEDGC
|
||||
if (externs->usethreadedgc)
|
||||
{
|
||||
#ifdef GCTIMINGS
|
||||
double starttime = Sys_DoubleTime(), endtime;
|
||||
|
@ -1286,18 +1303,30 @@ pbool PR_RunGC (progfuncs_t *progfuncs)
|
|||
gc->memsize = prinst.addressableused;
|
||||
memcpy(gc->amem, prinst.addressablehunk, prinst.addressableused);
|
||||
|
||||
gc->numtemps = prinst.maxtempstrings;
|
||||
gc->maxtemps = prinst.maxtempstrings;
|
||||
gc->tempstrings = (void*)((char*)gc->amem+prinst.addressableused);
|
||||
memcpy(gc->tempstrings, prinst.tempstrings, sizeof(*gc->tempstrings)*gc->numtemps);
|
||||
memcpy(gc->tempstrings, prinst.tempstrings, sizeof(*gc->tempstrings)*gc->maxtemps);
|
||||
|
||||
COM_InsertWork(WG_LOADER, PR_QCGC_Thread, gc, NULL, 0, 0);
|
||||
COM_AddWork(WG_LOADER, PR_QCGC_Thread, gc, NULL, 0, 0);
|
||||
|
||||
#ifdef GCTIMINGS
|
||||
endtime = Sys_DoubleTime();
|
||||
gc->externs->Printf("preparetime=%f\n", (endtime - starttime));
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
{ //same-thread gc.
|
||||
smallbool *marked = PR_QCGC_Mark(prinst.addressablehunk, prinst.addressableused, prinst.maxtempstrings);
|
||||
size_t swept = PR_QCGC_Sweep(progfuncs, marked, prinst.tempstrings, prinst.maxtempstrings);
|
||||
prinst.livetemps -= swept;
|
||||
|
||||
//if over half the (max)strings are still live, just increase the max so we are not spamming collections
|
||||
if (prinst.livetemps >= prinst.maxtempstrings/2)
|
||||
PR_ExpandTempStrings(progfuncs, prinst.maxtempstrings * 2);
|
||||
}
|
||||
}
|
||||
#ifdef THREADEDGC
|
||||
else if (prinst.gccontext->done)
|
||||
{
|
||||
prinst.livetemps -= prinst.gccontext->clearedtemps;
|
||||
|
@ -1306,29 +1335,21 @@ pbool PR_RunGC (progfuncs_t *progfuncs)
|
|||
|
||||
//if over half the (max)strings are still live, just increase the max so we are not spamming collections
|
||||
if (prinst.livetemps >= prinst.maxtempstrings/2)
|
||||
{
|
||||
unsigned int newmax = prinst.maxtempstrings * 2;
|
||||
tempstr_t **ntable = progfuncs->funcs.parms->memalloc(sizeof(char*) * newmax);
|
||||
memcpy(ntable, prinst.tempstrings, sizeof(char*) * prinst.maxtempstrings);
|
||||
memset(ntable+prinst.maxtempstrings, 0, sizeof(char*) * (newmax-prinst.maxtempstrings));
|
||||
prinst.maxtempstrings = newmax;
|
||||
if (prinst.tempstrings)
|
||||
progfuncs->funcs.parms->memfree(prinst.tempstrings);
|
||||
prinst.tempstrings = ntable;
|
||||
}
|
||||
return false;
|
||||
PR_ExpandTempStrings(progfuncs, prinst.maxtempstrings * 2);
|
||||
}
|
||||
return true; //running...
|
||||
#endif
|
||||
}
|
||||
|
||||
static void PR_FreeAllTemps (progfuncs_t *progfuncs)
|
||||
{
|
||||
unsigned int i;
|
||||
#ifdef THREADEDGC
|
||||
while (prinst.gccontext)
|
||||
{
|
||||
COM_WorkerPartialSync(prinst.gccontext, &prinst.gccontext->done, false);
|
||||
PR_RunGC(progfuncs);
|
||||
}
|
||||
#endif
|
||||
for (i = 0; i < prinst.maxtempstrings; i++)
|
||||
{
|
||||
externs->memfree(prinst.tempstrings[i]);
|
||||
|
@ -1337,151 +1358,11 @@ static void PR_FreeAllTemps (progfuncs_t *progfuncs)
|
|||
prinst.maxtempstrings = 0;
|
||||
prinst.nexttempstring = 0;
|
||||
}
|
||||
|
||||
#elif defined(QCGC)
|
||||
|
||||
pbool PR_RunGC (progfuncs_t *progfuncs)
|
||||
{
|
||||
unsigned int p;
|
||||
char *marked;
|
||||
unsigned int *str;
|
||||
unsigned int r_l, r_d;
|
||||
#ifdef GCTIMINGS
|
||||
double starttime, markedtime, endtime;
|
||||
#endif
|
||||
//only run the GC when we've itterated each string at least once.
|
||||
if (prinst.nexttempstring < (prinst.maxtempstrings>>1) || prinst.nexttempstring < 200)
|
||||
return false;
|
||||
#ifdef GCTIMINGS
|
||||
starttime = Sys_DoubleTime();
|
||||
#endif
|
||||
marked = malloc(sizeof(*marked) * prinst.numtempstrings);
|
||||
memset(marked, 0, sizeof(*marked) * prinst.numtempstrings);
|
||||
|
||||
//mark everything the qc has access to, even if it isn't even a string!
|
||||
//note that I did try specifically checking only data explicitly marked as a string type, but that was:
|
||||
//a) a smidge slower (lots of extra loops and conditions I guess)
|
||||
//b) doesn't work with pointers/structs (yes, we assume it'll all be aligned).
|
||||
//c) both methods got the same number of false positives in my test (2, probably dead strunzoned references)
|
||||
for (str = (unsigned int*)prinst.addressablehunk, p = 0; p < prinst.addressableused; p+=sizeof(*str), str++)
|
||||
{
|
||||
if ((*str & STRING_SPECMASK) == STRING_TEMP)
|
||||
{
|
||||
unsigned int idx = *str &~ STRING_SPECMASK;
|
||||
if (idx < prinst.numtempstrings)
|
||||
marked[idx] = true;
|
||||
}
|
||||
}
|
||||
|
||||
//sweep
|
||||
#ifdef GCTIMINGS
|
||||
markedtime = Sys_DoubleTime();
|
||||
#endif
|
||||
r_l = 0;
|
||||
r_d = 0;
|
||||
for (p = 0; p < prinst.numtempstrings; p++)
|
||||
{
|
||||
if (marked[p])
|
||||
{
|
||||
r_l++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
prinst.nexttempstring = p;
|
||||
for (; p < prinst.numtempstrings; p++)
|
||||
{
|
||||
if (marked[p])
|
||||
{
|
||||
r_l++;
|
||||
}
|
||||
else if (prinst.tempstrings[p])
|
||||
{
|
||||
r_d++;
|
||||
externs->memfree(prinst.tempstrings[p]);
|
||||
prinst.tempstrings[p] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
while (prinst.numtempstrings > 0 && prinst.tempstrings[prinst.numtempstrings-1] == NULL)
|
||||
prinst.numtempstrings--;
|
||||
|
||||
free(marked);
|
||||
|
||||
//if over half the (max)strings are still live, just increase the max so we are not spamming collections
|
||||
r_d += prinst.maxtempstrings - prinst.numtempstrings;
|
||||
if (r_l > r_d)
|
||||
{
|
||||
unsigned int newmax = prinst.maxtempstrings * 2;
|
||||
tempstr_t **ntable = progfuncs->funcs.parms->memalloc(sizeof(char*) * newmax);
|
||||
memcpy(ntable, prinst.tempstrings, sizeof(char*) * prinst.maxtempstrings);
|
||||
memset(ntable+prinst.maxtempstrings, 0, sizeof(char*) * (newmax-prinst.maxtempstrings));
|
||||
prinst.maxtempstrings = newmax;
|
||||
if (prinst.tempstrings)
|
||||
progfuncs->funcs.parms->memfree(prinst.tempstrings);
|
||||
prinst.tempstrings = ntable;
|
||||
}
|
||||
|
||||
#ifdef GCTIMINGS
|
||||
endtime = Sys_DoubleTime();
|
||||
externs->Printf("live: %u, dead: %u, time: mark=%f, sweep=%f, total=%f\n", r_l, r_d, markedtime - starttime, endtime - markedtime, endtime-starttime);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
static string_t PDECL PR_AllocTempStringLen (pubprogfuncs_t *ppf, char **str, unsigned int len)
|
||||
{
|
||||
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
|
||||
tempstr_t **ntable;
|
||||
int newmax;
|
||||
int i;
|
||||
|
||||
if (!str)
|
||||
return 0;
|
||||
|
||||
if (prinst.numtempstrings == prinst.maxtempstrings)
|
||||
{
|
||||
newmax = prinst.maxtempstrings + 1024;
|
||||
ntable = progfuncs->funcs.parms->memalloc(sizeof(char*) * newmax);
|
||||
memcpy(ntable, prinst.tempstrings, sizeof(char*) * prinst.numtempstrings);
|
||||
memset(ntable+prinst.maxtempstrings, 0, sizeof(char*) * (newmax-prinst.numtempstrings));
|
||||
prinst.maxtempstrings = newmax;
|
||||
if (prinst.tempstrings)
|
||||
progfuncs->funcs.parms->memfree(prinst.tempstrings);
|
||||
prinst.tempstrings = ntable;
|
||||
}
|
||||
|
||||
if (prinst.nexttempstring >= 0x10000000)
|
||||
return 0;
|
||||
do
|
||||
{
|
||||
i = prinst.nexttempstring++;
|
||||
} while(prinst.tempstrings[i] != NULL);
|
||||
if (i == prinst.numtempstrings)
|
||||
prinst.numtempstrings++;
|
||||
|
||||
prinst.tempstrings[i] = progfuncs->funcs.parms->memalloc(sizeof(tempstr_t) - sizeof(((tempstr_t*)NULL)->value) + len);
|
||||
prinst.tempstrings[i]->size = len;
|
||||
*str = prinst.tempstrings[i]->value;
|
||||
|
||||
return (string_t)((unsigned int)i | STRING_TEMP);
|
||||
}
|
||||
static void PR_FreeAllTemps (progfuncs_t *progfuncs)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < prinst.numtempstrings; i++)
|
||||
{
|
||||
externs->memfree(prinst.tempstrings[i]);
|
||||
prinst.tempstrings[i] = NULL;
|
||||
}
|
||||
prinst.numtempstrings = 0;
|
||||
prinst.nexttempstring = 0;
|
||||
}
|
||||
#else
|
||||
static string_t PDECL PR_AllocTempStringLen (pubprogfuncs_t *ppf, char **str, unsigned int len)
|
||||
{
|
||||
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
|
||||
tempstr_t **ntable;
|
||||
tempstr_t **ntable, *n;
|
||||
int newmax;
|
||||
int i;
|
||||
|
||||
|
@ -1505,9 +1386,10 @@ static string_t PDECL PR_AllocTempStringLen (pubprogfuncs_t *ppf, char **str,
|
|||
|
||||
prinst.numtempstrings++;
|
||||
|
||||
prinst.tempstrings[i] = progfuncs->funcs.parms->memalloc(sizeof(tempstr_t) - sizeof(((tempstr_t*)NULL)->value) + len);
|
||||
prinst.tempstrings[i]->size = len;
|
||||
*str = prinst.tempstrings[i]->value;
|
||||
n = progfuncs->funcs.parms->memalloc(sizeof(tempstr_t) - sizeof(((tempstr_t*)NULL)->value) + len);
|
||||
n->size = len;
|
||||
*str = n->value;
|
||||
prinst.tempstrings[i] = n; //doesn't have its value yet...
|
||||
|
||||
return (string_t)((unsigned int)i | STRING_TEMP);
|
||||
}
|
||||
|
@ -1738,53 +1620,6 @@ static void PDECL qclib_free(void *ptr)
|
|||
#define printf NULL //should be some null wrapper instead
|
||||
#endif
|
||||
|
||||
//defs incase following structure is not passed.
|
||||
static struct edict_s *safesv_edicts;
|
||||
static int safesv_num_edicts;
|
||||
static double safetime=0;
|
||||
|
||||
static progexterns_t defexterns = {
|
||||
PROGSTRUCT_VERSION,
|
||||
|
||||
NULL, //char *(*ReadFile) (char *fname, void *buffer, int len);
|
||||
NULL, //int (*FileSize) (char *fname); //-1 if file does not exist
|
||||
NULL, //bool (*WriteFile) (char *name, void *data, int len);
|
||||
qclib_null_printf, //void (*printf) (char *, ...);
|
||||
qclib_null_printf, //void (*dprintf) (char *, ...);
|
||||
(void*)exit, //void (*Sys_Error) (char *, ...);
|
||||
NULL, //void (*Abort) (char *, ...);
|
||||
NULL,
|
||||
|
||||
NULL, //void (*entspawn) (struct edict_s *ent); //ent has been spawned, but may not have all the extra variables (that may need to be set) set
|
||||
NULL, //bool (*entcanfree) (struct edict_s *ent); //return true to stop ent from being freed
|
||||
NULL, //void (*stateop) (float var, func_t func);
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
//used when loading a game
|
||||
NULL, //builtin_t *(*builtinsfor) (int num); //must return a pointer to the builtins that were used before the state was saved.
|
||||
NULL, //void (*loadcompleate) (int edictsize); //notification to reset any pointers.
|
||||
NULL,
|
||||
|
||||
qclib_malloc, //void *(*memalloc) (int size); //small string allocation malloced and freed randomly by the executor. (use memalloc if you want)
|
||||
qclib_free, //void (*memfree) (void * mem);
|
||||
|
||||
NULL, //int (*useeditor) (char *filename, int line, int nump, char **parms);
|
||||
NULL, //relocated
|
||||
|
||||
NULL, //builtin_t *globalbuiltins; //these are available to all progs
|
||||
0, //int numglobalbuiltins;
|
||||
|
||||
PR_NOCOMPILE,
|
||||
|
||||
&safetime, //double *gametime;
|
||||
|
||||
&safesv_edicts, //struct edict_s **sv_edicts;
|
||||
&safesv_num_edicts, //int *sv_num_edicts;
|
||||
sizeof(edictrun_t), //int edictsize; //size of edict_t
|
||||
};
|
||||
|
||||
//progfuncs_t *progfuncs = NULL;
|
||||
#undef memfree
|
||||
#undef prinst
|
||||
|
@ -1853,17 +1688,13 @@ pubprogfuncs_t * PDECL InitProgs(progexterns_t *ext)
|
|||
progfuncs_t *funcs;
|
||||
|
||||
if (!ext)
|
||||
ext = &defexterns;
|
||||
else
|
||||
{
|
||||
int i;
|
||||
if (ext->progsversion > PROGSTRUCT_VERSION)
|
||||
return NULL;
|
||||
static progexterns_t defexterns;
|
||||
ext = &defexterns;
|
||||
}
|
||||
else if (ext->progsversion != PROGSTRUCT_VERSION)
|
||||
return NULL;
|
||||
|
||||
for (i=0;i<sizeof(progexterns_t); i+=4) //make sure there are no items left out.
|
||||
if (!*(int *)((char *)ext+i))
|
||||
*(int *)((char *)ext+i) = *(int *)((char *)&defexterns+i);
|
||||
}
|
||||
#undef memalloc
|
||||
#undef pr_progstate
|
||||
#undef pr_argc
|
||||
|
@ -1875,6 +1706,24 @@ pubprogfuncs_t * PDECL InitProgs(progexterns_t *ext)
|
|||
|
||||
funcs->funcs.parms = ext;
|
||||
|
||||
|
||||
{
|
||||
//defs incase following structure is not passed.
|
||||
static struct edict_s *safe_edicts;
|
||||
static int safe_num_edicts;
|
||||
static double safetime=0;
|
||||
if (!ext->progsversion) ext->progsversion = PROGSTRUCT_VERSION;
|
||||
if (!ext->Printf) ext->Printf = qclib_null_printf;
|
||||
if (!ext->DPrintf) ext->DPrintf = qclib_null_printf;
|
||||
if (!ext->Sys_Error) ext->Sys_Error = (void*)exit;
|
||||
if (!ext->memalloc) ext->memalloc = qclib_malloc;
|
||||
if (!ext->memfree) ext->memfree = qclib_free;
|
||||
if (!ext->gametime) ext->gametime = &safetime;
|
||||
if (!ext->edicts) ext->edicts = &safe_edicts;
|
||||
if (!ext->num_edicts) ext->num_edicts = &safe_num_edicts;
|
||||
if (!ext->edictsize) ext->edictsize = sizeof(edictrun_t);
|
||||
}
|
||||
|
||||
SetEndian();
|
||||
|
||||
return &funcs->funcs;
|
||||
|
|
|
@ -887,12 +887,13 @@ Returns a string with a description and the contents of a global,
|
|||
padded to 20 field width
|
||||
============
|
||||
*/
|
||||
char *PR_GlobalString (progfuncs_t *progfuncs, int ofs)
|
||||
#include "qcc.h"
|
||||
char *PR_GlobalString (progfuncs_t *progfuncs, int ofs, struct QCC_type_s **typehint)
|
||||
{
|
||||
char *s;
|
||||
int i;
|
||||
ddef16_t *def16;
|
||||
ddef32_t *def32;
|
||||
ddef32_t *def32, def32tmp;
|
||||
void *val;
|
||||
static char line[128];
|
||||
|
||||
|
@ -900,41 +901,57 @@ char *PR_GlobalString (progfuncs_t *progfuncs, int ofs)
|
|||
{
|
||||
case PST_DEFAULT:
|
||||
case PST_KKQWSV:
|
||||
val = (void *)&pr_globals[ofs];
|
||||
def16 = ED_GlobalAtOfs16(progfuncs, ofs);
|
||||
if (!def16)
|
||||
sprintf (line,"%i(?""?""?)", ofs);
|
||||
else
|
||||
if (def16)
|
||||
{
|
||||
s = PR_ValueString (progfuncs, def16->type, val, false);
|
||||
sprintf (line,"%i(%s)%s", ofs, def16->s_name+progfuncs->funcs.stringtable, s);
|
||||
def32 = &def32tmp;
|
||||
def32->ofs = def16->ofs;
|
||||
def32->type = def16->type;
|
||||
def32->s_name = def16->s_name;
|
||||
}
|
||||
|
||||
i = strlen(line);
|
||||
for ( ; i<20 ; i++)
|
||||
strcat (line," ");
|
||||
strcat (line," ");
|
||||
return line;
|
||||
else
|
||||
def32 = NULL;
|
||||
break;
|
||||
case PST_QTEST:
|
||||
case PST_FTE32:
|
||||
val = (void *)&pr_globals[ofs];
|
||||
def32 = ED_GlobalAtOfs32(progfuncs, ofs);
|
||||
if (!def32)
|
||||
sprintf (line,"%i(?""?""?)", ofs);
|
||||
else
|
||||
{
|
||||
s = PR_ValueString (progfuncs, def32->type, val, false);
|
||||
sprintf (line,"%i(%s)%s", ofs, def32->s_name+progfuncs->funcs.stringtable, s);
|
||||
}
|
||||
|
||||
i = strlen(line);
|
||||
for ( ; i<20 ; i++)
|
||||
strcat (line," ");
|
||||
strcat (line," ");
|
||||
return line;
|
||||
break;
|
||||
default:
|
||||
externs->Sys_Error("Bad struct type in PR_GlobalString");
|
||||
return "";
|
||||
}
|
||||
externs->Sys_Error("Bad struct type in PR_GlobalString");
|
||||
return "";
|
||||
|
||||
val = (void *)&pr_globals[ofs];
|
||||
if (!def32)
|
||||
{
|
||||
etype_t type;
|
||||
//urgh, this is so hideous
|
||||
if (typehint == &type_float)
|
||||
type = ev_float;
|
||||
else if (typehint == &type_string)
|
||||
type = ev_string;
|
||||
else if (typehint == &type_vector)
|
||||
type = ev_vector;
|
||||
else if (typehint == &type_function)
|
||||
type = ev_function;
|
||||
else if (typehint == &type_field)
|
||||
type = ev_field;
|
||||
else
|
||||
type = ev_integer;
|
||||
s = PR_ValueString (progfuncs, type, val, false);
|
||||
sprintf (line,"%i(?)%s", ofs, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
s = PR_ValueString (progfuncs, def32->type, val, false);
|
||||
sprintf (line,"%i(%s)%s", ofs, def32->s_name+progfuncs->funcs.stringtable, s);
|
||||
}
|
||||
|
||||
i = strlen(line);
|
||||
for ( ; i<20 ; i++)
|
||||
strcat (line," ");
|
||||
strcat (line," ");
|
||||
return line;
|
||||
}
|
||||
|
||||
char *PR_GlobalStringNoContents (progfuncs_t *progfuncs, int ofs)
|
||||
|
|
|
@ -122,6 +122,7 @@ static void PR_PrintStatement (progfuncs_t *progfuncs, int statementnum)
|
|||
}
|
||||
|
||||
#if !defined(MINIMAL) && !defined(OMIT_QCC)
|
||||
#define TYPEHINT(a) (pr_opcodes[op].type_##a)
|
||||
if ( (unsigned)op < OP_NUMOPS)
|
||||
{
|
||||
int i;
|
||||
|
@ -134,23 +135,27 @@ static void PR_PrintStatement (progfuncs_t *progfuncs, int statementnum)
|
|||
#endif
|
||||
externs->Printf ("op%3i ", op);
|
||||
|
||||
#ifndef TYPEHINT
|
||||
#define TYPEHINT(a) NULL
|
||||
#endif
|
||||
|
||||
if (op == OP_IF_F || op == OP_IFNOT_F)
|
||||
externs->Printf ("%sbranch %i",PR_GlobalString(progfuncs, arg[0]),arg[1]);
|
||||
externs->Printf ("%sbranch %i",PR_GlobalString(progfuncs, arg[0], TYPEHINT(a)),arg[1]);
|
||||
else if (op == OP_GOTO)
|
||||
{
|
||||
externs->Printf ("branch %i",arg[0]);
|
||||
}
|
||||
else if ( (unsigned)(op - OP_STORE_F) < 6)
|
||||
{
|
||||
externs->Printf ("%s",PR_GlobalString(progfuncs, arg[0]));
|
||||
externs->Printf ("%s",PR_GlobalString(progfuncs, arg[0], TYPEHINT(a)));
|
||||
externs->Printf ("%s", PR_GlobalStringNoContents(progfuncs, arg[1]));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (arg[0])
|
||||
externs->Printf ("%s",PR_GlobalString(progfuncs, arg[0]));
|
||||
externs->Printf ("%s",PR_GlobalString(progfuncs, arg[0], TYPEHINT(a)));
|
||||
if (arg[1])
|
||||
externs->Printf ("%s",PR_GlobalString(progfuncs, arg[1]));
|
||||
externs->Printf ("%s",PR_GlobalString(progfuncs, arg[1], TYPEHINT(b)));
|
||||
if (arg[2])
|
||||
externs->Printf ("%s", PR_GlobalStringNoContents(progfuncs, arg[2]));
|
||||
}
|
||||
|
@ -233,19 +238,19 @@ void PDECL PR_GenerateStatementString (pubprogfuncs_t *ppf, int statementnum, ch
|
|||
|
||||
if (op == OP_IF_F || op == OP_IFNOT_F || op == OP_IF_I || op == OP_IFNOT_I || op == OP_IF_S || op == OP_IFNOT_S)
|
||||
{
|
||||
QC_snprintfz (out, outlen, "%sbranch %i(%i)",PR_GlobalStringNoContents(progfuncs, arg[0]),(short)arg[1], statementnum+(short)arg[0]);
|
||||
QC_snprintfz (out, outlen, "%sbranch %i(%+i)",PR_GlobalString(progfuncs, arg[0], TYPEHINT(a)),(short)arg[1], statementnum+(short)arg[0]);
|
||||
outlen -= strlen(out);
|
||||
out += strlen(out);
|
||||
}
|
||||
else if (op == OP_GOTO)
|
||||
{
|
||||
QC_snprintfz (out, outlen, "branch %i(%i)",(short)arg[0], statementnum+(short)arg[0]);
|
||||
QC_snprintfz (out, outlen, "branch %i(%+i)",(short)arg[0], statementnum+(short)arg[0]);
|
||||
outlen -= strlen(out);
|
||||
out += strlen(out);
|
||||
}
|
||||
else if ( (unsigned)(op - OP_STORE_F) < 6)
|
||||
{
|
||||
QC_snprintfz (out, outlen, "%s",PR_GlobalStringNoContents(progfuncs, arg[0]));
|
||||
QC_snprintfz (out, outlen, "%s",PR_GlobalString(progfuncs, arg[0], TYPEHINT(a)));
|
||||
outlen -= strlen(out);
|
||||
out += strlen(out);
|
||||
QC_snprintfz (out, outlen, "%s", PR_GlobalStringNoContents(progfuncs, arg[1]));
|
||||
|
@ -256,13 +261,13 @@ void PDECL PR_GenerateStatementString (pubprogfuncs_t *ppf, int statementnum, ch
|
|||
{
|
||||
if (arg[0])
|
||||
{
|
||||
QC_snprintfz (out, outlen, "%s",PR_GlobalStringNoContents(progfuncs, arg[0]));
|
||||
QC_snprintfz (out, outlen, "%s",PR_GlobalString(progfuncs, arg[0], TYPEHINT(a)));
|
||||
outlen -= strlen(out);
|
||||
out += strlen(out);
|
||||
}
|
||||
if (arg[1])
|
||||
{
|
||||
QC_snprintfz (out, outlen, "%s",PR_GlobalStringNoContents(progfuncs, arg[1]));
|
||||
QC_snprintfz (out, outlen, "%s",PR_GlobalString(progfuncs, arg[1], TYPEHINT(b)));
|
||||
outlen -= strlen(out);
|
||||
out += strlen(out);
|
||||
}
|
||||
|
|
|
@ -86,29 +86,28 @@ typedef struct
|
|||
prclocks_t timestamp;
|
||||
} prstack_t;
|
||||
|
||||
#if defined(QCGC) && defined(MULTITHREAD)
|
||||
#define THREADEDGC
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int size;
|
||||
char value[4];
|
||||
unsigned int size; //size of the data.
|
||||
char value[4]; //contents of the tempstring (or really any binary data - but not tempstring references because we don't mark these!).
|
||||
} tempstr_t;
|
||||
|
||||
#if defined(QCGC) && defined(MULTITHREAD)
|
||||
// #define THREADEDGC
|
||||
#endif
|
||||
|
||||
//FIXME: the defines hidden inside this structure are evil.
|
||||
typedef struct prinst_s
|
||||
{
|
||||
//temp strings are GCed, and can be created by engine, builtins, or just by ent parsing code.
|
||||
tempstr_t **tempstrings;
|
||||
unsigned int maxtempstrings;
|
||||
#ifdef THREADEDGC
|
||||
#if defined(QCGC)
|
||||
unsigned int nexttempstring;
|
||||
unsigned int livetemps; //increased on alloc, decremented after sweep
|
||||
struct qcgccontext_s *gccontext;
|
||||
#elif defined(QCGC)
|
||||
unsigned int numtempstrings;
|
||||
unsigned int nexttempstring;
|
||||
#ifdef THREADEDGC
|
||||
struct qcgccontext_s *gccontext;
|
||||
#endif
|
||||
#else
|
||||
unsigned int numtempstrings;
|
||||
unsigned int numtempstringsstack;
|
||||
|
@ -235,8 +234,8 @@ extern QCC_opcode_t pr_opcodes[]; // sized by initialization
|
|||
#define min(a,b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#define sv_num_edicts (*externs->sv_num_edicts)
|
||||
#define sv_edicts (*externs->sv_edicts)
|
||||
#define sv_num_edicts (*externs->num_edicts)
|
||||
#define sv_edicts (*externs->edicts)
|
||||
|
||||
#define PR_DPrintf externs->DPrintf
|
||||
//#define printf syntax error
|
||||
|
@ -405,7 +404,12 @@ void PR_Profile_f (void);
|
|||
struct edict_s *PDECL ED_Alloc (pubprogfuncs_t *progfuncs, pbool object, size_t extrasize);
|
||||
void PDECL ED_Free (pubprogfuncs_t *progfuncs, struct edict_s *ed, pbool instant);
|
||||
|
||||
pbool PR_RunGC (progfuncs_t *progfuncs);
|
||||
#ifdef QCGC
|
||||
void PR_RunGC (progfuncs_t *progfuncs);
|
||||
#else
|
||||
void PR_FreeTemps (progfuncs_t *progfuncs, int depth);
|
||||
#endif
|
||||
|
||||
string_t PDECL PR_AllocTempString (pubprogfuncs_t *ppf, const char *str);
|
||||
char *PDECL ED_NewString (pubprogfuncs_t *ppf, const char *string, int minlength, pbool demarkup);
|
||||
// returns a copy of the string allocated from the server's string heap
|
||||
|
@ -531,9 +535,7 @@ ddef32_t *ED_GlobalAtOfs32 (progfuncs_t *progfuncs, unsigned int ofs);
|
|||
string_t PDECL PR_StringToProgs (pubprogfuncs_t *inst, const char *str);
|
||||
const char *ASMCALL PR_StringToNative (pubprogfuncs_t *inst, string_t str);
|
||||
|
||||
void PR_FreeTemps (progfuncs_t *progfuncs, int depth);
|
||||
|
||||
char *PR_GlobalString (progfuncs_t *progfuncs, int ofs);
|
||||
char *PR_GlobalString (progfuncs_t *progfuncs, int ofs, struct QCC_type_s **typehint);
|
||||
char *PR_GlobalStringNoContents (progfuncs_t *progfuncs, int ofs);
|
||||
|
||||
pbool CompileFile(progfuncs_t *progfuncs, const char *filename);
|
||||
|
|
|
@ -239,8 +239,10 @@ typedef struct progexterns_s {
|
|||
|
||||
double *gametime; //used to prevent the vm from reusing an entity faster than 2 secs.
|
||||
|
||||
struct edict_s **sv_edicts; //pointer to the engine's reference to world.
|
||||
unsigned int *sv_num_edicts; //pointer to the engine's edict count.
|
||||
pbool usethreadedgc;
|
||||
|
||||
struct edict_s **edicts; //pointer to the engine's reference to world.
|
||||
unsigned int *num_edicts; //pointer to the engine's edict count.
|
||||
int edictsize; //size of edict_t
|
||||
|
||||
void *user; /*contains the owner's world reference in FTE*/
|
||||
|
|
|
@ -808,9 +808,12 @@ void Q_SetProgsParms(qboolean forcompiler)
|
|||
svprogparms.autocompile = PR_COMPILEIGNORE;//PR_COMPILECHANGED;//enum {PR_NOCOMPILE, PR_COMPILENEXIST, PR_COMPILECHANGED, PR_COMPILEALWAYS} autocompile;
|
||||
|
||||
svprogparms.gametime = &sv.time;
|
||||
#ifdef MULTITHREAD
|
||||
svprogparms.usethreadedgc = pr_gc_threaded.ival;
|
||||
#endif
|
||||
|
||||
svprogparms.sv_edicts = (edict_t**)&sv.world.edicts;
|
||||
svprogparms.sv_num_edicts = &sv.world.num_edicts;
|
||||
svprogparms.edicts = (edict_t**)&sv.world.edicts;
|
||||
svprogparms.num_edicts = &sv.world.num_edicts;
|
||||
|
||||
svprogparms.useeditor = QCEditor;
|
||||
|
||||
|
@ -12143,6 +12146,27 @@ void PR_DumpPlatform_f(void)
|
|||
{"global_gravitydir", "vector", QW|NQ|CS, D("The direction gravity should act in if not otherwise specified per entity."), 0,"'0 0 -1'"},
|
||||
{"serverid", "int", QW|NQ|CS, D("The unique id of this server within the server cluster.")},
|
||||
|
||||
{"button3", ".float", QW|NQ},
|
||||
{"button4", ".float", QW|NQ},
|
||||
{"button5", ".float", QW|NQ},
|
||||
{"button6", ".float", QW|NQ},
|
||||
{"button7", ".float", QW|NQ},
|
||||
{"button8", ".float", QW|NQ},
|
||||
|
||||
//and for dp compat (these names are fucked, yes)
|
||||
// {"buttonuse", ".float", QW|NQ},
|
||||
// {"buttonchat", ".float", QW|NQ},
|
||||
// {"cursor_active", ".float", QW|NQ},
|
||||
// {"button9", ".float", QW|NQ},
|
||||
// {"button10", ".float", QW|NQ},
|
||||
// {"button11", ".float", QW|NQ},
|
||||
// {"button12", ".float", QW|NQ},
|
||||
// {"button13", ".float", QW|NQ},
|
||||
|
||||
// {"button14", ".float", QW|NQ},
|
||||
// {"button15", ".float", QW|NQ},
|
||||
// {"button16", ".float", QW|NQ},
|
||||
|
||||
#define comfieldfloat(name,desc) {#name, ".float", FL, D(desc)},
|
||||
#define comfieldint(name,desc) {#name, ".int", FL, D(desc)},
|
||||
#define comfieldvector(name,desc) {#name, ".vector", FL, D(desc)},
|
||||
|
|
|
@ -1211,28 +1211,6 @@ void SV_FixupName(const char *in, char *out, unsigned int outlen);
|
|||
|
||||
#ifdef SUBSERVERS
|
||||
//cluster stuff
|
||||
typedef struct pubsubserver_s
|
||||
{
|
||||
struct
|
||||
{
|
||||
void (*InstructSlave)(struct pubsubserver_s *ps, sizebuf_t *cmd); //send to. first two bytes of the message should be ignored (overwrite them to carry size)
|
||||
int (*SubServerRead)(struct pubsubserver_s *ps); //read from. fills up net_message
|
||||
} funcs;
|
||||
|
||||
struct pubsubserver_s *next;
|
||||
unsigned int id;
|
||||
char name[64];
|
||||
int activeplayers;
|
||||
int transferingplayers;
|
||||
netadr_t addrv4;
|
||||
netadr_t addrv6;
|
||||
char printtext[4096]; //to split it into lines.
|
||||
qboolean started;
|
||||
#ifdef HAVE_CLIENT
|
||||
console_t *console;
|
||||
#endif
|
||||
} pubsubserver_t;
|
||||
extern qboolean isClusterSlave;
|
||||
void SSV_UpdateAddresses(void);
|
||||
void SSV_InitiatePlayerTransfer(client_t *cl, const char *newserver);
|
||||
void SSV_InstructMaster(sizebuf_t *cmd);
|
||||
|
@ -1242,9 +1220,13 @@ void SSV_ReadFromControlServer(void);
|
|||
void SSV_SavePlayerStats(client_t *cl, int reason); //initial, periodic (in case of node crashes), part
|
||||
void SSV_RequestShutdown(void); //asks the cluster to not send us new players
|
||||
|
||||
pubsubserver_t *Sys_ForkServer(void);
|
||||
vfsfile_t *Sys_ForkServer(void);
|
||||
void Sys_InstructMaster(sizebuf_t *cmd); //first two bytes will always be the length of the data
|
||||
vfsfile_t *Sys_GetStdInOutStream(void); //obtains a bi-directional pipe for reading/writing via stdin/stdout. make sure the system code won't be using it.
|
||||
|
||||
qboolean MSV_NewNetworkedNode(vfsfile_t *stream, qbyte *reqstart, qbyte *buffered, size_t buffersize, const char *remoteaddr); //call to register a pipe to a newly discovered node.
|
||||
void SSV_SetupControlPipe(vfsfile_t *stream); //call to register the pipe.
|
||||
extern qboolean isClusterSlave;
|
||||
#define SSV_IsSubServer() isClusterSlave
|
||||
|
||||
|
||||
|
|
|
@ -32,12 +32,41 @@
|
|||
// destination receives connection from client (or times out) and sends a ccmd_saveplayer(0) to the root, root sees the server change and sends ccmd_transferedplayer to the source.
|
||||
// source knows that the player is no longer present (or aborts the transfer if it was a timeout, reenabling other transfers/retries).
|
||||
|
||||
//to connect a new server to a remote gateway, add '-clusterhost GATEWAY:TCPPORT PASSWORD' to the new server's commandline. The gateway needs eg sv_port_tcp open (you might wish to ipfilter for added security).
|
||||
|
||||
#ifdef SUBSERVERS
|
||||
|
||||
#ifdef SQL
|
||||
#include "sv_sql.h"
|
||||
#endif
|
||||
|
||||
typedef struct pubsubserver_s
|
||||
{
|
||||
vfsfile_t *stream;
|
||||
|
||||
struct pubsubserver_s *next;
|
||||
unsigned int id;
|
||||
char name[64];
|
||||
int activeplayers;
|
||||
int transferingplayers;
|
||||
netadr_t addrv4;
|
||||
netadr_t addrv6;
|
||||
char printtext[4096]; //to split it into lines.
|
||||
qboolean started;
|
||||
#ifdef HAVE_CLIENT
|
||||
console_t *console;
|
||||
#endif
|
||||
|
||||
|
||||
size_t inbuffersize;
|
||||
qbyte inbuffer[8192];
|
||||
|
||||
qboolean outfailed;
|
||||
// size_t outbuffersize;
|
||||
// qbyte outbuffer[8192];
|
||||
} pubsubserver_t;
|
||||
|
||||
|
||||
extern cvar_t sv_serverip;
|
||||
|
||||
void VARGS SV_RejectMessage(enum serverprotocols_e protocol, char *format, ...);
|
||||
|
@ -61,8 +90,51 @@ typedef struct {
|
|||
static pubsubserver_t *subservers;
|
||||
static link_t clusterplayers;
|
||||
qboolean isClusterSlave;
|
||||
static vfsfile_t *controlconnection = NULL;
|
||||
static unsigned int nextserverid;
|
||||
|
||||
static void MSV_WriteSlave(pubsubserver_t *ps, sizebuf_t *cmd)
|
||||
{
|
||||
//FIXME: this is blocking. this is bad if the target is also blocking while trying to write to us.
|
||||
//FIXME: merge buffering logic with SSV_InstructMaster, and allow for failure if full
|
||||
vfsfile_t *s = ps->stream;
|
||||
int wrote;
|
||||
if (ps->outfailed)
|
||||
return; //give up after the first failure, to avoid corruption.
|
||||
cmd->data[0] = cmd->cursize & 0xff;
|
||||
cmd->data[1] = (cmd->cursize>>8) & 0xff;
|
||||
wrote = VFS_WRITE(s, cmd->data, cmd->cursize);
|
||||
if (wrote != cmd->cursize)
|
||||
ps->outfailed = true;
|
||||
}
|
||||
|
||||
static int MSV_SubServerRead(pubsubserver_t *ps)
|
||||
{
|
||||
if (ps->inbuffersize < sizeof(ps->inbuffer))
|
||||
{
|
||||
int avail = VFS_READ(ps->stream, ps->inbuffer+ps->inbuffersize, sizeof(ps->inbuffer)-ps->inbuffersize);
|
||||
if (avail < 0)
|
||||
return avail;
|
||||
ps->inbuffersize += avail;
|
||||
}
|
||||
|
||||
if(ps->inbuffersize >= 2)
|
||||
{
|
||||
unsigned short len = ps->inbuffer[0] | (ps->inbuffer[1]<<8);
|
||||
if (ps->inbuffersize >= len && len>=2)
|
||||
{
|
||||
memcpy(net_message.data, ps->inbuffer+2, len-2);
|
||||
net_message.cursize = len-2;
|
||||
memmove(ps->inbuffer, ps->inbuffer+len, ps->inbuffersize - len);
|
||||
ps->inbuffersize -= len;
|
||||
MSG_BeginReading (msg_nullnetprim);
|
||||
|
||||
return len;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static clusterplayer_t *MSV_FindPlayerId(unsigned int playerid)
|
||||
{
|
||||
link_t *l;
|
||||
|
@ -116,6 +188,8 @@ static void MSV_ServerCrashed(pubsubserver_t *server)
|
|||
}
|
||||
}
|
||||
|
||||
if (server->stream)
|
||||
VFS_CLOSE(server->stream);
|
||||
Z_Free(server);
|
||||
}
|
||||
|
||||
|
@ -131,29 +205,6 @@ pubsubserver_t *MSV_FindSubServer(unsigned int id)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static vfsfile_t *msv_loop_to_ss;
|
||||
static vfsfile_t *msv_loop_from_ss;
|
||||
static void MSV_Loop_Instruct(pubsubserver_t *ps, sizebuf_t *cmd)
|
||||
{
|
||||
unsigned short size = cmd->cursize;
|
||||
cmd->data[0] = cmd->cursize & 0xff;
|
||||
cmd->data[1] = (cmd->cursize>>8) & 0xff;
|
||||
VFS_WRITE(msv_loop_to_ss, cmd->data, size);
|
||||
}
|
||||
static int MSV_Loop_Read(pubsubserver_t *ps)
|
||||
{
|
||||
unsigned short size;
|
||||
if (sv.state < ss_loading)
|
||||
return -1; //failure
|
||||
if (!VFS_READ(msv_loop_from_ss, &size, sizeof(size)))
|
||||
return 0;
|
||||
net_message.cursize = size-2;
|
||||
VFS_READ(msv_loop_from_ss, net_message.data, net_message.cursize);
|
||||
|
||||
MSG_BeginReading (msg_nullnetprim);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void MSV_SendCvars(pubsubserver_t *s)
|
||||
{
|
||||
extern cvar_t skill, sv_nqplayerphysics, sv_pure, sv_minpitch, sv_maxpitch;
|
||||
|
@ -179,18 +230,21 @@ static void MSV_SendCvars(pubsubserver_t *s)
|
|||
MSG_WriteByte(&send, ccmd_setcvar);
|
||||
MSG_WriteString(&send, cvars[v]->name);
|
||||
MSG_WriteString(&send, cvars[v]->string);
|
||||
s->funcs.InstructSlave(s, &send);
|
||||
MSV_WriteSlave(s, &send);
|
||||
}
|
||||
}
|
||||
|
||||
static void MSV_Link_Server(pubsubserver_t *s, int id, const char *mapname)
|
||||
static pubsubserver_t *MSV_Link_Server(vfsfile_t *stream, int id, const char *mapname)
|
||||
{
|
||||
pubsubserver_t *s;
|
||||
sizebuf_t send;
|
||||
char send_buf[1024];
|
||||
if (!id)
|
||||
{
|
||||
do id = ++nextserverid; while(MSV_FindSubServer(id));
|
||||
}
|
||||
s = Z_Malloc(sizeof(*s));
|
||||
s->stream = stream;
|
||||
s->id = id;
|
||||
s->next = subservers;
|
||||
subservers = s;
|
||||
|
@ -208,12 +262,96 @@ static void MSV_Link_Server(pubsubserver_t *s, int id, const char *mapname)
|
|||
MSG_WriteByte(&send, ccmd_acceptserver);
|
||||
MSG_WriteLong(&send, s->id);
|
||||
MSG_WriteString(&send, s->name);
|
||||
s->funcs.InstructSlave(s, &send);
|
||||
MSV_WriteSlave(s, &send);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
pubsubserver_t *MSV_Loop_GetLocalServer(void)
|
||||
//network code just found a new node trying to announce itself to us.
|
||||
qboolean MSV_NewNetworkedNode(vfsfile_t *stream, qbyte *reqstart, qbyte *buffered, size_t buffersize, const char *remoteaddr)
|
||||
{
|
||||
if (stream)
|
||||
{
|
||||
const char *pwd = NULL;
|
||||
qbyte *line, *colon;
|
||||
while (reqstart < buffered)
|
||||
{
|
||||
colon = NULL;
|
||||
for (line = reqstart; line < buffered && *line; line++)
|
||||
{
|
||||
if (*line == ':')
|
||||
{
|
||||
line++;
|
||||
colon = line;
|
||||
break;
|
||||
}
|
||||
if (*line == '\n')
|
||||
break;
|
||||
}
|
||||
for (; line < buffered && *line; line++)
|
||||
{
|
||||
if (*line == '\n')
|
||||
break;
|
||||
}
|
||||
|
||||
*line++ = 0;
|
||||
|
||||
if (colon)
|
||||
{
|
||||
if (colon-reqstart == 9 && !strncmp(reqstart, "Password:", 9))
|
||||
pwd = colon;
|
||||
}
|
||||
reqstart = line;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (sv.state == ss_clustermode) //only allow remote node additions if we're actually using this stuff.
|
||||
{
|
||||
extern cvar_t rcon_password;
|
||||
COM_ParseOut(pwd, com_token, sizeof(com_token));
|
||||
if (*rcon_password.string && !strcmp(com_token, rcon_password.string))
|
||||
{
|
||||
pubsubserver_t *s = MSV_Link_Server(stream, 0, "");
|
||||
if (s)
|
||||
{ //and make sure we don't drop any data that was sent after the header.
|
||||
memcpy(s->inbuffer, buffered, buffersize);
|
||||
s->inbuffersize = buffersize;
|
||||
|
||||
Con_Printf("Server node at %s connected\n", remoteaddr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
Con_Printf("Server node at %s rejected - bad password\n", remoteaddr);
|
||||
}
|
||||
|
||||
VFS_CLOSE(stream);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//our pipes are one-way (one side writes, the other side reads).
|
||||
static vfsfile_t *msv_loop_to_ss;
|
||||
static vfsfile_t *msv_loop_from_ss;
|
||||
//but the master needs two-way pipes like tcp (each side can read the other's writes).
|
||||
static int QDECL MSV_Loop_Read (struct vfsfile_s *file, void *buffer, int bytestoread)
|
||||
{
|
||||
return VFS_READ(msv_loop_to_ss, buffer, bytestoread);
|
||||
}
|
||||
static int QDECL MSV_Loop_Write (struct vfsfile_s *file, const void *buffer, int bytestowrite)
|
||||
{
|
||||
return VFS_WRITE(msv_loop_to_ss, buffer, bytestowrite);
|
||||
}
|
||||
static qboolean QDECL MSV_Loop_Close (struct vfsfile_s *file)
|
||||
{
|
||||
Z_Free(file);
|
||||
return true;
|
||||
}
|
||||
static pubsubserver_t *MSV_Loop_GetLocalServer(void)
|
||||
{
|
||||
vfsfile_t *f;
|
||||
pubsubserver_t *s = MSV_FindSubServer(svs.clusterserverid);
|
||||
if (s)
|
||||
return s;
|
||||
|
@ -223,27 +361,38 @@ pubsubserver_t *MSV_Loop_GetLocalServer(void)
|
|||
|
||||
msv_loop_to_ss = VFSPIPE_Open(1, false);
|
||||
msv_loop_from_ss = VFSPIPE_Open(1, false);
|
||||
s = Z_Malloc(sizeof(*s));
|
||||
s->funcs.InstructSlave = MSV_Loop_Instruct;
|
||||
s->funcs.SubServerRead = MSV_Loop_Read;
|
||||
f = Z_Malloc(sizeof(*f));
|
||||
f->ReadBytes = MSV_Loop_Read;
|
||||
f->WriteBytes = MSV_Loop_Write;
|
||||
f->Close = MSV_Loop_Close;
|
||||
|
||||
MSV_Link_Server(s, 0, "");
|
||||
s = MSV_Link_Server(f, 0, "");
|
||||
Q_strncpyz(s->name, sv.mapname, sizeof(s->name));
|
||||
svs.clusterserverid = s->id;
|
||||
return s;
|
||||
}
|
||||
|
||||
pubsubserver_t *MSV_StartSubServer(unsigned int id, const char *mapname)
|
||||
//called at startup to let us know the control connection to read/write
|
||||
void SSV_SetupControlPipe(vfsfile_t *f)
|
||||
{
|
||||
pubsubserver_t *s = Sys_ForkServer();
|
||||
if (!isDedicated)
|
||||
Sys_Error("Subserver in non-dedicated server?");
|
||||
if (controlconnection)
|
||||
VFS_CLOSE(controlconnection);
|
||||
controlconnection = f;
|
||||
isClusterSlave = !!f;
|
||||
}
|
||||
|
||||
static pubsubserver_t *MSV_StartSubServer(unsigned int id, const char *mapname)
|
||||
{
|
||||
vfsfile_t *s = Sys_ForkServer();
|
||||
|
||||
if (s)
|
||||
MSV_Link_Server(s, id, mapname);
|
||||
return s;
|
||||
return MSV_Link_Server(s, id, mapname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//server names documented at the start of this file
|
||||
pubsubserver_t *MSV_FindSubServerName(const char *servername)
|
||||
static pubsubserver_t *MSV_FindSubServerName(const char *servername)
|
||||
{
|
||||
pubsubserver_t *s;
|
||||
unsigned int id;
|
||||
|
@ -304,7 +453,7 @@ qboolean MSV_InstructSlave(unsigned int id, sizebuf_t *cmd)
|
|||
if (!id)
|
||||
{
|
||||
for (s = subservers; s; s = s->next)
|
||||
s->funcs.InstructSlave(s, cmd);
|
||||
MSV_WriteSlave(s, cmd);
|
||||
return subservers?true:false;
|
||||
}
|
||||
else
|
||||
|
@ -312,7 +461,7 @@ qboolean MSV_InstructSlave(unsigned int id, sizebuf_t *cmd)
|
|||
s = MSV_FindSubServer(id);
|
||||
if (s)
|
||||
{
|
||||
s->funcs.InstructSlave(s, cmd);
|
||||
MSV_WriteSlave(s, cmd);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -378,6 +527,10 @@ void SSV_PrintToMaster(char *s)
|
|||
{
|
||||
sizebuf_t send;
|
||||
char send_buf[8192];
|
||||
static qboolean norecurse;
|
||||
if (norecurse)
|
||||
return;
|
||||
|
||||
memset(&send, 0, sizeof(send));
|
||||
send.data = send_buf;
|
||||
send.maxsize = sizeof(send_buf);
|
||||
|
@ -385,7 +538,9 @@ void SSV_PrintToMaster(char *s)
|
|||
|
||||
MSG_WriteByte(&send, ccmd_print);
|
||||
MSG_WriteString(&send, s);
|
||||
norecurse = true;
|
||||
SSV_InstructMaster(&send);
|
||||
norecurse = false;
|
||||
}
|
||||
|
||||
void MSV_Status(void)
|
||||
|
@ -422,6 +577,9 @@ static int MSV_SubConsole_LineBuffered(console_t *con, const char *utf8line)
|
|||
|
||||
Con_PrintCon(con, va("]%s\n", utf8line), PFS_FORCEUTF8|PFS_NONOTIFY);
|
||||
|
||||
if (*utf8line == '/')
|
||||
utf8line++; //command, not text.
|
||||
|
||||
if (!strcmp(utf8line, "clear"))
|
||||
{
|
||||
Con_ClearCon(con);
|
||||
|
@ -436,7 +594,7 @@ static int MSV_SubConsole_LineBuffered(console_t *con, const char *utf8line)
|
|||
MSG_WriteString(&buf, utf8line); //FIXME: is utf-8 a problem?
|
||||
buf.data[0] = buf.cursize & 0xff;
|
||||
buf.data[1] = (buf.cursize>>8) & 0xff;
|
||||
s->funcs.InstructSlave(s, &buf);
|
||||
MSV_WriteSlave(s, &buf);
|
||||
}
|
||||
else
|
||||
Con_Footerf(con, false, "< Unable to send >");
|
||||
|
@ -602,7 +760,7 @@ qboolean MSV_ForwardToAutoServer(void)
|
|||
MSG_WriteString(&buf, args);
|
||||
buf.data[0] = buf.cursize & 0xff;
|
||||
buf.data[1] = (buf.cursize>>8) & 0xff;
|
||||
s->funcs.InstructSlave(s, &buf);
|
||||
MSV_WriteSlave(s, &buf);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -702,7 +860,7 @@ void MSV_ReadFromSubServer(pubsubserver_t *s)
|
|||
MSG_WriteByte(&send, ccmd_transferedplayer);
|
||||
MSG_WriteLong(&send, s->id);
|
||||
MSG_WriteLong(&send, plid);
|
||||
pl->server->funcs.InstructSlave(pl->server, &send);
|
||||
MSV_WriteSlave(pl->server, &send);
|
||||
pl->server->activeplayers--;
|
||||
}
|
||||
pl->server = s;
|
||||
|
@ -771,7 +929,7 @@ void MSV_ReadFromSubServer(pubsubserver_t *s)
|
|||
|
||||
MSG_WriteByte(&send, statsblobsize/4);
|
||||
SZ_Write(&send, statsblob, statsblobsize&~3);
|
||||
s->funcs.InstructSlave(s, &send);
|
||||
MSV_WriteSlave(s, &send);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -808,7 +966,7 @@ void MSV_ReadFromSubServer(pubsubserver_t *s)
|
|||
while(c--)
|
||||
MSG_WriteFloat(&send, MSG_ReadFloat());
|
||||
|
||||
toptr->funcs.InstructSlave(toptr, &send);
|
||||
MSV_WriteSlave(toptr, &send);
|
||||
|
||||
s->transferingplayers--;
|
||||
toptr->transferingplayers++;
|
||||
|
@ -827,7 +985,7 @@ void MSV_ReadFromSubServer(pubsubserver_t *s)
|
|||
MSG_WriteLong(&send, plid);
|
||||
MSG_WriteString(&send, "");
|
||||
|
||||
s->funcs.InstructSlave(s, &send);
|
||||
MSV_WriteSlave(s, &send);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -868,7 +1026,7 @@ void MSV_ReadFromSubServer(pubsubserver_t *s)
|
|||
toptr = MSV_FindSubServer(to);
|
||||
if (toptr)
|
||||
{
|
||||
toptr->funcs.InstructSlave(toptr, &send);
|
||||
MSV_WriteSlave(toptr, &send);
|
||||
toptr->transferingplayers++;
|
||||
}
|
||||
}
|
||||
|
@ -937,21 +1095,21 @@ void MSV_ReadFromSubServer(pubsubserver_t *s)
|
|||
if (!*dest) //broadcast if no dest
|
||||
{
|
||||
for (s = subservers; s; s = s->next)
|
||||
s->funcs.InstructSlave(s, &send);
|
||||
MSV_WriteSlave(s, &send);
|
||||
}
|
||||
else if (*dest == '\\')
|
||||
{
|
||||
//send to a specific server (backslashes should not be valid in infostrings, and thus not in names.
|
||||
//FIXME: broadcasting for now.
|
||||
for (s = subservers; s; s = s->next)
|
||||
s->funcs.InstructSlave(s, &send);
|
||||
MSV_WriteSlave(s, &send);
|
||||
}
|
||||
else
|
||||
{
|
||||
//send it to the server that the player is currently on.
|
||||
clusterplayer_t *pl = MSV_FindPlayerName(dest);
|
||||
if (pl)
|
||||
pl->server->funcs.InstructSlave(pl->server, &send);
|
||||
MSV_WriteSlave(pl->server, &send);
|
||||
else if (!pl && strncmp(cmd, "error:", 6))
|
||||
{
|
||||
//player not found. send it back to the sender, but add an error prefix.
|
||||
|
@ -962,7 +1120,7 @@ void MSV_ReadFromSubServer(pubsubserver_t *s)
|
|||
SZ_Write(&send, "error:", 6);
|
||||
MSG_WriteString(&send, cmd);
|
||||
MSG_WriteString(&send, info);
|
||||
s->funcs.InstructSlave(s, &send);
|
||||
MSV_WriteSlave(s, &send);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -976,7 +1134,57 @@ void MSV_PollSlaves(void)
|
|||
{
|
||||
pubsubserver_t **link, *s;
|
||||
|
||||
if (msv_loop_to_ss)
|
||||
if (controlconnection)
|
||||
{
|
||||
static unsigned inbuffersize;
|
||||
static qbyte inbuffer[8192];
|
||||
qboolean error = false;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (inbuffersize < 2)
|
||||
{
|
||||
int r = VFS_READ(controlconnection, inbuffer+inbuffersize, 2-inbuffersize);
|
||||
if (r < 0)
|
||||
error = true;
|
||||
else
|
||||
inbuffersize += r;
|
||||
}
|
||||
if (inbuffersize >= 2)
|
||||
{
|
||||
size_t size = inbuffer[0] | ((unsigned short)inbuffer[1]<<8);
|
||||
int r;
|
||||
if (size > sizeof(inbuffer) || size >= sizeof(net_message_buffer))
|
||||
break; //error...
|
||||
if (size > inbuffersize)
|
||||
{
|
||||
r = VFS_READ(controlconnection, inbuffer+inbuffersize, size-inbuffersize);
|
||||
if (r < 0)
|
||||
error = true;
|
||||
else
|
||||
inbuffersize += r;
|
||||
}
|
||||
if (inbuffersize < size)
|
||||
break; //not complete yet.
|
||||
|
||||
net_message.cursize = size-2;
|
||||
memcpy(net_message.data, inbuffer+2, net_message.cursize);
|
||||
memmove(inbuffer, inbuffer+size, inbuffersize-size);
|
||||
inbuffersize -= size;
|
||||
|
||||
MSG_BeginReading (msg_nullnetprim);
|
||||
SSV_ReadFromControlServer();
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (error)
|
||||
{
|
||||
SSV_SetupControlPipe(NULL);
|
||||
inbuffersize = 0;
|
||||
}
|
||||
}
|
||||
else if (msv_loop_to_ss)
|
||||
{
|
||||
unsigned short size;
|
||||
while (VFS_READ(msv_loop_to_ss, &size, sizeof(size))>0)
|
||||
|
@ -990,7 +1198,7 @@ void MSV_PollSlaves(void)
|
|||
|
||||
for (link = &subservers; (s=*link); )
|
||||
{
|
||||
switch(s->funcs.SubServerRead(s))
|
||||
switch(MSV_SubServerRead(s))
|
||||
{
|
||||
case -1:
|
||||
//error - server is dead and needs to be freed.
|
||||
|
@ -1001,7 +1209,7 @@ void MSV_PollSlaves(void)
|
|||
//no messages
|
||||
link = &s->next;
|
||||
break;
|
||||
case 1:
|
||||
default:
|
||||
//got a message. read it and see if there's more.
|
||||
MSV_ReadFromSubServer(s);
|
||||
break;
|
||||
|
@ -1015,8 +1223,10 @@ void SSV_InstructMaster(sizebuf_t *cmd)
|
|||
cmd->data[1] = (cmd->cursize>>8) & 0xff;
|
||||
if (msv_loop_from_ss)
|
||||
VFS_WRITE(msv_loop_from_ss, cmd->data, cmd->cursize);
|
||||
else
|
||||
Sys_InstructMaster(cmd);
|
||||
else if (controlconnection)
|
||||
VFS_WRITE(controlconnection, cmd->data, cmd->cursize);
|
||||
|
||||
//FIXME: handle partial writes.
|
||||
}
|
||||
|
||||
void SSV_ReadFromControlServer(void)
|
||||
|
@ -1044,7 +1254,7 @@ void SSV_ReadFromControlServer(void)
|
|||
{
|
||||
cvar_t *var = Cvar_FindVar(MSG_ReadString());
|
||||
const char *val = MSG_ReadString();
|
||||
Con_Printf("Setting cvar \"%s\" to \"%s\"\n", var?var->name:"UNKNOWN", val);
|
||||
Con_DPrintf("Setting cvar \"%s\" to \"%s\"\n", var?var->name:"UNKNOWN", val);
|
||||
Cvar_Set(var, val);
|
||||
}
|
||||
break;
|
||||
|
@ -1470,7 +1680,7 @@ qboolean MSV_ClusterLoginReply(netadr_t *legacyclientredirect, unsigned int serv
|
|||
|
||||
MSG_WriteByte(&send, statsblobsize/4);
|
||||
SZ_Write(&send, statsblob, statsblobsize&~3);
|
||||
s->funcs.InstructSlave(s, &send);
|
||||
MSV_WriteSlave(s, &send);
|
||||
|
||||
if (serveraddr.type == NA_INVALID)
|
||||
{
|
||||
|
|
|
@ -2228,7 +2228,7 @@ void SV_MVD_QTVReverse_f (void)
|
|||
if (sv.state<ss_loading)
|
||||
return;
|
||||
|
||||
f = FS_OpenTCP(ip, 27599);
|
||||
f = FS_OpenTCP(ip, 27599, false);
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
|
|
|
@ -2523,8 +2523,13 @@ qboolean SV_Physics (void)
|
|||
int maxtics;
|
||||
double trueframetime = host_frametime;
|
||||
double maxtic = sv_maxtic.value;
|
||||
if (maxtic < sv_mintic.value)
|
||||
maxtic = sv_mintic.value;
|
||||
double mintic = sv_mintic.value;
|
||||
extern cvar_t sv_nqplayerphysics;
|
||||
if (sv_nqplayerphysics.ival)
|
||||
if (mintic < 0.013)
|
||||
mintic = 0.013; //NQ physics can't cope with low rates and just generally bugs out.
|
||||
if (maxtic < mintic)
|
||||
maxtic = mintic;
|
||||
|
||||
//keep gravity tracking the cvar properly
|
||||
movevars.gravity = sv_gravity.value;
|
||||
|
@ -2653,7 +2658,7 @@ qboolean SV_Physics (void)
|
|||
sv.world.physicstime = sv.time;
|
||||
break;
|
||||
}
|
||||
if (host_frametime <= 0 || host_frametime < sv_mintic.value)
|
||||
if (host_frametime <= 0 || host_frametime < mintic)
|
||||
break;
|
||||
if (host_frametime > maxtic)
|
||||
{
|
||||
|
|
|
@ -3609,16 +3609,28 @@ void SV_SendClientMessages (void)
|
|||
}
|
||||
else
|
||||
{
|
||||
extern cvar_t sv_nqplayerphysics;
|
||||
if (c->nextservertimeupdate > pt + 0.1)
|
||||
c->nextservertimeupdate = 0;
|
||||
|
||||
c->netchan.nqunreliableonly = false;
|
||||
c->send_message = false;
|
||||
//nq sends one packet only for each server physics frame
|
||||
if (c->nextservertimeupdate < pt && c->state >= cs_connected)
|
||||
if (sv_mintic.value || sv_nqplayerphysics.ival) //(nqplayerphysics forces 72hz when mintic )
|
||||
{ //explicit packet/tick rate. don't spam faster/slower, clients don't like that too much.
|
||||
if (c->nextservertimeupdate != pt && c->state >= cs_connected)
|
||||
{
|
||||
c->send_message = true;
|
||||
c->nextservertimeupdate = pt;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
c->send_message = true;
|
||||
c->nextservertimeupdate = pt + 1.0/77;
|
||||
if (c->nextservertimeupdate < pt && c->state >= cs_connected)
|
||||
{
|
||||
c->send_message = true;
|
||||
c->nextservertimeupdate = pt + 1.0/77;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -601,14 +601,6 @@ char *Sys_ConsoleInput (void)
|
|||
static char text[256];
|
||||
int len;
|
||||
|
||||
#ifdef SUBSERVERS
|
||||
if (SSV_IsSubServer())
|
||||
{
|
||||
SSV_CheckFromMaster();
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!stdin_ready || noconinput==true)
|
||||
return NULL; // the select didn't say it was ready
|
||||
stdin_ready = false;
|
||||
|
|
|
@ -695,14 +695,14 @@ void SVNQ_New_f (void)
|
|||
//which isn't all that useful. so lets customise it to advertise properly, as well as provide gamedir and map (file)name info
|
||||
if (protext2 & PEXT2_REPLACEMENTDELTAS)
|
||||
{
|
||||
Q_snprintfz (message, sizeof(message), "%c\n%s - "DISTRIBUTION" (FTENQ, %s) - %s", 2, gamedir,
|
||||
build, mapname);
|
||||
Q_snprintfz (message, sizeof(message), "%c\n"DISTRIBUTION" %s - %s - %s", 2,
|
||||
build,gamedir, mapname);
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_snprintfz (message, sizeof(message), "%c\n%s - "DISTRIBUTION" (%s%s%s, %s) - %s", 2, gamedir,
|
||||
Q_snprintfz (message, sizeof(message), "%c\n"DISTRIBUTION" (%s%s%s, %s) - %s - %s", 2,
|
||||
protoname,(protext1||(protext2&~PEXT2_VOICECHAT))?"+":"",(protext2&PEXT2_VOICECHAT)?"Voip":"",
|
||||
build, mapname);
|
||||
build,gamedir, mapname);
|
||||
}
|
||||
MSG_WriteByte (&host_client->netchan.message, svc_print);
|
||||
MSG_WriteString (&host_client->netchan.message,message);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
!!samps =REFLECT reflect=1
|
||||
!!samps =RIPPLEMAP ripplemap=2
|
||||
!!samps =DEPTH refractdepth=3
|
||||
!!permu FOG
|
||||
|
||||
#include "sys/defs.h"
|
||||
|
||||
|
@ -87,9 +88,7 @@ void main (void)
|
|||
}
|
||||
#endif
|
||||
#ifdef FRAGMENT_SHADER
|
||||
#ifdef ALPHA
|
||||
#include "sys/fog.h"
|
||||
#endif
|
||||
|
||||
|
||||
void main (void)
|
||||
|
@ -178,6 +177,8 @@ void main (void)
|
|||
vec4 ts = texture2D(s_diffuse, ntc);
|
||||
vec4 surf = fog4blend(vec4(ts.rgb, float(ALPHA)*ts.a));
|
||||
refr = mix(refr, surf.rgb, surf.a);
|
||||
#else
|
||||
refr = fog3(refr);
|
||||
#endif
|
||||
|
||||
//done
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
!!permu FOG
|
||||
!!samps 2
|
||||
!!samps base=0, cloud=1
|
||||
!!cvardf r_skyfog=0.5
|
||||
#include "sys/fog.h"
|
||||
|
||||
//regular sky shader for scrolling q1 skies
|
||||
|
@ -24,9 +25,14 @@ void main ()
|
|||
dir.z *= 3.0;
|
||||
dir.xy /= 0.5*length(dir);
|
||||
tccoord = (dir.xy + e_time*0.03125);
|
||||
vec3 solid = vec3(texture2D(s_t0, tccoord));
|
||||
vec3 sky = vec3(texture2D(s_base, tccoord));
|
||||
tccoord = (dir.xy + e_time*0.0625);
|
||||
vec4 clouds = texture2D(s_t1, tccoord);
|
||||
gl_FragColor = vec4(fog3((solid.rgb*(1.0-clouds.a)) + (clouds.a*clouds.rgb)), 1.0);
|
||||
vec4 clouds = texture2D(s_cloud, tccoord);
|
||||
sky = (sky.rgb*(1.0-clouds.a)) + (clouds.a*clouds.rgb);
|
||||
#ifdef FOG
|
||||
sky.rgb = mix(sky.rgb, w_fogcolour, float(r_skyfog)*w_fogalpha); //flat fog ignoring actual geometry
|
||||
//sky = fog3(sky); //fog according to actual geometry
|
||||
#endif
|
||||
gl_FragColor = vec4(sky, 1.0);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -35,6 +35,13 @@ void main ()
|
|||
void main ()
|
||||
{
|
||||
vec4 skybox = textureCube(s_reflectcube, pos);
|
||||
gl_FragColor = vec4(mix(skybox.rgb, fog3(skybox.rgb), float(r_skyfog)), 1.0);
|
||||
|
||||
//Fun question: should sky be fogged as if infinite, or as if an actual surface?
|
||||
#if 1
|
||||
skybox.rgb = mix(skybox.rgb, w_fogcolour_ float(r_skyfog)*w_fogalpha); //flat fog ignoring actual geometry
|
||||
#else
|
||||
skybox.rgb = mix(skybox.rgb, fog3(skybox.rgb), float(r_skyfog)); //fog in terms of actual geometry distance
|
||||
#endif
|
||||
gl_FragColor = skybox;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
!!ver 100 450
|
||||
!!permu TESS
|
||||
!!permu DELUXE
|
||||
!!permu FULLBRIGHT
|
||||
!!permu FULLBRIGHT //lumas rather than no lightmaps
|
||||
!!permu FOG
|
||||
!!permu LIGHTSTYLED
|
||||
!!permu BUMP
|
||||
|
@ -18,7 +18,7 @@
|
|||
//diffuse gives us alpha, and prevents dlight from bugging out when there's no diffuse.
|
||||
!!samps =EIGHTBIT paletted 1
|
||||
!!samps =SPECULAR specular
|
||||
!!samps lightmap
|
||||
!!samps !VERTEXLIT lightmap
|
||||
!!samps =LIGHTSTYLED lightmap1 lightmap2 lightmap3
|
||||
!!samps =DELUXE deluxemap
|
||||
!!samps =LIGHTSTYLED =DELUXE deluxemap1 deluxemap2 deluxemap3
|
||||
|
@ -269,7 +269,7 @@ void main ()
|
|||
//optional: round the lightmap coords to ensure all pixels within a texel have different lighting values either. it just looks wrong otherwise.
|
||||
//don't bother if its lightstyled, such cases will have unpredictable correlations anyway.
|
||||
//FIXME: this rounding is likely not correct with respect to software rendering. oh well.
|
||||
#if __VERSION__ >= 130
|
||||
#if __VERSION__ >= 130 && !defined(VERTEXLIT)
|
||||
vec2 lmsize = vec2(textureSize(s_lightmap0, 0));
|
||||
#else
|
||||
#define lmsize vec2(128.0,2048.0)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
!!ver 100 450
|
||||
!!permu FOG
|
||||
!!cvarf r_wateralpha
|
||||
!!samps diffuse lightmap
|
||||
|
||||
#include "sys/defs.h"
|
||||
|
@ -9,6 +8,7 @@
|
|||
//this is expected to be moderately fast.
|
||||
|
||||
#include "sys/fog.h"
|
||||
|
||||
varying vec2 tc;
|
||||
#ifdef LIT
|
||||
varying vec2 lm0;
|
||||
|
@ -27,12 +27,6 @@ void main ()
|
|||
}
|
||||
#endif
|
||||
#ifdef FRAGMENT_SHADER
|
||||
#ifndef ALPHA
|
||||
uniform float cvar_r_wateralpha;
|
||||
#define USEALPHA cvar_r_wateralpha
|
||||
#else
|
||||
#define USEALPHA float(ALPHA)
|
||||
#endif
|
||||
void main ()
|
||||
{
|
||||
vec2 ntc;
|
||||
|
@ -44,6 +38,10 @@ void main ()
|
|||
ts *= (texture2D(s_lightmap, lm0) * e_lmscale).rgb;
|
||||
#endif
|
||||
|
||||
gl_FragColor = fog4blend(vec4(ts, USEALPHA) * e_colourident);
|
||||
#ifdef ALPHA
|
||||
gl_FragColor = fog4blend(vec4(ts, float(ALPHA)) * e_colourident);
|
||||
#else
|
||||
gl_FragColor = fog4(vec4(ts, 1.0) * e_colourident);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1461,6 +1461,39 @@ vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t lay
|
|||
case PTI_ASTC_12X12_HDR: format = VK_FORMAT_ASTC_12x12_UNORM_BLOCK; break;
|
||||
#endif
|
||||
|
||||
#ifdef ASTC3D
|
||||
case PTI_ASTC_3X3X3_HDR: //vulkan doesn't support these for some reason
|
||||
case PTI_ASTC_4X3X3_HDR:
|
||||
case PTI_ASTC_4X4X3_HDR:
|
||||
case PTI_ASTC_4X4X4_HDR:
|
||||
case PTI_ASTC_5X4X4_HDR:
|
||||
case PTI_ASTC_5X5X4_HDR:
|
||||
case PTI_ASTC_5X5X5_HDR:
|
||||
case PTI_ASTC_6X5X5_HDR:
|
||||
case PTI_ASTC_6X6X5_HDR:
|
||||
case PTI_ASTC_6X6X6_HDR:
|
||||
case PTI_ASTC_3X3X3_LDR:
|
||||
case PTI_ASTC_4X3X3_LDR:
|
||||
case PTI_ASTC_4X4X3_LDR:
|
||||
case PTI_ASTC_4X4X4_LDR:
|
||||
case PTI_ASTC_5X4X4_LDR:
|
||||
case PTI_ASTC_5X5X4_LDR:
|
||||
case PTI_ASTC_5X5X5_LDR:
|
||||
case PTI_ASTC_6X5X5_LDR:
|
||||
case PTI_ASTC_6X6X5_LDR:
|
||||
case PTI_ASTC_6X6X6_LDR:
|
||||
case PTI_ASTC_3X3X3_SRGB:
|
||||
case PTI_ASTC_4X3X3_SRGB:
|
||||
case PTI_ASTC_4X4X3_SRGB:
|
||||
case PTI_ASTC_4X4X4_SRGB:
|
||||
case PTI_ASTC_5X4X4_SRGB:
|
||||
case PTI_ASTC_5X5X4_SRGB:
|
||||
case PTI_ASTC_5X5X5_SRGB:
|
||||
case PTI_ASTC_6X5X5_SRGB:
|
||||
case PTI_ASTC_6X6X5_SRGB:
|
||||
case PTI_ASTC_6X6X6_SRGB: break;
|
||||
#endif
|
||||
|
||||
//depth formats
|
||||
case PTI_DEPTH16: format = VK_FORMAT_D16_UNORM; break;
|
||||
case PTI_DEPTH24: format = VK_FORMAT_X8_D24_UNORM_PACK32; break;
|
||||
|
@ -1797,7 +1830,7 @@ qboolean VK_LoadTextureMips (texid_t tex, const struct pendingtextureinfo *mips)
|
|||
VkCommandBuffer vkloadcmd;
|
||||
vk_image_t target;
|
||||
uint32_t i;
|
||||
uint32_t blockwidth, blockheight;
|
||||
uint32_t blockwidth, blockheight, blockdepth;
|
||||
uint32_t blockbytes;
|
||||
uint32_t layers;
|
||||
uint32_t mipcount = mips->mipcount;
|
||||
|
@ -1835,7 +1868,7 @@ qboolean VK_LoadTextureMips (texid_t tex, const struct pendingtextureinfo *mips)
|
|||
}
|
||||
}
|
||||
|
||||
Image_BlockSizeForEncoding(mips->encoding, &blockbytes, &blockwidth, &blockheight);
|
||||
Image_BlockSizeForEncoding(mips->encoding, &blockbytes, &blockwidth, &blockheight, &blockdepth);
|
||||
|
||||
fence = VK_FencedBegin(VK_TextureLoaded, sizeof(*fence));
|
||||
fence->mips = mipcount;
|
||||
|
@ -1925,7 +1958,7 @@ qboolean VK_LoadTextureMips (texid_t tex, const struct pendingtextureinfo *mips)
|
|||
{
|
||||
uint32_t blockswidth = (mips->mip[i].width+blockwidth-1) / blockwidth;
|
||||
uint32_t blocksheight = (mips->mip[i].height+blockheight-1) / blockheight;
|
||||
uint32_t blocksdepth = (mips->mip[i].depth+1-1) / 1;
|
||||
uint32_t blocksdepth = (mips->mip[i].depth+blockdepth-1) / blockdepth;
|
||||
bci.size += blockswidth*blocksheight*blocksdepth*blockbytes;
|
||||
}
|
||||
bci.flags = 0;
|
||||
|
@ -1961,7 +1994,7 @@ qboolean VK_LoadTextureMips (texid_t tex, const struct pendingtextureinfo *mips)
|
|||
//for compressed formats (ie: s3tc/dxt) we need to round up to deal with npot.
|
||||
uint32_t blockswidth = (mips->mip[i].width+blockwidth-1) / blockwidth;
|
||||
uint32_t blocksheight = (mips->mip[i].height+blockheight-1) / blockheight;
|
||||
uint32_t blocksdepth = (mips->mip[i].depth+1-1) / 1;
|
||||
uint32_t blocksdepth = (mips->mip[i].depth+blockdepth-1) / blockdepth;
|
||||
|
||||
if (mips->mip[i].data)
|
||||
memcpy((char*)mapdata + bci.size, (char*)mips->mip[i].data, blockswidth*blockbytes*blocksheight*blocksdepth);
|
||||
|
|
59
imgtool.c
59
imgtool.c
|
@ -530,7 +530,7 @@ static qboolean ImgTool_ConvertPixelFormat(struct opts_s *args, const char *inna
|
|||
|
||||
qbyte *fdata;
|
||||
size_t fsize;
|
||||
int bb,bw,bh;
|
||||
int bb,bw,bh,bd;
|
||||
qboolean canktx = false;
|
||||
uploadfmt_t targfmt = args->newpixelformat;
|
||||
int d,l, layers, r;
|
||||
|
@ -605,10 +605,15 @@ static qboolean ImgTool_ConvertPixelFormat(struct opts_s *args, const char *inna
|
|||
tmp.extrafree = NULL;
|
||||
tmp.mipcount = 1;
|
||||
|
||||
Image_BlockSizeForEncoding(targfmt, &bb, &bw, &bh);
|
||||
Image_BlockSizeForEncoding(targfmt, &bb, &bw, &bh, &bd);
|
||||
Q_snprintfz(command+strlen(command), sizeof(command)-strlen(command), " \"%s\" \"%s\"", raw, comp);
|
||||
if (targfmt >= PTI_ASTC_FIRST && targfmt <= PTI_ASTC_LAST)
|
||||
Q_snprintfz(command+strlen(command), sizeof(command)-strlen(command), " %ix%i -exhaustive", bw, bh);
|
||||
{
|
||||
if (bd!=1)
|
||||
Q_snprintfz(command+strlen(command), sizeof(command)-strlen(command), " %ix%ix%i -exhaustive", bw, bh, bd);
|
||||
else
|
||||
Q_snprintfz(command+strlen(command), sizeof(command)-strlen(command), " %ix%i -exhaustive", bw, bh);
|
||||
}
|
||||
if (targfmt >= PTI_ASTC_4X4_SRGB && targfmt <= PTI_ASTC_12X12_SRGB)
|
||||
Q_strncatz(command, " -srgb", sizeof(command));
|
||||
if (targfmt >= PTI_ASTC_4X4_HDR && targfmt <= PTI_ASTC_12X12_HDR)
|
||||
|
@ -641,7 +646,7 @@ static qboolean ImgTool_ConvertPixelFormat(struct opts_s *args, const char *inna
|
|||
|
||||
// Con_Printf("%s: Compressing %u mips\n", inname, mips->mipcount);
|
||||
|
||||
Image_BlockSizeForEncoding(mips->encoding, &bb, &bw, &bh);
|
||||
Image_BlockSizeForEncoding(mips->encoding, &bb, &bw, &bh, &bd);
|
||||
for (m = 0; m < mips->mipcount; m++)
|
||||
{
|
||||
qbyte *srcdata = mips->mip[m].data;
|
||||
|
@ -731,8 +736,8 @@ static qboolean ImgTool_ConvertPixelFormat(struct opts_s *args, const char *inna
|
|||
if (mips->mipcount && targfmt >= PTI_BC1_RGB && targfmt <= PTI_BC7_RGBA_SRGB)
|
||||
{ //d3d has some annoying limitations.
|
||||
//do not warn for astc files, their block sizes are too weird.
|
||||
Image_BlockSizeForEncoding(targfmt, &bb, &bw, &bh);
|
||||
if (mips->mip[0].width%bw || mips->mip[0].height%bh)
|
||||
Image_BlockSizeForEncoding(targfmt, &bb, &bw, &bh, &bd);
|
||||
if (mips->mip[0].width%bw || mips->mip[0].height%bh || mips->mip[0].depth%bd)
|
||||
Con_Printf("%s: mip0 of %i*%i is not a multiple of %i*%i (d3d warning)\n", inname, mips->mip[0].width, mips->mip[0].height, bw, bh);
|
||||
}
|
||||
|
||||
|
@ -903,11 +908,11 @@ static struct pendingtextureinfo *ImgTool_Combine(struct opts_s *args, const cha
|
|||
{
|
||||
if (facetype[i] < 0)
|
||||
{ //flip to match legacy skyboxes
|
||||
unsigned bb,bw,bh;
|
||||
unsigned bb,bw,bh,bd;
|
||||
srcs[i] = tmpsrcs[-facetype[i]-1];
|
||||
t = srcs[i].in;
|
||||
Image_BlockSizeForEncoding(t->encoding, &bb,&bw,&bh);
|
||||
if (bw == 1 && bh == 1)
|
||||
Image_BlockSizeForEncoding(t->encoding, &bb,&bw,&bh,&bd);
|
||||
if (bw == 1 && bh == 1 && bd == 1)
|
||||
{
|
||||
for (j = 0; j < t->mipcount; j++)
|
||||
{
|
||||
|
@ -1071,7 +1076,7 @@ static void ImgTool_Convert(struct opts_s *args, struct pendingtextureinfo *in,
|
|||
#endif
|
||||
else
|
||||
{
|
||||
int bb,bw,bh;
|
||||
int bb,bw,bh,bd;
|
||||
|
||||
if (in->type != PTI_2D)
|
||||
Con_Printf("%s: Unable to write %s file to 2d image format\n", outname, imagetypename[in->type]);
|
||||
|
@ -1093,7 +1098,7 @@ static void ImgTool_Convert(struct opts_s *args, struct pendingtextureinfo *in,
|
|||
0;
|
||||
if (!outformats[in->encoding])
|
||||
Image_ChangeFormat(in, outformats, PTI_INVALID, outname);
|
||||
Image_BlockSizeForEncoding(in->encoding, &bb, &bw,&bh);
|
||||
Image_BlockSizeForEncoding(in->encoding, &bb, &bw,&bh,&bd);
|
||||
if (!Image_WritePNG(outname, FS_SYSTEM, 0, &in->mip[0].data, 1, in->mip[0].width*bb, in->mip[0].width, in->mip[0].height, in->encoding, false))
|
||||
#endif
|
||||
Con_Printf("%s(%s): Write failed\n", outname, Image_FormatName(in->encoding));
|
||||
|
@ -1115,7 +1120,7 @@ static void ImgTool_Convert(struct opts_s *args, struct pendingtextureinfo *in,
|
|||
0;
|
||||
if (!outformats[in->encoding])
|
||||
Image_ChangeFormat(in, outformats, PTI_INVALID, outname);
|
||||
Image_BlockSizeForEncoding(in->encoding, &bb, &bw,&bh);
|
||||
Image_BlockSizeForEncoding(in->encoding, &bb, &bw,&bh,&bd);
|
||||
if (!WriteTGA(outname, FS_SYSTEM, in->mip[0].data, in->mip[0].width*bb, in->mip[0].width, in->mip[0].height, in->encoding))
|
||||
Con_Printf("%s(%s): Write failed\n", outname, Image_FormatName(in->encoding));
|
||||
}
|
||||
|
@ -1133,7 +1138,7 @@ static void ImgTool_Convert(struct opts_s *args, struct pendingtextureinfo *in,
|
|||
0;
|
||||
if (!outformats[in->encoding])
|
||||
Image_ChangeFormat(in, outformats, PTI_INVALID, outname);
|
||||
Image_BlockSizeForEncoding(in->encoding, &bb, &bw,&bh);
|
||||
Image_BlockSizeForEncoding(in->encoding, &bb, &bw,&bh,&bd);
|
||||
if (!WritePCXfile(outname, FS_SYSTEM, in->mip[0].data, in->mip[0].width, in->mip[0].height, in->mip[0].width*bb, host_basepal, false))
|
||||
Con_Printf("%s(%s): Write failed\n", outname, Image_FormatName(in->encoding));
|
||||
}
|
||||
|
@ -1166,7 +1171,7 @@ static struct pendingtextureinfo *ImgTool_DecodeMiptex(struct opts_s *args, mipt
|
|||
struct pendingtextureinfo *out = Z_Malloc(sizeof(*out));
|
||||
qbyte *newdata = NULL;
|
||||
int neww=0, newh=0, sz;
|
||||
unsigned int bw,bh,bb;
|
||||
unsigned int bw,bh,bb,bd;
|
||||
out->type = PTI_2D;
|
||||
|
||||
out->encoding = PTI_INVALID;
|
||||
|
@ -1220,7 +1225,7 @@ static struct pendingtextureinfo *ImgTool_DecodeMiptex(struct opts_s *args, mipt
|
|||
if (out->encoding != PTI_INVALID) //use the first format we support, allowing prioritisation.
|
||||
continue;
|
||||
|
||||
Image_BlockSizeForEncoding(fmt, &bb, &bw, &bh);
|
||||
Image_BlockSizeForEncoding(fmt, &bb, &bw, &bh, &bd);
|
||||
w = data[ 8] | (data[ 9]<<8) | (data[10]<<16) | (data[11]<<24);
|
||||
h = data[12] | (data[13]<<8) | (data[14]<<16) | (data[15]<<24);
|
||||
for (csz = 16; w || h; w>>=1, h>>=1)
|
||||
|
@ -1243,7 +1248,7 @@ static struct pendingtextureinfo *ImgTool_DecodeMiptex(struct opts_s *args, mipt
|
|||
//only use our if there were no corrupt sections.
|
||||
if (data == dataend && newdata && neww && newh)
|
||||
{
|
||||
Image_BlockSizeForEncoding(out->encoding, &bb, &bw, &bh);
|
||||
Image_BlockSizeForEncoding(out->encoding, &bb, &bw, &bh, &bd);
|
||||
for (out->mipcount = 0; out->mipcount < countof(out->mip) && neww && newh; out->mipcount++, neww>>=1, newh>>=1)
|
||||
{
|
||||
neww = max(1, neww);
|
||||
|
@ -1254,6 +1259,7 @@ static struct pendingtextureinfo *ImgTool_DecodeMiptex(struct opts_s *args, mipt
|
|||
out->mip[out->mipcount].datasize = bb;
|
||||
out->mip[out->mipcount].datasize *= (out->mip[out->mipcount].width + bw-1)/bw;
|
||||
out->mip[out->mipcount].datasize *= (out->mip[out->mipcount].height + bh-1)/bh;
|
||||
out->mip[out->mipcount].datasize *= (out->mip[out->mipcount].depth + bd-1)/bd;
|
||||
out->mip[out->mipcount].data = newdata;
|
||||
newdata += out->mip[out->mipcount].datasize;
|
||||
}
|
||||
|
@ -1795,8 +1801,8 @@ static qboolean ImgTool_MipExport(struct opts_s *args, vfsfile_t *outfile, struc
|
|||
if (args->width && args->height && in->mipcount >= 1)
|
||||
{
|
||||
qbyte *newimg;
|
||||
unsigned int bb, bw, bh;
|
||||
Image_BlockSizeForEncoding(in->encoding, &bb, &bw, &bh);
|
||||
unsigned int bb, bw, bh, bd;
|
||||
Image_BlockSizeForEncoding(in->encoding, &bb, &bw, &bh, &bd);
|
||||
newimg = Image_ResampleTexture(in->encoding, in->mip[0].data, in->mip[0].width, in->mip[0].height, NULL, args->width, args->height);
|
||||
if (newimg)
|
||||
{
|
||||
|
@ -1807,7 +1813,8 @@ static qboolean ImgTool_MipExport(struct opts_s *args, vfsfile_t *outfile, struc
|
|||
in->mip[0].needfree = true;
|
||||
in->mip[0].width = args->width;
|
||||
in->mip[0].height = args->height;
|
||||
in->mip[0].datasize = bb*((in->mip[0].width+bw-1)/bw)*((in->mip[0].height+bh-1)/bh);
|
||||
in->mip[0].depth = 1;
|
||||
in->mip[0].datasize = bb*((in->mip[0].width+bw-1)/bw)*((in->mip[0].height+bh-1)/bh)*((in->mip[0].depth+bd-1)/bd);
|
||||
|
||||
Image_GenerateMips(in, args->flags);
|
||||
}
|
||||
|
@ -2172,18 +2179,18 @@ showhelp:
|
|||
Con_Printf("Supported compressed/interesting pixelformats are:\n");
|
||||
for (f = 0; f < PTI_MAX; f++)
|
||||
{
|
||||
int bb,bw,bh;
|
||||
Image_BlockSizeForEncoding(f, &bb,&bw,&bh);
|
||||
int bb,bw,bh,bd;
|
||||
Image_BlockSizeForEncoding(f, &bb,&bw,&bh,&bd);
|
||||
if (f >= PTI_ASTC_FIRST && f <= PTI_ASTC_LAST)
|
||||
{
|
||||
if (f >= PTI_ASTC_4X4_SRGB)
|
||||
continue;
|
||||
Con_Printf(" --%-16s %5.3g-bpp (requires astcenc)\n", Image_FormatName(f), 8*(float)bb/(bw*bh));
|
||||
Con_Printf(" --%-16s %5.3g-bpp (requires astcenc)\n", Image_FormatName(f), 8*(float)bb/(bw*bh*bd));
|
||||
}
|
||||
else if (f==PTI_BC1_RGB||f==PTI_BC1_RGBA||f==PTI_BC2_RGBA||f==PTI_BC3_RGBA||f==PTI_BC4_R||f==PTI_BC5_RG)
|
||||
Con_Printf(" --%-16s %5.3g-bpp (requires nvcompress)\n", Image_FormatName(f), 8*(float)bb/(bw*bh));
|
||||
Con_Printf(" --%-16s %5.3g-bpp (requires nvcompress)\n", Image_FormatName(f), 8*(float)bb/(bw*bh*bd));
|
||||
else if (f==PTI_BC6_RGB_UFLOAT || f==PTI_BC6_RGB_SFLOAT || f==PTI_BC7_RGBA)
|
||||
Con_Printf(" --%-16s %5.3g-bpp (requires nvcompress 2.1+)\n", Image_FormatName(f), 8*(float)bb/(bw*bh));
|
||||
Con_Printf(" --%-16s %5.3g-bpp (requires nvcompress 2.1+)\n", Image_FormatName(f), 8*(float)bb/(bw*bh*bd));
|
||||
else if ( f==PTI_RGBA16F ||
|
||||
f==PTI_RGBA32F ||
|
||||
f==PTI_E5BGR9 ||
|
||||
|
@ -2202,9 +2209,9 @@ showhelp:
|
|||
f==PTI_L8 ||
|
||||
f==PTI_L8A8 ||
|
||||
0)
|
||||
Con_Printf(" --%-16s %5.3g-bpp\n", Image_FormatName(f), 8*(float)bb/(bw*bh));
|
||||
Con_Printf(" --%-16s %5.3g-bpp\n", Image_FormatName(f), 8*(float)bb/(bw*bh*bd));
|
||||
// else
|
||||
// Con_DPrintf(" --%-16s %5.3g-bpp (unsupported)\n", Image_FormatName(f), 8*(float)bb/(bw*bh));
|
||||
// Con_DPrintf(" --%-16s %5.3g-bpp (unsupported)\n", Image_FormatName(f), 8*(float)bb/(bw*bh*bd));
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -28,13 +28,13 @@ struct avaudioctx
|
|||
|
||||
//output audio
|
||||
//we throw away data if the format changes. which is awkward, but gah.
|
||||
int64_t samples_start;
|
||||
int64_t samples_framestart;
|
||||
int samples_channels;
|
||||
int samples_speed;
|
||||
int samples_width;
|
||||
qaudiofmt_t samples_format;
|
||||
qbyte *samples_buffer;
|
||||
size_t samples_count;
|
||||
size_t samples_max;
|
||||
size_t samples_framecount;
|
||||
size_t samples_maxbytes;
|
||||
};
|
||||
|
||||
static void S_AV_Purge(sfx_t *s)
|
||||
|
@ -61,127 +61,213 @@ static void S_AV_Purge(sfx_t *s)
|
|||
activedecoders--;
|
||||
memset(&s->decoder, 0, sizeof(s->decoder));
|
||||
}
|
||||
#define QAF_U8 0x81
|
||||
#define QAF_S32 0x04
|
||||
#ifndef MIXER_F32
|
||||
#define QAF_F32 0x84
|
||||
#endif
|
||||
#define QAF_F64 0x88
|
||||
static void S_AV_ReadFrame(struct avaudioctx *ctx)
|
||||
{ //reads an audioframe and spits its data into the output sound file for the game engine to use.
|
||||
int width = 2;
|
||||
qaudiofmt_t outformat = QAF_S16, informat=QAF_S16;
|
||||
int channels = ctx->pACodecCtx->channels;
|
||||
int planes = 1, p;
|
||||
unsigned int auddatasize = av_samples_get_buffer_size(NULL, ctx->pACodecCtx->channels, ctx->pAFrame->nb_samples, ctx->pACodecCtx->sample_fmt, 1);
|
||||
void *auddata = ctx->pAFrame->data[0];
|
||||
switch(ctx->pACodecCtx->sample_fmt)
|
||||
{ //we don't support planar audio. we just treat it as mono instead.
|
||||
default:
|
||||
auddatasize = 0;
|
||||
break;
|
||||
case AV_SAMPLE_FMT_U8P:
|
||||
auddatasize /= channels;
|
||||
channels = 1;
|
||||
planes = channels;
|
||||
outformat = QAF_S8;
|
||||
informat = QAF_U8;
|
||||
break;
|
||||
case AV_SAMPLE_FMT_U8:
|
||||
width = 1;
|
||||
planes = 1;
|
||||
outformat = QAF_S8;
|
||||
informat = QAF_U8;
|
||||
break;
|
||||
case AV_SAMPLE_FMT_S16P:
|
||||
auddatasize /= channels;
|
||||
channels = 1;
|
||||
planes = channels;
|
||||
outformat = QAF_S16;
|
||||
informat = QAF_S16;
|
||||
break;
|
||||
case AV_SAMPLE_FMT_S16:
|
||||
width = 2;
|
||||
planes = 1;
|
||||
outformat = QAF_S16;
|
||||
informat = QAF_S16;
|
||||
break;
|
||||
|
||||
case AV_SAMPLE_FMT_S32P:
|
||||
planes = channels;
|
||||
outformat = QAF_S16;
|
||||
informat = QAF_S32;
|
||||
break;
|
||||
case AV_SAMPLE_FMT_S32:
|
||||
planes = 1;
|
||||
outformat = QAF_S16;
|
||||
informat = QAF_S32;
|
||||
break;
|
||||
|
||||
#ifdef MIXER_F32
|
||||
case AV_SAMPLE_FMT_FLTP:
|
||||
//FIXME: support float audio internally.
|
||||
{
|
||||
float *in[2] = {(float*)ctx->pAFrame->data[0],(float*)ctx->pAFrame->data[1]};
|
||||
signed short *out = (void*)auddata;
|
||||
int v;
|
||||
unsigned int i, c;
|
||||
unsigned int frames = ctx->pAFrame->nb_samples;
|
||||
if (channels > 2)
|
||||
channels = 2;
|
||||
for (i = 0; i < frames; i++)
|
||||
{
|
||||
for (c = 0; c < channels; c++)
|
||||
{
|
||||
v = (short)(in[c][i]*32767);
|
||||
if (v < -32767)
|
||||
v = -32767;
|
||||
else if (v > 32767)
|
||||
v = 32767;
|
||||
*out++ = v;
|
||||
}
|
||||
}
|
||||
width = sizeof(*out);
|
||||
auddatasize = frames*width*channels;
|
||||
}
|
||||
planes = channels;
|
||||
outformat = QAF_F32;
|
||||
informat = QAF_F32;
|
||||
break;
|
||||
case AV_SAMPLE_FMT_FLT:
|
||||
//FIXME: support float audio internally.
|
||||
{
|
||||
float *in = (void*)auddata;
|
||||
signed short *out = (void*)auddata;
|
||||
int v;
|
||||
unsigned int i;
|
||||
for (i = 0; i < auddatasize/sizeof(*in); i++)
|
||||
{
|
||||
v = (short)(in[i]*32767);
|
||||
if (v < -32767)
|
||||
v = -32767;
|
||||
else if (v > 32767)
|
||||
v = 32767;
|
||||
out[i] = v;
|
||||
}
|
||||
auddatasize/=2;
|
||||
width = 2;
|
||||
}
|
||||
planes = 1;
|
||||
outformat = QAF_F32;
|
||||
informat = QAF_F32;
|
||||
break;
|
||||
|
||||
case AV_SAMPLE_FMT_DBLP:
|
||||
auddatasize /= channels;
|
||||
channels = 1;
|
||||
case AV_SAMPLE_FMT_DBL:
|
||||
{
|
||||
double *in = (double*)auddata;
|
||||
signed short *out = (void*)auddata;
|
||||
int v;
|
||||
unsigned int i;
|
||||
for (i = 0; i < auddatasize/sizeof(*in); i++)
|
||||
{
|
||||
v = (short)(in[i]*32767);
|
||||
if (v < -32767)
|
||||
v = -32767;
|
||||
else if (v > 32767)
|
||||
v = 32767;
|
||||
out[i] = v;
|
||||
}
|
||||
auddatasize/=4;
|
||||
width = 2;
|
||||
}
|
||||
planes = channels;
|
||||
outformat = QAF_F32;
|
||||
informat = QAF_F64;
|
||||
break;
|
||||
case AV_SAMPLE_FMT_DBL:
|
||||
planes = 1;
|
||||
outformat = QAF_F32;
|
||||
informat = QAF_F64;
|
||||
break;
|
||||
#else
|
||||
case AV_SAMPLE_FMT_FLTP:
|
||||
planes = channels;
|
||||
outformat = QAF_S16;
|
||||
informat = QAF_F32;
|
||||
break;
|
||||
case AV_SAMPLE_FMT_FLT:
|
||||
planes = 1;
|
||||
outformat = QAF_S16;
|
||||
informat = QAF_F32;
|
||||
break;
|
||||
|
||||
case AV_SAMPLE_FMT_DBLP:
|
||||
planes = channels;
|
||||
outformat = QAF_S16;
|
||||
informat = QAF_F64;
|
||||
break;
|
||||
case AV_SAMPLE_FMT_DBL:
|
||||
planes = 1;
|
||||
outformat = QAF_S16;
|
||||
informat = QAF_F64;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
if (ctx->samples_channels != channels || ctx->samples_speed != ctx->pACodecCtx->sample_rate || ctx->samples_width != width)
|
||||
|
||||
if (ctx->samples_channels != channels || ctx->samples_speed != ctx->pACodecCtx->sample_rate || ctx->samples_format != outformat)
|
||||
{ //something changed, update
|
||||
ctx->samples_channels = channels;
|
||||
ctx->samples_speed = ctx->pACodecCtx->sample_rate;
|
||||
ctx->samples_width = width;
|
||||
ctx->samples_format = outformat;
|
||||
|
||||
//and discard any decoded audio. this might loose some.
|
||||
ctx->samples_start += ctx->samples_count;
|
||||
ctx->samples_count = 0;
|
||||
ctx->samples_framestart += ctx->samples_framecount;
|
||||
ctx->samples_framecount = 0;
|
||||
}
|
||||
if (ctx->samples_max < (ctx->samples_count*ctx->samples_width*ctx->samples_channels)+auddatasize)
|
||||
if (ctx->samples_maxbytes < (ctx->samples_framecount*QAF_BYTES(ctx->samples_format)*ctx->samples_channels)+auddatasize)
|
||||
{
|
||||
ctx->samples_max = (ctx->samples_count*ctx->samples_width*ctx->samples_channels)+auddatasize;
|
||||
ctx->samples_max *= 2; //slop
|
||||
ctx->samples_buffer = realloc(ctx->samples_buffer, ctx->samples_max);
|
||||
}
|
||||
if (width == 1)
|
||||
{ //FTE uses signed 8bit audio. ffmpeg uses unsigned 8bit audio. *sigh*.
|
||||
char *out = (char*)(ctx->samples_buffer + ctx->samples_count*(ctx->samples_width*ctx->samples_channels));
|
||||
unsigned char *in = auddata;
|
||||
int i;
|
||||
for (i = 0; i < auddatasize; i++)
|
||||
out[i] = in[i]-128;
|
||||
ctx->samples_maxbytes = (ctx->samples_framecount*QAF_BYTES(ctx->samples_format)*ctx->samples_channels)+auddatasize;
|
||||
ctx->samples_maxbytes *= 2; //slop
|
||||
ctx->samples_buffer = realloc(ctx->samples_buffer, ctx->samples_maxbytes);
|
||||
}
|
||||
if (planes==1 && outformat != QAF_S8 && informat==outformat)
|
||||
memcpy(ctx->samples_buffer + ctx->samples_framecount*(QAF_BYTES(ctx->samples_format)*ctx->samples_channels), ctx->pAFrame->data[0], auddatasize);
|
||||
else
|
||||
memcpy(ctx->samples_buffer + ctx->samples_count*(ctx->samples_width*ctx->samples_channels), auddata, auddatasize);
|
||||
ctx->samples_count += auddatasize/(ctx->samples_width*ctx->samples_channels);
|
||||
{
|
||||
void *fte_restrict outv = (ctx->samples_buffer + ctx->samples_framecount*(QAF_BYTES(ctx->samples_format)*ctx->samples_channels));
|
||||
size_t i, samples = auddatasize / (planes*QAF_BYTES(informat));
|
||||
if (outformat == QAF_S8 && informat == QAF_U8)
|
||||
{
|
||||
char *out = outv;
|
||||
for (p = 0; p < planes; p++, out++)
|
||||
{
|
||||
unsigned char *in = ctx->pAFrame->data[p];
|
||||
for (i = 0; i < samples; i++)
|
||||
out[i*planes] = in[i]-128; //convert from u8 to s8.
|
||||
}
|
||||
}
|
||||
else if (outformat == QAF_S16 && informat == QAF_S16)
|
||||
{
|
||||
signed short *out = outv;
|
||||
for (p = 0; p < planes; p++, out++)
|
||||
{
|
||||
signed short *in = (signed short *)ctx->pAFrame->data[p];
|
||||
for (i = 0; i < samples; i++)
|
||||
out[i*planes] = in[i]; //no conversion needed
|
||||
}
|
||||
}
|
||||
else if (outformat == QAF_S16 && informat == QAF_S32)
|
||||
{
|
||||
signed short *out = outv;
|
||||
for (p = 0; p < planes; p++, out++)
|
||||
{
|
||||
signed int *in = (signed int *)ctx->pAFrame->data[p];
|
||||
for (i = 0; i < samples; i++)
|
||||
out[i*planes] = in[i]>>16; //just use the MSBs, no clamping needed.
|
||||
}
|
||||
}
|
||||
#ifdef MIXER_F32
|
||||
else if (outformat == QAF_F32 && informat == QAF_F32)
|
||||
{
|
||||
float *out = outv;
|
||||
for (p = 0; p < planes; p++, out++)
|
||||
{
|
||||
float *in = (float *)ctx->pAFrame->data[p];
|
||||
for (i = 0; i < samples; i++)
|
||||
out[i*planes] = in[i]; //no conversion needed.
|
||||
}
|
||||
}
|
||||
else if (outformat == QAF_F32 && informat == QAF_F64)
|
||||
{
|
||||
float *out = outv;
|
||||
for (p = 0; p < planes; p++, out++)
|
||||
{
|
||||
double *in = (double *)ctx->pAFrame->data[p];
|
||||
for (i = 0; i < samples; i++)
|
||||
out[i*planes] = in[i]; //no clamping needed.
|
||||
}
|
||||
}
|
||||
#else
|
||||
else if (outformat == QAF_S16 && informat == QAF_F32)
|
||||
{
|
||||
signed short *out = outv;
|
||||
for (p = 0; p < planes; p++, out++)
|
||||
{
|
||||
float *in = (float *)ctx->pAFrame->data[p];
|
||||
for (i = 0; i < samples; i++)
|
||||
{
|
||||
int v = in[i] * 32767;
|
||||
if (v < -32768)
|
||||
v = -32768;
|
||||
if (v > 32767)
|
||||
v = 32767;
|
||||
out[i*planes] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (outformat == QAF_S16 && informat == QAF_F64)
|
||||
{
|
||||
signed short *out = outv;
|
||||
for (p = 0; p < planes; p++, out++)
|
||||
{
|
||||
double *in = (double *)ctx->pAFrame->data[p];
|
||||
for (i = 0; i < samples; i++)
|
||||
{
|
||||
int v = in[i] * 32767;
|
||||
if (v < -32768)
|
||||
v = -32768;
|
||||
if (v > 32767)
|
||||
v = 32767;
|
||||
out[i*planes] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
ctx->samples_framecount += auddatasize/(QAF_BYTES(informat)*ctx->samples_channels);
|
||||
}
|
||||
static sfxcache_t *S_AV_Locate(sfx_t *sfx, sfxcache_t *buf, ssamplepos_t start, int length)
|
||||
{ //warning: can be called on a different thread.
|
||||
|
@ -196,10 +282,10 @@ static sfxcache_t *S_AV_Locate(sfx_t *sfx, sfxcache_t *buf, ssamplepos_t start,
|
|||
|
||||
while (1)
|
||||
{
|
||||
if (start < ctx->samples_start)
|
||||
if (start < ctx->samples_framestart)
|
||||
break; //o.O rewind!
|
||||
|
||||
if (ctx->samples_start+ctx->samples_count > curtime)
|
||||
if (ctx->samples_framestart+ctx->samples_framecount > curtime)
|
||||
break; //no need yet.
|
||||
|
||||
#ifdef HAVE_DECOUPLED_API
|
||||
|
@ -242,11 +328,11 @@ static sfxcache_t *S_AV_Locate(sfx_t *sfx, sfxcache_t *buf, ssamplepos_t start,
|
|||
av_packet_unref(&packet);
|
||||
}
|
||||
|
||||
buf->length = ctx->samples_count;
|
||||
buf->length = ctx->samples_framecount;
|
||||
buf->speed = ctx->samples_speed;
|
||||
buf->width = ctx->samples_width;
|
||||
buf->format = ctx->samples_format;
|
||||
buf->numchannels = ctx->samples_channels;
|
||||
buf->soundoffset = ctx->samples_start;
|
||||
buf->soundoffset = ctx->samples_framestart;
|
||||
buf->data = ctx->samples_buffer;
|
||||
|
||||
//if we couldn't return any new data, then we're at an eof, return NULL to signal that.
|
||||
|
@ -267,7 +353,7 @@ static float S_AV_Query(struct sfx_s *sfx, struct sfxcache_s *buf, char *title,
|
|||
buf->length = 0;
|
||||
buf->numchannels = ctx->samples_channels;
|
||||
buf->speed = ctx->samples_speed;
|
||||
buf->width = ctx->samples_width;
|
||||
buf->format = ctx->samples_format;
|
||||
}
|
||||
return ctx->pFormatCtx->duration / (float)AV_TIME_BASE;
|
||||
}
|
||||
|
|
|
@ -232,7 +232,7 @@ void Mod_ExportIQM(char *fname, int flags, galiasinfo_t *mesh)
|
|||
{ //pos3, quat4, scale3
|
||||
float posquatscale[10]; //raw values, used to calibrate ranges
|
||||
} *posedata = NULL, *pd; //per bone*joint
|
||||
avec4_t *ivert;
|
||||
vecV_t *ivert;
|
||||
vec2_t *ist;
|
||||
vec3_t *overt;
|
||||
vec3_t *onorm = NULL;
|
||||
|
|
|
@ -16,7 +16,10 @@ vector mousefar;
|
|||
|
||||
float releasedmouse;
|
||||
|
||||
//#define WALLBROWSERS
|
||||
#ifdef WALLBROWSERS
|
||||
string pointedshadername;
|
||||
#endif
|
||||
vector pointedsurfacenormal;
|
||||
entity pointedent;
|
||||
float pointedsurface;
|
||||
|
@ -73,7 +76,7 @@ void(vector mouse) editor_options_overlay =
|
|||
else
|
||||
txt = strcat(txt, " (OFF)");
|
||||
}
|
||||
drawstring(pos, txt, '8 8', (sel==i)?'0 0 1':'1 1 1', 1, 0);
|
||||
drawstring(pos, txt, '8 8', (sel==i)?'0 0 1' :'1 1 1', 1, 0);
|
||||
pos_y += 8;
|
||||
}
|
||||
};
|
||||
|
@ -382,6 +385,7 @@ float (float event, float parama, float paramb) wrap_InputEvent =
|
|||
return TRUE;
|
||||
}
|
||||
}
|
||||
#ifdef WALLBROWSERS
|
||||
else if (pointedshadername != "")
|
||||
{
|
||||
/* if (parama == K_MOUSE2)
|
||||
|
@ -399,6 +403,7 @@ float (float event, float parama, float paramb) wrap_InputEvent =
|
|||
return TRUE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (orig_input_event)
|
||||
return orig_input_event(event, parama, paramb);
|
||||
|
@ -484,6 +489,7 @@ void() CSQC_Input_Frame =
|
|||
if (autocvar_ca_show) //when we're using the UI, don't send any attack or jump stuff. these are generally annoying modifiers or so
|
||||
input_buttons = 0;
|
||||
|
||||
#ifdef WALLBROWSERS
|
||||
if ((input_buttons & 1) && pointedshadername == "")
|
||||
{
|
||||
t = mousefar;
|
||||
|
@ -584,6 +590,7 @@ void() CSQC_Input_Frame =
|
|||
// pointparticles(particleeffectnum("te_spike"), xyz1 + dir1*f1 + dir2*f2, trace_plane_normal, 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue