1
0
Fork 0
forked from fte/fteqw

fix server crash (on two pk3s with the same pure path)

fix fteqcc issue unintentionally stripping things
added model event support.
added support for a couple of extra twiddles in the iqm format.
modelviewer now highlights meshes (to display hitmesh areas).
modelviewer now shows ragdolls, because I can.
fixed some nq download issues/crashes/fallbacks.
fixed 8bit bmp palette issue.
added capturethrottlesize cvar to throttle recording speed if disk space is getting low (to avoid Maverick's demo encoder getting swamped).
com_protocolname can now list multiple protocol names to list multiple server types. only the first will be reported to other clients however.
can now be compiled without support for q1bsp or q1mdl. not useful, but hey.
increase max_channels, by as much as is necessary.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5038 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2017-01-13 00:39:50 +00:00
parent cd75caeb27
commit c4ded89ad7
53 changed files with 2749 additions and 1325 deletions

View file

@ -47,6 +47,8 @@ extern cvar_t gl_simpleitems;
extern cvar_t cl_gibfilter, cl_deadbodyfilter; extern cvar_t cl_gibfilter, cl_deadbodyfilter;
extern int cl_playerindex; extern int cl_playerindex;
extern world_t csqc_world;
static struct predicted_player static struct predicted_player
{ {
int flags; int flags;
@ -3126,6 +3128,13 @@ static void CL_UpdateNetFrameLerpState(qboolean force, int curframe, int curbase
} }
le->newframe[fst] = frame; le->newframe[fst] = frame;
le->newframestarttime[fst] = cl.servertime; le->newframestarttime[fst] = cl.servertime;
// if (force)
// {
// //if its new, we need to tweak the age of the animation. looping anims won't appear any different, while non-looping ones will clamp to the last pose of the animation when its new.
// le->oldframestarttime[fst] -= Mod_GetFrameDuration(le->model, 0, le->oldframe[fst]);
// le->newframestarttime[fst] -= Mod_GetFrameDuration(le->model, 0, le->newframe[fst]);
// }
} }
} }
} }
@ -4075,7 +4084,7 @@ void CL_LinkPacketEntities (void)
#ifdef RAGDOLL #ifdef RAGDOLL
if (model && (model->dollinfo || le->skeletalobject)) if (model && (model->dollinfo || le->skeletalobject))
rag_updatedeltaent(ent, le); rag_updatedeltaent(&csqc_world, ent, le);
#endif #endif
ent->framestate.g[FS_REG].frame[0] &= ~0x8000; ent->framestate.g[FS_REG].frame[0] &= ~0x8000;
ent->framestate.g[FS_REG].frame[1] &= ~0x8000; ent->framestate.g[FS_REG].frame[1] &= ~0x8000;

View file

@ -35,7 +35,7 @@ void QDECL Name_Callback(struct cvar_s *var, char *oldvalue);
#define Name_Callback NULL #define Name_Callback NULL
#endif #endif
void CL_ForceStopDownload (qdownload_t *dl, qboolean finish); static void CL_ForceStopDownload (qboolean finish);
// we need to declare some mouse variables here, because the menu system // we need to declare some mouse variables here, because the menu system
// references them even when on a unix system. // references them even when on a unix system.
@ -160,7 +160,7 @@ cvar_t cl_sendguid = CVARD("cl_sendguid", "0", "Send a randomly generated 'gl
cvar_t cl_downloads = CVARFD("cl_downloads", "1", CVAR_NOTFROMSERVER, "Allows you to block all automatic downloads."); cvar_t cl_downloads = CVARFD("cl_downloads", "1", CVAR_NOTFROMSERVER, "Allows you to block all automatic downloads.");
cvar_t cl_download_csprogs = CVARFD("cl_download_csprogs", "1", CVAR_NOTFROMSERVER, "Download updated client gamecode if available. Warning: If you clear this to avoid downloading vm code, you should also clear cl_download_packages."); cvar_t cl_download_csprogs = CVARFD("cl_download_csprogs", "1", CVAR_NOTFROMSERVER, "Download updated client gamecode if available. Warning: If you clear this to avoid downloading vm code, you should also clear cl_download_packages.");
cvar_t cl_download_redirection = CVARFD("cl_download_redirection", "2", CVAR_NOTFROMSERVER, "Follow download redirection to download packages instead of individual files. Also allows the server to send nearly arbitary download commands.\n2: allows redirection only to named packages files (and demos/*.mvd), which is a bit safer."); cvar_t cl_download_redirection = CVARFD("cl_download_redirection", "2", CVAR_NOTFROMSERVER, "Follow download redirection to download packages instead of individual files. Also allows the server to send nearly arbitary download commands.\n2: allows redirection only to named packages files (and demos/*.mvd), which is a bit safer.");
cvar_t cl_download_mapsrc = CVARD("cl_download_mapsrc", "", "Specifies an http location prefix for map downloads. EG: \"http://bigfoot.morphos-team.net/misc/quakemaps/\""); cvar_t cl_download_mapsrc = CVARFD("cl_download_mapsrc", "", CVAR_ARCHIVE, "Specifies an http location prefix for map downloads. EG: \"http://bigfoot.morphos-team.net/misc/quakemaps/\"");
cvar_t cl_download_packages = CVARFD("cl_download_packages", "1", CVAR_NOTFROMSERVER, "0=Do not download packages simply because the server is using them. 1=Download and load packages as needed (does not affect games which do not use this package). 2=Do download and install permanently (use with caution!)"); cvar_t cl_download_packages = CVARFD("cl_download_packages", "1", CVAR_NOTFROMSERVER, "0=Do not download packages simply because the server is using them. 1=Download and load packages as needed (does not affect games which do not use this package). 2=Do download and install permanently (use with caution!)");
cvar_t requiredownloads = CVARFD("requiredownloads","1", CVAR_ARCHIVE, "0=join the game before downloads have even finished (might be laggy). 1=wait for all downloads to complete before joining."); cvar_t requiredownloads = CVARFD("requiredownloads","1", CVAR_ARCHIVE, "0=join the game before downloads have even finished (might be laggy). 1=wait for all downloads to complete before joining.");
@ -3684,8 +3684,9 @@ void CL_DownloadSize_f(void)
} }
void CL_FinishDownload(char *filename, char *tempname); void CL_FinishDownload(char *filename, char *tempname);
void CL_ForceStopDownload (qdownload_t *dl, qboolean finish) static void CL_ForceStopDownload (qboolean finish)
{ {
qdownload_t *dl = cls.download;
if (Cmd_IsInsecure()) if (Cmd_IsInsecure())
{ {
Con_Printf(CON_WARNING "Execution from server rejected for %s\n", Cmd_Argv(0)); Con_Printf(CON_WARNING "Execution from server rejected for %s\n", Cmd_Argv(0));
@ -3713,15 +3714,13 @@ void CL_ForceStopDownload (qdownload_t *dl, qboolean finish)
// get another file if needed // get another file if needed
CL_RequestNextDownload (); CL_RequestNextDownload ();
} }
void CL_SkipDownload_f (void) void CL_SkipDownload_f (void)
{ {
CL_ForceStopDownload(cls.download, false); CL_ForceStopDownload(false);
} }
void CL_FinishDownload_f (void) void CL_FinishDownload_f (void)
{ {
CL_ForceStopDownload(cls.download, true); CL_ForceStopDownload(true);
} }
#if defined(_WIN32) && !defined(WINRT) #if defined(_WIN32) && !defined(WINRT)
@ -5795,13 +5794,15 @@ void Host_Shutdown(void)
HTTP_CL_Terminate(); HTTP_CL_Terminate();
#endif #endif
//disconnect server/client/etc
CL_Disconnect_f();
M_Shutdown(true);
#ifdef PLUGINS #ifdef PLUGINS
Plug_Shutdown(false); Plug_Shutdown(false);
#endif #endif
//disconnect server/client/etc
CL_Disconnect_f();
#ifdef CSQC_DAT #ifdef CSQC_DAT
CSQC_Shutdown(); CSQC_Shutdown();
#endif #endif
@ -5821,7 +5822,6 @@ void Host_Shutdown(void)
#endif #endif
CL_FreeDlights(); CL_FreeDlights();
CL_FreeVisEdicts(); CL_FreeVisEdicts();
M_Shutdown(true);
Mod_Shutdown(true); Mod_Shutdown(true);
Wads_Flush(); Wads_Flush();
Con_History_Save(); //do this outside of the console code so that the filesystem is still running at this point but still allowing the filesystem to make console prints (you might not see them, but they should be visible to sys_printf still, for debugging). Con_History_Save(); //do this outside of the console code so that the filesystem is still running at this point but still allowing the filesystem to make console prints (you might not see them, but they should be visible to sys_printf still, for debugging).

View file

@ -680,7 +680,11 @@ void CL_DisenqueDownload(char *filename)
void CL_WebDownloadFinished(struct dl_download *dl) void CL_WebDownloadFinished(struct dl_download *dl)
{ {
if (dl->status == DL_FAILED) if (dl->status == DL_FAILED)
{
CL_DownloadFailed(dl->url, &dl->qdownload); CL_DownloadFailed(dl->url, &dl->qdownload);
if (dl->qdownload.flags & DLLF_ALLOWWEB) //re-enqueue it if allowed, but this time not from the web server.
CL_EnqueDownload(dl->qdownload.localname, dl->qdownload.localname, dl->qdownload.flags & ~DLLF_ALLOWWEB);
}
else if (dl->status == DL_FINISHED) else if (dl->status == DL_FINISHED)
{ {
if (dl->file) if (dl->file)
@ -697,9 +701,17 @@ void CL_SendDownloadStartRequest(char *filename, char *localname, unsigned int f
qdownload_t *dl; qdownload_t *dl;
#ifdef WEBCLIENT #ifdef WEBCLIENT
if (!strncmp(filename, "http://", 7)) if (!strncmp(filename, "http://", 7) || !strncmp(filename, "https://", 8))
{ {
if (!HTTP_CL_Get(filename, localname, CL_WebDownloadFinished)) struct dl_download *wdl = HTTP_CL_Get(filename, localname, CL_WebDownloadFinished);
if (wdl)
{
if (!(flags & DLLF_TEMPORARY))
Con_TPrintf ("Downloading %s to %s...\n", wdl->url, wdl->localname);
wdl->qdownload.flags = flags;
cls.download = &wdl->qdownload;
}
else
CL_DownloadFailed(filename, NULL); CL_DownloadFailed(filename, NULL);
return; return;
} }
@ -898,13 +910,22 @@ qboolean CL_CheckOrEnqueDownloadFile (const char *filename, const char *localnam
SCR_EndLoadingPlaque(); //release console. SCR_EndLoadingPlaque(); //release console.
if (*cl_download_mapsrc.string) if (flags & DLLF_ALLOWWEB)
if (!strncmp(filename, "maps/", 5))
if (!strcmp(filename + strlen(filename)-4, ".bsp"))
{ {
char base[MAX_QPATH]; flags &= ~DLLF_ALLOWWEB;
COM_FileBase(filename, base, sizeof(base)); if (*cl_download_mapsrc.string)
filename = va("%s%s.bsp", cl_download_mapsrc.string, base); if (!strcmp(filename, localname))
if (!strncmp(filename, "maps/", 5))
if (!strcmp(filename + strlen(filename)-4, ".bsp"))
{
char base[MAX_QPATH];
COM_FileBase(filename, base, sizeof(base));
if (!strncmp(cl_download_mapsrc.string, "http://", 7) || !strncmp(cl_download_mapsrc.string, "https://", 8))
filename = va("%s%s.bsp", cl_download_mapsrc.string, base);
else
filename = va("http://%s/%s.bsp", cl_download_mapsrc.string, base);
flags |= DLLF_ALLOWWEB;
}
} }
if (!CL_EnqueDownload(filename, localname, flags)) if (!CL_EnqueDownload(filename, localname, flags))
@ -2310,6 +2331,7 @@ void DL_Abort(qdownload_t *dl, enum qdlabort aborttype)
if (dl->flags & DLLF_BEGUN) if (dl->flags & DLLF_BEGUN)
{ {
dl->flags &= ~DLLF_BEGUN;
if (aborttype == QDL_COMPLETED) if (aborttype == QDL_COMPLETED)
{ {
//this file isn't needed now the download has finished. //this file isn't needed now the download has finished.
@ -2414,7 +2436,8 @@ void DL_Abort(qdownload_t *dl, enum qdlabort aborttype)
} }
dl->dlblocks = NULL; dl->dlblocks = NULL;
Z_Free(dl); if (dl->method != DL_HTTP)
Z_Free(dl);
if (cls.download == dl) if (cls.download == dl)
cls.download = NULL; cls.download = NULL;
} }
@ -2654,6 +2677,8 @@ void CLDP_ParseDownloadBegin(char *s)
return; return;
} }
if (dl->method == DL_QWPENDING)
dl->method = DL_DARKPLACES;
if (dl->method != DL_DARKPLACES) if (dl->method != DL_DARKPLACES)
{ {
Con_Printf("Warning: download method isn't right.\n"); Con_Printf("Warning: download method isn't right.\n");
@ -3571,7 +3596,7 @@ void CLNQ_ParseServerData(void) //Doesn't change gamedir - use with caution.
} }
strcpy (cl.model_name[nummodels], str); strcpy (cl.model_name[nummodels], str);
if (*str != '*' && strcmp(str, "null")) //not inline models! if (*str != '*' && strcmp(str, "null")) //not inline models!
CL_CheckOrEnqueDownloadFile(str, NULL, ((nummodels==1)?DLLF_REQUIRED:0)); CL_CheckOrEnqueDownloadFile(str, NULL, ((nummodels==1)?DLLF_REQUIRED|DLLF_ALLOWWEB:0));
Mod_TouchModel (str); Mod_TouchModel (str);
} }

View file

@ -550,6 +550,7 @@ typedef struct downloadlist_s {
#define DLLF_USEREXPLICIT (1u<<7) //use explicitly requested it, ignore the cl_downloads cvar. #define DLLF_USEREXPLICIT (1u<<7) //use explicitly requested it, ignore the cl_downloads cvar.
#define DLLF_BEGUN (1u<<8) //server has confirmed that the file exists, is readable, and we've opened a file. should not be set on new requests. #define DLLF_BEGUN (1u<<8) //server has confirmed that the file exists, is readable, and we've opened a file. should not be set on new requests.
#define DLLF_ALLOWWEB (1u<<9) //failed http downloads should retry but from the game server itself
struct downloadlist_s *next; struct downloadlist_s *next;
} downloadlist_t; } downloadlist_t;

View file

@ -1623,11 +1623,6 @@ void Con_PrintToSys(void)
//returns the bottom of the progress bar //returns the bottom of the progress bar
static int Con_DrawProgress(int left, int right, int y) static int Con_DrawProgress(int left, int right, int y)
{ {
#ifdef RUNTIMELIGHTING
extern model_t *lightmodel;
extern long relitsurface;
#endif
conchar_t dlbar[1024], *chr; conchar_t dlbar[1024], *chr;
unsigned char progresspercenttext[128]; unsigned char progresspercenttext[128];
char *progresstext = NULL; char *progresstext = NULL;

View file

@ -2108,7 +2108,7 @@ qbyte *ReadBMPFile(qbyte *buf, int length, int *width, int *height)
for (i = 0; i < h.NumofColorIndices; i++) for (i = 0; i < h.NumofColorIndices; i++)
{ {
pal[i] = data[i*4+0] + (data[i*4+1]<<8) + (data[i*4+2]<<16) + (255/*data[i*4+3]*/<<16); pal[i] = data[i*4+2] + (data[i*4+1]<<8) + (data[i*4+0]<<16) + (255/*data[i*4+3]*/<<24);
} }
buf += h.OffsetofBMPBits; buf += h.OffsetofBMPBits;
@ -4436,6 +4436,7 @@ static void Image_LoadHiResTextureWorker(void *ctx, void *data, size_t a, size_t
int firstex = (tex->flags & IF_EXACTEXTENSION)?tex_extensions_count-1:0; int firstex = (tex->flags & IF_EXACTEXTENSION)?tex_extensions_count-1:0;
char *altname; char *altname;
char *nextalt; char *nextalt;
qboolean exactext = !!(tex->flags & IF_EXACTEXTENSION);
// Sys_Sleep(0.3); // Sys_Sleep(0.3);
@ -4453,18 +4454,26 @@ static void Image_LoadHiResTextureWorker(void *ctx, void *data, size_t a, size_t
} }
//see if we recognise the extension, and only strip it if we do. //see if we recognise the extension, and only strip it if we do.
COM_FileExtension(altname, nicename, sizeof(nicename)); if (exactext)
e = 0; e = tex_extensions_count;
if (strcmp(nicename, "lmp") && strcmp(nicename, "wal")) else
for (; e < tex_extensions_count; e++) {
{ COM_FileExtension(altname, nicename, sizeof(nicename));
if (!strcmp(nicename, (*tex_extensions[e].name=='.')?tex_extensions[e].name+1:tex_extensions[e].name)) e = 0;
break; if (strcmp(nicename, "lmp") && strcmp(nicename, "wal"))
} for (; e < tex_extensions_count; e++)
{
if (!strcmp(nicename, (*tex_extensions[e].name=='.')?tex_extensions[e].name+1:tex_extensions[e].name))
break;
}
}
//strip it and try replacements if we do, otherwise assume that we're meant to be loading progs/foo.mdl_0.tga or whatever //strip it and try replacements if we do, otherwise assume that we're meant to be loading progs/foo.mdl_0.tga or whatever
if (e == tex_extensions_count || (tex->flags & IF_EXACTEXTENSION)) if (e == tex_extensions_count || exactext)
{
exactext = true;
Q_strncpyz(nicename, altname, sizeof(nicename)); Q_strncpyz(nicename, altname, sizeof(nicename));
}
else else
COM_StripExtension(altname, nicename, sizeof(nicename)); COM_StripExtension(altname, nicename, sizeof(nicename));
@ -4511,7 +4520,7 @@ static void Image_LoadHiResTextureWorker(void *ctx, void *data, size_t a, size_t
s = COM_SkipPath(nicename); s = COM_SkipPath(nicename);
n = basename; n = basename;
while (*s && *s != '.' && n < basename+sizeof(basename)-5) while (*s && (*s != '.'||exactext) && n < basename+sizeof(basename)-5)
*n++ = *s++; *n++ = *s++;
s = strchr(s, '_'); s = strchr(s, '_');
if (s) if (s)

View file

@ -16,6 +16,14 @@
#define WINAVI #define WINAVI
#endif #endif
#if defined(__linux__) && !defined(ANDROID)
//should really include posix 2001 systems in general
#define HAVE_STATVFS
#endif
#ifdef HAVE_STATVFS
#include <sys/statvfs.h>
#endif
typedef struct mediatrack_s{ typedef struct mediatrack_s{
char filename[MAX_QPATH]; char filename[MAX_QPATH];
@ -2737,13 +2745,21 @@ int captureoldfbo;
qboolean capturingfbo; qboolean capturingfbo;
texid_t capturetexture; texid_t capturetexture;
qboolean captureframeforce; qboolean captureframeforce;
#if defined(GLQUAKE) && !defined(GLESONLY) #if defined(GLQUAKE) && !defined(GLESONLY)
//ring buffer #define GLQUAKE_PBOS
int pbo_handles[4];
enum uploadfmt pbo_format;
#define CAN_USE_PBOS
#endif #endif
int pbo_oldest; struct
{
#ifdef GLQUAKE_PBOS
int pbo_handle;
#endif
enum uploadfmt format;
int width;
int height;
} offscreen_queue[4]; //ringbuffer of offscreen_captureframe...captureframe
int offscreen_captureframe;
enum uploadfmt offscreen_format;
#define CAPTURECODECDESC_DEFAULT "tga" #define CAPTURECODECDESC_DEFAULT "tga"
#ifdef WINAVI #ifdef WINAVI
@ -2765,6 +2781,7 @@ cvar_t capturesound = CVARD("capturesound", "1", "Enables the capturing of game
cvar_t capturesoundchannels = CVAR("capturesoundchannels", "2"); cvar_t capturesoundchannels = CVAR("capturesoundchannels", "2");
cvar_t capturesoundbits = CVAR("capturesoundbits", "16"); cvar_t capturesoundbits = CVAR("capturesoundbits", "16");
cvar_t capturemessage = CVAR("capturemessage", ""); cvar_t capturemessage = CVAR("capturemessage", "");
cvar_t capturethrottlesize = CVARD("capturethrottlesize", "0", "If set, capturing will slow down significantly if there is less disk space available than this cvar (in mb). This is useful when recording a stream to (ram)disk while another program is simultaneously consuming frames.");
qboolean recordingdemo; qboolean recordingdemo;
media_encoder_funcs_t *currentcapture_funcs; media_encoder_funcs_t *currentcapture_funcs;
@ -2834,6 +2851,34 @@ static void QDECL capture_raw_video (void *vctx, void *data, int frame, int widt
ctx->frames = frame+1; ctx->frames = frame+1;
Q_snprintfz(filename, sizeof(filename), "%s%8.8i.%s", ctx->videonameprefix, frame, ctx->videonameextension); Q_snprintfz(filename, sizeof(filename), "%s%8.8i.%s", ctx->videonameprefix, frame, ctx->videonameextension);
SCR_ScreenShot(filename, ctx->fsroot, &data, 1, width, height, fmt); SCR_ScreenShot(filename, ctx->fsroot, &data, 1, width, height, fmt);
if (capturethrottlesize.ival)
{
char base[MAX_QPATH];
Q_strncpyz(base, ctx->videonameprefix, sizeof(base));
*COM_SkipPath(base) = 0;
if (FS_NativePath(base, FS_GAMEONLY, filename, sizeof(filename)))
{
#if HAVE_STATVFS
//posix 2001
struct statvfs inf;
if(0==statvfs(filename, &inf))
{
if (inf.f_frsize*(double)inf.f_blocks < (1024.*1024)*capturethrottlesize.value)
Sys_Sleep(1);
}
#elif defined( _WIN32)
wchar_t ffs[MAX_OSPATH];
ULARGE_INTEGER freebytes;
if (GetDiskFreeSpaceExW(widen(ffs, sizeof(ffs), filename), &freebytes, NULL, NULL))
if (freebytes.QuadPart < (ULONGLONG)(1024*1024)*capturethrottlesize.value)
Sys_Sleep(1);
#else
Con_Printf("capturethrottlesize is unsupported in this build\n");
capturethrottlesize.ival = 0;
#endif
}
}
} }
static void QDECL capture_raw_audio (void *vctx, void *data, int bytes) static void QDECL capture_raw_audio (void *vctx, void *data, int bytes)
{ {
@ -2882,10 +2927,10 @@ static void QDECL capture_avi_end(void *vctx)
{ {
struct capture_avi_ctx *ctx = vctx; struct capture_avi_ctx *ctx = vctx;
if (ctx->uncompressed_video_stream) qAVIStreamRelease(ctx->uncompressed_video_stream); if (ctx->uncompressed_video_stream) qAVIStreamRelease(ctx->uncompressed_video_stream);
if (ctx->compressed_video_stream) qAVIStreamRelease(ctx->compressed_video_stream); if (ctx->compressed_video_stream) qAVIStreamRelease(ctx->compressed_video_stream);
if (ctx->uncompressed_audio_stream) qAVIStreamRelease(ctx->uncompressed_audio_stream); if (ctx->uncompressed_audio_stream) qAVIStreamRelease(ctx->uncompressed_audio_stream);
if (ctx->file) qAVIFileRelease(ctx->file); if (ctx->file) qAVIFileRelease(ctx->file);
Z_Free(ctx); Z_Free(ctx);
} }
@ -3230,7 +3275,7 @@ void Media_RecordFrame (void)
y = vid.height-8; y = vid.height-8;
#ifdef GLQUAKE #ifdef GLQUAKE
if (capturingfbo) if (capturingfbo && qrenderer == QR_OPENGL)
{ {
shader_t *pic; shader_t *pic;
GLBE_FBO_Pop(captureoldfbo); GLBE_FBO_Pop(captureoldfbo);
@ -3301,56 +3346,69 @@ void Media_RecordFrame (void)
if (R2D_Flush) if (R2D_Flush)
R2D_Flush(); R2D_Flush();
#ifdef CAN_USE_PBOS #ifdef GLQUAKE_PBOS
if (pbo_format != TF_INVALID) if (offscreen_format != TF_INVALID && qrenderer == QR_OPENGL)
{ {
int imagesize = vid.fbpwidth * vid.fbpheight; int frame;
switch(pbo_format) //encode the frame if we're about to stomp on it
while (offscreen_captureframe + countof(offscreen_queue) <= captureframe)
{ {
case TF_BGR24: frame = offscreen_captureframe%countof(offscreen_queue);
case TF_RGB24: qglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, offscreen_queue[frame].pbo_handle);
imagesize *= 3;
break;
case TF_BGRA32:
case TF_RGBA32:
imagesize *= 4;
break;
default:
break;
}
while (pbo_oldest + countof(pbo_handles) <= captureframe)
{
qglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pbo_handles[pbo_oldest%countof(pbo_handles)]);
buffer = qglMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB); buffer = qglMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
if (buffer) if (buffer)
{ {
//FIXME: thread these (with audio too, to avoid races) //FIXME: thread these (with audio too, to avoid races)
currentcapture_funcs->capture_video(currentcapture_ctx, buffer, pbo_oldest, vid.fbpwidth, vid.fbpheight, pbo_format); currentcapture_funcs->capture_video(currentcapture_ctx, buffer, offscreen_captureframe, offscreen_queue[frame].width, offscreen_queue[frame].height, offscreen_queue[frame].format);
qglUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); qglUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
} }
pbo_oldest++; offscreen_captureframe++;
} }
if (!pbo_handles[captureframe%countof(pbo_handles)]) frame = captureframe%countof(offscreen_queue);
//if we have no pbo yet, create one.
if (!offscreen_queue[frame].pbo_handle)
{ {
qglGenBuffersARB(1, &pbo_handles[captureframe%countof(pbo_handles)]); int imagesize = 0;
qglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pbo_handles[captureframe%countof(pbo_handles)]); offscreen_queue[frame].format = offscreen_format;
offscreen_queue[frame].width = vid.pixelwidth;
offscreen_queue[frame].height = vid.pixelheight;
switch(offscreen_queue[frame].format)
{
case TF_BGR24:
case TF_RGB24:
imagesize = 3;
break;
case TF_BGRA32:
case TF_RGBA32:
imagesize = 4;
break;
default:
break;
}
imagesize *= offscreen_queue[frame].width * offscreen_queue[frame].height;
qglGenBuffersARB(1, &offscreen_queue[frame].pbo_handle);
qglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, offscreen_queue[frame].pbo_handle);
qglBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, imagesize, NULL, GL_STATIC_READ_ARB); qglBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, imagesize, NULL, GL_STATIC_READ_ARB);
} }
qglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pbo_handles[captureframe%countof(pbo_handles)]);
switch(pbo_format) //get the gpu to copy the texture into the pbo. the driver should pipeline this read until we actually map the pbo, hopefully avoiding stalls
qglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, offscreen_queue[frame].pbo_handle);
switch(offscreen_queue[frame].format)
{ {
case TF_BGR24: case TF_BGR24:
qglReadPixels(0, 0, vid.fbpwidth, vid.fbpheight, GL_BGR_EXT, GL_UNSIGNED_BYTE, 0); qglReadPixels(0, 0, offscreen_queue[frame].width, offscreen_queue[frame].height, GL_BGR_EXT, GL_UNSIGNED_BYTE, 0);
break; break;
case TF_BGRA32: case TF_BGRA32:
qglReadPixels(0, 0, vid.fbpwidth, vid.fbpheight, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, 0); qglReadPixels(0, 0, offscreen_queue[frame].width, offscreen_queue[frame].height, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, 0);
break; break;
case TF_RGB24: case TF_RGB24:
qglReadPixels(0, 0, vid.fbpwidth, vid.fbpheight, GL_RGB, GL_UNSIGNED_BYTE, 0); qglReadPixels(0, 0, offscreen_queue[frame].width, offscreen_queue[frame].height, GL_RGB, GL_UNSIGNED_BYTE, 0);
break; break;
case TF_RGBA32: case TF_RGBA32:
qglReadPixels(0, 0, vid.fbpwidth, vid.fbpheight, GL_RGBA, GL_UNSIGNED_BYTE, 0); qglReadPixels(0, 0, offscreen_queue[frame].width, offscreen_queue[frame].height, GL_RGBA, GL_UNSIGNED_BYTE, 0);
break; break;
default: default:
break; break;
@ -3359,8 +3417,38 @@ void Media_RecordFrame (void)
} }
else else
#endif #endif
#if 0//def VKQUAKE
if (offscreen_format != TF_INVALID && qrenderer == QR_VULKAN)
{ {
pbo_oldest = captureframe+1; //try and collect any finished frames
while (offscreen_captureframe + countof(offscreen_queue) <= captureframe)
{
frame = offscreen_captureframe%countof(offscreen_queue);
vkFenceWait();
buffer = NULL;//qglMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
if (buffer)
{
//FIXME: thread these (with audio too, to avoid races)
currentcapture_funcs->capture_video(currentcapture_ctx, buffer, offscreen_captureframe, offscreen_queue[frame].width, offscreen_queue[frame].height, offscreen_queue[frame].format);
//qglUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
}
offscreen_captureframe++;
}
frame = captureframe%countof(offscreen_queue);
if (no frame yet)
{
create a buffer
map the buffer persistently
}
vkCopyImageToBuffer
vkSubmitFence
}
else
#endif
{
offscreen_captureframe = captureframe+1;
//submit the current video frame. audio will be mixed to match. //submit the current video frame. audio will be mixed to match.
buffer = VID_GetRGBInfo(&truewidth, &trueheight, &fmt); buffer = VID_GetRGBInfo(&truewidth, &trueheight, &fmt);
if (buffer) if (buffer)
@ -3388,7 +3476,7 @@ skipframe:
y = vid.height-8; y = vid.height-8;
#ifdef GLQUAKE #ifdef GLQUAKE
if (capturingfbo) if (capturingfbo && qrenderer == QR_OPENGL)
{ {
shader_t *pic; shader_t *pic;
GLBE_FBO_Pop(captureoldfbo); GLBE_FBO_Pop(captureoldfbo);
@ -3553,29 +3641,55 @@ void Media_InitFakeSoundDevice (int speed, int channels, int samplebits)
void Media_StopRecordFilm_f (void) void Media_StopRecordFilm_f (void)
{ {
#ifdef CAN_USE_PBOS #ifdef GLQUAKE_PBOS
if (pbo_format) if (offscreen_format && qrenderer == QR_OPENGL)
{ {
int i; int frame;
while (pbo_oldest < captureframe) qbyte *buffer;
while (offscreen_captureframe < captureframe)
{ {
qbyte *buffer; frame = offscreen_captureframe%countof(offscreen_queue);
qglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pbo_handles[pbo_oldest%countof(pbo_handles)]); qglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, offscreen_queue[frame].pbo_handle);
buffer = qglMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB); buffer = qglMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
if (buffer) if (buffer)
{ {
currentcapture_funcs->capture_video(currentcapture_ctx, buffer, pbo_oldest, vid.fbpwidth, vid.fbpheight, TF_BGR24); currentcapture_funcs->capture_video(currentcapture_ctx, buffer, offscreen_captureframe, offscreen_queue[frame].width, offscreen_queue[frame].height, offscreen_queue[frame].format);
// currentcapture_funcs->capture_video(currentcapture_ctx, buffer, pbo_oldest, vid.fbpwidth, vid.fbpheight, TF_BGRA32);
qglUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); qglUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
} }
pbo_oldest++; offscreen_captureframe++;
} }
for (i = 0; i < countof(pbo_handles); i++) for (frame = 0; frame < countof(offscreen_queue); frame++)
{ {
if (pbo_handles[i]) if (offscreen_queue[frame].pbo_handle)
qglDeleteBuffersARB(1, &pbo_handles[i]); qglDeleteBuffersARB(1, &offscreen_queue[frame].pbo_handle);
pbo_handles[i] = 0; memset(&offscreen_queue[frame], 0, sizeof(offscreen_queue[frame]));
}
}
#endif
#if 0//def VKQUAKE
if (pbo_format && qrenderer == QR_VULKAN)
{
int frame;
while (offscreen_captureframe < captureframe)
{
frame = offscreen_captureframe%countof(offscreen_queue);
qbyte *buffer;
qglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, offscreen_queue[frame].pbo_handle);
buffer = qglMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
if (buffer)
{
currentcapture_funcs->capture_video(currentcapture_ctx, buffer, offscreen_captureframe, offscreen_queue[frame].width, offscreen_queue[frame].height, offscreen_queue[frame].format);
qglUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
}
offscreen_captureframe++;
}
for (frame = 0; frame < countof(offscreen_queue); frame++)
{
if (offscreen_queue[frame].pbo_handle)
qglDeleteBuffersARB(1, &offscreen_queue[frame].pbo_handle);
memset(&offscreen_queue[frame], 0, sizeof(offscreen_queue[frame]));
} }
} }
#endif #endif
@ -3596,7 +3710,7 @@ void Media_StopRecordFilm_f (void)
currentcapture_funcs = NULL; currentcapture_funcs = NULL;
#ifdef GLQUAKE #ifdef GLQUAKE
if (capturingfbo) if (capturingfbo && qrenderer == QR_OPENGL)
{ {
GLBE_FBO_Pop(captureoldfbo); GLBE_FBO_Pop(captureoldfbo);
GLBE_FBO_Destroy(&capturefbo); GLBE_FBO_Destroy(&capturefbo);
@ -3627,7 +3741,7 @@ static void Media_RecordFilm (char *recordingname, qboolean demo)
Con_ClearNotify(); Con_ClearNotify();
captureframe = pbo_oldest = 0; captureframe = offscreen_captureframe = 0;
for (i = 0; i < sizeof(pluginencodersfunc)/sizeof(pluginencodersfunc[0]); i++) for (i = 0; i < sizeof(pluginencodersfunc)/sizeof(pluginencodersfunc[0]); i++)
{ {
if (pluginencodersfunc[i]) if (pluginencodersfunc[i])
@ -3668,17 +3782,26 @@ static void Media_RecordFilm (char *recordingname, qboolean demo)
vid.fbpheight = captureheight.ival; vid.fbpheight = captureheight.ival;
vid.framebuffer = capturetexture; vid.framebuffer = capturetexture;
} }
else
#endif #endif
{
vid.fbpwidth = vid.pixelwidth;
vid.fbpheight = vid.pixelheight;
}
#ifdef CAN_USE_PBOS offscreen_format = TF_INVALID;
pbo_format = TF_INVALID; #ifdef GLQUAKE_PBOS
if (qrenderer == QR_OPENGL && !gl_config.gles && gl_config.glversion >= 2.1) if (qrenderer == QR_OPENGL && !gl_config.gles && gl_config.glversion >= 2.1)
{ //both tgas and vfw favour bgr24, so lets get the gl drivers to suffer instead of us, where possible. { //both tgas and vfw favour bgr24, so lets get the gl drivers to suffer instead of us, where possible.
if (vid.fbpwidth & 3) if (vid.fbpwidth & 3)
pbo_format = TF_BGRA32; //don't bother changing pack alignment, just use something that is guarenteed to not need anything. offscreen_format = TF_BGRA32; //don't bother changing pack alignment, just use something that is guarenteed to not need anything.
else else
pbo_format = TF_BGR24; offscreen_format = TF_BGR24;
} }
#endif
#ifdef VKQUAKE
// if (qrenderer == QR_VULKAN)
// offscreen_format = TF_BGRA32; //use the native format, the driver won't do byteswapping for us.
#endif #endif
recordingdemo = demo; recordingdemo = demo;
@ -4531,6 +4654,7 @@ void Media_Init(void)
Cvar_Register(&captureheight, "AVI capture controls"); Cvar_Register(&captureheight, "AVI capture controls");
Cvar_Register(&capturedriver, "AVI capture controls"); Cvar_Register(&capturedriver, "AVI capture controls");
Cvar_Register(&capturecodec, "AVI capture controls"); Cvar_Register(&capturecodec, "AVI capture controls");
Cvar_Register(&capturethrottlesize, "AVI capture controls");
#if defined(WINAVI) #if defined(WINAVI)
Cvar_Register(&capturesoundbits, "AVI capture controls"); Cvar_Register(&capturesoundbits, "AVI capture controls");

View file

@ -2753,6 +2753,11 @@ void M_Menu_Video_f (void)
} }
#ifndef MINIMAL #ifndef MINIMAL
#ifdef RAGDOLL
#include "pr_common.h"
#endif
typedef struct typedef struct
{ {
enum { enum {
@ -2760,7 +2765,8 @@ typedef struct
MV_BONES, MV_BONES,
MV_SHADER, MV_SHADER,
MV_TEXTURE, MV_TEXTURE,
MV_COLLISION MV_COLLISION,
MV_EVENTS,
} mode; } mode;
int surfaceidx; int surfaceidx;
int skingroup; int skingroup;
@ -2776,6 +2782,17 @@ typedef struct
char shaderfile[MAX_QPATH]; char shaderfile[MAX_QPATH];
char *shadertext; char *shadertext;
#ifdef RAGDOLL
lerpents_t ragent;
world_t ragworld;
wedict_t ragworldedict;
comentvars_t ragworldvars;
comextentvars_t ragworldextvars;
pubprogfuncs_t ragfuncs;
qboolean flop; //ragdoll flopping enabled.
float fixedrate;
#endif
} modelview_t; } modelview_t;
static unsigned int genhsv(float h_, float s, float v) static unsigned int genhsv(float h_, float s, float v)
@ -2823,9 +2840,9 @@ static void M_BoneDisplayLame(entity_t *e, int *y, int depth, int parent, int fi
if (Mod_GetTag(e->model, i+1, &e->framestate, result)) if (Mod_GetTag(e->model, i+1, &e->framestate, result))
{ {
#if 0//def _DEBUG #if 0//def _DEBUG
Draw_FunString(depth*16, *y, va("%s%i: %s (%g %g %g)", (i==sel)?"^1":"", i, bname, result[3], result[7], result[11])); Draw_FunString(depth*16, *y, va("%s%i: %s (%g %g %g)", (i==sel)?"^1":"", i+1, bname, result[3], result[7], result[11]));
#else #else
Draw_FunString(depth*16, *y, va("%s%i: %s", (i==sel)?"^1":"", i, bname)); Draw_FunString(depth*16, *y, va("%s%i: %s", (i==sel)?"^1":"", i+1, bname));
#endif #endif
} }
else else
@ -2836,6 +2853,17 @@ static void M_BoneDisplayLame(entity_t *e, int *y, int depth, int parent, int fi
} }
} }
#endif #endif
static unsigned int tobit(unsigned int bitmask)
{
unsigned int b;
for (b = 0; b < 32; b++)
{
if (bitmask & (1<<b))
return b;
}
return 0;
}
static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_s *m) static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_s *m)
{ {
static playerview_t pv; static playerview_t pv;
@ -2935,16 +2963,40 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
return; return;
} }
#if 0
ent.framestate.bonestate = bones; #ifdef RAGDOLL
ent.framestate.bonecount = Mod_GetBoneRelations(ent.model, 0, MAX_BONES, &ent.framestate, ent.framestate.bonestate); if (mods->flop)
ent.framestate.skeltype = SKEL_RELATIVE; ent.framestate.g[FS_REG].frame[0] |= 0x8000;
if (ent.model->dollinfo)
{
float rate = 1.0/60;
rag_doallanimations(&mods->ragworld);
mods->fixedrate += host_frametime;
if (mods->fixedrate > 1)
mods->fixedrate = 1;
while (mods->fixedrate >= rate)
{
sv.world.rbe->Frame(&mods->ragworld, rate, 800);
mods->fixedrate -= rate;
}
rag_updatedeltaent(&mods->ragworld, &ent, &mods->ragent);
}
#endif #endif
if (mods->mode == MV_COLLISION) if (mods->mode == MV_COLLISION)
{ {
shader_t *s = R_RegisterShader("bboxshader_nodepth", SUF_NONE, shader_t *s;
#ifdef HALFLIFEMODELS
if (ent.model->type == mod_halflife)
HLMDL_DrawHitBoxes(&ent);
else
#endif
if (1)
{
s = R_RegisterShader("hitbox_nodepth", SUF_NONE,
"{\n" "{\n"
"polygonoffset\n" "polygonoffset\n"
"{\n" "{\n"
@ -2955,16 +3007,25 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
"nodepthtest\n" "nodepthtest\n"
"}\n" "}\n"
"}\n"); "}\n");
Mod_AddSingleSurface(&ent, mods->surfaceidx, s);
#ifdef HALFLIFEMODELS }
if (ent.model->type == mod_halflife)
HLMDL_DrawHitBoxes(&ent);
else else
#endif
{ {
vec3_t mins, maxs; vec3_t mins, maxs;
VectorAdd(ent.model->mins, ent.origin, mins); VectorAdd(ent.model->mins, ent.origin, mins);
VectorAdd(ent.model->maxs, ent.origin, maxs); VectorAdd(ent.model->maxs, ent.origin, maxs);
s = R_RegisterShader("bboxshader_nodepth", SUF_NONE,
"{\n"
"polygonoffset\n"
"{\n"
"map $whiteimage\n"
"blendfunc gl_src_alpha gl_one\n"
"rgbgen vertex\n"
"alphagen vertex\n"
"nodepthtest\n"
"}\n"
"}\n");
CLQ1_AddOrientedCube(s, mins, maxs, NULL, 1, 1, 1, 0.2); CLQ1_AddOrientedCube(s, mins, maxs, NULL, 1, 1, 1, 0.2);
} }
@ -2986,7 +3047,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
"}\n" "}\n"
"}\n"); "}\n");
if (ent.model->funcs.NativeTrace(ent.model, 0, &ent.framestate, NULL, v1, v2, vec3_origin, vec3_origin, false, ~0, &tr)) if (ent.model->funcs.NativeTrace && ent.model->funcs.NativeTrace(ent.model, 0, &ent.framestate, NULL, v1, v2, vec3_origin, vec3_origin, false, ~0, &tr))
{ {
vec3_t dir; vec3_t dir;
float f; float f;
@ -3067,13 +3128,26 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
R_RenderView(); R_RenderView();
y = 0; y = 0;
{
fname = Mod_SurfaceNameForNum(ent.model, mods->surfaceidx); fname = Mod_SurfaceNameForNum(ent.model, mods->surfaceidx);
if (!fname) if (!fname)
fname = "Unknown Surface"; fname = "Unknown Surface";
Draw_FunString(0, y, va("Surf %i: %s", mods->surfaceidx, fname)); Draw_FunString(0, y, va("Surf %i: %s", mods->surfaceidx, fname));
y+=8; y+=8;
}
{
fname = Mod_SkinNameForNum(ent.model, mods->surfaceidx, mods->skingroup);
if (!fname)
{
Draw_FunString(0, y, va("Skin %i: <invalid skin>", mods->skingroup));
}
else
{
shader = Mod_ShaderForSkin(ent.model, mods->surfaceidx, mods->skingroup);
Draw_FunString(0, y, va("Skin %i: \"%s\", shader \"%s\"", mods->skingroup, fname, shader?shader->name:"NO SHADER"));
}
y+=8;
}
{ {
char *fname; char *fname;
int numframes = 0; int numframes = 0;
@ -3084,12 +3158,6 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
Draw_FunString(0, y, va("Frame%i: %s (%i poses, %f/%f secs, %s)", mods->framegroup, fname, numframes, ent.framestate.g[FS_REG].frametime[0], duration, loop?"looped":"unlooped")); Draw_FunString(0, y, va("Frame%i: %s (%i poses, %f/%f secs, %s)", mods->framegroup, fname, numframes, ent.framestate.g[FS_REG].frametime[0], duration, loop?"looped":"unlooped"));
y+=8; y+=8;
} }
fname = Mod_SkinNameForNum(ent.model, mods->surfaceidx, mods->skingroup);
if (!fname)
fname = "Unknown Skin";
shader = Mod_ShaderForSkin(ent.model, mods->surfaceidx, mods->skingroup);
Draw_FunString(0, y, va("Skin %i: (%s) %s", mods->skingroup, fname, shader?shader->name:"NO SHADER"));
y+=8;
switch(mods->mode) switch(mods->mode)
{ {
@ -3100,22 +3168,75 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
"s: zoom out\n" "s: zoom out\n"
"m: mode\n" "m: mode\n"
"r: reset times\n" "r: reset times\n"
"home: skin-=1\n" "home: skin+=1\n"
"end: skin+=1\n" "end: skin-=1\n"
"pgup: frame+=1\n" "pgup: frame+=1\n"
"pgdn: frame-=1\n" "pgdn: frame-=1\n"
"mins: %g %g %g, maxs: %g %g %g\n", ent.model->mins[0], ent.model->mins[1], ent.model->mins[2], ent.model->maxs[0], ent.model->maxs[1], ent.model->maxs[2]) "mins: %g %g %g, maxs: %g %g %g\n", ent.model->mins[0], ent.model->mins[1], ent.model->mins[2], ent.model->maxs[0], ent.model->maxs[1], ent.model->maxs[2])
, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, fs); , CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, fs);
break; break;
case MV_COLLISION: case MV_COLLISION:
if (ent.model->type != mod_halflife) if (!ent.model)
;
else if (ent.model->type == mod_alias)
{
galiasinfo_t *inf = Mod_Extradata(ent.model);
int surfnum = mods->surfaceidx;
while(inf && surfnum-->0)
inf = inf->nextsurf;
if (inf)
{
char contents[512];
unsigned int i;
char *contentnames[32] = {NULL};
contentnames[tobit(FTECONTENTS_SOLID)] = "solid";
contentnames[tobit(FTECONTENTS_LAVA)] = "lava";
contentnames[tobit(FTECONTENTS_SLIME)] = "slime";
contentnames[tobit(FTECONTENTS_WATER)] = "water";
contentnames[tobit(FTECONTENTS_LADDER)] = "ladder";
contentnames[tobit(FTECONTENTS_PLAYERCLIP)] = "playerclip";
contentnames[tobit(FTECONTENTS_MONSTERCLIP)] = "monsterclip";
contentnames[tobit(FTECONTENTS_BODY)] = "body";
contentnames[tobit(FTECONTENTS_CORPSE)] = "corpse";
contentnames[tobit(FTECONTENTS_SKY)] = "sky";
for (*contents = 0, i = 0; i < 32; i++)
{
if (inf->contents & (1<<i))
{
if (*contents)
Q_strncatz(contents, "|", sizeof(contents));
if (contentnames[i])
Q_strncatz(contents, contentnames[i], sizeof(contents));
else
Q_strncatz(contents, va("%#x", 1<<i), sizeof(contents));
}
}
if (!*contents)
Q_strncatz(contents, "non-solid", sizeof(contents));
R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+y, r_refdef.grect.width, r_refdef.grect.height-y,
va( "mins: %g %g %g, maxs: %g %g %g\n"
"contents: %s\n"
"surfflags: %#x\n"
"body: %i\n"
"geomset: %i %i%s\n"
"numverts: %i\nnumtris: %i\n"
, ent.model->mins[0], ent.model->mins[1], ent.model->mins[2], ent.model->maxs[0], ent.model->maxs[1], ent.model->maxs[2],
contents,
inf->csurface.flags,
inf->surfaceid,
inf->geomset>=MAX_GEOMSETS?-1:inf->geomset, inf->geomid, inf->geomset>=MAX_GEOMSETS?" (always)":"",
inf->numverts, inf->numindexes/3
)
, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, fs);
}
}
else
{ {
R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+y, r_refdef.grect.width, r_refdef.grect.height-y, R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+y, r_refdef.grect.width, r_refdef.grect.height-y,
va("mins: %g %g %g, maxs: %g %g %g\n", ent.model->mins[0], ent.model->mins[1], ent.model->mins[2], ent.model->maxs[0], ent.model->maxs[1], ent.model->maxs[2]) va("mins: %g %g %g, maxs: %g %g %g\n", ent.model->mins[0], ent.model->mins[1], ent.model->mins[2], ent.model->maxs[0], ent.model->maxs[1], ent.model->maxs[2])
, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, fs); , CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, fs);
break;
} }
//fallthrough break;
case MV_BONES: case MV_BONES:
#ifdef SKELETALMODELS #ifdef SKELETALMODELS
{ {
@ -3131,6 +3252,21 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
} }
#endif #endif
break; break;
case MV_EVENTS:
{
int i;
float timestamp = 0;
int code = 0;
char *data = NULL;
Draw_FunString(0, y, va("Events: "));
y+=8;
for (i = 0; Mod_GetModelEvent(ent.model, mods->framegroup, i, &timestamp, &code, &data); y+=8, i++)
{
Draw_FunString(0, y, va("%i %f: %i %s", i, timestamp, code, data));
}
Draw_FunString(0, y, va("%f: <end of animation>", Mod_GetFrameDuration(ent.model, 0, mods->framegroup)));
}
break;
case MV_SHADER: case MV_SHADER:
{ {
if (!mods->shadertext) if (!mods->shadertext)
@ -3184,7 +3320,8 @@ static qboolean M_ModelViewerKey(struct menucustom_s *c, struct menu_s *m, int k
case MV_BONES: mods->mode = MV_SHADER; break; case MV_BONES: mods->mode = MV_SHADER; break;
case MV_SHADER: mods->mode = MV_TEXTURE; break; case MV_SHADER: mods->mode = MV_TEXTURE; break;
case MV_TEXTURE: mods->mode = MV_COLLISION; break; case MV_TEXTURE: mods->mode = MV_COLLISION; break;
case MV_COLLISION: mods->mode = MV_NONE; break; case MV_COLLISION: mods->mode = MV_EVENTS; break;
case MV_EVENTS: mods->mode = MV_NONE; break;
} }
} }
else if (key == 'r') else if (key == 'r')
@ -3192,6 +3329,14 @@ static qboolean M_ModelViewerKey(struct menucustom_s *c, struct menu_s *m, int k
mods->framechangetime = realtime; mods->framechangetime = realtime;
mods->skinchangetime = realtime; mods->skinchangetime = realtime;
} }
#ifdef RAGDOLL
else if (key == 'f')
{
mods->flop ^= 1;
if (!mods->flop)
rag_removedeltaent(&mods->ragent);
}
#endif
else if (key == '[') else if (key == '[')
mods->boneidx--; mods->boneidx--;
else if (key == ']') else if (key == ']')
@ -3204,14 +3349,14 @@ static qboolean M_ModelViewerKey(struct menucustom_s *c, struct menu_s *m, int k
mods->yaw -= 5; mods->yaw -= 5;
else if (key == K_RIGHTARROW) else if (key == K_RIGHTARROW)
mods->yaw += 5; mods->yaw += 5;
else if (key == K_HOME) else if (key == K_END)
{ {
mods->skingroup = max(0, mods->skingroup-1); mods->skingroup = max(0, mods->skingroup-1);
mods->skinchangetime = realtime; mods->skinchangetime = realtime;
Z_Free(mods->shadertext); Z_Free(mods->shadertext);
mods->shadertext = NULL; mods->shadertext = NULL;
} }
else if (key == K_END) else if (key == K_HOME)
{ {
mods->skingroup += 1; mods->skingroup += 1;
mods->skinchangetime = realtime; mods->skinchangetime = realtime;
@ -3230,13 +3375,13 @@ static qboolean M_ModelViewerKey(struct menucustom_s *c, struct menu_s *m, int k
mods->framegroup += 1; mods->framegroup += 1;
mods->framechangetime = realtime; mods->framechangetime = realtime;
} }
else if (key == K_INS) else if (key == K_DEL)
{ {
mods->surfaceidx = max(0, mods->surfaceidx-1); mods->surfaceidx = max(0, mods->surfaceidx-1);
Z_Free(mods->shadertext); Z_Free(mods->shadertext);
mods->shadertext = NULL; mods->shadertext = NULL;
} }
else if (key == K_DEL) else if (key == K_INS)
{ {
mods->surfaceidx += 1; mods->surfaceidx += 1;
Z_Free(mods->shadertext); Z_Free(mods->shadertext);
@ -3253,12 +3398,31 @@ static qboolean M_ModelViewerKey(struct menucustom_s *c, struct menu_s *m, int k
return true; return true;
} }
#ifdef RAGDOLL
void M_Modelviewer_Shutdown(struct menu_s *menu)
{
modelview_t *mv = menu->data;
rag_removedeltaent(&mv->ragent);
skel_reset(&mv->ragworld);
World_RBE_Shutdown(&mv->ragworld);
}
//haxors, for skeletal objects+RBE
char *PDECL M_Modelviewer_AddString(pubprogfuncs_t *prinst, const char *val, int minlength, pbool demarkup)
{
return Z_Malloc(minlength);
}
struct edict_s *PDECL M_Modelviewer_ProgsToEdict(pubprogfuncs_t *prinst, int num)
{
return (struct edict_s*)prinst->edicttable[num];
}
#endif
void M_Menu_ModelViewer_f(void) void M_Menu_ModelViewer_f(void)
{ {
modelview_t *mv; modelview_t *mv;
menucustom_t *c; menucustom_t *c;
menu_t *menu; menu_t *menu;
Key_Dest_Add(kdm_emenu); Key_Dest_Add(kdm_emenu);
menu = M_CreateMenu(sizeof(*mv)); menu = M_CreateMenu(sizeof(*mv));
@ -3268,10 +3432,28 @@ void M_Menu_ModelViewer_f(void)
c->draw = M_ModelViewerDraw; c->draw = M_ModelViewerDraw;
c->key = M_ModelViewerKey; c->key = M_ModelViewerKey;
mv->yaw = 180 + crandom()*45; mv->yaw = 180;// + crandom()*45;
mv->dist = 150; mv->dist = 150;
Q_strncpyz(mv->modelname, Cmd_Argv(1), sizeof(mv->modelname)); Q_strncpyz(mv->modelname, Cmd_Argv(1), sizeof(mv->modelname));
Q_strncpyz(mv->forceshader, Cmd_Argv(2), sizeof(mv->forceshader)); Q_strncpyz(mv->forceshader, Cmd_Argv(2), sizeof(mv->forceshader));
#ifdef RAGDOLL
menu->remove = M_Modelviewer_Shutdown;
mv->ragworld.progs = &mv->ragfuncs;
mv->ragfuncs.AddString = M_Modelviewer_AddString;
mv->ragfuncs.ProgsToEdict = M_Modelviewer_ProgsToEdict;
mv->ragfuncs.edicttable = (edict_t**)&mv->ragworld.edicts;
mv->ragworld.edicts = &mv->ragworldedict;
mv->ragworld.edicts->v = &mv->ragworldvars;
mv->ragworld.edicts->xv = &mv->ragworldextvars;
mv->ragworld.num_edicts = 1;
mv->ragworld.edicts->v->solid = SOLID_BBOX;
VectorSet(mv->ragworld.edicts->v->mins, -1000, -1000, -101);
VectorSet(mv->ragworld.edicts->v->maxs, 1000, 1000, -100);
mv->ragworld.worldmodel = Mod_ForName("", MLV_SILENT);
World_RBE_Start(&mv->ragworld);
#endif
} }
#else #else
void M_Menu_ModelViewer_f(void) void M_Menu_ModelViewer_f(void)

View file

@ -172,7 +172,10 @@ extern void Mod_TouchModel (const char *name);
extern const char *Mod_FixName (const char *modname, const char *worldname); //remaps the name appropriately extern const char *Mod_FixName (const char *modname, const char *worldname); //remaps the name appropriately
const char *Mod_ParseWorldspawnKey (struct model_s *mod, const char *key, char *buffer, size_t sizeofbuffer); const char *Mod_ParseWorldspawnKey (struct model_s *mod, const char *key, char *buffer, size_t sizeofbuffer);
extern long relitsurface;
extern struct model_s *lightmodel;
extern void Mod_Think (void); extern void Mod_Think (void);
extern qboolean Mod_GetModelEvent (struct model_s *model, int animation, int eventidx, float *timestamp, int *eventcode, char **eventdata);
extern int Mod_SkinNumForName (struct model_s *model, int surfaceidx, const char *name); extern int Mod_SkinNumForName (struct model_s *model, int surfaceidx, const char *name);
extern int Mod_FrameNumForName (struct model_s *model, int surfaceidx, const char *name); extern int Mod_FrameNumForName (struct model_s *model, int surfaceidx, const char *name);
extern float Mod_GetFrameDuration (struct model_s *model, int surfaceidx, int framenum); extern float Mod_GetFrameDuration (struct model_s *model, int surfaceidx, int framenum);
@ -183,6 +186,7 @@ extern int Mod_GetFrameCount (struct model_s *model);
extern qboolean Mod_GetTag (struct model_s *model, int tagnum, framestate_t *framestate, float *transforms); extern qboolean Mod_GetTag (struct model_s *model, int tagnum, framestate_t *framestate, float *transforms);
extern int Mod_TagNumForName (struct model_s *model, const char *name); extern int Mod_TagNumForName (struct model_s *model, const char *name);
void Mod_AddSingleSurface(struct entity_s *ent, int surfaceidx, shader_t *shader);
int Mod_GetNumBones(struct model_s *model, qboolean allowtags); int Mod_GetNumBones(struct model_s *model, qboolean allowtags);
int Mod_GetBoneRelations(struct model_s *model, int firstbone, int lastbone, framestate_t *fstate, float *result); int Mod_GetBoneRelations(struct model_s *model, int firstbone, int lastbone, framestate_t *fstate, float *result);
int Mod_GetBoneParent(struct model_s *model, int bonenum); int Mod_GetBoneParent(struct model_s *model, int bonenum);

View file

@ -17,7 +17,9 @@ void Master_DetermineMasterTypes(void)
{ {
if (com_protocolname.modified) if (com_protocolname.modified)
{ {
char tok[MAX_QPATH];
char *prot = com_protocolname.string; char *prot = com_protocolname.string;
char *game;
com_protocolname.modified = 0; com_protocolname.modified = 0;
sb_enabledarkplaces = true; //dpmaster is not specific to any single game/mod, so can be left enabled even when running q2 etc, for extra redundancy. sb_enabledarkplaces = true; //dpmaster is not specific to any single game/mod, so can be left enabled even when running q2 etc, for extra redundancy.
@ -26,19 +28,24 @@ void Master_DetermineMasterTypes(void)
sb_enablenetquake = false; sb_enablenetquake = false;
sb_enablequakeworld = false; sb_enablequakeworld = false;
//this is stupid for (prot = com_protocolname.string; *prot;)
if (!Q_strncasecmp(prot, "FTE-", 4)) {
prot += 4; prot = COM_ParseOut(prot, tok, sizeof(tok));
else if (!Q_strncasecmp(prot, "DarkPlaces-", 11)) game = tok;
prot += 11; //this is stupid, but hey
if (!Q_strncasecmp(game, "FTE-", 4))
game += 4;
else if (!Q_strncasecmp(game, "DarkPlaces-", 11))
game += 11;
if (!strcmp(prot, "Quake2")) if (!strcmp(game, "Quake2"))
sb_enablequake2 = true; sb_enablequake2 = true;
if (!strcmp(prot, "Quake3")) if (!strcmp(game, "Quake3"))
sb_enablequake3 = true; sb_enablequake3 = true;
//for DP compatibility, we consider these separate(ish) games. //for DP compatibility, we consider these separate(ish) games.
if (!strcmp(prot, "Quake") || !strcmp(com_protocolname.string, "Hipnotic") || !strcmp(com_protocolname.string, "Rogue")) if (!strcmp(game, "Quake") || !strcmp(game, "Hipnotic") || !strcmp(game, "Rogue"))
sb_enablenetquake = sb_enablequakeworld = true; sb_enablenetquake = sb_enablequakeworld = true;
}
} }
} }
@ -1974,7 +1981,7 @@ int Master_CheckPollSockets(void)
s = MSG_ReadString(); s = MSG_ReadString();
old = Info_ValueForKey(info->moreinfo->info, selectedserver.lastrule); old = Info_ValueForKey(info->moreinfo->info, selectedserver.lastrule);
if (strcmp(s, old)) if (strcmp(s, old) && !strchr(s, '\"') && !strchr(s, '\\'))
Info_SetValueForStarKey(info->moreinfo->info, selectedserver.lastrule, s, sizeof(info->moreinfo->info)); Info_SetValueForStarKey(info->moreinfo->info, selectedserver.lastrule, s, sizeof(info->moreinfo->info));
//... and now try to query the next one... because everyone gives up after the first, right?... dude... I hate this shit. //... and now try to query the next one... because everyone gives up after the first, right?... dude... I hate this shit.
@ -2352,13 +2359,20 @@ void MasterInfo_Request(master_t *mast)
case MP_DPMASTER: case MP_DPMASTER:
{ {
char *str; char *str;
//for compat with dp, we use the nq netchan version. which is stupid, but whatever char game[MAX_QPATH];
//we ask for ipv6 addresses from ipv6 masters (assuming it resolved okay) char *games = com_protocolname.string;
if (mast->adr.type == NA_IPV6) while(*games)
str = va("%c%c%c%cgetserversExt %s %u empty full ipv6"/*\x0A\n"*/, 255, 255, 255, 255, com_protocolname.string, NQ_NETCHAN_VERSION); { //send a request for each game listed.
else games = COM_ParseOut(games, game, sizeof(game));
str = va("%c%c%c%cgetservers %s %u empty full"/*\x0A\n"*/, 255, 255, 255, 255, com_protocolname.string, NQ_NETCHAN_VERSION);
NET_SendPollPacket (strlen(str), str, mast->adr); //for compat with dp, we use the nq netchan version. which is stupid, but whatever
//we ask for ipv6 addresses from ipv6 masters (assuming it resolved okay)
if (mast->adr.type == NA_IPV6)
str = va("%c%c%c%cgetserversExt %s %u empty full ipv6"/*\x0A\n"*/, 255, 255, 255, 255, game, NQ_NETCHAN_VERSION);
else
str = va("%c%c%c%cgetservers %s %u empty full"/*\x0A\n"*/, 255, 255, 255, 255, game, NQ_NETCHAN_VERSION);
NET_SendPollPacket (strlen(str), str, mast->adr);
}
} }
break; break;
#endif #endif

View file

@ -133,6 +133,7 @@ extern sfx_t *cl_sfx_r_exp3;
globalfloat(frametime, "frametime"); /*float Client render frame interval*/ \ globalfloat(frametime, "frametime"); /*float Client render frame interval*/ \
globalfloat(gamespeed, "gamespeed"); /*float Multiplier for real time -> simulation time*/ \ globalfloat(gamespeed, "gamespeed"); /*float Multiplier for real time -> simulation time*/ \
globalfloat(cltime, "cltime"); /*float Clientside map uptime indepent of gamespeed, latency, and the server in general*/ \ globalfloat(cltime, "cltime"); /*float Clientside map uptime indepent of gamespeed, latency, and the server in general*/ \
globalfloat(clframetime, "clframetime"); /*float time since last video frame*/ \
globalfloat(netnewtime, "servertime"); /*float Server time of latest inbound network frame*/ \ globalfloat(netnewtime, "servertime"); /*float Server time of latest inbound network frame*/ \
globalfloat(netoldtime, "serverprevtime"); /*float Server time of previous inbound network frame */ \ globalfloat(netoldtime, "serverprevtime"); /*float Server time of previous inbound network frame */ \
globalfloat(netdeltatime, "serverdeltatime"); /*float new-old */ \ globalfloat(netdeltatime, "serverdeltatime"); /*float new-old */ \
@ -600,7 +601,7 @@ static void cs_getframestate(csqcedict_t *in, unsigned int rflags, framestate_t
out->bonecount = 0; out->bonecount = 0;
out->bonestate = NULL; out->bonestate = NULL;
if (in->xv->skeletonindex) if (in->xv->skeletonindex)
skel_lookup(csqcprogs, in->xv->skeletonindex, out); skel_lookup(&csqc_world, in->xv->skeletonindex, out);
#endif #endif
} }
@ -1715,7 +1716,7 @@ static void QCBUILTIN PF_R_ClearScene (pubprogfuncs_t *prinst, struct globalvars
CL_DecayLights (); CL_DecayLights ();
#if defined(SKELETALOBJECTS) || defined(RAGDOLLS) #if defined(SKELETALOBJECTS) || defined(RAGDOLLS)
skel_dodelete(csqcprogs); skel_dodelete(&csqc_world);
#endif #endif
CL_ClearEntityLists(); CL_ClearEntityLists();
@ -3416,7 +3417,7 @@ static const char *PF_cs_getplayerkey_internal (unsigned int pnum, const char *k
static char buffer[64]; static char buffer[64];
char *ret; char *ret;
if (pnum < 0 || pnum >= cl.allocated_client_slots) if ((unsigned int)pnum >= (unsigned int)cl.allocated_client_slots)
ret = ""; ret = "";
else if (!strcmp(keyname, "viewentity")) //compat with DP. Yes, I know this is in the wrong place. This is an evil hack. else if (!strcmp(keyname, "viewentity")) //compat with DP. Yes, I know this is in the wrong place. This is an evil hack.
{ {
@ -4565,6 +4566,7 @@ static void CSQC_LerpStateToCSQC(lerpents_t *le, csqcedict_t *ent, qboolean nole
ent->xv->baseframe2 = le->oldframe[FST_BASE]; ent->xv->baseframe2 = le->oldframe[FST_BASE];
ent->xv->baseframe2time = max(0, cl.servertime - le->oldframestarttime[FST_BASE]); ent->xv->baseframe2time = max(0, cl.servertime - le->oldframestarttime[FST_BASE]);
ent->xv->baselerpfrac = bound(0, 1-(ent->xv->baseframe1time) / le->framelerpdeltatime[FST_BASE], 1); ent->xv->baselerpfrac = bound(0, 1-(ent->xv->baseframe1time) / le->framelerpdeltatime[FST_BASE], 1);
ent->xv->basebone = le->basebone;
if (nolerp) if (nolerp)
@ -5156,9 +5158,6 @@ static void QCBUILTIN PF_V_CalcRefdef(pubprogfuncs_t *prinst, struct globalvars_
CL_DecayLights (); CL_DecayLights ();
#if defined(SKELETALOBJECTS) || defined(RAGDOLLS)
skel_dodelete(csqcprogs);
#endif
CL_ClearEntityLists(); CL_ClearEntityLists();
V_ClearRefdef(csqc_playerview); V_ClearRefdef(csqc_playerview);
@ -5706,6 +5705,9 @@ static struct {
{"skel_delete", PF_skel_delete, 275},//void(float skel) skel_delete = #275; // (FTE_CSQC_SKELETONOBJECTS) {"skel_delete", PF_skel_delete, 275},//void(float skel) skel_delete = #275; // (FTE_CSQC_SKELETONOBJECTS)
{"frameforname", PF_frameforname, 276},//void(float modidx, string framename) frameforname = #276 (FTE_CSQC_SKELETONOBJECTS) {"frameforname", PF_frameforname, 276},//void(float modidx, string framename) frameforname = #276 (FTE_CSQC_SKELETONOBJECTS)
{"frameduration", PF_frameduration, 277},//void(float modidx, float framenum) frameduration = #277 (FTE_CSQC_SKELETONOBJECTS) {"frameduration", PF_frameduration, 277},//void(float modidx, float framenum) frameduration = #277 (FTE_CSQC_SKELETONOBJECTS)
{"processmodelevents", PF_processmodelevents, 0},
{"getnextmodelevent", PF_getnextmodelevent, 0},
{"getmodeleventidx", PF_getmodeleventidx, 0},
{"crossproduct", PF_crossproduct, 0}, {"crossproduct", PF_crossproduct, 0},
@ -6336,7 +6338,15 @@ static qboolean QDECL CSQC_Event_ContentsTransition(world_t *w, wedict_t *ent, i
static model_t *QDECL CSQC_World_ModelForIndex(world_t *w, int modelindex) static model_t *QDECL CSQC_World_ModelForIndex(world_t *w, int modelindex)
{ {
return CSQC_GetModelForIndex(modelindex); model_t *mod = CSQC_GetModelForIndex(modelindex);
if (mod && mod->loadstate != MLS_LOADED)
{
if (mod->loadstate == MLS_LOADING)
COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING);
if (mod->loadstate != MLS_LOADED)
mod = NULL; //gah, it failed!
}
return mod;
} }
static void QDECL CSQC_World_GetFrameState(world_t *w, wedict_t *win, framestate_t *out) static void QDECL CSQC_World_GetFrameState(world_t *w, wedict_t *win, framestate_t *out)
{ {
@ -7310,6 +7320,8 @@ qboolean CSQC_DrawView(void)
else else
*csqcg.frametime = host_frametime; *csqcg.frametime = host_frametime;
} }
if (csqcg.clframetime)
*csqcg.clframetime = host_frametime;
if (csqcg.numclientseats) if (csqcg.numclientseats)
*csqcg.numclientseats = cl.splitclients; *csqcg.numclientseats = cl.splitclients;

View file

@ -1838,7 +1838,9 @@ static void QCBUILTIN PF_m_clearscene(pubprogfuncs_t *prinst, struct globalvars_
// CL_DecayLights (); // CL_DecayLights ();
#if defined(SKELETALOBJECTS) || defined(RAGDOLLS) #if defined(SKELETALOBJECTS) || defined(RAGDOLLS)
skel_dodelete(prinst); world_t *world = prinst->parms->user;
if (world)
skel_dodelete(world);
#endif #endif
CL_ClearEntityLists(); CL_ClearEntityLists();

View file

@ -482,6 +482,19 @@ static qboolean rag_dollline(dollcreatectx_t *ctx, int linenum)
ctx->body->dimensions[1] = atof(Cmd_Argv(2)); ctx->body->dimensions[1] = atof(Cmd_Argv(2));
ctx->body->dimensions[2] = atof(Cmd_Argv(3)); ctx->body->dimensions[2] = atof(Cmd_Argv(3));
} }
else if (ctx->body && argc == 4 && !stricmp(cmd, "offset"))
{
vec3_t ang;
ctx->body->isoffset = true;
ctx->body->relmatrix[3] = atof(val);
ctx->body->relmatrix[7] = atof(Cmd_Argv(2));
ctx->body->relmatrix[11] = atof(Cmd_Argv(3));
ang[0] = atof(Cmd_Argv(4));
ang[1] = atof(Cmd_Argv(5));
ang[2] = atof(Cmd_Argv(6));
AngleVectorsFLU(ang, &ctx->body->relmatrix[0], &ctx->body->relmatrix[4], &ctx->body->relmatrix[8]);
Matrix3x4_Invert_Simple(ctx->body->relmatrix, ctx->body->inverserelmatrix);
}
//joint properties //joint properties
else if (ctx->joint && argc == 2 && !stricmp(cmd, "type")) else if (ctx->joint && argc == 2 && !stricmp(cmd, "type"))
@ -966,13 +979,13 @@ void skel_info_f(void)
} }
/*destroys all skeletons*/ /*destroys all skeletons*/
void skel_reset(pubprogfuncs_t *prinst) void skel_reset(world_t *world)
{ {
int i; int i;
for (i = 0; i < countof(skelobjects); i++) for (i = 0; i < countof(skelobjects); i++)
{ {
if (skelobjects[i].world == prinst->parms->user) if (skelobjects[i].world == world)
{ {
#ifdef RAGDOLL #ifdef RAGDOLL
rag_uninstanciate(&skelobjects[i]); rag_uninstanciate(&skelobjects[i]);
@ -992,7 +1005,7 @@ void skel_reset(pubprogfuncs_t *prinst)
} }
/*deletes any skeletons marked for deletion*/ /*deletes any skeletons marked for deletion*/
void skel_dodelete(pubprogfuncs_t *prinst) void skel_dodelete(world_t *world)
{ {
int skelidx; int skelidx;
if (!pendingkill) if (!pendingkill)
@ -1014,7 +1027,7 @@ void skel_dodelete(pubprogfuncs_t *prinst)
numskelobjectsused--; numskelobjectsused--;
} }
static skelobject_t *skel_create(pubprogfuncs_t *prinst, int bonecount) static skelobject_t *skel_create(world_t *world, int bonecount)
{ {
unsigned int skelidx; unsigned int skelidx;
//invalid if the bonecount is not set... //invalid if the bonecount is not set...
@ -1023,7 +1036,7 @@ static skelobject_t *skel_create(pubprogfuncs_t *prinst, int bonecount)
for (skelidx = 0; skelidx < numskelobjectsused; skelidx++) for (skelidx = 0; skelidx < numskelobjectsused; skelidx++)
{ {
if (!skelobjects[skelidx].inuse && skelobjects[skelidx].numbones == bonecount && skelobjects[skelidx].world == prinst->parms->user) if (!skelobjects[skelidx].inuse && skelobjects[skelidx].numbones == bonecount && skelobjects[skelidx].world == world)
{ {
skelobjects[skelidx].inuse = 1; skelobjects[skelidx].inuse = 1;
return &skelobjects[skelidx]; return &skelobjects[skelidx];
@ -1034,14 +1047,14 @@ static skelobject_t *skel_create(pubprogfuncs_t *prinst, int bonecount)
{ {
if (!skelobjects[skelidx].inuse && if (!skelobjects[skelidx].inuse &&
(!skelobjects[skelidx].numbones || skelobjects[skelidx].numbones == bonecount) && (!skelobjects[skelidx].numbones || skelobjects[skelidx].numbones == bonecount) &&
(!skelobjects[skelidx].world || skelobjects[skelidx].world == prinst->parms->user)) (!skelobjects[skelidx].world || skelobjects[skelidx].world == world))
{ {
if (!skelobjects[skelidx].numbones) if (!skelobjects[skelidx].numbones)
{ {
skelobjects[skelidx].numbones = bonecount; skelobjects[skelidx].numbones = bonecount;
skelobjects[skelidx].bonematrix = (float*)PR_AddString(prinst, "", sizeof(float)*12*bonecount, false); skelobjects[skelidx].bonematrix = (float*)PR_AddString(world->progs, "", sizeof(float)*12*bonecount, false);
} }
skelobjects[skelidx].world = prinst->parms->user; skelobjects[skelidx].world = world;
if (numskelobjectsused <= skelidx) if (numskelobjectsused <= skelidx)
numskelobjectsused = skelidx + 1; numskelobjectsused = skelidx + 1;
skelobjects[skelidx].model = NULL; skelobjects[skelidx].model = NULL;
@ -1052,7 +1065,7 @@ static skelobject_t *skel_create(pubprogfuncs_t *prinst, int bonecount)
return NULL; return NULL;
} }
static skelobject_t *skel_get(pubprogfuncs_t *prinst, int skelidx) static skelobject_t *skel_get(world_t *world, int skelidx)
{ {
skelidx--; skelidx--;
if ((unsigned int)skelidx >= numskelobjectsused) if ((unsigned int)skelidx >= numskelobjectsused)
@ -1062,9 +1075,9 @@ static skelobject_t *skel_get(pubprogfuncs_t *prinst, int skelidx)
return &skelobjects[skelidx]; return &skelobjects[skelidx];
} }
void skel_lookup(pubprogfuncs_t *prinst, int skelidx, framestate_t *out) void skel_lookup(world_t *world, int skelidx, framestate_t *out)
{ {
skelobject_t *sko = skel_get(prinst, skelidx); skelobject_t *sko = skel_get(world, skelidx);
if (sko && sko->inuse) if (sko && sko->inuse)
{ {
out->skeltype = sko->type; out->skeltype = sko->type;
@ -1075,9 +1088,10 @@ void skel_lookup(pubprogfuncs_t *prinst, int skelidx, framestate_t *out)
void QCBUILTIN PF_skel_mmap(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_skel_mmap(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
world_t *world = prinst->parms->user;
int skelidx = G_FLOAT(OFS_PARM0); int skelidx = G_FLOAT(OFS_PARM0);
skelobject_t *sko = skel_get(prinst, skelidx); skelobject_t *sko = skel_get(world, skelidx);
if (!sko || sko->world != prinst->parms->user) if (!sko || sko->world != world)
G_INT(OFS_RETURN) = 0; G_INT(OFS_RETURN) = 0;
else else
G_INT(OFS_RETURN) = (char*)sko->bonematrix - prinst->stringtable; G_INT(OFS_RETURN) = (char*)sko->bonematrix - prinst->stringtable;
@ -1118,9 +1132,17 @@ static void rag_uninstanciate(skelobject_t *sko)
} }
static void rag_genbodymatrix(skelobject_t *sko, rbebodyinfo_t *dollbody, float *emat, float *result) static void rag_genbodymatrix(skelobject_t *sko, rbebodyinfo_t *dollbody, float *emat, float *result)
{ {
float tmp[12];
float *bmat; float *bmat;
int bone = dollbody->bone; int bone = dollbody->bone;
bmat = sko->bonematrix + bone*12; bmat = sko->bonematrix + bone*12;
if (dollbody->isoffset)
{
R_ConcatTransforms((void*)dollbody->relmatrix, (void*)bmat, (void*)tmp);
bmat = tmp;
}
R_ConcatTransforms((void*)emat, (void*)bmat, (void*)result); R_ConcatTransforms((void*)emat, (void*)bmat, (void*)result);
if (dollbody->orient) if (dollbody->orient)
@ -1331,8 +1353,15 @@ static void rag_derive(skelobject_t *sko, skelobject_t *asko, float *emat)
{ {
//bones with a body are given an absolute pose matching that body. //bones with a body are given an absolute pose matching that body.
sko->world->rbe->RagMatrixFromBody(sko->world, &sko->body[doll->bone[i].bodyidx].odebody, bodymat); sko->world->rbe->RagMatrixFromBody(sko->world, &sko->body[doll->bone[i].bodyidx].odebody, bodymat);
//that body matrix is in world space, so transform to model space for our result if (doll->body[doll->bone[i].bodyidx].isoffset)
R_ConcatTransforms((void*)invemat, (void*)bodymat, (void*)((float*)bmat+i*12)); {
float tmp[12];
R_ConcatTransforms((void*)doll->body[doll->bone[i].bodyidx].inverserelmatrix, (void*)bodymat, (void*)tmp);
R_ConcatTransforms((void*)invemat, (void*)tmp, (void*)((float*)bmat+i*12));
}
else
//that body matrix is in world space, so transform to model space for our result
R_ConcatTransforms((void*)invemat, (void*)bodymat, (void*)((float*)bmat+i*12));
} }
else if (amat) //FIXME: don't do this when the bone has an unanimated child body. else if (amat) //FIXME: don't do this when the bone has an unanimated child body.
{ {
@ -1399,7 +1428,7 @@ void rag_removedeltaent(lerpents_t *le)
return; return;
le->skeletalobject = 0; le->skeletalobject = 0;
skelobj = skel_get(csqc_world.progs, skelidx); skelobj = skel_get(&csqc_world, skelidx);
if (skelobj) if (skelobj)
{ {
skelobj->inuse = 2; //2 means don't reuse yet. skelobj->inuse = 2; //2 means don't reuse yet.
@ -1421,7 +1450,7 @@ void rag_lerpdeltaent(lerpents_t *le, unsigned int bonecount, short *newstate, f
skelobject_t *sko; skelobject_t *sko;
if (le->skeletalobject) if (le->skeletalobject)
{ {
sko = skel_get(csqc_world.progs, le->skeletalobject); sko = skel_get(&csqc_world, le->skeletalobject);
if (sko->numbones != bonecount) if (sko->numbones != bonecount)
{ //unusable, discard it and create a new one. { //unusable, discard it and create a new one.
sko->inuse = 2; //2 means don't reuse yet. sko->inuse = 2; //2 means don't reuse yet.
@ -1435,7 +1464,7 @@ void rag_lerpdeltaent(lerpents_t *le, unsigned int bonecount, short *newstate, f
if (!sko || sko->inuse != 1) if (!sko || sko->inuse != 1)
{ {
sko = skel_create(csqc_world.progs, bonecount); sko = skel_create(&csqc_world, bonecount);
if (!sko) if (!sko)
return; //couldn't get one, ran out of memory or something? return; //couldn't get one, ran out of memory or something?
sko->model = NULL; sko->model = NULL;
@ -1480,10 +1509,8 @@ void rag_lerpdeltaent(lerpents_t *le, unsigned int bonecount, short *newstate, f
} }
} }
void rag_updatedeltaent(entity_t *ent, lerpents_t *le) void rag_updatedeltaent(world_t *w, entity_t *ent, lerpents_t *le)
{ {
extern world_t csqc_world;
world_t *w;
model_t *mod = ent->model; model_t *mod = ent->model;
skelobject_t *sko; skelobject_t *sko;
float emat[12]; float emat[12];
@ -1494,13 +1521,12 @@ void rag_updatedeltaent(entity_t *ent, lerpents_t *le)
if (mod->dollinfo) if (mod->dollinfo)
{ {
w = &csqc_world;
if (!w->rbe) if (!w->rbe)
return; return;
if (!le->skeletalobject) if (!le->skeletalobject)
{ {
sko = skel_create(w->progs, Mod_GetNumBones(mod, false)); sko = skel_create(w, Mod_GetNumBones(mod, false));
if (!sko) if (!sko)
return; //couldn't get one, ran out of memory or something? return; //couldn't get one, ran out of memory or something?
sko->model = mod; sko->model = mod;
@ -1509,7 +1535,7 @@ void rag_updatedeltaent(entity_t *ent, lerpents_t *le)
} }
else else
{ {
sko = skel_get(w->progs, le->skeletalobject); sko = skel_get(w, le->skeletalobject);
if (!sko) if (!sko)
{ {
le->skeletalobject = 0; le->skeletalobject = 0;
@ -1551,8 +1577,7 @@ void rag_updatedeltaent(entity_t *ent, lerpents_t *le)
} }
else if (le->skeletalobject) else if (le->skeletalobject)
{ {
w = &csqc_world; sko = skel_get(w, le->skeletalobject);
sko = skel_get(w->progs, le->skeletalobject);
if (!sko) if (!sko)
{ {
le->skeletalobject = 0; le->skeletalobject = 0;
@ -1574,6 +1599,7 @@ void QCBUILTIN PF_skel_ragedit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
{ {
//do we want to be able to generate a ragdoll object with this function too? //do we want to be able to generate a ragdoll object with this function too?
#ifdef RAGDOLL #ifdef RAGDOLL
world_t *w = prinst->parms->user;
wedict_t *wed = (wedict_t*)G_EDICT(prinst, OFS_PARM0); wedict_t *wed = (wedict_t*)G_EDICT(prinst, OFS_PARM0);
const char *ragname = PR_GetStringOfs(prinst, OFS_PARM1); const char *ragname = PR_GetStringOfs(prinst, OFS_PARM1);
int parentskel = G_FLOAT(OFS_PARM2); int parentskel = G_FLOAT(OFS_PARM2);
@ -1594,11 +1620,11 @@ void QCBUILTIN PF_skel_ragedit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
G_FLOAT(OFS_RETURN) = 0; G_FLOAT(OFS_RETURN) = 0;
//the parent skeletal object must be relative, if specified. //the parent skeletal object must be relative, if specified.
psko = skel_get(prinst, parentskel); psko = skel_get(w, parentskel);
if (psko && psko->type != SKEL_RELATIVE) if (psko && psko->type != SKEL_RELATIVE)
return; return;
sko = skel_get(prinst, skelidx); sko = skel_get(w, skelidx);
if (!sko) if (!sko)
{ {
Con_DPrintf("PF_skel_ragedit: invalid skeletal object\n"); Con_DPrintf("PF_skel_ragedit: invalid skeletal object\n");
@ -1747,7 +1773,7 @@ void QCBUILTIN PF_skel_create (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
return; //this isn't a skeletal model. return; //this isn't a skeletal model.
} }
skelobj = skel_create(prinst, numbones); skelobj = skel_create(w, numbones);
if (!skelobj) if (!skelobj)
return; //couldn't get one, ran out of memory or something? return; //couldn't get one, ran out of memory or something?
@ -1804,9 +1830,9 @@ void QCBUILTIN PF_skel_build(pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
} }
if (!skelidx) if (!skelidx)
skelobj = skel_create(prinst, numbones); skelobj = skel_create(w, numbones);
else else
skelobj = skel_get(prinst, skelidx); skelobj = skel_get(w, skelidx);
if (!skelobj) if (!skelobj)
return; //couldn't get one, ran out of memory or something? return; //couldn't get one, ran out of memory or something?
@ -1888,10 +1914,11 @@ void QCBUILTIN PF_skel_build(pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
//float(float skel) skel_get_numbones (FTE_CSQC_SKELETONOBJECTS) //float(float skel) skel_get_numbones (FTE_CSQC_SKELETONOBJECTS)
void QCBUILTIN PF_skel_get_numbones (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_skel_get_numbones (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
world_t *w = prinst->parms->user;
int skelidx = G_FLOAT(OFS_PARM0); int skelidx = G_FLOAT(OFS_PARM0);
skelobject_t *skelobj; skelobject_t *skelobj;
skelobj = skel_get(prinst, skelidx); skelobj = skel_get(w, skelidx);
if (!skelobj) if (!skelobj)
G_FLOAT(OFS_RETURN) = 0; G_FLOAT(OFS_RETURN) = 0;
@ -1902,11 +1929,12 @@ void QCBUILTIN PF_skel_get_numbones (pubprogfuncs_t *prinst, struct globalvars_s
//string(float skel, float bonenum) skel_get_bonename (FTE_CSQC_SKELETONOBJECTS) (returns tempstring) //string(float skel, float bonenum) skel_get_bonename (FTE_CSQC_SKELETONOBJECTS) (returns tempstring)
void QCBUILTIN PF_skel_get_bonename (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_skel_get_bonename (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
world_t *w = prinst->parms->user;
int skelidx = G_FLOAT(OFS_PARM0); int skelidx = G_FLOAT(OFS_PARM0);
int boneidx = G_FLOAT(OFS_PARM1); int boneidx = G_FLOAT(OFS_PARM1);
skelobject_t *skelobj; skelobject_t *skelobj;
skelobj = skel_get(prinst, skelidx); skelobj = skel_get(w, skelidx);
if (!skelobj) if (!skelobj)
G_INT(OFS_RETURN) = 0; G_INT(OFS_RETURN) = 0;
@ -1919,11 +1947,12 @@ void QCBUILTIN PF_skel_get_bonename (pubprogfuncs_t *prinst, struct globalvars_s
//float(float skel, float bonenum) skel_get_boneparent (FTE_CSQC_SKELETONOBJECTS) //float(float skel, float bonenum) skel_get_boneparent (FTE_CSQC_SKELETONOBJECTS)
void QCBUILTIN PF_skel_get_boneparent (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_skel_get_boneparent (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
world_t *w = prinst->parms->user;
int skelidx = G_FLOAT(OFS_PARM0); int skelidx = G_FLOAT(OFS_PARM0);
int boneidx = G_FLOAT(OFS_PARM1); int boneidx = G_FLOAT(OFS_PARM1);
skelobject_t *skelobj; skelobject_t *skelobj;
skelobj = skel_get(prinst, skelidx); skelobj = skel_get(w, skelidx);
if (!skelobj) if (!skelobj)
G_FLOAT(OFS_RETURN) = 0; G_FLOAT(OFS_RETURN) = 0;
@ -1934,11 +1963,12 @@ void QCBUILTIN PF_skel_get_boneparent (pubprogfuncs_t *prinst, struct globalvars
//float(float skel, string tagname) skel_find_bone (FTE_CSQC_SKELETONOBJECTS) //float(float skel, string tagname) skel_find_bone (FTE_CSQC_SKELETONOBJECTS)
void QCBUILTIN PF_skel_find_bone (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_skel_find_bone (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
world_t *w = prinst->parms->user;
int skelidx = G_FLOAT(OFS_PARM0); int skelidx = G_FLOAT(OFS_PARM0);
const char *bname = PR_GetStringOfs(prinst, OFS_PARM1); const char *bname = PR_GetStringOfs(prinst, OFS_PARM1);
skelobject_t *skelobj; skelobject_t *skelobj;
skelobj = skel_get(prinst, skelidx); skelobj = skel_get(w, skelidx);
if (!skelobj) if (!skelobj)
G_FLOAT(OFS_RETURN) = 0; G_FLOAT(OFS_RETURN) = 0;
else else
@ -1951,7 +1981,7 @@ void QCBUILTIN PF_skel_get_bonerel (pubprogfuncs_t *prinst, struct globalvars_s
world_t *w = prinst->parms->user; world_t *w = prinst->parms->user;
int skelidx = G_FLOAT(OFS_PARM0); int skelidx = G_FLOAT(OFS_PARM0);
int boneidx = G_FLOAT(OFS_PARM1)-1; int boneidx = G_FLOAT(OFS_PARM1)-1;
skelobject_t *skelobj = skel_get(prinst, skelidx); skelobject_t *skelobj = skel_get(w, skelidx);
if (!skelobj || (unsigned int)boneidx >= skelobj->numbones) if (!skelobj || (unsigned int)boneidx >= skelobj->numbones)
bonematident_toqcvectors(w->g.v_forward, w->g.v_right, w->g.v_up, G_VECTOR(OFS_RETURN)); bonematident_toqcvectors(w->g.v_forward, w->g.v_right, w->g.v_up, G_VECTOR(OFS_RETURN));
else if (skelobj->type!=SKEL_RELATIVE) else if (skelobj->type!=SKEL_RELATIVE)
@ -1977,7 +2007,7 @@ void QCBUILTIN PF_skel_get_boneabs (pubprogfuncs_t *prinst, struct globalvars_s
int boneidx = G_FLOAT(OFS_PARM1)-1; int boneidx = G_FLOAT(OFS_PARM1)-1;
float workingm[12], tempmatrix[3][4]; float workingm[12], tempmatrix[3][4];
int i; int i;
skelobject_t *skelobj = skel_get(prinst, skelidx); skelobject_t *skelobj = skel_get(w, skelidx);
if (!skelobj || (unsigned int)boneidx >= skelobj->numbones) if (!skelobj || (unsigned int)boneidx >= skelobj->numbones)
bonematident_toqcvectors(w->g.v_forward, w->g.v_right, w->g.v_up, G_VECTOR(OFS_RETURN)); bonematident_toqcvectors(w->g.v_forward, w->g.v_right, w->g.v_up, G_VECTOR(OFS_RETURN));
@ -2050,7 +2080,7 @@ void QCBUILTIN PF_skel_set_bone_world (pubprogfuncs_t *prinst, struct globalvars
} }
/*make sure the skeletal object is correct*/ /*make sure the skeletal object is correct*/
skelobj = skel_get(prinst, ent->xv->skeletonindex); skelobj = skel_get(w, ent->xv->skeletonindex);
if (!skelobj || boneidx >= skelobj->numbones) if (!skelobj || boneidx >= skelobj->numbones)
return; return;
@ -2101,7 +2131,7 @@ void QCBUILTIN PF_skel_set_bone (pubprogfuncs_t *prinst, struct globalvars_s *pr
matrix[2] = w->g.v_up; matrix[2] = w->g.v_up;
} }
skelobj = skel_get(prinst, skelidx); skelobj = skel_get(w, skelidx);
if (!skelobj || boneidx >= skelobj->numbones) if (!skelobj || boneidx >= skelobj->numbones)
return; return;
@ -2123,7 +2153,7 @@ void QCBUILTIN PF_skel_mul_bone (pubprogfuncs_t *prinst, struct globalvars_s *pr
else else
bonemat_fromqcvectors((float*)mult, w->g.v_forward, w->g.v_right, w->g.v_up, G_VECTOR(OFS_PARM2)); bonemat_fromqcvectors((float*)mult, w->g.v_forward, w->g.v_right, w->g.v_up, G_VECTOR(OFS_PARM2));
skelobj = skel_get(prinst, skelidx); skelobj = skel_get(w, skelidx);
if (!skelobj || boneidx >= skelobj->numbones) if (!skelobj || boneidx >= skelobj->numbones)
return; return;
//testme //testme
@ -2148,7 +2178,7 @@ void QCBUILTIN PF_skel_mul_bones (pubprogfuncs_t *prinst, struct globalvars_s *p
else else
bonemat_fromqcvectors((float*)mult, w->g.v_forward, w->g.v_right, w->g.v_up, G_VECTOR(OFS_PARM3)); bonemat_fromqcvectors((float*)mult, w->g.v_forward, w->g.v_right, w->g.v_up, G_VECTOR(OFS_PARM3));
skelobj = skel_get(prinst, skelidx); skelobj = skel_get(w, skelidx);
if (!skelobj) if (!skelobj)
return; return;
@ -2173,6 +2203,7 @@ void QCBUILTIN PF_skel_mul_bones (pubprogfuncs_t *prinst, struct globalvars_s *p
//void(float skeldst, float skelsrc, float startbone, float entbone) skel_copybones (FTE_CSQC_SKELETONOBJECTS) //void(float skeldst, float skelsrc, float startbone, float entbone) skel_copybones (FTE_CSQC_SKELETONOBJECTS)
void QCBUILTIN PF_skel_copybones (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_skel_copybones (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
world_t *w = prinst->parms->user;
int skeldst = G_FLOAT(OFS_PARM0); int skeldst = G_FLOAT(OFS_PARM0);
int skelsrc = G_FLOAT(OFS_PARM1); int skelsrc = G_FLOAT(OFS_PARM1);
int startbone = G_FLOAT(OFS_PARM2)-1; int startbone = G_FLOAT(OFS_PARM2)-1;
@ -2181,8 +2212,8 @@ void QCBUILTIN PF_skel_copybones (pubprogfuncs_t *prinst, struct globalvars_s *p
skelobject_t *skelobjdst; skelobject_t *skelobjdst;
skelobject_t *skelobjsrc; skelobject_t *skelobjsrc;
skelobjdst = skel_get(prinst, skeldst); skelobjdst = skel_get(w, skeldst);
skelobjsrc = skel_get(prinst, skelsrc); skelobjsrc = skel_get(w, skelsrc);
if (!skelobjdst || !skelobjsrc) if (!skelobjdst || !skelobjsrc)
return; return;
if (startbone == -1) if (startbone == -1)
@ -2220,10 +2251,11 @@ void QCBUILTIN PF_skel_copybones (pubprogfuncs_t *prinst, struct globalvars_s *p
//void(float skel) skel_delete (FTE_CSQC_SKELETONOBJECTS) //void(float skel) skel_delete (FTE_CSQC_SKELETONOBJECTS)
void QCBUILTIN PF_skel_delete (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_skel_delete (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
world_t *w = prinst->parms->user;
int skelidx = G_FLOAT(OFS_PARM0); int skelidx = G_FLOAT(OFS_PARM0);
skelobject_t *skelobj; skelobject_t *skelobj;
skelobj = skel_get(prinst, skelidx); skelobj = skel_get(w, skelidx);
if (skelobj) if (skelobj)
{ {
skelobj->inuse = 2; //2 means don't reuse yet. skelobj->inuse = 2; //2 means don't reuse yet.
@ -2344,6 +2376,238 @@ void QCBUILTIN PF_modelframecount (pubprogfuncs_t *prinst, struct globalvars_s *
G_FLOAT(OFS_RETURN) = 0; G_FLOAT(OFS_RETURN) = 0;
} }
//void(float modidx, float framenum, __inout float basetime, float targettime, void(float timestamp, int code, string data) callback)
void QCBUILTIN PF_processmodelevents (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
world_t *w = prinst->parms->user;
unsigned int modelindex = G_FLOAT(OFS_PARM0);
unsigned int frame = G_FLOAT(OFS_PARM1);
float basetime = G_FLOAT(OFS_PARM2);
float targettime = G_FLOAT(OFS_PARM3);
func_t callback = G_INT(OFS_PARM4);
model_t *mod = w->Get_CModel(w, modelindex);
float starttime, timestamp;
if (targettime == basetime)
return; //don't refire the same event multiple times.
//returns all basetime <= eventtime < targettime
if (mod)
{
if (mod->type == mod_alias)
{ //slightly more optimised path that is kinda redundant, but w/e
galiasinfo_t *ga = Mod_Extradata(mod);
galiasanimation_t *anim = ga->ofsanimations + frame;
galiasevent_t *ev;
float loopduration;
if (frame < (unsigned int)ga->numanimations && anim->events)
{
if (anim->loop)
{
loopduration = anim->rate * anim->numposes;
starttime = loopduration*(unsigned int)(basetime/loopduration);
}
else
starttime = loopduration = 0;
for (ev = anim->events; ; )
{
//be careful to use as consistent timings as we can
timestamp = starttime + ev->timestamp;
if (timestamp >= targettime)
break; //this is in the future.
if (timestamp >= basetime)
{
G_FLOAT(OFS_PARM0) = timestamp;
G_INT(OFS_PARM1) = ev->code;
G_INT(OFS_PARM2) = PR_TempString(prinst, ev->data);
PR_ExecuteProgram(prinst, callback);
}
ev = ev->next;
if (!ev)
{
if (loopduration)
ev = anim->events;
else
break; //animation ends here, so no more events possible
starttime += loopduration;
}
}
}
}
#ifdef HALFLIFEMODELS
else //actually this is a generic version that would work for iqm etc too, but is less efficient due to repeated lookups. oh well.
{
int ev, code;
char *data;
float loopduration;
qboolean looping;
if (Mod_FrameInfoForNum(mod, 0, frame, &data, &code, &loopduration, &looping))
{
if (looping && loopduration)
starttime = loopduration*(unsigned int)(basetime/loopduration);
else
starttime = loopduration = 0;
for (ev = 0; ; ev++)
{
if (!Mod_GetModelEvent(mod, frame, ev, &timestamp, &code, &data))
{
if (looping && Mod_GetModelEvent(mod, frame, 0, &timestamp, &code, &data))
{
ev = 0;
starttime += loopduration;
}
else
break; //end of anim
}
//be careful to use as consistent timings as we can...
timestamp += starttime;
if (timestamp >= targettime)
break; //this is in the future.
if (timestamp >= basetime)
{
G_FLOAT(OFS_PARM0) = timestamp;
G_INT(OFS_PARM1) = code;
G_INT(OFS_PARM2) = PR_TempString(prinst, data);
PR_ExecuteProgram(prinst, callback);
}
}
}
}
#endif
}
G_FLOAT(OFS_PARM2) = targettime;
}
//float(float modidx, float framenum, __inout float basetime, float targettime, __out int code, __out string data)
void QCBUILTIN PF_getnextmodelevent (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
world_t *w = prinst->parms->user;
unsigned int modelindex = G_FLOAT(OFS_PARM0);
unsigned int frame = G_FLOAT(OFS_PARM1);
float basetime = G_FLOAT(OFS_PARM2);
float targettime = G_FLOAT(OFS_PARM3);
model_t *mod = w->Get_CModel(w, modelindex);
float starttime, timestamp;
//default return values
G_FLOAT(OFS_RETURN) = false;
G_FLOAT(OFS_PARM2) = targettime;
G_INT(OFS_PARM4) = 0;
G_INT(OFS_PARM5) = 0;
if (mod)
{
if (mod->type == mod_alias)
{ //slightly more optimised path that is kinda redundant, but w/e
galiasinfo_t *ga = Mod_Extradata(mod);
galiasanimation_t *anim = ga->ofsanimations + frame;
galiasevent_t *ev;
float loopduration;
if (frame >= (unsigned int)ga->numanimations || !anim->events)
return;
if (anim->loop)
{
loopduration = anim->rate * anim->numposes;
starttime = loopduration*(unsigned int)(basetime/loopduration);
}
else
starttime = loopduration = 0;
for (ev = anim->events; ; )
{
//be careful to use as consistent timings as we can
timestamp = starttime + ev->timestamp;
if (timestamp > targettime)
break; //this is in the future.
if (timestamp > basetime)
{
G_FLOAT(OFS_RETURN) = true;
G_FLOAT(OFS_PARM2) = timestamp;
G_INT(OFS_PARM4) = ev->code;
G_INT(OFS_PARM5) = PR_TempString(prinst, ev->data);
return;
}
ev = ev->next;
if (!ev)
{
if (loopduration)
ev = anim->events;
else
return; //animation ended here, so no more events
starttime += loopduration;
}
}
}
#ifdef HALFLIFEMODELS
else //actually this is a generic version that would work for iqm etc too, but is less efficient due to repeated lookups. oh well.
{
int ev, code;
char *data;
float loopduration;
qboolean looping;
if (!Mod_FrameInfoForNum(mod, 0, frame, &data, &code, &loopduration, &looping))
return; //invalid frame
if (looping && loopduration)
starttime = loopduration*(unsigned int)(basetime/loopduration);
else
starttime = loopduration = 0;
for (ev = 0; ; ev++)
{
if (!Mod_GetModelEvent(mod, frame, ev, &timestamp, &code, &data))
{
if (looping && Mod_GetModelEvent(mod, frame, 0, &timestamp, &code, &data))
{
ev = 0;
starttime += loopduration;
}
else
break; //end of anim
}
//be careful to use as consistent timings as we can...
timestamp += starttime;
if (timestamp > targettime)
break; //this is in the future.
if (timestamp > basetime)
{
G_FLOAT(OFS_RETURN) = true;
G_FLOAT(OFS_PARM2) = timestamp;
G_INT(OFS_PARM4) = code;
G_INT(OFS_PARM5) = PR_TempString(prinst, data);
return;
}
}
}
#endif
}
}
//float(float modidx, float framenum, int idx, __out float timestamp, __out int code, __out string data)
void QCBUILTIN PF_getmodeleventidx (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
world_t *w = prinst->parms->user;
unsigned int modelindex = G_FLOAT(OFS_PARM0);
unsigned int frame = G_FLOAT(OFS_PARM1);
int eventindex = G_INT(OFS_PARM2);
model_t *mod = w->Get_CModel(w, modelindex);
//default return values
float timestamp = 0;
int code = 0;
char *data = NULL;
G_FLOAT(OFS_RETURN) = Mod_GetModelEvent(mod, frame, eventindex, &timestamp, &code, &data);
G_FLOAT(OFS_PARM3) = timestamp;
G_INT(OFS_PARM4) = code;
if (data)
G_INT(OFS_PARM5) = PR_TempString(prinst, data);
else
G_INT(OFS_PARM5) = 0;
}
//string(float modidx, float skinnum) skintoname //string(float modidx, float skinnum) skintoname
void QCBUILTIN PF_skintoname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_skintoname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {

View file

@ -660,6 +660,7 @@ void R2D_Image2dQuad(vec2_t points[], vec2_t texcoords[], mpic_t *pic)
{ {
Vector2Copy(points[i], draw_mesh_xyz[i]); Vector2Copy(points[i], draw_mesh_xyz[i]);
Vector2Copy(texcoords[i], draw_mesh_st[i]); Vector2Copy(texcoords[i], draw_mesh_st[i]);
Vector4Copy(draw_active_colour, draw_mesh_colors[i]);
} }
BE_DrawMesh_Single(pic, &draw_mesh, NULL, r2d_be_flags); BE_DrawMesh_Single(pic, &draw_mesh, NULL, r2d_be_flags);

View file

@ -1160,7 +1160,7 @@ void P_DefaultTrail (unsigned int entityeffects, unsigned int modelflags, int *t
*trailid = P_FindParticleType("tr_scarab"); *trailid = P_FindParticleType("tr_scarab");
*trailpalidx = 254; *trailpalidx = 254;
} }
else if (modelflags & MFH2_ROCKET) else if (modelflags & MFH2_SPIDERBLOOD)
{ {
//spiders //spiders
*trailid = P_FindParticleType("TR_GREENBLOOD"); *trailid = P_FindParticleType("TR_GREENBLOOD");

View file

@ -1889,7 +1889,7 @@ start:
Surf_RecursiveWorldNode (node->children[side], clipflags); Surf_RecursiveWorldNode (node->children[side], clipflags);
// draw stuff // draw stuff
c = node->numsurfaces; c = node->numsurfaces;
if (c) if (c)
{ {
@ -2907,6 +2907,8 @@ void R_GenWorldEBO(void *ctx, void *data, size_t a, size_t b)
} }
else else
#endif #endif
#ifdef Q1BSPS
if (es->wmodel->fromgame == fg_quake || es->wmodel->fromgame == fg_halflife)
{ {
//maybe we should just use fatpvs instead, and wait for completion when outside? //maybe we should just use fatpvs instead, and wait for completion when outside?
if (es->leaf[1]) if (es->leaf[1])
@ -2926,6 +2928,11 @@ void R_GenWorldEBO(void *ctx, void *data, size_t a, size_t b)
} }
Surf_SimpleWorld_Q1BSP(es, pvs); Surf_SimpleWorld_Q1BSP(es, pvs);
} }
else
#endif
{
//panic
}
COM_AddWork(WG_MAIN, R_GeneratedWorldEBO, es, NULL, 0, 0); COM_AddWork(WG_MAIN, R_GeneratedWorldEBO, es, NULL, 0, 0);
} }
@ -2963,12 +2970,12 @@ void Surf_DrawWorld (void)
{ {
RSpeedRemark(); RSpeedRemark();
Surf_LightmapShift(cl.worldmodel); Surf_LightmapShift(currentmodel);
#ifdef THREADEDWORLD #ifdef THREADEDWORLD
if ((r_dynamic.ival < 0 || cl.worldmodel->numbatches) && !r_refdef.recurse && cl.worldmodel->type == mod_brush) if ((r_dynamic.ival < 0 || currentmodel->numbatches) && !r_refdef.recurse && currentmodel->type == mod_brush)
{ {
if (webostate && webostate->wmodel != cl.worldmodel) if (webostate && webostate->wmodel != currentmodel)
{ {
R_DestroyWorldEBO(webostate); R_DestroyWorldEBO(webostate);
webostate = NULL; webostate = NULL;
@ -2976,7 +2983,8 @@ void Surf_DrawWorld (void)
if (qrenderer != QR_OPENGL && qrenderer != QR_VULKAN) if (qrenderer != QR_OPENGL && qrenderer != QR_VULKAN)
; ;
else if (cl.worldmodel->fromgame == fg_quake) #ifdef Q1BSPS
else if (currentmodel->fromgame == fg_quake || currentmodel->fromgame == fg_halflife)
{ {
int i = MAX_LIGHTSTYLES; int i = MAX_LIGHTSTYLES;
if (webostate && !webogenerating) if (webostate && !webogenerating)
@ -2993,21 +3001,21 @@ void Surf_DrawWorld (void)
if (!webogenerating) if (!webogenerating)
{ {
int i; int i;
if (!cl.worldmodel->numbatches) if (!currentmodel->numbatches)
{ {
int sortid; int sortid;
batch_t *batch; batch_t *batch;
cl.worldmodel->numbatches = 0; currentmodel->numbatches = 0;
for (sortid = 0; sortid < SHADER_SORT_COUNT; sortid++) for (sortid = 0; sortid < SHADER_SORT_COUNT; sortid++)
for (batch = cl.worldmodel->batches[sortid]; batch != NULL; batch = batch->next) for (batch = currentmodel->batches[sortid]; batch != NULL; batch = batch->next)
{ {
batch->ebobatch = cl.worldmodel->numbatches; batch->ebobatch = currentmodel->numbatches;
cl.worldmodel->numbatches++; currentmodel->numbatches++;
} }
} }
webogeneratingstate = true; webogeneratingstate = true;
webogenerating = BZ_Malloc(sizeof(*webogenerating) + sizeof(webogenerating->batches[0]) * (cl.worldmodel->numbatches-1)); webogenerating = BZ_Malloc(sizeof(*webogenerating) + sizeof(webogenerating->batches[0]) * (currentmodel->numbatches-1));
webogenerating->wmodel = cl.worldmodel; webogenerating->wmodel = currentmodel;
webogenerating->leaf[0] = r_viewleaf; webogenerating->leaf[0] = r_viewleaf;
webogenerating->leaf[1] = r_viewleaf2; webogenerating->leaf[1] = r_viewleaf2;
for (i = 0; i < MAX_LIGHTSTYLES; i++) for (i = 0; i < MAX_LIGHTSTYLES; i++)
@ -3017,7 +3025,9 @@ void Surf_DrawWorld (void)
} }
} }
} }
else if (cl.worldmodel->fromgame == fg_quake3) #endif
#ifdef Q3BSPS
else if (currentmodel->fromgame == fg_quake3)
{ {
if (webostate && webostate->cluster[0] == r_viewcluster && webostate->cluster[1] == r_viewcluster2) if (webostate && webostate->cluster[0] == r_viewcluster && webostate->cluster[1] == r_viewcluster2)
{ {
@ -3026,21 +3036,21 @@ void Surf_DrawWorld (void)
{ {
if (!webogenerating) if (!webogenerating)
{ {
if (!cl.worldmodel->numbatches) if (!currentmodel->numbatches)
{ {
int sortid; int sortid;
batch_t *batch; batch_t *batch;
cl.worldmodel->numbatches = 0; currentmodel->numbatches = 0;
for (sortid = 0; sortid < SHADER_SORT_COUNT; sortid++) for (sortid = 0; sortid < SHADER_SORT_COUNT; sortid++)
for (batch = cl.worldmodel->batches[sortid]; batch != NULL; batch = batch->next) for (batch = currentmodel->batches[sortid]; batch != NULL; batch = batch->next)
{ {
batch->ebobatch = cl.worldmodel->numbatches; batch->ebobatch = currentmodel->numbatches;
cl.worldmodel->numbatches++; currentmodel->numbatches++;
} }
} }
webogeneratingstate = true; webogeneratingstate = true;
webogenerating = BZ_Malloc(sizeof(*webogenerating) + sizeof(webogenerating->batches[0]) * (cl.worldmodel->numbatches-1)); webogenerating = BZ_Malloc(sizeof(*webogenerating) + sizeof(webogenerating->batches[0]) * (currentmodel->numbatches-1));
webogenerating->wmodel = cl.worldmodel; webogenerating->wmodel = currentmodel;
webogenerating->cluster[0] = r_viewcluster; webogenerating->cluster[0] = r_viewcluster;
webogenerating->cluster[1] = r_viewcluster2; webogenerating->cluster[1] = r_viewcluster2;
Q_strncpyz(webogenerating->dbgid, "webostate", sizeof(webogenerating->dbgid)); Q_strncpyz(webogenerating->dbgid, "webostate", sizeof(webogenerating->dbgid));
@ -3048,6 +3058,7 @@ void Surf_DrawWorld (void)
} }
} }
} }
#endif
if (webostate) if (webostate)
{ {
@ -3065,7 +3076,7 @@ void Surf_DrawWorld (void)
BE_DrawWorld(webostate->rbatches); BE_DrawWorld(webostate->rbatches);
/*FIXME: move this away*/ /*FIXME: move this away*/
if (cl.worldmodel->fromgame == fg_quake || cl.worldmodel->fromgame == fg_halflife) if (currentmodel->fromgame == fg_quake || currentmodel->fromgame == fg_halflife)
Surf_LessenStains(); Surf_LessenStains();
return; return;
} }
@ -3073,26 +3084,34 @@ void Surf_DrawWorld (void)
#endif #endif
Surf_PushChains(cl.worldmodel->batches); Surf_PushChains(currentmodel->batches);
#ifdef TERRAIN
if (currentmodel->type == mod_heightmap)
{
frustumvis = NULL;
entvis = surfvis = NULL;
}
else
#endif
#ifdef Q2BSPS #ifdef Q2BSPS
if (cl.worldmodel->fromgame == fg_quake2 || cl.worldmodel->fromgame == fg_quake3) if (currentmodel->fromgame == fg_quake2 || currentmodel->fromgame == fg_quake3)
{ {
frustumvis = frustumvis_; frustumvis = frustumvis_;
memset(frustumvis, 0, (cl.worldmodel->numclusters + 7)>>3); memset(frustumvis, 0, (currentmodel->numclusters + 7)>>3);
if (!r_refdef.areabitsknown) if (!r_refdef.areabitsknown)
{ //generate the info each frame, as the gamecode didn't tell us what to use. { //generate the info each frame, as the gamecode didn't tell us what to use.
int leafnum = CM_PointLeafnum (cl.worldmodel, r_refdef.vieworg); int leafnum = CM_PointLeafnum (currentmodel, r_refdef.vieworg);
int clientarea = CM_LeafArea (cl.worldmodel, leafnum); int clientarea = CM_LeafArea (currentmodel, leafnum);
CM_WriteAreaBits(cl.worldmodel, r_refdef.areabits, clientarea, false); CM_WriteAreaBits(currentmodel, r_refdef.areabits, clientarea, false);
r_refdef.areabitsknown = true; r_refdef.areabitsknown = true;
} }
#ifdef Q3BSPS #ifdef Q3BSPS
if (cl.worldmodel->fromgame == fg_quake3) if (currentmodel->fromgame == fg_quake3)
{ {
entvis = surfvis = R_MarkLeaves_Q3 (); entvis = surfvis = R_MarkLeaves_Q3 ();
Surf_RecursiveQ3WorldNode (cl.worldmodel->nodes, (1<<r_refdef.frustum_numworldplanes)-1); Surf_RecursiveQ3WorldNode (currentmodel->nodes, (1<<r_refdef.frustum_numworldplanes)-1);
//Surf_LeafWorldNode (); //Surf_LeafWorldNode ();
} }
else else
@ -3100,7 +3119,7 @@ void Surf_DrawWorld (void)
{ {
entvis = surfvis = R_MarkLeaves_Q2 (); entvis = surfvis = R_MarkLeaves_Q2 ();
VectorCopy (r_refdef.vieworg, modelorg); VectorCopy (r_refdef.vieworg, modelorg);
Surf_RecursiveQ2WorldNode (cl.worldmodel->nodes); Surf_RecursiveQ2WorldNode (currentmodel->nodes);
} }
surfvis = frustumvis; surfvis = frustumvis;
@ -3108,9 +3127,9 @@ void Surf_DrawWorld (void)
else else
#endif #endif
#ifdef MAP_PROC #ifdef MAP_PROC
if (cl.worldmodel->fromgame == fg_doom3) if (currentmodel->fromgame == fg_doom3)
{ {
entvis = surfvis = D3_CalcVis(cl.worldmodel, r_origin); entvis = surfvis = D3_CalcVis(currentmodel, r_origin);
} }
else else
#endif #endif
@ -3122,14 +3141,8 @@ void Surf_DrawWorld (void)
} }
else else
#endif #endif
#ifdef TERRAIN #ifdef Q1BSPS
if (currentmodel->type == mod_heightmap) if (1)
{
frustumvis = NULL;
entvis = surfvis = NULL;
}
else
#endif
{ {
//extern cvar_t temp1; //extern cvar_t temp1;
// if (0)//temp1.value) // if (0)//temp1.value)
@ -3141,15 +3154,21 @@ void Surf_DrawWorld (void)
VectorCopy (r_origin, modelorg); VectorCopy (r_origin, modelorg);
frustumvis = frustumvis_; frustumvis = frustumvis_;
memset(frustumvis, 0, (cl.worldmodel->numclusters + 7)>>3); memset(frustumvis, 0, (currentmodel->numclusters + 7)>>3);
if (r_refdef.useperspective) if (r_refdef.useperspective)
Surf_RecursiveWorldNode (cl.worldmodel->nodes, 0x1f); Surf_RecursiveWorldNode (currentmodel->nodes, 0x1f);
else else
Surf_OrthoRecursiveWorldNode (cl.worldmodel->nodes, 0x1f); Surf_OrthoRecursiveWorldNode (currentmodel->nodes, 0x1f);
surfvis = frustumvis; surfvis = frustumvis;
} }
} }
else
#endif
{
frustumvis = NULL;
entvis = surfvis = NULL;
}
RSpeedEnd(RSPEED_WORLDNODE); RSpeedEnd(RSPEED_WORLDNODE);

View file

@ -1046,6 +1046,7 @@ rendererinfo_t swrendererinfo;
#endif #endif
#ifdef VKQUAKE #ifdef VKQUAKE
rendererinfo_t vkrendererinfo; rendererinfo_t vkrendererinfo;
//rendererinfo_t headlessvkrendererinfo;
#endif #endif
rendererinfo_t headlessrenderer; rendererinfo_t headlessrenderer;
@ -1074,6 +1075,9 @@ rendererinfo_t *rendererinfo[] =
&dedicatedrendererinfo, &dedicatedrendererinfo,
#endif #endif
&headlessrenderer, &headlessrenderer,
#ifdef VKQUAKE
//&headlessvkrendererinfo,
#endif
}; };
@ -1863,7 +1867,7 @@ void R_SetRenderer_f (void)
for (i = 0; i < sizeof(rendererinfo)/sizeof(rendererinfo[0]); i++) for (i = 0; i < sizeof(rendererinfo)/sizeof(rendererinfo[0]); i++)
{ {
if (rendererinfo[i]->description) if (rendererinfo[i]->description)
Con_Printf("^1%s^7: %s%s\n", rendererinfo[i]->name[0], rendererinfo[i]->description, (currentrendererstate.renderer == rendererinfo[i])?" ^2(current)":""); Con_Printf("^[%s\\type\\/setrenderer %s^]^7: %s%s\n", rendererinfo[i]->name[0], rendererinfo[i]->name[0], rendererinfo[i]->description, (currentrendererstate.renderer == rendererinfo[i])?" ^2(current)":"");
} }
return; return;
} }
@ -1880,7 +1884,7 @@ void R_SetRenderer_f (void)
Cvar_Set(&vid_bpp, Cmd_Argv(2)); Cvar_Set(&vid_bpp, Cmd_Argv(2));
} }
if (newr.renderer->rtype != QR_HEADLESS) //don't save headless in the vid_renderer cvar via the setrenderer command. 'setrenderer headless;vid_restart' can then do what is most sane. if (newr.renderer->rtype != QR_HEADLESS && !strstr(param, "headless")) //don't save headless in the vid_renderer cvar via the setrenderer command. 'setrenderer headless;vid_restart' can then do what is most sane.
Cvar_Set(&vid_renderer, param); Cvar_Set(&vid_renderer, param);
if (!r_blockvidrestart) if (!r_blockvidrestart)
@ -2279,6 +2283,7 @@ qbyte *R_MarkLeaves_Q2 (void)
} }
#endif #endif
#ifdef Q1BSPS
#if 0 #if 0
qbyte *R_CalcVis_Q1 (void) qbyte *R_CalcVis_Q1 (void)
{ {
@ -2420,6 +2425,7 @@ qbyte *R_MarkLeaves_Q1 (qboolean getvisonly)
} }
return vis; return vis;
} }
#endif
/* /*
================= =================

View file

@ -321,8 +321,8 @@ extern cvar_t snd_doppler;
typedef struct typedef struct
{ {
#define NUM_SOURCES MAX_CHANNELS ALuint *source;
ALuint source[NUM_SOURCES]; size_t max_sources;
ALCdevice *OpenAL_Device; ALCdevice *OpenAL_Device;
ALCcontext *OpenAL_Context; ALCcontext *OpenAL_Context;
@ -582,8 +582,12 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, unsigned
int chnum = chan - sc->channel; int chnum = chan - sc->channel;
ALuint buf; ALuint buf;
if (chnum >= NUM_SOURCES) if (chnum >= oali->max_sources)
{
size_t nc = chnum+1+64;
Z_ReallocElements((void**)&oali->source, &oali->max_sources, nc, sizeof(*oali->source));
return; return;
}
//alcMakeContextCurrent //alcMakeContextCurrent
@ -966,7 +970,7 @@ static qboolean OpenAL_Init(soundcardinfo_t *sc, const char *devname)
//S_Info(); //S_Info();
//fixme... //fixme...
memset(oali->source, 0, sizeof(oali->source)); memset(oali->source, 0, sizeof(*oali->source)*oali->max_sources);
PrintALError("alGensources for normal sources"); PrintALError("alGensources for normal sources");
palListenerfv(AL_POSITION, oali->ListenPos); palListenerfv(AL_POSITION, oali->ListenPos);
@ -1107,7 +1111,7 @@ static void OpenAL_Shutdown (soundcardinfo_t *sc)
//alcMakeContextCurrent //alcMakeContextCurrent
palDeleteSources(NUM_SOURCES, oali->source); palDeleteSources(oali->max_sources, oali->source);
/*make sure the buffers are cleared from the sound effects*/ /*make sure the buffers are cleared from the sound effects*/
for (i=0;i<num_sfx;i++) for (i=0;i<num_sfx;i++)

View file

@ -233,7 +233,7 @@ void S_SoundInfo_f(void)
Con_DPrintf(" %s (%i %i, %g %g %g, inactive)\n", sc->channel[i].sfx->name, sc->channel[i].entnum, sc->channel[i].entchannel, sc->channel[i].origin[0], sc->channel[i].origin[1], sc->channel[i].origin[2]); Con_DPrintf(" %s (%i %i, %g %g %g, inactive)\n", sc->channel[i].sfx->name, sc->channel[i].entnum, sc->channel[i].entchannel, sc->channel[i].origin[0], sc->channel[i].origin[1], sc->channel[i].origin[2]);
} }
} }
Con_Printf(" %d/%d/%d/%d active/known/highest/max\n", active, known, sc->total_chans, MAX_CHANNELS); Con_Printf(" %d/%d/%d/%d active/known/highest/max\n", active, known, sc->total_chans, sc->max_chans);
for (i = 0; i < sc->sn.numchannels; i++) for (i = 0; i < sc->sn.numchannels; i++)
{ {
Con_Printf(" chan %i: fwd:%-4g rt:%-4g up:%-4g dist:%-4g\n", i, sc->speakerdir[i][0], sc->speakerdir[i][1], sc->speakerdir[i][2], sc->dist[i]); Con_Printf(" chan %i: fwd:%-4g rt:%-4g up:%-4g dist:%-4g\n", i, sc->speakerdir[i][0], sc->speakerdir[i][1], sc->speakerdir[i][2], sc->dist[i]);
@ -2845,9 +2845,10 @@ void S_StopAllSounds(qboolean clear)
} }
sc->total_chans = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS + NUM_MUSICS; // no statics sc->total_chans = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS + NUM_MUSICS; // no statics
Z_ReallocElements((void**)&sc->channel, &sc->max_chans, sc->total_chans, sizeof(*sc->channel));
memcpy(musics, &sc->channel[MUSIC_FIRST], sizeof(musics)); memcpy(musics, &sc->channel[MUSIC_FIRST], sizeof(musics));
Q_memset(sc->channel, 0, MAX_CHANNELS * sizeof(channel_t)); Q_memset(sc->channel, 0, sc->max_chans * sizeof(channel_t));
memcpy(&sc->channel[MUSIC_FIRST], musics, sizeof(musics)); memcpy(&sc->channel[MUSIC_FIRST], musics, sizeof(musics));
if (clear && !sc->selfpainting) //if its self-painting, then the mixer will continue painting anyway (which is important if its still painting music, but otherwise don't stutter at all when loading) if (clear && !sc->selfpainting) //if its self-painting, then the mixer will continue painting anyway (which is important if its still painting music, but otherwise don't stutter at all when loading)
@ -2903,10 +2904,13 @@ void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation)
for (scard = sndcardinfo; scard; scard = scard->next) for (scard = sndcardinfo; scard; scard = scard->next)
{ {
if (scard->total_chans == MAX_CHANNELS) if (scard->total_chans == scard->max_chans)
{ {
Con_Printf ("total_channels == MAX_CHANNELS\n"); if (!ZF_ReallocElements((void**)&scard->channel, &scard->max_chans, scard->max_chans+64, sizeof(*scard->channel)))
continue; {
Con_Printf ("total_channels == MAX_CHANNELS\n");
continue;
}
} }
if (!S_LoadSound (sfx)) if (!S_LoadSound (sfx))
@ -3004,11 +3008,14 @@ S_UpdateAmbientSounds
mleaf_t *Q1BSP_LeafForPoint (model_t *model, vec3_t p); mleaf_t *Q1BSP_LeafForPoint (model_t *model, vec3_t p);
void S_UpdateAmbientSounds (soundcardinfo_t *sc) void S_UpdateAmbientSounds (soundcardinfo_t *sc)
{ {
mleaf_t *l; float vol;
float vol, oldvol;
channel_t *chan; channel_t *chan;
int i; int i;
#ifdef Q1BSPS
mleaf_t *l;
float oldvol;
int ambientlevel[NUM_AMBIENTS]; int ambientlevel[NUM_AMBIENTS];
#endif
if (!snd_ambient) if (!snd_ambient)
return; return;
@ -3073,7 +3080,7 @@ void S_UpdateAmbientSounds (soundcardinfo_t *sc)
} }
} }
#ifdef Q1BSPS
// calc ambient sound levels // calc ambient sound levels
for (i = 0; i < NUM_AMBIENTS; i++) for (i = 0; i < NUM_AMBIENTS; i++)
ambientlevel[i] = 0; ambientlevel[i] = 0;
@ -3140,6 +3147,7 @@ void S_UpdateAmbientSounds (soundcardinfo_t *sc)
if (sc->ChannelUpdate) if (sc->ChannelUpdate)
sc->ChannelUpdate(sc, chan, (oldvol == 0) ^ (sc->ambientlevels[i] == 0)); sc->ChannelUpdate(sc, chan, (oldvol == 0) ^ (sc->ambientlevels[i] == 0));
} }
#endif
} }
struct sndreverbproperties_s *reverbproperties; struct sndreverbproperties_s *reverbproperties;

View file

@ -255,7 +255,6 @@ void OpenAL_CvarInit(void);
// User-setable variables // User-setable variables
// ==================================================================== // ====================================================================
#define MAX_CHANNELS 1024/*tracked sounds (including statics)*/
#define MAX_DYNAMIC_CHANNELS 64 /*playing sounds (identical ones merge)*/ #define MAX_DYNAMIC_CHANNELS 64 /*playing sounds (identical ones merge)*/
@ -331,8 +330,9 @@ struct soundcardinfo_s { //windows has one defined AFTER directsound
//info on which sound effects are playing //info on which sound effects are playing
//FIXME: use a linked list //FIXME: use a linked list
channel_t channel[MAX_CHANNELS]; channel_t *channel;
int total_chans; int total_chans;
int max_chans;
float ambientlevels[NUM_AMBIENTS]; //we use a float instead of the channel's int volume value to avoid framerate dependancies with slow transitions. float ambientlevels[NUM_AMBIENTS]; //we use a float instead of the channel's int volume value to avoid framerate dependancies with slow transitions.

View file

@ -367,12 +367,13 @@ void Sys_CloseLibrary(dllhandle_t *lib)
} }
HMODULE LoadLibraryU(const char *name) HMODULE LoadLibraryU(const char *name)
{ {
HMODULE ret;
if (WinNT) if (WinNT)
{ {
wchar_t wide[MAX_OSPATH]; wchar_t wide[MAX_OSPATH];
widen(wide, sizeof(wide), name); widen(wide, sizeof(wide), name);
return LoadLibraryW(wide); ret = LoadLibraryW(wide);
} }
else else
{ {
@ -380,8 +381,9 @@ HMODULE LoadLibraryU(const char *name)
char ansi[MAX_OSPATH]; char ansi[MAX_OSPATH];
widen(wide, sizeof(wide), name); widen(wide, sizeof(wide), name);
ansi[WideCharToMultiByte(CP_ACP, 0, wide, wcslen(wide), ansi, sizeof(ansi)-1, NULL, NULL)] = 0; ansi[WideCharToMultiByte(CP_ACP, 0, wide, wcslen(wide), ansi, sizeof(ansi)-1, NULL, NULL)] = 0;
return LoadLibraryA(ansi); ret = LoadLibraryA(ansi);
} }
return ret;
} }
dllhandle_t *Sys_LoadLibrary(const char *name, dllfunction_t *funcs) dllhandle_t *Sys_LoadLibrary(const char *name, dllfunction_t *funcs)
{ {
@ -4186,7 +4188,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
{ {
isDedicated = isClusterSlave = true; isDedicated = isClusterSlave = true;
#ifdef _DEBUG #ifdef _DEBUG
MessageBox(0, "Cluster slave", "gah", 0); MessageBox(0, "New cluster slave starting\nAttach to process now, if desired.", "FTEQW", 0);
#endif #endif
} }
#endif #endif

View file

@ -281,4 +281,112 @@ rendererinfo_t headlessrenderer =
Headless_BE_RenderToTextureUpdate2d, Headless_BE_RenderToTextureUpdate2d,
"" ""
}; };
#if 0//def VKQUAKE
#include "../vk/vkrenderer.h"
static qboolean HeadlessVK_CreateSurface(void)
{
vk.surface = VK_NULL_HANDLE; //nothing to create, we're using offscreen rendering.
return true;
}
//static void HeadlessVK_Present(struct vkframe *theframe)
//{
//VK_DoPresent(theframe);
//}
static qboolean HeadlessVK_Init (rendererstate_t *info, unsigned char *palette)
{
extern cvar_t vid_conautoscale;
#ifdef VK_NO_PROTOTYPES
static dllhandle_t *hInstVulkan = NULL;
dllfunction_t vkfuncs[] =
{
{(void**)&vkGetInstanceProcAddr, "vkGetInstanceProcAddr"},
{NULL}
};
if (!hInstVulkan)
hInstVulkan = *info->subrenderer?Sys_LoadLibrary(info->subrenderer, vkfuncs):NULL;
#ifdef _WIN32
if (!hInstVulkan)
hInstVulkan = Sys_LoadLibrary("vulkan-1.dll", vkfuncs);
#else
if (!hInstVulkan)
hInstVulkan = Sys_LoadLibrary("libvulkan.so.1", vkfuncs);
if (!hInstVulkan)
hInstVulkan = Sys_LoadLibrary("libvulkan.so", vkfuncs);
#endif
if (!hInstVulkan)
{
Con_Printf("Unable to load vulkan library\nNo Vulkan drivers are installed\n");
return false;
}
#endif
vid.pixelwidth = 1920;
vid.pixelheight = 1080;
if (!VK_Init(info, NULL, HeadlessVK_CreateSurface, NULL))
return false;
Cvar_ForceCallback(&vid_conautoscale);
return true;
}
rendererinfo_t headlessvkrendererinfo =
{
"Headless Vulkan",
{
"vkheadless"
},
QR_VULKAN,
VK_Draw_Init,
VK_Draw_Shutdown,
VK_UpdateFiltering,
VK_LoadTextureMips,
VK_DestroyTexture,
VK_R_Init,
VK_R_DeInit,
VK_R_RenderView,
HeadlessVK_Init,
GLVID_DeInit,
GLVID_SwapBuffers,
GLVID_ApplyGammaRamps,
WIN_CreateCursor,
WIN_SetCursor,
WIN_DestroyCursor,
GLVID_SetCaption,
VKVID_GetRGBInfo,
VK_SCR_UpdateScreen,
VKBE_SelectMode,
VKBE_DrawMesh_List,
VKBE_DrawMesh_Single,
VKBE_SubmitBatch,
VKBE_GetTempBatch,
VKBE_DrawWorld,
VKBE_Init,
VKBE_GenBrushModelVBO,
VKBE_ClearVBO,
VKBE_UploadAllLightmaps,
VKBE_SelectEntity,
VKBE_SelectDLight,
VKBE_Scissor,
VKBE_LightCullModel,
VKBE_VBO_Begin,
VKBE_VBO_Data,
VKBE_VBO_Finish,
VKBE_VBO_Destroy,
VKBE_RenderToTextureUpdate2d,
"no more"
};
#endif
#endif #endif

View file

@ -173,6 +173,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define SPRMODELS //quake1 sprite models #define SPRMODELS //quake1 sprite models
#define INTERQUAKEMODELS #define INTERQUAKEMODELS
#define RTLIGHTS //realtime lighting #define RTLIGHTS //realtime lighting
#define Q1BSPS //quake 1 bsp support, because we're still a quake engine
#define Q2BSPS //quake 2 bsp support (a dependancy of q3bsp) #define Q2BSPS //quake 2 bsp support (a dependancy of q3bsp)
#define Q3BSPS //quake 3 bsp support #define Q3BSPS //quake 3 bsp support
// #define TERRAIN //heightmap support // #define TERRAIN //heightmap support
@ -234,6 +235,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
// #define DSPMODELS //doom sprites (only needs DOOMWADS to generate the right wad file names) // #define DSPMODELS //doom sprites (only needs DOOMWADS to generate the right wad file names)
#define SPRMODELS //quake1 sprite models #define SPRMODELS //quake1 sprite models
#define SP2MODELS //quake2 sprite models #define SP2MODELS //quake2 sprite models
#define MD1MODELS //quake1 alias models
#define MD2MODELS //quake2 alias models #define MD2MODELS //quake2 alias models
#define MD3MODELS //quake3 alias models #define MD3MODELS //quake3 alias models
#define MD5MODELS //doom3 models #define MD5MODELS //doom3 models
@ -249,6 +251,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
// #define MAP_DOOM //doom map support // #define MAP_DOOM //doom map support
#define MAP_PROC //doom3/quake4 map support #define MAP_PROC //doom3/quake4 map support
//#define WOLF3DSUPPORT //wolfenstein3d map support (not started yet) //#define WOLF3DSUPPORT //wolfenstein3d map support (not started yet)
#define Q1BSPS //quake 1 bsp support, because we're still a quake engine
#define Q2BSPS //quake 2 bsp support #define Q2BSPS //quake 2 bsp support
#define Q3BSPS //quake 3 bsp support #define Q3BSPS //quake 3 bsp support
#define TERRAIN //heightmap support #define TERRAIN //heightmap support

View file

@ -552,7 +552,7 @@ typedef struct
#define Q2CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans #define Q2CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans
#define Q2CONTENTS_LADDER 0x20000000 #define Q2CONTENTS_LADDER 0x20000000
//0x40000000 //0x40000000
//0x80000000 //FTECONTENTS_SKY //0x80000000
#define Q3CONTENTS_SOLID FTECONTENTS_SOLID //0x00000001 // should never be on a brush, only in game #define Q3CONTENTS_SOLID FTECONTENTS_SOLID //0x00000001 // should never be on a brush, only in game
@ -580,7 +580,7 @@ typedef struct
#define Q3CONTENTS_BOTCLIP 0x00400000 #define Q3CONTENTS_BOTCLIP 0x00400000
#define Q3CONTENTS_MOVER 0x00800000 #define Q3CONTENTS_MOVER 0x00800000
#define Q3CONTENTS_ORIGIN Q2CONTENTS_ORIGIN //0x01000000 #define Q3CONTENTS_ORIGIN Q2CONTENTS_ORIGIN //0x01000000
#define Q3CONTENTS_BODY 0x02000000 #define Q3CONTENTS_BODY FTECONTENTS_BODY //0x02000000
#define Q3CONTENTS_CORPSE FTECONTENTS_CORPSE //0x04000000 #define Q3CONTENTS_CORPSE FTECONTENTS_CORPSE //0x04000000
#define Q3CONTENTS_DETAIL Q2CONTENTS_DETAIL //0x08000000 #define Q3CONTENTS_DETAIL Q2CONTENTS_DETAIL //0x08000000
#define Q3CONTENTS_STRUCTURAL 0x10000000 #define Q3CONTENTS_STRUCTURAL 0x10000000

File diff suppressed because it is too large Load diff

View file

@ -32,6 +32,14 @@ typedef struct
vec3_t scale_origin; vec3_t scale_origin;
} galiaspose_t; } galiaspose_t;
typedef struct galiasevent_s
{
struct galiasevent_s *next;
float timestamp;
int code;
char *data;
} galiasevent_t;
//a frame group (aka: animation) //a frame group (aka: animation)
typedef struct typedef struct
{ {
@ -44,6 +52,7 @@ typedef struct
int numposes; int numposes;
float rate; float rate;
galiaspose_t *poseofs; galiaspose_t *poseofs;
galiasevent_t *events;
char name[64]; char name[64];
} galiasanimation_t; } galiasanimation_t;
@ -120,6 +129,14 @@ typedef struct galiasinfo_s
index_t *ofs_indexes; index_t *ofs_indexes;
int numindexes; int numindexes;
//for hitmodel
unsigned int contents; //default CONTENTS_BODY
q2csurface_t csurface; //flags, and also collision name, if useful...
unsigned int surfaceid; //the body reported to qc via trace_surface
float mindist;
float maxdist;
int *ofs_trineighbours; int *ofs_trineighbours;
float lerpcutoff; //hack. should probably be part of the entity structure, but I really don't want new models (and thus code) to have access to this ugly inefficient hack. make your models properly in the first place. float lerpcutoff; //hack. should probably be part of the entity structure, but I really don't want new models (and thus code) to have access to this ugly inefficient hack. make your models properly in the first place.
@ -148,8 +165,6 @@ typedef struct galiasinfo_s
float *baseframeofs; /*non-heirachical*/ float *baseframeofs; /*non-heirachical*/
int numbones; int numbones;
galiasbone_t *ofsbones; galiasbone_t *ofsbones;
//FTE_DEPRECATED int numswtransforms;
//FTE_DEPRECATED galisskeletaltransforms_t *ofsswtransforms;
vecV_t *ofs_skel_xyz; vecV_t *ofs_skel_xyz;
vec3_t *ofs_skel_norm; vec3_t *ofs_skel_norm;

View file

@ -143,10 +143,10 @@ static void QDECL World_Bullet_End(world_t *world)
struct bulletcontext_s *ctx = (struct bulletcontext_s*)world->rbe; struct bulletcontext_s *ctx = (struct bulletcontext_s*)world->rbe;
world->rbe = NULL; world->rbe = NULL;
delete ctx->dworld; delete ctx->dworld;
delete ctx->solver; delete ctx->solver;
delete ctx->collisionconfig; delete ctx->collisionconfig;
delete ctx->collisiondispatcher; delete ctx->collisiondispatcher;
delete ctx->broadphase; delete ctx->broadphase;
delete ctx->ownerfilter; delete ctx->ownerfilter;
Z_Free(ctx); Z_Free(ctx);
} }
@ -819,24 +819,24 @@ public:
trans.setOrigin(org); trans.setOrigin(org);
} }
QCMotionState(wedict_t *ed, world_t *w) QCMotionState(wedict_t *ed, world_t *w)
{ {
dirty = qtrue; dirty = qtrue;
edict = ed; edict = ed;
world = w; world = w;
ReloadMotionState(); ReloadMotionState();
} }
virtual ~QCMotionState() virtual ~QCMotionState()
{ {
} }
virtual void getWorldTransform(btTransform &worldTrans) const virtual void getWorldTransform(btTransform &worldTrans) const
{ {
worldTrans = trans; worldTrans = trans;
} }
virtual void setWorldTransform(const btTransform &worldTrans) virtual void setWorldTransform(const btTransform &worldTrans)
{ {
vec3_t fwd, left, up, offset; vec3_t fwd, left, up, offset;
trans = worldTrans; trans = worldTrans;
@ -872,7 +872,7 @@ public:
// mSceneNode ->setOrientation(rot.w(), rot.x(), rot.y(), rot.z()); // mSceneNode ->setOrientation(rot.w(), rot.x(), rot.y(), rot.z());
// btVector3 pos = worldTrans.getOrigin(); // btVector3 pos = worldTrans.getOrigin();
// mSceneNode ->setPosition(pos.x(), pos.y(), pos.z()); // mSceneNode ->setPosition(pos.x(), pos.y(), pos.z());
} }
}; };
static void World_Bullet_Frame_BodyFromEntity(world_t *world, wedict_t *ed) static void World_Bullet_Frame_BodyFromEntity(world_t *world, wedict_t *ed)

View file

@ -766,7 +766,7 @@ static int QDECL COM_Dir_List(const char *name, qofs_t size, time_t mtime, void
|| !Q_strcasecmp(link, "ent") || !Q_strcasecmp(link, "rtlights") || !Q_strcasecmp(link, "ent") || !Q_strcasecmp(link, "rtlights")
|| !Q_strcasecmp(link, "shader") || !Q_strcasecmp(link, "framegroups")) || !Q_strcasecmp(link, "shader") || !Q_strcasecmp(link, "framegroups"))
Q_snprintfz(link, sizeof(link), "\\edit\\%s", name); Q_snprintfz(link, sizeof(link), "\\edit\\%s", name);
else if (!Q_strcasecmp(link, "tga") || !Q_strcasecmp(link, "png") || !Q_strcasecmp(link, "jpg") || !Q_strcasecmp(link, "jpeg") || !Q_strcasecmp(link, "lmp") || !Q_strcasecmp(link, "pcx")) else if (!Q_strcasecmp(link, "tga") || !Q_strcasecmp(link, "png") || !Q_strcasecmp(link, "jpg") || !Q_strcasecmp(link, "jpeg") || !Q_strcasecmp(link, "lmp") || !Q_strcasecmp(link, "pcx")|| !Q_strcasecmp(link, "bmp"))
{ {
//FIXME: image replacements are getting in the way here. //FIXME: image replacements are getting in the way here.
Q_snprintfz(link, sizeof(link), "\\tiprawimg\\%s\\tip\\(note: image replacement rules are context-dependant, including base path, sub path, extension, or complete replacement via a shader)", name); Q_snprintfz(link, sizeof(link), "\\tiprawimg\\%s\\tip\\(note: image replacement rules are context-dependant, including base path, sub path, extension, or complete replacement via a shader)", name);
@ -1255,6 +1255,9 @@ fail:
return depth+1; return depth+1;
} }
//returns the package/'gamedir/foo.pk3' filename to tell the client to download
//unfortunately foo.pk3 may contain a 'bar.pk3' and downloading dir/foo.pk3/bar.pk3 won't work
//so if loc->search is dir/foo.pk3/bar.pk3 find dir/foo.pk3 instead
char *FS_GetPackageDownloadFilename(flocation_t *loc) char *FS_GetPackageDownloadFilename(flocation_t *loc)
{ {
searchpath_t *sp, *search; searchpath_t *sp, *search;
@ -1263,11 +1266,11 @@ char *FS_GetPackageDownloadFilename(flocation_t *loc)
{ {
for (search = com_searchpaths; search; search = search->next) for (search = com_searchpaths; search; search = search->next)
{ {
if (search != sp && search->handle->GeneratePureCRC) if (search != sp)
{ //only consider files that have a pure hash. this excludes system paths if (search->handle->GeneratePureCRC) //only consider files that have a pure hash. this excludes system paths
if (!strncmp(search->purepath, sp->purepath, strlen(search->purepath))) if (!strncmp(search->purepath, sp->purepath, strlen(search->purepath)))
break; if (sp->purepath[strlen(search->purepath)] == '/') //also ensures that the path gets shorter, avoiding infinite loops as it fights between base+home dirs.
} break;
} }
if (search) if (search)
sp = search; sp = search;
@ -1275,7 +1278,7 @@ char *FS_GetPackageDownloadFilename(flocation_t *loc)
break; break;
} }
if (sp && strchr(sp->purepath, '/')) if (sp && strchr(sp->purepath, '/')) //never allow any packages that are directly sitting in the basedir.
return sp->purepath; return sp->purepath;
return NULL; return NULL;
} }

View file

@ -90,7 +90,7 @@ void CalcSurfaceExtents (model_t *mod, msurface_t *s)
int idx; int idx;
mins[0] = mins[1] = 999999; mins[0] = mins[1] = 999999;
maxs[0] = maxs[1] = -99999; maxs[0] = maxs[1] = -999999;
tex = s->texinfo; tex = s->texinfo;

View file

@ -608,9 +608,12 @@ void VARGS PR_CB_Free(void *mem)
//DP_QC_GETSURFACE //DP_QC_GETSURFACE
static void PF_BuildSurfaceMesh(model_t *model, unsigned int surfnum) static void PF_BuildSurfaceMesh(model_t *model, unsigned int surfnum)
{ {
//this function might be called on dedicated servers.
#ifdef Q1BSPS
void ModQ1_Batches_BuildQ1Q2Poly(model_t *mod, msurface_t *surf, builddata_t *cookie); void ModQ1_Batches_BuildQ1Q2Poly(model_t *mod, msurface_t *surf, builddata_t *cookie);
if (model->fromgame == fg_quake) if (model->fromgame == fg_quake || model->fromgame == fg_halflife)
ModQ1_Batches_BuildQ1Q2Poly(model, &model->surfaces[surfnum], NULL); ModQ1_Batches_BuildQ1Q2Poly(model, &model->surfaces[surfnum], NULL);
#endif
//fixme: q3... //fixme: q3...
} }
// #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE) // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
@ -5852,7 +5855,7 @@ void QCBUILTIN PF_physics_addtorque(pubprogfuncs_t *prinst, struct globalvars_s
void PR_Common_Shutdown(pubprogfuncs_t *progs, qboolean errored) void PR_Common_Shutdown(pubprogfuncs_t *progs, qboolean errored)
{ {
#if defined(SKELETALOBJECTS) || defined(RAGDOLLS) #if defined(SKELETALOBJECTS) || defined(RAGDOLLS)
skel_reset(progs); skel_reset(progs->parms->user);
#endif #endif
PR_fclose_progs(progs); PR_fclose_progs(progs);
search_close_progs(progs, !errored); search_close_progs(progs, !errored);
@ -6221,6 +6224,8 @@ lh_extension_t QSG_Extensions[] = {
{"FTE_FORCEINFOKEY", 1, NULL, {"forceinfokey"}, "Provides an easy way to change a user's userinfo from the server."}, {"FTE_FORCEINFOKEY", 1, NULL, {"forceinfokey"}, "Provides an easy way to change a user's userinfo from the server."},
{"FTE_GFX_QUAKE3SHADERS", 0, NULL, {NULL}, "specifies that the engine has full support for vanilla quake3 shaders"}, {"FTE_GFX_QUAKE3SHADERS", 0, NULL, {NULL}, "specifies that the engine has full support for vanilla quake3 shaders"},
{"FTE_GFX_REMAPSHADER", 0, NULL, {NULL}, "With the raw power of stuffcmds, the r_remapshader console command is exposed! This mystical command can be used to remap any shader to another. Remapped shaders that specify $diffuse etc in some form will inherit the textures implied by the surface."}, {"FTE_GFX_REMAPSHADER", 0, NULL, {NULL}, "With the raw power of stuffcmds, the r_remapshader console command is exposed! This mystical command can be used to remap any shader to another. Remapped shaders that specify $diffuse etc in some form will inherit the textures implied by the surface."},
// {"FTE_GFX_IQM_HITMESH", 0, NULL, {NULL}, "Supports hitmesh iqm extensions. Also supports geomsets and embedded events."},
// {"FTE_GFX_MODELEVENTS", 1, NULL, {"processmodelevents", "getnextmodelevent", "getmodeleventidx"}, "Provides a query for per-animation events in model files, including from progs/foo.mdl.events files."},
{"FTE_ISBACKBUFFERED", 1, NULL, {"isbackbuffered"}, "Allows you to check if a client has too many reliable messages pending."}, {"FTE_ISBACKBUFFERED", 1, NULL, {"isbackbuffered"}, "Allows you to check if a client has too many reliable messages pending."},
{"FTE_MEMALLOC", 4, NULL, {"memalloc", "memfree", "memcpy", "memfill8"}, "Allows dynamically allocating memory. Use pointers to access this memory. Memory will not be saved into saved games."}, {"FTE_MEMALLOC", 4, NULL, {"memalloc", "memfree", "memcpy", "memfill8"}, "Allows dynamically allocating memory. Use pointers to access this memory. Memory will not be saved into saved games."},
#ifndef NOMEDIA #ifndef NOMEDIA

View file

@ -262,10 +262,15 @@ void QCBUILTIN PF_setattachment(pubprogfuncs_t *prinst, struct globalvars_s *pr_
void QCBUILTIN PF_gettaginfo (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_gettaginfo (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_gettagindex (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_gettagindex (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
#endif #endif
void QCBUILTIN PF_processmodelevents (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_getnextmodelevent (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_getmodeleventidx (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
#if defined(SKELETALOBJECTS) || defined(RAGDOLL) #if defined(SKELETALOBJECTS) || defined(RAGDOLL)
void skel_lookup(pubprogfuncs_t *prinst, int skelidx, framestate_t *out); void skel_lookup(world_t *prinst, int skelidx, framestate_t *out);
void skel_dodelete(pubprogfuncs_t *prinst); void skel_dodelete(world_t *world);
void skel_reset(pubprogfuncs_t *prinst); void skel_reset(world_t *world);
#endif #endif
void QCBUILTIN PF_physics_enable(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_physics_enable(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_physics_addforce(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_physics_addforce(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);

File diff suppressed because it is too large Load diff

View file

@ -60,6 +60,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qi", "..\..\plugins\qi\qi.v
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models", "..\..\plugins\models\models.vcproj", "{E6CDA919-628B-45BF-A5DB-FB55179D6443}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models", "..\..\plugins\models\models.vcproj", "{E6CDA919-628B-45BF-A5DB-FB55179D6443}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iqm", "..\..\iqm\iqm.vcproj", "{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
D3DDebug|Win32 = D3DDebug|Win32 D3DDebug|Win32 = D3DDebug|Win32
@ -689,7 +691,6 @@ Global
{74542CA7-48C1-4664-9007-66F751131EA3}.MinGLRelease|Win32.ActiveCfg = Release|Win32 {74542CA7-48C1-4664-9007-66F751131EA3}.MinGLRelease|Win32.ActiveCfg = Release|Win32
{74542CA7-48C1-4664-9007-66F751131EA3}.MinGLRelease|x64.ActiveCfg = Release|Win32 {74542CA7-48C1-4664-9007-66F751131EA3}.MinGLRelease|x64.ActiveCfg = Release|Win32
{74542CA7-48C1-4664-9007-66F751131EA3}.MRelease|Win32.ActiveCfg = Release|Win32 {74542CA7-48C1-4664-9007-66F751131EA3}.MRelease|Win32.ActiveCfg = Release|Win32
{74542CA7-48C1-4664-9007-66F751131EA3}.MRelease|Win32.Build.0 = Release|Win32
{74542CA7-48C1-4664-9007-66F751131EA3}.MRelease|x64.ActiveCfg = Release|Win32 {74542CA7-48C1-4664-9007-66F751131EA3}.MRelease|x64.ActiveCfg = Release|Win32
{74542CA7-48C1-4664-9007-66F751131EA3}.Release Dedicated Server|Win32.ActiveCfg = Release|Win32 {74542CA7-48C1-4664-9007-66F751131EA3}.Release Dedicated Server|Win32.ActiveCfg = Release|Win32
{74542CA7-48C1-4664-9007-66F751131EA3}.Release Dedicated Server|x64.ActiveCfg = Release|Win32 {74542CA7-48C1-4664-9007-66F751131EA3}.Release Dedicated Server|x64.ActiveCfg = Release|Win32
@ -805,7 +806,6 @@ Global
{ED16B405-BDCD-4EB8-BF70-761964301368}.MinGLRelease|Win32.Build.0 = Release|Win32 {ED16B405-BDCD-4EB8-BF70-761964301368}.MinGLRelease|Win32.Build.0 = Release|Win32
{ED16B405-BDCD-4EB8-BF70-761964301368}.MinGLRelease|x64.ActiveCfg = Release|Win32 {ED16B405-BDCD-4EB8-BF70-761964301368}.MinGLRelease|x64.ActiveCfg = Release|Win32
{ED16B405-BDCD-4EB8-BF70-761964301368}.MRelease|Win32.ActiveCfg = Release|Win32 {ED16B405-BDCD-4EB8-BF70-761964301368}.MRelease|Win32.ActiveCfg = Release|Win32
{ED16B405-BDCD-4EB8-BF70-761964301368}.MRelease|Win32.Build.0 = Release|Win32
{ED16B405-BDCD-4EB8-BF70-761964301368}.MRelease|x64.ActiveCfg = Release|Win32 {ED16B405-BDCD-4EB8-BF70-761964301368}.MRelease|x64.ActiveCfg = Release|Win32
{ED16B405-BDCD-4EB8-BF70-761964301368}.Release Dedicated Server|Win32.ActiveCfg = Release|Win32 {ED16B405-BDCD-4EB8-BF70-761964301368}.Release Dedicated Server|Win32.ActiveCfg = Release|Win32
{ED16B405-BDCD-4EB8-BF70-761964301368}.Release Dedicated Server|Win32.Build.0 = Release|Win32 {ED16B405-BDCD-4EB8-BF70-761964301368}.Release Dedicated Server|Win32.Build.0 = Release|Win32
@ -897,7 +897,6 @@ Global
{F756A3D2-025A-43D4-9829-4074753B774B}.MinGLRelease|x64.ActiveCfg = Release|x64 {F756A3D2-025A-43D4-9829-4074753B774B}.MinGLRelease|x64.ActiveCfg = Release|x64
{F756A3D2-025A-43D4-9829-4074753B774B}.MinGLRelease|x64.Build.0 = Release|x64 {F756A3D2-025A-43D4-9829-4074753B774B}.MinGLRelease|x64.Build.0 = Release|x64
{F756A3D2-025A-43D4-9829-4074753B774B}.MRelease|Win32.ActiveCfg = Release|Win32 {F756A3D2-025A-43D4-9829-4074753B774B}.MRelease|Win32.ActiveCfg = Release|Win32
{F756A3D2-025A-43D4-9829-4074753B774B}.MRelease|Win32.Build.0 = Release|Win32
{F756A3D2-025A-43D4-9829-4074753B774B}.MRelease|x64.ActiveCfg = Release|x64 {F756A3D2-025A-43D4-9829-4074753B774B}.MRelease|x64.ActiveCfg = Release|x64
{F756A3D2-025A-43D4-9829-4074753B774B}.MRelease|x64.Build.0 = Release|x64 {F756A3D2-025A-43D4-9829-4074753B774B}.MRelease|x64.Build.0 = Release|x64
{F756A3D2-025A-43D4-9829-4074753B774B}.Release Dedicated Server|Win32.ActiveCfg = Release|x64 {F756A3D2-025A-43D4-9829-4074753B774B}.Release Dedicated Server|Win32.ActiveCfg = Release|x64
@ -1011,6 +1010,60 @@ Global
{E6CDA919-628B-45BF-A5DB-FB55179D6443}.VkRelease|Win32.Build.0 = Release|Win32 {E6CDA919-628B-45BF-A5DB-FB55179D6443}.VkRelease|Win32.Build.0 = Release|Win32
{E6CDA919-628B-45BF-A5DB-FB55179D6443}.VkRelease|x64.ActiveCfg = Release|x64 {E6CDA919-628B-45BF-A5DB-FB55179D6443}.VkRelease|x64.ActiveCfg = Release|x64
{E6CDA919-628B-45BF-A5DB-FB55179D6443}.VkRelease|x64.Build.0 = Release|x64 {E6CDA919-628B-45BF-A5DB-FB55179D6443}.VkRelease|x64.Build.0 = Release|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.D3DDebug|Win32.ActiveCfg = Debug|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.D3DDebug|Win32.Build.0 = Debug|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.D3DDebug|x64.ActiveCfg = Debug|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.D3DDebug|x64.Build.0 = Debug|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.D3DRelease|Win32.ActiveCfg = Release|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.D3DRelease|Win32.Build.0 = Release|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.D3DRelease|x64.ActiveCfg = Release|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.D3DRelease|x64.Build.0 = Release|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.Debug Dedicated Server|Win32.ActiveCfg = Debug|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.Debug Dedicated Server|x64.ActiveCfg = Debug|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.Debug Dedicated Server|x64.Build.0 = Debug|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.Debug|Win32.ActiveCfg = Debug|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.Debug|Win32.Build.0 = Debug|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.Debug|x64.ActiveCfg = Debug|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.Debug|x64.Build.0 = Debug|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.GLDebug|Win32.ActiveCfg = Debug|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.GLDebug|Win32.Build.0 = Debug|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.GLDebug|x64.ActiveCfg = Debug|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.GLDebug|x64.Build.0 = Debug|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.GLRelease|Win32.ActiveCfg = Release|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.GLRelease|Win32.Build.0 = Release|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.GLRelease|x64.ActiveCfg = Release|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.GLRelease|x64.Build.0 = Release|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.MDebug|Win32.ActiveCfg = Debug|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.MDebug|Win32.Build.0 = Debug|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.MDebug|x64.ActiveCfg = Debug|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.MDebug|x64.Build.0 = Debug|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.MinGLDebug|Win32.ActiveCfg = Debug|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.MinGLDebug|Win32.Build.0 = Debug|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.MinGLDebug|x64.ActiveCfg = Debug|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.MinGLDebug|x64.Build.0 = Debug|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.MinGLRelease|Win32.ActiveCfg = Release|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.MinGLRelease|Win32.Build.0 = Release|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.MinGLRelease|x64.ActiveCfg = Release|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.MinGLRelease|x64.Build.0 = Release|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.MRelease|Win32.ActiveCfg = Release|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.MRelease|Win32.Build.0 = Release|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.MRelease|x64.ActiveCfg = Release|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.MRelease|x64.Build.0 = Release|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.Release Dedicated Server|Win32.ActiveCfg = Release|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.Release Dedicated Server|x64.ActiveCfg = Release|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.Release Dedicated Server|x64.Build.0 = Release|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.Release|Win32.ActiveCfg = Release|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.Release|Win32.Build.0 = Release|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.Release|x64.ActiveCfg = Release|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.Release|x64.Build.0 = Release|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.VkDebug|Win32.ActiveCfg = Debug|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.VkDebug|Win32.Build.0 = Debug|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.VkDebug|x64.ActiveCfg = Debug|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.VkDebug|x64.Build.0 = Debug|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.VkRelease|Win32.ActiveCfg = Release|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.VkRelease|Win32.Build.0 = Release|Win32
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.VkRelease|x64.ActiveCfg = Release|x64
{0AE4667A-A446-44E7-A758-69CF5D9AF8FC}.VkRelease|x64.Build.0 = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View file

@ -602,6 +602,9 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
plskin = sk->qwskin; plskin = sk->qwskin;
} }
} }
else if (inf->geomset < MAX_GEOMSETS && 0 != inf->geomid)
return NULL;
/*hexen2 feature: global skins */ /*hexen2 feature: global skins */
if (inf->numskins < e->skinnum && e->skinnum >= r_globalskin_first.ival && e->skinnum < r_globalskin_first.ival+r_globalskin_count.ival) if (inf->numskins < e->skinnum && e->skinnum >= r_globalskin_first.ival && e->skinnum < r_globalskin_first.ival+r_globalskin_count.ival)

View file

@ -4862,7 +4862,7 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
{ {
newvals = PR_GetStringOfs(prinst, OFS_PARM2); newvals = PR_GetStringOfs(prinst, OFS_PARM2);
if (idx >= mod->numentityinfo) if (idx >= mod->numentityinfo)
Z_ReallocElements(&mod->entityinfo, &mod->numentityinfo, idx+64, sizeof(*mod->entityinfo)); Z_ReallocElements((void**)&mod->entityinfo, &mod->numentityinfo, idx+64, sizeof(*mod->entityinfo));
mod->entityinfo[idx].keyvals = Z_StrDup(newvals); mod->entityinfo[idx].keyvals = Z_StrDup(newvals);
} }
else else
@ -6198,7 +6198,7 @@ void CL_Parse_BrushEdit(void)
if (id > 0xffff) if (id > 0xffff)
return; return;
if (id >= mod->numentityinfo) if (id >= mod->numentityinfo)
Z_ReallocElements(&mod->entityinfo, &mod->numentityinfo, id+64, sizeof(*mod->entityinfo)); Z_ReallocElements((void**)&mod->entityinfo, &mod->numentityinfo, id+64, sizeof(*mod->entityinfo));
if (id < mod->numentityinfo) if (id < mod->numentityinfo)
{ {
if (!ignore) if (!ignore)

View file

@ -396,6 +396,21 @@ int HLMDL_FrameForName(model_t *mod, const char *name)
return -1; return -1;
} }
qboolean HLMDL_GetModelEvent(model_t *model, int animation, int eventidx, float *timestamp, int *eventcode, char **eventdata)
{
hlmodel_t *mc = Mod_Extradata(model);
hlmdl_header_t *h = mc->header;
hlmdl_event_t *ev;
hlmdl_sequencelist_t *seq = animation + (hlmdl_sequencelist_t*)((char*)h+h->seqindex);
if (animation < 0 || animation >= h->numseq || eventidx < 0 || eventidx >= seq->num_events)
return false;
ev = eventidx + (hlmdl_event_t*)((char*)h+seq->ofs_events);
*timestamp = ev->pose / seq->timing;
*eventcode = ev->code;
*eventdata = ev->data;
return true;
}
int HLMDL_BoneForName(model_t *mod, const char *name) int HLMDL_BoneForName(model_t *mod, const char *name)
{ {
int i; int i;

View file

@ -52,7 +52,9 @@ void CM_Shutdown(void);
void Mod_LoadSpriteShaders(model_t *spr); void Mod_LoadSpriteShaders(model_t *spr);
qboolean QDECL Mod_LoadSpriteModel (model_t *mod, void *buffer, size_t fsize); qboolean QDECL Mod_LoadSpriteModel (model_t *mod, void *buffer, size_t fsize);
qboolean QDECL Mod_LoadSprite2Model (model_t *mod, void *buffer, size_t fsize); qboolean QDECL Mod_LoadSprite2Model (model_t *mod, void *buffer, size_t fsize);
qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsize); #ifdef Q1BSPS
static qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsize);
#endif
#ifdef Q2BSPS #ifdef Q2BSPS
qboolean QDECL Mod_LoadQ2BrushModel (model_t *mod, void *buffer, size_t fsize); qboolean QDECL Mod_LoadQ2BrushModel (model_t *mod, void *buffer, size_t fsize);
#endif #endif
@ -77,18 +79,18 @@ extern cvar_t r_loadlits;
extern cvar_t gl_specular; extern cvar_t gl_specular;
#endif #endif
extern cvar_t r_fb_bmodels; extern cvar_t r_fb_bmodels;
mesh_t nullmesh;
void Mod_SortShaders(model_t *mod); void Mod_SortShaders(model_t *mod);
void Mod_LoadAliasShaders(model_t *mod); void Mod_LoadAliasShaders(model_t *mod);
#ifdef RUNTIMELIGHTING #ifdef RUNTIMELIGHTING
model_t *lightmodel; model_t *lightmodel;
struct relight_ctx_s *lightcontext; static struct relight_ctx_s *lightcontext;
int numlightdata; static int numlightdata;
qboolean writelitfile; static qboolean writelitfile;
long relitsurface; long relitsurface;
void Mod_UpdateLightmap(int snum) #ifndef MULTITHREAD
static void Mod_UpdateLightmap(int snum)
{ {
msurface_t *s; msurface_t *s;
if (lightmodel) if (lightmodel)
@ -107,6 +109,7 @@ void Mod_UpdateLightmap(int snum)
} }
} }
#endif #endif
#endif
static void Mod_MemList_f(void) static void Mod_MemList_f(void)
{ {
@ -261,12 +264,13 @@ static void Mod_BlockTextureColour_f (void)
#endif #endif
#if defined(RUNTIMELIGHTING) && defined(MULTITHREAD) #if defined(RUNTIMELIGHTING)
void *relightthread[8]; #if defined(MULTITHREAD)
unsigned int relightthreads; static void *relightthread[8];
volatile qboolean wantrelight; static unsigned int relightthreads;
static volatile qboolean wantrelight;
int RelightThread(void *arg) static int RelightThread(void *arg)
{ {
int surf; int surf;
void *threadctx = malloc(lightthreadctxsize); void *threadctx = malloc(lightthreadctxsize);
@ -287,8 +291,8 @@ int RelightThread(void *arg)
free(threadctx); free(threadctx);
return 0; return 0;
} }
#else #endif
void *lightmainthreadctx; static void *lightmainthreadctx;
#endif #endif
void Mod_Think (void) void Mod_Think (void)
@ -707,7 +711,9 @@ void Mod_Init (qboolean initial)
Mod_ClearAll(); //shouldn't be needed Mod_ClearAll(); //shouldn't be needed
Mod_Purge(MP_RESET);//shouldn't be needed Mod_Purge(MP_RESET);//shouldn't be needed
mod_numknown = 0; mod_numknown = 0;
#ifdef Q1BSPS
Q1BSP_Init(); Q1BSP_Init();
#endif
Cmd_AddCommand("mod_memlist", Mod_MemList_f); Cmd_AddCommand("mod_memlist", Mod_MemList_f);
#ifndef SERVERONLY #ifndef SERVERONLY
@ -758,12 +764,14 @@ void Mod_Init (qboolean initial)
Mod_RegisterModelFormatText(NULL, "Doom3 (cm)", "CM", D3_LoadMap_CollisionMap); Mod_RegisterModelFormatText(NULL, "Doom3 (cm)", "CM", D3_LoadMap_CollisionMap);
#endif #endif
#ifdef Q1BSPS
//q1-based formats //q1-based formats
Mod_RegisterModelFormatMagic(NULL, "Quake1 2PSB Map(bsp)", BSPVERSION_LONG1, Mod_LoadBrushModel); Mod_RegisterModelFormatMagic(NULL, "Quake1 2PSB Map(bsp)", BSPVERSION_LONG1, Mod_LoadBrushModel);
Mod_RegisterModelFormatMagic(NULL, "Quake1 BSP2 Map(bsp)", BSPVERSION_LONG2, Mod_LoadBrushModel); Mod_RegisterModelFormatMagic(NULL, "Quake1 BSP2 Map(bsp)", BSPVERSION_LONG2, Mod_LoadBrushModel);
Mod_RegisterModelFormatMagic(NULL, "Half-Life Map (bsp)", 30, Mod_LoadBrushModel); Mod_RegisterModelFormatMagic(NULL, "Half-Life Map (bsp)", 30, Mod_LoadBrushModel);
Mod_RegisterModelFormatMagic(NULL, "Quake1 Map (bsp)", 29, Mod_LoadBrushModel); Mod_RegisterModelFormatMagic(NULL, "Quake1 Map (bsp)", 29, Mod_LoadBrushModel);
Mod_RegisterModelFormatMagic(NULL, "Quake1 Prerelease Map (bsp)", 28, Mod_LoadBrushModel); Mod_RegisterModelFormatMagic(NULL, "Quake1 Prerelease Map (bsp)", 28, Mod_LoadBrushModel);
#endif
} }
} }
@ -1120,7 +1128,7 @@ Mod_LoadModel
Loads a model into the cache Loads a model into the cache
================== ==================
*/ */
void Mod_LoadModelWorker (void *ctx, void *data, size_t a, size_t b) static void Mod_LoadModelWorker (void *ctx, void *data, size_t a, size_t b)
{ {
model_t *mod = ctx; model_t *mod = ctx;
enum mlverbosity_e verbose = a; enum mlverbosity_e verbose = a;
@ -1436,10 +1444,9 @@ static const char *Mod_RemapBuggyTexture(const char *name, const qbyte *data, un
} }
#endif #endif
void Mod_FinishTexture(texture_t *tx, const char *loadname, qboolean safetoloadfromwads)
{
#ifndef SERVERONLY #ifndef SERVERONLY
static void Mod_FinishTexture(texture_t *tx, const char *loadname, qboolean safetoloadfromwads)
{
extern cvar_t gl_shadeq1_name; extern cvar_t gl_shadeq1_name;
char altname[MAX_QPATH]; char altname[MAX_QPATH];
char *star; char *star;
@ -1520,9 +1527,7 @@ void Mod_FinishTexture(texture_t *tx, const char *loadname, qboolean safetoloadf
R_BuildLegacyTexnums(tx->shader, origname, loadname, maps, 0, fmt, tx->width, tx->height, tx->mips, tx->palette); R_BuildLegacyTexnums(tx->shader, origname, loadname, maps, 0, fmt, tx->width, tx->height, tx->mips, tx->palette);
} }
BZ_Free(tx->mips[0]); BZ_Free(tx->mips[0]);
#endif
} }
#ifndef SERVERONLY
static void Mod_LoadMiptex(model_t *loadmodel, texture_t *tx, miptex_t *mt) static void Mod_LoadMiptex(model_t *loadmodel, texture_t *tx, miptex_t *mt)
{ {
unsigned int size = unsigned int size =
@ -1559,7 +1564,7 @@ static void Mod_LoadMiptex(model_t *loadmodel, texture_t *tx, miptex_t *mt)
Mod_LoadTextures Mod_LoadTextures
================= =================
*/ */
qboolean Mod_LoadTextures (model_t *loadmodel, qbyte *mod_base, lump_t *l) static qboolean Mod_LoadTextures (model_t *loadmodel, qbyte *mod_base, lump_t *l)
{ {
int i, j, num, max, altmax; int i, j, num, max, altmax;
miptex_t *mt; miptex_t *mt;
@ -2224,7 +2229,7 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
Mod_LoadVisibility Mod_LoadVisibility
================= =================
*/ */
void Mod_LoadVisibility (model_t *loadmodel, qbyte *mod_base, lump_t *l, qbyte *ptr, size_t len) static void Mod_LoadVisibility (model_t *loadmodel, qbyte *mod_base, lump_t *l, qbyte *ptr, size_t len)
{ {
if (!ptr) if (!ptr)
{ {
@ -2462,7 +2467,7 @@ qboolean Mod_LoadVertexNormals (model_t *loadmodel, qbyte *mod_base, lump_t *l)
Mod_LoadSubmodels Mod_LoadSubmodels
================= =================
*/ */
qboolean Mod_LoadSubmodels (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean *hexen2map) static qboolean Mod_LoadSubmodels (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean *hexen2map)
{ {
dq1model_t *inq; dq1model_t *inq;
dh2model_t *inh; dh2model_t *inh;
@ -2611,7 +2616,7 @@ qboolean Mod_LoadEdges (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
Mod_LoadTexinfo Mod_LoadTexinfo
================= =================
*/ */
qboolean Mod_LoadTexinfo (model_t *loadmodel, qbyte *mod_base, lump_t *l) static qboolean Mod_LoadTexinfo (model_t *loadmodel, qbyte *mod_base, lump_t *l)
{ {
texinfo_t *in; texinfo_t *in;
mtexinfo_t *out; mtexinfo_t *out;
@ -2652,7 +2657,7 @@ qboolean Mod_LoadTexinfo (model_t *loadmodel, qbyte *mod_base, lump_t *l)
out->texture = r_notexture_mip; // texture not found out->texture = r_notexture_mip; // texture not found
out->flags = 0; out->flags = 0;
} }
if (!strncmp(out->texture->name, "scroll", 6) || ((*out->texture->name == '*' || *out->texture->name == '{' || *out->texture->name == '!') && !strncmp(out->texture->name+1, "scroll", 6))) else if (!strncmp(out->texture->name, "scroll", 6) || ((*out->texture->name == '*' || *out->texture->name == '{' || *out->texture->name == '!') && !strncmp(out->texture->name+1, "scroll", 6)))
out->flags |= TI_FLOWING; out->flags |= TI_FLOWING;
} }
@ -2721,7 +2726,7 @@ void CalcSurfaceExtents (model_t *mod, msurface_t *s);
Mod_LoadFaces Mod_LoadFaces
================= =================
*/ */
qboolean Mod_LoadFaces (model_t *loadmodel, qbyte *mod_base, lump_t *l, lump_t *lightlump, qboolean lm) static qboolean Mod_LoadFaces (model_t *loadmodel, qbyte *mod_base, lump_t *l, lump_t *lightlump, qboolean lm)
{ {
dsface_t *ins; dsface_t *ins;
dlface_t *inl; dlface_t *inl;
@ -3113,7 +3118,7 @@ static void Mod_Batches_BuildModelMeshes(model_t *mod, int maxverts, int maxindi
} }
//q1 autoanimates. if the frame is set, it uses the alternate animation. //q1 autoanimates. if the frame is set, it uses the alternate animation.
void Mod_UpdateBatchShader_Q1 (struct batch_s *batch) static void Mod_UpdateBatchShader_Q1 (struct batch_s *batch)
{ {
texture_t *base = batch->texture; texture_t *base = batch->texture;
int reletive; int reletive;
@ -3144,7 +3149,7 @@ void Mod_UpdateBatchShader_Q1 (struct batch_s *batch)
} }
//q2 has direct control over the texture frames used, but typically has the client generate the frame (different flags autogenerate different ranges). //q2 has direct control over the texture frames used, but typically has the client generate the frame (different flags autogenerate different ranges).
void Mod_UpdateBatchShader_Q2 (struct batch_s *batch) static void Mod_UpdateBatchShader_Q2 (struct batch_s *batch)
{ {
texture_t *base = batch->texture; texture_t *base = batch->texture;
int reletive; int reletive;
@ -3721,7 +3726,7 @@ static qboolean Mod_LoadNodes (model_t *loadmodel, qbyte *mod_base, lump_t *l, i
out->firstsurface = LittleLong (in->firstface); out->firstsurface = LittleLong (in->firstface);
out->numsurfaces = LittleLong (in->numfaces); out->numsurfaces = LittleLong (in->numfaces);
for (j=0 ; j<2 ; j++) for (j=0 ; j<2 ; j++)
{ {
p = LittleLong (in->children[j]); p = LittleLong (in->children[j]);
@ -3760,7 +3765,7 @@ static qboolean Mod_LoadNodes (model_t *loadmodel, qbyte *mod_base, lump_t *l, i
out->firstsurface = (unsigned short)LittleShort (in->firstface); out->firstsurface = (unsigned short)LittleShort (in->firstface);
out->numsurfaces = (unsigned short)LittleShort (in->numfaces); out->numsurfaces = (unsigned short)LittleShort (in->numfaces);
for (j=0 ; j<2 ; j++) for (j=0 ; j<2 ; j++)
{ {
p = LittleShort (in->children[j]); p = LittleShort (in->children[j]);
@ -3988,13 +3993,13 @@ static qboolean Mod_LoadLeafs (model_t *loadmodel, qbyte *mod_base, lump_t *l, i
//these are used to boost other info sizes //these are used to boost other info sizes
int numsuplementryplanes; static int numsuplementryplanes;
int numsuplementryclipnodes; static int numsuplementryclipnodes;
void *suplementryclipnodes; static void *suplementryclipnodes;
void *suplementryplanes; static void *suplementryplanes;
void *crouchhullfile; static void *crouchhullfile;
void Mod_LoadCrouchHull(model_t *loadmodel) static void Mod_LoadCrouchHull(model_t *loadmodel)
{ {
int i, h; int i, h;
int numsm; int numsm;
@ -4065,7 +4070,7 @@ void Mod_LoadCrouchHull(model_t *loadmodel)
Mod_LoadClipnodes Mod_LoadClipnodes
================= =================
*/ */
qboolean Mod_LoadClipnodes (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean lm, qboolean hexen2map) static qboolean Mod_LoadClipnodes (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean lm, qboolean hexen2map)
{ {
dsclipnode_t *ins; dsclipnode_t *ins;
dlclipnode_t *inl; dlclipnode_t *inl;
@ -4320,7 +4325,7 @@ Mod_MakeHull0
Deplicate the drawing hull structure as a clipping hull Deplicate the drawing hull structure as a clipping hull
================= =================
*/ */
void Mod_MakeHull0 (model_t *loadmodel) static void Mod_MakeHull0 (model_t *loadmodel)
{ {
mnode_t *in, *child; mnode_t *in, *child;
mclipnode_t *out; mclipnode_t *out;
@ -4452,7 +4457,7 @@ qboolean Mod_LoadSurfedges (model_t *loadmodel, qbyte *mod_base, lump_t *l)
Mod_LoadPlanes Mod_LoadPlanes
================= =================
*/ */
qboolean Mod_LoadPlanes (model_t *loadmodel, qbyte *mod_base, lump_t *l) static qboolean Mod_LoadPlanes (model_t *loadmodel, qbyte *mod_base, lump_t *l)
{ {
int i, j; int i, j;
mplane_t *out; mplane_t *out;
@ -4550,7 +4555,7 @@ static void Q1BSP_StainNode (mnode_t *node, float *parms)
} }
#endif #endif
void Mod_FixupNodeMinsMaxs (mnode_t *node, mnode_t *parent) static void Mod_FixupNodeMinsMaxs (mnode_t *node, mnode_t *parent)
{ {
if (!node) if (!node)
return; return;
@ -4733,6 +4738,8 @@ void ModBrush_LoadGLStuff(void *ctx, void *data, size_t a, size_t b)
#endif #endif
} }
#ifdef Q1BSPS
struct vispatch_s struct vispatch_s
{ {
void *fileptr; void *fileptr;
@ -4816,7 +4823,7 @@ static void Mod_FindVisPatch(struct vispatch_s *patch, model_t *mod, size_t leaf
Mod_LoadBrushModel Mod_LoadBrushModel
================= =================
*/ */
qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsize) static qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsize)
{ {
struct vispatch_s vispatch; struct vispatch_s vispatch;
int i, j; int i, j;
@ -5109,6 +5116,7 @@ TRACE(("LoadBrushModel %i\n", __LINE__));
#endif #endif
return true; return true;
} }
#endif
/* /*
============================================================================== ==============================================================================

View file

@ -66,8 +66,9 @@ struct doll_s *rag_createdollfromstring(struct model_s *mod, const char *fname,
struct world_s; struct world_s;
void rag_doallanimations(struct world_s *world); void rag_doallanimations(struct world_s *world);
void rag_removedeltaent(lerpents_t *le); void rag_removedeltaent(lerpents_t *le);
void rag_updatedeltaent(entity_t *ent, lerpents_t *le); void rag_updatedeltaent(struct world_s *w, entity_t *ent, lerpents_t *le);
void rag_lerpdeltaent(lerpents_t *le, unsigned int bonecount, short *newstate, float frac, short *oldstate); void rag_lerpdeltaent(lerpents_t *le, unsigned int bonecount, short *newstate, float frac, short *oldstate);
void skel_reset(struct world_s *world);
typedef struct mesh_s typedef struct mesh_s
{ {
@ -107,7 +108,6 @@ typedef struct mesh_s
byte_vec4_t *bonenums; byte_vec4_t *bonenums;
vec4_t *boneweights; vec4_t *boneweights;
} mesh_t; } mesh_t;
extern mesh_t nullmesh;
/* /*
batches are generated for each shader/ent as required. batches are generated for each shader/ent as required.
@ -831,7 +831,7 @@ typedef enum {fg_quake, fg_quake2, fg_quake3, fg_halflife, fg_new, fg_doom, fg_d
#define MFH2_SCARAB (1u<<21) // white transparent particles with little gravity #define MFH2_SCARAB (1u<<21) // white transparent particles with little gravity
#define MFH2_ACIDBALL (1u<<22) // Green drippy acid shit #define MFH2_ACIDBALL (1u<<22) // Green drippy acid shit
#define MFH2_BLOODSHOT (1u<<23) // Blood rain shot trail #define MFH2_BLOODSHOT (1u<<23) // Blood rain shot trail
#define MFH2_ROCKET (1u<<31) // spider blood (remapped from MF_ROCKET, to avoid dlight issues) #define MFH2_SPIDERBLOOD (1u<<31) // spider blood (remapped from MF_ROCKET, to avoid dlight issues)
typedef union { typedef union {
struct { struct {

View file

@ -1591,10 +1591,10 @@ static float *GLRecursiveLightPoint3C (model_t *mod, mnode_t *node, vec3_t start
front = DotProduct (start, plane->normal) - plane->dist; front = DotProduct (start, plane->normal) - plane->dist;
back = DotProduct (end, plane->normal) - plane->dist; back = DotProduct (end, plane->normal) - plane->dist;
side = front < 0; side = front < 0;
if ( (back < 0) == side) if ( (back < 0) == side)
return GLRecursiveLightPoint3C (mod, node->children[side], start, end); return GLRecursiveLightPoint3C (mod, node->children[side], start, end);
frac = front / (front-back); frac = front / (front-back);
mid[0] = start[0] + (end[0] - start[0])*frac; mid[0] = start[0] + (end[0] - start[0])*frac;
mid[1] = start[1] + (end[1] - start[1])*frac; mid[1] = start[1] + (end[1] - start[1])*frac;
@ -1604,10 +1604,10 @@ static float *GLRecursiveLightPoint3C (model_t *mod, mnode_t *node, vec3_t start
r = GLRecursiveLightPoint3C (mod, node->children[side], start, mid); r = GLRecursiveLightPoint3C (mod, node->children[side], start, mid);
if (r && r[0]+r[1]+r[2] >= 0) if (r && r[0]+r[1]+r[2] >= 0)
return r; // hit something return r; // hit something
if ( (back < 0) == side ) if ( (back < 0) == side )
return NULL; // didn't hit anuthing return NULL; // didn't hit anuthing
// check for impact on this node // check for impact on this node
VectorCopy (mid, lightspot); VectorCopy (mid, lightspot);
lightplane = plane; lightplane = plane;
@ -1626,7 +1626,7 @@ static float *GLRecursiveLightPoint3C (model_t *mod, mnode_t *node, vec3_t start
if (s < surf->texturemins[0] || if (s < surf->texturemins[0] ||
t < surf->texturemins[1]) t < surf->texturemins[1])
continue; continue;
ds = s - surf->texturemins[0]; ds = s - surf->texturemins[0];
dt = t - surf->texturemins[1]; dt = t - surf->texturemins[1];

View file

@ -192,7 +192,9 @@ typedef struct
char name[32]; char name[32];
float timing; float timing;
int loop; int loop;
int unknown1[4]; int unknown1[2];
int num_events;
int ofs_events;
int numframes; int numframes;
int unknown2[2]; int unknown2[2];
int motiontype; int motiontype;
@ -209,6 +211,14 @@ typedef struct
int unknown9[4]; int unknown9[4];
} hlmdl_sequencelist_t; } hlmdl_sequencelist_t;
typedef struct
{
int pose;
int code;
int unknown1;
char data[64];
} hlmdl_event_t;
/* /*
----------------------------------------------------------------------------------------------------------------------- -----------------------------------------------------------------------------------------------------------------------
sequence groups sequence groups
@ -289,6 +299,7 @@ int HLMDL_BoneForName(model_t *mod, const char *name);
int HLMDL_FrameForName(model_t *mod, const char *name); int HLMDL_FrameForName(model_t *mod, const char *name);
const char *HLMDL_FrameNameForNum(model_t *model, int surfaceidx, int num); const char *HLMDL_FrameNameForNum(model_t *model, int surfaceidx, int num);
qboolean HLMDL_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **name, int *numframes, float *duration, qboolean *loop); qboolean HLMDL_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **name, int *numframes, float *duration, qboolean *loop);
qboolean HLMDL_GetModelEvent(model_t *model, int animation, int eventidx, float *timestamp, int *eventcode, char **eventdata);
int HLMDL_GetNumBones(model_t *mod, qboolean tagstoo); int HLMDL_GetNumBones(model_t *mod, qboolean tagstoo);
int HLMDL_GetBoneParent(model_t *mod, int bonenum); int HLMDL_GetBoneParent(model_t *mod, int bonenum);
const char *HLMDL_GetBoneName(model_t *mod, int bonenum); const char *HLMDL_GetBoneName(model_t *mod, int bonenum);

View file

@ -1379,7 +1379,10 @@ static int DL_Thread_Work(void *arg)
#ifdef NPFTE #ifdef NPFTE
//the plugin doesn't have a download loop //the plugin doesn't have a download loop
if (dl->notifycomplete) if (dl->notifycomplete)
{
dl->notifycomplete(dl); dl->notifycomplete(dl);
dl->notifycomplete = NULL;
}
if (dl->file) if (dl->file)
VFS_CLOSE(dl->file); VFS_CLOSE(dl->file);
#else #else
@ -1452,6 +1455,7 @@ struct dl_download *DL_Create(const char *url)
strcpy(newdl->url, url); strcpy(newdl->url, url);
newdl->poll = DL_Decide; newdl->poll = DL_Decide;
newdl->sizelimit = 0x80000000u; //some sanity limit. newdl->sizelimit = 0x80000000u; //some sanity limit.
newdl->qdownload.method = DL_HTTP;
if (!newdl->poll(newdl)) if (!newdl->poll(newdl))
{ {
@ -1488,6 +1492,10 @@ void DL_Close(struct dl_download *dl)
if (dl->threadctx) if (dl->threadctx)
Sys_WaitOnThread(dl->threadctx); Sys_WaitOnThread(dl->threadctx);
#endif #endif
if (dl->file && dl->file->Seek)
VFS_SEEK(dl->file, 0);
if (dl->notifycomplete)
dl->notifycomplete(dl);
if (dl->abort) if (dl->abort)
dl->abort(dl); dl->abort(dl);
if (dl->file) if (dl->file)
@ -1542,7 +1550,6 @@ struct dl_download *HTTP_CL_Get(const char *url, const char *localfile, void (*N
if (!cls.download && localfile && !newdl->isquery) if (!cls.download && localfile && !newdl->isquery)
{ {
cls.download = &newdl->qdownload; cls.download = &newdl->qdownload;
newdl->qdownload.method = DL_HTTP;
if (*newdl->localname) if (*newdl->localname)
Q_strncpyz(newdl->qdownload.localname, newdl->localname, sizeof(newdl->qdownload.localname)); Q_strncpyz(newdl->qdownload.localname, newdl->localname, sizeof(newdl->qdownload.localname));
else else
@ -1614,10 +1621,6 @@ void HTTP_CL_Think(void)
if (!dl->poll(dl)) if (!dl->poll(dl))
{ {
*link = dl->next; *link = dl->next;
if (dl->file && dl->file->Seek)
VFS_SEEK(dl->file, 0);
if (dl->notifycomplete)
dl->notifycomplete(dl);
DL_Close(dl); DL_Close(dl);
continue; continue;
} }

View file

@ -2529,6 +2529,8 @@ int PR_ReallyLoadProgs (progfuncs_t *progfuncs, const char *filename, progstate_
int stringadjust; int stringadjust;
char *mainstringtable, *newstringtable;
current_progstate = progstate; current_progstate = progstate;
strcpy(current_progstate->filename, filename); strcpy(current_progstate->filename, filename);
@ -2792,6 +2794,9 @@ retry:
len=sizeof(char)*pr_progs->numstrings; len=sizeof(char)*pr_progs->numstrings;
s = PRAddressableExtend(progfuncs, pr_strings, len, 0); s = PRAddressableExtend(progfuncs, pr_strings, len, 0);
newstringtable = s;
mainstringtable = progfuncs->funcs.stringtable;
pr_strings = (char *)s; pr_strings = (char *)s;
len=sizeof(float)*pr_progs->numglobals; len=sizeof(float)*pr_progs->numglobals;

View file

@ -670,6 +670,7 @@ int QCC_PR_IntConstExpr(void);
#ifndef COMMONINLINES #ifndef COMMONINLINES
pbool QCC_PR_CheckImmediate (const char *string); pbool QCC_PR_CheckImmediate (const char *string);
pbool QCC_PR_CheckToken (const char *string); pbool QCC_PR_CheckToken (const char *string);
pbool QCC_PR_PeekToken (const char *string);
pbool QCC_PR_CheckName (const char *string); pbool QCC_PR_CheckName (const char *string);
void QCC_PR_Expect (const char *string); void QCC_PR_Expect (const char *string);
pbool QCC_PR_CheckKeyword(int keywordenabled, const char *string); pbool QCC_PR_CheckKeyword(int keywordenabled, const char *string);
@ -1073,6 +1074,16 @@ static bool inline QCC_PR_CheckToken (char *string)
QCC_PR_Lex (); QCC_PR_Lex ();
return true; return true;
} }
static bool inline QCC_PR_PeekToken (char *string)
{
if (pr_token_type != tt_punct)
return false;
if (STRCMP (string, pr_token))
return false;
return true;
}
static void inline QCC_PR_Expect (const char *string) static void inline QCC_PR_Expect (const char *string)
{ {

View file

@ -3,6 +3,8 @@
#include "qcc.h" #include "qcc.h"
#include <math.h> #include <math.h>
#define WARN_IMPLICITVARIANTCAST 0
//FIXME: #define IAMNOTLAZY //FIXME: #define IAMNOTLAZY
#define SUPPORTINLINE #define SUPPORTINLINE
@ -191,6 +193,7 @@ void QCC_PR_DiscardRef(QCC_ref_t *ref);
QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_def_t *def, QCC_type_t *type, pbool dowrap); QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_def_t *def, QCC_type_t *type, pbool dowrap);
const char *QCC_VarAtOffset(QCC_sref_t ref, unsigned int size); const char *QCC_VarAtOffset(QCC_sref_t ref, unsigned int size);
QCC_sref_t QCC_EvaluateCast(QCC_sref_t src, QCC_type_t *cast, pbool implicit); QCC_sref_t QCC_EvaluateCast(QCC_sref_t src, QCC_type_t *cast, pbool implicit);
void QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *basedef, QCC_sref_t def, unsigned int flags);
QCC_statement_t *QCC_Generate_OP_IFNOT(QCC_sref_t e, pbool preserve); QCC_statement_t *QCC_Generate_OP_IFNOT(QCC_sref_t e, pbool preserve);
QCC_statement_t *QCC_Generate_OP_IF(QCC_sref_t e, pbool preserve); QCC_statement_t *QCC_Generate_OP_IF(QCC_sref_t e, pbool preserve);
@ -5887,60 +5890,8 @@ QCC_sref_t QCC_PR_ParseFunctionCall (QCC_ref_t *funcref) //warning, the func cou
if (p) if (p)
{ {
if (typecmp(e->cast, p)) if (typecmp(e->cast, p))
/*if (e->type->type != ev_integer && p->type != ev_function)
if (e->type->type != ev_function && p->type != ev_integer)
if ( e->type->type != p->type )*/
{ {
e = QCC_PR_BuildRef(&parambuf[arg], REF_GLOBAL, QCC_EvaluateCast(QCC_RefToDef(e, true), p, true), nullsref, p, true); e = QCC_PR_BuildRef(&parambuf[arg], REF_GLOBAL, QCC_EvaluateCast(QCC_RefToDef(e, true), p, true), nullsref, p, true);
#if 0
if (p->type == ev_integer && e.cast->type == ev_float) //convert float -> int... is this a constant?
e = QCC_PR_Statement(pr_opcodes+OP_CONV_FTOI, e, nullsref, NULL);
else if (p->type == ev_float && e.cast->type == ev_integer) //convert float -> int... is this a constant?
e = QCC_PR_Statement(pr_opcodes+OP_CONV_ITOF, e, nullsref, NULL);
else if ((p->type == ev_function || p->type == ev_field || p->type == ev_string || p->type == ev_pointer || p->type == ev_entity) && QCC_SRef_IsNull(e))
{ //you're allowed to use int 0 to pass a null function/field/string/pointer/entity
//this is basically because __NULL__ is defined as 0i (int 0)
//WARNING: field 0 is actually a valid field, and is commonly modelindex.
}
else if ((p->type == ev_field || p->type == ev_pointer) && e.cast->type == p->type && (p->aux_type->type == ev_variant || e.cast->aux_type->type == ev_variant || p->aux_type->type == ev_void || e.cast->aux_type->type == ev_void))
{ //allow passing variant fields etc (also allow .void or *void as universal/variant field/pointer types)
}
else if ( (p->type == ev_accessor && p->parentclass->type == e.cast->type)
|| (e.cast->type == ev_accessor && e.cast->parentclass->type == p->type))
{
}
else if ((p->type == ev_vector) && QCC_SRef_IsNull(e))
{
//also allow it for vector types too, but make sure the entire vector is valid.
e = QCC_MakeVectorConst(0, 0, 0);
}
else if (p->type != ev_variant && e.cast->type != ev_variant) //can cast to variant whatever happens
{
QCC_type_t *inh;
for (inh = e.cast->parentclass; inh; inh = inh->parentclass)
{
if (!typecmp(inh, p))
break;
}
if (!inh)
{
char typebuf1[1024];
char typebuf2[1024];
if (flag_laxcasts || (p->type == ev_function && e.cast->type == ev_function))
{
QCC_PR_ParseWarning(WARN_LAXCAST, "type mismatch on parm %i: %s should be %s", arg+1, TypeName(e.cast, typebuf1, sizeof(typebuf1)), TypeName(p, typebuf2, sizeof(typebuf2)));
QCC_PR_ParsePrintSRef(WARN_LAXCAST, func);
}
else
{
QCC_PR_ParseWarning (ERR_TYPEMISMATCHPARM, "type mismatch on parm %i: %s should be %s", arg+1, TypeName(e.cast, typebuf1, sizeof(typebuf1)), TypeName(p, typebuf2, sizeof(typebuf2)));
QCC_PR_ParsePrintSRef(ERR_TYPEMISMATCHPARM, func);
}
}
}
#endif
} }
} }
param[arg] = e; param[arg] = e;
@ -7053,6 +7004,73 @@ vectorarrayindex:
return r; return r;
} }
QCC_sref_t QCC_PR_GenerateVector(QCC_sref_t x, QCC_sref_t y, QCC_sref_t z)
{
QCC_sref_t d;
if ((x.cast->type != ev_float && x.cast->type != ev_integer) ||
(y.cast->type != ev_float && y.cast->type != ev_integer) ||
(z.cast->type != ev_float && z.cast->type != ev_integer))
{
QCC_PR_ParseError(ERR_TYPEMISMATCH, "Argument not a single numeric value in vector constructor");
return QCC_MakeVectorConst(0, 0, 0);
}
//return a constant if we can.
if (x.sym->constant && y.sym->constant && z.sym->constant)
{
d = QCC_MakeVectorConst(
(x.cast->type==ev_float)?x.sym->symboldata[x.ofs]._float:x.sym->symboldata[x.ofs]._int,
(y.cast->type==ev_float)?y.sym->symboldata[y.ofs]._float:y.sym->symboldata[y.ofs]._int,
(z.cast->type==ev_float)?z.sym->symboldata[z.ofs]._float:z.sym->symboldata[z.ofs]._int);
QCC_FreeTemp(x);
QCC_FreeTemp(y);
QCC_FreeTemp(z);
return d;
}
if (QCC_SRef_IsNull(y) && QCC_SRef_IsNull(z))
{
QCC_FreeTemp(y);
QCC_FreeTemp(z);
return QCC_PR_StatementFlags(pr_opcodes + OP_MUL_VF, QCC_MakeVectorConst(1, 0, 0), QCC_SupplyConversion(x, ev_float, true), NULL, 0);
}
if (QCC_SRef_IsNull(x) && QCC_SRef_IsNull(z))
{
QCC_FreeTemp(x);
QCC_FreeTemp(z);
return QCC_PR_StatementFlags(pr_opcodes + OP_MUL_VF, QCC_MakeVectorConst(0, 1, 0), QCC_SupplyConversion(y, ev_float, true), NULL, 0);
}
if (QCC_SRef_IsNull(x) && QCC_SRef_IsNull(y))
{
QCC_FreeTemp(x);
QCC_FreeTemp(y);
return QCC_PR_StatementFlags(pr_opcodes + OP_MUL_VF, QCC_MakeVectorConst(0, 0, 1), QCC_SupplyConversion(z, ev_float, true), NULL, 0);
}
//pack the variables into a vector
d = QCC_GetTemp(type_vector);
d.cast = type_float;
if (x.cast->type == ev_float)
QCC_PR_StatementFlags(pr_opcodes + OP_STORE_F, x, d, NULL, STFL_PRESERVEB|STFL_DISCARDRESULT);
else
QCC_PR_StatementFlags(pr_opcodes+OP_STORE_IF, x, d, NULL, STFL_PRESERVEB|STFL_DISCARDRESULT);
d.ofs++;
if (y.cast->type == ev_float)
QCC_PR_StatementFlags(pr_opcodes + OP_STORE_F, y, d, NULL, STFL_PRESERVEB|STFL_DISCARDRESULT);
else
QCC_PR_StatementFlags(pr_opcodes+OP_STORE_IF, y, d, NULL, STFL_PRESERVEB|STFL_DISCARDRESULT);
d.ofs++;
if (z.cast->type == ev_float)
QCC_PR_StatementFlags(pr_opcodes + OP_STORE_F, z, d, NULL, STFL_PRESERVEB|STFL_DISCARDRESULT);
else
QCC_PR_StatementFlags(pr_opcodes+OP_STORE_IF, z, d, NULL, STFL_PRESERVEB|STFL_DISCARDRESULT);
d.ofs++;
d.ofs -= 3;
d.cast = type_vector;
return d;
}
/* /*
============ ============
PR_ParseValue PR_ParseValue
@ -7105,67 +7123,7 @@ QCC_ref_t *QCC_PR_ParseRefValue (QCC_ref_t *refbuf, QCC_type_t *assumeclass, pbo
QCC_PR_Expect("]"); QCC_PR_Expect("]");
if ((x.cast->type != ev_float && x.cast->type != ev_integer) || return QCC_DefToRef(refbuf, QCC_PR_GenerateVector(x,y,z));
(y.cast->type != ev_float && y.cast->type != ev_integer) ||
(z.cast->type != ev_float && z.cast->type != ev_integer))
{
QCC_PR_ParseError(ERR_TYPEMISMATCH, "Argument not a single numeric value in vector constructor");
return QCC_DefToRef(refbuf, QCC_MakeVectorConst(0, 0, 0));
}
//return a constant if we can.
if (x.sym->constant && y.sym->constant && z.sym->constant)
{
d = QCC_MakeVectorConst(
(x.cast->type==ev_float)?x.sym->symboldata[x.ofs]._float:x.sym->symboldata[x.ofs]._int,
(y.cast->type==ev_float)?y.sym->symboldata[y.ofs]._float:y.sym->symboldata[y.ofs]._int,
(z.cast->type==ev_float)?z.sym->symboldata[z.ofs]._float:z.sym->symboldata[z.ofs]._int);
QCC_FreeTemp(x);
QCC_FreeTemp(y);
QCC_FreeTemp(z);
return QCC_DefToRef(refbuf, d);
}
if (QCC_SRef_IsNull(y) && QCC_SRef_IsNull(z))
{
QCC_FreeTemp(y);
QCC_FreeTemp(z);
return QCC_DefToRef(refbuf, QCC_PR_StatementFlags(pr_opcodes + OP_MUL_VF, QCC_MakeVectorConst(1, 0, 0), QCC_SupplyConversion(x, ev_float, true), NULL, 0));
}
if (QCC_SRef_IsNull(x) && QCC_SRef_IsNull(z))
{
QCC_FreeTemp(x);
QCC_FreeTemp(z);
return QCC_DefToRef(refbuf, QCC_PR_StatementFlags(pr_opcodes + OP_MUL_VF, QCC_MakeVectorConst(0, 1, 0), QCC_SupplyConversion(y, ev_float, true), NULL, 0));
}
if (QCC_SRef_IsNull(x) && QCC_SRef_IsNull(y))
{
QCC_FreeTemp(x);
QCC_FreeTemp(y);
return QCC_DefToRef(refbuf, QCC_PR_StatementFlags(pr_opcodes + OP_MUL_VF, QCC_MakeVectorConst(0, 0, 1), QCC_SupplyConversion(z, ev_float, true), NULL, 0));
}
//pack the variables into a vector
d = QCC_GetTemp(type_vector);
d.cast = type_float;
if (x.cast->type == ev_float)
QCC_PR_StatementFlags(pr_opcodes + OP_STORE_F, x, d, NULL, STFL_PRESERVEB|STFL_DISCARDRESULT);
else
QCC_PR_StatementFlags(pr_opcodes+OP_STORE_IF, x, d, NULL, STFL_PRESERVEB|STFL_DISCARDRESULT);
d.ofs++;
if (y.cast->type == ev_float)
QCC_PR_StatementFlags(pr_opcodes + OP_STORE_F, y, d, NULL, STFL_PRESERVEB|STFL_DISCARDRESULT);
else
QCC_PR_StatementFlags(pr_opcodes+OP_STORE_IF, y, d, NULL, STFL_PRESERVEB|STFL_DISCARDRESULT);
d.ofs++;
if (z.cast->type == ev_float)
QCC_PR_StatementFlags(pr_opcodes + OP_STORE_F, z, d, NULL, STFL_PRESERVEB|STFL_DISCARDRESULT);
else
QCC_PR_StatementFlags(pr_opcodes+OP_STORE_IF, z, d, NULL, STFL_PRESERVEB|STFL_DISCARDRESULT);
d.ofs++;
d.ofs -= 3;
d.cast = type_vector;
return QCC_DefToRef(refbuf, d);
} }
if (QCC_PR_CheckToken("::")) if (QCC_PR_CheckToken("::"))
@ -7501,7 +7459,18 @@ QCC_sref_t QCC_EvaluateCast(QCC_sref_t src, QCC_type_t *cast, pbool implicit)
/*variants can be cast from/to anything without warning, even implicitly. FIXME: size issues*/ /*variants can be cast from/to anything without warning, even implicitly. FIXME: size issues*/
else if (totype == ev_variant || src.cast->type == ev_variant else if (totype == ev_variant || src.cast->type == ev_variant
|| (totype == ev_field && totype == src.cast->type && (tmp->aux_type->type == ev_variant || src.cast->aux_type->type == ev_variant))) || (totype == ev_field && totype == src.cast->type && (tmp->aux_type->type == ev_variant || src.cast->aux_type->type == ev_variant)))
{
src.cast = cast; src.cast = cast;
if (implicit && typecmp_lax(src.cast, cast))
{
char typea[256];
char typeb[256];
TypeName(src.cast, typea, sizeof(typea));
TypeName(cast, typeb, sizeof(typeb));
QCC_PR_ParseWarning(WARN_IMPLICITVARIANTCAST, "Implicit cast from %s to %s", typea, typeb);
}
}
/*these casts are fine when explicit*/ /*these casts are fine when explicit*/
else if ( else if (
/*you may explicitly cast between pointers and ints (strings count as pointers - WARNING: some strings may not be expressable as pointers)*/ /*you may explicitly cast between pointers and ints (strings count as pointers - WARNING: some strings may not be expressable as pointers)*/
@ -7706,34 +7675,34 @@ QCC_ref_t *QCC_PR_RefTerm (QCC_ref_t *retbuf, unsigned int exprflags)
newtype = QCC_PR_ParseType(false, true); newtype = QCC_PR_ParseType(false, true);
if (newtype) if (newtype)
{ {
/*if (QCC_PR_Check ("["))
{
QCC_PR_Expect ("]");
QCC_PR_Expect(")");
QCC_PR_Expect("{");
QCC_PR_Expect ("}");
return array;
}*/
QCC_PR_Expect (")"); QCC_PR_Expect (")");
if (newtype->type == ev_function && pr_token_type == tt_punct && !strcmp(pr_token, "{")) if (QCC_PR_PeekToken("{"))
{ {
//save some state of the parent if (newtype->type == ev_vector)
QCC_def_t *firstlocal = pr.local_head.nextlocal; {
QCC_def_t *lastlocal = pr.local_tail; QCC_sref_t x,y,z;
QCC_function_t *parent = pr_scope; QCC_PR_Expect("{");
QCC_statement_t *patch; x = QCC_PR_Expression(TOP_PRIORITY, EXPR_DISALLOW_COMMA);
QCC_PR_Expect(",");
//FIXME: make sure gotos/labels/cases/continues/breaks are not broken by this. y = QCC_PR_Expression(TOP_PRIORITY, EXPR_DISALLOW_COMMA);
QCC_PR_Expect(",");
//generate a goto statement around the nested function, so that nothing is hurt. z = QCC_PR_Expression(TOP_PRIORITY, EXPR_DISALLOW_COMMA);
e = nullsref; QCC_PR_Expect ("}");
e.cast = type_float; return QCC_DefToRef(retbuf, QCC_PR_GenerateVector(x,y,z));
patch = QCC_Generate_OP_GOTO(); }
e = QCC_MakeIntConst(QCC_PR_ParseImmediateStatements (NULL, newtype, false) - functions); else
e.cast = newtype; {
patch->a.ofs = &statements[numstatements] - patch; e = QCC_GetTemp(newtype);
QCC_PR_ParseInitializerType(0, NULL, e, 0);
//make sure parent state is restored properly. }
pr.local_head.nextlocal = firstlocal;
pr.local_tail = lastlocal;
pr_scope = parent;
}
else if ((newtype->type == ev_struct || newtype->type == ev_union) && pr_token_type == tt_punct && !strcmp(pr_token, "{"))
{
//FIXME
QCC_PR_ParseError(0, "struct immediates are not supported at this time\n");
} }
else else
{ {
@ -8612,11 +8581,13 @@ QCC_sref_t QCC_StoreSRefToRef(QCC_ref_t *dest, QCC_sref_t source, pbool readable
break; break;
t = t->parentclass; t = t->parentclass;
} }
if (!t && !(source.cast->type == ev_pointer && dest->cast->type == ev_pointer && (source.cast->aux_type->type == ev_void || source.cast->aux_type->type == ev_variant))) if (!t && !(source.cast->type == ev_pointer && dest->cast->type == ev_pointer && (source.cast->aux_type->type == ev_void || source.cast->aux_type->type == ev_variant)) && source.cast->type != ev_variant && dest->cast->type != ev_variant)
{ //extra check to allow void*->any* { //extra check to allow void*->any*
char typea[256]; char typea[256];
char typeb[256]; char typeb[256];
if ((dest->cast->type == ev_float || dest->cast->type == ev_integer) && (source.cast->type == ev_float || source.cast->type == ev_integer)) if (source.cast->type == ev_variant || dest->cast->type == ev_variant)
QCC_PR_ParseWarning(WARN_IMPLICITVARIANTCAST, "type mismatch: %s %s to %s %s.%s", typea, QCC_GetSRefName(source), typeb, QCC_GetSRefName(dest->base), QCC_GetSRefName(dest->index));
else if ((dest->cast->type == ev_float || dest->cast->type == ev_integer) && (source.cast->type == ev_float || source.cast->type == ev_integer))
source = QCC_SupplyConversion(source, dest->cast->type, true); source = QCC_SupplyConversion(source, dest->cast->type, true);
else else
{ {
@ -11582,6 +11553,9 @@ void QCC_WriteAsmFunction(QCC_function_t *sc, unsigned int firststatement, QCC_d
QCC_type_t *type; QCC_type_t *type;
char typebuf[512]; char typebuf[512];
if (sc->parentscope) //don't print dupes.
return;
if (flag_guiannotate) if (flag_guiannotate)
QCC_WriteGUIAsmFunction(sc, firststatement); QCC_WriteGUIAsmFunction(sc, firststatement);
@ -13052,6 +13026,7 @@ void QCC_PR_ExpandUnionToFields(QCC_type_t *type, unsigned int *fields)
#define PIF_WRAP 1 //new initialisation is meant to wrap an existing one. #define PIF_WRAP 1 //new initialisation is meant to wrap an existing one.
#define PIF_STRONGER 2 //previous initialisation was weak. #define PIF_STRONGER 2 //previous initialisation was weak.
//basedef can be null, meaning its initialising a temp
void QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *basedef, QCC_sref_t def, unsigned int flags) void QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *basedef, QCC_sref_t def, unsigned int flags)
{ {
QCC_sref_t tmp; QCC_sref_t tmp;
@ -13112,7 +13087,7 @@ void QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *basedef, QCC_sref_t d
strncpy(fname, QCC_PR_ParseName(), sizeof(fname)); strncpy(fname, QCC_PR_ParseName(), sizeof(fname));
//if the builtin already exists, just use that dfunction instead //if the builtin already exists, just use that dfunction instead
if (basedef->initialized) if (basedef && basedef->initialized)
{ {
if (*fname) if (*fname)
{ {
@ -13158,34 +13133,36 @@ void QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *basedef, QCC_sref_t d
} }
else else
{ {
if (flags&PIF_WRAP) if (basedef)
{ {
if (!basedef->initialized || !def.sym->symboldata[def.ofs]._int) if (flags&PIF_WRAP)
QCC_PR_ParseErrorPrintSRef (ERR_REDECLARATION, def, "wrapper function does not wrap anything");
}
else if (basedef->initialized == 1 && !(flags & PIF_STRONGER))
{
//normally this is an error, but to aid supporting new stuff with old, we convert it into a warning if a vanilla(ish) qc function replaces extension builtins.
//the qc function is the one that is used, but there is a warning so you know how to gain efficiency.
int bi = -1;
if (def.cast->type == ev_function && !arraysize)
{ {
if (!strcmp(defname, "anglemod") || !strcmp(defname, "crossproduct")) if (!basedef->initialized || !def.sym->symboldata[def.ofs]._int)
bi = def.sym->symboldata[def.ofs]._int; QCC_PR_ParseErrorPrintSRef (ERR_REDECLARATION, def, "wrapper function does not wrap anything");
} }
if (bi <= 0 || bi >= numfunctions) else if (basedef->initialized == 1 && !(flags & PIF_STRONGER))
bi = 0;
else
bi = functions[bi].code;
if (bi < 0)
{ {
QCC_PR_ParseWarning(WARN_NOTSTANDARDBEHAVIOUR, "%s already declared as a builtin", defname); //normally this is an error, but to aid supporting new stuff with old, we convert it into a warning if a vanilla(ish) qc function replaces extension builtins.
QCC_PR_ParsePrintSRef(WARN_NOTSTANDARDBEHAVIOUR, def); //the qc function is the one that is used, but there is a warning so you know how to gain efficiency.
basedef->initialized = 3; int bi = -1;
if (def.cast->type == ev_function && !arraysize)
{
if (!strcmp(defname, "anglemod") || !strcmp(defname, "crossproduct"))
bi = def.sym->symboldata[def.ofs]._int;
}
if (bi <= 0 || bi >= numfunctions)
bi = 0;
else
bi = functions[bi].code;
if (bi < 0)
{
QCC_PR_ParseWarning(WARN_NOTSTANDARDBEHAVIOUR, "%s already declared as a builtin", defname);
QCC_PR_ParsePrintSRef(WARN_NOTSTANDARDBEHAVIOUR, def);
basedef->initialized = 3;
}
else
QCC_PR_ParseErrorPrintSRef (ERR_REDECLARATION, def, "redeclaration of function body");
} }
else
QCC_PR_ParseErrorPrintSRef (ERR_REDECLARATION, def, "redeclaration of function body");
} }
if (pr_scope) if (pr_scope)
@ -13213,7 +13190,7 @@ void QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *basedef, QCC_sref_t d
f = QCC_PR_ParseImmediateStatements (def.sym, type, flags&PIF_WRAP); f = QCC_PR_ParseImmediateStatements (def.sym, type, flags&PIF_WRAP);
//allow dupes if its a builtin //allow dupes if its a builtin
if (!f->code && basedef->initialized) if (basedef && !f->code && basedef->initialized)
{ {
for (i = 1; i < numfunctions; i++) for (i = 1; i < numfunctions; i++)
{ {
@ -13290,7 +13267,7 @@ void QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *basedef, QCC_sref_t d
tmp = QCC_EvaluateCast(tmp, type, true); tmp = QCC_EvaluateCast(tmp, type, true);
} }
if (!basedef->scope || basedef->constant || basedef->isstatic) if (basedef && (!basedef->scope || basedef->constant || basedef->isstatic))
{ {
tmp.sym->referenced = true; tmp.sym->referenced = true;
if (!tmp.sym->constant) if (!tmp.sym->constant)
@ -13368,6 +13345,17 @@ void QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *basedef, QCC_sref_t d
else else
QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_FNC], rhs, def, NULL, STFL_PRESERVEA|STFL_PRESERVEB)); QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_FNC], rhs, def, NULL, STFL_PRESERVEA|STFL_PRESERVEB));
} }
else if (def.cast->type == ev_string)
{
rhs.cast = def.cast = type_string;
if (type->size - i == 1)
{
QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_S], rhs, def, NULL, STFL_PRESERVEB));
return;
}
else
QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_S], rhs, def, NULL, STFL_PRESERVEA|STFL_PRESERVEB));
}
else if (def.cast->type == ev_entity) else if (def.cast->type == ev_entity)
{ {
rhs.cast = def.cast = type_entity; rhs.cast = def.cast = type_entity;

View file

@ -3886,6 +3886,15 @@ pbool QCC_PR_CheckToken (const char *string)
return true; return true;
} }
pbool QCC_PR_PeekToken (const char *string)
{
if (pr_token_type != tt_punct)
return false;
if (STRCMP (string, pr_token))
return false;
return true;
}
pbool QCC_PR_CheckImmediate (const char *string) pbool QCC_PR_CheckImmediate (const char *string)
{ {
if (pr_token_type != tt_immediate) if (pr_token_type != tt_immediate)

View file

@ -1462,7 +1462,7 @@ pbool QCC_WriteData (int crc)
} }
} }
*/ */
if (!def->referenced) if (!def->symbolheader->used)
{ {
int wt = def->constant?WARN_NOTREFERENCEDCONST:WARN_NOTREFERENCED; int wt = def->constant?WARN_NOTREFERENCEDCONST:WARN_NOTREFERENCED;
pr_scope = def->scope; pr_scope = def->scope;
@ -1504,7 +1504,7 @@ pbool QCC_WriteData (int crc)
if (def->strip || !def->symbolheader->used) if (def->strip || !def->symbolheader->used)
{ {
#ifdef DEBUG_DUMP #ifdef DEBUG_DUMP
printf("code: %s:%i: strip %s %s@%i;\n", strings+def->s_file, def->s_line, def->type->name, def->name, def->ofs); printf("code: %s:%i: strip %s %s@%i;\n", def->filen, def->s_line, def->type->name, def->name, def->ofs);
#endif #endif
continue; continue;
} }
@ -1550,9 +1550,9 @@ pbool QCC_WriteData (int crc)
#ifdef DEBUG_DUMP #ifdef DEBUG_DUMP
if (def->scope) if (def->scope)
printf("code: %s:%i: strip local %s %s@%i;\n", strings+def->s_file, def->s_line, def->type->name, def->name, def->ofs); printf("code: %s:%i: strip local %s %s@%i;\n", def->filen, def->s_line, def->type->name, def->name, def->ofs);
else if (def->constant) else if (def->constant)
printf("code: %s:%i: strip const %s %s@%i;\n", strings+def->s_file, def->s_line, def->type->name, def->name, def->ofs); printf("code: %s:%i: strip const %s %s@%i;\n", def->filen, def->s_line, def->type->name, def->name, def->ofs);
#endif #endif
continue; continue;
} }
@ -1590,19 +1590,19 @@ pbool QCC_WriteData (int crc)
#ifdef DEBUG_DUMP #ifdef DEBUG_DUMP
if ((dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)) == ev_string) if ((dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)) == ev_string)
printf("code: %s:%i: %s%s%s %s@%i = \"%s\"\n", strings+def->s_file, def->s_line, dd->type&DEF_SAVEGLOBAL?"save ":"nosave ", dd->type&DEF_SHARED?"shared ":"", basictypenames[dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)], strings+dd->s_name, dd->ofs, ((unsigned)def->symboldata[def->ofs].string>=(unsigned)strofs)?"???":(strings + def->symboldata[def->ofs].string)); printf("code: %s:%i: %s%s%s %s@%i = \"%s\"\n", def->filen, def->s_line, dd->type&DEF_SAVEGLOBAL?"save ":"nosave ", dd->type&DEF_SHARED?"shared ":"", basictypenames[dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)], strings+dd->s_name, dd->ofs, ((unsigned)def->symboldata[def->ofs].string>=(unsigned)strofs)?"???":(strings + def->symboldata[def->ofs].string));
else if ((dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)) == ev_float) else if ((dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)) == ev_float)
printf("code: %s:%i: %s%s%s %s@%i = %g\n", strings+def->s_file, def->s_line, dd->type&DEF_SAVEGLOBAL?"save ":"nosave ", dd->type&DEF_SHARED?"shared ":"", basictypenames[dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)], strings+dd->s_name, dd->ofs, def->symboldata[def->ofs]._float); printf("code: %s:%i: %s%s%s %s@%i = %g\n", def->filen, def->s_line, dd->type&DEF_SAVEGLOBAL?"save ":"nosave ", dd->type&DEF_SHARED?"shared ":"", basictypenames[dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)], strings+dd->s_name, dd->ofs, def->symboldata[def->ofs]._float);
else if ((dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)) == ev_integer) else if ((dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)) == ev_integer)
printf("code: %s:%i: %s%s%s %s@%i = %i\n", strings+def->s_file, def->s_line, dd->type&DEF_SAVEGLOBAL?"save ":"nosave ", dd->type&DEF_SHARED?"shared ":"", basictypenames[dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)], strings+dd->s_name, dd->ofs, def->symboldata[def->ofs]._int); printf("code: %s:%i: %s%s%s %s@%i = %i\n", def->filen, def->s_line, dd->type&DEF_SAVEGLOBAL?"save ":"nosave ", dd->type&DEF_SHARED?"shared ":"", basictypenames[dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)], strings+dd->s_name, dd->ofs, def->symboldata[def->ofs]._int);
else if ((dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)) == ev_vector) else if ((dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)) == ev_vector)
printf("code: %s:%i: %s%s%s %s@%i = '%g %g %g'\n", strings+def->s_file, def->s_line, dd->type&DEF_SAVEGLOBAL?"save ":"nosave ", dd->type&DEF_SHARED?"shared ":"", basictypenames[dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)], strings+dd->s_name, dd->ofs, def->symboldata[def->ofs].vector[0], def->symboldata[def->ofs].vector[1], def->symboldata[def->ofs].vector[2]); printf("code: %s:%i: %s%s%s %s@%i = '%g %g %g'\n", def->filen, def->s_line, dd->type&DEF_SAVEGLOBAL?"save ":"nosave ", dd->type&DEF_SHARED?"shared ":"", basictypenames[dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)], strings+dd->s_name, dd->ofs, def->symboldata[def->ofs].vector[0], def->symboldata[def->ofs].vector[1], def->symboldata[def->ofs].vector[2]);
else if ((dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)) == ev_function) else if ((dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)) == ev_function)
printf("code: %s:%i: %s%s%s %s@%i = %i(%s)\n", strings+def->s_file, def->s_line, dd->type&DEF_SAVEGLOBAL?"save ":"nosave ", dd->type&DEF_SHARED?"shared ":"", basictypenames[dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)], strings+dd->s_name, dd->ofs, def->symboldata[def->ofs].function, def->symboldata[def->ofs].function >= numfunctions?"???":functions[def->symboldata[def->ofs].function].name); printf("code: %s:%i: %s%s%s %s@%i = %i(%s)\n", def->filen, def->s_line, dd->type&DEF_SAVEGLOBAL?"save ":"nosave ", dd->type&DEF_SHARED?"shared ":"", basictypenames[dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)], strings+dd->s_name, dd->ofs, def->symboldata[def->ofs].function, def->symboldata[def->ofs].function >= numfunctions?"???":functions[def->symboldata[def->ofs].function].name);
else if ((dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)) == ev_field) else if ((dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)) == ev_field)
printf("code: %s:%i: %s%s%s %s@%i = @%i\n", strings+def->s_file, def->s_line, dd->type&DEF_SAVEGLOBAL?"save ":"nosave ", dd->type&DEF_SHARED?"shared ":"", basictypenames[dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)], strings+dd->s_name, dd->ofs, def->symboldata[def->ofs]._int); printf("code: %s:%i: %s%s%s %s@%i = @%i\n", def->filen, def->s_line, dd->type&DEF_SAVEGLOBAL?"save ":"nosave ", dd->type&DEF_SHARED?"shared ":"", basictypenames[dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)], strings+dd->s_name, dd->ofs, def->symboldata[def->ofs]._int);
else else
printf("code: %s:%i: %s%s%s %s@%i\n", strings+def->s_file, def->s_line, dd->type&DEF_SAVEGLOBAL?"save ":"nosave ", dd->type&DEF_SHARED?"shared ":"", basictypenames[dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)], strings+dd->s_name, dd->ofs); printf("code: %s:%i: %s%s%s %s@%i\n", def->filen, def->s_line, dd->type&DEF_SAVEGLOBAL?"save ":"nosave ", dd->type&DEF_SHARED?"shared ":"", basictypenames[dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)], strings+dd->s_name, dd->ofs);
#endif #endif
} }

View file

@ -506,9 +506,18 @@ model_t *QDECL SVPR_GetCModel(world_t *w, int modelindex)
{ {
if ((unsigned int)modelindex < MAX_PRECACHE_MODELS) if ((unsigned int)modelindex < MAX_PRECACHE_MODELS)
{ {
model_t *mod;
if (!sv.models[modelindex] && sv.strings.model_precache[modelindex]) if (!sv.models[modelindex] && sv.strings.model_precache[modelindex])
sv.models[modelindex] = Mod_ForName(Mod_FixName(sv.strings.model_precache[modelindex], sv.modelname), MLV_WARN); sv.models[modelindex] = Mod_ForName(Mod_FixName(sv.strings.model_precache[modelindex], sv.modelname), MLV_WARN);
return sv.models[modelindex]; mod = sv.models[modelindex];
if (mod && mod->loadstate != MLS_LOADED)
{
if (mod->loadstate == MLS_LOADING)
COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING);
if (mod->loadstate != MLS_LOADED)
mod = NULL; //gah, it failed!
}
return mod;
} }
else else
return NULL; return NULL;
@ -528,7 +537,7 @@ static void QDECL SVPR_Get_FrameState(world_t *w, wedict_t *ent, framestate_t *f
#if defined(SKELETALOBJECTS) || defined(RAGDOLL) #if defined(SKELETALOBJECTS) || defined(RAGDOLL)
if (ent->xv->skeletonindex) if (ent->xv->skeletonindex)
skel_lookup(w->progs, ent->xv->skeletonindex, fstate); skel_lookup(w, ent->xv->skeletonindex, fstate);
#endif #endif
} }
@ -10253,6 +10262,9 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"skel_delete", PF_skel_delete, 0, 0, 0, 275, D("void(float skel)", "Deletes a skeletal object. The actual delete is delayed, allowing the skeletal object to be deleted in an entity's predraw function yet still be valid by the time the addentity+renderscene builtins need it. Also uninstanciates any ragdoll currently in effect on the skeletal object.")}, // (FTE_CSQC_SKELETONOBJECTS) {"skel_delete", PF_skel_delete, 0, 0, 0, 275, D("void(float skel)", "Deletes a skeletal object. The actual delete is delayed, allowing the skeletal object to be deleted in an entity's predraw function yet still be valid by the time the addentity+renderscene builtins need it. Also uninstanciates any ragdoll currently in effect on the skeletal object.")}, // (FTE_CSQC_SKELETONOBJECTS)
{"frameforname", PF_frameforname, 0, 0, 0, 276, D("float(float modidx, string framename)", "Looks up a framegroup from a model by name, avoiding the need for hardcoding. Returns -1 on error.")},// (FTE_CSQC_SKELETONOBJECTS) {"frameforname", PF_frameforname, 0, 0, 0, 276, D("float(float modidx, string framename)", "Looks up a framegroup from a model by name, avoiding the need for hardcoding. Returns -1 on error.")},// (FTE_CSQC_SKELETONOBJECTS)
{"frameduration", PF_frameduration, 0, 0, 0, 277, D("float(float modidx, float framenum)", "Retrieves the duration (in seconds) of the specified framegroup.")},// (FTE_CSQC_SKELETONOBJECTS) {"frameduration", PF_frameduration, 0, 0, 0, 277, D("float(float modidx, float framenum)", "Retrieves the duration (in seconds) of the specified framegroup.")},// (FTE_CSQC_SKELETONOBJECTS)
{"processmodelevents",PF_processmodelevents,0, 0, 0, 0, D("void(float modidx, float framenum, __inout float basetime, float targettime, void(float timestamp, int code, string data) callback)", "Calls a callback for each event that has been reached. Basetime is set to targettime.")},
{"getnextmodelevent",PF_getnextmodelevent,0, 0, 0, 0, D("float(float modidx, float framenum, __inout float basetime, float targettime, __out int code, __out string data)", "Reports the next event within a model's animation. Returns a boolean if an event was found between basetime and targettime. Writes to basetime,code,data arguments (if an event was found, basetime is set to the event's time, otherwise to targettime).\nWARNING: this builtin cannot deal with multiple events with the same timestamp (only the first will be reported).")},
{"getmodeleventidx",PF_getmodeleventidx,0, 0, 0, 0, D("float(float modidx, float framenum, int eventidx, __out float timestamp, __out int code, __out string data)", "Reports an indexed event within a model's animation. Writes to timestamp,code,data arguments on success. Returns false if the animation/event/model was out of range/invalid. Does not consider looping animations (retry from index 0 if it fails and you know that its a looping animation). This builtin is more annoying to use than getnextmodelevent, but can be made to deal with multiple events with the exact same timestamp.")},
{"crossproduct", PF_crossproduct, 0, 0, 0, 0, D("#define dotproduct(v1,v2) ((vector)(v1)*(vector)(v2))\nvector(vector v1, vector v2)", "Small helper function to calculate the crossproduct of two vectors.")}, {"crossproduct", PF_crossproduct, 0, 0, 0, 0, D("#define dotproduct(v1,v2) ((vector)(v1)*(vector)(v2))\nvector(vector v1, vector v2)", "Small helper function to calculate the crossproduct of two vectors.")},
@ -10349,8 +10361,8 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"drawrotsubpic", PF_Fixme, 0, 0, 0, 0, D("void(vector pivot, vector mins, vector maxs, string pic, vector txmin, vector txsize, vector rgb, vector alphaandangles)", "Overcomplicated draw function for over complicated people. Positions follow drawrotpic, while texture coords follow drawsubpic. Due to argument count limitations in builtins, the alpha value and angles are combined into separate fields of a vector (tip: use fteqcc's [alpha, angle] feature.")}, {"drawrotsubpic", PF_Fixme, 0, 0, 0, 0, D("void(vector pivot, vector mins, vector maxs, string pic, vector txmin, vector txsize, vector rgb, vector alphaandangles)", "Overcomplicated draw function for over complicated people. Positions follow drawrotpic, while texture coords follow drawsubpic. Due to argument count limitations in builtins, the alpha value and angles are combined into separate fields of a vector (tip: use fteqcc's [alpha, angle] feature.")},
//330 //330
{"getstati", PF_Fixme, 0, 0, 0, 330, D("float(float stnum)", "Retrieves the numerical value of the given EV_INTEGER or EV_ENTITY stat (converted to a float).")},// (EXT_CSQC) {"getstati", PF_Fixme, 0, 0, 0, 330, D("#define getstati_punf(stnum) (float)(__variant)getstati(stnum)\nint(float stnum)", "Retrieves the numerical value of the given EV_INTEGER or EV_ENTITY stat (converted to a float).")},// (EXT_CSQC)
{"getstatf", PF_Fixme, 0, 0, 0, 331, D("#define getstatbits getstatf\nfloat(float stnum, optional float firstbit, optional float bitcount)", "Retrieves the numerical value of the given EV_FLOAT stat. If firstbit and bitcount are specified, retrieves the upper bits of the STAT_ITEMS stat.")},// (EXT_CSQC) {"getstatf", PF_Fixme, 0, 0, 0, 331, D("#define getstatbits getstatf\nfloat(float stnum, optional float firstbit, optional float bitcount)", "Retrieves the numerical value of the given EV_FLOAT stat. If firstbit and bitcount are specified, retrieves the upper bits of the STAT_ITEMS stat (converted into a float, so there are no VM dependancies).")},// (EXT_CSQC)
{"getstats", PF_Fixme, 0, 0, 0, 332, D("string(float stnum)", "Retrieves the value of the given EV_STRING stat, as a tempstring.\nOlder engines may use 4 consecutive integer stats, with a limit of 15 chars (yes, really. 15.), but "FULLENGINENAME" uses a separate namespace for string stats and has a much higher length limit.")}, {"getstats", PF_Fixme, 0, 0, 0, 332, D("string(float stnum)", "Retrieves the value of the given EV_STRING stat, as a tempstring.\nOlder engines may use 4 consecutive integer stats, with a limit of 15 chars (yes, really. 15.), but "FULLENGINENAME" uses a separate namespace for string stats and has a much higher length limit.")},
{"getplayerstat", PF_Fixme, 0, 0, 0, 0, D("__variant(float playernum, float statnum, float stattype)", "Retrieves a specific player's stat, matching the type specified on the server. This builtin is primarily intended for mvd playback where ALL players are known. For EV_ENTITY, world will be returned if the entity is not in the pvs, use type-punning with EV_INTEGER to get the entity number if you just want to see if its set. STAT_ITEMS should be queried as an EV_INTEGER on account of runes and items2 being packed into the upper bits.")}, {"getplayerstat", PF_Fixme, 0, 0, 0, 0, D("__variant(float playernum, float statnum, float stattype)", "Retrieves a specific player's stat, matching the type specified on the server. This builtin is primarily intended for mvd playback where ALL players are known. For EV_ENTITY, world will be returned if the entity is not in the pvs, use type-punning with EV_INTEGER to get the entity number if you just want to see if its set. STAT_ITEMS should be queried as an EV_INTEGER on account of runes and items2 being packed into the upper bits.")},

View file

@ -421,10 +421,13 @@ typedef struct
float animate; float animate;
qboolean draw:1; qboolean draw:1;
qboolean orient:1; qboolean orient:1;
qboolean isoffset:1;
int orientpeer; int orientpeer;
//ode info //ode info
int geomshape; int geomshape;
float relmatrix[12];
float inverserelmatrix[12];
vec3_t dimensions; vec3_t dimensions;
float mass; float mass;
} rbebodyinfo_t; } rbebodyinfo_t;

View file

@ -3240,7 +3240,7 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli
framestate_t fs; framestate_t fs;
fs.skeltype = SKEL_IDENTITY; fs.skeltype = SKEL_IDENTITY;
fs.bonecount = 0; fs.bonecount = 0;
skel_lookup(sv.world.progs, ent->xv->skeletonindex, &fs); skel_lookup(&sv.world, ent->xv->skeletonindex, &fs);
if (fs.skeltype == SKEL_RELATIVE && fs.bonecount) if (fs.skeltype == SKEL_RELATIVE && fs.bonecount)
{ {
Bones_To_PosQuat4(fs.bonecount, fs.bonestate, AllocateBoneSpace(pack, state->bonecount = fs.bonecount, &state->boneoffset)); Bones_To_PosQuat4(fs.bonecount, fs.bonestate, AllocateBoneSpace(pack, state->bonecount = fs.bonecount, &state->boneoffset));

View file

@ -1135,6 +1135,7 @@ void SVC_GetInfo (char *challenge, int fullstatus)
{ {
//dpmaster support //dpmaster support
char response[MAX_UDP_PACKET]; char response[MAX_UDP_PACKET];
char protocolname[MAX_QPATH];
client_t *cl; client_t *cl;
int numclients = 0; int numclients = 0;
@ -1164,6 +1165,7 @@ void SVC_GetInfo (char *challenge, int fullstatus)
else else
gamestatus = ""; gamestatus = "";
COM_ParseOut(com_protocolname.string, protocolname, sizeof(protocolname));
resp = response; resp = response;
@ -1184,7 +1186,7 @@ void SVC_GetInfo (char *challenge, int fullstatus)
//this is a DP protocol query, so some QW fields are not needed //this is a DP protocol query, so some QW fields are not needed
Info_RemoveKey(resp, "maxclients"); //replaced with sv_maxclients Info_RemoveKey(resp, "maxclients"); //replaced with sv_maxclients
Info_RemoveKey(resp, "map"); //replaced with mapname Info_RemoveKey(resp, "map"); //replaced with mapname
Info_SetValueForKey(resp, "gamename", com_protocolname.string, sizeof(response) - (resp-response)); Info_SetValueForKey(resp, "gamename", protocolname, sizeof(response) - (resp-response));
Info_SetValueForKey(resp, "modname", FS_GetGamedir(true), sizeof(response) - (resp-response)); Info_SetValueForKey(resp, "modname", FS_GetGamedir(true), sizeof(response) - (resp-response));
// Info_SetValueForKey(resp, "gamedir", FS_GetGamedir(true), sizeof(response) - (resp-response)); // Info_SetValueForKey(resp, "gamedir", FS_GetGamedir(true), sizeof(response) - (resp-response));
Info_SetValueForKey(resp, "protocol", va("%d", NQ_NETCHAN_VERSION), sizeof(response) - (resp-response)); Info_SetValueForKey(resp, "protocol", va("%d", NQ_NETCHAN_VERSION), sizeof(response) - (resp-response));

View file

@ -65,7 +65,8 @@ qboolean World_CheckBottom (world_t *world, wedict_t *ent, vec3_t up)
sign = (up[a2]>0)?1:-1; sign = (up[a2]>0)?1:-1;
VectorAdd (ent->v->origin, ent->v->mins, mins); VectorAdd (ent->v->origin, ent->v->mins, mins);
if (world->worldmodel->fromgame == fg_quake) #ifdef Q1BSPS
if (world->worldmodel->fromgame == fg_quake || world->worldmodel->fromgame == fg_halflife)
{ {
//quake's hulls are weird. sizes are defined as from mins to mins+hullsize. the actual maxs is ignored other than for its size. //quake's hulls are weird. sizes are defined as from mins to mins+hullsize. the actual maxs is ignored other than for its size.
hull_t *hull; hull_t *hull;
@ -75,6 +76,7 @@ qboolean World_CheckBottom (world_t *world, wedict_t *ent, vec3_t up)
VectorAdd (maxs, hull->clip_maxs, maxs); VectorAdd (maxs, hull->clip_maxs, maxs);
} }
else else
#endif
VectorAdd (ent->v->origin, ent->v->maxs, maxs); VectorAdd (ent->v->origin, ent->v->maxs, maxs);
// if all of the points under the corners are solid world, don't bother // if all of the points under the corners are solid world, don't bother

View file

@ -2404,6 +2404,7 @@ qboolean SV_Physics (void)
int i; int i;
qboolean moved = false; qboolean moved = false;
int maxtics; int maxtics;
double trueframetime = host_frametime;
//keep gravity tracking the cvar properly //keep gravity tracking the cvar properly
movevars.gravity = sv_gravity.value; movevars.gravity = sv_gravity.value;
@ -2425,6 +2426,7 @@ qboolean SV_Physics (void)
if (host_frametime < sv_maxtic.value && realtime) if (host_frametime < sv_maxtic.value && realtime)
{ {
// sv.time+=host_frametime; // sv.time+=host_frametime;
host_frametime = trueframetime;
return false; //don't bother with the whole server thing for a bit longer return false; //don't bother with the whole server thing for a bit longer
} }
if (host_frametime > sv_maxtic.value) if (host_frametime > sv_maxtic.value)
@ -2446,6 +2448,7 @@ qboolean SV_Physics (void)
default: default:
break; break;
} }
host_frametime = trueframetime;
return true; return true;
} }
@ -2581,6 +2584,7 @@ qboolean SV_Physics (void)
sv.world.physicstime += host_frametime; sv.world.physicstime += host_frametime;
} }
host_frametime = trueframetime;
return moved; return moved;
} }
#endif #endif

View file

@ -254,15 +254,20 @@ static qboolean VK_CreateSwapChain(void)
vk.dopresent(NULL); //make sure they're all pushed through. vk.dopresent(NULL); //make sure they're all pushed through.
VkAssert(vkGetPhysicalDeviceSurfaceFormatsKHR(vk.gpu, vk.surface, &fmtcount, NULL)); if (!vk.surface)
surffmts = malloc(sizeof(VkSurfaceFormatKHR)*fmtcount); return true;
VkAssert(vkGetPhysicalDeviceSurfaceFormatsKHR(vk.gpu, vk.surface, &fmtcount, surffmts)); else
{
VkAssert(vkGetPhysicalDeviceSurfaceFormatsKHR(vk.gpu, vk.surface, &fmtcount, NULL));
surffmts = malloc(sizeof(VkSurfaceFormatKHR)*fmtcount);
VkAssert(vkGetPhysicalDeviceSurfaceFormatsKHR(vk.gpu, vk.surface, &fmtcount, surffmts));
VkAssert(vkGetPhysicalDeviceSurfacePresentModesKHR(vk.gpu, vk.surface, &presentmodes, NULL)); VkAssert(vkGetPhysicalDeviceSurfacePresentModesKHR(vk.gpu, vk.surface, &presentmodes, NULL));
presentmode = malloc(sizeof(VkPresentModeKHR)*presentmodes); presentmode = malloc(sizeof(VkPresentModeKHR)*presentmodes);
VkAssert(vkGetPhysicalDeviceSurfacePresentModesKHR(vk.gpu, vk.surface, &presentmodes, presentmode)); VkAssert(vkGetPhysicalDeviceSurfacePresentModesKHR(vk.gpu, vk.surface, &presentmodes, presentmode));
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk.gpu, vk.surface, &surfcaps); vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk.gpu, vk.surface, &surfcaps);
}
swapinfo.surface = vk.surface; swapinfo.surface = vk.surface;
swapinfo.minImageCount = surfcaps.minImageCount+vk.triplebuffer; swapinfo.minImageCount = surfcaps.minImageCount+vk.triplebuffer;
@ -2110,11 +2115,19 @@ qboolean VK_SCR_GrabBackBuffer(void)
if (vk.frame) //erk, we already have one... if (vk.frame) //erk, we already have one...
return true; return true;
RSpeedRemark(); RSpeedRemark();
VK_FencedCheck(); VK_FencedCheck();
if (!vk.surface)
{
// if (Media_Capturing() != 2)
// Cmd_ExecuteString("quit force\n", RESTRICT_LOCAL);
return false; //headless...
}
if (!vk.unusedframes) if (!vk.unusedframes)
{ {
struct vkframe *newframe = Z_Malloc(sizeof(*vk.frame)); struct vkframe *newframe = Z_Malloc(sizeof(*vk.frame));
@ -2745,8 +2758,14 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat
const char *extensions[8]; const char *extensions[8];
qboolean nvglsl = false; qboolean nvglsl = false;
uint32_t extensions_count = 0; uint32_t extensions_count = 0;
extensions[extensions_count++] = sysextname; qboolean headless = false;
extensions[extensions_count++] = VK_KHR_SURFACE_EXTENSION_NAME; if (sysextname)
{
extensions[extensions_count++] = sysextname;
extensions[extensions_count++] = VK_KHR_SURFACE_EXTENSION_NAME;
}
else
headless = true;
if (vk_debug.ival) if (vk_debug.ival)
extensions[extensions_count++] = VK_EXT_DEBUG_REPORT_EXTENSION_NAME; extensions[extensions_count++] = VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
@ -2877,18 +2896,21 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat
vkGetPhysicalDeviceProperties(devs[i], &props); vkGetPhysicalDeviceProperties(devs[i], &props);
vkGetPhysicalDeviceQueueFamilyProperties(devs[i], &queue_count, NULL); vkGetPhysicalDeviceQueueFamilyProperties(devs[i], &queue_count, NULL);
for (j = 0; j < queue_count; j++) if (!headless)
{ {
VkBool32 supportsPresent; for (j = 0; j < queue_count; j++)
VkAssert(vkGetPhysicalDeviceSurfaceSupportKHR(devs[i], j, vk.surface, &supportsPresent)); {
if (supportsPresent) VkBool32 supportsPresent = false;
break; //okay, this one should be usable VkAssert(vkGetPhysicalDeviceSurfaceSupportKHR(devs[i], j, vk.surface, &supportsPresent));
} if (supportsPresent)
if (j == queue_count) break; //okay, this one should be usable
{ }
//no queues can present to that surface, so I guess we can't use that device if (j == queue_count)
Con_DPrintf("vulkan: ignoring device %s as it can't present to window\n", props.deviceName); {
continue; //no queues can present to that surface, so I guess we can't use that device
Con_DPrintf("vulkan: ignoring device %s as it can't present to window\n", props.deviceName);
continue;
}
} }
if (!vk.gpu) if (!vk.gpu)
@ -3022,8 +3044,11 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat
{ {
for (i = 0; i < queue_count; i++) for (i = 0; i < queue_count; i++)
{ {
VkBool32 supportsPresent; VkBool32 supportsPresent = false;
VkAssert(vkGetPhysicalDeviceSurfaceSupportKHR(vk.gpu, i, vk.surface, &supportsPresent)); if (headless)
supportsPresent = true; //won't be used anyway.
else
VkAssert(vkGetPhysicalDeviceSurfaceSupportKHR(vk.gpu, i, vk.surface, &supportsPresent));
if ((queueprops[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && supportsPresent) if ((queueprops[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && supportsPresent)
{ {