threaded loading code and associated/extensive tweaks.

unified image loading code a little between renderers.
support switching worldmodel in csqc. also associated bugfixes.


git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4758 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2014-10-05 20:04:11 +00:00
parent 8d72e19726
commit 7f6c2054d9
172 changed files with 9730 additions and 10862 deletions

View File

@ -50,6 +50,11 @@ NATIVE_BASE_DIR?=$(BASE_DIR)
NATIVE_RELEASE_DIR?=$(RELEASE_DIR)
NATIVE_DEBUG_DIR?=$(DEBUG_DIR)
#include the appropriate games.
ifneq (,$(BRANDING))
CFLAGS+=-DBRANDING_INC=../game_$(BRANDING).h
-include game_$(BRANDING).mak
endif
#correct the gcc build when cross compiling
ifneq (,$(findstring win32,$(FTE_TARGET)))
@ -1322,11 +1327,11 @@ endif
# This is for linking the FTE icon to the MinGW target
$(OUT_DIR)/resources.o : winquake.rc
@$(WINDRES) -I$(CLIENT_DIR) -O coff $< $@
@$(WINDRES) $(CFLAGS) -I$(CLIENT_DIR) -O coff $< $@
#npAPI stuff requires some extra resources
$(OUT_DIR)/npplug.o : ftequake/npplug.rc
@$(WINDRES) -I$(CLIENT_DIR) -O coff $< $@
@$(WINDRES) $(CFLAGS) -I$(CLIENT_DIR) -O coff $< $@
#$(OUT_DIR)/%.d: %.c

View File

@ -340,7 +340,7 @@ static void Cam_CheckHighTarget(playerview_t *pv)
void Cam_SelfTrack(playerview_t *pv)
{
vec3_t vec;
if (!cl.worldmodel || cl.worldmodel->needload)
if (!cl.worldmodel || cl.worldmodel->loadstate != MLS_LOADED)
return;
if (selfcam == 1)
@ -405,7 +405,7 @@ void Cam_Track(playerview_t *pv, usercmd_t *cmd)
if (cl_hightrack.value && !pv->cam_locked)
Cam_CheckHighTarget(pv);
if (!pv->cam_auto || cls.state != ca_active || cl.worldmodel || cl.worldmodel->needload)
if (!pv->cam_auto || cls.state != ca_active || cl.worldmodel || cl.worldmodel->loadstate != MLS_LOADED)
return;
if (pv->cam_locked && (!cl.players[pv->cam_spec_track].name[0] || cl.players[pv->cam_spec_track].spectator))

View File

@ -586,7 +586,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
}
else
mod = cl.model_precache[modhandle+1];
if (mod && !mod->needload)
if (mod && mod->loadstate == MLS_LOADED)
pc = mod->funcs.NativeContents(mod, 0, 0, NULL, VM_POINTER(arg[0]), vec3_origin, vec3_origin);
else
pc = 1;//FTECONTENTS_SOLID;
@ -603,11 +603,16 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
float *angles = VM_POINTER(arg[3]);
model_t *mod;
if (modhandle >= MAX_PRECACHE_MODELS)
mod = &box_model;
{
// if (modhandle == MAX_PRECACHE_MODELS+1)
// mod = &capsule_model;
// else
mod = &box_model;
}
else
mod = cl.model_precache[modhandle+1];
if (mod)
if (mod && mod->loadstate == MLS_LOADED)
{
vec3_t p_l;
vec3_t axis[3];
@ -650,7 +655,12 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
float *angles = VM_POINTER(arg[8]);
model_t *mod;
if (modhandle >= MAX_PRECACHE_MODELS)
mod = &box_model;
{
// if (modhandle == MAX_PRECACHE_MODELS+1)
// mod = &capsule_model;
// else
mod = &box_model;
}
else
mod = cl.model_precache[modhandle+1];
@ -662,7 +672,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
origin = vec3_origin;
if (!angles)
angles = vec3_origin;
if (mod && !mod->needload)
if (mod && mod->loadstate == MLS_LOADED)
#if !defined(CLIENTONLY) || defined(CSQC_DAT)
World_TransformedTrace(mod, 0, 0, start, end, mins, maxs, fn==CG_CM_TRANSFORMEDCAPSULETRACE, &tr, origin, angles, brushmask);
#else
@ -708,10 +718,25 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
int brushmask = VM_LONG(arg[6]);
model_t *mod;
if (modhandle >= MAX_PRECACHE_MODELS)
mod = &box_model;
{
// if (modhandle == MAX_PRECACHE_MODELS+1)
// mod = &capsule_model;
// else
mod = &box_model;
}
else
mod = cl.model_precache[modhandle+1];
if (mod->loadstate != MLS_LOADED)
{
if (mod->loadstate == MLS_NOTLOADED)
Mod_LoadModel(mod, MLV_SILENT);
if (mod->loadstate == MLS_LOADING)
COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING);
if (mod->loadstate != MLS_LOADED)
mod = &box_model; //stop crashes, even if this is wrong.
}
if (!mins)
mins = vec3_origin;
if (!maxs)
@ -737,14 +762,16 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
int i;
char *mapname = VM_POINTER(arg[0]);
strcpy(cl.model_name[1], mapname);
cl.worldmodel = cl.model_precache[1] = Mod_ForName(mapname, MLV_SILENT);
if (cl.worldmodel->needload)
cl.worldmodel = cl.model_precache[1] = Mod_ForName(Mod_FixName(mapname, mapname), MLV_SILENT);
if (cl.worldmodel->loadstate == MLS_LOADING)
COM_WorkerPartialSync(cl.worldmodel, &cl.worldmodel->loadstate, MLS_LOADING);
if (cl.worldmodel->loadstate != MLS_LOADED)
Host_EndGame("Couldn't load map %s", mapname);
for (i=1 ; i<cl.model_precache[1]->numsubmodels ; i++)
{
strcpy(cl.model_name[1+i], va("*%i", i));
cl.model_precache[i+1] = Mod_ForName (cl.model_name[i+1], MLV_SILENT);
cl.model_precache[i+1] = Mod_ForName (Mod_FixName(cl.model_name[i+1], mapname), MLV_SILENT);
}
}
@ -775,6 +802,9 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
model_t *mod = VM_FROMMHANDLE(arg[0]);
if (mod)
{
if (mod->loadstate == MLS_LOADING)
COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING);
VectorCopy(mod->mins, ((float*)VM_POINTER(arg[1])));
VectorCopy(mod->maxs, ((float*)VM_POINTER(arg[2])));
}
@ -785,8 +815,13 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
{
char *name = VM_POINTER(arg[0]);
model_t *mod;
mod = Mod_ForName(name, MLV_SILENT);
if (mod->needload || mod->type == mod_dummy)
mod = Mod_ForName(Mod_FixName(name, cl.model_name[1]), MLV_SILENT);
if (mod->loadstate == MLS_LOADING)
{ //needed to ensure it really is missing
if (!COM_FCheckExists(mod->name))
COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING);
}
if (mod->loadstate == MLS_FAILED || mod->type == mod_dummy)
VM_LONG(ret) = 0;
else
VM_LONG(ret) = VM_TOMHANDLE(mod);
@ -1091,7 +1126,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
case CG_FTE_SPAWNPARTICLEEFFECT:
return pe->RunParticleEffectState(VM_POINTER(arg[0]), VM_POINTER(arg[1]), VM_FLOAT(arg[2]), VM_LONG(arg[3]), VM_POINTER(arg[4]));
case CG_FTE_SPAWNPARTICLETRAIL:
return pe->ParticleTrail(VM_POINTER(arg[0]), VM_POINTER(arg[1]), VM_LONG(arg[2]), 0, VM_POINTER(arg[3]));
return pe->ParticleTrail(VM_POINTER(arg[0]), VM_POINTER(arg[1]), VM_LONG(arg[2]), 0, NULL, VM_POINTER(arg[3]));
case CG_FTE_FREEPARTICLESTATE:
pe->DelinkTrailstate(VM_POINTER(arg[0]));
break;

View File

@ -497,6 +497,8 @@ qboolean CL_GetDemoMessage (void)
}
demoframe = host_framecount;
}
if (cls.signon < 4)
demtime = 0;
if (readdemobytes(&demopos, &msglength, 4) != 4)
{
return 0;
@ -956,7 +958,7 @@ void CL_RecordMap_f (void)
{
char demoname[MAX_QPATH];
char mapname[MAX_QPATH];
char *demoext;
char demoext[8];
Q_strncpyz(demoname, Cmd_Argv(1), sizeof(demoname));
Q_strncpyz(mapname, Cmd_Argv(2), sizeof(mapname));
CL_Disconnect_f();
@ -964,7 +966,7 @@ void CL_RecordMap_f (void)
SV_SpawnServer (mapname, NULL, false, false);
COM_DefaultExtension(demoname, ".mvd", sizeof(demoname));
demoext = COM_FileExtension(demoname);
COM_FileExtension(demoname, demoext, sizeof(demoext));
if (!strcmp(demoext, "mvd"))
{

View File

@ -2822,7 +2822,7 @@ void CL_LinkStaticEntities(void *pvs)
stat = &cl_static_entities[i].ent;
clmodel = stat->model;
if (!clmodel || clmodel->needload)
if (!clmodel || clmodel->loadstate != MLS_LOADED)
continue;
if ((!r_drawflame.ival) && (clmodel->engineflags & MDLF_FLAME))
@ -3238,6 +3238,7 @@ void CL_TransitionEntities (void)
void CL_LinkPacketEntities (void)
{
extern cvar_t gl_part_flame;
entity_t *ent;
packet_entities_t *pack;
entity_state_t *state;
@ -3252,7 +3253,7 @@ void CL_LinkPacketEntities (void)
vec3_t angles;
static int flickertime;
static int flicker;
int trailef;
int trailef, trailidx;
int modelflags;
pack = cl.currentpackentities;
@ -3382,15 +3383,17 @@ void CL_LinkPacketEntities (void)
dl->style = state->lightstyle;
dl->flags &= ~LFLAG_FLASHBLEND;
dl->flags |= (state->lightpflags & PFLAGS_NOSHADOW)?LFLAG_NOSHADOWS:0;
#ifdef RTLIGHTS
if (state->skinnum)
{
VectorCopy(ent->angles, angles);
angles[0]*=-1; //pflags matches alias models.
VectorCopy(le->angles, angles);
//if (model && model->type == mod_alias)
angles[0]*=-1; //pflags matches alias models.
AngleVectors(angles, dl->axis[0], dl->axis[1], dl->axis[2]);
VectorInverse(dl->axis[1]);
snprintf(dl->cubemapname, sizeof(dl->cubemapname), "cubemaps/%i", state->skinnum);
dl->cubetexture = R_LoadReplacementTexture(dl->cubemapname, "", IF_CUBEMAP);
R_LoadNumberedLightTexture(dl, state->skinnum);
}
#endif
}
// if set to invisible, skip
@ -3417,7 +3420,7 @@ void CL_LinkPacketEntities (void)
if (cl.model_precache_vwep[0])
{
if (state->modelindex == cl_playerindex && !cl.model_precache_vwep[0]->needload)
if (state->modelindex == cl_playerindex && !cl.model_precache_vwep[0]->loadstate != MLS_LOADED)
{
model = cl.model_precache_vwep[0];
model2 = cl.model_precache_vwep[state->modelindex2];
@ -3582,24 +3585,23 @@ void CL_LinkPacketEntities (void)
}
}
//figure out which trail this entity is using
trailef = model->particletrail;
trailidx = model->traildefaultindex;
if (state->effects & 0xff800000)
P_DefaultTrail (modelflags, &trailef, &trailidx);
if (state->u.q1.traileffectnum)
trailef = CL_TranslateParticleFromServer(state->u.q1.traileffectnum);
if (trailef == P_INVALID || pe->ParticleTrail (old_origin, ent->origin, trailef, ent->keynum, &(le->trailstate)))
//and emit it
if (trailef == P_INVALID || pe->ParticleTrail (old_origin, ent->origin, trailef, ent->keynum, ent->axis, &(le->trailstate)))
if (model->traildefaultindex >= 0)
pe->ParticleTrailIndex(old_origin, ent->origin, model->traildefaultindex, 0, &(le->trailstate));
{
extern cvar_t gl_part_flame;
if (model->particleeffect != P_INVALID && cls.allow_anyparticles && gl_part_flame.ival)
{
P_EmitEffect (ent->origin, model->particleeffect, &(le->emitstate));
}
}
pe->ParticleTrailIndex(old_origin, ent->origin, trailidx, 0, &(le->trailstate));
if (model->particleeffect != P_INVALID && cls.allow_anyparticles && gl_part_flame.ival)
P_EmitEffect (ent->origin, model->particleeffect, &(le->emitstate));
//dlights are not so customisable.
if (r_rocketlight.value)
if (r_rocketlight.value && (modelflags & MF_ROCKET))
{
float rad = 0;
vec3_t dclr;
@ -3607,55 +3609,17 @@ void CL_LinkPacketEntities (void)
dclr[0] = 2.0;
dclr[1] = 1.0;
dclr[2] = 0.25;
rad = 200;
rad += r_lightflicker.value?((flicker + state->number)&31):0;
dl = CL_AllocDlight (state->number);
memcpy(dl->axis, ent->axis, sizeof(dl->axis));
VectorCopy (ent->origin, dl->origin);
dl->die = (float)cl.time;
if (modelflags & MF_ROCKET)
{
#ifdef warningmsg
#pragma warningmsg("Replace this flag on load for hexen2 models")
#endif
#ifdef HEXEN2
if (strncmp(model->name, "models/sflesh", 13))
#endif
{ //hmm. hexen spider gibs...
rad = 200;
rad += r_lightflicker.value?((flicker + state->number)&31):0;
}
}
#ifdef HEXEN2
else if (modelflags & MFH2_FIREBALL)
{
rad = 120 - (r_lightflicker.value?(rand() % 20):10);
}
else if (modelflags & MFH2_ACIDBALL)
{
rad = 120 - (r_lightflicker.value?(rand() % 20):10);
dclr[0] = 0.5;
dclr[1] = 1;
dclr[2] = 0.25;
}
else if (modelflags & MFH2_SPIT)
{
// as far as I can tell this effect inverses the light...
dclr[0] = -dclr[0];
dclr[1] = -dclr[1];
dclr[2] = -dclr[2];
rad = 120 - (r_lightflicker.value?(rand() % 20):10);
}
#endif
if (rad)
{
dl = CL_AllocDlight (state->number);
memcpy(dl->axis, ent->axis, sizeof(dl->axis));
VectorCopy (ent->origin, dl->origin);
dl->die = (float)cl.time;
if (modelflags & MF_ROCKET)
dl->origin[2] += 1; // is this even necessary
dl->radius = rad * r_rocketlight.value;
VectorCopy(dclr, dl->color);
}
dl->origin[2] += 1; // is this even necessary
dl->radius = rad * r_rocketlight.value;
VectorCopy(dclr, dl->color);
}
}
#ifdef CSQC_DAT
@ -4337,7 +4301,7 @@ void CL_LinkPlayers (void)
float predictmsmult = 1000*cl_predict_players_frac.value;
int modelindex2;
if (!cl.worldmodel || cl.worldmodel->needload)
if (!cl.worldmodel || cl.worldmodel->loadstate != MLS_LOADED)
return;
if (cl.paused)
@ -4474,6 +4438,7 @@ void CL_LinkPlayers (void)
ent->flags = 0;
ent->model = model;
ent->forcedshader = NULL;
ent->customskin = 0;
ent->skinnum = state->skinnum;
@ -4881,7 +4846,7 @@ void CL_SetUpPlayerPrediction(qboolean dopred)
if (playertime > realtime)
playertime = realtime;
if (cl_nopred.value || /*cls.demoplayback ||*/ cl.paused || cl.worldmodel->needload)
if (cl_nopred.value || /*cls.demoplayback ||*/ cl.paused || cl.worldmodel->loadstate != MLS_LOADED)
return;
frame = &cl.inframes[cl.parsecount&UPDATE_MASK];

View File

@ -1550,10 +1550,10 @@ void CL_SendCmd (double frametime, qboolean mainloop)
CL_ProxyMenuHooks();
if (cls.demoplayback != DPB_NONE || cls.netchan.remote_address.type == NA_INVALID)
if (cls.demoplayback != DPB_NONE || !cls.state)
{
cursor_active = false;
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
if (!cls.state || cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
{
extern cvar_t cl_splitscreen;
cl.ackedmovesequence = cl.movesequence;
@ -1601,6 +1601,11 @@ void CL_SendCmd (double frametime, qboolean mainloop)
Cam_FinishMove(&cl.playerview[plnum], cmd);
#ifdef CSQC_DAT
CSQC_Input_Frame(plnum, cmd);
#endif
if (cls.state == ca_active)
{
player_state_t *from, *to;
playerview_t *pv = &cl.playerview[plnum];

View File

@ -1356,6 +1356,8 @@ void CL_ClearState (void)
{
VectorSet(cl.playerview[i].gravitydir, 0, 0, -1);
cl.playerview[i].viewheight = DEFAULT_VIEWHEIGHT;
cl.playerview[i].maxspeed = 320;
cl.playerview[i].entgravity = 1;
}
cl.minpitch = -70;
cl.maxpitch = 80;
@ -3123,7 +3125,8 @@ qboolean CL_AllowArbitaryDownload(char *localfile)
allow = cl_download_redirection.ival;
if (allow == 2)
{
char *ext = COM_FileExtension(localfile);
char ext[8];
COM_FileExtension(localfile, ext, sizeof(ext));
if (!strcmp(ext, "pak") || !strcmp(ext, "pk3") || !strcmp(ext, "pk4"))
return true;
else
@ -3707,6 +3710,8 @@ void CL_Init (void)
#endif
Ignore_Init();
CL_ClearState(); //make sure the cl.* fields are set properly if there's no ssqc or whatever.
}
@ -3722,11 +3727,14 @@ void VARGS Host_EndGame (char *message, ...)
va_list argptr;
char string[1024];
SCR_EndLoadingPlaque();
va_start (argptr,message);
vsnprintf (string,sizeof(string)-1, message,argptr);
va_end (argptr);
COM_AssertMainThread(string);
SCR_EndLoadingPlaque();
Con_TPrintf ("^&C0Host_EndGame: %s\n", string);
Con_Printf ("\n");
@ -3931,7 +3939,8 @@ void Host_BeginFileDownload(struct dl_download *dl, char *mimetype)
if (!(f->flags & HRF_FILETYPES))
{
char *ext = COM_FileExtension(f->fname);
char ext[8];
COM_FileExtension(f->fname, ext, sizeof(ext));
if (!strcmp(ext, "qwd"))
f->flags |= HRF_DEMO_QWD;
else if (!strcmp(ext, "mvd"))
@ -4044,7 +4053,7 @@ void Host_DoRunFile(hrf_t *f)
if (!(f->flags & HRF_FILETYPES))
{
char *ext;
char ext[8];
#ifdef WEBCLIENT
if (isurl(f->fname) && !f->srcfile)
@ -4068,7 +4077,7 @@ void Host_DoRunFile(hrf_t *f)
#endif
//if we get here, we have no mime type to give us any clues.
ext = COM_FileExtension(f->fname);
COM_FileExtension(f->fname, ext, sizeof(ext));
if (!strcmp(ext, "qwd"))
f->flags |= HRF_DEMO_QWD;
else if (!strcmp(ext, "mvd"))
@ -4393,6 +4402,8 @@ double Host_Frame (double time)
if (startuppending)
CL_StartCinematicOrMenu();
COM_MainThreadWork();
#ifdef PLUGINS
Plug_Tick();
#endif
@ -4429,6 +4440,8 @@ double Host_Frame (double time)
RSpeedEnd(RSPEED_SERVER);
}
#endif
while(COM_DoWork(0, false))
;
return idlesec - (realtime - oldrealtime);
}
}
@ -4471,7 +4484,11 @@ double Host_Frame (double time)
// realtime += spare/1000; //don't use it all!
spare = CL_FilterTime((realtime - oldrealtime)*1000, maxfps, maxfpsignoreserver);
if (!spare)
{
while(COM_DoWork(0, false))
;
return (cl_yieldcpu.ival || vid.isminimized)? (1.0 / maxfps - (realtime - oldrealtime)) : 0;
}
if (spare < 0 || cls.state < ca_onserver)
spare = 0; //uncapped.
if (spare > cl_sparemsec.ival)
@ -4666,7 +4683,7 @@ void CL_ReadCDKey(void)
{ //q3 cdkey
//you don't need one, just use a server without sv_strictauth set to 0.
char *buffer;
buffer = COM_LoadTempFile("q3key");
buffer = COM_LoadTempFile("q3key", NULL);
if (buffer) //a cdkey is meant to be 16 chars
{
char *chr;
@ -4807,6 +4824,8 @@ void CL_ExecInitialConfigs(char *resetcommand)
Cbuf_Execute (); //make sure any pending console commands are done with. mostly, anyway...
SCR_ShowPic_Clear(true);
Cbuf_AddText("alias restart \"changelevel .\"\n",RESTRICT_LOCAL);
Cbuf_AddText("alias startmap_sp \"map start\"\n", RESTRICT_LOCAL);
Cbuf_AddText("unbindall\n", RESTRICT_LOCAL);
Cbuf_AddText("bind volup \"inc volume 0.1\"\n", RESTRICT_LOCAL);
Cbuf_AddText("bind voldown \"inc volume -0.1\"\n", RESTRICT_LOCAL);
@ -4815,6 +4834,7 @@ void CL_ExecInitialConfigs(char *resetcommand)
Cbuf_AddText("cvarreset *\n", RESTRICT_LOCAL); //reset all cvars to their current (engine) defaults
Cbuf_AddText(resetcommand, RESTRICT_LOCAL);
Cbuf_AddText("\n", RESTRICT_LOCAL);
COM_ParsePlusSets(true);
//who should we imitate?
qrc = COM_FDepthFile("quake.rc", true); //q1
@ -4835,7 +4855,9 @@ void CL_ExecInitialConfigs(char *resetcommand)
Cbuf_AddText ("exec q3config.cfg\n", RESTRICT_LOCAL);
Cbuf_AddText ("exec autoexec.cfg\n", RESTRICT_LOCAL);
}
#ifndef QUAKETC
Cbuf_AddText ("exec fte.cfg\n", RESTRICT_LOCAL);
#endif
#ifdef QUAKESPYAPI
if (COM_FCheckExists ("frontend.cfg"))
Cbuf_AddText ("exec frontend.cfg\n", RESTRICT_LOCAL);
@ -4922,7 +4944,7 @@ void Host_Init (quakeparms_t *parms)
Sys_Init();
COM_ParsePlusSets();
COM_ParsePlusSets(false);
Cbuf_Init ();
Cmd_Init ();
V_Init ();
@ -5044,15 +5066,20 @@ void Host_Shutdown(void)
NET_Shutdown ();
#endif
Stats_Clear();
#ifdef Q3CLIENT
VMQ3_FlushStringHandles();
#endif
COM_DestroyWorkerThread();
Cvar_Shutdown();
Validation_FlushFileList();
Cmd_Shutdown();
Key_Unbindall_f();
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).
FS_Shutdown();

View File

@ -426,9 +426,9 @@ int CL_IsDownloading(const char *localname)
qboolean CL_EnqueDownload(const char *filename, const char *localname, unsigned int flags)
{
extern cvar_t cl_downloads;
char *ext;
downloadlist_t *dl;
qboolean webdl = false;
char ext[8];
if (!strncmp(filename, "http://", 7))
{
if (!localname)
@ -444,7 +444,7 @@ qboolean CL_EnqueDownload(const char *filename, const char *localname, unsigned
if (cls.demoplayback && cls.demoplayback != DPB_EZTV)
return false;
}
ext = COM_FileExtension(localname);
COM_FileExtension(localname, ext, sizeof(ext));
if (!stricmp(ext, "dll") || !stricmp(ext, "so") || strchr(localname, '\\') || strchr(localname, ':') || strstr(localname, ".."))
{
Con_Printf("Denying download of \"%s\"\n", filename);
@ -640,7 +640,7 @@ void CL_SendDownloadStartRequest(char *filename, char *localname, unsigned int f
void CL_DownloadFinished(qdownload_t *dl)
{
int i;
char *ext;
char ext[8];
char filename[MAX_QPATH];
char tempname[MAX_QPATH];
@ -652,7 +652,7 @@ void CL_DownloadFinished(qdownload_t *dl)
COM_RefreshFSCache_f();
ext = COM_FileExtension(filename);
COM_FileExtension(filename, ext, sizeof(ext));
//should probably ask the filesytem code if its a package format instead.
@ -757,6 +757,7 @@ Returns true if the file exists, returns false if it triggered a download.
qboolean CL_CheckOrEnqueDownloadFile (const char *filename, const char *localname, unsigned int flags)
{ //returns false if we don't have the file yet.
COM_AssertMainThread("CL_CheckOrEnqueDownloadFile");
if (flags & DLLF_NONGAME)
{
/*pak/pk3 downloads have an explicit leading package/ as an internal/network marker*/
@ -976,10 +977,9 @@ Model_NextDownload
*/
void Model_CheckDownloads (void)
{
// char *twf;
char *s;
int i;
// extern char gamedirfile[];
char ext[8];
// Con_TPrintf (TLC_CHECKINGMODELS);
@ -1006,7 +1006,7 @@ void Model_CheckDownloads (void)
if (s[0] == '*')
continue; // inline brush model
if (!stricmp(COM_FileExtension(s), "dsp")) //doom sprites are weird, and not really downloadable via this system
if (!stricmp(COM_FileExtension(s, ext, sizeof(ext)), "dsp")) //doom sprites are weird, and not really downloadable via this system
continue;
#ifdef Q2CLIENT
@ -1022,7 +1022,7 @@ void Model_CheckDownloads (void)
{
s = cl.model_name_vwep[i];
if (!stricmp(COM_FileExtension(s), "dsp")) //doom sprites are weird, and not really downloadable via this system
if (!stricmp(COM_FileExtension(s, ext, sizeof(ext)), "dsp")) //doom sprites are weird, and not really downloadable via this system
continue;
if (!*s)
@ -1035,10 +1035,9 @@ void Model_CheckDownloads (void)
int CL_LoadModels(int stage, qboolean dontactuallyload)
{
extern model_t *loadmodel;
int i;
float giveuptime = Sys_DoubleTime()+0.3; //small things get padded into a single frame
float giveuptime = Sys_DoubleTime()+1; //small things get padded into a single frame
#define atstage() ((cl.contentstage == stage++ && !dontactuallyload)?++cl.contentstage:false)
#define endstage() if (!cls.timedemo && giveuptime<Sys_DoubleTime()) return -1;
@ -1120,10 +1119,7 @@ int CL_LoadModels(int stage, qboolean dontactuallyload)
if (atstage())
{
SCR_SetLoadingFile("prenewmap");
loadmodel = cl.worldmodel;
if (R_PreNewMap)
R_PreNewMap();
Surf_PreNewMap();
endstage();
}
@ -1141,6 +1137,7 @@ int CL_LoadModels(int stage, qboolean dontactuallyload)
if (atstage())
{
#if 0
SCR_SetLoadingFile(cl.model_name[i]);
#ifdef CSQC_DAT
if (i == 1)
@ -1148,12 +1145,13 @@ int CL_LoadModels(int stage, qboolean dontactuallyload)
else
CSQC_LoadResource(cl.model_name[i], "model");
#endif
#endif
#ifdef Q2CLIENT
if (cls.protocol == CP_QUAKE2 && *cl.model_name[i] == '#')
cl.model_precache[i] = NULL;
else
#endif
cl.model_precache[i] = Mod_ForName (cl.model_name[i], MLV_WARN);
cl.model_precache[i] = Mod_ForName (Mod_FixName(cl.model_name[i], cl.model_name[1]), MLV_WARN);
S_ExtraUpdate();
@ -1167,9 +1165,11 @@ int CL_LoadModels(int stage, qboolean dontactuallyload)
if (atstage())
{
#if 0
SCR_SetLoadingFile(cl.model_name_vwep[i]);
#ifdef CSQC_DAT
CSQC_LoadResource(cl.model_name_vwep[i], "vwep");
#endif
#endif
cl.model_precache_vwep[i] = Mod_ForName (cl.model_name_vwep[i], MLV_WARN);
endstage();
@ -1206,12 +1206,14 @@ int CL_LoadModels(int stage, qboolean dontactuallyload)
continue;
if (atstage())
{
#if 0
SCR_SetLoadingFile(cl.model_csqcname[i]);
#ifdef CSQC_DAT
if (i == 1)
CSQC_LoadResource(cl.model_csqcname[i], "map");
else
CSQC_LoadResource(cl.model_csqcname[i], "model");
#endif
#endif
cl.model_csqcprecache[i] = Mod_ForName (cl.model_csqcname[i], MLV_WARN);
@ -1232,10 +1234,10 @@ int CL_LoadModels(int stage, qboolean dontactuallyload)
if (atstage())
{
SCR_SetLoadingFile("external textures");
loadmodel = cl.worldmodel;
// if (!loadmodel || loadmodel->type == mod_dummy)
// Host_EndGame("No worldmodel was loaded\n");
Mod_NowLoadExternal();
if (cl.worldmodel && cl.worldmodel->loadstate == MLS_LOADING)
COM_WorkerPartialSync(cl.worldmodel, &cl.worldmodel->loadstate, MLS_LOADING);
if (cl.worldmodel && cl.worldmodel->loadstate == MLS_LOADED)
Mod_NowLoadExternal(cl.worldmodel);
endstage();
}
@ -1245,11 +1247,10 @@ int CL_LoadModels(int stage, qboolean dontactuallyload)
if (atstage())
{
SCR_SetLoadingFile("newmap");
loadmodel = cl.worldmodel;
// if (!loadmodel || loadmodel->type == mod_dummy)
// if (!cl.worldmodel || cl.worldmodel->type == mod_dummy)
// Host_EndGame("No worldmodel was loaded\n");
cl.model_precaches_added = false;
R_NewMap ();
Surf_NewMap ();
pmove.physents[0].model = cl.worldmodel;
@ -1292,9 +1293,11 @@ int CL_LoadSounds(int stage, qboolean dontactuallyload)
if (atstage())
{
#if 0
SCR_SetLoadingFile(cl.sound_name[i]);
#ifdef CSQC_DAT
CSQC_LoadResource(cl.sound_name[i], "sound");
#endif
#endif
cl.sound_precache[i] = S_PrecacheSound (cl.sound_name[i]);
@ -1466,13 +1469,23 @@ void CL_RequestNextDownload (void)
current_loading_size = cl.contentstage;
if (stage < 0)
return;
if (requiredownloads.ival && COM_HasWork())
{
SCR_SetLoadingFile("loading content");
return;
}
SCR_SetLoadingFile("receiving game state");
cl.sendprespawn = false;
if (cl.worldmodel && cl.worldmodel->loadstate == MLS_LOADING)
COM_WorkerPartialSync(cl.worldmodel, &cl.worldmodel->loadstate, MLS_LOADING);
#ifdef warningmsg
#pragma warningmsg("timedemo timer should start here")
#endif
if (!cl.worldmodel || cl.worldmodel->needload)
if (!cl.worldmodel || cl.worldmodel->loadstate != MLS_LOADED)
{
Con_Printf("\n\n-------------\nCouldn't download %s - cannot fully connect\n", cl.worldmodel->name);
SCR_SetLoadingStage(LS_NONE);
@ -2794,7 +2807,6 @@ void CLQW_ParseServerData (void)
#ifndef CLIENTONLY
Info_SetValueForStarKey (svs.info, "*gamedir", str, MAX_SERVERINFO_STRING);
#endif
COM_FlushFSCache();
Cvar_ForceCallback(Cvar_FindVar("r_particlesdesc"));
}
@ -3025,7 +3037,6 @@ void CLQ2_ParseServerData (void)
COM_Gamedir("baseq2");
else
COM_Gamedir(str);
COM_FlushFSCache();
// if ((*str && (!fs_gamedirvar->string || !*fs_gamedirvar->string || strcmp(fs_gamedirvar->string, str))) || (!*str && (fs_gamedirvar->string || *fs_gamedirvar->string)))
// Cvar_Set("game", str);
@ -3079,8 +3090,7 @@ void CLQ2_ParseServerData (void)
Cvar_ForceCallback(Cvar_FindVar("r_particlesdesc"));
if (R_PreNewMap)
R_PreNewMap();
Surf_PreNewMap();
}
#endif
@ -3246,8 +3256,7 @@ void CLNQ_ParseServerData(void) //Doesn't change gamedir - use with caution.
SCR_BeginLoadingPlaque();
if (R_PreNewMap)
R_PreNewMap();
Surf_PreNewMap();
memset (cl.model_name, 0, sizeof(cl.model_name));
for (nummodels=1 ; ; nummodels++)
@ -3341,6 +3350,7 @@ Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
{
case 1:
cl.sendprespawn = true;
SCR_SetLoadingFile("loading data");
CL_RequestNextDownload();
break;
@ -3583,6 +3593,7 @@ void CL_ParseSoundlist (qboolean lots)
CL_AllowIndependantSendCmd(false); //stop it now, the indep stuff *could* require model tracing.
cl.sendprespawn = true;
SCR_SetLoadingFile("loading data");
}
else
#endif
@ -3681,6 +3692,7 @@ void CL_ParseModellist (qboolean lots)
//set the flag to load models and send prespawn
cl.sendprespawn = true;
SCR_SetLoadingFile("loading data");
}
void CL_ProcessUserInfo (int slot, player_info_t *player);
@ -3925,6 +3937,7 @@ void CLQ2_Precache_f (void)
cl.contentstage = 0;
cl.sendprespawn = true;
SCR_SetLoadingFile("loading data");
#ifdef VM_CG
CG_Start();
@ -3998,6 +4011,7 @@ void CL_ParseStatic (int version)
cl_static_entities[i].mdlidx = es.modelindex;
cl_static_entities[i].emit = NULL;
cl_static_entities[i].state = es;
ent = &cl_static_entities[i].ent;
V_ClearEntity(ent);
memset(&cl_static_entities[i].pvscache, 0, sizeof(cl_static_entities[i].pvscache));
@ -4041,7 +4055,7 @@ void CL_ParseStatic (int version)
AngleVectors(es.angles, ent->axis[0], ent->axis[1], ent->axis[2]);
VectorInverse(ent->axis[1]);
if (!cl.worldmodel || cl.worldmodel->needload)
if (!cl.worldmodel || cl.worldmodel->loadstate != MLS_LOADED)
{
Con_TPrintf ("Warning: Parsestatic and no map loaded yet\n");
return;
@ -4161,6 +4175,7 @@ void CLQ2_ParseStartSoundPacket(void)
float attenuation;
int flags;
float ofs;
sfx_t *sfx;
flags = MSG_ReadByte ();
sound_num = MSG_ReadByte ();
@ -4211,20 +4226,25 @@ void CLQ2_ParseStartSoundPacket(void)
if (!cl.sound_precache[sound_num])
return;
if (cl.sound_precache[sound_num]->name[0] == '*' && ent > 0 && ent <= MAX_CLIENTS)
sfx = cl.sound_precache[sound_num];
if (sfx->name[0] == '*')
{ //a 'sexed' sound
char *model = Info_ValueForKey(cl.players[ent-1].userinfo, "skin");
char *skin;
skin = strchr(model, '/');
if (skin)
*skin = '\0';
if (*model)
if (ent > 0 && ent <= MAX_CLIENTS)
{
S_StartSound (ent, channel, S_PrecacheSound(va("players/%s/%s", model, cl.sound_precache[sound_num]->name+1)), pos, volume, attenuation, ofs, 0);
return;
char *model = Info_ValueForKey(cl.players[ent-1].userinfo, "skin");
char *skin;
skin = strchr(model, '/');
if (skin)
*skin = '\0';
if (*model)
sfx = S_PrecacheSound(va("players/%s/%s", model, cl.sound_precache[sound_num]->name+1));
}
//fall back to male if it failed to load.
//note: threaded loading can still make it silent the first time we hear it.
if (sfx->loadstate == SLS_FAILED)
sfx = S_PrecacheSound(va("players/male/%s", cl.sound_precache[sound_num]->name+1));
}
S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume, attenuation, ofs, 0);
S_StartSound (ent, channel, sfx, pos, volume, attenuation, ofs, 0);
}
#endif
@ -4801,7 +4821,7 @@ void CL_MuzzleFlash (int entnum)
if (!dlightkey)
return;
if (P_RunParticleEffectType(org, NULL, 1, pt_muzzleflash))
if (P_RunParticleEffectType(org, axis[0], 1, pt_muzzleflash))
{
dl = CL_AllocDlight (dlightkey);
VectorMA (org, 15, axis[0], dl->origin);
@ -5411,12 +5431,12 @@ void CL_PrintChat(player_info_t *plr, char *rawmsg, char *msg, int plrflags)
con_chat = Con_Create("chat", CONF_HIDDEN|CONF_NOTIFY|CONF_NOTIFY_BOTTOM);
if (con_chat)
{
Con_PrintCon(con_chat, fullchatmessage);
Con_PrintCon(con_chat, fullchatmessage, con_chat->parseflags);
if (con_separatechat.ival == 1)
{
con_main.flags |= CONF_NOTIMES;
Con_PrintCon(&con_main, fullchatmessage);
Con_PrintCon(&con_main, fullchatmessage, con_main.parseflags);
con_main.flags &= CONF_NOTIMES;
return;
}
@ -5631,7 +5651,7 @@ void CL_ParsePrecache(void)
{
model_t *model;
CL_CheckOrEnqueDownloadFile(s, s, 0);
model = Mod_ForName(s, (i == 1)?MLV_ERROR:MLV_WARN);
model = Mod_ForName(Mod_FixName(s, cl.model_name[1]), (i == 1)?MLV_ERROR:MLV_WARN);
if (!model)
Con_Printf("svc_precache: Mod_ForName(\"%s\") failed\n", s);
cl.model_precache[i] = model;
@ -6777,17 +6797,17 @@ void CLNQ_ParseServerMessage (void)
break;
case svc_setview:
i=MSGCL_ReadEntity();
if (!cl.playerview[destsplit].viewentity)
{
cl.playerview[destsplit].playernum = (cl.playerview[destsplit].viewentity = MSGCL_ReadEntity())-1;
cl.playerview[destsplit].playernum = (unsigned int)i;
if (cl.playerview[destsplit].playernum >= cl.allocated_client_slots)
{
Con_Printf(CON_WARNING "WARNING: Server put us in slot %i. We are not on the scoreboard.\n", cl.playerview[destsplit].playernum);
Con_DPrintf(CON_WARNING "WARNING: Server put us in slot %i. We are not on the scoreboard.\n", i);
cl.playerview[destsplit].playernum = cl.allocated_client_slots; //pretend it's an mvd (we have that spare slot)
}
}
else
cl.playerview[destsplit].viewentity=MSGCL_ReadEntity();
cl.playerview[destsplit].viewentity = i;
break;
case svc_signonnum:

View File

@ -138,7 +138,7 @@ qintptr_t VARGS Plug_Draw_LoadImageData(void *offset, quintptr_t mask, const qin
// char *mimetype = VM_POINTER(arg[1]);
void *codeddata = VM_POINTER(arg[2]);
unsigned int datalength = VM_LONG(arg[3]);
texid_t t;
image_t *t;
qbyte *rgbdata;
unsigned int width, height;
@ -148,12 +148,13 @@ qintptr_t VARGS Plug_Draw_LoadImageData(void *offset, quintptr_t mask, const qin
if ((rgbdata = Read32BitImageFile(codeddata, datalength, &width, &height, NULL, name)))
{
name = va("%s/", name);
t = R_FindTexture(name, IF_NOMIPMAP|IF_UIPIC|IF_CLAMP);
t = Image_FindTexture(name, NULL, IF_NOMIPMAP|IF_UIPIC|IF_CLAMP);
if (!TEXVALID(t))
t = R_AllocNewTexture(name, width, height, IF_NOMIPMAP|IF_UIPIC|IF_CLAMP);
t = Image_CreateTexture(name, NULL, IF_NOMIPMAP|IF_UIPIC|IF_CLAMP);
if (TEXVALID(t))
{
R_Upload(t, name, TF_RGBA32, rgbdata, NULL, width, height, IF_NOMIPMAP|IF_UIPIC|IF_CLAMP);
Image_Upload(t, TF_RGBA32, rgbdata, NULL, width, height, IF_NOMIPMAP|IF_UIPIC|IF_CLAMP);
ret = Plug_Draw_LoadImage(name, 3, NULL);
}
@ -506,7 +507,7 @@ qintptr_t VARGS Plug_Con_SubPrint(void *offset, quintptr_t mask, const qintptr_t
}
}
Con_PrintCon(con, text);
Con_PrintCon(con, text, con->parseflags);
return 1;
}
@ -635,11 +636,7 @@ qintptr_t VARGS Plug_Mod_GetPluginModelFuncs(void *offset, quintptr_t mask, cons
Matrix3x4_Invert_Simple,
COM_StripExtension,
GenMatrixPosQuat4Scale,
Alias_ForceConvertBoneData,
R_RegisterShader,
R_RegisterSkin,
R_BuildDefaultTexnums
Alias_ForceConvertBoneData
};
if (VM_LONG(arg[0]) >= sizeof(funcs))
return (qintptr_t)&funcs;

View File

@ -377,7 +377,7 @@ void CL_PredictUsercmd (int pnum, int entnum, player_state_t *from, player_state
CL_PredictUsercmd (pnum, entnum, &temp, to, &split);
return;
}
if (!cl.worldmodel || cl.worldmodel->needload)
if (!cl.worldmodel || cl.worldmodel->loadstate != MLS_LOADED)
return;
VectorCopy (from->origin, pmove.origin);
@ -667,7 +667,7 @@ static void CL_DecodeStateSize(unsigned short solid, int modelindex, vec3_t mins
{
if (solid == ES_SOLID_BSP)
{
if (modelindex < MAX_PRECACHE_MODELS && cl.model_precache[modelindex] && !cl.model_precache[modelindex]->needload)
if (modelindex < MAX_PRECACHE_MODELS && cl.model_precache[modelindex] && cl.model_precache[modelindex]->loadstate == MLS_LOADED)
{
VectorCopy(cl.model_precache[modelindex]->mins, mins);
VectorCopy(cl.model_precache[modelindex]->maxs, maxs);
@ -869,7 +869,7 @@ void CL_PredictMovePNum (int seat)
#ifdef Q2CLIENT
if (cls.protocol == CP_QUAKE2)
{
if (!cl.worldmodel || cl.worldmodel->needload)
if (!cl.worldmodel || cl.worldmodel->loadstate != MLS_LOADED)
return;
pv->crouch = 0;
CLQ2_PredictMovement();

View File

@ -382,7 +382,13 @@ void SCR_CenterPrint (int pnum, char *str, qboolean skipgamecode)
p->flags |= CPRINT_PERSIST | CPRINT_BACKGROUND;
p->flags &= ~CPRINT_TALIGN;
}
else if (str[1] == 'O')
else if (str[1] == 'W') //wait between each char
p->flags ^= CPRINT_TYPEWRITER;
else if (str[1] == 'S') //Stay
p->flags ^= CPRINT_PERSIST;
else if (str[1] == 'M') //'Mask' the background so that its readable.
p->flags ^= CPRINT_BACKGROUND;
else if (str[1] == 'O') //Obituaries are shown at the bottom, ish.
p->flags ^= CPRINT_OBITUARTY;
else if (str[1] == 'B')
p->flags ^= CPRINT_BALIGN; //Note: you probably want to add some blank lines...
@ -506,9 +512,11 @@ void SCR_DrawCenterString (vrect_t *rect, cprint_t *p, struct font_s *font)
{
if (!(p->flags & CPRINT_BACKGROUND))
{
int w, h;
R_GetShaderSizes(pic, &w, &h, false);
y+= 16;
R2D_ScalePic ( (vid.width-pic->width)/2, 16, pic->width, pic->height, pic);
y+= pic->height;
R2D_ScalePic ( (vid.width-w)/2, 16, w, h, pic);
y+= h;
y+= 8;
}
}
@ -526,7 +534,7 @@ void SCR_DrawCenterString (vrect_t *rect, cprint_t *p, struct font_s *font)
y = (bottom-top - Font_CharHeight()*linecount) * 0.65 + top;
else
{
if (linecount <= 4)
if (linecount <= 5)
{
//small messages appear above and away from the crosshair
y = (bottom-top - Font_CharHeight()*linecount) * 0.35 + top;
@ -616,6 +624,7 @@ void R_DrawTextField(int x, int y, int w, int h, const char *text, unsigned int
p.charcount = COM_ParseFunString(defaultmask, text, p.string, sizeof(p.string), false) - p.string;
p.time_off = scr_centertime.value;
p.time_start = cl.time;
*p.titleimage = 0;
SCR_DrawCenterString(&r, &p, font_default);
}
@ -677,6 +686,10 @@ void SCR_DrawCursor(void)
if (rf->VID_CreateCursor)
{
key_customcursor[cmod].handle = rf->VID_CreateCursor(key_customcursor[cmod].name, key_customcursor[cmod].hotspot[0], key_customcursor[cmod].hotspot[1], key_customcursor[cmod].scale);
if (!key_customcursor[cmod].handle)
key_customcursor[cmod].handle = rf->VID_CreateCursor("gfx/cursor.tga", key_customcursor[cmod].hotspot[0], key_customcursor[cmod].hotspot[1], key_customcursor[cmod].scale); //try the fallback
if (!key_customcursor[cmod].handle)
key_customcursor[cmod].handle = rf->VID_CreateCursor("gfx/cursor.png", key_customcursor[cmod].hotspot[0], key_customcursor[cmod].hotspot[1], key_customcursor[cmod].scale); //try the fallback
if (!key_customcursor[cmod].handle)
key_customcursor[cmod].handle = rf->VID_CreateCursor("gfx/cursor.lmp", key_customcursor[cmod].hotspot[0], key_customcursor[cmod].hotspot[1], key_customcursor[cmod].scale); //try the fallback
}
@ -697,9 +710,9 @@ void SCR_DrawCursor(void)
//system doesn't support a hardware cursor, so try to draw a software one.
p = R2D_SafeCachePic(key_customcursor[cmod].name);
if (!p)
if (!p || !R_GetShaderSizes(p, NULL, NULL, false))
p = R2D_SafeCachePic("gfx/cursor.lmp");
if (p)
if (p && R_GetShaderSizes(p, NULL, NULL, false))
{
R2D_ImageColours(1, 1, 1, 1);
R2D_Image(mousecursor_x-key_customcursor[cmod].hotspot[0], mousecursor_y-key_customcursor[cmod].hotspot[1], p->width*cl_cursorscale.value, p->height*cl_cursorscale.value, 0, 0, 1, 1, p);
@ -1209,6 +1222,17 @@ void SCR_DrawTurtle (void)
R2D_ScalePic (scr_vrect.x, scr_vrect.y, 64, 64, scr_turtle);
}
void SCR_DrawDisk (void)
{
if (!draw_disc)
return;
if (!COM_HasWork())
return;
R2D_ScalePic (scr_vrect.x + vid.width-24, scr_vrect.y, 24, 24, draw_disc);
}
/*
==============
SCR_DrawNet
@ -1498,6 +1522,9 @@ void SCR_SetLoadingStage(int stage)
}
void SCR_SetLoadingFile(char *str)
{
if (loadingfile && !strcmp(loadingfile, str))
return;
if (loadingfile)
Z_Free(loadingfile);
loadingfile = Z_Malloc(strlen(str)+1);
@ -1511,7 +1538,7 @@ void SCR_SetLoadingFile(char *str)
void SCR_DrawLoading (qboolean opaque)
{
int sizex, x, y;
int sizex, x, y, w, h;
mpic_t *pic;
char *s;
int qdepth;
@ -1522,6 +1549,7 @@ void SCR_DrawLoading (qboolean opaque)
if (*levelshotname)
{
pic = R2D_SafeCachePic (levelshotname);
R_GetShaderSizes(pic, NULL, NULL, true);
R2D_ImageColours(1, 1, 1, 1);
R2D_ScalePic (0, 0, vid.width, vid.height, pic);
}
@ -1535,13 +1563,13 @@ void SCR_DrawLoading (qboolean opaque)
{ //quake files
pic = R2D_SafeCachePic ("gfx/loading.lmp");
if (pic)
if (R_GetShaderSizes(pic, &w, &h, true))
{
x = (vid.width - pic->width)/2;
y = (vid.height - 48 - pic->height)/2;
R2D_ScalePic (x, y, pic->width, pic->height, pic);
x = (vid.width - w)/2;
y = (vid.height - 48 - h)/2;
R2D_ScalePic (x, y, w, h, pic);
x = (vid.width/2) - 96;
y += pic->height + 8;
y += h + 8;
}
else
{
@ -1586,15 +1614,15 @@ void SCR_DrawLoading (qboolean opaque)
else
{ //hexen2 files
pic = R2D_SafeCachePic ("gfx/menu/loading.lmp");
if (pic)
if (R_GetShaderSizes(pic, &w, &h, true))
{
int size, count, offset;
if (!scr_drawloading && loading_stage == 0)
return;
offset = (vid.width - pic->width)/2;
R2D_ScalePic (offset, 0, pic->width, pic->height, pic);
offset = (vid.width - w)/2;
R2D_ScalePic (offset, 0, w, h, pic);
if (loading_stage == LS_NONE)
return;
@ -1693,10 +1721,10 @@ void SCR_BeginLoadingPlaque (void)
// redraw with no console and the loading plaque
Sbar_Changed ();
scr_drawloading = true;
scr_disabled_for_loading = true;
SCR_UpdateScreen ();
scr_drawloading = false;
scr_disabled_for_loading = true;
scr_disabled_time = Sys_DoubleTime(); //realtime tends to change... Hmmm....
}
@ -1719,7 +1747,7 @@ void SCR_ImageName (char *mapname)
#ifdef GLQUAKE
if (qrenderer == QR_OPENGL)
{
if (!R2D_SafeCachePic (levelshotname))
if (!R_GetShaderSizes(R2D_SafeCachePic (levelshotname), NULL, NULL, true))
{
*levelshotname = '\0';
return;
@ -1772,7 +1800,7 @@ void SCR_SetUpToDrawConsole (void)
//android has an onscreen imm that we don't want to obscure
fullscreenpercent = scr_consize.value;
#endif
if (!con_stayhidden.ival && (!Key_Dest_Has(~(kdm_console|kdm_game))) && (!cl.sendprespawn && cl.worldmodel && cl.worldmodel->needload))
if (!con_stayhidden.ival && (!Key_Dest_Has(~(kdm_console|kdm_game))) && (!cl.sendprespawn && cl.worldmodel && cl.worldmodel->loadstate != MLS_LOADED))
{
//force console to fullscreen if we're loading stuff
// Key_Dest_Add(kdm_console);
@ -1932,9 +1960,9 @@ qboolean SCR_ScreenShot (char *filename, void *rgb_buffer, int width, int height
extern cvar_t scr_sshot_compression;
#endif
char *ext;
char ext[8];
ext = COM_FileExtension(filename);
COM_FileExtension(filename, ext, sizeof(ext));
if (!rgb_buffer)
return false;
@ -2333,6 +2361,7 @@ void SCR_DrawTwoDimensional(int uimenu, qboolean nohud)
R2D_DrawCrosshair();
SCR_DrawNet ();
SCR_DrawDisk();
SCR_DrawFPS ();
SCR_DrawUPS ();
SCR_DrawClock();

View File

@ -313,7 +313,7 @@ sfx_t *cl_sfx_ric2;
sfx_t *cl_sfx_ric3;
sfx_t *cl_sfx_r_exp3;
cvar_t cl_expsprite = CVARFD("cl_expsprite", "0", CVAR_ARCHIVE, "Display a central sprite in explosion effects. QuakeWorld typically does so, NQ mods should not.");
cvar_t cl_expsprite = CVARFD("cl_expsprite", "0", CVAR_ARCHIVE, "Display a central sprite in explosion effects. QuakeWorld typically does so, NQ mods should not (which is problematic when played with the qw protocol).");
cvar_t r_explosionlight = CVARFC("r_explosionlight", "1", CVAR_ARCHIVE, Cvar_Limiter_ZeroToOne_Callback);
cvar_t cl_truelightning = CVARF("cl_truelightning", "0", CVAR_SEMICHEAT);
cvar_t cl_beam_trace = CVAR("cl_beam_trace", "0");
@ -400,8 +400,8 @@ void CL_AssociateEffect_f(void)
associatedeffect = ae;
}
//FIXME: overkill
CL_RegisterParticles();
if (pe)
CL_RegisterParticles();
}
void CL_InitTEntSounds (void)
@ -467,7 +467,7 @@ void P_LoadedModel(model_t *mod)
mod->particleeffect = P_INVALID;
mod->particletrail = P_INVALID;
mod->engineflags &= ~(MDLF_NODEFAULTTRAIL | MDLF_ENGULPHS);
mod->engineflags &= ~MDLF_ENGULPHS;
for(ae = associatedeffect; ae; ae = ae->next)
{
if (!strcmp(ae->mname, mod->name))
@ -489,7 +489,7 @@ void P_LoadedModel(model_t *mod)
}
}
if (mod->particletrail == P_INVALID)
P_DefaultTrail(mod);
P_DefaultTrail(mod->flags, &mod->particletrail, &mod->traildefaultindex);
}
void CL_RefreshCustomTEnts(void);
@ -501,7 +501,7 @@ void CL_RegisterParticles(void)
int i;
for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
{
if (!mod->needload)
if (mod->loadstate == MLS_LOADED)
{
P_LoadedModel(mod);
}
@ -790,7 +790,7 @@ void CL_AddBeam (int tent, int ent, vec3_t start, vec3_t end) //fixme: use TE_ n
if (ent < 0 && ent >= -512) //a zquake concept. ent between -1 and -maxplayers is to be taken to be a railtrail from a particular player instead of a beam.
{
// TODO: add support for those finnicky colored railtrails...
if (P_ParticleTrail(start, end, rtqw_railtrail, -ent, NULL))
if (P_ParticleTrail(start, end, rtqw_railtrail, -ent, NULL, NULL))
P_ParticleTrailIndex(start, end, 208, 8, NULL);
return;
}
@ -844,7 +844,7 @@ void CL_AddBeam (int tent, int ent, vec3_t start, vec3_t end) //fixme: use TE_ n
else
m = Mod_ForName(mname, MLV_WARN);
if (m && m->needload)
if (m && m->loadstate != MLS_LOADED)
CL_CheckOrEnqueDownloadFile(m->name, NULL, 0);
// save end position for truelightning
@ -1104,6 +1104,9 @@ void CL_ParseTEnt (void)
case TENQ_BEAM:
type = TEQW_BEAM;
break;
case TE_EXPLOSION:
type = TE_EXPLOSIONNOSPRITE;
break;
default:
break;
}
@ -1332,7 +1335,8 @@ void CL_ParseTEnt (void)
ex->endalpha = ex->startalpha; //don't fade out
}
break;
case TE_EXPLOSION: // rocket explosion
case TE_EXPLOSIONNOSPRITE: //nq-style, no sprite
case TE_EXPLOSION: //qw-style, with (optional) sprite
// particles
pos[0] = MSG_ReadCoord ();
pos[1] = MSG_ReadCoord ();
@ -1364,7 +1368,7 @@ void CL_ParseTEnt (void)
S_StartSound (-2, 0, cl_sfx_r_exp3, pos, 1, 1, 0, 0);
// sprite
if (cl_expsprite.ival && !nqprot) // temp hopefully
if (type == TE_EXPLOSION && cl_expsprite.ival) // temp hopefully
{
explosion_t *ex = CL_AllocExplosion (pos);
ex->start = cl.time;
@ -1554,8 +1558,8 @@ void CL_ParseTEnt (void)
pos2[1] = MSG_ReadCoord ();
pos2[2] = MSG_ReadCoord ();
if (P_ParticleTrail(pos, pos2, rtqw_railtrail, 0, NULL))
if (P_ParticleTrail(pos, pos2, rtq2_railtrail, 0, NULL))
if (P_ParticleTrail(pos, pos2, rtqw_railtrail, 0, NULL, NULL))
if (P_ParticleTrail(pos, pos2, rtq2_railtrail, 0, NULL, NULL))
P_ParticleTrailIndex(pos, pos2, 208, 8, NULL);
break;
@ -1692,7 +1696,7 @@ void CL_ParseTEnt (void)
// stain (Hopefully this is close to how DP does it)
if (cl_legacystains.ival) Surf_AddStain(pos, -10, -10, -10, 30);
if (P_ParticleTrail(pos, pos2, P_FindParticleType("te_plasmaburn"), 0, NULL))
if (P_ParticleTrail(pos, pos2, P_FindParticleType("te_plasmaburn"), 0, NULL, NULL))
P_ParticleTrailIndex(pos, pos2, 15, 0, NULL);
break;
@ -1710,7 +1714,7 @@ void CL_ParseTEnt (void)
MSG_ReadCoord ();
MSG_ReadCoord ();
if (P_ParticleTrail(pos, pos2, P_FindParticleType("te_nexbeam"), 0, NULL))
if (P_ParticleTrail(pos, pos2, P_FindParticleType("te_nexbeam"), 0, NULL, NULL))
P_ParticleTrailIndex(pos, pos2, 15, 0, NULL);
break;
@ -1887,7 +1891,7 @@ void CL_SpawnCustomTEnt(custtentinst_t *info)
}
}
else
failed = P_ParticleTrail(info->pos, info->pos2, t->particleeffecttype, 0, NULL);
failed = P_ParticleTrail(info->pos, info->pos2, t->particleeffecttype, 0, NULL, NULL);
}
else
{
@ -2110,6 +2114,9 @@ void CL_RefreshCustomTEnts(void)
cl.particle_csprecache[i] = P_INVALID;
}
}
#ifdef CSQC_DAT
CSQC_ResetTrails();
#endif
}
void CL_ClearCustomTEnts(void)
{
@ -2174,8 +2181,8 @@ void CL_ParseTrailParticles(void)
else
ts = NULL;
if (P_ParticleTrail(start, end, effectindex, entityindex, ts))
P_ParticleTrail(start, end, rt_blood, entityindex, ts);
if (P_ParticleTrail(start, end, effectindex, entityindex, NULL, ts))
P_ParticleTrail(start, end, rt_blood, entityindex, NULL, ts);
}
void CL_ParsePointParticles(qboolean compact)
@ -2468,7 +2475,7 @@ void CLQ2_ParseTEnt (void)
case Q2TE_BLUEHYPERBLASTER: //TE_BLASTER without model+light
MSG_ReadPos (pos);
MSG_ReadPos (pos2);
P_ParticleTrail(pos, pos2, pt, 0, NULL);
P_ParticleTrail(pos, pos2, pt, 0, NULL, NULL);
break;
case Q2TE_EXPLOSION1: //column
case Q2TE_EXPLOSION2: //splits
@ -2722,7 +2729,7 @@ fixme:
case Q2TE_RAILTRAIL: // railgun effect
MSG_ReadPos (pos);
MSG_ReadPos (pos2);
if (P_ParticleTrail(pos, pos2, rtq2_railtrail, 0, NULL))
if (P_ParticleTrail(pos, pos2, rtq2_railtrail, 0, NULL, NULL))
P_ParticleTrailIndex(pos, pos2, 0x74, 8, NULL);
Q2S_StartSound (pos, 0, 0, S_PrecacheSound ("weapons/railgf1a.wav"), 1, ATTN_NORM, 0);
break;
@ -2930,7 +2937,7 @@ fixme:
case Q2TE_BUBBLETRAIL:
MSG_ReadPos (pos);
MSG_ReadPos (pos2);
if (P_ParticleTrail(pos, pos2, rtq2_bubbletrail, 0, NULL))
if (P_ParticleTrail(pos, pos2, rtq2_bubbletrail, 0, NULL, NULL))
P_ParticleTrailIndex(pos, pos2, 4, 8, NULL);
break;
@ -3103,7 +3110,7 @@ fixme:
case Q2TE_DEBUGTRAIL:
MSG_ReadPos (pos);
MSG_ReadPos (pos2);
if (P_ParticleTrail(pos, pos2, P_FindParticleType("te_debugtrail"), 0, NULL))
if (P_ParticleTrail(pos, pos2, P_FindParticleType("te_debugtrail"), 0, NULL, NULL))
P_ParticleTrailIndex(pos, pos2, 116, 8, NULL);
break;
@ -3381,6 +3388,7 @@ entity_t *CL_NewTempEntity (void)
return ent;
}
void CSQC_GetEntityOrigin(unsigned int csqcent, float *out);
/*
=================
@ -3503,6 +3511,12 @@ void CL_UpdateBeams (void)
}
}
}
#ifdef CSQC_DAT
else if ((b->bflags & 1) && b->entity > MAX_EDICTS)
{
CSQC_GetEntityOrigin(b->entity-MAX_EDICTS, b->start);
}
#endif
else if (b->bflags & STREAM_ATTACHED)
{
player_state_t *pl;
@ -3542,7 +3556,7 @@ void CL_UpdateBeams (void)
}
if (ruleset_allow_particle_lightning.ival || !b->model)
if (b->particleeffect >= 0 && !P_ParticleTrail(b->start, b->end, b->particleeffect, b->entity, &b->trailstate))
if (b->particleeffect >= 0 && !P_ParticleTrail(b->start, b->end, b->particleeffect, b->entity, NULL, &b->trailstate))
continue;
if (!b->model)
continue;
@ -3696,7 +3710,7 @@ void CL_UpdateExplosions (void)
ent->drawflags = SCALE_ORIGIN_ORIGIN;
if (ex->traileffect != P_INVALID)
pe->ParticleTrail(ent->oldorigin, ent->origin, ex->traileffect, 0, &(ex->trailstate));
pe->ParticleTrail(ent->oldorigin, ent->origin, ex->traileffect, 0, ent->axis, &(ex->trailstate));
if (!(ex->flags & Q2RF_BEAM))
VectorCopy(ent->origin, ex->oldorigin); //don't corrupt q2 beams
if (ex->flags & Q2RF_BEAM)

View File

@ -111,7 +111,7 @@ int Script_Read(int handle, struct pc_token_s *token)
if (sc->originalfilestack[sc->stackdepth])
BZ_Free(sc->originalfilestack[sc->stackdepth]);
sc->filestack[sc->stackdepth] = sc->originalfilestack[sc->stackdepth] = FS_LoadMallocFile(com_token);
sc->filestack[sc->stackdepth] = sc->originalfilestack[sc->stackdepth] = FS_LoadMallocFile(com_token, NULL);
Q_strncpyz(sc->filename[sc->stackdepth], com_token, MAX_QPATH);
sc->stackdepth++;
continue;
@ -205,7 +205,7 @@ int Script_LoadFile(char *filename)
sc = scripts+i;
memset(sc, 0, sizeof(*sc));
sc->filestack[0] = sc->originalfilestack[0] = FS_LoadMallocFile(filename);
sc->filestack[0] = sc->originalfilestack[0] = FS_LoadMallocFile(filename, NULL);
Q_strncpyz(sc->filename[sc->stackdepth], filename, MAX_QPATH);
sc->stackdepth = 1;
@ -639,13 +639,14 @@ void UI_RegisterFont(char *fontName, int pointSize, fontInfo_t *font)
} in;
int i;
char name[MAX_QPATH];
size_t sz;
#define readInt() LittleLong(*in.i++)
#define readFloat() LittleFloat(*in.f++)
snprintf(name, sizeof(name), "fonts/fontImage_%i.dat",pointSize);
in.c = COM_LoadTempFile(name);
if (com_filesize == sizeof(fontInfo_t))
in.c = COM_LoadTempFile(name, &sz);
if (sz == sizeof(fontInfo_t))
{
for(i=0; i<GLYPHS_PER_FONT; i++)
{
@ -678,7 +679,7 @@ void UI_RegisterFont(char *fontName, int pointSize, fontInfo_t *font)
#define VALIDATEPOINTER(o,l) if ((int)o + l >= mask || VM_POINTER(o) < offset) Host_EndGame("Call to ui trap %i passes invalid pointer\n", (int)fn); //out of bounds.
#define VALIDATEPOINTER(o,l) if ((quintptr_t)o + l >= mask || VM_POINTER(o) < offset) Host_EndGame("Call to ui trap %i passes invalid pointer\n", (int)fn); //out of bounds.
static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, const qintptr_t *arg)
{
@ -846,7 +847,9 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
char *name = VM_POINTER(arg[0]);
model_t *mod;
mod = Mod_ForName(name, MLV_SILENT);
if (mod->needload || mod->type == mod_dummy)
if (mod && mod->loadstate == MLS_LOADING)
COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING);
if (!mod || mod->loadstate != MLS_LOADED || mod->type == mod_dummy)
VM_LONG(ret) = 0;
else
VM_LONG(ret) = VM_TOMHANDLE(mod);
@ -922,7 +925,7 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
case UI_S_REGISTERSOUND:
{
sfx_t *sfx;
sfx = S_PrecacheSound(va("../%s", (char*)VM_POINTER(arg[0])));
sfx = S_PrecacheSound(va("%s", (char*)VM_POINTER(arg[0])));
if (sfx)
VM_LONG(ret) = VM_TOSTRCACHE(arg[0]); //return handle is the parameter they just gave
else
@ -1000,7 +1003,38 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
case UI_GETCLIENTSTATE: //get client state
//fixme: we need to fill in a structure.
Con_Printf("ui_getclientstate\n");
// Con_Printf("ui_getclientstate\n");
VALIDATEPOINTER(arg[0], sizeof(uiClientState_t));
{
uiClientState_t *state = VM_POINTER(arg[0]);
state->connectPacketCount = 0;//clc.connectPacketCount;
switch(cls.state)
{
case ca_disconnected:
if (CL_TryingToConnect())
state->connState = Q3CA_CONNECTING;
else
state->connState = Q3CA_DISCONNECTED;
break;
case ca_demostart:
state->connState = Q3CA_CONNECTING;
break;
case ca_connected:
state->connState = Q3CA_CONNECTED;
break;
case ca_onserver:
state->connState = Q3CA_PRIMED;
break;
case ca_active:
state->connState = Q3CA_ACTIVE;
break;
}
Q_strncpyz( state->servername, cls.servername, sizeof( state->servername ) );
Q_strncpyz( state->updateInfoString, "FTE!", sizeof( state->updateInfoString ) ); //warning/motd message from update server
Q_strncpyz( state->messageString, "", sizeof( state->messageString ) ); //error message from game server
state->clientNum = cl.playerview[0].playernum;
}
break;
case UI_GETCONFIGSTRING:
@ -1553,6 +1587,11 @@ void UI_Stop (void)
VM_Destroy(uivm);
VM_fcloseall(0);
uivm = NULL;
//mimic Q3 and save the config if anything got changed.
//note that q3 checks every frame. we only check when the ui is closed.
if (Cvar_UnsavedArchive())
Cmd_ExecuteString("cfg_save", RESTRICT_LOCAL);
}
}
@ -1612,7 +1651,7 @@ qboolean UI_OpenMenu(void)
qboolean UI_Command(void)
{
if (uivm)
return VM_Call(uivm, UI_CONSOLE_COMMAND);
return VM_Call(uivm, UI_CONSOLE_COMMAND, (int)(realtime * 1000));
return false;
}

View File

@ -30,7 +30,7 @@ typedef struct qwskin_s
//for hardware 32bit texture overrides
texnums_t textures;
qboolean failedload; // the name isn't a valid skin
qbyte failedload; // the name isn't a valid skin
void *skindata;
} qwskin_t;
@ -268,6 +268,7 @@ typedef struct dlight_s
int key; // so entities can reuse same entry
vec3_t origin;
vec3_t axis[3];
vec3_t rotation; //cubemap/spotlight rotation
float radius;
float die; // stop lighting after this time
float decay; // drop this each second
@ -851,7 +852,9 @@ extern cvar_t m_side;
extern cvar_t _windowed_mouse;
#ifndef SERVERONLY
extern cvar_t name;
#endif
extern cvar_t ruleset_allow_playercount;
@ -873,6 +876,7 @@ extern client_state_t cl;
typedef struct
{
entity_t ent;
entity_state_t state;
trailstate_t *emit;
int mdlidx; /*negative are csqc indexes*/
pvscache_t pvscache;
@ -1218,6 +1222,7 @@ qboolean CSQC_JoystickAxis(int axis, float value, int devid);
qboolean CSQC_Accelerometer(float x, float y, float z);
int CSQC_StartSound(int entnum, int channel, char *soundname, vec3_t pos, float vol, float attenuation, float pitchmod);
void CSQC_ParseEntities(void);
void CSQC_ResetTrails(void);
qboolean CSQC_DeltaPlayer(int playernum, player_state_t *state);
void CSQC_DeltaStart(float time);
@ -1455,6 +1460,7 @@ int qm_strcmp(char *s1, char *s2);
int qm_stricmp(char *s1, char *s2);
void Stats_ParsePrintLine(char *line);
void Stats_NewMap(void);
void Stats_Clear(void);
enum uploadfmt;
typedef struct

View File

@ -1314,7 +1314,7 @@ void CLQ2_AddPacketEntities (q2frame_t *frame)
player = &cl.players[(s1->skinnum&0xff)%cl.allocated_client_slots];
ent.model = player->model;
if (!ent.model || ent.model->needload) //we need to do better than this
if (!ent.model || ent.model->loadstate != MLS_LOADED) //we need to do better than this
{
ent.model = Mod_ForName("players/male/tris.md2", MLV_SILENT);
ent.customskin = Mod_RegisterSkinFile("players/male/grunt.skin");
@ -1603,8 +1603,9 @@ void CLQ2_AddPacketEntities (q2frame_t *frame)
{
if (effects & Q2EF_ROCKET)
{
if (P_ParticleTrail(cent->lerp_origin, ent.origin, rtq2_rocket, ent.keynum, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, rt_rocket, ent.keynum, &cent->trailstate))
//FIXME: cubemap orientation
if (P_ParticleTrail(cent->lerp_origin, ent.origin, rtq2_rocket, ent.keynum, NULL, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, rt_rocket, ent.keynum, NULL, &cent->trailstate))
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, 0xdc, 4, &cent->trailstate);
V_AddLight (ent.keynum, ent.origin, 200, 0.2, 0.1, 0.05);
@ -1621,7 +1622,7 @@ void CLQ2_AddPacketEntities (q2frame_t *frame)
}
else
{
if (P_ParticleTrail(cent->lerp_origin, ent.origin, rtq2_blastertrail, ent.keynum, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, rtq2_blastertrail, ent.keynum, NULL, &cent->trailstate))
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, 0xe0, 1, &cent->trailstate);
V_AddLight (ent.keynum, ent.origin, 200, 0.2, 0.2, 0);
}
@ -1636,14 +1637,14 @@ void CLQ2_AddPacketEntities (q2frame_t *frame)
}
else if (effects & Q2EF_GIB)
{
if (P_ParticleTrail(cent->lerp_origin, ent.origin, rtq2_gib, ent.keynum, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, rt_blood, ent.keynum, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, rtq2_gib, ent.keynum, NULL, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, rt_blood, ent.keynum, NULL, &cent->trailstate))
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, 0xe8, 8, &cent->trailstate);
}
else if (effects & Q2EF_GRENADE)
{
if (P_ParticleTrail(cent->lerp_origin, ent.origin, rtq2_grenade, ent.keynum, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, rt_grenade, ent.keynum, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, rtq2_grenade, ent.keynum, NULL, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, rt_grenade, ent.keynum, NULL, &cent->trailstate))
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, 4, 8, &cent->trailstate);
}
else if (effects & Q2EF_FLIES)
@ -1675,13 +1676,13 @@ void CLQ2_AddPacketEntities (q2frame_t *frame)
}
else if (effects & Q2EF_FLAG1)
{
if (P_ParticleTrail(cent->lerp_origin, ent.origin, P_FindParticleType("ef_flag1"), ent.keynum, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, P_FindParticleType("ef_flag1"), ent.keynum, NULL, &cent->trailstate))
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, 242, 1, &cent->trailstate);
V_AddLight (ent.keynum, ent.origin, 225, 0.2, 0.05, 0.05);
}
else if (effects & Q2EF_FLAG2)
{
if (P_ParticleTrail(cent->lerp_origin, ent.origin, P_FindParticleType("ef_flag2"), ent.keynum, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, P_FindParticleType("ef_flag2"), ent.keynum, NULL, &cent->trailstate))
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, 115, 1, &cent->trailstate);
V_AddLight (ent.keynum, ent.origin, 225, 0.05, 0.05, 0.2);
}
@ -1689,7 +1690,7 @@ void CLQ2_AddPacketEntities (q2frame_t *frame)
//ROGUE
else if (effects & Q2EF_TAGTRAIL)
{
if (P_ParticleTrail(cent->lerp_origin, ent.origin, P_FindParticleType("ef_tagtrail"), ent.keynum, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, P_FindParticleType("ef_tagtrail"), ent.keynum, NULL, &cent->trailstate))
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, 220, 1, &cent->trailstate);
V_AddLight (ent.keynum, ent.origin, 225, 0.2, 0.2, 0.0);
}
@ -1712,7 +1713,7 @@ void CLQ2_AddPacketEntities (q2frame_t *frame)
}
else if (effects & Q2EF_TRACKER)
{
if (P_ParticleTrail(cent->lerp_origin, ent.origin, P_FindParticleType("ef_tracker"), ent.keynum, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, P_FindParticleType("ef_tracker"), ent.keynum, NULL, &cent->trailstate))
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, 0, 1, &cent->trailstate);
V_AddLight (ent.keynum, ent.origin, 200, -0.2, -0.2, -0.2);
}
@ -1721,13 +1722,13 @@ void CLQ2_AddPacketEntities (q2frame_t *frame)
// RAFAEL
else if (effects & Q2EF_GREENGIB)
{
if (P_ParticleTrail(cent->lerp_origin, ent.origin, P_FindParticleType("ef_greengib"), ent.keynum, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, P_FindParticleType("ef_greengib"), ent.keynum, NULL, &cent->trailstate))
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, 219, 8, &cent->trailstate);
}
// RAFAEL
else if (effects & Q2EF_IONRIPPER)
{
if (P_ParticleTrail(cent->lerp_origin, ent.origin, P_FindParticleType("ef_ionripper"), ent.keynum, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, P_FindParticleType("ef_ionripper"), ent.keynum, NULL, &cent->trailstate))
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, 228, 4, &cent->trailstate);
V_AddLight (ent.keynum, ent.origin, 100, 0.2, 0.1, 0.1);
}
@ -1741,7 +1742,7 @@ void CLQ2_AddPacketEntities (q2frame_t *frame)
{
if (effects & Q2EF_ANIM_ALLFAST)
{
P_ParticleTrail(cent->lerp_origin, ent.origin, rtq2_blastertrail, ent.keynum, &cent->trailstate);
P_ParticleTrail(cent->lerp_origin, ent.origin, rtq2_blastertrail, ent.keynum, NULL, &cent->trailstate);
}
V_AddLight (ent.keynum, ent.origin, 130, 0.2, 0.1, 0.1);
}

View File

@ -515,7 +515,6 @@ qboolean CLQ3_SystemInfoChanged(char *str)
#ifndef CLIENTONLY
Info_SetValueForStarKey (svs.info, "*gamedir", value, MAX_SERVERINFO_STRING);
#endif
COM_FlushFSCache();
}
rc = Info_ValueForKey(str, "sv_referencedPaks"); //the ones that we should download.
@ -612,7 +611,7 @@ void CLQ3_ParseGameState(void)
Host_EndGame("CGame didn't set a map.\n");
cl.model_precaches_added = false;
R_NewMap ();
Surf_NewMap ();
SCR_EndLoadingPlaque();

View File

@ -204,12 +204,6 @@ qboolean Con_NameForNum(int num, char *buffer, int buffersize)
return false;
}
/*print text to a console*/
void Con_PrintCon (console_t *con, char *txt);
#ifdef QTERM
void QT_Update(void)
{
@ -506,8 +500,8 @@ void Cmd_ConEcho_f(void)
if (con)
{
Cmd_ShiftArgs(1, false);
Con_PrintCon(con, Cmd_Args());
Con_PrintCon(con, "\n");
Con_PrintCon(con, Cmd_Args(), con->parseflags);
Con_PrintCon(con, "\n", con->parseflags);
}
}
@ -580,7 +574,7 @@ void Con_Init (void)
Q_strncpyz(con_main.title, "MAIN", sizeof(con_main.title));
con_initialized = true;
Con_TPrintf ("Console initialized.\n");
// Con_TPrintf ("Console initialized.\n");
//
// register our commands
@ -618,8 +612,6 @@ void Con_Shutdown(void)
{
int i;
Con_History_Save();
for (i = 0; i <= CON_EDIT_LINES_MASK; i++)
{
BZ_Free(key_lines[i]);
@ -674,14 +666,14 @@ void Con_PrintConChars (console_t *con, conchar_t *c, int len)
con->current->length+=len;
}
void Con_PrintCon (console_t *con, char *txt)
void Con_PrintCon (console_t *con, char *txt, unsigned int parseflags)
{
conchar_t expanded[4096];
conchar_t *c;
conline_t *oc;
conline_t *reuse;
COM_ParseFunString(con->defaultcharbits, txt, expanded, sizeof(expanded), con->parseflags);
COM_ParseFunString(con->defaultcharbits, txt, expanded, sizeof(expanded), parseflags);
c = expanded;
if (*c)
@ -796,7 +788,13 @@ void Con_PrintCon (console_t *con, char *txt)
void Con_Print (char *txt)
{
Con_PrintCon(&con_main, txt); //client console
Con_PrintCon(&con_main, txt, con_main.parseflags); //client console
}
void Con_PrintFlags(char *txt, unsigned int setflags, unsigned int clearflags)
{
setflags |= con_main.parseflags;
setflags &= ~clearflags;
Con_PrintCon(&con_main, txt, setflags);
}
void Con_CycleConsole(void)
@ -830,6 +828,12 @@ void SV_FlushRedirect (void);
#endif
#define MAXPRINTMSG 4096
static void Con_PrintFromThread (void *ctx, void *data, size_t a, size_t b)
{
Con_Printf("%s", data);
BZ_Free(data);
}
// FIXME: make a buffer size safe vsprintf?
void VARGS Con_Printf (const char *fmt, ...)
{
@ -840,6 +844,12 @@ void VARGS Con_Printf (const char *fmt, ...)
vsnprintf (msg,sizeof(msg), fmt,argptr);
va_end (argptr);
if (!Sys_IsThread(NULL))
{
COM_AddWork(0, Con_PrintFromThread, NULL, Z_StrDup(msg), 0, 0);
return;
}
#ifndef CLIENTONLY
// add to redirected message
if (sv_redirected)
@ -939,7 +949,7 @@ void VARGS Con_DPrintf (const char *fmt, ...)
else
{
Sys_Printf ("%s", msg); // also echo to debugging console
Con_PrintCon(&con_main, msg);
Con_PrintCon(&con_main, msg, con_main.parseflags);
}
}

View File

@ -327,7 +327,7 @@ static void Stats_StatMessage(fragfilemsgtypes_t type, int wid, char *token1, ch
fragstats.readkills = true;
}
static void Stats_Clear(void)
void Stats_Clear(void)
{
int i;
statmessage_t *ms;
@ -364,7 +364,7 @@ static void Stats_LoadFragFile(char *name)
strcpy(filename, name);
COM_DefaultExtension(filename, ".dat", sizeof(filename));
file = COM_LoadTempFile(filename);
file = COM_LoadTempFile(filename, NULL);
if (!file || !*file)
{
Con_DPrintf("Couldn't load %s\n", filename);

File diff suppressed because it is too large Load Diff

View File

@ -1613,7 +1613,10 @@ void INS_StartupJoystick (void)
}
}
Con_Printf ("found %i joysticks\n", joy_count);
if (joy_count)
Con_Printf ("found %i joysticks\n", joy_count);
else
Con_DPrintf ("found no joysticks\n");
}
/*

View File

@ -609,7 +609,7 @@ static void Menu_Download_Got(struct dl_download *dl)
{
char *fname = dl->localname;
qboolean successful = dl->status == DL_FINISHED;
char *ext;
char ext[8];
package_t *p;
int dlnum = atoi(fname+3);
@ -635,7 +635,7 @@ static void Menu_Download_Got(struct dl_download *dl)
p->flags &= ~DPF_DOWNLOADING;
ext = COM_FileExtension(p->dest);
COM_FileExtension(p->dest, ext, sizeof(ext));
if (!stricmp(ext, "pak") || !stricmp(ext, "pk3"))
FS_UnloadPackFiles(); //we reload them after
@ -657,7 +657,6 @@ static void Menu_Download_Got(struct dl_download *dl)
WriteInstalledPackages();
ext = COM_FileExtension(p->dest);
if (!stricmp(ext, "pak") || !stricmp(ext, "pk3"))
FS_ReloadPackFiles();
return;

View File

@ -14,10 +14,10 @@ void Draw_TextBox (int x, int y, int width, int lines)
cy = y;
p = R2D_SafeCachePic ("gfx/box_tl.lmp");
if (!p) //assume none exist
if (R_GetShaderSizes(p, NULL, NULL, false) != true) //assume none exist
{
R2D_ImageColours(0.0, 0.0, 0.0, 1.0);
R2D_FillBlock(x, y, width*16 + 16, 8 * (2 + lines));
R2D_ImageColours(0.0, 0.0, 0.0, 0.5);
R2D_FillBlock(x, y, width*8 + 16, 8 * (2 + lines));
R2D_ImageColours(1.0, 1.0, 1.0, 1.0);
return;
}
@ -94,7 +94,7 @@ void Draw_Hexen2BigFontString(int x, int y, const char *text)
{
int sx, sy;
mpic_t *p;
unsigned int hack;
unsigned int hack; //FIXME: threads can't cope
hack = d_8to24rgbtable[0];
d_8to24rgbtable[0] = 0;
p = R2D_SafeCachePic ("gfx/menu/bigfont.lmp");
@ -127,18 +127,20 @@ void Draw_Hexen2BigFontString(int x, int y, const char *text)
mpic_t *QBigFontWorks(void)
{
mpic_t *p;
p = R2D_SafeCachePic ("gfx/mcharset.lmp");
if (p)
return p;
p = R2D_SafeCachePic ("mcharset.lmp");
if (p)
return p;
p = R2D_SafeCachePic ("textures/gfx/mcharset.lmp");
if (p)
return p;
p = R2D_SafeCachePic ("textures/mcharset.lmp");
if (p)
return p;
int i;
char *names[] = {
"gfx/mcharset.lmp",
"mcharset.lmp",
"textures/gfx/mcharset.lmp",
"textures/mcharset.lmp",
NULL
};
for (i = 0; names[i]; i++)
{
p = R2D_SafeCachePic (names[i]);
if (p && R_GetShaderSizes(p, NULL, NULL, true))
return p;
}
return NULL;
}
void Draw_BigFontString(int x, int y, const char *text)
@ -381,9 +383,11 @@ static void M_CheckMouseMove(void)
{
if (!option->common.noselectionsound)
{
#ifdef HEXEN2
if (mgt == MGT_HEXEN2)
S_LocalSound ("raven/menu1.wav");
else
#endif
S_LocalSound ("misc/menu1.wav");
}
@ -406,6 +410,7 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu
{
int i;
mpic_t *p;
int pw,ph;
while (option)
{
@ -441,7 +446,7 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu
case mt_menudot:
i = (int)(realtime * 10)%maxdots;
p = R2D_SafeCachePic(va(menudotstyle, i+mindot ));
R2D_ScalePic(xpos+option->common.posx, ypos+option->common.posy+dotofs, 20, 20, p);
R2D_ScalePic(xpos+option->common.posx, ypos+option->common.posy+dotofs, option->common.width, option->common.height, p);
break;
case mt_picturesel:
p = NULL;
@ -453,14 +458,15 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu
Q_strncatz(selname, "_sel", sizeof(selname));
p = R2D_SafeCachePic(selname);
}
if (!p)
if (!R_GetShaderSizes(p, &pw, &ph, false))
p = R2D_SafeCachePic(option->picture.picturename);
R2D_ScalePic(xpos+option->common.posx, ypos+option->common.posy, option->common.width?option->common.width:p->width, option->common.height?option->common.height:p->height, p);
R_GetShaderSizes(p, &pw, &ph, false);
R2D_ScalePic(xpos+option->common.posx, ypos+option->common.posy, option->common.width?option->common.width:pw, option->common.height?option->common.height:ph, p);
break;
case mt_picture:
p = R2D_SafeCachePic(option->picture.picturename);
if (p) R2D_ScalePic(xpos+option->common.posx, ypos+option->common.posy, option->common.width, option->common.height, p);
if (R_GetShaderSizes(p, NULL, NULL, false)>=0) R2D_ScalePic(xpos+option->common.posx, ypos+option->common.posy, option->common.width, option->common.height, p);
break;
case mt_childwindow:
MenuDrawItems(xpos+option->common.posx, ypos+option->common.posy, ((menu_t *)option->custom.dptr)->options, (menu_t *)option->custom.dptr);
@ -809,7 +815,11 @@ menupicture_t *MC_AddCenterPicture(menu_t *menu, int y, int height, char *picnam
}
else
{
width = (p->width * (float)height) / p->height;
int pwidth, pheight;
if (R_GetShaderSizes(p, &pwidth, &pheight, true))
width = (pwidth * (float)height) / pheight;
else
width = 64;
x = (320-(int)width)/2;
}
@ -859,32 +869,44 @@ menupicture_t *MC_AddCursor(menu_t *menu, menuresel_t *reselection, int x, int y
n->common.iszone = true;
n->common.posx = x;
n->common.posy = y;
n->common.width = 20;
n->common.height = 20;
n->common.next = menu->options;
menu->options = (menuoption_t *)n;
mgt = M_GameType();
if (mgt == MGT_QUAKE2)
{ //AND QUAKE 2 WINS!!!
menudotstyle = "m_cursor%i";
switch(mgt)
{
#ifdef Q2CLIENT
case MGT_QUAKE2:
//AND QUAKE 2 WINS!!!
menudotstyle = "pics/m_cursor%i.pcx";
mindot = 0;
maxdots = 15;
dotofs=0;
}
else if (mgt == MGT_HEXEN2)
{ //AND THE WINNER IS HEXEN 2!!!
//this is *obviously* the correct size... not.
n->common.width = 22;
n->common.height = 29;
break;
#endif
#ifdef HEXEN2
case MGT_HEXEN2:
//AND THE WINNER IS HEXEN 2!!!
menudotstyle = "gfx/menu/menudot%i.lmp";
mindot = 1;
maxdots = 8;
dotofs=-2;
}
else
{ //QUAKE 1 WINS BY DEFAULT!
break;
#endif
default:
//QUAKE 1 WINS BY DEFAULT!
menudotstyle = "gfx/menudot%i.lmp";
mindot = 1;
maxdots = 6;
dotofs=0;
break;
}
if (menu->reselection)
@ -1709,9 +1731,11 @@ void M_Complex_Key(int key, int unicode)
if (key == 0)
return;
#ifdef HEXEN2
if (mgt == MGT_HEXEN2)
S_LocalSound ("raven/menu1.wav");
else
#endif
S_LocalSound ("misc/menu1.wav");
if (key != K_ESCAPE && key != '`')
@ -1729,9 +1753,11 @@ void M_Complex_Key(int key, int unicode)
case K_ESCAPE:
//remove
M_RemoveMenu(currentmenu);
#ifdef HEXEN2
if (mgt == MGT_HEXEN2)
S_LocalSound ("raven/menu3.wav");
else
#endif
S_LocalSound ("misc/menu3.wav");
break;
case K_TAB:
@ -1740,9 +1766,11 @@ void M_Complex_Key(int key, int unicode)
if (currentmenu->selecteditem)
{
#ifdef HEXEN2
if (mgt == MGT_HEXEN2)
S_LocalSound ("raven/menu1.wav");
else
#endif
S_LocalSound ("misc/menu1.wav");
if (currentmenu->cursoritem)
@ -1754,9 +1782,11 @@ void M_Complex_Key(int key, int unicode)
if (currentmenu->selecteditem)
{
#ifdef HEXEN2
if (mgt == MGT_HEXEN2)
S_LocalSound ("raven/menu1.wav");
else
#endif
S_LocalSound ("misc/menu1.wav");
if (currentmenu->cursoritem)
@ -1786,9 +1816,11 @@ void M_Complex_Key(int key, int unicode)
else if (key == K_ENTER || key == K_KP_ENTER || key == K_MOUSE1)
{
Cbuf_AddText(currentmenu->selecteditem->button.command, RESTRICT_LOCAL);
#ifdef HEXEN2
if (mgt == MGT_HEXEN2)
S_LocalSound ("raven/menu2.wav");
else
#endif
S_LocalSound ("misc/menu2.wav");
}
break;
@ -1979,9 +2011,10 @@ void M_Menu_Main_f (void)
S_LocalSound ("misc/menu2.wav");
mgt = M_GameType();
#ifdef Q2CLIENT
if (mgt == MGT_QUAKE2) //quake2 main menu.
{
if (R2D_SafeCachePic("pics/m_main_game"))
if (R_GetShaderSizes(R2D_SafeCachePic("pics/m_main_quit"), NULL, NULL, true) > 0)
{
m_state = m_complex;
Key_Dest_Add(kdm_menu);
@ -2032,10 +2065,13 @@ void M_Menu_Main_f (void)
mainm->cursoritem = (menuoption_t *)MC_AddCursor(mainm, &resel, 42, mainm->selecteditem->common.posy);
}
}
else if (mgt == MGT_HEXEN2)
else
#endif
#ifdef HEXEN2
if (mgt == MGT_HEXEN2)
{
p = R2D_SafeCachePic("gfx/menu/title0.lmp");
if (!p)
if (R_GetShaderSizes(p, NULL, NULL, true) <= 0)
return;
m_state = m_complex;
@ -2073,14 +2109,16 @@ void M_Menu_Main_f (void)
mainm->cursoritem = (menuoption_t *)MC_AddCursor(mainm, &resel, 56, mainm->selecteditem->common.posy);
}
else if (QBigFontWorks())
else
#endif
if (QBigFontWorks())
{
m_state = m_complex;
Key_Dest_Add(kdm_menu);
mainm = M_CreateMenu(0);
p = R2D_SafeCachePic("gfx/ttl_main.lmp");
if (!p)
if (R_GetShaderSizes(p, NULL, NULL, true) <= 0)
{
MC_AddRedText(mainm, 16, 170, 0, "MAIN MENU", false);
@ -2118,7 +2156,7 @@ void M_Menu_Main_f (void)
mainm = M_CreateMenu(0);
p = R2D_SafeCachePic("gfx/ttl_main.lmp");
if (!p)
if (R_GetShaderSizes(p, NULL, NULL, true) <= 0)
{
MC_AddRedText(mainm, 16, 170, 0, "MAIN MENU", false);

View File

@ -2665,8 +2665,8 @@ texid_tf Media_UpdateForShader(cin_t *cin)
if (!cin->outunchanged)
{
if (!TEXVALID(cin->texture))
TEXASSIGN(cin->texture, R_AllocNewTexture("***cin***", cin->outwidth, cin->outheight, IF_NOMIPMAP|IF_NOALPHA));
R_Upload(cin->texture, "cin", cin->outtype, cin->outdata, cin->outpalette, cin->outwidth, cin->outheight, IF_NOMIPMAP|IF_NOALPHA|IF_NOGAMMA);
TEXASSIGN(cin->texture, Image_CreateTexture("***cin***", NULL, IF_NOMIPMAP|IF_NOALPHA));
Image_Upload(cin->texture, cin->outtype, cin->outdata, cin->outpalette, cin->outwidth, cin->outheight, IF_NOMIPMAP|IF_NOALPHA|IF_NOGAMMA);
}
if (cin->doneframe)
@ -4365,7 +4365,8 @@ qboolean S_LoadMP3Sound (sfx_t *s, qbyte *data, int datalen, int sndspeed)
HACMDRIVER drv = NULL;
mp3decoder_t *dec;
char *ext = COM_FileExtension(s->name);
char ext[8];
COM_FileExtension(s->name, ext, sizeof(ext));
if (stricmp(ext, "mp3"))
return false;

View File

@ -25,6 +25,7 @@ void M_Menu_MultiPlayer_f (void)
menu = M_CreateMenu(0);
#ifdef Q2CLIENT
if (mgt == MGT_QUAKE2)
{
MC_AddCenterPicture(menu, 4, 24, "pics/m_banner_multiplayer");
@ -39,7 +40,10 @@ void M_Menu_MultiPlayer_f (void)
menu->cursoritem = (menuoption_t*)MC_AddWhiteText(menu, 48, 0, 40, NULL, false);
return;
}
else if (mgt == MGT_HEXEN2)
else
#endif
#ifdef HEXEN2
if (mgt == MGT_HEXEN2)
{
MC_AddCenterPicture(menu, 0, 60, "gfx/menu/title4.lmp");
@ -53,7 +57,9 @@ void M_Menu_MultiPlayer_f (void)
menu->cursoritem = (menuoption_t *)MC_AddCursor(menu, &resel, 48, 64);
return;
}
else if (QBigFontWorks())
else
#endif
if (QBigFontWorks())
{
MC_AddPicture(menu, 16, 4, 32, 144, "gfx/qplaque.lmp");
MC_AddCenterPicture(menu, 4, 24, "gfx/p_multi.lmp");
@ -112,12 +118,14 @@ typedef struct {
menuedit_t *nameedit;
menuedit_t *teamedit;
menuedit_t *skinedit;
#ifdef HEXEN2
menucombo_t *classedit;
int ticlass;
#endif
menucombo_t *modeledit;
int topcolour;
int lowercolour;
int ticlass;
int tiwidth, tiheight;
qbyte translationimage[128*128];
} setupmenu_t;
@ -130,8 +138,10 @@ qboolean ApplySetupMenu (union menuoption_s *option,struct menu_s *menu, int key
Cvar_Set(&team, info->teamedit->text);
if (info->skinedit)
Cvar_Set(&skin, info->skinedit->text);
#ifdef HEXEN2
if (info->classedit)
Cvar_SetValue(Cvar_FindVar("cl_playerclass"), info->classedit->selectedoption+1);
#endif
Cbuf_AddText(va("color %i %i\n", info->lowercolour, info->topcolour), RESTRICT_LOCAL);
S_LocalSound ("misc/menu2.wav");
M_RemoveMenu(menu);
@ -281,19 +291,23 @@ void MSetup_TransDraw (int x, int y, menucustom_t *option, menu_t *menu)
info->skinedit->modified = false;
reloadtimage = true;
}
#ifdef HEXEN2
if (info->classedit && info->classedit->selectedoption != info->ticlass)
{
info->ticlass = info->classedit->selectedoption;
reloadtimage = true;
}
#endif
if (reloadtimage)
{
#ifdef HEXEN2
if (info->classedit) //quake2 main menu.
{
FS_LoadFile(va("gfx/menu/netp%i.lmp", info->ticlass+1), &f);
}
else
#endif
{
FS_LoadFile(va("gfx/player/%s.lmp", info->skinedit->text), &f);
if (!f)
@ -330,6 +344,7 @@ void M_Menu_Setup_f (void)
static menuresel_t resel;
mgt = M_GameType();
#ifdef Q2CLIENT
if (mgt == MGT_QUAKE2) //quake2 main menu.
{
if (R2D_SafeCachePic("pics/m_banner_player_setup"))
@ -367,6 +382,7 @@ void M_Menu_Setup_f (void)
}
return;
}
#endif
Key_Dest_Add(kdm_menu);
m_state = m_complex;
@ -383,6 +399,8 @@ void M_Menu_Setup_f (void)
menu->selecteditem = (menuoption_t*)
(info->nameedit = MC_AddEdit(menu, 64, 160, 40, "Your name", name.string));
(info->teamedit = MC_AddEdit(menu, 64, 160, 56, "Your team", team.string));
#ifdef HEXEN2
info->ticlass = -1;
if (mgt == MGT_HEXEN2)
{
static const char *classnames[] =
@ -398,6 +416,7 @@ void M_Menu_Setup_f (void)
(info->classedit = MC_AddCombo(menu, 64, 160, 72, "Your class", (const char **)classnames, pc->ival-1));
}
else
#endif
(info->skinedit = MC_AddEdit(menu, 64, 160, 72, "Your skin", skin.string));
ci = MC_AddCustom(menu, 172+32, 88, NULL, 0);
@ -419,7 +438,6 @@ void M_Menu_Setup_f (void)
info->topcolour = topcolor.value;
if (info->skinedit)
info->skinedit->modified = true;
info->ticlass = -1;
}

View File

@ -114,11 +114,13 @@ menu_t *M_Options_Title(int *y, int infosize)
MC_AddCenterPicture(menu, 4, 24, "pics/m_banner_options");
*y += 32;
break;
#ifdef HEXEN2
case MGT_HEXEN2://h2
MC_AddPicture(menu, 16, 0, 35, 176, "gfx/menu/hplaque.lmp");
MC_AddCenterPicture(menu, 0, 60, "gfx/menu/title3.lmp");
*y += 32;
break;
#endif
default: //q1
MC_AddPicture(menu, 16, 4, 32, 144, "gfx/qplaque.lmp");
MC_AddCenterPicture(menu, 4, 24, "gfx/p_option.lmp");
@ -708,8 +710,8 @@ const char *presetexec[] =
"cl_bob 0.02;"
//these things are perhaps a little extreme
"r_loadlit 0;"
"gl_texturemode nn;" //yup, we went there.
"gl_texturemode2d n;" //yeah, 2d too.
"gl_texturemode nnl;" //yup, we went there.
"gl_texturemode2d n.l;" //yeah, 2d too.
"r_part_classic_square 1;" //blocky baby!
"r_part_classic_expgrav 1;" //vanillaery
"r_particlesystem script;" //q2 or hexen2 particle effects need to be loadable
@ -1547,7 +1549,7 @@ void M_Menu_Singleplayer_Cheats_Quake (void)
#endif
MC_AddRedText(menu, 16, 170, y, " Quake Singleplayer Cheats", false); y+=8;
MC_AddWhiteText(menu, 16, 170, y, " <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ", false); y+=8;
MC_AddWhiteText(menu, 16, 170, y, " ^Ue080^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue082 ", false); y+=8;
y+=8;
#ifndef CLIENTONLY
info->skillcombo = MC_AddCombo(menu,16,170, y, "Difficulty", skilloptions, currentskill); y+=8;
@ -1661,7 +1663,7 @@ void M_Menu_Singleplayer_Cheats_Quake2 (void)
#endif
MC_AddRedText(menu, 16, 170, y, "Quake2 Singleplayer Cheats", false); y+=8;
MC_AddWhiteText(menu, 16, 170, y, "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ", false); y+=8;
MC_AddWhiteText(menu, 16, 170, y, "^Ue080^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue082", false); y+=8;
y+=8;
#ifndef CLIENTONLY
info->skillcombo = MC_AddCombo(menu,16,170, y, "Difficulty", skilloptions, currentskill); y+=8;
@ -2019,7 +2021,7 @@ void M_Menu_Singleplayer_Cheats_Hexen2 (void)
currentmap = 0;
MC_AddRedText(menu, 16, 170, y, "Hexen2 Singleplayer Cheats", false); y+=8;
MC_AddWhiteText(menu, 16, 170, y, "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ", false); y+=8;
MC_AddWhiteText(menu, 16, 170, y, "^Ue080^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue082 ", false); y+=8;
y+=8;
#ifndef CLIENTONLY
info->skillcombo = MC_AddCombo(menu,16,170, y, "Difficulty", skilloptions, currentskill); y+=8;
@ -2072,12 +2074,16 @@ void M_Menu_Singleplayer_Cheats_f (void)
case MGT_QUAKE1:
M_Menu_Singleplayer_Cheats_Quake();
break;
#ifdef Q2CLIENT
case MGT_QUAKE2:
M_Menu_Singleplayer_Cheats_Quake2();
break;
#endif
#ifdef HEXEN2
case MGT_HEXEN2:
M_Menu_Singleplayer_Cheats_Hexen2();
break;
#endif
}
}
@ -2527,6 +2533,11 @@ void M_Menu_Video_f (void)
#ifndef MINIMAL
typedef struct
{
enum {
MV_NONE,
MV_BONES,
MV_SHADER
} mode;
int skingroup;
int framegroup;
double framechangetime;
@ -2536,6 +2547,8 @@ typedef struct
float dist;
char modelname[MAX_QPATH];
char forceshader[MAX_QPATH];
char *shadertext;
} modelview_t;
static unsigned int genhsv(float h_, float s, float v)
@ -2666,18 +2679,50 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
Draw_FunString(0, y, va("%i: %s", mods->skingroup, fname));
y+=8;
#ifdef SKELETALMODELS
switch(mods->mode)
{
int bonecount;
galiasbone_t *b = Mod_GetBoneInfo(ent.model, &bonecount);
if (b && bonecount)
case MV_NONE:
R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+y, r_refdef.grect.width, r_refdef.grect.height-y,
"arrows: pitch/rotate\n"
"w: zoom in\n"
"s: zoom out\n"
"m: mode\n"
"r: reset times\n"
"home: skin-=1\n"
"end: skin+=1\n"
"pgup: frame+=1\n"
"pgdn: frame-=1\n"
, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN);
break;
case MV_BONES:
#ifdef SKELETALMODELS
{
Draw_FunString(0, y, va("Bones: "));
y+=8;
M_BoneDisplay(&ent, b, &y, 0, -1, 0, bonecount);
int bonecount;
galiasbone_t *b = Mod_GetBoneInfo(ent.model, &bonecount);
if (b && bonecount)
{
Draw_FunString(0, y, va("Bones: "));
y+=8;
M_BoneDisplay(&ent, b, &y, 0, -1, 0, bonecount);
}
else
R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+y, r_refdef.grect.width, r_refdef.grect.height-y, "No bones in model", CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN);
}
}
#endif
break;
case MV_SHADER:
{
if (!mods->shadertext)
{
char *body = Shader_GetShaderBody(Mod_ShaderForSkin(ent.model, mods->skingroup));
mods->shadertext = Z_StrDup(body);
}
R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+16, r_refdef.grect.width, r_refdef.grect.height-16, mods->shadertext, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN);
//fixme: draw the shader's textures.
}
break;
}
}
static qboolean M_ModelViewerKey(struct menucustom_s *c, struct menu_s *m, int key)
{
@ -2691,6 +2736,17 @@ static qboolean M_ModelViewerKey(struct menucustom_s *c, struct menu_s *m, int k
}
else if (key == 's')
mods->dist /= 0.9;
else if (key == 'm')
{
Z_Free(mods->shadertext);
mods->shadertext = NULL;
switch (mods->mode)
{
case MV_NONE: mods->mode = MV_BONES; break;
case MV_BONES: mods->mode = MV_SHADER; break;
case MV_SHADER: mods->mode = MV_NONE; break;
}
}
else if (key == 'r')
{
mods->framechangetime = realtime;
@ -2853,8 +2909,11 @@ void M_Menu_Mods_f (void)
menu = M_CreateMenu(sizeof(modmenu_t));
*(modmenu_t*)menu->data = mods;
MC_AddPicture(menu, 16, 4, 32, 144, "gfx/qplaque.lmp");
MC_AddCenterPicture(menu, 0, 24, "gfx/p_option.lmp");
if (COM_FCheckExists("gfx/p_option.lmp"))
{
MC_AddPicture(menu, 16, 4, 32, 144, "gfx/qplaque.lmp");
MC_AddCenterPicture(menu, 0, 24, "gfx/p_option.lmp");
}
c = MC_AddCustom(menu, 64, 32, menu->data, 0);
menu->cursoritem = (menuoption_t*)c;

View File

@ -126,7 +126,6 @@ void M_Menu_SinglePlayer_f (void)
{
menu_t *menu;
#ifndef CLIENTONLY
int mgt;
menubutton_t *b;
mpic_t *p;
#endif
@ -144,9 +143,10 @@ void M_Menu_SinglePlayer_f (void)
MC_AddBox (menu, 60, 10*8, 25, 4);
#else
mgt = M_GameType();
if (mgt == MGT_QUAKE2)
{ //q2...
switch(M_GameType())
{
#ifdef Q2CLIENT
case MGT_QUAKE2:
menu = M_CreateMenu(0);
MC_AddCenterPicture(menu, 4, 24, "pics/m_banner_game");
@ -162,174 +162,180 @@ void M_Menu_SinglePlayer_f (void)
menu->cursoritem = (menuoption_t*)MC_AddWhiteText(menu, 48, 0, 40, NULL, false);
return;
}
else if (mgt == MGT_HEXEN2)
{ //h2
int y;
int i;
cvar_t *pc;
qboolean havemp;
static char *classlistmp[] = {
"Paladin",
"Crusader",
"Necromancer",
"Assasin",
"Demoness"
};
menubutton_t *b;
havemp = COM_FCheckExists("maps/keep1.bsp");
menu = M_CreateMenu(0);
MC_AddPicture(menu, 16, 0, 35, 176, "gfx/menu/hplaque.lmp");
Cvar_Get("cl_playerclass", "1", CVAR_USERINFO|CVAR_ARCHIVE, "Hexen2");
y = 64-20;
if (!strncmp(Cmd_Argv(1), "class", 5))
#endif
#ifdef HEXEN2
case MGT_HEXEN2:
{
int pnum;
extern cvar_t cl_splitscreen;
pnum = atoi(Cmd_Argv(1)+5);
if (!pnum)
pnum = 1;
MC_AddCenterPicture(menu, 0, 60, "gfx/menu/title2.lmp");
if (cl_splitscreen.ival)
MC_AddBufferedText(menu, 80, 0, (y+=8)+12, va("Player %i\n", pnum), false, true);
for (i = 0; i < 4+havemp; i++)
{
b = MC_AddConsoleCommandHexen2BigFont(menu, 80, y+=20, classlistmp[i],
va("p%i setinfo cl_playerclass %i; menu_single %s %s\n",
pnum,
i+1,
((pnum+1 > cl_splitscreen.ival+1)?"skill":va("class%i",pnum+1)),
Cmd_Argv(2)));
if (!menu->selecteditem)
menu->selecteditem = (menuoption_t*)b;
}
}
else if (!strncmp(Cmd_Argv(1), "skill", 5))
{
static char *skillnames[6][4] =
{
{
"Easy",
"Medium",
"Hard",
"Nightmare"
},
{
"Apprentice",
"Squire",
"Adept",
"Lord"
},
{
"Gallant",
"Holy Avenger",
"Divine Hero",
"Legend"
},
{
"Sorcerer",
"Dark Servant",
"Warlock",
"Lich King"
},
{
"Rogue",
"Cutthroat",
"Executioner",
"Widow Maker"
},
{
"Larva",
"Spawn",
"Fiend",
"She Bitch"
}
int y;
int i;
cvar_t *pc;
qboolean havemp;
static char *classlistmp[] = {
"Paladin",
"Crusader",
"Necromancer",
"Assasin",
"Demoness"
};
char **sn = skillnames[0];
pc = Cvar_Get("cl_playerclass", "1", CVAR_USERINFO|CVAR_ARCHIVE, "Hexen2");
if (pc && (unsigned)pc->ival <= 5)
sn = skillnames[pc->ival];
menubutton_t *b;
havemp = COM_FCheckExists("maps/keep1.bsp");
menu = M_CreateMenu(0);
MC_AddPicture(menu, 16, 0, 35, 176, "gfx/menu/hplaque.lmp");
MC_AddCenterPicture(menu, 0, 60, "gfx/menu/title5.lmp");
for (i = 0; i < 4; i++)
Cvar_Get("cl_playerclass", "1", CVAR_USERINFO|CVAR_ARCHIVE, "Hexen2");
y = 64-20;
if (!strncmp(Cmd_Argv(1), "class", 5))
{
b = MC_AddConsoleCommandHexen2BigFont(menu, 80, y+=20, sn[i], va("skill %i; closemenu; disconnect; deathmatch 0; coop 0;wait;map %s\n", i, Cmd_Argv(2)));
if (!menu->selecteditem)
menu->selecteditem = (menuoption_t*)b;
int pnum;
extern cvar_t cl_splitscreen;
pnum = atoi(Cmd_Argv(1)+5);
if (!pnum)
pnum = 1;
MC_AddCenterPicture(menu, 0, 60, "gfx/menu/title2.lmp");
if (cl_splitscreen.ival)
MC_AddBufferedText(menu, 80, 0, (y+=8)+12, va("Player %i\n", pnum), false, true);
for (i = 0; i < 4+havemp; i++)
{
b = MC_AddConsoleCommandHexen2BigFont(menu, 80, y+=20, classlistmp[i],
va("p%i setinfo cl_playerclass %i; menu_single %s %s\n",
pnum,
i+1,
((pnum+1 > cl_splitscreen.ival+1)?"skill":va("class%i",pnum+1)),
Cmd_Argv(2)));
if (!menu->selecteditem)
menu->selecteditem = (menuoption_t*)b;
}
}
}
else
{
MC_AddCenterPicture(menu, 0, 60, "gfx/menu/title1.lmp");
//startmap selection in hexen2 is nasty.
if (havemp)
else if (!strncmp(Cmd_Argv(1), "skill", 5))
{
menu->selecteditem = (menuoption_t*)
MC_AddConsoleCommandHexen2BigFont(menu, 80, y+=20, "New Mission", "menu_single class keep1\n");
MC_AddConsoleCommandHexen2BigFont(menu, 80, y+=20, "Old Mission", "menu_single class demo1\n");
static char *skillnames[6][4] =
{
{
"Easy",
"Medium",
"Hard",
"Nightmare"
},
{
"Apprentice",
"Squire",
"Adept",
"Lord"
},
{
"Gallant",
"Holy Avenger",
"Divine Hero",
"Legend"
},
{
"Sorcerer",
"Dark Servant",
"Warlock",
"Lich King"
},
{
"Rogue",
"Cutthroat",
"Executioner",
"Widow Maker"
},
{
"Larva",
"Spawn",
"Fiend",
"She Bitch"
}
};
char **sn = skillnames[0];
pc = Cvar_Get("cl_playerclass", "1", CVAR_USERINFO|CVAR_ARCHIVE, "Hexen2");
if (pc && (unsigned)pc->ival <= 5)
sn = skillnames[pc->ival];
MC_AddCenterPicture(menu, 0, 60, "gfx/menu/title5.lmp");
for (i = 0; i < 4; i++)
{
b = MC_AddConsoleCommandHexen2BigFont(menu, 80, y+=20, sn[i], va("skill %i; closemenu; disconnect; deathmatch 0; coop 0;wait;map %s\n", i, Cmd_Argv(2)));
if (!menu->selecteditem)
menu->selecteditem = (menuoption_t*)b;
}
}
else
{
menu->selecteditem = (menuoption_t*)
MC_AddConsoleCommandHexen2BigFont(menu, 80, y+=20, "New Game", "menu_single class demo1\n");
MC_AddCenterPicture(menu, 0, 60, "gfx/menu/title1.lmp");
//startmap selection in hexen2 is nasty.
if (havemp)
{
menu->selecteditem = (menuoption_t*)
MC_AddConsoleCommandHexen2BigFont(menu, 80, y+=20, "New Mission", "menu_single class keep1\n");
MC_AddConsoleCommandHexen2BigFont(menu, 80, y+=20, "Old Mission", "menu_single class demo1\n");
}
else
{
menu->selecteditem = (menuoption_t*)
MC_AddConsoleCommandHexen2BigFont(menu, 80, y+=20, "New Game", "menu_single class demo1\n");
}
MC_AddConsoleCommandHexen2BigFont(menu, 80, y+=20, "Save Game", "menu_save\n");
MC_AddConsoleCommandHexen2BigFont(menu, 80, y+=20, "Load Game", "menu_load\n");
}
MC_AddConsoleCommandHexen2BigFont(menu, 80, y+=20, "Save Game", "menu_save\n");
MC_AddConsoleCommandHexen2BigFont(menu, 80, y+=20, "Load Game", "menu_load\n");
}
/*
pc = Cvar_Get("cl_playerclass", "1", CVAR_USERINFO|CVAR_ARCHIVE, "Hexen2");
if (pc)
MC_AddCvarCombo (menu, 64, y+=8, "Player class", pc, havemp?(const char **)classlistmp:(const char **)classlist, (const char **)(classvalues+havemp));
y+=8;
menu->selecteditem = (menuoption_t*)
MC_AddConsoleCommand (menu, 64, y+=8, "Classic: Easy", "closemenu\nskill 0;deathmatch 0; coop 0;disconnect;wait;map demo1\n");
MC_AddConsoleCommand (menu, 64, y+=8, "Classic: Medium", "closemenu\nskill 1;deathmatch 0; coop 0;disconnect;wait;map demo1\n");
MC_AddConsoleCommand (menu, 64, y+=8, "Classic: Hard", "closemenu\nskill 2;deathmatch 0; coop 0;disconnect;wait;map demo1\n");
y+=8;
if (havemp)
{
MC_AddConsoleCommand(menu, 64, y+=8, "Expansion: Easy", "closemenu\nskill 0;deathmatch 0; coop 0;disconnect;wait;map keep1\n");
MC_AddConsoleCommand(menu, 64, y+=8, "Expansion: Medium", "closemenu\nskill 1;deathmatch 0; coop 0;disconnect;wait;map keep1\n");
MC_AddConsoleCommand(menu, 64, y+=8, "Expansion: Hard", "closemenu\nskill 2;deathmatch 0; coop 0;disconnect;wait;map keep1\n");
/*
pc = Cvar_Get("cl_playerclass", "1", CVAR_USERINFO|CVAR_ARCHIVE, "Hexen2");
if (pc)
MC_AddCvarCombo (menu, 64, y+=8, "Player class", pc, havemp?(const char **)classlistmp:(const char **)classlist, (const char **)(classvalues+havemp));
y+=8;
menu->selecteditem = (menuoption_t*)
MC_AddConsoleCommand (menu, 64, y+=8, "Classic: Easy", "closemenu\nskill 0;deathmatch 0; coop 0;disconnect;wait;map demo1\n");
MC_AddConsoleCommand (menu, 64, y+=8, "Classic: Medium", "closemenu\nskill 1;deathmatch 0; coop 0;disconnect;wait;map demo1\n");
MC_AddConsoleCommand (menu, 64, y+=8, "Classic: Hard", "closemenu\nskill 2;deathmatch 0; coop 0;disconnect;wait;map demo1\n");
y+=8;
if (havemp)
{
MC_AddConsoleCommand(menu, 64, y+=8, "Expansion: Easy", "closemenu\nskill 0;deathmatch 0; coop 0;disconnect;wait;map keep1\n");
MC_AddConsoleCommand(menu, 64, y+=8, "Expansion: Medium", "closemenu\nskill 1;deathmatch 0; coop 0;disconnect;wait;map keep1\n");
MC_AddConsoleCommand(menu, 64, y+=8, "Expansion: Hard", "closemenu\nskill 2;deathmatch 0; coop 0;disconnect;wait;map keep1\n");
y+=8;
}
MC_AddConsoleCommand (menu, 64, y+=8, "Load Game", "menu_load\n");
MC_AddConsoleCommand (menu, 64, y+=8, "Save Game", "menu_save\n");
*/
menu->cursoritem = (menuoption_t *)MC_AddCursor(menu, &resel, 56, menu->selecteditem?menu->selecteditem->common.posy:0);
return;
}
break;
#endif
default:
if (QBigFontWorks())
{
menu = M_CreateMenu(0);
MC_AddPicture(menu, 16, 4, 32, 144, "gfx/qplaque.lmp");
MC_AddCenterPicture(menu, 0, 24, "gfx/p_option.lmp");
MC_AddConsoleCommand (menu, 64, y+=8, "Load Game", "menu_load\n");
MC_AddConsoleCommand (menu, 64, y+=8, "Save Game", "menu_save\n");
*/
menu->selecteditem = (menuoption_t*)
MC_AddConsoleCommandQBigFont (menu, 72, 32, "New Game", "closemenu;disconnect;maxclients 1;deathmatch 0;coop 0;startmap_sp\n");
MC_AddConsoleCommandQBigFont (menu, 72, 52, "Load Game", "menu_load\n");
MC_AddConsoleCommandQBigFont (menu, 72, 72, "Save Game", "menu_save\n");
menu->cursoritem = (menuoption_t *)MC_AddCursor(menu, &resel, 56, menu->selecteditem?menu->selecteditem->common.posy:0);
return;
}
else if (QBigFontWorks())
{
menu = M_CreateMenu(0);
MC_AddPicture(menu, 16, 4, 32, 144, "gfx/qplaque.lmp");
MC_AddCenterPicture(menu, 0, 24, "gfx/p_option.lmp");
menu->selecteditem = (menuoption_t*)
MC_AddConsoleCommandQBigFont (menu, 72, 32, "New Game", "closemenu;disconnect;maxclients 1;deathmatch 0;coop 0;startmap_sp\n");
MC_AddConsoleCommandQBigFont (menu, 72, 52, "Load Game", "menu_load\n");
MC_AddConsoleCommandQBigFont (menu, 72, 72, "Save Game", "menu_save\n");
menu->cursoritem = (menuoption_t*)MC_AddCursor(menu, &resel, 54, 32);
return;
}
else
{ //q1
menu = M_CreateMenu(0);
MC_AddPicture(menu, 16, 4, 32, 144, "gfx/qplaque.lmp");
MC_AddCenterPicture(menu, 4, 24, "gfx/p_option.lmp");
menu->cursoritem = (menuoption_t*)MC_AddCursor(menu, &resel, 54, 32);
return;
}
else
{ //q1
menu = M_CreateMenu(0);
MC_AddPicture(menu, 16, 4, 32, 144, "gfx/qplaque.lmp");
MC_AddCenterPicture(menu, 4, 24, "gfx/p_option.lmp");
}
break;
}
p = R2D_SafeCachePic("gfx/sp_menu.lmp");

View File

@ -438,7 +438,6 @@ void M_Menu_Keys_f (void)
{
int y;
menu_t *menu;
int mgt;
extern cvar_t cl_splitscreen, cl_forcesplitclient;
vfsfile_t *bindslist;
@ -446,27 +445,27 @@ void M_Menu_Keys_f (void)
m_state = m_complex;
menu = M_CreateMenu(0);
mgt = M_GameType();
#ifdef Q2CLIENT
if (mgt == MGT_QUAKE2) //quake2 main menu.
switch(M_GameType())
{
#ifdef Q2CLIENT
case MGT_QUAKE2:
//fixme: no art?
y = 48;
bindnames = q2bindnames;
}
else
break;
#endif
if (mgt == MGT_HEXEN2)
{
#ifdef HEXEN2
case MGT_HEXEN2:
MC_AddCenterPicture(menu, 0, 60, "gfx/menu/title6.lmp");
y = 64;
bindnames = h2bindnames;
}
else
{
break;
#endif
default:
MC_AddCenterPicture(menu, 4, 24, "gfx/ttl_cstm.lmp");
y = 48;
bindnames = qwbindnames;
break;
}
if (cl_splitscreen.ival)
@ -591,7 +590,11 @@ void M_Help_Draw (void)
int i;
mpic_t *pic = NULL;
for (i = 0; i < sizeof(helpstyles)/sizeof(helpstyles[0]) && !pic; i++)
{
pic = R2D_SafeCachePic(va(helpstyles[i].pattern, help_page+helpstyles[i].base));
if (R_GetShaderSizes(pic, NULL, NULL, true) <= 0)
pic = NULL;
}
if (!pic)
M_Menu_Main_f ();
else
@ -1415,19 +1418,33 @@ int M_GameType (void)
if (FS_Restarted(&cachedrestarts))
{
int q1 = COM_FDepthFile("gfx/sp_menu.lmp", true);
int h2 = COM_FDepthFile("gfx/menu/title2.lmp", true);
#if defined(Q2CLIENT)
int q2 = COM_FDepthFile("pics/m_banner_game.pcx", true);
if (q2 < h2 && q2 < q1)
cached = MGT_QUAKE2;
else
struct
{
int gametype;
char *path;
} configs[] =
{
{MGT_QUAKE1, "gfx/sp_menu.lmp"},
#ifdef Q2CLIENT
{MGT_QUAKE2, "pics/m_banner_game.pcx"},
#endif
if (h2 < q1)
cached = MGT_HEXEN2;
else
cached = MGT_QUAKE1;
#ifdef HEXEN2
{MGT_HEXEN2, "gfx/menu/title2.lmp"},
#endif
{0, NULL}
};
int bd = COM_FDepthFile(configs[0].path, true);
int i;
cached = configs[0].gametype;
for (i = 1; configs[i].path; i++)
{
int gd = COM_FDepthFile(configs[i].path, true);
if (bd > gd)
{
bd = gd;
cached = configs[i].gametype;
}
}
}
return cached;

View File

@ -9,6 +9,7 @@ struct batch_s;
struct entity_s;
struct dlight_s;
struct galiasbone_s;
struct dlight_s;
typedef enum
{
@ -88,9 +89,6 @@ extern void (*R_Init) (void);
extern void (*R_DeInit) (void);
extern void (*R_RenderView) (void); // must set r_refdef first
extern void (*R_NewMap) (void);
extern void (*R_PreNewMap) (void);
extern qboolean (*VID_Init) (rendererstate_t *info, unsigned char *palette);
extern void (*VID_DeInit) (void);
extern char *(*VID_GetRGBInfo) (int prepad, int *truevidwidth, int *truevidheight);
@ -140,8 +138,7 @@ extern struct model_s *Mod_ForName (const char *name, enum mlverbosity_e verb
extern struct model_s *Mod_LoadModel (struct model_s *mod, enum mlverbosity_e verbose); //makes sure a model is loaded
extern void *Mod_Extradata (struct model_s *mod); // handles caching
extern void Mod_TouchModel (const char *name);
extern void Mod_NowLoadExternal (void);
extern const char *Mod_FixName (const char *modname, const char *worldname); //remaps the name appropriately
extern void Mod_Think (void);
extern int Mod_SkinNumForName (struct model_s *model, const char *name);
@ -170,29 +167,79 @@ extern int r_regsequence;
// qbyte *Mod_LeafPVS (struct mleaf_s *leaf, struct model_s *model, qbyte *buffer);
#endif
typedef struct
typedef enum uploadfmt
{
TF_INVALID,
TF_RGBA32, /*rgba byte order*/
TF_BGRA32, /*bgra byte order*/
TF_RGBX32, /*rgb byte order, with extra wasted byte after blue*/
TF_BGRX32, /*rgb byte order, with extra wasted byte after blue*/
TF_RGB24, /*rgb byte order, no alpha channel nor pad, and regular top down*/
TF_BGR24, /*bgr byte order, no alpha channel nor pad, and regular top down*/
TF_BGR24_FLIP, /*bgr byte order, no alpha channel nor pad, and bottom up*/
TF_LUM8, /*8bit greyscale image*/
TF_SOLID8, /*8bit quake-palette image*/
TF_TRANS8, /*8bit quake-palette image, index 255=transparent*/
TF_TRANS8_FULLBRIGHT, /*fullbright 8 - fullbright texels have alpha 255, everything else 0*/
TF_HEIGHT8, /*image data is greyscale, convert to a normalmap and load that, uploaded alpha contains the original heights*/
TF_HEIGHT8PAL, /*source data is palette values rather than actual heights, generate a fallback heightmap*/
TF_H2_T7G1, /*8bit data, odd indexes give greyscale transparence*/
TF_H2_TRANS8_0, /*8bit data, 0 is transparent, not 255*/
TF_H2_T4A4, /*8bit data, weird packing*/
/*this block requires a palette*/
TF_PALETTES,
TF_8PAL24,
TF_8PAL32,
/*for render targets*/
TF_DEPTH16,
TF_DEPTH24,
TF_DEPTH32,
TF_RGBA16F,
TF_RGBA32F
} uploadfmt_t;
enum
{
TEX_NOTLOADED,
TEX_LOADING,
TEX_LOADED,
TEX_FAILED
};
typedef struct image_s
{
char *ident; //allocated on end
char *subpath; //allocated on end
int regsequence;
int width;
int height;
} texcom_t;
struct texid_s
{
union
{
unsigned int num;
int status; //TEX_
unsigned int flags;
struct image_s *next;
struct image_s *prev;
#if defined(D3DQUAKE) || defined(SWQUAKE)
void *ptr;
void *ptr; //texture
void *ptr2; //view
#endif
};
texcom_t *ref;
};
#ifdef GLQUAKE
int num;
#endif
void *fallbackdata;
int fallbackwidth;
int fallbackheight;
uploadfmt_t fallbackfmt;
} image_t;
#if 1
typedef struct texid_s texid_t;
typedef image_t *texid_t;
#define texid_tf texid_t
#define TEXASSIGN(d,s) d=s
#define TEXASSIGNF(d,s) d=s
#define TEXVALID(t) ((t).ref!=NULL)
#define TEXVALID(t) ((t))
#define TEXLOADED(tex) ((tex) && (tex)->status == TEX_LOADED)
#define TEXDOWAIT(tex) if ((tex) && (tex)->status == TEX_LOADING) COM_WorkerPartialSync((tex), &(tex)->status, TEX_LOADING)
#else
typedef struct texid_s texid_t[1];
typedef struct texid_s texid_tf;
@ -201,6 +248,38 @@ typedef struct texid_s texid_tf;
#define TEXVALID(t) 1
#endif
struct pendingtextureinfo
{
enum
{
PTI_2D,
PTI_3D,
PTI_CUBEMAP //mips are packed (to make d3d11 happy)
} type;
enum
{
PTI_RGBA8, //rgba byte ordering
PTI_RGBX8, //rgb pad byte ordering
PTI_BGRA8, //alpha channel
PTI_BGRX8, //no alpha channel
//compressed formats
PTI_S3RGB1,
PTI_S3RGBA1,
PTI_S3RGBA3,
PTI_S3RGBA5
} encoding; //0
int mipcount;
struct
{
void *data;
size_t datasize;
int width;
int height;
qboolean needfree;
} mip[32];
void *extrafree;
};
//small context for easy vbo creation.
typedef struct
{
@ -214,7 +293,7 @@ typedef struct vboarray_s
{
union
{
void *dummy;
void *sysptr;
#ifdef GLQUAKE
struct
{
@ -251,38 +330,6 @@ typedef struct texnums_s {
texid_t loweroverlay;
texid_t fullbright;
} texnums_t;
typedef enum uploadfmt
{
TF_INVALID,
TF_RGBA32, /*rgba byte order*/
TF_BGRA32, /*bgra byte order*/
TF_RGBX32, /*rgb byte order, with extra wasted byte after blue*/
TF_BGRX32, /*rgb byte order, with extra wasted byte after blue*/
TF_RGB24, /*rgb byte order, no alpha channel nor pad, and regular top down*/
TF_BGR24, /*bgr byte order, no alpha channel nor pad, and regular top down*/
TF_BGR24_FLIP, /*bgr byte order, no alpha channel nor pad, and bottom up*/
TF_LUM8, /*8bit greyscale image*/
TF_SOLID8, /*8bit quake-palette image*/
TF_TRANS8, /*8bit quake-palette image, index 255=transparent*/
TF_TRANS8_FULLBRIGHT, /*fullbright 8 - fullbright texels have alpha 255, everything else 0*/
TF_HEIGHT8, /*image data is greyscale, convert to a normalmap and load that, uploaded alpha contains the original heights*/
TF_HEIGHT8PAL, /*source data is palette values rather than actual heights, generate a fallback heightmap*/
TF_H2_T7G1, /*8bit data, odd indexes give greyscale transparence*/
TF_H2_TRANS8_0, /*8bit data, 0 is transparent, not 255*/
TF_H2_T4A4, /*8bit data, weird packing*/
/*this block requires a palette*/
TF_PALETTES,
TF_8PAL24,
TF_8PAL32,
/*for render targets*/
TF_DEPTH16,
TF_DEPTH24,
TF_DEPTH32,
TF_RGBA16F,
TF_RGBA32F
} uploadfmt_t;
//not all modes accept meshes - STENCIL(intentional) and DEPTHONLY(not implemented)
typedef enum backendmode_e
@ -306,22 +353,14 @@ typedef struct rendererinfo_s {
void (*Draw_Init) (void);
void (*Draw_Shutdown) (void);
texid_tf (*IMG_LoadTexture) (const char *identifier, int width, int height, uploadfmt_t fmt, void *data, unsigned int flags);
texid_tf (*IMG_LoadTexture8Pal24) (const char *identifier, int width, int height, qbyte *data, qbyte *palette24, unsigned int flags);
texid_tf (*IMG_LoadTexture8Pal32) (const char *identifier, int width, int height, qbyte *data, qbyte *palette32, unsigned int flags);
texid_tf (*IMG_LoadCompressed) (const char *name);
texid_tf (*IMG_FindTexture) (const char *identifier, unsigned int flags);
texid_tf (*IMG_AllocNewTexture) (const char *identifier, int w, int h, unsigned int flags);
void (*IMG_Upload) (texid_t tex, const char *name, uploadfmt_t fmt, void *data, void *palette, int width, int height, unsigned int flags);
void (*IMG_UpdateFiltering) (image_t *imagelist, int filtermip[3], int filterpic[3], int mipcap[2], float anis);
qboolean (*IMG_LoadTextureMips) (texid_t tex, struct pendingtextureinfo *mips);
void (*IMG_DestroyTexture) (texid_t tex);
void (*R_Init) (void); //FIXME - merge implementations
void (*R_DeInit) (void); //FIXME - merge implementations
void (*R_RenderView) (void); // must set r_refdef first
void (*R_NewMap) (void); //FIXME - merge implementations
void (*R_PreNewMap) (void); //FIXME - merge implementations
qboolean (*VID_Init) (rendererstate_t *info, unsigned char *palette);
void (*VID_DeInit) (void);
void (*VID_SwapBuffers) (void); //force a buffer swap, regardless of what's displayed.
@ -356,7 +395,7 @@ typedef struct rendererinfo_s {
//Uploads all modified lightmaps
void (*BE_UploadAllLightmaps)(void);
void (*BE_SelectEntity)(struct entity_s *ent);
qboolean (*BE_SelectDLight)(struct dlight_s *dl, vec3_t colour, unsigned int lmode);
qboolean (*BE_SelectDLight)(struct dlight_s *dl, vec3_t colour, vec3_t axis[3], unsigned int lmode);
void (*BE_Scissor)(srect_t *rect);
/*check to see if an ent should be drawn for the selected light*/
qboolean (*BE_LightCullModel)(vec3_t org, struct model_s *model);
@ -372,15 +411,6 @@ typedef struct rendererinfo_s {
#define VID_SwapBuffers rf->VID_SwapBuffers
#define R_LoadTexture rf->IMG_LoadTexture
#define R_LoadTexture8Pal24 rf->IMG_LoadTexture8Pal24
#define R_LoadTexture8Pal32 rf->IMG_LoadTexture8Pal32
#define R_LoadCompressed rf->IMG_LoadCompressed
#define R_FindTexture rf->IMG_FindTexture
#define R_AllocNewTexture rf->IMG_AllocNewTexture
#define R_Upload rf->IMG_Upload
#define R_DestroyTexture rf->IMG_DestroyTexture
#define BE_Init rf->BE_Init
#define BE_SelectMode rf->BE_SelectMode
#define BE_GenBrushModelVBO rf->BE_GenBrushModelVBO

View File

@ -43,6 +43,7 @@ typedef enum {
LAVASPLASH_POINT,
EXPLOSION_POINT,
TELEPORTSPLASH_POINT,
MUZZLEFLASH_POINT,
EFFECTTYPE_MAX
} effect_type_t;
@ -127,6 +128,8 @@ static int PClassic_FindParticleType(const char *name)
return EXPLOSION_POINT;
if (!stricmp("te_teleport", name))
return TELEPORTSPLASH_POINT;
if (!stricmp("te_muzzleflash", name))
return MUZZLEFLASH_POINT;
return P_INVALID;
}
@ -867,7 +870,7 @@ done:
//builds a trail from here to there. The trail state can be used to remember how far you got last frame.
static int PClassic_ParticleTrail (vec3_t startpos, vec3_t end, int type, int dlkey, trailstate_t **tsk)
static int PClassic_ParticleTrail (vec3_t startpos, vec3_t end, int type, int dlkey, vec3_t dlaxis[3], trailstate_t **tsk)
{
float leftover;
@ -897,6 +900,36 @@ static int PClassic_RunParticleEffectState (vec3_t org, vec3_t dir, float count,
case TELEPORTSPLASH_POINT:
Classic_TeleportSplash(org);
break;
case MUZZLEFLASH_POINT:
{
dlight_t *dl = CL_AllocDlight (0);
if (dir)
VectorCopy(dir, dl->axis[0]);
else
VectorSet(dir, 0, 0, 1);
VectorVectors(dl->axis[0], dl->axis[1], dl->axis[2]);
VectorInverse(dl->axis[1]);
if (dir)
VectorMA (org, 15, dl->axis[0], dl->origin);
else
VectorCopy (org, dl->origin);
dl->radius = 200 + (rand()&31);
dl->minlight = 32;
dl->die = cl.time + 0.1;
dl->color[0] = 1.5;
dl->color[1] = 1.3;
dl->color[2] = 1.0;
dl->channelfade[0] = 1.5;
dl->channelfade[1] = 0.75;
dl->channelfade[2] = 0.375;
dl->decay = 1000;
#ifdef RTLIGHTS
dl->lightcolourscales[2] = 4;
#endif
}
break;
default:
return 1;
}

View File

@ -12,7 +12,7 @@ static int PNULL_FindParticleType(const char *name)
}
static int PNULL_RunParticleEffectTypeString (vec3_t org, vec3_t dir, float count, char *name){return 1;}
static int PNULL_ParticleTrail (vec3_t startpos, vec3_t end, int type, int dlkey, trailstate_t **tsk){return 1;}
static int PNULL_ParticleTrail (vec3_t startpos, vec3_t end, int type, int dlkey, vec3_t dlaxis[3], trailstate_t **tsk){return 1;}
static int PNULL_RunParticleEffectState (vec3_t org, vec3_t dir, float count, int typenum, trailstate_t **tsk){return 1;}
static void PNULL_RunParticleWeather(vec3_t minb, vec3_t maxb, vec3_t dir, float count, int colour, char *efname){}
static void PNULL_RunParticleCube(int typenum, vec3_t minb, vec3_t maxb, vec3_t dir_min, vec3_t dir_max, float count, int colour, qboolean gravity, float jitter){}

View File

@ -273,7 +273,7 @@ typedef struct part_type_s {
float stainonimpact;
vec3_t dl_rgb;
float dl_radius;
float dl_radius[2];
float dl_time;
vec4_t dl_decay;
float dl_corona_intensity;
@ -622,6 +622,8 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn)
"alphagen vertex\n"
"}\n"
"polygonoffset\n"
"surfaceparm noshadows\n"
"surfaceparm nodlight\n"
"}\n"
;
break;
@ -638,6 +640,8 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn)
"alphagen vertex\n"
"}\n"
"polygonoffset\n"
"surfaceparm noshadows\n"
"surfaceparm nodlight\n"
"}\n"
;
break;
@ -655,6 +659,8 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn)
"alphagen vertex\n"
"}\n"
"polygonoffset\n"
"surfaceparm noshadows\n"
"surfaceparm nodlight\n"
"}\n"
;
break;
@ -672,6 +678,8 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn)
"alphagen vertex\n"
"}\n"
"polygonoffset\n"
"surfaceparm noshadows\n"
"surfaceparm nodlight\n"
"}\n"
;
break;
@ -689,6 +697,8 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn)
"alphagen vertex\n"
"}\n"
"polygonoffset\n"
"surfaceparm noshadows\n"
"surfaceparm nodlight\n"
"}\n"
;
break;
@ -706,6 +716,8 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn)
"alphagen vertex\n"
"}\n"
"polygonoffset\n"
"surfaceparm noshadows\n"
"surfaceparm nodlight\n"
"}\n"
;
break;
@ -723,6 +735,8 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn)
"alphagen vertex\n"
"}\n"
"polygonoffset\n"
"surfaceparm noshadows\n"
"surfaceparm nodlight\n"
"}\n"
;
break;
@ -739,14 +753,23 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn)
"alphagen vertex\n"
"}\n"
"polygonoffset\n"
"surfaceparm noshadows\n"
"surfaceparm nodlight\n"
"}\n"
;
break;
}
memset(&tn, 0, sizeof(tn));
tn.base = R_LoadHiResTexture(ptype->texname, "particles", IF_NOMIPMAP|(ptype->looks.premul?IF_PREMULTIPLYALPHA:0)); //mipmapping breaks particlefont stuff
if (!TEXVALID(tn.base))
if (*ptype->texname)
{
tn.base = R_LoadHiResTexture(ptype->texname, "particles", IF_NOMIPMAP|(ptype->looks.premul?IF_PREMULTIPLYALPHA:0)); //mipmapping breaks particlefont stuff
if (tn.base && tn.base->status == TEX_LOADING)
COM_WorkerPartialSync(tn.base, &tn.base->status, TEX_LOADING);
}
else
tn.base = NULL;
if (!TEXLOADED(tn.base))
{
/*okay, so the texture they specified wasn't valid either. use a fully default one*/
@ -1719,7 +1742,12 @@ static void P_ParticleEffect_f(void)
ptype->flags |= PT_NOSPREADLAST;
else if (!strcmp(var, "lightradius"))
ptype->dl_radius = atof(value);
{ //float version
ptype->dl_radius[0] = ptype->dl_radius[1] = atof(value);
if (Cmd_Argc()>3)
ptype->dl_radius[1] = atof(Cmd_Argv(2));
ptype->dl_radius[1] -= ptype->dl_radius[0];
}
else if (!strcmp(var, "lightradiusfade"))
ptype->dl_decay[3] = atof(value);
else if (!strcmp(var, "lightrgb"))
@ -1805,7 +1833,7 @@ static void P_ParticleEffect_f(void)
ptype->alphachange = (-ptype->alphachange / ptype->die) * ptype->alpha;
if (!ptype->dl_time && ptype->dl_decay[3])
ptype->dl_time = ptype->dl_radius / ptype->dl_decay[3];
ptype->dl_time = ptype->dl_radius[0] / ptype->dl_decay[3];
if (ptype->rampmode && !ptype->ramp)
{
@ -2009,7 +2037,7 @@ qboolean PScript_Query(int typenum, int body, char *outstr, int outstrlen)
if (ptype->dl_radius)
{
Q_strncatz(outstr, va("lightradius %g\n", ptype->dl_radius), outstrlen);
Q_strncatz(outstr, va("lightradius %g\n", ptype->dl_radius[0]), outstrlen);
Q_strncatz(outstr, va("lightradiusfade %g\n", ptype->dl_decay[3]), outstrlen);
Q_strncatz(outstr, va("lightrgb %g %g %g\n", ptype->dl_rgb[0], ptype->dl_rgb[1], ptype->dl_rgb[2]), outstrlen);
Q_strncatz(outstr, va("lightrgbfade %g %g %g\n", ptype->dl_decay[0], ptype->dl_decay[1], ptype->dl_decay[2]), outstrlen);
@ -2243,7 +2271,7 @@ void FinishParticleType(part_type_t *ptype)
ptype->die = 15;
}
if (ptype->dl_decay[3] && !ptype->dl_time)
ptype->dl_time = ptype->dl_radius / ptype->dl_decay[3];
ptype->dl_time = ptype->dl_radius[0] / ptype->dl_decay[3];
if (ptype->looks.scalefactor > 1 && !ptype->looks.invscalefactor)
{
ptype->scale *= ptype->looks.scalefactor;
@ -2561,7 +2589,10 @@ static void P_ImportEffectInfo(char *config, char *line)
Con_Printf("effectinfo 'orientation %s' not supported\n", arg[1]);
}
else if (!strcmp(arg[0], "lightradius") && args == 2)
ptype->dl_radius = atof(arg[1]);
{
ptype->dl_radius[0] = atof(arg[1]);
ptype->dl_radius[1] = 0;
}
else if (!strcmp(arg[0], "lightradiusfade") && args == 2)
ptype->dl_decay[3] = atof(arg[1]);
else if (!strcmp(arg[0], "lightcolor") && args == 4)
@ -2986,6 +3017,7 @@ static void R_Particles_KillAllEffects(void)
static void R_ParticleDesc_Callback(struct cvar_s *var, char *oldvalue)
{
char token[256];
qboolean first;
char *c;
@ -2996,12 +3028,12 @@ static void R_ParticleDesc_Callback(struct cvar_s *var, char *oldvalue)
R_Particles_KillAllEffects();
first = true;
for (c = COM_ParseStringSet(var->string); com_token[0]; c = COM_ParseStringSet(c))
for (c = COM_ParseStringSet(var->string, token, sizeof(token)); token[0]; c = COM_ParseStringSet(c, token, sizeof(token)))
{
/*set up a default*/
if (first && !*com_token)
strcpy(com_token, "faithful");
P_LoadParticleSet(com_token, false);
if (first && !*token)
strcpy(token, "classic");
P_LoadParticleSet(token, false);
first = false;
}
@ -3556,8 +3588,10 @@ static void PScript_ApplyOrgVel(vec3_t oorg, vec3_t ovel, vec3_t eforg, vec3_t e
VectorAdd(oorg, ptype->orgbias, oorg);
}
static void PScript_EffectSpawned(part_type_t *ptype, vec3_t org, vec3_t dir, int dlkey, float countscale)
static void PScript_EffectSpawned(part_type_t *ptype, vec3_t org, vec3_t axis[3], int dlkey, float countscale)
{
extern cvar_t r_rocketlight;
extern cvar_t r_lightflicker;
if (ptype->nummodels)
{
int count = ptype->countextra + countscale*(ptype->count+ptype->countrand*frandom());
@ -3570,17 +3604,30 @@ static void PScript_EffectSpawned(part_type_t *ptype, vec3_t org, vec3_t dir, in
mod = &ptype->models[rand() % ptype->nummodels];
if (!mod->model)
mod->model = Mod_ForName(mod->name, MLV_WARN);
if (mod->model && !mod->model->needload)
if (mod->model && mod->model->loadstate == MLS_LOADED)
{
vec3_t morg, mdir;
PScript_ApplyOrgVel(morg, mdir, org, dir, i, count, ptype);
CL_SpawnSpriteEffect(morg, mdir, (mod->rflags&RF_USEORIENTATION)?dir:NULL, mod->model, mod->framestart, (mod->frameend?mod->frameend:(mod->model->numframes - mod->framestart)), mod->framerate?mod->framerate:10, mod->alpha?mod->alpha:1, ptype->rotationmin*180/M_PI, ptype->gravity, mod->traileffect, mod->rflags & ~RF_USEORIENTATION);
PScript_ApplyOrgVel(morg, mdir, org, axis[0], i, count, ptype);
CL_SpawnSpriteEffect(morg, mdir, (mod->rflags&RF_USEORIENTATION)?axis[0]:NULL, mod->model, mod->framestart, (mod->frameend?mod->frameend:(mod->model->numframes - mod->framestart)), mod->framerate?mod->framerate:10, mod->alpha?mod->alpha:1, ptype->rotationmin*180/M_PI, ptype->gravity, mod->traileffect, mod->rflags & ~RF_USEORIENTATION);
}
}
}
if (ptype->dl_radius)
if (ptype->dl_radius)// && r_rocketlight.value)
{
dlight_t *dl = CL_NewDlight(dlkey, org, ptype->dl_radius, ptype->dl_time, ptype->dl_rgb[0], ptype->dl_rgb[1], ptype->dl_rgb[2]);
float radius;
dlight_t *dl;
static int flickertime;
static int flicker;
int i = realtime*20;
if (flickertime != i)
{
flickertime = i;
flicker = rand();
}
radius = ptype->dl_radius[0] + (r_lightflicker.ival?((flicker + dlkey*2000)&0xffff)*(1.0f/0xffff):0.5)*ptype->dl_radius[1];
dl = CL_NewDlight(dlkey, org, radius, ptype->dl_time, ptype->dl_rgb[0], ptype->dl_rgb[1], ptype->dl_rgb[2]);
dl->channelfade[0] = ptype->dl_decay[0];
dl->channelfade[1] = ptype->dl_decay[1];
dl->channelfade[2] = ptype->dl_decay[2];
@ -3595,7 +3642,7 @@ static void PScript_EffectSpawned(part_type_t *ptype, vec3_t org, vec3_t dir, in
if (ptype->flags & PT_NODLSHADOW)
dl->flags |= LFLAG_NOSHADOWS;
if (ptype->dl_cubemapnum)
snprintf(dl->cubemapname, sizeof(dl->cubemapname), "cubemaps/%i", ptype->dl_cubemapnum);
Q_snprintfz(dl->cubemapname, sizeof(dl->cubemapname), "cubemaps/%i", ptype->dl_cubemapnum);
}
if (ptype->numsounds)
{
@ -3695,8 +3742,17 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count,
goto skip;
}
PScript_EffectSpawned(ptype, org, dir, 0, count);
if (dir)
{
void PerpendicularVector( vec3_t dst, const vec3_t src );
VectorCopy(dir, axis[2]);
VectorNormalize(axis[2]);
PerpendicularVector(axis[0], axis[2]);
VectorNormalize(axis[0]);
CrossProduct(axis[2], axis[0], axis[1]);
VectorNormalize(axis[1]);
}
PScript_EffectSpawned(ptype, org, axis, 0, count);
if (ptype->looks.type == PT_CDECAL)
{
@ -3897,17 +3953,6 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count,
break;
}
if (dir)
{
void PerpendicularVector( vec3_t dst, const vec3_t src );
VectorCopy(dir, axis[2]);
VectorNormalize(axis[2]);
PerpendicularVector(axis[0], axis[2]);
VectorNormalize(axis[0]);
CrossProduct(axis[2], axis[0], axis[1]);
VectorNormalize(axis[1]);
}
// time limit (for completeness)
if (ptype->spawntime && ts)
{
@ -4497,7 +4542,7 @@ static void PScript_RunParticleWeather(vec3_t minb, vec3_t maxb, vec3_t dir, flo
}
}
static void P_ParticleTrailDraw (vec3_t startpos, vec3_t end, part_type_t *ptype, trailstate_t **tsk, int dlkey)
static void P_ParticleTrailDraw (vec3_t startpos, vec3_t end, part_type_t *ptype, trailstate_t **tsk, int dlkey, vec3_t dlaxis[3])
{
vec3_t vec, vstep, right, up, start;
float len;
@ -4546,14 +4591,14 @@ static void P_ParticleTrailDraw (vec3_t startpos, vec3_t end, part_type_t *ptype
else
ts = NULL;
PScript_EffectSpawned(ptype, start, vec3_origin, dlkey, 1);
PScript_EffectSpawned(ptype, start, dlaxis, dlkey, 1);
if (ptype->assoc>=0)
{
if (ts)
P_ParticleTrail(start, end, ptype->assoc, dlkey, &(ts->assoc));
P_ParticleTrail(start, end, ptype->assoc, dlkey, NULL, &(ts->assoc));
else
P_ParticleTrail(start, end, ptype->assoc, dlkey, NULL);
P_ParticleTrail(start, end, ptype->assoc, dlkey, NULL, NULL);
}
if (r_part_contentswitch.ival && (ptype->flags & (PT_TRUNDERWATER | PT_TROVERWATER)) && cl.worldmodel)
@ -4989,14 +5034,14 @@ static void P_ParticleTrailDraw (vec3_t startpos, vec3_t end, part_type_t *ptype
return;
}
static int PScript_ParticleTrail (vec3_t startpos, vec3_t end, int type, int dlkey, trailstate_t **tsk)
static int PScript_ParticleTrail (vec3_t startpos, vec3_t end, int type, int dlkey, vec3_t axis[3], trailstate_t **tsk)
{
part_type_t *ptype = &part_type[type];
// TODO: fallback particle system won't have a decent trailstate which will mess up
// high fps trails
if (type >= FALLBACKBIAS && fallback)
return fallback->ParticleTrail(startpos, end, type-FALLBACKBIAS, dlkey, NULL);
return fallback->ParticleTrail(startpos, end, type-FALLBACKBIAS, dlkey, axis, NULL);
if (type < 0 || type >= numparticletypes)
return 1; //bad value
@ -5014,7 +5059,7 @@ static int PScript_ParticleTrail (vec3_t startpos, vec3_t end, int type, int dlk
ptype = &part_type[ptype->inwater];
}
P_ParticleTrailDraw (startpos, end, ptype, tsk, dlkey);
P_ParticleTrailDraw (startpos, end, ptype, tsk, dlkey, axis);
return 0;
}
@ -5022,7 +5067,7 @@ static void PScript_ParticleTrailIndex (vec3_t start, vec3_t end, int color, int
{
part_type[pe_defaulttrail].colorindex = color;
part_type[pe_defaulttrail].colorrand = crnd;
P_ParticleTrail(start, end, pe_defaulttrail, 0, tsk);
P_ParticleTrail(start, end, pe_defaulttrail, 0, NULL, tsk);
}
static vec3_t pright, pup;
@ -5766,7 +5811,7 @@ static void PScript_DrawParticleTypes (void)
{
if (type->clippeddecals)
{
if (cl_numstris && cl_stris[cl_numstris-1].shader == type->looks.shader && cl_stris[cl_numstris-1].flags == (BEF_NODLIGHT|BEF_NOSHADOWS))
if (cl_numstris && cl_stris[cl_numstris-1].shader == type->looks.shader && cl_stris[cl_numstris-1].flags == 0)
scenetri = &cl_stris[cl_numstris-1];
else
{
@ -5777,7 +5822,7 @@ static void PScript_DrawParticleTypes (void)
}
scenetri = &cl_stris[cl_numstris++];
scenetri->shader = type->looks.shader;
scenetri->flags = BEF_NODLIGHT|BEF_NOSHADOWS;
scenetri->flags = 0;
scenetri->firstidx = cl_numstrisidx;
scenetri->firstvert = cl_numstrisvert;
scenetri->numvert = 0;
@ -5890,7 +5935,7 @@ static void PScript_DrawParticleTypes (void)
if (!tdraw || type->looks.shader->sort == SHADER_SORT_BLEND)
scenetri = NULL;
else if (cl_numstris && cl_stris[cl_numstris-1].shader == type->looks.shader && cl_stris[cl_numstris-1].flags == (BEF_NODLIGHT|BEF_NOSHADOWS))
else if (cl_numstris && cl_stris[cl_numstris-1].shader == type->looks.shader && cl_stris[cl_numstris-1].flags == 0)
scenetri = &cl_stris[cl_numstris-1];
else
{
@ -5903,7 +5948,7 @@ static void PScript_DrawParticleTypes (void)
scenetri->shader = type->looks.shader;
scenetri->firstidx = cl_numstrisidx;
scenetri->firstvert = cl_numstrisvert;
scenetri->flags = BEF_NODLIGHT|BEF_NOSHADOWS;
scenetri->flags = 0;
scenetri->numvert = 0;
scenetri->numidx = 0;
}
@ -6139,7 +6184,7 @@ static void PScript_DrawParticleTypes (void)
if (type->emit >= 0)
{
if (type->emittime < 0)
P_ParticleTrail(oldorg, p->org, type->emit, 0, &p->state.trailstate);
P_ParticleTrail(oldorg, p->org, type->emit, 0, NULL, &p->state.trailstate);
else if (p->state.nextemit < particletime)
{
p->state.nextemit = particletime + type->emittime + frandom()*type->emitrand;

View File

@ -469,7 +469,7 @@ void QCBUILTIN PF_soundlength (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
const char *sample = PR_GetStringOfs(prinst, OFS_PARM0);
sfx_t *sfx = S_PrecacheSound(sample);
if (!sfx || sfx->failedload)
if (!sfx || sfx->loadstate != SLS_LOADED)
G_FLOAT(OFS_RETURN) = 0;
else
{

View File

@ -70,6 +70,7 @@ static playerview_t *csqc_playerview;
static qboolean csqc_isdarkplaces;
static qboolean csqc_singlecheats; /*single player or cheats active, allowing custom addons*/
static qboolean csqc_mayread; //csqc is allowed to ReadByte();
static qboolean csqc_worldchanged; //make sure any caches are rebuilt properly before the next renderscene
static char csqc_printbuffer[8192];
@ -476,9 +477,10 @@ static void cs_getframestate(csqcedict_t *in, unsigned int rflags, framestate_t
out->g[FS_REG].frametime[1] = in->xv->frame2time;
}
#if defined(SKELETALOBJECTS) || defined(RAGDOLL)
out->bonecount = 0;
out->bonestate = NULL;
#if defined(SKELETALOBJECTS) || defined(RAGDOLL)
if (in->xv->skeletonindex)
skel_lookup(csqcprogs, in->xv->skeletonindex, out);
#endif
@ -740,7 +742,12 @@ static void QCBUILTIN PF_cs_makestatic (pubprogfuncs_t *prinst, struct globalvar
ent = &cl_static_entities[cl.num_statics].ent;
if (CopyCSQCEdictToEntity(in, ent))
{
cl_static_entities[cl.num_statics].emit = NULL;
cl_static_entities[cl.num_statics].mdlidx = in->v->modelindex;
if (cl.worldmodel && cl.worldmodel->funcs.FindTouchedLeafs)
cl.worldmodel->funcs.FindTouchedLeafs(cl.worldmodel, &cl_static_entities[cl.num_statics].pvscache, in->v->absmin, in->v->absmax);
else
memset(&cl_static_entities[cl.num_statics].pvscache, 0, sizeof(cl_static_entities[cl.num_statics].pvscache));
cl.num_statics++;
}
@ -828,7 +835,7 @@ static void QCBUILTIN PF_R_DynamicLight_Set(pubprogfuncs_t *prinst, struct globa
s = PR_GetStringOfs(prinst, OFS_PARM2);
Q_strncpyz(l->cubemapname, s, sizeof(l->cubemapname));
if (*l->cubemapname)
l->cubetexture = R_LoadReplacementTexture(l->cubemapname, "", IF_CUBEMAP);
l->cubetexture = R_LoadReplacementTexture(l->cubemapname, "", IF_CUBEMAP, NULL, 0, 0, TF_INVALID);
else
l->cubetexture = r_nulltex;
break;
@ -842,6 +849,11 @@ static void QCBUILTIN PF_R_DynamicLight_Set(pubprogfuncs_t *prinst, struct globa
case lfield_specularscale:
l->lightcolourscales[2] = G_FLOAT(OFS_PARM2);
break;
case lfield_rotation:
l->rotation[0] = G_FLOAT(OFS_PARM2+0);
l->rotation[1] = G_FLOAT(OFS_PARM2+1);
l->rotation[2] = G_FLOAT(OFS_PARM2+2);
break;
#endif
default:
break;
@ -907,6 +919,11 @@ static void QCBUILTIN PF_R_DynamicLight_Get(pubprogfuncs_t *prinst, struct globa
case lfield_specularscale:
G_FLOAT(OFS_RETURN) = l->lightcolourscales[2];
break;
case lfield_rotation:
G_FLOAT(OFS_RETURN+0) = l->rotation[0];
G_FLOAT(OFS_RETURN+1) = l->rotation[1];
G_FLOAT(OFS_RETURN+2) = l->rotation[2];
break;
#endif
default:
G_INT(OFS_RETURN) = 0;
@ -938,9 +955,12 @@ void QCBUILTIN PF_R_DynamicLight_Add(pubprogfuncs_t *prinst, struct globalvars_s
//if the org matches self, then attach it.
dl = CL_NewDlight (dlkey, org, radius, -0.1, rgb[0], rgb[1], rgb[2]);
VectorCopy(csqcg.forward, dl->axis[0]);
VectorCopy(csqcg.right, dl->axis[1]);
VectorCopy(csqcg.up, dl->axis[2]);
if (*dl->cubemapname)
{
VectorCopy(csqcg.forward, dl->axis[0]);
VectorCopy(csqcg.right, dl->axis[1]);
VectorCopy(csqcg.up, dl->axis[2]);
}
if (pflags & PFLAGS_NOSHADOW)
dl->flags |= LFLAG_NOSHADOWS;
@ -951,7 +971,7 @@ void QCBUILTIN PF_R_DynamicLight_Add(pubprogfuncs_t *prinst, struct globalvars_s
dl->style = style;
Q_strncpyz(dl->cubemapname, cubemapname, sizeof(dl->cubemapname));
if (*dl->cubemapname)
dl->cubetexture = R_LoadReplacementTexture(dl->cubemapname, "", IF_CUBEMAP);
dl->cubetexture = R_LoadReplacementTexture(dl->cubemapname, "", IF_CUBEMAP, NULL, 0, 0, TF_INVALID);
else
dl->cubetexture = r_nulltex;
@ -1344,14 +1364,14 @@ void QCBUILTIN PF_R_GetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
break;
case VF_CL_VIEWANGLES_V:
if (r_refdef.playerview)
VectorCopy(r_refdef.playerview->viewangles, r);
if (csqc_playerview)
VectorCopy(csqc_playerview->viewangles, r);
break;
case VF_CL_VIEWANGLES_X:
case VF_CL_VIEWANGLES_Y:
case VF_CL_VIEWANGLES_Z:
if (r_refdef.playerview)
*r = r_refdef.playerview->viewangles[parametertype-VF_CL_VIEWANGLES_X];
if (csqc_playerview)
*r = csqc_playerview->viewangles[parametertype-VF_CL_VIEWANGLES_X];
break;
case VF_CARTESIAN_ANGLES:
@ -1473,13 +1493,13 @@ void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
case VF_ORIGIN:
VectorCopy(p, r_refdef.vieworg);
if (r_refdef.playerview)
r_refdef.playerview->crouch = 0;
if (csqc_playerview)
csqc_playerview->crouch = 0;
break;
case VF_ORIGIN_Z:
if (r_refdef.playerview)
r_refdef.playerview->crouch = 0;
if (csqc_playerview)
csqc_playerview->crouch = 0;
case VF_ORIGIN_X:
case VF_ORIGIN_Y:
r_refdef.vieworg[parametertype-VF_ORIGIN_X] = *p;
@ -1495,14 +1515,14 @@ void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
break;
case VF_CL_VIEWANGLES_V:
if (r_refdef.playerview)
VectorCopy(p, r_refdef.playerview->viewangles);
if (csqc_playerview)
VectorCopy(p, csqc_playerview->viewangles);
break;
case VF_CL_VIEWANGLES_X:
case VF_CL_VIEWANGLES_Y:
case VF_CL_VIEWANGLES_Z:
if (r_refdef.playerview)
r_refdef.playerview->viewangles[parametertype-VF_CL_VIEWANGLES_X] = *p;
if (csqc_playerview)
csqc_playerview->viewangles[parametertype-VF_CL_VIEWANGLES_X] = *p;
break;
case VF_CARTESIAN_ANGLES:
@ -1611,6 +1631,12 @@ void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
void R2D_PolyBlend (void);
static void QCBUILTIN PF_R_RenderScene(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
if (csqc_worldchanged)
{
csqc_worldchanged = false;
Surf_NewMap();
}
if (cl.worldmodel)
R_PushDlights ();
@ -1704,24 +1730,42 @@ static void QCBUILTIN PF_cs_getstats(pubprogfuncs_t *prinst, struct globalvars_s
static void QCBUILTIN PF_cs_SetOrigin(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
csqcedict_t *ent = (void*)G_EDICT(prinst, OFS_PARM0);
world_t *w = prinst->parms->user;
wedict_t *ent = (void*)G_WEDICT(prinst, OFS_PARM0);
float *org = G_VECTOR(OFS_PARM1);
if (ent->readonly)
{
Con_Printf("setorigin on entity %i\n", ent->entnum);
return;
}
VectorCopy(org, ent->v->origin);
World_LinkEdict(&csqc_world, (wedict_t*)ent, false);
World_LinkEdict(w, (wedict_t*)ent, false);
}
static void QCBUILTIN PF_cs_SetSize(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
static void QCBUILTIN PF_cs_SetSize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
csqcedict_t *ent = (void*)G_EDICT(prinst, OFS_PARM0);
float *mins = G_VECTOR(OFS_PARM1);
float *maxs = G_VECTOR(OFS_PARM2);
world_t *w = prinst->parms->user;
wedict_t *e;
float *min, *max;
VectorCopy(mins, ent->v->mins);
VectorCopy(maxs, ent->v->maxs);
World_LinkEdict(&csqc_world, (wedict_t*)ent, false);
e = G_WEDICT(prinst, OFS_PARM0);
if (e->isfree)
{
Con_TPrintf("%s edict was free\n", "setsize");
prinst->pr_trace = 1;
return;
}
if (e->readonly)
{
Con_TPrintf("setsize on entity %i\n", e->entnum);
return;
}
min = G_VECTOR(OFS_PARM1);
max = G_VECTOR(OFS_PARM2);
VectorCopy (min, e->v->mins);
VectorCopy (max, e->v->maxs);
VectorSubtract (max, min, e->v->size);
World_LinkEdict (w, (wedict_t*)e, false);
}
static void cs_settracevars(trace_t *tr, struct globalvars_s *pr_globals)
@ -1880,7 +1924,7 @@ static void QCBUILTIN PF_cs_pointcontents(pubprogfuncs_t *prinst, struct globalv
G_FLOAT(OFS_RETURN) = Q1CONTENTS_EMPTY;
}
static int FindModel(const char *name, int *free)
static int CS_FindModel(const char *name, int *free)
{
int i;
@ -1889,6 +1933,8 @@ static int FindModel(const char *name, int *free)
if (!name || !*name)
return 0;
name = Mod_FixName(name, csqc_world.worldmodel->name);
for (i = 1; i < MAX_CSMODELS; i++)
{
if (!*cl.model_csqcname[i])
@ -1907,31 +1953,48 @@ static int FindModel(const char *name, int *free)
return 0;
}
static void csqc_setmodel(pubprogfuncs_t *prinst, csqcedict_t *ent, int modelindex)
static model_t *csqc_setmodel(pubprogfuncs_t *prinst, csqcedict_t *ent, int modelindex)
{
model_t *model;
if (ent->readonly)
{
Con_Printf("setmodel on readonly entity %i\n", ent->entnum);
return NULL;
}
ent->v->modelindex = modelindex;
if (modelindex < 0)
{
if (modelindex <= -MAX_CSMODELS)
return;
return NULL;
ent->v->model = PR_SetString(prinst, cl.model_csqcname[-modelindex]);
if (!cl.model_csqcprecache[-modelindex])
cl.model_csqcprecache[-modelindex] = Mod_ForName(cl.model_csqcname[-modelindex], MLV_WARN);
cl.model_csqcprecache[-modelindex] = Mod_ForName(Mod_FixName(cl.model_csqcname[-modelindex], csqc_world.worldmodel->name), MLV_WARN);
model = cl.model_csqcprecache[-modelindex];
}
else
{
if (modelindex >= MAX_PRECACHE_MODELS)
return;
return NULL;
ent->v->model = PR_SetString(prinst, cl.model_name[modelindex]);
model = cl.model_precache[modelindex];
}
if (model)
{
//csqc probably needs to know the actual model size for any entity. it might as well.
while(model->loadstate == MLS_LOADING)
COM_WorkerPartialSync(model, &model->loadstate, MLS_LOADING);
VectorCopy(model->mins, ent->v->mins);
VectorCopy(model->maxs, ent->v->maxs);
VectorSubtract (model->maxs, model->mins, ent->v->size);
if (!ent->entnum)
{
cl.worldmodel = r_worldentity.model = csqc_world.worldmodel = model;
csqc_worldchanged = true;
}
}
else
{
@ -1940,6 +2003,8 @@ static void csqc_setmodel(pubprogfuncs_t *prinst, csqcedict_t *ent, int modelind
}
World_LinkEdict(&csqc_world, (wedict_t*)ent, false);
return model;
}
static void QCBUILTIN PF_cs_SetModel(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -1947,7 +2012,8 @@ static void QCBUILTIN PF_cs_SetModel(pubprogfuncs_t *prinst, struct globalvars_s
csqcedict_t *ent = (void*)G_EDICT(prinst, OFS_PARM0);
const char *modelname = PR_GetStringOfs(prinst, OFS_PARM1);
int freei;
int modelindex = FindModel(modelname, &freei);
int modelindex = CS_FindModel(modelname, &freei);
model_t *mod;
if (!modelindex && modelname && *modelname)
{
@ -1960,7 +2026,9 @@ static void QCBUILTIN PF_cs_SetModel(pubprogfuncs_t *prinst, struct globalvars_s
cl.model_csqcprecache[-freei] = NULL;
}
csqc_setmodel(prinst, ent, modelindex);
mod = csqc_setmodel(prinst, ent, modelindex);
if (mod)
ent->xv->modelflags = mod->flags;
}
static void QCBUILTIN PF_cs_SetModelIndex(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
@ -1973,6 +2041,7 @@ static void QCBUILTIN PF_cs_PrecacheModel(pubprogfuncs_t *prinst, struct globalv
{
int modelindex, freei;
const char *modelname = PR_GetStringOfs(prinst, OFS_PARM0);
const char *fixedname;
int i;
if (!*modelname)
@ -1981,28 +2050,32 @@ static void QCBUILTIN PF_cs_PrecacheModel(pubprogfuncs_t *prinst, struct globalv
return;
}
fixedname = Mod_FixName(modelname, csqc_world.worldmodel->name);
for (i = 1; i < MAX_PRECACHE_MODELS; i++) //Make sure that the server specified model is loaded..
{
if (!*cl.model_name[i])
break;
if (!strcmp(cl.model_name[i], modelname))
if (!strcmp(cl.model_name[i], fixedname))
{
cl.model_precache[i] = Mod_ForName(cl.model_name[i], MLV_WARN);
if (!cl.model_precache[i])
cl.model_precache[i] = Mod_ForName(cl.model_name[i], MLV_WARN);
break;
}
}
modelindex = FindModel(modelname, &freei); //now load it
modelindex = CS_FindModel(modelname, &freei); //now load it
if (!modelindex)
{
if (!freei)
Host_EndGame("CSQC ran out of model slots\n");
Q_strncpyz(cl.model_csqcname[-freei], modelname, sizeof(cl.model_csqcname[-freei])); //allocate a slot now
fixedname = Mod_FixName(modelname, csqc_world.worldmodel->name);
Q_strncpyz(cl.model_csqcname[-freei], fixedname, sizeof(cl.model_csqcname[-freei])); //allocate a slot now
modelindex = freei;
CL_CheckOrEnqueDownloadFile(modelname, modelname, 0);
cl.model_csqcprecache[-freei] = NULL;
cl.model_csqcprecache[-freei] = Mod_ForName(fixedname, MLV_WARN);
}
G_FLOAT(OFS_RETURN) = modelindex;
@ -2197,7 +2270,7 @@ static void QCBUILTIN PF_cs_boxparticles(pubprogfuncs_t *prinst, struct globalva
if (flags & 128)
{
flags &= ~128;
P_ParticleTrail(org_from, org_to, effectnum, 0, NULL);
P_ParticleTrail(org_from, org_to, effectnum, 0, NULL, NULL);
}
else
{
@ -2244,9 +2317,25 @@ static void QCBUILTIN PF_cs_trailparticles (pubprogfuncs_t *prinst, struct globa
efnum = CL_TranslateParticleFromServer(efnum);
if (!ent->entnum) //world trails are non-state-based.
pe->ParticleTrail(start, end, efnum, 0, NULL);
pe->ParticleTrail(start, end, efnum, 0, NULL, NULL);
else
pe->ParticleTrail(start, end, efnum, -ent->entnum, &ent->trailstate);
pe->ParticleTrail(start, end, efnum, -ent->entnum, NULL, &ent->trailstate);
}
void CSQC_ResetTrails(void)
{
pubprogfuncs_t *prinst = csqc_world.progs;
int i;
csqcedict_t *ent;
if (!prinst)
return;
for (i = 0; i < *prinst->parms->sv_num_edicts; i++)
{
ent = (csqcedict_t*)EDICT_NUM(prinst, i);
ent->trailstate = NULL;
}
}
//0 for error, non-0 for success.
@ -2535,6 +2624,25 @@ static void QCBUILTIN PF_cs_runplayerphysics (pubprogfuncs_t *prinst, struct glo
if (ent)
{
int mt = ent->v->movetype;
if (ent->xv->entnum)
pmove.skipent = ent->xv->entnum;
else
pmove.skipent = -1;
mt &= 255;
switch(mt)
{
default:
case MOVETYPE_WALK:
pmove.pm_type = PM_NORMAL;
break;
case MOVETYPE_NOCLIP:
pmove.pm_type = PM_SPECTATOR;
break;
case MOVETYPE_FLY:
pmove.pm_type = PM_FLY;
break;
}
pmove.jump_held = (int)ent->xv->pmove_flags & PMF_JUMP_HELD;
pmove.waterjumptime = 0;
VectorCopy(ent->v->origin, pmove.origin);
@ -2576,6 +2684,9 @@ static void QCBUILTIN PF_cs_runplayerphysics (pubprogfuncs_t *prinst, struct glo
ent->xv->pmove_flags = 0;
ent->xv->pmove_flags += pmove.jump_held ? PMF_JUMP_HELD : 0;
ent->xv->pmove_flags += pmove.onladder ? PMF_LADDER : 0;
//fixme: touch triggers?
World_LinkEdict (&csqc_world, (wedict_t*)ent, true);
}
else
{
@ -2587,10 +2698,6 @@ static void QCBUILTIN PF_cs_runplayerphysics (pubprogfuncs_t *prinst, struct glo
VectorCopy(pmove.origin, csqcg.pmove_org);
VectorCopy(pmove.velocity, csqcg.pmove_vel);
}
//fixme: touch solids
World_LinkEdict (&csqc_world, (wedict_t*)ent, true);
}
static void QCBUILTIN PF_cs_getentitytoken (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -3465,7 +3572,7 @@ static void QCBUILTIN PF_cs_addprogs (pubprogfuncs_t *prinst, struct globalvars_
newp = -1;
else
{
newp = PR_LoadProgs(prinst, s, 0, NULL, 0);
newp = PR_LoadProgs(prinst, s, NULL, 0);
if (newp >= 0)
PR_ProgsAdded(csqcprogs, newp, s);
}
@ -3474,6 +3581,7 @@ static void QCBUILTIN PF_cs_addprogs (pubprogfuncs_t *prinst, struct globalvars_
static void QCBUILTIN PF_cs_OpenPortal (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
/*
#ifdef Q2BSPS
if (cl.worldmodel->fromgame == fg_quake2)
{
@ -3482,15 +3590,16 @@ static void QCBUILTIN PF_cs_OpenPortal (pubprogfuncs_t *prinst, struct globalvar
if (G_INT(OFS_PARM1) >= MAX_EDICTS)
portal = G_FLOAT(OFS_PARM0); //old legacy crap.
else
portal = G_EDICT(prinst, OFS_PARM0)->xv->style; //read the func_areaportal's style field.
portal = G_WEDICT(prinst, OFS_PARM0)->xv->style; //read the func_areaportal's style field.
CMQ2_SetAreaPortalState(portal, state);
}
#endif
*/
#ifdef Q3BSPS
if (cl.worldmodel->fromgame == fg_quake3)
{
int state = G_FLOAT(OFS_PARM1)!=0;
edict_t *portal = G_EDICT(prinst, OFS_PARM0);
wedict_t *portal = G_WEDICT(prinst, OFS_PARM0);
int area1 = portal->pvsinfo.areanum, area2 = portal->pvsinfo.areanum2;
if (area1 == area2 || area1<0 || area2<0)
return;
@ -3756,7 +3865,7 @@ void CSQC_EntStateToCSQC(unsigned int flags, float lerptime, entity_state_t *src
//use entnum as a test to see if its new (if the old origin isn't usable)
if (ent->xv->entnum)
{
if (model->particletrail == P_INVALID || pe->ParticleTrail (ent->v->origin, src->origin, model->particletrail, src->number, &(le->trailstate)))
if (model->particletrail == P_INVALID || pe->ParticleTrail (ent->v->origin, src->origin, model->particletrail, src->number, NULL, &(le->trailstate)))
if (model->traildefaultindex >= 0)
pe->ParticleTrailIndex(ent->v->origin, src->origin, model->traildefaultindex, 0, &(le->trailstate));
}
@ -4345,6 +4454,143 @@ static void QCBUILTIN PF_ReadServerEntityState(pubprogfuncs_t *prinst, struct gl
newlist->numents = newidx;
}
#endif
//be careful to not touch the resource unless we're meant to, to avoid stalling
static void QCBUILTIN PF_resourcestatus(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int restype = G_FLOAT(OFS_PARM0);
int doload = G_FLOAT(OFS_PARM1);
const char *resname = PR_GetStringOfs(prinst, OFS_PARM2);
int idx, idx2;
model_t *mod;
image_t *img;
// shader_t *sh;
sfx_t *sfx;
G_FLOAT(OFS_RETURN) = RESSTATE_NOTKNOWN;
switch(restype)
{
case RESTYPE_MODEL:
idx = CS_FindModel(resname, &idx2);
if (idx < 0)
{
mod = cl.model_csqcprecache[-idx];
if (!cl.model_csqcprecache[-idx] && doload)
mod = cl.model_csqcprecache[-idx] = Mod_ForName(Mod_FixName(cl.model_csqcname[-idx], cl.model_name[1]), MLV_WARN);
}
else if (idx > 0)
{
mod = cl.model_precache[idx];
if (!cl.model_precache[idx] && doload)
mod = cl.model_precache[idx] = Mod_ForName(Mod_FixName(cl.model_name[idx], cl.model_name[1]), MLV_WARN);
}
else
return;
if (!mod)
G_FLOAT(OFS_RETURN) = RESSTATE_NOTLOADED;
else
{
if (doload && mod->loadstate == MLS_NOTLOADED)
Mod_LoadModel (mod, MLV_SILENT); //should avoid blocking.
switch(mod->loadstate)
{
default:
case MLS_NOTLOADED:
G_FLOAT(OFS_RETURN) = RESSTATE_NOTLOADED;
break;
case MLS_LOADING:
G_FLOAT(OFS_RETURN) = RESSTATE_LOADING;
break;
case MLS_LOADED:
G_FLOAT(OFS_RETURN) = RESSTATE_LOADED;
break;
case MLS_FAILED:
G_FLOAT(OFS_RETURN) = RESSTATE_FAILED;
break;
}
}
return;
case RESTYPE_SOUND:
sfx = NULL;
for (idx=1 ; idx<MAX_PRECACHE_SOUNDS && cl.sound_name[idx] ; idx++)
{
if (!strcmp(cl.sound_name[idx], resname))
{
sfx = cl.sound_precache[idx];
break;
}
}
if (!sfx)
sfx = S_FindName(resname, doload);
if (!sfx)
G_FLOAT(OFS_RETURN) = RESSTATE_NOTKNOWN;
else
{
if (doload && sfx->loadstate == SLS_NOTLOADED)
S_LoadSound(sfx);
switch(sfx->loadstate)
{
case SLS_NOTLOADED:
G_FLOAT(OFS_RETURN) = RESSTATE_NOTLOADED;
break;
case SLS_LOADING:
G_FLOAT(OFS_RETURN) = RESSTATE_LOADING;
break;
case SLS_LOADED:
G_FLOAT(OFS_RETURN) = RESSTATE_LOADED;
break;
case SLS_FAILED:
G_FLOAT(OFS_RETURN) = RESSTATE_FAILED;
break;
}
}
break;
/*
case RESTYPE_PARTICLE:
G_FLOAT(OFS_RETURN) = RESSTATE_NOTKNOWN;
break;
case RESTYPE_SHADER:
sh = R_RegisterCustom(resname, 0, NULL, NULL);
if (sh)
{
//FIXME: scan through the images.
}
else
G_FLOAT(OFS_RETURN) = RESSTATE_NOTKNOWN;
break;
case RESTYPE_SKIN:
G_FLOAT(OFS_RETURN) = RESSTATE_NOTKNOWN;
break;
*/
case RESTYPE_TEXTURE:
G_FLOAT(OFS_RETURN) = RESSTATE_NOTKNOWN;
img = Image_FindTexture(resname, NULL, 0);
if (!img)
G_FLOAT(OFS_RETURN) = RESSTATE_NOTKNOWN;
else
{
switch(img->status)
{
case TEX_NOTLOADED:
G_FLOAT(OFS_RETURN) = RESSTATE_NOTLOADED;
break;
case TEX_LOADING:
G_FLOAT(OFS_RETURN) = RESSTATE_LOADING;
break;
case TEX_LOADED:
G_FLOAT(OFS_RETURN) = RESSTATE_LOADED;
break;
case TEX_FAILED:
G_FLOAT(OFS_RETURN) = RESSTATE_FAILED;
break;
}
}
break;
default:
G_FLOAT(OFS_RETURN) = RESSTATE_UNSUPPORTED;
break;
}
}
#define PF_FixTen PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme
@ -4585,6 +4831,7 @@ static struct {
{"skel_set_bone_world", PF_skel_set_bone_world, 283},
{"frametoname", PF_frametoname, 284},//string(float modidx, float framenum) frametoname
{"skintoname", PF_skintoname, 285},//string(float modidx, float skin) skintoname
{"resourcestatus", PF_resourcestatus, 286},
{"hash_createtab", PF_hash_createtab, 287},
{"hash_destroytab", PF_hash_destroytab, 288},
@ -5146,6 +5393,7 @@ void CSQC_World_GetFrameState(world_t *w, wedict_t *win, framestate_t *out)
void CSQC_Shutdown(void)
{
int i;
if (csqcprogs)
{
key_dest_absolutemouse &= ~kdm_game;
@ -5174,6 +5422,12 @@ void CSQC_Shutdown(void)
csqcent = NULL;
maxcsqcentities = 0;
for (i = 0; i < MAX_CSPARTICLESPRE && cl.particle_csname[i]; i++)
{
free(cl.particle_csname[i]);
cl.particle_csname[i] = NULL;
}
csqcmapentitydata = NULL;
csqcmapentitydataloaded = false;
@ -5182,9 +5436,12 @@ void CSQC_Shutdown(void)
}
//when the qclib needs a file, it calls out to this function.
qbyte *PDECL CSQC_PRLoadFile (const char *path, void *buffer, int bufsize)
qbyte *PDECL CSQC_PRLoadFile (const char *path, void *buffer, int bufsize, size_t *sz)
{
qbyte *file;
size_t ssz;
if (!sz)
sz = &ssz;
if (!strcmp(path, "csprogs.dat"))
{
@ -5193,40 +5450,40 @@ qbyte *PDECL CSQC_PRLoadFile (const char *path, void *buffer, int bufsize)
if (csprogs_checksum)
{
file = COM_LoadStackFile(newname, buffer, bufsize);
file = COM_LoadStackFile(newname, buffer, bufsize, sz);
if (file)
{
if (cls.protocol == CP_NETQUAKE)
{
if (QCRC_Block(file, com_filesize) == csprogs_checksum)
if (QCRC_Block(file, *sz) == csprogs_checksum)
return file;
}
else
{
if (LittleLong(Com_BlockChecksum(file, com_filesize)) == csprogs_checksum) //and the user wasn't trying to be cunning.
if (LittleLong(Com_BlockChecksum(file, *sz)) == csprogs_checksum) //and the user wasn't trying to be cunning.
return file;
}
}
}
file = COM_LoadStackFile(path, buffer, bufsize);
file = COM_LoadStackFile(path, buffer, bufsize, sz);
if (file && !cls.demoplayback) //allow them to use csprogs.dat if playing a demo, and don't care about the checksum
{
if (csprogs_checksum && !csprogs_promiscuous)
{
if (cls.protocol == CP_NETQUAKE)
{
if (QCRC_Block(file, com_filesize) != csprogs_checksum)
if (QCRC_Block(file, *sz) != csprogs_checksum)
return NULL;
}
else
{
if (LittleLong(Com_BlockChecksum(file, com_filesize)) != csprogs_checksum)
if (LittleLong(Com_BlockChecksum(file, *sz)) != csprogs_checksum)
return NULL; //not valid
}
//back it up
COM_WriteFile(newname, file, com_filesize);
COM_WriteFile(newname, file, *sz);
}
}
@ -5234,12 +5491,13 @@ qbyte *PDECL CSQC_PRLoadFile (const char *path, void *buffer, int bufsize)
}
return COM_LoadStackFile(path, buffer, bufsize);
return COM_LoadStackFile(path, buffer, bufsize, NULL);
}
int QDECL CSQC_PRFileSize (const char *path)
{
qbyte *file;
size_t sz;
if (!strcmp(path, "csprogs.dat"))
{
@ -5248,35 +5506,35 @@ int QDECL CSQC_PRFileSize (const char *path)
if (csprogs_checksum)
{
file = COM_LoadTempFile (newname);
file = COM_LoadTempFile (newname, &sz);
if (file)
{
if (cls.protocol == CP_NETQUAKE)
{
if (QCRC_Block(file, com_filesize) == csprogs_checksum)
return com_filesize+1;
if (QCRC_Block(file, sz) == csprogs_checksum)
return sz+1;
}
else
{
if (LittleLong(Com_BlockChecksum(file, com_filesize)) == csprogs_checksum) //and the user wasn't trying to be cunning.
return com_filesize+1;
if (LittleLong(Com_BlockChecksum(file, sz)) == csprogs_checksum) //and the user wasn't trying to be cunning.
return sz+1;
}
}
}
file = COM_LoadTempFile(path);
file = COM_LoadTempFile(path, &sz);
if (file && !cls.demoplayback) //allow them to use csprogs.dat if playing a demo, and don't care about the checksum
{
if (csprogs_checksum && !csprogs_promiscuous)
{
if (cls.protocol == CP_NETQUAKE)
{
if (QCRC_Block(file, com_filesize) != csprogs_checksum)
if (QCRC_Block(file, sz) != csprogs_checksum)
return -1; //not valid
}
else
{
if (LittleLong(Com_BlockChecksum(file, com_filesize)) != csprogs_checksum)
if (LittleLong(Com_BlockChecksum(file, sz)) != csprogs_checksum)
return -1; //not valid
}
}
@ -5284,7 +5542,7 @@ int QDECL CSQC_PRFileSize (const char *path)
if (!file)
return -1;
return com_filesize;
return sz;
}
return COM_FileSize(path);
@ -5318,6 +5576,44 @@ qboolean CSQC_UnconnectedInit(void)
return true;
return CSQC_Init(true, true, 0);
}
void ASMCALL CSQC_StateOp(pubprogfuncs_t *prinst, float var, func_t func)
{
world_t *w = prinst->parms->user;
stdentvars_t *vars = PROG_TO_EDICT(prinst, *w->g.self)->v;
vars->nextthink = *w->g.time+0.1;
vars->think = func;
vars->frame = var;
}
void ASMCALL CSQC_CStateOp(pubprogfuncs_t *progs, float min, float max, func_t func)
{
Con_Printf("CSQC_CStateOp: not implemented\n");
}
void ASMCALL CSQC_CWStateOp(pubprogfuncs_t *progs, float min, float max, func_t func)
{
Con_Printf("CSQC_CWStateOp: not implemented\n");
}
void ASMCALL CSQC_ThinkTimeOp(pubprogfuncs_t *progs, edict_t *ed, float var)
{
world_t *w = progs->parms->user;
stdentvars_t *vars = ed->v;
vars->nextthink = *w->g.time+var;
}
pbool PDECL CSQC_CheckHeaderCrc(pubprogfuncs_t *progs, progsnum_t num, int crc)
{
if (!num)
{
if (crc == 22390)
csqc_isdarkplaces = false;
else
{
if (crc == 52195)
csqc_isdarkplaces = true;
Con_Printf(CON_WARNING "Running outdated or unknown csprogs.dat version\n");
}
}
return true;
}
double csqctime;
qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checksum)
@ -5354,6 +5650,22 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks
if (cl_nocsqc.value)
return false;
if (cls.state == ca_disconnected)
{
movevars.gravity = 800;
movevars.entgravity = 1;
movevars.maxspeed = 320;
movevars.bunnyspeedcap = 0;//pm_bunnyspeedcap.value;
movevars.ktjump = false;//pm_ktjump.value;
movevars.slidefix = true;//(pm_slidefix.value != 0);
movevars.airstep = true;//(pm_airstep.value != 0);
movevars.walljump = false;//(pm_walljump.value);
movevars.slidyslopes = false;//(pm_slidyslopes.value!=0);
movevars.watersinkspeed = 60;//*pm_watersinkspeed.string?pm_watersinkspeed.value:60;
movevars.flyfriction = 4;//*pm_flyfriction.string?pm_flyfriction.value:4;
movevars.stepheight = PM_DEFAULTSTEPHEIGHT;
}
for (i = 0; i < sizeof(csqc_builtin)/sizeof(csqc_builtin[0]); i++)
csqc_builtin[i] = PF_Fixme;
for (i = 0; BuiltinList[i].bifunc; i++)
@ -5373,14 +5685,15 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks
csqcprogparms.Printf = PR_Printf;//Con_Printf;//void (*printf) (char *, ...);
csqcprogparms.Sys_Error = Sys_Error;
csqcprogparms.Abort = CSQC_Abort;
csqcprogparms.CheckHeaderCrc = CSQC_CheckHeaderCrc;
csqcprogparms.edictsize = sizeof(csqcedict_t);
csqcprogparms.entspawn = CSQC_EntSpawn;//void (*entspawn) (struct edict_s *ent); //ent has been spawned, but may not have all the extra variables (that may need to be set) set
csqcprogparms.entcanfree = CSQC_EntFree;//bool (*entcanfree) (struct edict_s *ent); //return true to stop ent from being freed
csqcprogparms.stateop = NULL;//StateOp;//void (*stateop) (float var, func_t func);
csqcprogparms.cstateop = NULL;//CStateOp;
csqcprogparms.cwstateop = NULL;//CWStateOp;
csqcprogparms.thinktimeop = NULL;//ThinkTimeOp;
csqcprogparms.stateop = CSQC_StateOp;//StateOp;//void (*stateop) (float var, func_t func);
csqcprogparms.cstateop = CSQC_CStateOp;//CStateOp;
csqcprogparms.cwstateop = CSQC_CWStateOp;//CWStateOp;
csqcprogparms.thinktimeop = CSQC_ThinkTimeOp;//ThinkTimeOp;
//used when loading a game
csqcprogparms.builtinsfor = NULL;//builtin_t *(*builtinsfor) (int num); //must return a pointer to the builtins that were used before the state was saved.
@ -5414,7 +5727,7 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks
csqcprogs = InitProgs(&csqcprogparms);
csqc_world.progs = csqcprogs;
csqc_world.usesolidcorpse = true;
PR_Configure(csqcprogs, pr_csqc_memsize.ival, 16, pr_enable_profiling.ival);
PR_Configure(csqcprogs, pr_csqc_memsize.ival, MAX_PROGS, pr_enable_profiling.ival);
csqc_world.worldmodel = cl.worldmodel;
csqc_world.Event_Touch = CSQC_Event_Touch;
csqc_world.Event_Think = CSQC_Event_Think;
@ -5435,25 +5748,14 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks
csqc_isdarkplaces = false;
if (csdatenabled || csqc_singlecheats || anycsqc)
{
csprogsnum = PR_LoadProgs(csqcprogs, "csprogs.dat", 22390, NULL, 0);
if (csprogsnum == -1)
{
csprogsnum = PR_LoadProgs(csqcprogs, "csprogs.dat", 52195, NULL, 0);
if (csprogsnum >= 0)
csqc_isdarkplaces = true;
else
csprogsnum = PR_LoadProgs(csqcprogs, "csprogs.dat", 0, NULL, 0);
if (csprogsnum != -1)
Con_Printf(CON_WARNING "Running outdated or unknown csprogs.dat version\n");
}
csprogsnum = PR_LoadProgs(csqcprogs, "csprogs.dat", NULL, 0);
if (csprogsnum == -1)
Con_DPrintf("Loaded csprogs.dat\n");
}
if (csqc_singlecheats || anycsqc)
{
csaddonnum = PR_LoadProgs(csqcprogs, "csaddon.dat", 0, NULL, 0);
csaddonnum = PR_LoadProgs(csqcprogs, "csaddon.dat", NULL, 0);
if (csaddonnum >= 0)
Con_DPrintf("loaded csaddon.dat...\n");
else
@ -5474,6 +5776,9 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks
PF_InitTempStrings(csqcprogs);
csqc_world.physicstime = 0;
if (!csqc_world.worldmodel)
csqc_world.worldmodel = Mod_ForName("", MLV_SILENT);
csqc_worldchanged = false;
memset(csqcent, 0, sizeof(*csqcent)*maxcsqcentities); //clear the server->csqc entity translations.
@ -5496,6 +5801,17 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks
worldent = (csqcedict_t *)EDICT_NUM(csqcprogs, 0);
worldent->isfree = false;
for (i = 0; i < csqcprogs->numprogs; i++)
{
func_t f = PR_FindFunction (csqcprogs, "initents", i);
if (f)
{
void *pr_globals = PR_globals(csqcprogs, PR_CURRENT);
G_PROG(OFS_PARM0) = i-1;
PR_ExecuteProgram(csqcprogs, f);
}
}
/*DP compat*/
str = (string_t*)csqcprogs->GetEdictFieldValue(csqcprogs, (edict_t*)worldent, "message", NULL);
if (str)
@ -5521,6 +5837,8 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks
Con_DPrintf("Loaded csqc\n");
csqcmapentitydataloaded = false;
csqc_world.physicstime = 0.1;
}
return true; //success!
@ -5544,19 +5862,14 @@ void CSQC_RendererRestarted(void)
void CSQC_WorldLoaded(void)
{
char *map;
csqcedict_t *worldent;
const char *entfile;
if (!csqcprogs)
return;
if (csqcmapentitydataloaded)
return;
csqcmapentitydataloaded = true;
map = Info_ValueForKey(cl.serverinfo, "map");
entfile = csqcmapentitydata = map?FS_LoadMallocFile(va("maps/%s.ent", map)):NULL;
if (!csqcmapentitydata)
csqcmapentitydata = cl.worldmodel->entities;
csqcmapentitydata = cl.worldmodel->entities;
csqc_world.worldmodel = cl.worldmodel;
#ifdef USEODE
@ -5572,9 +5885,10 @@ void CSQC_WorldLoaded(void)
if (csqcg.worldloaded)
PR_ExecuteProgram(csqcprogs, csqcg.worldloaded);
csqcmapentitydata = NULL;
BZ_Free((char*)entfile);
worldent->readonly = true;
csqc_worldchanged = false; //should be done elsewhere, don't do it for double-cost.
}
void CSQC_CoreDump(void)
@ -5872,13 +6186,13 @@ qboolean CSQC_DrawView(void)
}
if (host_frametime > mintic)
host_frametime = mintic;
csqc_world.physicstime += host_frametime;
#ifdef USEODE
World_ODE_Frame(&csqc_world, host_frametime, 800);
#endif
World_Physics_Frame(&csqc_world);
csqc_world.physicstime += host_frametime;
}
}
@ -6341,6 +6655,15 @@ int CSQC_StartSound(int entnum, int channel, char *soundname, vec3_t pos, float
return false;
}
void CSQC_GetEntityOrigin(unsigned int csqcent, float *out)
{
wedict_t *ent;
if (!csqcprogs)
return;
ent = WEDICT_NUM(csqcprogs, csqcent);
VectorCopy(ent->v->origin, out);
}
void CSQC_ParseEntities(void)
{
csqcedict_t *ent;
@ -6355,7 +6678,7 @@ void CSQC_ParseEntities(void)
if (!csqcg.ent_update || !csqcg.self)
Host_EndGame("CSQC has no CSQC_Ent_Update function\n");
if (!csqc_world.worldmodel || csqc_world.worldmodel->needload)
if (!csqc_world.worldmodel || csqc_world.worldmodel->loadstate != MLS_LOADED)
Host_EndGame("world is not yet initialised\n");
pr_globals = PR_globals(csqcprogs, PR_CURRENT);

View File

@ -437,7 +437,7 @@ void QCBUILTIN PF_CL_drawpic (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
mpic_t *p;
p = R2D_SafeCachePic(picname);
if (!p)
if (!p || !R_GetShaderSizes(p, NULL, NULL, false))
p = R2D_SafePicFromWad(picname);
if (!p)
@ -511,7 +511,7 @@ void QCBUILTIN PF_CL_precache_pic (pubprogfuncs_t *prinst, struct globalvars_s *
{
pic = R2D_SafeCachePic(str);
if ((!pic || (pic->flags & SHADER_NOIMAGE)) && cls.state
if ((!pic || !R_GetShaderSizes(pic, NULL, NULL, true)) && cls.state
#ifndef CLIENTONLY
&& !sv.active
#endif
@ -671,11 +671,12 @@ void QCBUILTIN PF_CL_drawgetimagesize (pubprogfuncs_t *prinst, struct globalvars
mpic_t *p = R2D_SafeCachePic(picname);
float *ret = G_VECTOR(OFS_RETURN);
if (p)
int iw, ih;
if (R_GetShaderSizes(p, &iw, &ih, true) > 0)
{
ret[0] = p->width;
ret[1] = p->height;
ret[0] = iw;
ret[1] = ih;
ret[2] = 0;
}
else
@ -814,7 +815,7 @@ void QCBUILTIN PF_SubConPrintf (pubprogfuncs_t *prinst, struct globalvars_s *pr_
if (!con)
return;
PF_sprintf_internal(prinst, pr_globals, fmt, 2, outbuf, sizeof(outbuf));
Con_PrintCon(con, outbuf);
Con_PrintCon(con, outbuf, con->parseflags);
}
void QCBUILTIN PF_SubConDraw (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
@ -2071,6 +2072,11 @@ void MP_CvarChanged(cvar_t *var)
}
}
pbool PDECL Menu_CheckHeaderCrc(pubprogfuncs_t *inst, progsnum_t idx, int crc)
{
return crc == 10020;
}
double menutime;
qboolean MP_Init (void)
{
@ -2097,6 +2103,7 @@ qboolean MP_Init (void)
menuprogparms.Printf = (void *)Con_Printf;//Con_Printf;//void (*printf) (char *, ...);
menuprogparms.Sys_Error = Sys_Error;
menuprogparms.Abort = Menu_Abort;
menuprogparms.CheckHeaderCrc = Menu_CheckHeaderCrc;
menuprogparms.edictsize = sizeof(menuedict_t);
menuprogparms.entspawn = NULL;//void (*entspawn) (struct edict_s *ent); //ent has been spawned, but may not have all the extra variables (that may need to be set) set
@ -2136,7 +2143,7 @@ qboolean MP_Init (void)
Con_DPrintf("Initializing menu.dat\n");
menu_world.progs = InitProgs(&menuprogparms);
PR_Configure(menu_world.progs, 64*1024*1024, 1, pr_enable_profiling.ival);
mprogs = PR_LoadProgs(menu_world.progs, "menu.dat", 10020, NULL, 0);
mprogs = PR_LoadProgs(menu_world.progs, "menu.dat", NULL, 0);
if (mprogs < 0) //no per-progs builtins.
{
//failed to load or something
@ -2236,10 +2243,10 @@ void MP_Reload_f(void)
static void MP_Poke_f(void)
{
if (!SV_MayCheat())
/*if (!SV_MayCheat())
Con_TPrintf ("Please set sv_cheats 1 and restart the map first.\n");
else if (svprogfuncs && svprogfuncs->EvaluateDebugString)
Con_TPrintf("Result: %s\n", svprogfuncs->EvaluateDebugString(svprogfuncs, Cmd_Args()));
else */if (menu_world.progs && menu_world.progs->EvaluateDebugString)
Con_TPrintf("Result: %s\n", menu_world.progs->EvaluateDebugString(menu_world.progs, Cmd_Args()));
else
Con_TPrintf ("not supported.\n");
}

View File

@ -256,6 +256,7 @@ extern cvar_t com_protocolname;
extern cvar_t com_modname;
extern cvar_t com_nogamedirnativecode;
extern cvar_t com_parseutf8;
extern cvar_t com_parseezquake;
extern cvar_t sys_ticrate;
extern cvar_t sys_nostdout;
extern cvar_t developer;
@ -275,6 +276,7 @@ void Host_InitCommands (void);
void Host_Init (quakeparms_t *parms);
void Host_FinishInit(void);
void Host_Shutdown(void);
qboolean com_fatalerror; //supresses shutdown prints+threads
NORETURN void VARGS Host_Error (char *error, ...) LIKEPRINTF(1);
NORETURN void VARGS Host_EndGame (char *message, ...) LIKEPRINTF(1);
qboolean Host_SimulationTime(float time);
@ -284,6 +286,36 @@ void Host_Quit_f (void);
void VARGS Host_ClientCommands (char *fmt, ...) LIKEPRINTF(1);
void Host_ShutdownServer (qboolean crash);
#ifdef LOADERTHREAD
extern cvar_t worker_flush;
qboolean COM_DoWork(int thread, qboolean leavelocked);
#define COM_MainThreadWork() while (COM_DoWork(0, false) && worker_flush.ival) /*called each frame to do any gl uploads or whatever*/
#define COM_MainThreadFlush() while (COM_DoWork(0, false)) /*make sure the main thread has done ALL work pending*/
void COM_AddWork(int thread, void(*func)(void *ctx, void *data, size_t a, size_t b), void *ctx, void *data, size_t a, size_t b);
qboolean COM_HasWork(void);
void COM_WorkerFullSync(void);
void COM_DestroyWorkerThread(void);
void COM_WorkerPartialSync(void *priorityctx, int *address, int value);
void *com_resourcemutex; //random mutex to simplify resource creation type stuff.
void COM_WorkerAbort(char *message); //calls sys_error on the main thread, if running on a worker.
#ifdef _DEBUG
void COM_AssertMainThread(const char *msg);
#else
#define COM_AssertMainThread(msg)
#endif
#else
#define COM_AddWork(t,f,a,b,c,d) (f)((a),(b),(c),(d))
#define COM_WorkerPartialSync(c,a,v)
#define COM_WorkerFullSync()
#define COM_HasWork() false
#define COM_DoWork(t,l) false
#define COM_AssertMainThread(msg)
#define COM_MainThreadWork()
#define COM_MainThreadFlush()
#define COM_DestroyWorkerThread()
#define COM_WorkerAbort(m)
#endif
extern qboolean msg_suppress_1; // suppresses resolution and cache size console output
// an fullscreen DIB focus gain/loss

View File

@ -143,7 +143,7 @@ void R2D_Init(void)
int i;
unsigned int glossval;
unsigned int normval;
extern cvar_t gl_specular_fallback;
extern cvar_t gl_specular_fallback, gl_specular_fallbackexp;
conback = NULL;
Shader_Init();
@ -166,7 +166,7 @@ void R2D_Init(void)
glossval = min(gl_specular_fallback.value*255, 255);
glossval *= 0x10101;
glossval |= 0xff000000;
glossval |= 0x01000000 * bound(0, (int)(gl_specular_fallbackexp.value*255), 255);
glossval = LittleLong(glossval);
normval = 0xffff8080;
normval = LittleLong(normval);
@ -352,8 +352,6 @@ mpic_t *R2D_SafeCachePic (const char *path)
if (!qrenderer)
return NULL;
s = R_RegisterPic(path);
if (s->flags & SHADER_NOIMAGE)
return NULL;
return s;
}
@ -367,15 +365,16 @@ mpic_t *R2D_SafePicFromWad (const char *name)
snprintf(newnamewad, sizeof(newnamewad), "wad/%s", name);
snprintf(newnamegfx, sizeof(newnamegfx), "gfx/%s", name);
/*
s = R_RegisterPic(newnamewad);
if (!(s->flags & SHADER_NOIMAGE))
return s;
*/
s = R_RegisterPic(newnamegfx);
if (!(s->flags & SHADER_NOIMAGE))
// if (!(s->flags & SHADER_NOIMAGE))
return s;
return NULL;
// return NULL;
}
@ -403,9 +402,19 @@ void R2D_ImagePaletteColour(unsigned int i, float a)
//awkward and weird to use
void R2D_Image(float x, float y, float w, float h, float s1, float t1, float s2, float t2, mpic_t *pic)
{
int i;
if (!pic)
return;
//don't draw pics if they have an image which is still loading.
for (i = 0; i < pic->numpasses; i++)
{
if (pic->passes[i].texgen == T_GEN_SINGLEMAP && pic->passes[i].anim_frames[0] && pic->passes[i].anim_frames[0]->status == TEX_LOADING)
return;
if (pic->passes[i].texgen == T_GEN_DIFFUSE && pic->defaulttextures.base && pic->defaulttextures.base->status == TEX_LOADING)
return;
}
draw_mesh_xyz[0][0] = x;
draw_mesh_xyz[0][1] = y;
draw_mesh_st[0][0] = s1;
@ -485,7 +494,7 @@ void R2D_TransPicTranslate (float x, float y, int width, int height, qbyte *pic,
if (!TEXVALID(translate_texture))
{
translate_texture = R_AllocNewTexture("***translatedpic***", 64, 64, 0);
translate_texture = Image_CreateTexture("***translatedpic***", NULL, IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA);
translate_shader = R_RegisterShader("translatedpic", SUF_2D,
"{\n"
"if $nofixed\n"
@ -502,7 +511,7 @@ void R2D_TransPicTranslate (float x, float y, int width, int height, qbyte *pic,
translate_shader->defaulttextures.base = translate_texture;
}
/* could avoid reuploading already translated textures but this func really isn't used enough anyway */
R_Upload(translate_texture, NULL, TF_RGBA32, trans, NULL, 64, 64, IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA);
Image_Upload(translate_texture, TF_RGBA32, trans, NULL, 64, 64, IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA);
R2D_ScalePic(x, y, width, height, translate_shader);
}
@ -537,7 +546,7 @@ void R2D_ConsoleBackground (int firstline, int lastline, qboolean forceopaque)
h>>=1;
w>>=1;
}
if (!conback)
if (R_GetShaderSizes(conback, NULL, NULL, false) <= 0)
{
R2D_ImageColours(0, 0, 0, a);
R2D_FillBlock(0, lastline-(int)vid.height, w, h);
@ -615,14 +624,17 @@ void R2D_Conback_Callback(struct cvar_s *var, char *oldvalue)
if (*var->string)
conback = R_RegisterPic(var->string);
if (!conback || conback->flags & SHADER_NOIMAGE)
if (!R_GetShaderSizes(conback, NULL, NULL, true))
{
conback = R_RegisterCustom("console", SUF_2D, NULL, NULL);
if (!conback || conback->flags & SHADER_NOIMAGE)
conback = R_RegisterCustom("console", SUF_2D, NULL, NULL); //quake3
if (!R_GetShaderSizes(conback, NULL, NULL, true))
{
#ifdef HEXEN2
if (M_GameType() == MGT_HEXEN2)
conback = R_RegisterPic("gfx/menu/conback.lmp");
else if (M_GameType() == MGT_QUAKE2)
else
#endif
if (M_GameType() == MGT_QUAKE2)
conback = R_RegisterPic("pics/conback.pcx");
else
conback = R_RegisterPic("gfx/conback.lmp");
@ -1187,7 +1199,7 @@ void R2D_Crosshair_Update(void)
c = c % (sizeof(crosshair_pixels) / (CS_HEIGHT*sizeof(*crosshair_pixels)));
if (!TEXVALID(ch_int_texture))
ch_int_texture = R_AllocNewTexture("***crosshair***", CS_WIDTH, CS_HEIGHT, IF_UIPIC|IF_NOMIPMAP);
ch_int_texture = Image_CreateTexture("***crosshair***", NULL, IF_UIPIC|IF_NOMIPMAP);
shader_crosshair->defaulttextures.base = ch_int_texture;
Q_memset(crossdata, 0, sizeof(crossdata));
@ -1204,7 +1216,7 @@ void R2D_Crosshair_Update(void)
}
}
R_Upload(ch_int_texture, NULL, TF_RGBA32, crossdata, NULL, CS_WIDTH, CS_HEIGHT, IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA);
Image_Upload(ch_int_texture, TF_RGBA32, crossdata, NULL, CS_WIDTH, CS_HEIGHT, IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA);
}
@ -1299,6 +1311,7 @@ void R2D_DrawCrosshair(void)
R2D_ImageColours(1, 1, 1, 1);
}
#define RT_IMAGEFLAGS IF_NOMIPMAP|IF_CLAMP|IF_LINEAR
static texid_t internalrt;
//resize a texture for a render target and specify the format of it.
//pass TF_INVALID and sizes=0 to get without configuring (shaders that hardcode an $rt1 etc).
@ -1307,14 +1320,15 @@ texid_t R2D_RT_Configure(const char *id, int width, int height, uploadfmt_t rtfm
texid_t tid;
if (!strcmp(id, "-"))
{
internalrt = tid = R_AllocNewTexture("", 0, 0, IF_NOMIPMAP);
internalrt = tid = Image_CreateTexture("", NULL, RT_IMAGEFLAGS);
}
else
{
tid = R_FindTexture(id, IF_NOMIPMAP|IF_CLAMP|IF_LINEAR);
tid = Image_FindTexture(id, NULL, RT_IMAGEFLAGS);
if (!TEXVALID(tid))
tid = R_AllocNewTexture(id, 0, 0, IF_NOMIPMAP|IF_CLAMP|IF_LINEAR);
tid = Image_CreateTexture(id, NULL, RT_IMAGEFLAGS);
}
if (rtfmt)
{
switch(rtfmt)
@ -1327,9 +1341,9 @@ texid_t R2D_RT_Configure(const char *id, int width, int height, uploadfmt_t rtfm
case 6: rtfmt = TF_DEPTH32; break;
default:rtfmt = TF_INVALID; break;
}
R_Upload(tid, id, rtfmt, NULL, NULL, width, height, IF_NOMIPMAP|IF_CLAMP|IF_LINEAR);
tid.ref->width = width;
tid.ref->height = height;
Image_Upload(tid, rtfmt, NULL, NULL, width, height, RT_IMAGEFLAGS);
tid->width = width;
tid->height = height;
}
return tid;
}
@ -1337,14 +1351,17 @@ texid_t R2D_RT_GetTexture(const char *id, unsigned int *width, unsigned int *hei
{
texid_t tid;
if (!strcmp(id, "-"))
tid = internalrt;
else
tid = R_FindTexture(id, IF_NOMIPMAP);
if (tid.ref)
{
*width = tid.ref->width;
*height = tid.ref->height;
tid = internalrt;
internalrt = r_nulltex;
}
else
tid = Image_FindTexture(id, NULL, RT_IMAGEFLAGS);
if (tid)
{
*width = tid->width;
*height = tid->height;
}
else
{

View File

@ -37,9 +37,9 @@ void R_Rockettrail_Callback(struct cvar_s *var, char *oldvalue)
for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
{
if (!mod->needload)
if (mod->loadstate == MLS_LOADED)
if (mod->flags & MF_ROCKET)
P_DefaultTrail(mod);
P_LoadedModel(mod);
}
}
@ -55,9 +55,9 @@ void R_Grenadetrail_Callback(struct cvar_s *var, char *oldvalue)
for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
{
if (!mod->needload)
if (mod->loadstate == MLS_LOADED)
if (mod->flags & MF_GRENADE)
P_DefaultTrail(mod);
P_LoadedModel(mod);
}
}
@ -219,7 +219,7 @@ qboolean TraceLineN (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal)
pe = &pmove.physents[i];
if (pe->nonsolid)
continue;
if (pe->model && !pe->model->needload)
if (pe->model && pe->model->loadstate == MLS_LOADED)
{
VectorSubtract(start, pe->origin, ts);
VectorSubtract(end, pe->origin, te);
@ -292,7 +292,7 @@ void P_EmitEffect (vec3_t pos, int type, trailstate_t **tsk)
// P_SelectableTrail: given default/opposite effects, model pointer, and a user selection cvar
// changes model to the appropriate trail effect and default trail index
void P_SelectableTrail(model_t *model, cvar_t *selection, int mdleffect, int mdlcidx, int oppeffect, int oppcidx)
static void P_SelectableTrail(int *trailid, int *trailpalidx, cvar_t *selection, int mdleffect, int mdlcidx, int oppeffect, int oppcidx)
{
int select = (int)(selection->value);
@ -301,8 +301,8 @@ void P_SelectableTrail(model_t *model, cvar_t *selection, int mdleffect, int mdl
case 0: // check for string, otherwise no trail
if (selection->string[0] == '0')
{
model->particletrail = P_INVALID;
model->traildefaultindex = -1;
*trailid = P_INVALID;
*trailpalidx = -1;
break;
}
else
@ -311,48 +311,48 @@ void P_SelectableTrail(model_t *model, cvar_t *selection, int mdleffect, int mdl
if (effect >= 0)
{
model->particletrail = effect;
model->traildefaultindex = mdlcidx;
*trailid = effect;
*trailpalidx = mdlcidx;
break;
}
}
// fall through to default (so semicheat will work properly)
case 1: // default model effect
default:
model->particletrail = mdleffect;
model->traildefaultindex = mdlcidx;
*trailid = mdleffect;
*trailpalidx = mdlcidx;
break;
case 2: // opposite effect
model->particletrail = oppeffect;
model->traildefaultindex= oppcidx;
*trailid = oppeffect;
*trailpalidx= oppcidx;
break;
case 3: // alt rocket effect
model->particletrail = P_FindParticleType("TR_ALTROCKET");
model->traildefaultindex = 107;
*trailid = P_FindParticleType("TR_ALTROCKET");
*trailpalidx = 107;
break;
case 4: // gib
model->particletrail = P_FindParticleType("TR_BLOOD");
model->traildefaultindex = 70;
*trailid = P_FindParticleType("TR_BLOOD");
*trailpalidx = 70;
break;
case 5: // zombie gib
model->particletrail = P_FindParticleType("TR_SLIGHTBLOOD");
model->traildefaultindex = 70;
*trailid = P_FindParticleType("TR_SLIGHTBLOOD");
*trailpalidx = 70;
break;
case 6: // Scrag tracer
model->particletrail = P_FindParticleType("TR_WIZSPIKE");
model->traildefaultindex = 60;
*trailid = P_FindParticleType("TR_WIZSPIKE");
*trailpalidx = 60;
break;
case 7: // Knight tracer
model->particletrail = P_FindParticleType("TR_KNIGHTSPIKE");
model->traildefaultindex = 238;
*trailid = P_FindParticleType("TR_KNIGHTSPIKE");
*trailpalidx = 238;
break;
case 8: // Vore tracer
model->particletrail = P_FindParticleType("TR_VORESPIKE");
model->traildefaultindex = 154;
*trailid = P_FindParticleType("TR_VORESPIKE");
*trailpalidx = 154;
break;
case 9: // rail trail
model->particletrail = P_FindParticleType("TE_RAILTRAIL");
model->traildefaultindex = 15;
*trailid = P_FindParticleType("TE_RAILTRAIL");
*trailpalidx = 15;
break;
}
}
@ -360,102 +360,108 @@ void P_SelectableTrail(model_t *model, cvar_t *selection, int mdleffect, int mdl
//figure out which particle trail to use for the given model, filling in its values as required.
void P_DefaultTrail (model_t *model)
void P_DefaultTrail (unsigned int modelflags, int *trailid, int *trailpalidx)
{
// TODO: EF_BRIGHTFIELD should probably be handled in here somewhere
// TODO: make trail default color into RGB values instead of indexes
if (model->engineflags & MDLF_NODEFAULTTRAIL)
return;
if (!pe)
return;
if (model->flags & MF_ROCKET)
P_SelectableTrail(model, &r_rockettrail, P_FindParticleType("TR_ROCKET"), 109, P_FindParticleType("TR_GRENADE"), 6);
else if (model->flags & MF_GRENADE)
P_SelectableTrail(model, &r_grenadetrail, P_FindParticleType("TR_GRENADE"), 6, P_FindParticleType("TR_ROCKET"), 109);
else if (model->flags & MF_GIB)
if (modelflags & MF_ROCKET)
P_SelectableTrail(trailid, trailpalidx, &r_rockettrail, P_FindParticleType("TR_ROCKET"), 109, P_FindParticleType("TR_GRENADE"), 6);
else if (modelflags & MF_GRENADE)
P_SelectableTrail(trailid, trailpalidx, &r_grenadetrail, P_FindParticleType("TR_GRENADE"), 6, P_FindParticleType("TR_ROCKET"), 109);
else if (modelflags & MF_GIB)
{
model->particletrail = P_FindParticleType("TR_BLOOD");
model->traildefaultindex = 70;
*trailid = P_FindParticleType("TR_BLOOD");
*trailpalidx = 70;
}
else if (model->flags & MF_TRACER)
else if (modelflags & MF_TRACER)
{
model->particletrail = P_FindParticleType("TR_WIZSPIKE");
model->traildefaultindex = 60;
*trailid = P_FindParticleType("TR_WIZSPIKE");
*trailpalidx = 60;
}
else if (model->flags & MF_ZOMGIB)
else if (modelflags & MF_ZOMGIB)
{
model->particletrail = P_FindParticleType("TR_SLIGHTBLOOD");
model->traildefaultindex = 70;
*trailid = P_FindParticleType("TR_SLIGHTBLOOD");
*trailpalidx = 70;
}
else if (model->flags & MF_TRACER2)
else if (modelflags & MF_TRACER2)
{
model->particletrail = P_FindParticleType("TR_KNIGHTSPIKE");
model->traildefaultindex = 238;
*trailid = P_FindParticleType("TR_KNIGHTSPIKE");
*trailpalidx = 238;
}
else if (model->flags & MF_TRACER3)
else if (modelflags & MF_TRACER3)
{
model->particletrail = P_FindParticleType("TR_VORESPIKE");
model->traildefaultindex = 154;
*trailid = P_FindParticleType("TR_VORESPIKE");
*trailpalidx = 154;
}
else if (model->flags & MFH2_BLOODSHOT) //these are the hexen2 ones.
#ifdef HEXEN2
else if (modelflags & MFH2_BLOODSHOT) //these are the hexen2 ones.
{
model->particletrail = P_FindParticleType("tr_bloodshot");
model->traildefaultindex = 136;
*trailid = P_FindParticleType("tr_bloodshot");
*trailpalidx = 136;
}
else if (model->flags & MFH2_FIREBALL)
else if (modelflags & MFH2_FIREBALL)
{
model->particletrail = P_FindParticleType("tr_fireball");
model->traildefaultindex = 424;
*trailid = P_FindParticleType("tr_fireball");
*trailpalidx = 424;
}
else if (model->flags & MFH2_ACIDBALL)
else if (modelflags & MFH2_ACIDBALL)
{
model->particletrail = P_FindParticleType("tr_acidball");
model->traildefaultindex = 440;
*trailid = P_FindParticleType("tr_acidball");
*trailpalidx = 440;
}
else if (model->flags & MFH2_ICE)
else if (modelflags & MFH2_ICE)
{
model->particletrail = P_FindParticleType("tr_ice");
model->traildefaultindex = 408;
*trailid = P_FindParticleType("tr_ice");
*trailpalidx = 408;
}
else if (model->flags & MFH2_SPIT)
else if (modelflags & MFH2_SPIT)
{
model->particletrail = P_FindParticleType("tr_spit");
model->traildefaultindex = 260;
*trailid = P_FindParticleType("tr_spit");
*trailpalidx = 260;
}
else if (model->flags & MFH2_SPELL)
else if (modelflags & MFH2_SPELL)
{
model->particletrail = P_FindParticleType("tr_spell");
model->traildefaultindex = 260;
*trailid = P_FindParticleType("tr_spell");
*trailpalidx = 260;
}
else if (model->flags & MFH2_VORP_MISSILE)
else if (modelflags & MFH2_VORP_MISSILE)
{
model->particletrail = P_FindParticleType("tr_vorpmissile");
model->traildefaultindex = 302;
*trailid = P_FindParticleType("tr_vorpmissile");
*trailpalidx = 302;
}
else if (model->flags & MFH2_SET_STAFF)
else if (modelflags & MFH2_SET_STAFF)
{
model->particletrail = P_FindParticleType("tr_setstaff");
model->traildefaultindex = 424;
*trailid = P_FindParticleType("tr_setstaff");
*trailpalidx = 424;
}
else if (model->flags & MFH2_MAGICMISSILE)
else if (modelflags & MFH2_MAGICMISSILE)
{
model->particletrail = P_FindParticleType("tr_magicmissile");
model->traildefaultindex = 149;
*trailid = P_FindParticleType("tr_magicmissile");
*trailpalidx = 149;
}
else if (model->flags & MFH2_BONESHARD)
else if (modelflags & MFH2_BONESHARD)
{
model->particletrail = P_FindParticleType("tr_boneshard");
model->traildefaultindex = 384;
*trailid = P_FindParticleType("tr_boneshard");
*trailpalidx = 384;
}
else if (model->flags & MFH2_SCARAB)
else if (modelflags & MFH2_SCARAB)
{
model->particletrail = P_FindParticleType("tr_scarab");
model->traildefaultindex = 254;
*trailid = P_FindParticleType("tr_scarab");
*trailpalidx = 254;
}
else if (modelflags & MFH2_ROCKET)
{
//spiders
*trailid = P_FindParticleType("TR_GREENBLOOD");
*trailpalidx = 70; //fixme
}
#endif
else
{
model->particletrail = P_INVALID;
model->traildefaultindex = -1;
*trailid = P_INVALID;
*trailpalidx = -1;
}
}

View File

@ -3,6 +3,7 @@ WARNING: THIS FILE IS GENERATED BY 'generatebuiltin.c'.
YOU SHOULD NOT EDIT THIS FILE BY HAND
*/
#include "bothdefs.h"
#include "r_partset.h"
@ -1593,14 +1594,30 @@ char *particle_set_high =
//r_effect "progs/s_explod.spr" hidden 1
//////////////////////////////////////////
//for when a spawn dies.
//also used by TF for emp explosions.
//r_part te_tarexplosion
//{
//}
//////////////////////////////////////////
//r_part te_lavasplash
//{
//}
//cthon falling into lava.
//often also used for TF gas grenades.
"r_part te_lavasplash\n"
"{\n"
"texture \"particles/fteparticlefont.tga\"\n"
"tcoords 129 1 191 63 256\n"
"count 654\n"
"scale 15\n"
"alpha 0.7\n"
"die 4\n"
"randomvel 64\n"
"rgb 255 128 128\n"
"gravity 50\n"
"blend add\n"
"spawnorg 192 64\n"
"up 48\n"
"}\n"
//////////////////////////////////////////
//FIXME: what if we don't have glsl support?
@ -2083,6 +2100,7 @@ char *particle_set_minimal =
//////////////////////////////////////////////////////
#ifdef HEXEN2
char *particle_set_h2part =
//hexen2-compatible particle config
//for the purposes of faithfulness, I'm using uhexen2 (with gl_missile_glows etc set to 0) as a baseline.
@ -2340,6 +2358,10 @@ char *particle_set_h2part =
"rgbrand 0 0 0\n"
"gravity 200\n"
"scalefactor 0.4\n"
"lighttime 0\n"
"lightshadows 1\n"
"lightradius 100 120\n"
"lightrgb 0.50 1.00 0.25\n"
"}\n"
//fixme:test
@ -2381,6 +2403,11 @@ char *particle_set_h2part =
"rgbrand 0 0 0\n"
"gravity 0\n"
"scalefactor 0.3\n"
"lighttime 0\n"
"lightshadows 1\n"
"lightradius 100 120\n"
"lightrgb -2.00 -1.00 -0.25\n"
"}\n"
//famine missiles
"r_part tr_spell\n"
@ -2473,6 +2500,10 @@ char *particle_set_h2part =
"blend add\n"
"scalefactor 1\n"
"scaledelta -15\n"
"lighttime 0\n"
"lightshadows 1\n"
"lightradius 100 120\n"
"lightrgb 2.00 1.00 0.25\n"
"}\n"
"r_part +tr_fireball\n"
"{\n"
@ -3204,13 +3235,16 @@ char *particle_set_h2part =
//h2part.ce_grey_smoke_100 was not loaded
//h2part.ce_chunk_fire was not loaded
;
#endif
//////////////////////////////////////////////////////
#ifdef Q2CLIENT
char *particle_set_q2part =
"r_part namespace q2part\n"
"r_part pe_default\n"
"{\n"
@ -3370,6 +3404,7 @@ char *particle_set_q2part =
"colorindex 0 15\n"
"}\n"
;
#endif

View File

@ -1,9 +1,30 @@
/*
WARNING: THIS FILE IS GENERATED BY 'generatebuiltin.c'.
YOU SHOULD NOT EDIT THIS FILE BY HAND
*/
extern char *particle_set_spikeset;
#define R_PARTSET_BUILTINS_spikeset {"spikeset", &particle_set_spikeset},
extern char *particle_set_faithful;
#define R_PARTSET_BUILTINS_faithful {"faithful", &particle_set_faithful},
extern char *particle_set_highfps;
#define R_PARTSET_BUILTINS_highfps {"highfps", &particle_set_highfps},
extern char *particle_set_high;
#define R_PARTSET_BUILTINS_high {"high", &particle_set_high},
extern char *particle_set_minimal;
#define R_PARTSET_BUILTINS_minimal {"minimal", &particle_set_minimal},
#ifdef HEXEN2
extern char *particle_set_h2part;
#define R_PARTSET_BUILTINS_h2part {"h2part", &particle_set_h2part},
#else
#define R_PARTSET_BUILTINS_h2part
#endif
#ifdef Q2CLIENT
extern char *particle_set_q2part;
#define R_PARTSET_BUILTINS_q2part {"q2part", &particle_set_q2part},
#else
#define R_PARTSET_BUILTINS_q2part
#endif
extern char *particle_set_tsshaft;
#define R_PARTSET_BUILTINS {"spikeset", &particle_set_spikeset},{"faithful", &particle_set_faithful},{"highfps", &particle_set_highfps},{"high", &particle_set_high},{"minimal", &particle_set_minimal},{"h2part", &particle_set_h2part},{"q2part", &particle_set_q2part},{"tsshaft", &particle_set_tsshaft},
#define R_PARTSET_BUILTINS_tsshaft {"tsshaft", &particle_set_tsshaft},
#define R_PARTSET_BUILTINS R_PARTSET_BUILTINS_spikeset R_PARTSET_BUILTINS_faithful R_PARTSET_BUILTINS_highfps R_PARTSET_BUILTINS_high R_PARTSET_BUILTINS_minimal R_PARTSET_BUILTINS_h2part R_PARTSET_BUILTINS_q2part R_PARTSET_BUILTINS_tsshaft

View File

@ -197,7 +197,7 @@ void Surf_AddStain(vec3_t org, float red, float green, float blue, float radius)
int i;
float parms[7];
if (!cl.worldmodel || cl.worldmodel->needload || r_stains.value <= 0)
if (!cl.worldmodel || cl.worldmodel->loadstate != MLS_LOADED || r_stains.value <= 0)
return;
parms[0] = radius;
parms[1] = org[0];
@ -210,12 +210,12 @@ void Surf_AddStain(vec3_t org, float red, float green, float blue, float radius)
cl.worldmodel->funcs.StainNode(cl.worldmodel->rootnode, parms);
//now stain bsp models other than world.
//now stain inline bsp models other than world.
for (i=1 ; i< pmove.numphysent ; i++) //0 is world...
{
pe = &pmove.physents[i];
if (pe->model && pe->model->surfaces == cl.worldmodel->surfaces && !pe->model->needload)
if (pe->model && pe->model->surfaces == cl.worldmodel->surfaces && pe->model->loadstate == MLS_LOADED)
{
parms[1] = org[0] - pe->origin[0];
parms[2] = org[1] - pe->origin[1];
@ -1190,7 +1190,7 @@ void Surf_RenderDynamicLightmaps (msurface_t *fa)
lightmapinfo_t *lm, *dlm;
//surfaces without lightmaps
if (fa->lightmaptexturenums[0]<0)
if (fa->lightmaptexturenums[0]<0 || !lightmap)
return;
// check for lightmap modification
@ -2005,7 +2005,7 @@ void Surf_SetupFrame(void)
if (r_refdef.flags & RDF_NOWORLDMODEL)
{
}
else if (!cl.worldmodel || cl.worldmodel->needload || cl.worldmodel->fromgame == fg_doom3 )
else if (!cl.worldmodel || cl.worldmodel->loadstate != MLS_LOADED || cl.worldmodel->fromgame == fg_doom3 )
{
r_viewleaf = NULL;
r_viewleaf2 = NULL;
@ -2292,7 +2292,7 @@ void Surf_DrawWorld (void)
BE_DrawWorld(false, NULL);
return;
}
if (!cl.worldmodel || cl.worldmodel->needload)
if (!cl.worldmodel || cl.worldmodel->loadstate != MLS_LOADED)
{
/*Don't act as a wallhack*/
return;
@ -2602,8 +2602,10 @@ int Surf_NewExternalLightmaps(int count, char *filepattern, qboolean deluxe)
Q_snprintfz(nname, sizeof(nname), filepattern, i - numlightmaps);
TEXASSIGN(lightmap[i]->lightmap_texture, R_LoadHiResTexture(nname, NULL, 0));
lightmap[i]->width = image_width;
lightmap[i]->height = image_height;
if (lightmap[i]->lightmap_texture->status == TEX_LOADING)
COM_WorkerPartialSync(lightmap[i]->lightmap_texture, &lightmap[i]->lightmap_texture->status, TEX_LOADING);
lightmap[i]->width = lightmap[i]->lightmap_texture->width;
lightmap[i]->height = lightmap[i]->lightmap_texture->height;
}
if (odd)
@ -2636,6 +2638,7 @@ void Surf_BuildModelLightmaps (model_t *m)
return;
#ifdef TERRAIN
//easiest way to deal with heightmap lightmaps is to just purge the entire thing.
if (m->terrain)
Terr_PurgeTerrainModel(m, true, false);
#endif
@ -2645,7 +2648,7 @@ void Surf_BuildModelLightmaps (model_t *m)
if (!m->lightmaps.count)
return;
if (m->needload)
if (m->loadstate != MLS_LOADED)
return;
currentmodel = m;
@ -2653,7 +2656,7 @@ void Surf_BuildModelLightmaps (model_t *m)
if (*m->name == '*' && m->fromgame == fg_quake3) //FIXME: should be all bsp formats
{
if (!cl.model_precache[1] || cl.model_precache[1]->needload)
if (!cl.model_precache[1] || cl.model_precache[1]->loadstate != MLS_LOADED)
return;
newfirst = cl.model_precache[1]->lightmaps.first;
}
@ -2752,11 +2755,11 @@ void Surf_BuildModelLightmaps (model_t *m)
lightmapinfo_t *lm, *dlm;
qbyte *deluxemap;
if (*m->name == '*')
{
if (!cl.worldmodel || cl.worldmodel->needload)
return;
}
// if (*m->name == '*')
// {
// if (!cl.worldmodel || cl.worldmodel->loadstate != MLS_LOADED)
// return;
// }
//fixup surface lightmaps, and paint
for (i=0; i<m->nummodelsurfaces; i++)
{
@ -2809,6 +2812,9 @@ void Surf_BuildLightmaps (void)
int i, j;
model_t *m;
extern model_t *mod_known;
extern int mod_numknown;
r_framecount = 1; // no dlightcache
for (i = 0; i < numlightmaps; i++)
@ -2832,7 +2838,7 @@ void Surf_BuildLightmaps (void)
m = cl.model_precache[j];
if (!m)
break;
if (m->needload)
if (m->loadstate != MLS_LOADED)
continue;
Surf_BuildModelLightmaps(m);
}
@ -2845,4 +2851,102 @@ void Surf_BuildLightmaps (void)
}
BE_UploadAllLightmaps();
}
/*
===============
Surf_NewMap
===============
*/
void Surf_NewMap (void)
{
char namebuf[MAX_QPATH];
extern cvar_t host_mapname;
int i;
for (i=0 ; i<256 ; i++)
d_lightstylevalue[i] = 264; // normal light value
memset (&r_worldentity, 0, sizeof(r_worldentity));
AngleVectors(r_worldentity.angles, r_worldentity.axis[0], r_worldentity.axis[1], r_worldentity.axis[2]);
VectorInverse(r_worldentity.axis[1]);
r_worldentity.model = cl.worldmodel;
Vector4Set(r_worldentity.shaderRGBAf, 1, 1, 1, 1);
VectorSet(r_worldentity.light_avg, 1, 1, 1);
if (cl.worldmodel)
COM_StripExtension(COM_SkipPath(cl.worldmodel->name), namebuf, sizeof(namebuf));
else
*namebuf = '\0';
Cvar_Set(&host_mapname, namebuf);
Surf_DeInit();
r_viewleaf = NULL;
r_oldviewleaf = NULL;
r_viewcluster = -1;
r_oldviewcluster = 0;
r_viewcluster2 = -1;
if (cl.worldmodel)
{
if (cl.worldmodel->loadstate == MLS_LOADING)
COM_WorkerPartialSync(cl.worldmodel, &cl.worldmodel->loadstate, MLS_LOADING);
Mod_ParseInfoFromEntityLump(cl.worldmodel, cl.worldmodel->entities, cl.worldmodel->name);
}
if (!pe)
Cvar_ForceCallback(&r_particlesystem);
TRACE(("dbg: Surf_NewMap: clear particles\n"));
P_ClearParticles ();
TRACE(("dbg: Surf_NewMap: wiping them stains (getting the cloth out)\n"));
Surf_WipeStains();
CL_RegisterParticles();
TRACE(("dbg: Surf_NewMap: building lightmaps\n"));
Surf_BuildLightmaps ();
TRACE(("dbg: Surf_NewMap: ui\n"));
#ifdef VM_UI
UI_Reset();
#endif
TRACE(("dbg: Surf_NewMap: tp\n"));
TP_NewMap();
R_SetSky(cl.skyname);
#ifdef MAP_PROC
if (cl.worldmodel->fromgame == fg_doom3)
D3_GenerateAreas(cl.worldmodel);
#endif
for (i = 0; i < cl.num_statics; i++)
{
vec3_t mins, maxs;
//fixme: no rotation
VectorAdd(cl_static_entities[i].ent.origin, cl_static_entities[i].ent.model->mins, mins);
VectorAdd(cl_static_entities[i].ent.origin, cl_static_entities[i].ent.model->maxs, maxs);
cl.worldmodel->funcs.FindTouchedLeafs(cl.worldmodel, &cl_static_entities[i].pvscache, mins, maxs);
cl_static_entities[i].emit = NULL;
}
#ifdef RTLIGHTS
Sh_PreGenerateLights();
#endif
}
void Surf_PreNewMap(void)
{
r_loadbumpmapping = r_deluxemapping.ival || r_glsl_offsetmapping.ival;
#ifdef RTLIGHTS
r_loadbumpmapping |= r_shadow_realtime_world.ival || r_shadow_realtime_dlight.ival;
#endif
r_viewleaf = NULL;
r_oldviewleaf = NULL;
r_viewleaf2 = NULL;
r_oldviewleaf2 = NULL;
}
#endif

View File

@ -35,7 +35,7 @@ struct model_s;
struct texnums_s;
struct texture_s;
static const texid_t r_nulltex = {{0}};
static const texid_t r_nulltex = NULL;
#if 1 || defined(MINIMAL) || defined(D3DQUAKE) || defined(ANDROID)
@ -280,6 +280,8 @@ void R_DrawSkyChain (struct batch_s *batch); /*called from the backend, and call
void R_InitSky (struct texnums_s *ret, struct texture_s *mt, qbyte *src); /*generate q1 sky texnums*/
//r_surf.c
void Surf_NewMap (void);
void Surf_PreNewMap(void);
void Surf_SetupFrame(void); //determine pvs+viewcontents
void Surf_DrawWorld(void);
void Surf_GenBrushBatches(struct batch_s **batches, entity_t *ent);
@ -335,9 +337,6 @@ void GLR_RenderView (void); // must set r_refdef first
// called whenever r_refdef or vid change
void GLR_DrawPortal(struct batch_s *batch, struct batch_s **blist, struct batch_s *depthmasklist[2], int portaltype);
void GLR_PreNewMap(void);
void GLR_NewMap (void);
void GLR_PushDlights (void);
void GLR_DrawWaterSurfaces (void);
@ -352,67 +351,62 @@ void R_RenderDlights (void);
enum imageflags
{
/*warning: many of these flags only apply the first time it is requested*/
IF_CLAMP = 1<<0,
IF_NEAREST = 1<<1,
IF_NOPICMIP = 1<<2,
IF_NOMIPMAP = 1<<3,
IF_NOALPHA = 1<<4,
IF_NOGAMMA = 1<<5,
IF_3DMAP = 1<<6, /*waning - don't test directly*/
IF_CUBEMAP = 1<<7, /*waning - don't test directly*/
IF_CUBEMAPEXTRA = 1<<8,
IF_TEXTYPE = (1<<6) | (1<<7) | (1<<8), /*0=2d, 1=3d, 2-7=cubeface*/
IF_TEXTYPESHIFT = 6, /*0=2d, 1=3d, 2-7=cubeface*/
IF_MIPCAP = 1<<9,
IF_UIPIC = 1<<10, //subject to texturemode2d
IF_LINEAR = 1<<11,
IF_PREMULTIPLYALPHA = 1<<12, //rgb *= alpha
IF_CLAMP = 1<<0, //disable texture coord wrapping.
IF_NOMIPMAP = 1<<1, //disable mipmaps.
IF_NEAREST = 1<<2, //force nearest
IF_LINEAR = 1<<3, //force linear
IF_UIPIC = 1<<4, //subject to texturemode2d
/*WARNING: If the above are changed, be sure to change shader pass flags*/
IF_NOPICMIP = 1<<5,
IF_NOALPHA = 1<<6,
IF_NOGAMMA = 1<<7,
IF_3DMAP = 1<<8, /*waning - don't test directly*/
IF_CUBEMAP = 1<<9, /*waning - don't test directly*/
IF_TEXTYPE = (1<<8) | (1<<9), /*0=2d, 1=3d, 2=cubeface, 3=?*/
IF_TEXTYPESHIFT = 8, /*0=2d, 1=3d, 2-7=cubeface*/
IF_MIPCAP = 1<<10,
IF_PREMULTIPLYALPHA = 1<<12, //rgb *= alpha
IF_NOPCX = 1<<26, /*block pcx format. meaning qw skins can use team colours and cropping*/
IF_TRYBUMP = 1<<27, /*attempt to load _bump if the specified _norm texture wasn't found*/
IF_RENDERTARGET = 1<<28, /*never loaded from disk, loading can't fail*/
IF_EXACTEXTENSION = 1<<29,
IF_REPLACE = 1<<30,
IF_SUBDIRONLY = 1<<31
IF_EXACTEXTENSION = 1<<29, /*don't mangle extensions, use what is specified and ONLY that*/
IF_NOREPLACE = 1<<30, /*don't load a replacement, for some reason*/
IF_NOWORKER = 1u<<31 /*don't pass the work to a loader thread. this gives synchronous loading.*/
};
#define R_LoadTexture8(id,w,h,d,f,t) R_LoadTexture(id,w,h,t?TF_TRANS8:TF_SOLID8,d,f)
#define R_LoadTexture32(id,w,h,d,f) R_LoadTexture(id,w,h,TF_RGBA32,d,f)
#define R_LoadTextureFB(id,w,h,d,f) R_LoadTexture(id,w,h,TF_TRANS8_FULLBRIGHT,d,f)
#define R_LoadTexture8BumpPal(id,w,h,d,f) R_LoadTexture(id,w,h,TF_HEIGHT8PAL,d,f)
#define R_LoadTexture8Bump(id,w,h,d,f) R_LoadTexture(id,w,h,TF_HEIGHT8,d,f)
#define R_LoadTexture8(id,w,h,d,f,t) Image_GetTexture(id, NULL, f, d, NULL, w, h, t?TF_TRANS8:TF_SOLID8)
#define R_LoadTexture32(id,w,h,d,f) Image_GetTexture(id, NULL, f, d, NULL, w, h, TF_RGBA32)
#define R_LoadTextureFB(id,w,h,d,f) Image_GetTexture(id, NULL, f, d, NULL, w, h, TF_TRANS8_FULLBRIGHT)
#define R_LoadTexture(id,w,h,fmt,d,fl) Image_GetTexture(id, NULL, fl, d, NULL, w, h, fmt)
/*it seems a little excessive to have to include glquake (and windows headers), just to load some textures/shaders for the backend*/
#ifdef GLQUAKE
texid_tf GL_AllocNewTexture(const char *name, int w, int h, unsigned int flags);
void GL_UploadFmt(texid_t tex, const char *name, enum uploadfmt fmt, void *data, void *palette, int width, int height, unsigned int flags);
texid_tf GL_LoadTextureFmt (const char *identifier, int width, int height, enum uploadfmt fmt, void *data, unsigned int flags);
void GL_DestroyTexture(texid_t tex);
image_t *Image_FindTexture (const char *identifier, const char *subpath, unsigned int flags);
image_t *Image_CreateTexture(const char *identifier, const char *subpath, unsigned int flags);
image_t *Image_GetTexture (const char *identifier, const char *subpath, unsigned int flags, void *fallbackdata, void *fallbackpalette, int fallbackwidth, int fallbackheight, uploadfmt_t fallbackfmt);
void Image_Upload (texid_t tex, uploadfmt_t fmt, void *data, void *palette, int width, int height, unsigned int flags);
void Image_Init(void);
void Image_Shutdown(void);
image_t *Image_LoadTexture (const char *identifier, int width, int height, uploadfmt_t fmt, void *data, unsigned int flags);
#define R_DestroyTexture(id) //FIXME
#ifdef D3D9QUAKE
void D3D9_UpdateFiltering (image_t *imagelist, int filtermip[3], int filterpic[3], int mipcap[2], float anis);
qboolean D3D9_LoadTextureMips (texid_t tex, struct pendingtextureinfo *mips);
void D3D9_DestroyTexture (texid_t tex);
#endif
#ifdef D3DQUAKE
texid_t D3D9_LoadTexture (const char *identifier, int width, int height, enum uploadfmt fmt, void *data, unsigned int flags);
texid_t D3D9_LoadTexture8Pal24 (const char *identifier, int width, int height, qbyte *data, qbyte *palette24, unsigned int flags);
texid_t D3D9_LoadTexture8Pal32 (const char *identifier, int width, int height, qbyte *data, qbyte *palette32, unsigned int flags);
texid_t D3D9_LoadCompressed (const char *name);
texid_t D3D9_FindTexture (const char *identifier, unsigned int flags);
texid_t D3D9_AllocNewTexture(const char *ident, int width, int height, unsigned int flags);
void D3D9_Upload (texid_t tex, const char *name, enum uploadfmt fmt, void *data, void *palette, int width, int height, unsigned int flags);
void D3D9_DestroyTexture (texid_t tex);
void D3D9_Image_Shutdown(void);
texid_t D3D11_LoadTexture (const char *identifier, int width, int height, enum uploadfmt fmt, void *data, unsigned int flags);
texid_t D3D11_LoadTexture8Pal24 (const char *identifier, int width, int height, qbyte *data, qbyte *palette24, unsigned int flags);
texid_t D3D11_LoadTexture8Pal32 (const char *identifier, int width, int height, qbyte *data, qbyte *palette32, unsigned int flags);
texid_t D3D11_LoadCompressed (const char *name);
texid_t D3D11_FindTexture (const char *identifier, unsigned int flags);
texid_t D3D11_AllocNewTexture(const char *ident, int width, int height, unsigned int flags);
void D3D11_Upload (texid_t tex, const char *name, enum uploadfmt fmt, void *data, void *palette, int width, int height, unsigned int flags);
void D3D11_DestroyTexture (texid_t tex);
void D3D11_Image_Shutdown(void);
#ifdef D3D11QUAKE
void D3D11_UpdateFiltering (image_t *imagelist, int filtermip[3], int filterpic[3], int mipcap[2], float anis);
qboolean D3D11_LoadTextureMips (texid_t tex, struct pendingtextureinfo *mips);
void D3D11_DestroyTexture (texid_t tex);
#endif
extern int image_width, image_height;
texid_tf R_LoadReplacementTexture(const char *name, const char *subpath, unsigned int flags);
//extern int image_width, image_height;
texid_t R_LoadReplacementTexture(const char *name, const char *subpath, unsigned int flags, void *lowres, int lowreswidth, int lowresheight, uploadfmt_t fmt);
texid_tf R_LoadHiResTexture(const char *name, const char *subpath, unsigned int flags);
texid_tf R_LoadBumpmapTexture(const char *name, const char *subpath);
void R_LoadNumberedLightTexture(struct dlight_s *dl, int cubetexnum);
qbyte *Read32BitImageFile(qbyte *buf, int len, int *width, int *height, qboolean *hasalpha, char *fname);
@ -445,7 +439,7 @@ void Mod_RebuildLightmaps (void);
struct mleaf_s *Mod_PointInLeaf (struct model_s *model, float *p);
void Mod_Think (void);
void Mod_NowLoadExternal(void);
void Mod_NowLoadExternal(struct model_s *loadmodel);
void GLR_LoadSkys (void);
void R_BloomRegister(void);
@ -453,6 +447,7 @@ int Mod_RegisterModelFormatText(void *module, const char *formatname, char *magi
int Mod_RegisterModelFormatMagic(void *module, const char *formatname, unsigned int magic, qboolean (QDECL *load) (struct model_s *mod, void *buffer, size_t fsize));
void Mod_UnRegisterModelFormat(void *module, int idx);
void Mod_UnRegisterAllModelFormats(void *module);
void Mod_ModelLoaded(void *ctx, void *data, size_t a, size_t b);
#ifdef RUNTIMELIGHTING
void LightFace (int surfnum);
@ -532,7 +527,7 @@ extern cvar_t r_shadow_realtime_dlight, r_shadow_realtime_dlight_shadows;
extern cvar_t r_shadow_realtime_dlight_ambient;
extern cvar_t r_shadow_realtime_dlight_diffuse;
extern cvar_t r_shadow_realtime_dlight_specular;
extern cvar_t r_shadow_realtime_world, r_shadow_realtime_world_shadows;
extern cvar_t r_shadow_realtime_world, r_shadow_realtime_world_shadows, r_shadow_realtime_world_lightmaps;
extern cvar_t r_shadow_shadowmapping;
extern cvar_t r_editlights_import_radius;
extern cvar_t r_editlights_import_ambient;

View File

@ -36,12 +36,7 @@ extern int gl_anisotropy_factor;
// callbacks used for cvars
void SCR_Viewsize_Callback (struct cvar_s *var, char *oldvalue);
void SCR_Fov_Callback (struct cvar_s *var, char *oldvalue);
#if defined(GLQUAKE)
void GL_Mipcap_Callback (struct cvar_s *var, char *oldvalue);
void GL_Texturemode_Callback (struct cvar_s *var, char *oldvalue);
void GL_Texturemode2d_Callback (struct cvar_s *var, char *oldvalue);
void GL_Texture_Anisotropic_Filtering_Callback (struct cvar_s *var, char *oldvalue);
#endif
void Image_TextureMode_Callback (struct cvar_s *var, char *oldvalue);
cvar_t vid_vsync = CVARAF ("vid_wait", "0",
"vid_vsync", CVAR_ARCHIVE);
@ -325,23 +320,22 @@ cvar_t gl_maxdist = CVARD ("gl_maxdist", "8192", "The distance of the far
#ifdef SPECULAR
cvar_t gl_specular = CVARF ("gl_specular", "1", CVAR_ARCHIVE);
cvar_t gl_specular_fallback = CVARF ("gl_specular_fallback", "0.05", CVAR_ARCHIVE|CVAR_RENDERERLATCH);
cvar_t gl_specular_fallbackexp = CVARF ("gl_specular_fallbackexp", "1", CVAR_ARCHIVE|CVAR_RENDERERLATCH);
#endif
// The callbacks are not in D3D yet (also ugly way of seperating this)
#ifdef GLQUAKE
cvar_t gl_texture_anisotropic_filtering = CVARFC("gl_texture_anisotropic_filtering", "0",
CVAR_ARCHIVE | CVAR_RENDERERCALLBACK,
GL_Texture_Anisotropic_Filtering_Callback);
cvar_t gl_texturemode = CVARFC("gl_texturemode", "GL_LINEAR_MIPMAP_NEAREST",
Image_TextureMode_Callback);
cvar_t gl_texturemode = CVARFDC("gl_texturemode", "GL_LINEAR_MIPMAP_NEAREST",
CVAR_ARCHIVE | CVAR_RENDERERCALLBACK | CVAR_SAVE,
GL_Texturemode_Callback);
"Specifies how world/model textures appear. Typically 3 letters eg lln.\nFirst letter can be l(inear) or n(earest) and says how to sample from the mip (when downsampling).\nThe middle letter can . to disable mipmaps, or l or n to describe whether to blend between mipmaps.\nThe third letter says what to do when the texture is too low resolution and is thus the most noticable with low resolution textures, a n will make it look like lego, while an l will keep it smooth.", Image_TextureMode_Callback);
cvar_t gl_mipcap = CVARFC("d_mipcap", "0 1000",
CVAR_ARCHIVE | CVAR_RENDERERCALLBACK,
GL_Mipcap_Callback);
cvar_t gl_texturemode2d = CVARFC("gl_texturemode2d", "GL_LINEAR",
Image_TextureMode_Callback);
cvar_t gl_texturemode2d = CVARFDC("gl_texturemode2d", "GL_LINEAR",
CVAR_ARCHIVE | CVAR_RENDERERCALLBACK,
GL_Texturemode2d_Callback);
#endif
"Specifies how 2d images are sampled. format is a 3-tupple ", Image_TextureMode_Callback);
cvar_t vid_triplebuffer = CVARAFD ("vid_triplebuffer", "1", "gl_triplebuffer", CVAR_ARCHIVE, "Specifies whether the hardware is forcing tripplebuffering on us, this is the number of extra page swaps required before old data has been completely overwritten.");
@ -453,10 +447,6 @@ void GLRenderer_Init(void)
Cvar_Register (&gl_picmip2d, GLRENDEREROPTIONS);
Cvar_Register (&r_shaderblobs, GLRENDEREROPTIONS);
Cvar_Register (&gl_mipcap, GLRENDEREROPTIONS);
Cvar_Register (&gl_texturemode, GLRENDEREROPTIONS);
Cvar_Register (&gl_texturemode2d, GLRENDEREROPTIONS);
Cvar_Register (&gl_texture_anisotropic_filtering, GLRENDEREROPTIONS);
Cvar_Register (&gl_savecompressedtex, GLRENDEREROPTIONS);
Cvar_Register (&gl_compress, GLRENDEREROPTIONS);
// Cvar_Register (&gl_detail, GRAPHICALNICETIES);
@ -640,6 +630,7 @@ void Renderer_Init(void)
Cvar_Register (&r_flashblendscale, GRAPHICALNICETIES);
Cvar_Register (&gl_specular, GRAPHICALNICETIES);
Cvar_Register (&gl_specular_fallback, GRAPHICALNICETIES);
Cvar_Register (&gl_specular_fallbackexp, GRAPHICALNICETIES);
Sh_RegisterCvars();
@ -715,6 +706,10 @@ void Renderer_Init(void)
Cvar_Register (&gl_max_size, GLRENDEREROPTIONS);
Cvar_Register (&gl_maxdist, GLRENDEREROPTIONS);
Cvar_Register (&gl_miptexLevel, GRAPHICALNICETIES);
Cvar_Register (&gl_texturemode, GLRENDEREROPTIONS);
Cvar_Register (&gl_texturemode2d, GLRENDEREROPTIONS);
Cvar_Register (&gl_mipcap, GLRENDEREROPTIONS);
Cvar_Register (&gl_texture_anisotropic_filtering, GLRENDEREROPTIONS);
Cvar_Register (&r_drawflat, GRAPHICALNICETIES);
Cvar_Register (&r_menutint, GRAPHICALNICETIES);
@ -776,9 +771,6 @@ void (*R_Init) (void);
void (*R_DeInit) (void);
void (*R_RenderView) (void); // must set r_refdef first
void (*R_NewMap) (void);
void (*R_PreNewMap) (void);
qboolean (*VID_Init) (rendererstate_t *info, unsigned char *palette);
void (*VID_DeInit) (void);
char *(*VID_GetRGBInfo) (int prepad, int *truevidwidth, int *truevidheight);
@ -805,22 +797,14 @@ rendererinfo_t dedicatedrendererinfo = {
NULL, //Draw_Init;
NULL, //Draw_Shutdown;
NULL, //R_LoadTexture
NULL, //R_LoadTexture8Pal24
NULL, //R_LoadTexture8Pal32
NULL, //R_LoadCompressed
NULL, //R_FindTexture
NULL, //R_AllocNewTexture
NULL, //R_Upload
NULL, //R_DestroyTexture
NULL, //IMG_UpdateFiltering
NULL, //IMG_LoadTextureMips
NULL, //IMG_DestroyTexture
NULL, //R_Init;
NULL, //R_DeInit;
NULL, //R_RenderView;
NULL, //R_NewMap;
NULL, //R_PreNewMap
NULL, //VID_Init,
NULL, //VID_DeInit,
NULL, //VID_SwapBuffers
@ -915,8 +899,6 @@ void R_SetRenderer(rendererinfo_t *ri)
R_Init = ri->R_Init;
R_DeInit = ri->R_DeInit;
R_RenderView = ri->R_RenderView;
R_NewMap = ri->R_NewMap;
R_PreNewMap = ri->R_PreNewMap;
VID_Init = ri->VID_Init;
VID_DeInit = ri->VID_DeInit;
@ -951,6 +933,9 @@ void D3DSucks(void)
void R_ShutdownRenderer(qboolean videotoo)
{
//make sure the worker isn't still loading stuff
COM_WorkerFullSync();
CL_AllowIndependantSendCmd(false); //FIXME: figure out exactly which parts are going to affect the model loading.
P_Shutdown();
@ -1010,12 +995,17 @@ void R_GenPaletteLookup(void)
qboolean R_ApplyRenderer (rendererstate_t *newr)
{
double time;
if (newr->bpp == -1)
return false;
if (!newr->renderer)
return false;
time = Sys_DoubleTime();
M_Shutdown(false);
Media_CaptureDemoEnd();
R_ShutdownRenderer(true);
Con_DPrintf("video shutdown took %f seconds\n", Sys_DoubleTime() - time);
if (qrenderer == QR_NONE)
{
@ -1025,17 +1015,19 @@ qboolean R_ApplyRenderer (rendererstate_t *newr)
Sys_CloseTerminal ();
}
time = Sys_DoubleTime();
R_SetRenderer(newr->renderer);
Con_DPrintf("video startup took %f seconds\n", Sys_DoubleTime() - time);
return R_ApplyRenderer_Load(newr);
}
qboolean R_ApplyRenderer_Load (rendererstate_t *newr)
{
int i, j;
extern model_t *loadmodel;
double start = Sys_DoubleTime();
Cache_Flush();
COM_FlushFSCache(); //make sure the fs cache is built if needed. there's lots of loading here.
COM_FlushFSCache(false, true); //make sure the fs cache is built if needed. there's lots of loading here.
TRACE(("dbg: R_ApplyRenderer: old renderer closed\n"));
@ -1043,6 +1035,7 @@ qboolean R_ApplyRenderer_Load (rendererstate_t *newr)
if (qrenderer != QR_NONE) //graphics stuff only when not dedicated
{
size_t sz;
qbyte *data;
#ifndef CLIENTONLY
isDedicated = false;
@ -1052,15 +1045,17 @@ qboolean R_ApplyRenderer_Load (rendererstate_t *newr)
if (host_basepal)
BZ_Free(host_basepal);
host_basepal = (qbyte *)FS_LoadMallocFile ("gfx/palette.lmp");
if (!host_basepal)
host_basepal = (qbyte *)FS_LoadMallocFile ("wad/playpal");
host_basepal = (qbyte *)FS_LoadMallocFile ("gfx/palette.lmp", &sz);
if (!host_basepal)
host_basepal = (qbyte *)FS_LoadMallocFile ("wad/playpal", &sz);
if (!host_basepal || sz != 768)
{
qbyte *pcx=NULL;
if (host_basepal)
Z_Free(host_basepal);
host_basepal = BZ_Malloc(768);
pcx = COM_LoadTempFile("pics/colormap.pcx");
if (!pcx || !ReadPCXPalette(pcx, com_filesize, host_basepal))
pcx = COM_LoadTempFile("pics/colormap.pcx", &sz);
if (!pcx || !ReadPCXPalette(pcx, sz, host_basepal))
{
memcpy(host_basepal, default_quakepal, 768);
}
@ -1072,7 +1067,7 @@ qboolean R_ApplyRenderer_Load (rendererstate_t *newr)
}
{
qbyte *colormap = (qbyte *)FS_LoadMallocFile ("gfx/colormap.lmp");
qbyte *colormap = (qbyte *)FS_LoadMallocFile ("gfx/colormap.lmp", NULL);
if (!colormap)
{
vid.fullbright=0;
@ -1096,7 +1091,7 @@ qboolean R_ApplyRenderer_Load (rendererstate_t *newr)
#ifdef HEXEN2
if (h2playertranslations)
BZ_Free(h2playertranslations);
h2playertranslations = FS_LoadMallocFile ("gfx/player.lmp");
h2playertranslations = FS_LoadMallocFile ("gfx/player.lmp", NULL);
#endif
if (vid.fullbright < 2)
@ -1116,6 +1111,7 @@ TRACE(("dbg: R_ApplyRenderer: vid applied\n"));
W_LoadWadFile("gfx.wad");
TRACE(("dbg: R_ApplyRenderer: wad loaded\n"));
Image_Init();
Draw_Init();
TRACE(("dbg: R_ApplyRenderer: draw inited\n"));
R_Init();
@ -1156,12 +1152,9 @@ TRACE(("dbg: R_ApplyRenderer: initing mods\n"));
// host_hunklevel = Hunk_LowMark();
if (R_PreNewMap)
if (cl.worldmodel)
{
TRACE(("dbg: R_ApplyRenderer: R_PreNewMap (how handy)\n"));
R_PreNewMap();
}
TRACE(("dbg: R_ApplyRenderer: R_PreNewMap (how handy)\n"));
Surf_PreNewMap();
#ifndef CLIENTONLY
if (sv.world.worldmodel)
@ -1172,27 +1165,28 @@ TRACE(("dbg: R_ApplyRenderer: initing mods\n"));
#endif
TRACE(("dbg: R_ApplyRenderer: reloading server map\n"));
sv.world.worldmodel = Mod_ForName (sv.modelname, MLV_WARN);
sv.world.worldmodel = Mod_ForName (sv.modelname, MLV_ERROR);
TRACE(("dbg: R_ApplyRenderer: loaded\n"));
if (sv.world.worldmodel->loadstate == MLS_LOADING)
COM_WorkerPartialSync(sv.world.worldmodel, &sv.world.worldmodel->loadstate, MLS_LOADING);
TRACE(("dbg: R_ApplyRenderer: doing that funky phs thang\n"));
SV_CalcPHS ();
TRACE(("dbg: R_ApplyRenderer: clearing world\n"));
World_ClearWorld (&sv.world);
if (sv.world.worldmodel->needload)
if (sv.world.worldmodel->loadstate != MLS_LOADED)
SV_UnspawnServer();
else if (svs.gametype == GT_PROGS)
{
for (i = 0; i < MAX_PRECACHE_MODELS; i++)
{
if (sv.strings.model_precache[i] && *sv.strings.model_precache[i] && (!strcmp(sv.strings.model_precache[i] + strlen(sv.strings.model_precache[i]) - 4, ".bsp") || i-1 < sv.world.worldmodel->numsubmodels))
sv.models[i] = Mod_FindName(sv.strings.model_precache[i]);
sv.models[i] = Mod_FindName(Mod_FixName(sv.strings.model_precache[i], sv.strings.model_precache[1]));
else
sv.models[i] = NULL;
}
World_ClearWorld (&sv.world);
ent = sv.world.edicts;
// ent->v->model = PR_NewString(svprogfuncs, sv.worldmodel->name); //FIXME: is this a problem for normal ents?
for (i=0 ; i<sv.world.num_edicts ; i++)
@ -1216,11 +1210,12 @@ TRACE(("dbg: R_ApplyRenderer: clearing world\n"));
for (i = 0; i < MAX_PRECACHE_MODELS; i++)
{
if (sv.strings.configstring[Q2CS_MODELS+i] && *sv.strings.configstring[Q2CS_MODELS+i] && (!strcmp(sv.strings.configstring[Q2CS_MODELS+i] + strlen(sv.strings.configstring[Q2CS_MODELS+i]) - 4, ".bsp") || i-1 < sv.world.worldmodel->numsubmodels))
sv.models[i] = Mod_FindName(sv.strings.configstring[Q2CS_MODELS+i]);
sv.models[i] = Mod_FindName(Mod_FixName(sv.strings.configstring[Q2CS_MODELS+i], sv.modelname));
else
sv.models[i] = NULL;
}
World_ClearWorld (&sv.world);
q2ent = ge->edicts;
for (i=0 ; i<ge->num_edicts ; i++, q2ent = (q2edict_t *)((char *)q2ent + ge->edict_size))
{
@ -1240,6 +1235,8 @@ TRACE(("dbg: R_ApplyRenderer: clearing world\n"));
#ifdef Q3SERVER
else if (svs.gametype == GT_QUAKE3)
{
memset(&sv.models, 0, sizeof(sv.models));
sv.models[1] = Mod_FindName(sv.modelname);
//traditionally a q3 server can just keep hold of its world cmodel and nothing is harmed.
//this means we just need to reload the worldmodel and all is fine...
//there are some edge cases however, like lingering pointers refering to entities.
@ -1261,13 +1258,17 @@ TRACE(("dbg: R_ApplyRenderer: starting on client state\n"));
if (newr)
memcpy(&currentrendererstate, newr, sizeof(currentrendererstate));
TRACE(("dbg: R_ApplyRenderer: S_Restart_f\n"));
if (!isDedicated)
S_DoRestart();
#ifdef Q3SERVER
if (svs.gametype == GT_QUAKE3)
{
CG_Stop();
CG_Start();
if (cl.worldmodel)
R_NewMap();
Surf_NewMap();
}
else
#endif
@ -1290,7 +1291,10 @@ TRACE(("dbg: R_ApplyRenderer: reloading ALL models\n"));
cl.model_precache[i] = NULL;
else
#endif
cl.model_precache[i] = Mod_ForName (cl.model_name[i], MLV_SILENT);
if (i == 1)
cl.model_precache[i] = Mod_ForName (cl.model_name[i], MLV_SILENT);
else
cl.model_precache[i] = Mod_FindName (Mod_FixName(cl.model_name[i], cl.model_name[1]));
if ((!cl.model_precache[i] || cl.model_precache[i]->type == mod_dummy) && i == 1)
{
@ -1322,7 +1326,7 @@ TRACE(("dbg: R_ApplyRenderer: reloading ALL models\n"));
cl.model_csqcprecache[i] = NULL;
TRACE(("dbg: R_ApplyRenderer: reloading csqc model %s\n", cl.model_csqcname[i]));
cl.model_csqcprecache[i] = Mod_ForName (cl.model_csqcname[i], MLV_SILENT);
cl.model_csqcprecache[i] = Mod_ForName (Mod_FixName(cl.model_csqcname[i], cl.model_name[1]), MLV_SILENT);
if (!cl.model_csqcprecache[i])
{
@ -1339,23 +1343,26 @@ TRACE(("dbg: R_ApplyRenderer: reloading ALL models\n"));
}
#endif
loadmodel = cl.worldmodel = cl.model_precache[1];
cl.worldmodel = cl.model_precache[1];
if (cl.worldmodel && cl.worldmodel->loadstate == MLS_LOADING)
COM_WorkerPartialSync(cl.worldmodel, &cl.worldmodel->loadstate, MLS_LOADING);
TRACE(("dbg: R_ApplyRenderer: done the models\n"));
if (loadmodel->needload)
if (!cl.worldmodel || cl.worldmodel->loadstate != MLS_LOADED)
{
CL_Disconnect ();
#ifdef VM_UI
UI_Reset();
#endif
memcpy(&currentrendererstate, newr, sizeof(currentrendererstate));
if (newr)
memcpy(&currentrendererstate, newr, sizeof(currentrendererstate));
return true;
}
TRACE(("dbg: R_ApplyRenderer: checking any wad textures\n"));
Mod_NowLoadExternal();
TRACE(("dbg: R_ApplyRenderer: R_NewMap\n"));
R_NewMap();
TRACE(("dbg: R_ApplyRenderer: efrags\n"));
Mod_NowLoadExternal(cl.worldmodel);
for (i = 0; i < cl.num_statics; i++) //make the static entities reappear.
{
cl_static_entities[i].ent.model = NULL;
@ -1371,6 +1378,10 @@ TRACE(("dbg: R_ApplyRenderer: efrags\n"));
}
}
TRACE(("dbg: R_ApplyRenderer: Surf_NewMap\n"));
Surf_NewMap();
TRACE(("dbg: R_ApplyRenderer: efrags\n"));
Skin_FlushAll();
#ifdef CSQC_DAT
@ -1389,18 +1400,18 @@ TRACE(("dbg: R_ApplyRenderer: efrags\n"));
Con_TPrintf("%s renderer initialized\n", newr->renderer->description);
}
TRACE(("dbg: R_ApplyRenderer: S_Restart_f\n"));
if (!isDedicated)
S_DoRestart();
TRACE(("dbg: R_ApplyRenderer: done\n"));
Con_DPrintf("video restart took %f seconds\n", Sys_DoubleTime() - start);
return true;
}
void R_ReloadRenderer_f (void)
{
float time = Sys_DoubleTime();
R_ShutdownRenderer(false);
Con_DPrintf("teardown = %f\n", Sys_DoubleTime() - time);
//reloads textures without destroying video context.
R_ApplyRenderer_Load(NULL);
}
@ -1477,7 +1488,7 @@ qboolean R_BuildRenderstate(rendererstate_t *newr, char *rendererstring)
int dbpp, dheight, dwidth, drate;
extern qboolean isPlugin;
if ((!newr->fullscreen && !vid_desktopsettings.value && !isPlugin) || !Sys_GetDesktopParameters(&dwidth, &dheight, &dbpp, &drate))
if ((!newr->fullscreen && !isPlugin) || (!vid_desktopsettings.value && !isPlugin) || !Sys_GetDesktopParameters(&dwidth, &dheight, &dbpp, &drate))
{
// force default values for systems not supporting desktop parameters
dwidth = DEFAULT_WIDTH;
@ -1526,9 +1537,6 @@ void R_RestartRenderer (rendererstate_t *newr)
return;
}
M_Shutdown(false);
Media_CaptureDemoEnd();
TRACE(("dbg: R_RestartRenderer_f renderer %i\n", newr.renderer));
memcpy(&oldr, &currentrendererstate, sizeof(rendererstate_t));
@ -1598,6 +1606,7 @@ void R_RestartRenderer (rendererstate_t *newr)
void R_RestartRenderer_f (void)
{
double time;
rendererstate_t newr;
Cvar_ApplyLatches(CVAR_RENDERERLATCH);
@ -1610,7 +1619,11 @@ void R_RestartRenderer_f (void)
return;
}
time = Sys_DoubleTime();
R_RestartRenderer(&newr);
Con_DPrintf("main thread video restart took %f secs\n", Sys_DoubleTime() - time);
// COM_WorkerFullSync();
// Con_Printf("full video restart took %f secs\n", Sys_DoubleTime() - time);
}
void R_SetRenderer_f (void)
@ -2487,7 +2500,7 @@ void R_InitParticleTexture (void)
}
}
TEXASSIGN(particletexture, R_LoadTexture32("", 8, 8, data, IF_NOMIPMAP|IF_NOPICMIP));
TEXASSIGN(particletexture, R_LoadTexture32("dotparticle", 8, 8, data, IF_NOMIPMAP|IF_NOPICMIP));
//
@ -2574,7 +2587,7 @@ void R_InitParticleTexture (void)
data[y*PARTICLETEXTURESIZE+x][3] = (qbyte) d;
}
}
beamtexture = R_LoadTexture32("", PARTICLETEXTURESIZE, PARTICLETEXTURESIZE, data, IF_NOMIPMAP|IF_NOPICMIP);
beamtexture = R_LoadTexture32("beamparticle", PARTICLETEXTURESIZE, PARTICLETEXTURESIZE, data, IF_NOMIPMAP|IF_NOPICMIP);
for (y = 0;y < PARTICLETEXTURESIZE;y++)
{
@ -2592,6 +2605,6 @@ void R_InitParticleTexture (void)
data[y*PARTICLETEXTURESIZE+x][3] = (qbyte) d/2;
}
}
ptritexture = R_LoadTexture32("", PARTICLETEXTURESIZE, PARTICLETEXTURESIZE, data, IF_NOMIPMAP|IF_NOPICMIP);
ptritexture = R_LoadTexture32("ptritexture", PARTICLETEXTURESIZE, PARTICLETEXTURESIZE, data, IF_NOMIPMAP|IF_NOPICMIP);
}

View File

@ -5,6 +5,7 @@
#define IDC_STATIC -1
#define IDI_ICON1 1
#define IDI_ICON2 2
#define IDI_ICON3 3
// Next default values for new objects
//

View File

@ -22,7 +22,7 @@ typedef struct {
typedef struct {
vfsfile_t *fp;
unsigned int maxpos; //addition for pack files. all seeks add this, all tells subtract this.
qofs_t maxpos; //addition for pack files. all seeks add this, all tells subtract this.
int buf_size;
unsigned char *buf;
roq_cell cells[256];

View File

@ -307,7 +307,6 @@ vfsfile_t *fp;
roq_info *ri;
int i;
// if (COM_FOpenFile(fname, &fp)==-1)
if((fp = FS_OpenVFS(fname, "rb", FS_GAME)) == NULL)
{
return NULL;
@ -321,9 +320,7 @@ int i;
memset(ri, 0, sizeof(roq_info));
com_filesize = VFS_GETLEN(fp);
ri->maxpos = VFS_TELL(fp)+com_filesize;//no adds/subracts for fileoffset here
ri->maxpos = VFS_TELL(fp)+VFS_GETLEN(fp);//no adds/subracts for fileoffset here
ri->fp = fp;
if(roq_parse_file(fp, ri))

View File

@ -255,6 +255,7 @@ static void SCR_DrawField (float x, float y, int color, float width, int value)
int l;
int frame;
mpic_t *p;
int pw,ph;
if (width < 1)
return;
@ -278,8 +279,8 @@ static void SCR_DrawField (float x, float y, int color, float width, int value)
frame = *ptr -'0';
p = Sbar_Q2CachePic(q2sb_nums[color][frame]);
if (p)
R2D_ScalePic (x,y,p->width, p->height, p);
if (p && R_GetShaderSizes(p, &pw, &ph, false)>0)
R2D_ScalePic (x,y,pw, ph, p);
x += CHAR_WIDTH;
ptr++;
l--;
@ -311,6 +312,7 @@ void Sbar_ExecuteLayoutString (char *s)
int value;
int width;
int index;
int pw, ph;
// q2clientinfo_t *ci;
mpic_t *p;
@ -342,7 +344,7 @@ void Sbar_ExecuteLayoutString (char *s)
if (!strcmp(com_token, "xv"))
{
s = COM_Parse (s);
x = sbar_rect.x + sbar_rect.width/2 - 160 + atoi(com_token);
x = sbar_rect.x + (sbar_rect.width-320)/2 + atoi(com_token);
continue;
}
@ -361,7 +363,7 @@ void Sbar_ExecuteLayoutString (char *s)
if (!strcmp(com_token, "yv"))
{
s = COM_Parse (s);
y = sbar_rect.y + sbar_rect.height/2 - 120 + atoi(com_token);
y = sbar_rect.y + (sbar_rect.height-240)/2 + atoi(com_token);
continue;
}
@ -376,8 +378,8 @@ void Sbar_ExecuteLayoutString (char *s)
// SCR_AddDirtyPoint (x, y);
// SCR_AddDirtyPoint (x+23, y+23);
p = Sbar_Q2CachePic(Get_Q2ConfigString(Q2CS_IMAGES+value));
if (p)
R2D_ScalePic (x, y, p->width, p->height, p);
if (p && R_GetShaderSizes(p, &pw, &ph, false)>0)
R2D_ScalePic (x, y, pw, ph, p);
}
continue;
}
@ -414,7 +416,7 @@ void Sbar_ExecuteLayoutString (char *s)
Draw_FunString (x+32, y+24, va("Time: %i", time));
p = R2D_SafeCachePic(va("players/%s_i.pcx", cl.players[value].qwskin->name));
if (!p) //display a default if the icon couldn't be found.
if (!p || !R_GetShaderSizes(p, NULL, NULL, false)) //display a default if the icon couldn't be found.
p = R2D_SafeCachePic("players/male/grunt_i.pcx");
R2D_ScalePic (x, y, 32, 32, p);
continue;
@ -460,8 +462,8 @@ void Sbar_ExecuteLayoutString (char *s)
// SCR_AddDirtyPoint (x, y);
// SCR_AddDirtyPoint (x+23, y+23);
p = Sbar_Q2CachePic(com_token);
if (p)
R2D_ScalePic (x, y, p->width, p->height, p);
if (p && R_GetShaderSizes(p, &pw, &ph, false)>0)
R2D_ScalePic (x, y, pw, ph, p);
continue;
}
@ -491,8 +493,8 @@ void Sbar_ExecuteLayoutString (char *s)
if (cl.q2frame.playerstate.stats[Q2STAT_FLASHES] & 1)
{
p = Sbar_Q2CachePic("field_3");
if (p)
R2D_ScalePic (x, y, p->width, p->height, p);
if (p && R_GetShaderSizes(p, &pw, &ph, false)>0)
R2D_ScalePic (x, y, pw, ph, p);
}
SCR_DrawField (x, y, color, width, value);
@ -515,8 +517,8 @@ void Sbar_ExecuteLayoutString (char *s)
if (cl.q2frame.playerstate.stats[Q2STAT_FLASHES] & 4)
{
p = Sbar_Q2CachePic("field_3");
if (p)
R2D_ScalePic (x, y, p->width, p->height, p);
if (p && R_GetShaderSizes(p, &pw, &ph, false)>0)
R2D_ScalePic (x, y, pw, ph, p);
}
SCR_DrawField (x, y, color, width, value);
@ -791,7 +793,6 @@ Sbar_Init
static qboolean sbar_loaded;
static qboolean failedpic;
mpic_t *Sbar_PicFromWad(char *name)
{
mpic_t *ret;
@ -802,7 +803,6 @@ mpic_t *Sbar_PicFromWad(char *name)
if (ret)
return ret;
failedpic = true;
return NULL;
}
void Sbar_Flush (void)
@ -817,14 +817,13 @@ void Sbar_Start (void) //if one of these fails, skip the entire status bar.
sbar_loaded = true;
COM_FlushFSCache(false, true); //make sure the fs cache is built if needed. there's lots of loading here.
if (!wad_base) //the wad isn't loaded. This is an indication that it doesn't exist.
{
sbarfailed = true;
return;
}
failedpic = false;
COM_FlushFSCache(); //make sure the fs cache is built if needed. there's lots of loading here.
sbarfailed = false;
@ -835,8 +834,10 @@ void Sbar_Start (void) //if one of these fails, skip the entire status bar.
}
#ifdef HEXEN2
if (sb_nums[0][0] && sb_nums[0][0]->width < 13)
if (W_SafeGetLumpName("tinyfont"))
sbar_hexen2 = true;
// if (sb_nums[0][0] && sb_nums[0][0]->width < 13)
// sbar_hexen2 = true;
#endif
sb_nums[0][10] = Sbar_PicFromWad ("num_minus");
@ -909,66 +910,57 @@ void Sbar_Start (void) //if one of these fails, skip the entire status bar.
sb_face_invis_invuln = Sbar_PicFromWad ("face_inv2");
sb_face_quad = Sbar_PicFromWad ("face_quad");
sb_sbar = Sbar_PicFromWad ("sbar");
sb_ibar = Sbar_PicFromWad ("ibar");
sb_sbar = Sbar_PicFromWad ("sbar");
sb_scorebar = Sbar_PicFromWad ("scorebar");
if (failedpic)
sbarfailed = true;
//try to detect rogue wads, and thus the stats we will be getting from the server.
failedpic = false;
rsb_invbar[0] = Sbar_PicFromWad ("r_invbar1");
rsb_invbar[1] = Sbar_PicFromWad ("r_invbar2");
rsb_weapons[0] = Sbar_PicFromWad ("r_lava");
rsb_weapons[1] = Sbar_PicFromWad ("r_superlava");
rsb_weapons[2] = Sbar_PicFromWad ("r_gren");
rsb_weapons[3] = Sbar_PicFromWad ("r_multirock");
rsb_weapons[4] = Sbar_PicFromWad ("r_plasma");
rsb_items[0] = Sbar_PicFromWad ("r_shield1");
rsb_items[1] = Sbar_PicFromWad ("r_agrav1");
rsb_teambord = Sbar_PicFromWad ("r_teambord");
rsb_ammo[0] = Sbar_PicFromWad ("r_ammolava");
rsb_ammo[1] = Sbar_PicFromWad ("r_ammomulti");
rsb_ammo[2] = Sbar_PicFromWad ("r_ammoplasma");
if (!failedpic || COM_CheckParm("-rogue"))
sbar_rogue = true;
else
sbar_rogue = false;
//try to detect hipnotic wads, and thus the stats we will be getting from the server.
failedpic = false;
hsb_weapons[0][0] = Sbar_PicFromWad ("inv_laser");
hsb_weapons[0][1] = Sbar_PicFromWad ("inv_mjolnir");
hsb_weapons[0][2] = Sbar_PicFromWad ("inv_gren_prox");
hsb_weapons[0][3] = Sbar_PicFromWad ("inv_prox_gren");
hsb_weapons[0][4] = Sbar_PicFromWad ("inv_prox");
hsb_weapons[1][0] = Sbar_PicFromWad ("inv2_laser");
hsb_weapons[1][1] = Sbar_PicFromWad ("inv2_mjolnir");
hsb_weapons[1][2] = Sbar_PicFromWad ("inv2_gren_prox");
hsb_weapons[1][3] = Sbar_PicFromWad ("inv2_prox_gren");
hsb_weapons[1][4] = Sbar_PicFromWad ("inv2_prox");
for (i=0 ; i<5 ; i++)
sbar_rogue = COM_CheckParm("-rogue") || !!W_SafeGetLumpName("r_lava");
if (sbar_rogue)
{
hsb_weapons[2+i][0] = Sbar_PicFromWad (va("inva%i_laser",i+1));
hsb_weapons[2+i][1] = Sbar_PicFromWad (va("inva%i_mjolnir",i+1));
hsb_weapons[2+i][2] = Sbar_PicFromWad (va("inva%i_gren_prox",i+1));
hsb_weapons[2+i][3] = Sbar_PicFromWad (va("inva%i_prox_gren",i+1));
hsb_weapons[2+i][4] = Sbar_PicFromWad (va("inva%i_prox",i+1));
}
hsb_items[0] = Sbar_PicFromWad ("sb_wsuit");
hsb_items[1] = Sbar_PicFromWad ("sb_eshld");
rsb_invbar[0] = Sbar_PicFromWad ("r_invbar1");
rsb_invbar[1] = Sbar_PicFromWad ("r_invbar2");
if (!failedpic || COM_CheckParm("-hipnotic"))
sbar_hipnotic = true;
else
sbar_hipnotic = false;
rsb_weapons[0] = Sbar_PicFromWad ("r_lava");
rsb_weapons[1] = Sbar_PicFromWad ("r_superlava");
rsb_weapons[2] = Sbar_PicFromWad ("r_gren");
rsb_weapons[3] = Sbar_PicFromWad ("r_multirock");
rsb_weapons[4] = Sbar_PicFromWad ("r_plasma");
rsb_items[0] = Sbar_PicFromWad ("r_shield1");
rsb_items[1] = Sbar_PicFromWad ("r_agrav1");
rsb_teambord = Sbar_PicFromWad ("r_teambord");
rsb_ammo[0] = Sbar_PicFromWad ("r_ammolava");
rsb_ammo[1] = Sbar_PicFromWad ("r_ammomulti");
rsb_ammo[2] = Sbar_PicFromWad ("r_ammoplasma");
}
sbar_hipnotic = COM_CheckParm("-hipnotic") || !!W_SafeGetLumpName("inv_mjolnir");
if (sbar_hipnotic)
{
hsb_weapons[0][0] = Sbar_PicFromWad ("inv_laser");
hsb_weapons[0][1] = Sbar_PicFromWad ("inv_mjolnir");
hsb_weapons[0][2] = Sbar_PicFromWad ("inv_gren_prox");
hsb_weapons[0][3] = Sbar_PicFromWad ("inv_prox_gren");
hsb_weapons[0][4] = Sbar_PicFromWad ("inv_prox");
hsb_weapons[1][0] = Sbar_PicFromWad ("inv2_laser");
hsb_weapons[1][1] = Sbar_PicFromWad ("inv2_mjolnir");
hsb_weapons[1][2] = Sbar_PicFromWad ("inv2_gren_prox");
hsb_weapons[1][3] = Sbar_PicFromWad ("inv2_prox_gren");
hsb_weapons[1][4] = Sbar_PicFromWad ("inv2_prox");
for (i=0 ; i<5 ; i++)
{
hsb_weapons[2+i][0] = Sbar_PicFromWad (va("inva%i_laser",i+1));
hsb_weapons[2+i][1] = Sbar_PicFromWad (va("inva%i_mjolnir",i+1));
hsb_weapons[2+i][2] = Sbar_PicFromWad (va("inva%i_gren_prox",i+1));
hsb_weapons[2+i][3] = Sbar_PicFromWad (va("inva%i_prox_gren",i+1));
hsb_weapons[2+i][4] = Sbar_PicFromWad (va("inva%i_prox",i+1));
}
hsb_items[0] = Sbar_PicFromWad ("sb_wsuit");
hsb_items[1] = Sbar_PicFromWad ("sb_eshld");
}
}
void Sbar_Init (void)
@ -1065,7 +1057,7 @@ void Draw_TinyString (float x, float y, const qbyte *str)
if (!font_tiny)
{
font_tiny = Font_LoadFont(6, "gfx/tinyfont");
font_tiny = Font_LoadFont(8, "gfx/tinyfont");
if (!font_tiny)
return;
}
@ -1090,6 +1082,18 @@ void Sbar_DrawTinyString (float x, float y, char *str)
{
Draw_TinyString (sbar_rect.x + x /*+ ((sbar_rect.width - 320)>>1) */, sbar_rect.y + y+ sbar_rect.height-SBAR_HEIGHT, str);
}
void Sbar_DrawTinyStringf (float x, float y, char *fmt, ...)
{
va_list argptr;
char string[256];
va_start (argptr, fmt);
vsnprintf (string, sizeof(string)-1, fmt, argptr);
va_end (argptr);
Draw_TinyString (sbar_rect.x + x /*+ ((sbar_rect.width - 320)>>1) */, sbar_rect.y + y+ sbar_rect.height-SBAR_HEIGHT, string);
}
void Sbar_FillPC (float x, float y, float w, float h, unsigned int pcolour)
{
@ -2210,26 +2214,26 @@ static void Sbar_Hexen2DrawExtra (playerview_t *pv)
Sbar_DrawTinyString (11, 48, pclassname[pclass]);
Sbar_DrawTinyString (11, 58, va("int"));
Sbar_DrawTinyString (33, 58, va("%02d", pv->stats[STAT_H2_INTELLIGENCE]));
Sbar_DrawTinyString (11, 58, "int");
Sbar_DrawTinyStringf (33, 58, "%02d", pv->stats[STAT_H2_INTELLIGENCE]);
Sbar_DrawTinyString (11, 64, va("wis"));
Sbar_DrawTinyString (33, 64, va("%02d", pv->stats[STAT_H2_WISDOM]));
Sbar_DrawTinyString (11, 64, "wis");
Sbar_DrawTinyStringf (33, 64, "%02d", pv->stats[STAT_H2_WISDOM]);
Sbar_DrawTinyString (11, 70, va("dex"));
Sbar_DrawTinyString (33, 70, va("%02d", pv->stats[STAT_H2_DEXTERITY]));
Sbar_DrawTinyString (11, 70, "dex");
Sbar_DrawTinyStringf (33, 70, "%02d", pv->stats[STAT_H2_DEXTERITY]);
Sbar_DrawTinyString (58, 58, va("str"));
Sbar_DrawTinyString (80, 58, va("%02d", pv->stats[STAT_H2_STRENGTH]));
Sbar_DrawTinyString (58, 58, "str");
Sbar_DrawTinyStringf (80, 58, "%02d", pv->stats[STAT_H2_STRENGTH]);
Sbar_DrawTinyString (58, 64, va("lvl"));
Sbar_DrawTinyString (80, 64, va("%02d", pv->stats[STAT_H2_LEVEL]));
Sbar_DrawTinyString (58, 64, "lvl");
Sbar_DrawTinyStringf (80, 64, "%02d", pv->stats[STAT_H2_LEVEL]);
Sbar_DrawTinyString (58, 70, va("exp"));
Sbar_DrawTinyString (80, 70, va("%06d", pv->stats[STAT_H2_EXPERIENCE]));
Sbar_DrawTinyString (58, 70, "exp");
Sbar_DrawTinyStringf (80, 70, "%06d", pv->stats[STAT_H2_EXPERIENCE]);
Sbar_DrawTinyString (11, 79, va("abilities"));
Sbar_DrawTinyString (11, 79, "abilities");
if (pv->stats[STAT_H2_FLAGS] & (1<<22))
Sbar_DrawTinyString (8, 89, T_GetString(400 + 2*(pclass-1) + 0));
if (pv->stats[STAT_H2_FLAGS] & (1<<23))
@ -2240,7 +2244,7 @@ static void Sbar_Hexen2DrawExtra (playerview_t *pv)
if (pv->stats[STAT_H2_ARMOUR1+i] > 0)
{
Sbar_DrawPic (164+i*40, 115, 28, 19, R2D_SafeCachePic(va("gfx/armor%d.lmp", i+1)));
Sbar_DrawTinyString (168+i*40, 136, va("+%d", pv->stats[STAT_H2_ARMOUR1+i]));
Sbar_DrawTinyStringf (168+i*40, 136, "+%d", pv->stats[STAT_H2_ARMOUR1+i]);
}
}
for (i = 0; i < 4; i++)
@ -2261,7 +2265,7 @@ static void Sbar_Hexen2DrawExtra (playerview_t *pv)
slot = 0;
for (i = 0; i < 8; i++)
{
if (pv->statsstr[STAT_H2_PUZZLE1+i])
if (pv->statsstr[STAT_H2_PUZZLE1+i] && *pv->statsstr[STAT_H2_PUZZLE1+i])
{
Sbar_DrawPic (194+(slot%4)*31, slot<4?51:82, 26, 26, R2D_SafeCachePic(va("gfx/puzzle/%s.lmp", pv->statsstr[STAT_H2_PUZZLE1+i])));
slot++;
@ -2319,7 +2323,7 @@ static void Sbar_Hexen2DrawBasic(playerview_t *pv)
maxval = pv->stats[STAT_H2_MAXMANA];
val = pv->stats[STAT_H2_BLUEMANA];
val = bound(0, val, maxval);
Sbar_DrawTinyString(201, 22, va("%03d", val));
Sbar_DrawTinyStringf(201, 22, "%03d", val);
if(val)
{
Sbar_DrawPic(190, 26-(int)((val*18.0)/(float)maxval+0.5), 3, 19, R2D_SafeCachePic("gfx/bmana.lmp"));
@ -2330,7 +2334,7 @@ static void Sbar_Hexen2DrawBasic(playerview_t *pv)
maxval = pv->stats[STAT_H2_MAXMANA];
val = pv->stats[STAT_H2_GREENMANA];
val = bound(0, val, maxval);
Sbar_DrawTinyString(243, 22, va("%03d", val));
Sbar_DrawTinyStringf(243, 22, "%03d", val);
if(val)
{
Sbar_DrawPic(232, 26-(int)((val*18.0)/(float)maxval+0.5), 3, 19, R2D_SafeCachePic("gfx/gmana.lmp"));
@ -2368,8 +2372,8 @@ static void Sbar_Hexen2DrawMinimal(playerview_t *pv)
Sbar_DrawPic(3, y, 31, 17, R2D_SafeCachePic("gfx/bmmana.lmp"));
Sbar_DrawPic(3, y+18, 31, 17, R2D_SafeCachePic("gfx/gmmana.lmp"));
Sbar_DrawTinyString(10, y+6, va("%03d", pv->stats[STAT_H2_BLUEMANA]));
Sbar_DrawTinyString(10, y+18+6, va("%03d", pv->stats[STAT_H2_GREENMANA]));
Sbar_DrawTinyStringf(10, y+6, "%03d", pv->stats[STAT_H2_BLUEMANA]);
Sbar_DrawTinyStringf(10, y+18+6, "%03d", pv->stats[STAT_H2_GREENMANA]);
Sbar_Hexen2DrawNum(38, y+18, pv->stats[STAT_HEALTH], 3);
}
@ -2786,6 +2790,7 @@ void Sbar_TeamOverlay (void)
char num[12];
team_t *tm;
int plow, phigh, pavg;
int pw,ph;
playerview_t *pv = r_refdef.playerview;
if (!pv)
@ -2803,9 +2808,9 @@ void Sbar_TeamOverlay (void)
if (scr_scoreboard_drawtitle.ival)
{
pic = R2D_SafeCachePic ("gfx/ranking.lmp");
if (pic)
if (pic && R_GetShaderSizes(pic, &pw, &ph, false)>0)
{
k = (pic->width * 24) / pic->height;
k = (pw * 24) / ph;
R2D_ScalePic ((vid.width-k)/2, 0, k, 24, pic);
}
y += 24;
@ -3033,8 +3038,12 @@ void Sbar_DeathmatchOverlay (int start)
pic = R2D_SafeCachePic ("gfx/ranking.lmp");
if (pic)
{
k = (pic->width * 24) / pic->height;
R2D_ScalePic ((vid.width-k)/2, 0, k, 24, pic);
int w, h;
if (R_GetShaderSizes(pic, &w, &h, false)>0)
{
k = (w * 24) / h;
R2D_ScalePic ((vid.width-k)/2, 0, k, 24, pic);
}
}
y += 24;
}

View File

@ -216,25 +216,18 @@ qbyte *Skin_Cache8 (qwskin_t *skin)
int runLength;
int fbremap[256];
char *skinpath;
size_t pcxsize;
if (noskins.value==1) // JACK: So NOSKINS > 1 will show skins, but
return NULL; // not download new ones.
if (skin->failedload)
if (skin->failedload==true)
return NULL;
TEXASSIGN(skin->textures.base, r_nulltex);
TEXASSIGN(skin->textures.loweroverlay, r_nulltex);
TEXASSIGN(skin->textures.upperoverlay, r_nulltex);
out = skin->skindata;
if (out)
return out;
// TODO: we build a fullbright remap.. can we get rid of this?
for (x = 0; x < vid.fullbright; x++)
fbremap[x] = x + (256-vid.fullbright); //fullbrights don't exist, so don't loose palette info.
//
// load the pic from disk
//
@ -267,63 +260,60 @@ qbyte *Skin_Cache8 (qwskin_t *skin)
skinpath = "skins";
//favour 24bit+recoloured skins if gl_load24bit is enabled.
Q_snprintfz (name, sizeof(name), "%s_shirt", skin->name);
TEXASSIGN(skin->textures.upperoverlay, R_LoadReplacementTexture(name, skinpath, 0));
Q_snprintfz (name, sizeof(name), "%s_pants", skin->name);
TEXASSIGN(skin->textures.loweroverlay, R_LoadReplacementTexture(name, skinpath, 0));
if (TEXVALID(skin->textures.upperoverlay) || TEXVALID(skin->textures.loweroverlay))
//2 is used to try to force the skin if it load24bit is false.
if (gl_load24bit.ival || skin->failedload==2)
{
TEXASSIGN(skin->textures.base, R_LoadReplacementTexture(skin->name, skinpath, IF_NOALPHA));
if (TEXVALID(skin->textures.base))
if (!skin->textures.base)
skin->textures.base = R_LoadHiResTexture(skin->name, skinpath, IF_NOALPHA|IF_NOPCX);
if (skin->textures.base->status == TEX_LOADING)
return NULL; //don't spam the others until we actually know this one will load.
if (skin->failedload == 2)
skin->failedload = 1;
if (TEXLOADED(skin->textures.base))
{
Q_snprintfz (name, sizeof(name), "%s_luma", skin->name);
TEXASSIGN(skin->textures.fullbright, R_LoadReplacementTexture(skin->name, skinpath, IF_NOALPHA));
Q_snprintfz (name, sizeof(name), "%s_gloss", skin->name);
TEXASSIGN(skin->textures.specular, R_LoadReplacementTexture(skin->name, skinpath, 0));
skin->failedload = true;
return NULL;
if (!skin->textures.upperoverlay)
{
Q_snprintfz (name, sizeof(name), "%s_shirt", skin->name);
TEXASSIGN(skin->textures.upperoverlay, R_LoadHiResTexture(name, skinpath, 0));
}
if (!skin->textures.loweroverlay)
{
Q_snprintfz (name, sizeof(name), "%s_pants", skin->name);
TEXASSIGN(skin->textures.loweroverlay, R_LoadHiResTexture(name, skinpath, 0));
}
if (!skin->textures.fullbright)
{
Q_snprintfz (name, sizeof(name), "%s_luma", skin->name);
TEXASSIGN(skin->textures.fullbright, R_LoadHiResTexture(skin->name, skinpath, 0));
}
if (!skin->textures.specular)
{
Q_snprintfz (name, sizeof(name), "%s_gloss", skin->name);
TEXASSIGN(skin->textures.specular, R_LoadHiResTexture(skin->name, skinpath, 0));
}
skin->failedload = 1;
return NULL; //can use the high-res textures instead.
}
}
Q_snprintfz (name, sizeof(name), "%s/%s.pcx", skinpath, skin->name);
raw = COM_LoadTempFile (name);
raw = COM_LoadTempFile (name, &pcxsize);
if (!raw)
{
//use 24bit skins even if gl_load24bit is failed
if (strcmp(skin->name, baseskin.string))
{
// if (!gl_load24bit.value)
{
TEXASSIGN(skin->textures.base, R_LoadHiResTexture(skin->name, skinpath, IF_NOALPHA));
if (TEXVALID(skin->textures.base))
{
Q_snprintfz (name, sizeof(name), "%s_shirt", skin->name);
TEXASSIGN(skin->textures.upperoverlay, R_LoadHiResTexture(name, skinpath, 0));
Q_snprintfz (name, sizeof(name), "%s_pants", skin->name);
TEXASSIGN(skin->textures.loweroverlay, R_LoadHiResTexture(name, skinpath, 0));
if (!TEXVALID(skin->textures.upperoverlay) && !TEXVALID(skin->textures.loweroverlay))
Con_DPrintf("skin \"%s\" has no colourmapping info\n", skin->name);
Q_snprintfz (name, sizeof(name), "%s_luma", skin->name);
TEXASSIGN(skin->textures.fullbright, R_LoadHiResTexture(skin->name, skinpath, IF_NOALPHA));
Q_snprintfz (name, sizeof(name), "%s_gloss", skin->name);
TEXASSIGN(skin->textures.specular, R_LoadHiResTexture(skin->name, skinpath, 0));
skin->failedload = true;
return NULL;
}
}
//if its not already the base skin, try the base (and warn if anything not base couldn't load).
Con_Printf ("Couldn't load skin %s\n", name);
Q_snprintfz (name, sizeof(name), "skins/%s.pcx", baseskin.string);
raw = COM_LoadTempFile (name);
raw = COM_LoadTempFile (name, &pcxsize);
}
if (!raw)
{
skin->failedload = true;
if (skin->failedload)
skin->failedload = true;
else
skin->failedload = 2;
return NULL;
}
}
@ -366,6 +356,11 @@ qbyte *Skin_Cache8 (qwskin_t *skin)
if (!out)
Sys_Error ("Skin_Cache: couldn't allocate");
// TODO: we build a fullbright remap.. can we get rid of this?
for (x = 0; x < vid.fullbright; x++)
fbremap[x] = x + (256-vid.fullbright); //fullbrights don't exist, so don't loose palette info.
pix = out;
// memset (out, 0, skin->width*skin->height);
@ -374,7 +369,7 @@ qbyte *Skin_Cache8 (qwskin_t *skin)
{
for (x=0 ; x < srcw ; )
{
if (raw - (qbyte*)pcx > com_filesize)
if (raw - (qbyte*)pcx > pcxsize)
{
BZ_Free(skin->skindata);
skin->skindata = NULL;
@ -387,7 +382,7 @@ qbyte *Skin_Cache8 (qwskin_t *skin)
if((dataByte & 0xC0) == 0xC0)
{
runLength = dataByte & 0x3F;
if (raw - (qbyte*)pcx > com_filesize)
if (raw - (qbyte*)pcx > pcxsize)
{
BZ_Free(skin->skindata);
skin->skindata = NULL;
@ -426,7 +421,7 @@ qbyte *Skin_Cache8 (qwskin_t *skin)
for (x = 0; x < skin->width; )
pix[x++] = dataByte;
if ( raw - (qbyte *)pcx > com_filesize)
if ( raw - (qbyte *)pcx > pcxsize)
{
BZ_Free(skin->skindata);
skin->skindata = NULL;

View File

@ -30,7 +30,7 @@ static void S_StopAllSounds_f (void);
static void S_UpdateCard(soundcardinfo_t *sc);
static void S_ClearBuffer (soundcardinfo_t *sc);
static sfx_t *S_FindName (const char *name);
sfx_t *S_FindName (const char *name, qboolean create);
// =======================================================================
// Internal sound data & structures
@ -1762,7 +1762,7 @@ void S_DoRestart (void)
{
if (!cl.sound_name[i][0])
break;
cl.sound_precache[i] = S_FindName (cl.sound_name[i]);
cl.sound_precache[i] = S_FindName (cl.sound_name[i], true);
}
}
@ -1993,6 +1993,14 @@ void S_Shutdown(qboolean final)
Z_Free(known_sfx);
known_sfx = NULL;
num_sfx = 0;
#ifdef MULTITHREAD
if (final && mixermutex)
{
Sys_DestroyMutex(mixermutex);
mixermutex = NULL;
}
#endif
}
@ -2007,7 +2015,7 @@ S_FindName
also touches it
==================
*/
static sfx_t *S_FindName (const char *name)
sfx_t *S_FindName (const char *name, qboolean create)
{
int i;
sfx_t *sfx;
@ -2029,11 +2037,16 @@ static sfx_t *S_FindName (const char *name)
if (num_sfx == MAX_SFX)
Sys_Error ("S_FindName: out of sfx_t");
sfx = &known_sfx[i];
strcpy (sfx->name, name);
known_sfx[i].touched = true;
if (create)
{
sfx = &known_sfx[i];
strcpy (sfx->name, name);
known_sfx[i].touched = true;
num_sfx++;
num_sfx++;
}
else
sfx = NULL;
return sfx;
}
@ -2057,15 +2070,18 @@ void S_Purge(qboolean retaintouched)
for (i=0 ; i < num_sfx ; i++)
{
sfx = &known_sfx[i];
/*don't hurt sounds if they're being processed by a worker thread*/
if (sfx->loadstate == SLS_LOADING)
continue;
/*don't purge the file if its still relevent*/
if (retaintouched && sfx->touched)
continue;
sfx->loadstate = SLS_NOTLOADED;
/*nothing to do if there's no data within*/
if (!sfx->decoder.buf)
continue;
/*stop the decoder first*/
if (sfx->decoder.purge)
sfx->decoder.purge(sfx);
@ -2084,7 +2100,10 @@ void S_ResetFailedLoad(void)
{
int i;
for (i=0 ; i < num_sfx ; i++)
known_sfx[i].failedload = false;
{
if (known_sfx[i].loadstate == SLS_FAILED)
known_sfx[i].loadstate = SLS_NOTLOADED;
}
}
void S_UntouchAll(void)
@ -2105,7 +2124,7 @@ void S_TouchSound (char *name)
if (!sound_started)
return;
S_FindName (name);
S_FindName (name, true);
}
/*
@ -2118,10 +2137,10 @@ sfx_t *S_PrecacheSound (const char *name)
{
sfx_t *sfx;
if (nosound.ival || !known_sfx)
if (nosound.ival || !known_sfx || !*name)
return NULL;
sfx = S_FindName (name);
sfx = S_FindName (name, true);
// cache it in
if (precache.ival && sndcardinfo)
@ -2597,7 +2616,7 @@ void S_UpdateAmbientSounds (soundcardinfo_t *sc)
{
newmusic = S_PrecacheSound(nexttrack);
if (newmusic && !newmusic->failedload)
if (newmusic && newmusic->loadstate != SLS_FAILED)
{
chan->sfx = newmusic;
chan->rate = 1<<PITCHSHIFT;

View File

@ -715,7 +715,7 @@ qboolean S_LoadWavSound (sfx_t *s, qbyte *data, int datalen, int sndspeed)
info = GetWavinfo (s->name, data, datalen);
if (info.numchannels < 1 || info.numchannels > 2)
{
s->failedload = true;
s->loadstate = SLS_FAILED;
Con_Printf ("%s has an unsupported quantity of channels.\n",s->name);
return false;
}
@ -762,26 +762,19 @@ S_LoadSound
==============
*/
qboolean S_LoadSound (sfx_t *s)
qboolean S_LoadSoundWorker (void *ctx, void *ctxdata, size_t a, size_t b)
{
char stackbuf[65536];
sfx_t *s = ctx;
char namebuffer[256];
qbyte *data;
int i;
size_t result;
char *name = s->name;
if (s->failedload)
return false; //it failed to load once before, don't bother trying again.
// see if still in memory
if (s->decoder.buf || s->decoder.decodedata)
return true;
size_t filesize;
if (name[1] == ':' && name[2] == '\\')
{
vfsfile_t *f;
int fsize;
#ifndef _WIN32 //convert from windows to a suitable alternative.
char unixname[128];
Q_snprintfz(unixname, sizeof(unixname), "/mnt/%c/%s", name[0]-'A'+'a', name+3);
@ -798,18 +791,19 @@ qboolean S_LoadSound (sfx_t *s)
if ((f = VFSOS_Open(name, "rb")))
{
fsize = VFS_GETLEN(f);
data = Hunk_TempAlloc (fsize);
result = VFS_READ(f, data, fsize);
filesize = VFS_GETLEN(f);
data = BZ_Malloc (filesize);
result = VFS_READ(f, data, filesize);
if (result != fsize)
Con_SafePrintf("S_LoadSound() fread: Filename: %s, expected %i, result was %u\n", name, fsize, (unsigned int)result);
if (result != filesize)
Con_SafePrintf("S_LoadSound() fread: Filename: %s, expected %i, result was %u\n", name, filesize, (unsigned int)result);
VFS_CLOSE(f);
}
else
{
Con_SafePrintf ("Couldn't load %s\n", namebuffer);
s->loadstate = SLS_FAILED;
return false;
}
}
@ -819,12 +813,12 @@ qboolean S_LoadSound (sfx_t *s)
// load it in
data = NULL;
filesize = 0;
if (*name == '*') //q2 sexed sounds
{
//clq2_parsestartsound detects this also
//here we just precache the male sound name, which provides us with our default
Q_strcpy(namebuffer, "players/male/"); //q2
Q_strcat(namebuffer, name+1); //q2
//clq2_parsestartsound detects this also, and should not try playing these sounds.
s->loadstate = SLS_FAILED;
return false;
}
else if (name[0] == '.' && name[1] == '.' && name[2] == '/')
{
@ -836,19 +830,19 @@ qboolean S_LoadSound (sfx_t *s)
//q1 behaviour, relative to sound/
Q_strcpy(namebuffer, "sound/");
Q_strcat(namebuffer, name);
data = COM_LoadStackFile(name, stackbuf, sizeof(stackbuf));
data = COM_LoadFile(namebuffer, 5, &filesize);
}
// Con_Printf ("loading %s\n",namebuffer);
if (!data)
data = COM_LoadStackFile(namebuffer, stackbuf, sizeof(stackbuf));
data = COM_LoadFile(name, 5, &filesize);
if (!data)
{
char altname[sizeof(namebuffer)];
COM_StripExtension(namebuffer, altname, sizeof(altname));
COM_DefaultExtension(altname, ".ogg", sizeof(altname));
data = COM_LoadStackFile(altname, stackbuf, sizeof(stackbuf));
data = COM_LoadFile(altname, 5, &filesize);
if (data)
Con_DPrintf("found a mangled name\n");
}
@ -858,31 +852,43 @@ qboolean S_LoadSound (sfx_t *s)
{
//FIXME: check to see if queued for download.
Con_DPrintf ("Couldn't load %s\n", namebuffer);
s->failedload = true;
s->loadstate = SLS_FAILED;
return false;
}
s->failedload = false;
for (i = sizeof(AudioInputPlugins)/sizeof(AudioInputPlugins[0])-1; i >= 0; i--)
{
if (AudioInputPlugins[i])
{
if (AudioInputPlugins[i](s, data, com_filesize, snd_speed))
if (AudioInputPlugins[i](s, data, filesize, snd_speed))
{
s->loadstate = SLS_LOADED;
BZ_Free(data);
return true;
}
}
}
if (!s->failedload)
if (s->loadstate != SLS_FAILED)
Con_Printf ("Format not recognised: %s\n", namebuffer);
s->failedload = true;
s->loadstate = SLS_FAILED;
BZ_Free(data);
return false;
}
qboolean S_LoadSound (sfx_t *s)
{
if (s->loadstate == SLS_NOTLOADED && sndcardinfo)
{
s->loadstate = SLS_LOADING;
COM_AddWork(1, S_LoadSoundWorker, s, NULL, 0, 0);
}
if (s->loadstate == SLS_FAILED)
return false; //it failed to load once before, don't bother trying again.
return true; //loaded okay, or still loading
}
/*
===============================================================================

View File

@ -143,7 +143,7 @@ void S_PaintChannels(soundcardinfo_t *sc, int endtime)
for (i=0; i<sc->total_chans ; i++, ch++)
{
s = ch->sfx;
if (!s)
if (!s || s->loadstate == SLS_LOADING)
continue;
if (!ch->vol[0] && !ch->vol[1] && !ch->vol[2] && !ch->vol[3] && !ch->vol[4] && !ch->vol[5])
{

View File

@ -108,7 +108,7 @@ qboolean S_LoadOVSound (sfx_t *s, qbyte *data, int datalen, int sndspeed)
buffer->decodedbytecount = 0;
Z_Free(s->decoder.buf);
s->decoder.buf = NULL;
s->failedload = true;
s->loadstate = SLS_FAILED; //failed!
return false;
}

View File

@ -50,7 +50,12 @@ typedef struct sfx_s
char name[MAX_OSPATH];
sfxdecode_t decoder;
qboolean failedload:1; //no more super-spammy
enum {
SLS_NOTLOADED, //not tried to load it
SLS_LOADING, //loading it on a worker thread.
SLS_LOADED, //currently in memory and usable.
SLS_FAILED //already tried to load it. it won't work. not found, invalid format, etc
} loadstate; //no more super-spammy
qboolean touched:1; //if the sound is still relevent
#ifdef AVAIL_OPENAL
@ -136,6 +141,7 @@ qboolean S_HaveOutput(void);
void S_Music_Clear(sfx_t *onlyifsample);
void S_Music_Seek(float time);
sfx_t *S_FindName (const char *name, qboolean create);
sfx_t *S_PrecacheSound (const char *sample);
void S_TouchSound (char *sample);
void S_UntouchAll(void);

View File

@ -348,6 +348,9 @@ char *COM_ParseOut (const char *data, char *out, int outlen)
int c;
int len;
if (out == com_token)
COM_AssertMainThread("COM_ParseOut: com_token");
len = 0;
out[0] = 0;

View File

@ -29,6 +29,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <conio.h>
#include <io.h>
#include <direct.h>
#include "pr_common.h"
//#define RESTARTTEST
@ -591,8 +592,8 @@ DWORD CrashExceptionHandler (qboolean iswatchdog, DWORD exceptionCode, LPEXCEPTI
}
#ifdef PRINTGLARRAYS
if (!iswatchdog && qrenderer == QR_OPENGL)
DumpGLState();
// if (!iswatchdog && qrenderer == QR_OPENGL)
// DumpGLState();
#endif
hKernel = LoadLibrary ("kernel32");
@ -1428,7 +1429,6 @@ void Sys_Shutdown(void)
}
}
void VARGS Sys_Error (const char *error, ...)
{
va_list argptr;
@ -1440,6 +1440,8 @@ void VARGS Sys_Error (const char *error, ...)
vsnprintf (text, sizeof(text), error, argptr);
va_end (argptr);
COM_WorkerAbort(text);
#ifndef SERVERONLY
SetHookState(false);
Host_Shutdown ();
@ -2472,6 +2474,7 @@ void Win7_TaskListInit(void)
link->lpVtbl->Release(link);
}
break;
#ifdef HEXEN2
case MGT_HEXEN2:
link = CreateShellLink("+menu_servers", "", "Hexen2 Server List", "Pick a multiplayer server to join");
if (link)
@ -2486,6 +2489,7 @@ void Win7_TaskListInit(void)
link->lpVtbl->Release(link);
}
break;
#endif
}
if (SUCCEEDED(col->lpVtbl->QueryInterface(col, &qIID_IObjectArray, (void**)&arr)))

View File

@ -16,6 +16,7 @@ F11 will step through.
#include "quakedef.h"
#ifdef TEXTEDITOR
#include "pr_common.h"
#ifdef _WIN32
#define editaddcr_default "1"
@ -361,6 +362,7 @@ static void EditorOpenFile(char *name, qboolean readonly)
firstblock->flags |= FB_BREAK;
}
}
#ifndef CLIENTONLY
else
{
if (svprogfuncs)
@ -371,6 +373,7 @@ static void EditorOpenFile(char *name, qboolean readonly)
}
}
}
#endif
i++;
}

View File

@ -66,9 +66,8 @@ static void Validation_Version(void)
char authbuf[256];
char *auth = authbuf;
extern cvar_t r_shadow_realtime_world, r_drawflat;
extern cvar_t r_drawflat;
s = sr;
//print certain allowed 'cheat' options.
//realtime lighting (shadows can show around corners)
//drawflat is just lame
@ -174,7 +173,7 @@ void Validation_CheckIfResponse(char *text)
}
{
char *match = DISTRIBUTION"Quake v";
char *match = DISTRIBUTION" v";
if (strncmp(versionstring, match, strlen(match)))
return; //this is not us
}

View File

@ -42,7 +42,9 @@ typedef struct {
char subrenderer[MAX_QPATH];
struct rendererinfo_s *renderer;
} rendererstate_t;
#ifndef SERVERONLY
extern rendererstate_t currentrendererstate;
#endif
typedef struct vrect_s
{

View File

@ -14,45 +14,26 @@ static texid_tf dummytex;
static void Headless_Draw_Init(void)
{
//we always return some valid texture. this avoids having to hit the disk for each and every possibility until it fails, thus 'loading' textures much faster (hurrah for findtexture always finding one).
static texcom_t dummytexinfo;
dummytexinfo.width = 64;
dummytexinfo.height = 64;
dummytex.ref = &dummytexinfo;
R2D_Init();
}
static void Headless_Draw_Shutdown(void)
{
Shader_Shutdown();
}
static texid_tf Headless_IMG_LoadTexture (const char *identifier, int width, int height, uploadfmt_t fmt, void *data, unsigned int flags)
{
return dummytex;
}
static texid_tf Headless_IMG_LoadTexture8Pal24 (const char *identifier, int width, int height, qbyte *data, qbyte *palette24, unsigned int flags)
{
return dummytex;
}
static texid_tf Headless_IMG_LoadTexture8Pal32 (const char *identifier, int width, int height, qbyte *data, qbyte *palette32, unsigned int flags)
{
return dummytex;
}
static texid_tf Headless_IMG_LoadCompressed (const char *name)
{
return dummytex;
}
static texid_tf Headless_IMG_FindTexture (const char *identifier, unsigned int flags)
{
return dummytex;
}
static texid_tf Headless_IMG_AllocNewTexture (const char *identifier, int w, int h, unsigned int flags)
{
return dummytex;
}
static void Headless_IMG_Upload (texid_t tex, const char *name, uploadfmt_t fmt, void *data, void *palette, int width, int height, unsigned int flags)
static void Headless_IMG_UpdateFiltering (image_t *imagelist, int filtermip[3], int filterpic[3], int mipcap[2], float anis)
{
}
static void Headless_IMG_DestroyTexture (texid_t tex)
static qboolean Headless_IMG_LoadTextureMips (texid_t tex, struct pendingtextureinfo *mips)
{
int i;
for (i = 0; i < mips->mipcount; i++)
if (mips->mip[i].needfree)
Z_Free(mips->mip[i].data);
if (mips->extrafree)
Z_Free(mips->extrafree);
return true;
}
static void Headless_IMG_DestroyTexture (texid_t tex)
{
}
static void Headless_R_Init (void)
@ -64,13 +45,6 @@ static void Headless_R_DeInit (void)
static void Headless_R_RenderView (void)
{
}
static void Headless_R_NewMap (void)
{
}
static void Headless_R_PreNewMap (void)
{
}
#ifdef _WIN32
//tray icon crap, so the user can still restore the game.
LRESULT CALLBACK HeadlessWndProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
@ -202,7 +176,7 @@ static void Headless_BE_UploadAllLightmaps (void)
static void Headless_BE_SelectEntity (struct entity_s *ent)
{
}
static qboolean Headless_BE_SelectDLight (struct dlight_s *dl, vec3_t colour, unsigned int lmode)
static qboolean Headless_BE_SelectDLight (struct dlight_s *dl, vec3_t colour, vec3_t axis[3], unsigned int lmode)
{
return false;
}
@ -237,19 +211,12 @@ rendererinfo_t headlessrenderer =
Headless_Draw_Init,
Headless_Draw_Shutdown,
Headless_IMG_LoadTexture,
Headless_IMG_LoadTexture8Pal24,
Headless_IMG_LoadTexture8Pal32,
Headless_IMG_LoadCompressed,
Headless_IMG_FindTexture,
Headless_IMG_AllocNewTexture,
Headless_IMG_Upload,
Headless_IMG_UpdateFiltering,
Headless_IMG_LoadTextureMips,
Headless_IMG_DestroyTexture,
Headless_R_Init,
Headless_R_DeInit,
Headless_R_RenderView,
Headless_R_NewMap,
Headless_R_PreNewMap,
Headless_VID_Init,
Headless_VID_DeInit,
Headless_VID_SwapBuffers,

View File

@ -1302,10 +1302,6 @@ void V_CalcRefdef (playerview_t *pv)
r_refdef.time = cl.servertime;
{
extern model_t *loadmodel;
loadmodel = cl.worldmodel;
}
if (chase_active.ival && cls.allow_cheats) //cheat restriction might be lifted some time when any wallhacks are solved.
{
@ -1323,7 +1319,6 @@ void V_CalcRefdef (playerview_t *pv)
cl.worldmodel->funcs.NativeTrace(cl.worldmodel, 0, 0, NULL, r_refdef.vieworg, camorg, vec3_origin, vec3_origin, true, MASK_WORLDSOLID, &tr);
if (!tr.startsolid)
{
float extralen;
if (tr.fraction < 1)
{
//we found a plane, bisect it weirdly to push 4qu infront
@ -1675,7 +1670,7 @@ void V_RenderView (void)
}
else
{
if (r_worldentity.model && !r_worldentity.model->needload)
if (r_worldentity.model && r_worldentity.model->loadstate == MLS_LOADED)
{
RSpeedMark();

View File

@ -81,7 +81,7 @@ void W_LoadWadFile (char *filename)
if (wad_base)
Z_Free(wad_base);
wad_base = COM_LoadFile (filename, 0);
wad_base = COM_LoadFile (filename, 0, NULL);
if (!wad_base)
{
wad_numlumps = 0;
@ -432,7 +432,7 @@ qbyte *W_GetTexture(const char *name, int *width, int *height, qboolean *usesalp
miptex_t *tex;
qbyte *data;
if (!strncmp(name, "gfx/", 4))
if ((!strncmp(name, "gfx/", 4) || !strncmp(name, "wad/", 4)) && strcmp(name, "gfx/conchars"))
{
qpic_t *p;
p = W_SafeGetLumpName(name+4);
@ -580,6 +580,7 @@ void CL_Skygroup_f(void)
char wads[4096];
void Mod_ParseInfoFromEntityLump(model_t *wmodel, char *data, char *mapname) //actually, this should be in the model code.
{
char token[4096];
char key[128];
mapskys_t *msky;
@ -600,31 +601,31 @@ void Mod_ParseInfoFromEntityLump(model_t *wmodel, char *data, char *mapname) //a
cl.skyname[0] = '\0';
if (data)
if ((data=COM_Parse(data))) //read the map info.
if (com_token[0] == '{')
if ((data=COM_ParseOut(data, token, sizeof(token)))) //read the map info.
if (token[0] == '{')
while (1)
{
if (!(data=COM_Parse(data)))
if (!(data=COM_ParseOut(data, token, sizeof(token))))
break; // error
if (com_token[0] == '}')
if (token[0] == '}')
break; // end of worldspawn
if (com_token[0] == '_')
strcpy(key, com_token + 1); //_ vars are for comments/utility stuff that arn't visible to progs. Ignore them.
if (token[0] == '_')
Q_strncpyz(key, token + 1, sizeof(key)); //_ vars are for comments/utility stuff that arn't visible to progs. Ignore them.
else
strcpy(key, com_token);
if (!((data=COM_Parse(data))))
Q_strncpyz(key, token, sizeof(key));
if (!((data=COM_ParseOut(data, token, sizeof(token)))))
break; // error
if (!strcmp("wad", key)) // for HalfLife maps
{
if (wmodel->fromgame == fg_halflife)
{
strncat(wads, ";", 4095); //cache it for later (so that we don't play with any temp memory yet)
strncat(wads, com_token, 4095); //cache it for later (so that we don't play with any temp memory yet)
Q_strncatz(wads, ";", sizeof(wads)); //cache it for later (so that we don't play with any temp memory yet)
Q_strncatz(wads, token, sizeof(wads)); //cache it for later (so that we don't play with any temp memory yet)
}
}
else if (!strcmp("skyname", key)) // for HalfLife maps
{
Q_strncpyz(cl.skyname, com_token, sizeof(cl.skyname));
Q_strncpyz(cl.skyname, token, sizeof(cl.skyname));
}
else if (!strcmp("fog", key)) //q1 extension. FIXME: should be made temporary.
{
@ -632,7 +633,7 @@ void Mod_ParseInfoFromEntityLump(model_t *wmodel, char *data, char *mapname) //a
void CL_Fog_f(void);
key[0] = 'f';
key[1] = ' ';
Q_strncpyz(key+2, com_token, sizeof(key)-2);
Q_strncpyz(key+2, token, sizeof(key)-2);
Cmd_TokenizeString(key, false, false);
Cmd_ExecLevel=RESTRICT_LOCAL;
CL_Fog_f();
@ -666,25 +667,25 @@ void Mod_ParseInfoFromEntityLump(model_t *wmodel, char *data, char *mapname) //a
}
else if (!strcmp("sky", key)) // for Quake2 maps
{
Q_strncpyz(cl.skyname, com_token, sizeof(cl.skyname));
Q_strncpyz(cl.skyname, token, sizeof(cl.skyname));
}
else if (!strcmp("skyrotate", key)) //q2 feature
{
cl.skyrotate = atof(com_token);
cl.skyrotate = atof(token);
}
else if (!strcmp("skyaxis", key)) //q2 feature
{
char *s;
Q_strncpyz(key, com_token, sizeof(key));
s = COM_Parse(key);
Q_strncpyz(key, token, sizeof(key));
s = COM_ParseOut(key, token, sizeof(token));
if (s)
{
cl.skyaxis[0] = atof(s);
s = COM_Parse(s);
s = COM_ParseOut(s, token, sizeof(token));
if (s)
{
cl.skyaxis[1] = atof(s);
COM_Parse(s);
COM_ParseOut(s, token, sizeof(token));
if (s)
cl.skyaxis[2] = atof(s);
}

View File

@ -32,6 +32,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#pragma warning( disable : 4229 ) // mgraph gets this
#endif
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400
#endif
#define WIN32_LEAN_AND_MEAN
#define byte winbyte
#include <windows.h>

View File

@ -53,7 +53,7 @@ END
//
// Dialog
//
#if 0
IDD_DIALOG1 DIALOGEX 0, 0, 67, 40
STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | WS_POPUP | WS_VISIBLE
EXSTYLE WS_EX_TOOLWINDOW | WS_EX_CLIENTEDGE
@ -62,8 +62,7 @@ BEGIN
CTEXT FULLENGINENAME,IDC_STATIC,0,0,67,21,SS_CENTERIMAGE
CTEXT ENGINEWEBSITE,IDC_STATIC,0,23,66,17,SS_CENTERIMAGE
END
#endif
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
@ -85,7 +84,14 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
#ifdef BRANDING_ICON
IDI_ICON1 ICON BRANDING_ICON
IDI_ICON2 ICON "bymorphed.ico"
IDI_ICON3 ICON "q2.ico"
#else
IDI_ICON1 ICON "bymorphed.ico"
IDI_ICON2 ICON "q2.ico"
#endif
/////////////////////////////////////////////////////////////////////////////
//

View File

@ -1392,7 +1392,7 @@ static void TP_LoadLocFile (char *filename, qbool quiet)
Q_snprintfz (fullpath, sizeof(fullpath) - 4, "locs/%s", filename);
COM_DefaultExtension (fullpath, ".loc", sizeof(fullpath));
buf = (char *) COM_LoadTempFile (fullpath);
buf = (char *) COM_LoadTempFile (fullpath, NULL);
if (!buf)
{
if (!quiet)

View File

@ -25,15 +25,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define FTE_VER_MAJOR 1
#define FTE_VER_MINOR 3
//#define VERSION 2.56
#ifndef DISTRIBUTION
#define DISTRIBUTION "FTE" //short name used to identify this engine. must be a single word
#define DISTRIBUTIONLONG "Forethought Entertainment" //effectively the 'company' name
#define FULLENGINENAME "FTE QuakeWorld" //the posh name for the engine
#define ENGINEWEBSITE "http://www.fteqw.com" //url for program
#endif
#if defined(__APPLE__) && defined(__MACH__)
#define MACOSX
#endif
@ -159,6 +150,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//set any additional defines or libs in win32
#define SVRANKING
#define LOADERTHREAD
#ifdef MINIMAL
#define CL_MASTER //this is useful
@ -191,7 +183,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define SIDEVIEWS 4 //enable secondary/reverse views.
#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 SP2MODELS //quake2 sprite models
#define MD2MODELS //quake2 alias models
@ -200,7 +192,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define ZYMOTICMODELS //zymotic skeletal models.
#define DPMMODELS //darkplaces model format (which I've never seen anyone use)
#define PSKMODELS //PSK model format (ActorX stuff from UT, though not the format the game itself uses)
#define HALFLIFEMODELS //halflife model support (experimental)
// #define HALFLIFEMODELS //halflife model support (experimental)
#define INTERQUAKEMODELS
#define RAGDOLL
@ -265,7 +257,25 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif
//#define QUAKETC
//include a file to update the various configurations for game-specific configs (hopefully just names)
#ifdef BRANDING_INC
#define STRINGIFY2(s) #s
#define STRINGIFY(s) STRINGIFY2(s)
#include STRINGIFY(BRANDING_INC)
#endif
#ifndef DISTRIBUTION
#define DISTRIBUTION "FTE" //short name used to identify this engine. must be a single word
#endif
#ifndef DISTRIBUTIONLONG
#define DISTRIBUTIONLONG "Forethought Entertainment" //effectively the 'company' name
#endif
#ifndef FULLENGINENAME
#define FULLENGINENAME "FTE QuakeWorld" //the posh name for the engine
#endif
#ifndef ENGINEWEBSITE
#define ENGINEWEBSITE "http://www.fteqw.com" //url for program
#endif
#ifdef QUAKETC
#define NOBUILTINMENUS //kill engine menus (should be replaced with ewither csqc or menuqc)
@ -348,6 +358,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif
#ifndef MULTITHREAD
//database code requires threads to do stuff async.
#undef USE_SQLITE
#undef USE_MYSQL
#endif
@ -369,6 +380,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif
#endif
#if (defined(NOLOADERTHREAD) || !defined(MULTITHREAD)) && defined(LOADERTHREAD)
#undef LOADERTHREAD
#endif
#ifndef _WIN32
#undef QTERM //not supported - FIXME: move to native plugin
#endif

View File

@ -546,9 +546,19 @@ void Cmd_Exec_f (void)
Con_DPrintf("Ignoring UTF-8 BOM\n");
s+=3;
}
if (!strcmp(name, "config.cfg") || !strcmp(name, "fte.cfg"))
{
//if the config is from id1 and the default.cfg was from some mod, make sure the default.cfg overrides the config.
//we won't just exec the default instead, because we can at least retain things which are not specified (ie: a few binds)
int cfgdepth = COM_FDepthFile(name, true);
int defdepth = COM_FDepthFile("default.cfg", true);
if (defdepth < cfgdepth)
Cbuf_InsertText("exec default.cfg\n", ((Cmd_FromGamecode() || com_file_untrusted) ? RESTRICT_INSECURE : Cmd_ExecLevel), false);
}
// don't execute anything if it was from server (either the stuffcmd/localcmd, or the file)
if (!strcmp(name, "default.cfg") && !(Cmd_FromGamecode() || com_file_untrusted))
Cbuf_InsertText ("\ncvar_lockdefaults 1\n", ((Cmd_FromGamecode() || com_file_untrusted) ? RESTRICT_INSECURE : Cmd_ExecLevel), true);
Cbuf_InsertText ("\ncvar_lockdefaults 1\n", ((Cmd_FromGamecode() || com_file_untrusted) ? RESTRICT_INSECURE : Cmd_ExecLevel), false);
Cbuf_InsertText (s, ((Cmd_FromGamecode() || com_file_untrusted) ? RESTRICT_INSECURE : Cmd_ExecLevel), true);
FS_FreeFile(f);
}
@ -566,7 +576,13 @@ void Cmd_Echo_f (void)
int i;
for (i=1 ; i<Cmd_Argc() ; i++)
Con_Printf ("%s ",Cmd_Argv(i));
{
#ifdef SERVERONLY
Con_Printf ("%s", Cmd_Argv(i));
#else
Con_PrintFlags (Cmd_Argv(i), (com_parseezquake.ival?PFS_EZQUAKEMARKUP:0), 0);
#endif
}
Con_Printf ("\n");
}
@ -1847,6 +1863,53 @@ void Cmd_List_f (void)
Con_Printf("\n");
}
//I'm not personally keen on this name, but its somewhat standard in both DP and suse (which lh uses, hence why DP uses that name). oh well.
void Cmd_Apropos_f (void)
{
extern cvar_group_t *cvar_groups;
cmd_function_t *cmd;
cvar_group_t *grp;
cvar_t *var;
char *name;
char escapedvalue[1024];
char latchedvalue[1024];
char *query = Cmd_Argv(1);
for (grp=cvar_groups ; grp ; grp=grp->next)
for (var=grp->cvars ; var ; var=var->next)
{
if (var->name && Q_strcasestr(var->name, query))
name = var->name;
else if (var->name2 && Q_strcasestr(var->name2, query))
name = var->name2;
else if (var->description && Q_strcasestr(var->description, query))
name = var->name;
else
continue;
COM_QuotedString(var->string, escapedvalue, sizeof(escapedvalue));
if (var->latched_string)
{
COM_QuotedString(var->latched_string, latchedvalue, sizeof(latchedvalue));
Con_Printf("cvar ^2%s^7: %s (effective %s): %s\n", name, latchedvalue, escapedvalue, var->description?var->description:"no description");
}
else
Con_Printf("cvar ^2%s^7: %s : %s\n", name, escapedvalue, var->description?var->description:"no description");
}
for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
{
if (cmd->name && Q_strcasestr(cmd->name, query))
;
else if (cmd->description && strstr(cmd->description, query))
;
else
continue;
Con_Printf("command ^2%s^7: %s\n", cmd->name, cmd->description?cmd->description:"no description");
}
//FIXME: add aliases.
}
#ifndef SERVERONLY // FIXME
/*
@ -1997,7 +2060,11 @@ void Cmd_ExecuteString (char *text, int level)
return;
#endif
if (Cmd_AliasExist(cmd_argv[0], level))
break; //server stuffed an alias for a command that it would already have received. use that instead.
return; //server stuffed an alias for a command that it would already have received. use that instead.
#if defined(CSQC_DAT) && !defined(SERVERONLY)
if (CSQC_ConsoleCommand(text))
return; //let the csqc handle it if it wants.
#endif
Cmd_ForwardToServer ();
}
else
@ -2852,7 +2919,11 @@ void Cmd_WriteConfig_f(void)
filename = Cmd_Argv(1);
if (!*filename)
{
#ifdef QUAKETC
snprintf(fname, sizeof(fname), "config.cfg");
#else
snprintf(fname, sizeof(fname), "fte.cfg");
#endif
FS_NativePath(fname, FS_GAMEONLY, sysname, sizeof(sysname));
FS_CreatePath(fname, FS_GAMEONLY);
f = FS_OpenVFS(fname, "wbp", FS_GAMEONLY);
@ -3113,6 +3184,8 @@ void Cmd_Init (void)
Cmd_AddCommand ("cvar_purgedefaults", Cvar_PurgeDefaults_f);
Cmd_AddCommand ("fs_flush", COM_RefreshFSCache_f);
Cmd_AddCommandD ("apropos", Cmd_Apropos_f, "Lists all cvars or commands with the specified substring somewhere in their name or descrition.");
Cmd_AddMacro("time", Macro_Time, true);
Cmd_AddMacro("ukdate", Macro_UKDate, false);
Cmd_AddMacro("usdate", Macro_USDate, false);

File diff suppressed because it is too large Load Diff

View File

@ -68,14 +68,22 @@ typedef struct FTE_DEPRECATED
//we can't be bothered with animating skins.
//We'll load up to four of them but after that you're on your own
#ifndef SERVERONLY
typedef struct
{
shader_t *shader;
qbyte *texels; //this is 8bit for frame 0 only. only valid in q1 models without replacement textures, used for colourising player skins.
char *defaultshader;
char shadername[MAX_QPATH];
texnums_t texnums;
} skinframe_t;
typedef struct
{
int skinwidth;
int skinheight;
qbyte **ofstexels; //this is 8bit for frame 0 only. only valid in q1 models without replacement textures, used for colourising player skins.
float skinspeed;
int numshaders;
shader_t **ofsshaders;
int numframes;
skinframe_t *frame;
char name[MAX_QPATH];
} galiasskin_t;
@ -170,28 +178,27 @@ typedef struct
void (QDECL *UnRegisterModelFormat)(int idx);
void (QDECL *UnRegisterAllModelFormats)(void);
void *(QDECL *ZG_Malloc)(zonegroup_t *ctx, int size);
void *(QDECL *ZG_Malloc)(zonegroup_t *ctx, int size); //ctx=&mod->memgroup and the data will be freed when the model is freed.
void (QDECL *ConcatTransforms) (float in1[3][4], float in2[3][4], float out[3][4]);
void (QDECL *M3x4_Invert) (const float *in1, float *out);
void (QDECL *StripExtension) (const char *in, char *out, int outlen);
void (QDECL *GenMatrixPosQuat4Scale)(vec3_t pos, vec4_t quat, vec3_t scale, float result[12]);
void (QDECL *ForceConvertBoneData)(skeltype_t sourcetype, const float *sourcedata, size_t bonecount, galiasbone_t *bones, skeltype_t desttype, float *destbuffer, size_t destbonecount);
shader_t *(QDECL *RegisterShader) (const char *name, unsigned int usageflags, const char *shaderscript);
shader_t *(QDECL *RegisterSkin) (const char *shadername, const char *modname);
void (QDECL *BuildDefaultTexnums)(texnums_t *tn, shader_t *shader);
} modplugfuncs_t;
#define MODPLUGFUNCS_VERSION 0
#define MODPLUGFUNCS_VERSION 1
#ifdef SKELETALMODELS
void Alias_TransformVerticies(float *bonepose, galisskeletaltransforms_t *weights, int numweights, vecV_t *xyzout, vec3_t *normout);
void QDECL Alias_ForceConvertBoneData(skeltype_t sourcetype, const float *sourcedata, size_t bonecount, galiasbone_t *bones, skeltype_t desttype, float *destbuffer, size_t destbonecount);
#endif
qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, int surfnum, entity_t *e, qboolean allowskel);
void Mod_DestroyMesh(galiasinfo_t *galias);
void Alias_FlushCache(void);
void Alias_Shutdown(void);
void Alias_Register(void);
shader_t *Mod_ShaderForSkin(model_t *model, int num);
const char *Mod_SkinNameForNum(model_t *model, int num);
void Mod_DoCRC(model_t *mod, char *buffer, int buffersize);

View File

@ -94,8 +94,9 @@ cvar_t fs_gamemanifest = CVARFD("fs_gamemanifest", "", CVAR_NOSET, "A small upda
cvar_t com_protocolname = CVARD("com_gamename", "", "The game name used for dpmaster queries");
cvar_t com_modname = CVARD("com_modname", "", "dpmaster information");
cvar_t com_parseutf8 = CVARD("com_parseutf8", "0", "Interpret console messages/playernames/etc as UTF-8. Requires special fonts. -1=iso 8859-1. 0=quakeascii(chat uses high chars). 1=utf8, revert to ascii on decode errors. 2=utf8 ignoring errors"); //1 parse. 2 parse, but stop parsing that string if a char was malformed.
cvar_t com_parseezquake = CVARD("com_parseezquake", "0", "Treat chevron chars from configs as a per-character flag. You should use this only for compat with nquake's configs.");
cvar_t com_highlightcolor = CVARD("com_highlightcolor", STRINGIFY(COLOR_RED), "ANSI colour to be used for highlighted text, used when com_parseutf8 is active.");
cvar_t com_nogamedirnativecode = CVARFD("com_nogamedirnativecode", "1", CVAR_NOTFROMSERVER, FULLENGINENAME" blocks all downloads of files with a .dll or .so extension, however other engines (eg: ezquake and fodquake) do not - this omission can be used to trigger remote exploits in any engine (including "FULLENGINENAME"which is later run from the same gamedir.\nQuake2, Quake3(when debugging), and KTX typically run native gamecode from within gamedirs, so if you wish to run any of these games you will need to ensure this cvar is changed to 0, as well as ensure that you don't run unsafe clients.\n");
cvar_t com_nogamedirnativecode = CVARFD("com_nogamedirnativecode", "1", CVAR_NOTFROMSERVER, FULLENGINENAME" blocks all downloads of files with a .dll or .so extension, however other engines (eg: ezquake and fodquake) do not - this omission can be used to trigger remote exploits in any engine (including "DISTRIBUTION") which is later run from the same gamedir.\nQuake2, Quake3(when debugging), and KTX typically run native gamecode from within gamedirs, so if you wish to run any of these games you will need to ensure this cvar is changed to 0, as well as ensure that you don't run unsafe clients.\n");
cvar_t sys_platform = CVAR("sys_platform", PLATFORM);
qboolean com_modified; // set true if using non-id files
@ -369,6 +370,45 @@ int QDECL Q_stricmp (const char *s1, const char *s2)
return Q_strncasecmp (s1, s2, 99999);
}
char *Q_strcasestr(const char *haystack, const char *needle)
{
int c1, c2, c2f;
int i;
c2f = *needle;
if (c2f >= 'a' && c2f <= 'z')
c2f -= ('a' - 'A');
if (!c2f)
return (char*)haystack;
while (1)
{
c1 = *haystack;
if (!c1)
return NULL;
if (c1 >= 'a' && c1 <= 'z')
c1 -= ('a' - 'A');
if (c1 == c2f)
{
for (i = 1; ; i++)
{
c1 = haystack[i];
c2 = needle[i];
if (c1 >= 'a' && c1 <= 'z')
c1 -= ('a' - 'A');
if (c2 >= 'a' && c2 <= 'z')
c2 -= ('a' - 'A');
if (!c2)
return (char*)haystack; //end of needle means we found a complete match
if (!c1) //end of haystack means we can't possibly find needle in it any more
return NULL;
if (c1 != c2) //mismatch means no match starting at haystack[0]
break;
}
}
haystack++;
}
return NULL; //didn't find it
}
int QDECL Q_vsnprintf(char *buffer, int size, const char *format, va_list argptr)
{
return vsnprintf(buffer, size, format, argptr);
@ -1719,14 +1759,13 @@ void SZ_Print (sizebuf_t *buf, const char *data)
//============================================================================
char *COM_TrimString(char *str)
char *COM_TrimString(char *str, char *buffer, int buffersize)
{
int i;
static char buffer[256];
while (*str <= ' ' && *str>'\0')
str++;
for (i = 0; i < 255; i++)
for (i = 0; i < buffersize-1; i++)
{
if (*str <= ' ')
break;
@ -1806,23 +1845,25 @@ void COM_StripAllExtensions (char *in, char *out, int outlen)
COM_FileExtension
============
*/
char *COM_FileExtension (const char *in)
char *COM_FileExtension (const char *in, char *result, size_t sizeofresult)
{
static char exten[8];
int i;
const char *dot;
for (dot = in + strlen(in); dot >= in && *dot != '.'; dot--)
;
if (dot < in)
return "";
{
*result = 0;
return result;
}
in = dot;
in++;
for (i=0 ; i<7 && *in ; i++,in++)
exten[i] = *in;
exten[i] = 0;
return exten;
for (i=0 ; i<sizeofresult-1 && *in ; i++,in++)
result[i] = *in;
result[i] = 0;
return result;
}
//Quake 2's tank model has a borked skin (or two).
@ -2880,13 +2921,19 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t
unsigned int uc;
int utf8 = com_parseutf8.ival;
conchar_t linkinitflags = CON_WHITEMASK;/*doesn't need the init, but msvc is stupid*/
qboolean keepmarkup = flags & PFS_KEEPMARKUP;
qboolean keepmarkup = !!(flags & PFS_KEEPMARKUP);
qboolean linkkeep = keepmarkup;
qboolean ezquakemess = false;
conchar_t *linkstart = NULL;
conchar_t ext;
conchar_t *oldout = out;
if (flags & PFS_EZQUAKEMARKUP)
{
ezquakemess = true;
utf8 = 0;
}
if (flags & PFS_FORCEUTF8)
utf8 = 2;
@ -2936,7 +2983,14 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t
continue;
}
}
if (*str == '^' && !(flags & PFS_NOMARKUP))
if (ezquakemess && *str == '^')
{
str++;
uc = (unsigned char)(*str++);
*out++ = (uc | ext) ^ CON_2NDCHARSETTEXT;
continue;
}
else if (*str == '^' && !(flags & PFS_NOMARKUP))
{
if (str[1] >= '0' && str[1] <= '9')
{
@ -3366,6 +3420,9 @@ char *COM_Parse (const char *data)
int c;
int len;
if (out == com_token)
COM_AssertMainThread("COM_ParseOut: com_token");
len = 0;
com_token[0] = 0;
@ -3431,13 +3488,16 @@ skipwhite:
#endif
//semi-colon delimited tokens
char *COM_ParseStringSet (const char *data)
char *COM_ParseStringSet (const char *data, char *out, size_t outsize)
{
int c;
int len;
if (out == com_token)
COM_AssertMainThread("COM_ParseOut: com_token");
len = 0;
com_token[0] = 0;
out[0] = 0;
if (!data)
return NULL;
@ -3453,19 +3513,19 @@ char *COM_ParseStringSet (const char *data)
// parse a regular word
do
{
if (len >= TOKENSIZE-1)
if (len >= outsize-1)
{
com_token[len] = 0;
out[len] = 0;
return (char*)data;
}
com_token[len] = c;
out[len] = c;
data++;
len++;
c = *(unsigned char*)data;
} while (c>32 && c != ';');
com_token[len] = 0;
out[len] = 0;
return (char*)data;
}
@ -3475,6 +3535,9 @@ char *COM_ParseOut (const char *data, char *out, int outlen)
int c;
int len;
if (out == com_token)
COM_AssertMainThread("COM_ParseOut: com_token");
len = 0;
out[0] = 0;
@ -3569,6 +3632,9 @@ char *COM_StringParse (const char *data, char *token, unsigned int tokenlen, qbo
len = 0;
token[0] = 0;
if (token == com_token)
COM_AssertMainThread("COM_ParseOut: com_token");
if (!data)
return NULL;
@ -3774,6 +3840,8 @@ char *COM_ParseToken (const char *data, const char *punctuation)
if (!punctuation)
punctuation = DEFAULT_PUNCTUATION;
COM_AssertMainThread("COM_ParseOut: com_token");
len = 0;
com_token[0] = 0;
@ -3953,6 +4021,9 @@ char *COM_ParseCString (const char *data, char *token, size_t sizeoftoken, size_
len = 0;
token[0] = 0;
if (token == com_token)
COM_AssertMainThread("COM_ParseCString: com_token");
if (lengthwritten)
*lengthwritten = 0;
@ -4103,7 +4174,7 @@ functions may use the cvar before anything's loaded.
This isn't really needed, but might make some thing nicer.
===============
*/
void COM_ParsePlusSets (void)
void COM_ParsePlusSets (qboolean docbuf)
{
int i;
for (i=1 ; i<com_argc-2 ; i++)
@ -4120,10 +4191,25 @@ void COM_ParsePlusSets (void)
if (*com_argv[i+2] == '-' || *com_argv[i+2] == '+')
continue; //erm
if (!strcmp(com_argv[i], "+set"))
Cvar_Get(com_argv[i+1], com_argv[i+2], 0, "Cvars set on commandline");
else if (!strcmp(com_argv[i], "+seta"))
Cvar_Get(com_argv[i+1], com_argv[i+2], CVAR_ARCHIVE, "Cvars set on commandline");
if (docbuf)
{
if (!strcmp(com_argv[i], "+set") || !strcmp(com_argv[i], "+seta"))
{
Cbuf_AddText(com_argv[i]+1, RESTRICT_LOCAL);
Cbuf_AddText(" ", RESTRICT_LOCAL);
Cbuf_AddText(com_argv[i+1], RESTRICT_LOCAL);
Cbuf_AddText(" ", RESTRICT_LOCAL);
Cbuf_AddText(com_argv[i+2], RESTRICT_LOCAL);
Cbuf_AddText("\n", RESTRICT_LOCAL);
}
}
else
{
if (!strcmp(com_argv[i], "+set"))
Cvar_Get(com_argv[i+1], com_argv[i+2], 0, "Cvars set on commandline");
else if (!strcmp(com_argv[i], "+seta"))
Cvar_Get(com_argv[i+1], com_argv[i+2], CVAR_ARCHIVE, "Cvars set on commandline");
}
i+=2;
}
}
@ -4299,16 +4385,28 @@ void COM_Version_f (void)
#endif
#ifdef SERVERONLY
Con_Printf("dedicated server build\n");
#endif
#else
Con_Printf("Renderers:");
#ifdef GLQUAKE
Con_Printf("OpenGL available\n");
#ifdef GLESONLY
Con_Printf(" OpenGLES");
#else
Con_Printf(" OpenGL");
#endif
#ifdef GLSLONLY
Con_Printf("(GLSL)");
#endif
#endif
#ifdef D3D9QUAKE
Con_Printf("Direct3D9 available\n");
Con_Printf(" Direct3D9");
#endif
#ifdef D3D11QUAKE
Con_Printf("Direct3D11 available\n");
Con_Printf(" Direct3D11");
#endif
#ifdef SWQUAKE
Con_Printf(" Software");
#endif
Con_Printf("\n");
#endif
#ifdef QCJIT
@ -4405,7 +4503,11 @@ void COM_Version_f (void)
#endif
#ifdef MULTITHREAD
Con_Printf("multithreading: enabled\n");
#ifdef LOADERTHREAD
Con_Printf("multithreading: enabled (loader enabled)\n");
#else
Con_Printf("multithreading: enabled (no loader)\n");
#endif
#else
Con_Printf("multithreading: disabled\n");
#endif
@ -4418,9 +4520,8 @@ void COM_Version_f (void)
#endif
//but print client ones only if we're not dedicated
#ifndef SERVERONLY
//but print client ones only if we're not dedicated
#ifndef AVAIL_PNGLIB
Con_Printf("libpng disabled\n");
#else
@ -4431,46 +4532,79 @@ void COM_Version_f (void)
#else
Con_Printf("libjpeg: %i (%d series)\n", JPEG_LIB_VERSION, ( JPEG_LIB_VERSION / 10 ) );
#endif
#ifdef SPEEX_STATIC
Con_Printf("speex: static\n");
#elif defined(VOICECHAT)
Con_Printf("speex: dynamic\n");
Con_Printf("VoiceChat:");
#if !defined(VOICECHAT)
Con_Printf(" disabled");
#else
Con_Printf("speex: disabled\n");
#endif
#ifdef ODE_STATIC
Con_Printf("ODE: static\n");
#elif defined(USEODE)
Con_Printf("ODE: dynamic\n");
#else
Con_Printf("ODE: disabled\n");
#ifdef SPEEX_STATIC
Con_Printf(" speex(static)");
#else
Con_Printf(" speex(dynamic)");
#endif
#ifdef OPUS_STATIC
Con_Printf(" opus(static)");
#else
Con_Printf(" opus(dynamic)");
#endif
#endif
Con_Printf("\n");
Con_Printf("Audio Decoders:");
#ifndef AVAIL_OGGVORBIS
Con_Printf("Ogg Vorbis: disabled\n");
Con_Printf(" ^h(disabled: Ogg Vorbis)^7");
#elif defined(LIBVORBISFILE_STATIC)
Con_Printf("Ogg Vorbis: static\n");
Con_Printf(" Ogg Vorbis(static)");
#else
Con_Printf("Ogg Vorbis: dynamic\n");
Con_Printf(" Ogg Vorbis(dynamic)");
#endif
#ifdef USE_MYSQL
Con_Printf("mySQL: dynamic\n");
#if defined(_WIN32) && !defined(WINRT) && !defined(NOMEDIA)
Con_Printf(" mp3(system)");
#endif
Con_Printf("\n");
#endif
#ifdef SQL
Con_Printf("Databases:");
#ifdef USE_MYSQL
Con_Printf(" mySQL(dynamic)");
#else
Con_Printf(" ^h(disabled: mySQL)^7");
#endif
#ifdef USE_SQLITE
Con_Printf(" sqlite(dynamic)");
#else
Con_Printf(" ^h(disabled: sqlite)^7");
#endif
Con_Printf("\n");
#endif
Con_Printf("Misc:");
#ifdef ODE_STATIC
Con_Printf(" ODE(static)");
#elif defined(USEODE)
Con_Printf(" ODE(dynamic)");
#else
Con_Printf("mySQL: disabled\n");
Con_Printf(" ^h(disabled: ODE)^7");
#endif
#ifdef USE_SQLITE
Con_Printf("sqlite: dynamic\n");
#ifdef SUBSERVERS
Con_Printf(" mapcluster(enabled)");
#else
Con_Printf("sqlite: disabled\n");
Con_Printf(" ^h(disabled: mapcluster)^7");
#endif
#ifndef AVAIL_OGGVORBIS
Con_Printf("libvorbis disabled\n");
#ifndef SERVERONLY
#ifdef AVAIL_FREETYPE
Con_Printf(" freetype2");
#else
Con_Printf(" ^h(disabled: freetype2)^7");
#endif
#ifndef AVAIL_FREETYPE
Con_Printf("freetype2 disabled\n");
#ifdef AVAIL_OPENAL
Con_Printf(" openal");
#else
Con_Printf(" ^h(disabled: openal)^7");
#endif
#ifndef AVAIL_OPENAL
Con_Printf("openal disabled\n");
#endif
Con_Printf("\n");
#ifdef _WIN32
#ifndef AVAIL_DINPUT
@ -4486,7 +4620,56 @@ void COM_Version_f (void)
Con_Printf("DirectDraw disabled\n");
#endif
#endif
Con_Printf("Games:");
#if defined(Q3SERVER) && defined(Q3CLIENT)
Con_Printf(" Quake3");
#elif defined(Q3SERVER)
Con_Printf(" Quake3(server)");
#elif defined(Q3CLIENT)
Con_Printf(" Quake3(client)");
#elif defined(Q3BSPS)
Con_Printf(" Quake3(bsp only)");
#else
Con_Printf(" ^h(disabled: Quake3)^7");
#endif
#if defined(Q2SERVER) && defined(Q2CLIENT)
Con_Printf(" Quake2");
#elif defined(Q2SERVER)
Con_Printf(" Quake2(server)");
#elif defined(Q2CLIENT)
Con_Printf(" Quake2(client)");
#elif defined(Q2BSPS)
Con_Printf(" Quake2(bsp only)");
#else
Con_Printf(" ^h(disabled: Quake2)^7");
#endif
#if defined(HEXEN2)
Con_Printf(" Hexen2");
#else
Con_Printf(" ^h(disabled: Hexen2)^7");
#endif
#if defined(NQPROT)
Con_Printf(" NetQuake");
#else
Con_Printf(" ^h(disabled: NetQuake)");
#endif
#if defined(VM_Q1)
Con_Printf(" ssq1qvm");
#endif
#if defined(VM_LUA)
Con_Printf(" ssq1lua(dynamic)");
#endif
#if defined(MENU_DAT)
Con_Printf(" menuqc");
#endif
#if defined(CSQC_DAT)
Con_Printf(" csqc");
#endif
#ifndef CLIENTONLY
Con_Printf(" ssqc");
#endif
Con_Printf("\n");
}
void COM_CrashMe_f(void)
@ -4501,6 +4684,325 @@ void COM_ErrorMe_f(void)
Sys_Error("\"errorme\" command used");
}
#ifdef LOADERTHREAD
/*multithreading worker thread stuff*/
static void *com_workercondition[2];
static qboolean com_workerdone[2];
static void *com_workerthread;
static unsigned int mainthreadid;
qboolean com_fatalerror;
static struct com_work_s
{
struct com_work_s *next;
void(*func)(void *ctx, void *data, size_t a, size_t b);
void *ctx;
void *data;
size_t a;
size_t b;
} *com_work_head[2], *com_work_tail[2];
static void Sys_ErrorThread(void *ctx, void *data, size_t a, size_t b)
{
Sys_Error(data);
}
void COM_WorkerAbort(char *message)
{
struct com_work_s work;
com_fatalerror = true;
if (Sys_IsThread(NULL))
return;
work.func = Sys_ErrorThread;
work.ctx = NULL;
work.data = message;
work.a = 0;
work.b = 0;
Sys_LockConditional(com_workercondition[0]);
if (com_work_tail[0])
{
com_work_tail[0]->next = &work;
com_work_tail[0] = &work;
}
else
com_work_head[0] = com_work_tail[0] = &work;
Sys_ConditionSignal(com_workercondition[0]);
Sys_UnlockConditional(com_workercondition[0]);
while(com_fatalerror)
Sys_Sleep(0.1);
Sys_ThreadAbort();
}
//return if there's *any* loading that needs to be done anywhere.
qboolean COM_HasWork(void)
{
return com_work_head[0] || com_work_head[1];
}
//thread==0 is main thread, thread==1 is a worker thread
void COM_AddWork(int thread, void(*func)(void *ctx, void *data, size_t a, size_t b), void *ctx, void *data, size_t a, size_t b)
{
//build the work
struct com_work_s *work = Z_Malloc(sizeof(*work));
work->func = func;
work->ctx = ctx;
work->data = data;
work->a = a;
work->b = b;
if (!com_workerthread || com_fatalerror)
thread = 0;
//queue it (fifo)
Sys_LockConditional(com_workercondition[thread]);
if (com_work_tail[thread])
{
com_work_tail[thread]->next = work;
com_work_tail[thread] = work;
}
else
com_work_head[thread] = com_work_tail[thread] = work;
// Sys_Printf("%x: Queued work %p (%s)\n", thread, work->ctx, work->ctx?(char*)work->ctx:"?");
Sys_ConditionSignal(com_workercondition[thread]);
Sys_UnlockConditional(com_workercondition[thread]);
if (!com_workerthread)
while(COM_DoWork(0, false))
;
}
//leavelocked = false == poll mode.
//leavelocked = true == safe sleeping
qboolean COM_DoWork(int thread, qboolean leavelocked)
{
struct com_work_s *work;
if (!leavelocked)
{
//skip the locks if it looks like we can be lazy.
if (!com_work_head[thread])
return false;
Sys_LockConditional(com_workercondition[thread]);
}
work = com_work_head[thread];
if (work)
com_work_head[thread] = work->next;
if (!com_work_head[thread])
com_work_head[thread] = com_work_tail[thread] = NULL;
if (work)
{
// Sys_Printf("%x: Doing work %p (%s)\n", thread, work->ctx, work->ctx?(char*)work->ctx:"?");
Sys_UnlockConditional(com_workercondition[thread]);
work->func(work->ctx, work->data, work->a, work->b);
Z_Free(work);
if (leavelocked)
Sys_LockConditional(com_workercondition[thread]);
return true; //did something, check again
}
if (!leavelocked)
Sys_UnlockConditional(com_workercondition[thread]);
//nothing going on, if leavelocked then noone can add anything until we sleep.
return false;
}
static int COM_WorkerThread(void *arg)
{
int thread = *(int*)arg;
Sys_LockConditional(com_workercondition[thread]);
do
{
while(COM_DoWork(thread, true))
;
if (com_workerdone[thread])
break;
} while (Sys_ConditionWait(com_workercondition[thread]));
Sys_UnlockConditional(com_workercondition[thread]);
return 0;
}
static void COM_WorkerSync_Stop(void *ctx, void *data, size_t a, size_t b)
{
Sys_LockConditional(com_workercondition[a]);
com_workerdone[a] = true;
Sys_ConditionSignal(com_workercondition[a]);
Sys_UnlockConditional(com_workercondition[a]);
}
#ifndef COM_AssertMainThread
void COM_AssertMainThread(const char *msg)
{
if (com_resourcemutex && !Sys_IsThread(NULL))
{
Sys_Error("Not on main thread: %s", msg);
}
}
#endif
void COM_DestroyWorkerThread(void)
{
com_fatalerror = false;
if (com_workerthread)
{
//send it the terminate message
COM_AddWork(1, COM_WorkerSync_Stop, NULL, NULL, 1, 0);
Sys_WaitOnThread(com_workerthread);
com_workerthread = NULL;
}
if (com_workercondition[0])
Sys_DestroyConditional(com_workercondition[0]);
com_workercondition[0] = NULL;
if (com_workercondition[1])
Sys_DestroyConditional(com_workercondition[1]);
com_workercondition[1] = NULL;
if (com_resourcemutex)
Sys_DestroyMutex(com_resourcemutex);
com_resourcemutex = NULL;
}
//partial means we're waiting for an explicit response. the caller will need to check when that response arrives.
void COM_WorkerFullSync(void)
{
qboolean repeat;
if (!com_workerthread)
return;
//main thread asks worker thread to set main thread's 'done' flag.
//the worker might be posting work to the main thread and back (shaders with texures) so make sure that the only work we do before the reply is the reply itself.
do
{
int cmds = 0;
com_workerdone[0] = false;
repeat = COM_HasWork();
COM_AddWork(1, COM_WorkerSync_Stop, NULL, NULL, 0, 0);
Sys_LockConditional(com_workercondition[0]);
do
{
if (com_fatalerror)
break;
while(COM_DoWork(0, true))
cmds++;
if (com_workerdone[0])
break;
} while (Sys_ConditionWait(com_workercondition[0]));
Sys_UnlockConditional(com_workercondition[0]);
if (com_fatalerror)
break;
if (cmds > 1)
repeat = true;
} while (COM_DoWork(0, false) || repeat); //outer loop ensures there isn't anything pingponging between
}
//main thread wants a specific object to be prioritised.
//an ancestor of the work must be pending on either the main thread or the worker thread.
//typically the worker gives us a signal to handle the final activation of the object.
//the address should be the load status. the value is the current value.
//the work that we're waiting for will be considered complete when the address is no longer set to value.
void COM_WorkerPartialSync(void *priorityctx, int *address, int value)
{
struct com_work_s **link, *work, *prev;
double time1 = Sys_DoubleTime();
int thread = 1;
// Con_Printf("waiting for %p %s\n", priorityctx, priorityctx);
//boost the priority of the object that we're waiting for on the other thread, if we can find it.
//this avoids waiting for everything.
//if we can't find it, then its probably currently being processed anyway.
//main thread is meant to do all loadstate value changes anyway, ensuring that we're woken up properly in this case.
if (priorityctx)
{
qboolean found = false;
Sys_LockConditional(com_workercondition[thread]);
for (link = &com_work_head[thread], work = NULL; *link; link = &(*link)->next)
{
prev = work;
work = *link;
if (work->ctx == priorityctx)
{ //unlink it
*link = work->next;
if (!work->next)
com_work_tail[thread] = prev;
//link it in at the head, so its the next thing seen.
work->next = com_work_head[thread];
com_work_head[thread] = work;
if (!work->next)
com_work_tail[thread] = work;
found = true;
break; //found it, nothing else to do.
}
}
if (!found)
Con_DPrintf("Might be in for a long wait for %s\n", priorityctx);
//we've not actually added any work, so no need to signal
Sys_UnlockConditional(com_workercondition[thread]);
}
Sys_LockConditional(com_workercondition[0]);
do
{
if (com_fatalerror)
break;
while(COM_DoWork(0, true))
{
//give up as soon as we're done
if (*address != value)
break;
}
//if our object's state has changed, we're done
if (*address != value)
break;
} while (Sys_ConditionWait(com_workercondition[0]));
Sys_UnlockConditional(com_workercondition[0]);
// Con_Printf("Waited %f for %s\n", Sys_DoubleTime() - time1, priorityctx);
}
static void COM_WorkerPing(void *ctx, void *data, size_t a, size_t b)
{
double *timestamp = data;
if (!b)
COM_AddWork(0, COM_WorkerPing, ctx, data , 0, 1);
else
{
Con_Printf("Ping: %g\n", Sys_DoubleTime() - *timestamp);
}
}
static void COM_WorkerTest_f(void)
{
if (com_workerthread)
{
double *timestamp = Z_Malloc(sizeof(*timestamp));
*timestamp = Sys_DoubleTime();
COM_AddWork(1, COM_WorkerPing, NULL, timestamp, 0, 0);
}
else
Con_Printf("Worker is not active.\n");
}
cvar_t worker_flush = CVARD("worker_flush", "1", "Is set, process the entire load queue, loading stuff faster but at the risk of stalling.");
static void COM_InitWorkerThread(void)
{
static int tid = 1;
//in theory, we could run multiple workers, signalling a different one in turn for each bit of work.
com_resourcemutex = Sys_CreateMutex();
com_workercondition[0] = Sys_CreateConditional();
com_workercondition[1] = Sys_CreateConditional();
if (!COM_CheckParm("-noworker"))
com_workerthread = Sys_CreateThread("loadworker", COM_WorkerThread, &tid, 0, 256*1024);
Cmd_AddCommand ("worker_test", COM_WorkerTest_f);
Cvar_Register(&worker_flush, NULL);
}
#endif
/*
================
COM_Init
@ -4532,6 +5034,13 @@ void COM_Init (void)
LittleFloat = FloatSwap;
}
#ifdef MULTITHREAD
Sys_ThreadsInit();
#endif
#ifdef LOADERTHREAD
COM_InitWorkerThread();
#endif
Cmd_AddCommand ("path", COM_Path_f); //prints a list of current search paths.
Cmd_AddCommand ("dir", COM_Dir_f); //q3 like
Cmd_AddCommand ("flocate", COM_Locate_f); //prints the pak or whatever where this file can be found.
@ -4548,6 +5057,7 @@ void COM_Init (void)
Cvar_Register (&gameversion_max, "Gamecode");
Cvar_Register (&com_nogamedirnativecode, "Gamecode");
Cvar_Register (&com_parseutf8, "Internationalisation");
Cvar_Register (&com_parseezquake, NULL);
Cvar_Register (&com_highlightcolor, "Internationalisation");
com_parseutf8.ival = 1;
@ -4585,6 +5095,8 @@ char *VARGS va(const char *format, ...)
static char string[VA_BUFFERS][1024];
static int bufnum;
COM_AssertMainThread("va");
bufnum++;
bufnum &= (VA_BUFFERS-1);
@ -4844,6 +5356,8 @@ char *Info_ValueForKey (const char *s, const char *key)
static int valueindex;
char *o;
COM_AssertMainThread("Info_ValueForKey");
valueindex = (valueindex + 1) % 4;
if (*s == '\\')
s++;

View File

@ -253,7 +253,8 @@ void QDECL Q_strncpyz(char*d, const char*s, int n);
#endif*/
/*replacement functions which do not care for locale in text formatting ('C' locale)*/
/*replacement functions which do not care for locale in text formatting ('C' locale), or are non-standard*/
char *Q_strcasestr(const char *haystack, const char *needle);
int Q_strncasecmp (const char *s1, const char *s2, int n);
int Q_strcasecmp (const char *s1, const char *s2);
int Q_atoi (const char *str);
@ -274,11 +275,11 @@ extern qboolean com_eof;
//char *COM_Parse (const char *data);
#define COM_Parse(d) COM_ParseOut(d,com_token, sizeof(com_token))
char *COM_ParseOut (const char *data, char *out, int outlen);
char *COM_ParseStringSet (const char *data);
char *COM_ParseStringSet (const char *data, char *out, size_t outlen);
char *COM_ParseCString (const char *data, char *out, size_t maxoutlen, size_t *writtenlen);
char *COM_StringParse (const char *data, char *token, unsigned int tokenlen, qboolean expandmacros, qboolean qctokenize);
char *COM_ParseToken (const char *data, const char *punctuation);
char *COM_TrimString(char *str);
char *COM_TrimString(char *str, char *buffer, int buffersize);
const char *COM_QuotedString(const char *string, char *buf, int buflen); //inverse of COM_StringParse
@ -291,13 +292,14 @@ void COM_AddParm (const char *parm);
void COM_Init (void);
void COM_InitArgv (int argc, const char **argv);
void COM_ParsePlusSets (void);
void COM_ParsePlusSets (qboolean docbuf);
typedef unsigned int conchar_t;
char *COM_DeFunString(conchar_t *str, conchar_t *stop, char *out, int outsize, qboolean ignoreflags);
#define PFS_KEEPMARKUP 1 //leave markup in the final string (but do parse it)
#define PFS_FORCEUTF8 2 //force utf-8 decoding
#define PFS_NOMARKUP 4 //strip markup completely
#define PFS_KEEPMARKUP 1 //leave markup in the final string (but do parse it)
#define PFS_FORCEUTF8 2 //force utf-8 decoding
#define PFS_NOMARKUP 4 //strip markup completely
#define PFS_EZQUAKEMARKUP 8 //aim for compat with ezquake instead of q3 compat
conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t *out, int outsize, int keepmarkup); //ext is usually CON_WHITEMASK, returns its null terminator
unsigned int utf8_decode(int *error, const void *in, char **out);
unsigned int utf8_encode(void *out, unsigned int unicode, int maxlen);
@ -326,7 +328,7 @@ void COM_FileBase (const char *in, char *out, int outlen);
int QDECL COM_FileSize(const char *path);
void COM_DefaultExtension (char *path, char *extension, int maxlen);
qboolean COM_RequireExtension(char *path, char *extension, int maxlen);
char *COM_FileExtension (const char *in);
char *COM_FileExtension (const char *in, char *result, size_t sizeofresult);
void COM_CleanUpPath(char *str);
char *VARGS va(const char *format, ...) LIKEPRINTF(1);
@ -335,7 +337,6 @@ char *VARGS va(const char *format, ...) LIKEPRINTF(1);
//============================================================================
extern qboolean com_file_copyprotected;
extern int com_filesize;
extern qboolean com_file_untrusted;
struct cache_user_s;
@ -386,15 +387,6 @@ char *FS_GetPackNames(char *buffer, int buffersize, int referencedonly, qboolean
qboolean FS_GenCachedPakName(char *pname, char *crc, char *local, int llen); //returns false if the name is invalid.
void FS_ReferenceControl(unsigned int refflag, unsigned int resetflags);
FTE_DEPRECATED int COM_FOpenFile (const char *filename, FILE **file);
FTE_DEPRECATED int COM_FOpenWriteFile (const char *filename, FILE **file);
//#ifdef _MSC_VER //this is enough to annoy me, without conflicting with other (more bizzare) platforms.
//#define fopen dont_use_fopen
//#endif
FTE_DEPRECATED void COM_CloseFile (FILE *h);
#define COM_FDepthFile(filename,ignorepacks) FS_FLocateFile(filename,ignorepacks?FSLFRT_DEPTH_OSONLY:FSLFRT_DEPTH_ANYPATH, NULL)
#define COM_FCheckExists(filename) FS_FLocateFile(filename,FSLFRT_IFFOUND, NULL)
@ -437,7 +429,7 @@ enum fs_relative{
FS_SYSTEM //a system path. absolute paths are explicitly allowed and expected.
};
void FS_FlushFSHashReally(void);
void FS_FlushFSHashReally(qboolean domutexes);
void FS_FlushFSHashWritten(void);
void FS_FlushFSHashRemoved(void);
void FS_CreatePath(const char *pname, enum fs_relative relativeto);
@ -460,14 +452,14 @@ void FS_PureMode(int mode, char *purenamelist, char *purecrclist, char *refnamel
//recursively tries to open files until it can get a zip.
vfsfile_t *CL_OpenFileInPackage(searchpathfuncs_t *search, char *name);
qbyte *QDECL COM_LoadStackFile (const char *path, void *buffer, int bufsize);
qbyte *COM_LoadTempFile (const char *path);
qbyte *COM_LoadTempMoreFile (const char *path); //allocates a little bit more without freeing old temp
qbyte *QDECL COM_LoadStackFile (const char *path, void *buffer, int bufsize, size_t *fsize);
qbyte *COM_LoadTempFile (const char *path, size_t *fsize);
qbyte *COM_LoadTempMoreFile (const char *path, size_t *fsize); //allocates a little bit more without freeing old temp
//qbyte *COM_LoadHunkFile (const char *path);
qbyte *COM_LoadMallocFile (const char *path);
qbyte *COM_LoadMallocFile (const char *path, size_t *fsize);
searchpathfuncs_t *COM_IteratePaths (void **iterator, char *pathbuffer, int pathbuffersize, char *dirname, int dirnamesize);
void COM_FlushFSCache(void); //a file was written using fopen
void COM_FlushFSCache(qboolean purge, qboolean domutex); //a file was written using fopen
void COM_RefreshFSCache_f(void);
qboolean FS_Restarted(unsigned int *since);
@ -510,12 +502,12 @@ char *FS_GetBasedir(void);
char *FS_GetManifestArgs(void);
struct zonegroup_s;
void *FS_LoadMallocGroupFile(struct zonegroup_s *ctx, char *path);
qbyte *FS_LoadMallocFile (const char *path);
void *FS_LoadMallocGroupFile(struct zonegroup_s *ctx, char *path, size_t *fsize);
qbyte *FS_LoadMallocFile (const char *path, size_t *fsize);
qofs_t FS_LoadFile(const char *name, void **file);
void FS_FreeFile(void *file);
qbyte *COM_LoadFile (const char *path, int usehunk);
qbyte *COM_LoadFile (const char *path, int usehunk, size_t *filesize);
qboolean COM_LoadMapPackFile(const char *name, qofs_t offset);
void COM_FlushTempoaryPacks(void);

View File

@ -175,12 +175,14 @@ void Con_CheckResize (void);
void Con_ForceActiveNow(void);
void Con_Init (void);
void Con_Shutdown (void);
void Con_History_Save(void);
void Con_History_Load(void);
struct font_s;
void Con_DrawOneConsole(console_t *con, struct font_s *font, float fx, float fy, float fsx, float fsy);
void Con_DrawConsole (int lines, qboolean noback);
char *Con_CopyConsole(qboolean nomarkup, qboolean onlyiflink);
void Con_Print (char *txt);
void Con_PrintFlags(char *text, unsigned int setflags, unsigned int clearflags);
void VARGS Con_Printf (const char *fmt, ...) LIKEPRINTF(1);
void VARGS Con_TPrintf (translation_t text, ...);
void VARGS Con_DPrintf (const char *fmt, ...) LIKEPRINTF(1);
@ -204,7 +206,7 @@ qboolean Con_NameForNum(int num, char *buffer, int buffersize);
console_t *Con_FindConsole(const char *name);
console_t *Con_Create(const char *name, unsigned int flags);
void Con_SetVisible (console_t *con);
void Con_PrintCon (console_t *con, char *txt);
void Con_PrintCon (console_t *con, char *txt, unsigned int parseflags);
void Con_NotifyBox (char *text); // during startup for sound / cd warnings

View File

@ -17,6 +17,7 @@ hashtable_t filesystemhash;
qboolean com_fschanged = true;
qboolean fs_readonly;
static unsigned int fs_restarts;
void *fs_thread_mutex;
cvar_t com_fs_cache = CVARF("fs_cache", IFMINIMAL("2","1"), CVAR_ARCHIVE);
cvar_t cfg_reload_on_gamedir = CVAR("cfg_reload_on_gamedir", "1");
@ -86,19 +87,22 @@ void FS_UnRegisterFileSystemModule(void *module)
{
int i;
qboolean found = false;
for (i = 0; i < sizeof(searchpathformats)/sizeof(searchpathformats[0]); i++)
if (Sys_LockMutex(fs_thread_mutex))
{
if (searchpathformats[i].module == module)
for (i = 0; i < sizeof(searchpathformats)/sizeof(searchpathformats[0]); i++)
{
searchpathformats[i].OpenNew = NULL;
searchpathformats[i].module = NULL;
found = true;
if (searchpathformats[i].module == module)
{
searchpathformats[i].OpenNew = NULL;
searchpathformats[i].module = NULL;
found = true;
}
}
Sys_UnlockMutex(fs_thread_mutex);
if (found)
{
Cmd_ExecuteString("fs_restart", RESTRICT_LOCAL);
}
}
if (found)
{
Cmd_ExecuteString("fs_restart", RESTRICT_LOCAL);
}
}
@ -158,7 +162,6 @@ char pubgamedirfile[MAX_OSPATH]; //like gamedirfile, but not set to the fte-only
//the various COM_LoadFiles set these on return
int com_filesize;
qboolean com_file_copyprotected;//file should not be available for download.
qboolean com_file_untrusted; //file was downloaded inside a package
@ -462,7 +465,11 @@ ftemanifest_t *FS_Manifest_Parse(const char *fname, const char *data)
{ //every manifest should have an internal name specified, so we can guess the correct basedir
//if we don't recognise it, then we'll typically prompt (or just use the working directory), but always assuming a default at least ensures things are sane.
//fixme: we should probably fill in the basegame here (and share that logic with the legacy manifest generation code)
#ifdef BRANDING_NAME
data = Cmd_TokenizeString((char*)"game "STRINGIFY(BRANDING_NAME), false, false);
#else
data = Cmd_TokenizeString((char*)"game quake", false, false);
#endif
FS_Manifest_ParseTokens(man);
}
@ -494,6 +501,7 @@ typedef struct searchpath_s
char purepath[256]; //server tracks the path used to load them so it can tell the client
int crc_check; //client sorts packs according to this checksum
int crc_reply; //client sends a different crc back to the server, for the paks it's actually loaded.
int orderkey; //used to check to see if the paths were actually changed or not.
struct searchpath_s *next;
struct searchpath_s *nextpure;
@ -750,23 +758,30 @@ struct fsbucketblock
};
static struct fsbucketblock *fs_hash_filebuckets;
void FS_FlushFSHashReally(void)
void FS_FlushFSHashReally(qboolean domutexes)
{
if (filesystemhash.numbuckets)
COM_AssertMainThread("FS_FlushFSHashReally");
if (!domutexes || Sys_LockMutex(fs_thread_mutex))
{
int i;
for (i = 0; i < filesystemhash.numbuckets; i++)
filesystemhash.bucket[i] = NULL;
}
com_fschanged = true;
while (fs_hash_filebuckets)
{
struct fsbucketblock *n = fs_hash_filebuckets->prev;
Z_Free(fs_hash_filebuckets);
fs_hash_filebuckets = n;
}
if (filesystemhash.numbuckets)
{
int i;
for (i = 0; i < filesystemhash.numbuckets; i++)
filesystemhash.bucket[i] = NULL;
}
com_fschanged = true;
while (fs_hash_filebuckets)
{
struct fsbucketblock *n = fs_hash_filebuckets->prev;
Z_Free(fs_hash_filebuckets);
fs_hash_filebuckets = n;
}
if (domutexes)
Sys_UnlockMutex(fs_thread_mutex);
}
}
void FS_FlushFSHashWritten(void)
{
@ -774,7 +789,7 @@ void FS_FlushFSHashWritten(void)
}
void FS_FlushFSHashRemoved(void)
{
FS_FlushFSHashReally();
FS_FlushFSHashReally(true);
}
static void QDECL FS_AddFileHash(int depth, const char *fname, fsbucket_t *filehandle, void *pathhandle)
@ -819,13 +834,18 @@ static void QDECL FS_AddFileHash(int depth, const char *fname, fsbucket_t *fileh
fs_hash_files++;
}
void FS_RebuildFSHash(void)
void FS_RebuildFSHash(qboolean domutex)
{
int depth = 1;
searchpath_t *search;
if (!com_fschanged)
return;
COM_AssertMainThread("FS_RebuildFSHash");
if (domutex && !Sys_LockMutex(fs_thread_mutex))
return; //amg!
if (!filesystemhash.numbuckets)
{
filesystemhash.numbuckets = 1024;
@ -833,7 +853,7 @@ void FS_RebuildFSHash(void)
}
else
{
FS_FlushFSHashRemoved();
FS_FlushFSHashReally(false);
}
Hash_InitTable(&filesystemhash, filesystemhash.numbuckets, filesystemhash.bucket);
@ -857,6 +877,9 @@ void FS_RebuildFSHash(void)
com_fschanged = false;
if (domutex)
Sys_UnlockMutex(fs_thread_mutex);
Con_DPrintf("%i unique files, %i duplicates\n", fs_hash_files, fs_hash_dups);
}
@ -1578,12 +1601,11 @@ Filename are reletive to the quake directory.
Always appends a 0 qbyte to the loaded data.
============
*/
qbyte *COM_LoadFile (const char *path, int usehunk)
qbyte *COM_LoadFile (const char *path, int usehunk, size_t *filesize)
{
vfsfile_t *f;
qbyte *buf;
qofs_t len;
char base[MAX_OSPATH];
flocation_t loc;
FS_FLocateFile(path, FSLFRT_LENGTH, &loc);
@ -1597,9 +1619,12 @@ qbyte *COM_LoadFile (const char *path, int usehunk)
if (!f)
return NULL;
com_filesize = len = VFS_GETLEN(f);
// extract the filename base name for hunk tag
COM_FileBase (path, base, sizeof(base));
len = VFS_GETLEN(f);
if (filesize)
*filesize = len;
if (usehunk == 2 || usehunk == 4 || usehunk == 6)
COM_AssertMainThread("COM_LoadFile+hunk");
if (usehunk == 0)
buf = (qbyte*)Z_Malloc (len+1);
@ -1633,12 +1658,12 @@ qbyte *COM_LoadFile (const char *path, int usehunk)
return buf;
}
qbyte *FS_LoadMallocFile (const char *path)
qbyte *FS_LoadMallocFile (const char *path, size_t *fsize)
{
return COM_LoadFile (path, 5);
return COM_LoadFile (path, 5, fsize);
}
void *FS_LoadMallocGroupFile(zonegroup_t *ctx, char *path)
void *FS_LoadMallocGroupFile(zonegroup_t *ctx, char *path, size_t *fsize)
{
char *mem = NULL;
vfsfile_t *f = FS_OpenVFS(path, "rb", FS_GAME);
@ -1650,7 +1675,7 @@ void *FS_LoadMallocGroupFile(zonegroup_t *ctx, char *path)
{
mem[len] = 0;
if (VFS_READ(f, mem, len) == len)
com_filesize = len;
*fsize = len;
else
mem = NULL;
}
@ -1660,23 +1685,25 @@ void *FS_LoadMallocGroupFile(zonegroup_t *ctx, char *path)
return mem;
}
qbyte *COM_LoadTempFile (const char *path)
qbyte *COM_LoadTempFile (const char *path, size_t *fsize)
{
return COM_LoadFile (path, 2);
return COM_LoadFile (path, 2, fsize);
}
qbyte *COM_LoadTempMoreFile (const char *path)
qbyte *COM_LoadTempMoreFile (const char *path, size_t *fsize)
{
return COM_LoadFile (path, 6);
return COM_LoadFile (path, 6, fsize);
}
// uses temp hunk if larger than bufsize
qbyte *QDECL COM_LoadStackFile (const char *path, void *buffer, int bufsize)
qbyte *QDECL COM_LoadStackFile (const char *path, void *buffer, int bufsize, size_t *fsize)
{
qbyte *buf;
COM_AssertMainThread("COM_LoadStackFile");
loadbuf = (qbyte *)buffer;
loadsize = bufsize;
buf = COM_LoadFile (path, 4);
buf = COM_LoadFile (path, 4, fsize);
return buf;
}
@ -1685,10 +1712,11 @@ qbyte *QDECL COM_LoadStackFile (const char *path, void *buffer, int bufsize)
/*warning: at some point I'll change this function to return only read-only buffers*/
qofs_t FS_LoadFile(const char *name, void **file)
{
*file = FS_LoadMallocFile(name);
size_t fsz;
*file = COM_LoadFile (name, 5, &fsz);
if (!*file)
return (qofs_t)-1;
return com_filesize;
return fsz;
}
void FS_FreeFile(void *file)
{
@ -1825,7 +1853,8 @@ searchpathfuncs_t *FS_OpenPackByExtension(vfsfile_t *f, const char *pakname)
{
searchpathfuncs_t *pak;
int j;
char *ext = COM_FileExtension(pakname);
char ext[8];
COM_FileExtension(pakname, ext, sizeof(ext));
for (j = 0; j < sizeof(searchpathformats)/sizeof(searchpathformats[0]); j++)
{
if (!searchpathformats[j].extension || !searchpathformats[j].OpenNew)
@ -1899,7 +1928,8 @@ static void FS_AddDataFiles(searchpath_t **oldpaths, const char *purepath, const
ptlen = strlen(purepath);
for (i = 0; i < sizeof(fs_manifest->package) / sizeof(fs_manifest->package[0]); i++)
{
if (fs_manifest->package[i].path && !strcmp(COM_FileExtension(fs_manifest->package[i].path), extension))
char ext[8];
if (fs_manifest->package[i].path && !strcmp(COM_FileExtension(fs_manifest->package[i].path, ext, sizeof(ext)), extension))
{
palen = strlen(fs_manifest->package[i].path);
if (palen > ptlen && (fs_manifest->package[i].path[ptlen] == '/' || fs_manifest->package[i].path[ptlen] == '\\' )&& !strncmp(purepath, fs_manifest->package[i].path, ptlen))
@ -2017,7 +2047,8 @@ void COM_RefreshFSCache_f(void)
com_fschanged=true;
}
void COM_FlushFSCache(void)
//optionally purges the cache and rebuilds it
void COM_FlushFSCache(qboolean purge, qboolean domutex)
{
searchpath_t *search;
if (com_fs_cache.ival && com_fs_cache.ival != 2)
@ -2036,7 +2067,7 @@ void COM_FlushFSCache(void)
if (com_fs_cache.ival && com_fschanged)
{
//rebuild it if needed
FS_RebuildFSHash();
FS_RebuildFSHash(domutex);
}
#endif
}
@ -2218,16 +2249,17 @@ void COM_Gamedir (const char *dir)
FS_Manifest_PurgeGamedirs(man);
if (*dir)
{
char *dup = Z_StrDup(dir);
char token[MAX_QPATH];
char *dup = Z_StrDup(dir); //FIXME: is this really needed?
dir = dup;
while ((dir = COM_ParseStringSet(dir)))
while ((dir = COM_ParseStringSet(dir, token, sizeof(token))))
{
if (!strcmp(dir, ";"))
continue;
if (!*com_token)
if (!*token)
continue;
Cmd_TokenizeString(va("gamedir \"%s\"", com_token), false, false);
Cmd_TokenizeString(va("gamedir \"%s\"", token), false, false);
FS_Manifest_ParseTokens(man);
}
Z_Free(dup);
@ -2243,7 +2275,7 @@ void COM_Gamedir (const char *dir)
/*some modern non-compat settings*/
#define DMFCFG "set com_parseutf8 1\npm_airstep 1\nsv_demoExtensions 1\n"
/*set some stuff so our regular qw client appears more like hexen2. sv_mintic is required to 'fix' the ravenstaff so that its projectiles don't impact upon each other*/
#define HEX2CFG "set com_parseutf8 -1\nset gl_font gfx/hexen2\nset in_builtinkeymap 0\nset_calc cl_playerclass int (random * 5) + 1\nset sv_maxspeed 640\ncl_run 0\nset watervis 1\nset r_lavaalpha 1\nset r_lavastyle -2\nset r_wateralpha 0.5\nset sv_pupglow 1\ngl_shaftlight 0.5\nsv_mintic 0.015\nset cl_model_bobbing 1\nsv_sound_land \"fx/thngland.wav\"\n"
#define HEX2CFG "set com_parseutf8 -1\nset gl_font gfx/hexen2\nset in_builtinkeymap 0\nset_calc cl_playerclass int (random * 5) + 1\nset sv_maxspeed 640\ncl_run 0\nset watervis 1\nset r_lavaalpha 1\nset r_lavastyle -2\nset r_wateralpha 0.5\nset sv_pupglow 1\ngl_shaftlight 0.5\nsv_mintic 0.015\nset mod_warnmodels 0\nset cl_model_bobbing 1\nsv_sound_land \"fx/thngland.wav\"\n"
/*yay q2!*/
#define Q2CFG "com_nogamedirnativecode 0\n"
/*Q3's ui doesn't like empty model/headmodel/handicap cvars, even if the gamecode copes*/
@ -2288,26 +2320,28 @@ const gamemode_info_t gamemode_info[] = {
"basesj/pak0.pak"}, NULL, {"basesj", }, "Scouts Journey"},
{"-rmq", "rmq", "RMQ", {NULL}, RMQCFG, {"id1", "qw", "rmq", "*fte"}, "Remake Quake"},
//supported commercial mods (some are currently only partially supported)
#ifdef HEXEN2
//hexen2's mission pack generally takes precedence if both are installed.
{"-portals", "h2mp", "FTE-H2MP", {"portals/hexen.rc",
"portals/pak3.pak"}, HEX2CFG,{"data1", "portals", "*fteh2"}, "Hexen II MP"},
{"-hexen2", "hexen2", "FTE-Hexen2", {"data1/pak0.pak"}, HEX2CFG,{"data1", "*fteh2"}, "Hexen II"},
#endif
#if defined(Q2CLIENT) || defined(Q2SERVER)
{"-quake2", "q2", "FTE-Quake2", {"baseq2/pak0.pak"}, Q2CFG, {"baseq2", "*fteq2"}, "Quake II"},
{"-quake3", "q3", "FTE-Quake3", {"baseq3/pak0.pk3"}, Q3CFG, {"baseq3", "*fteq3"}, "Quake III Arena"},
//mods of the above that should generally work.
{"-dday", "dday", "FTE-Quake2", {"dday/pak0.pak"}, Q2CFG, {"baseq2", "dday", "*fteq2"}, "D-Day: Normandy"},
#endif
//can run in windows, needs
{"-halflife", "hl", "FTE-HalfLife", {"valve/liblist.gam"}, NULL, {"valve", "*ftehl"}, "Half-Life"},
#if defined(Q3CLIENT) || defined(Q3SERVER)
{"-quake3", "q3", "FTE-Quake3", {"baseq3/pak0.pk3"}, Q3CFG, {"baseq3", "*fteq3"}, "Quake III Arena"},
//the rest are not supported in any real way. maps-only mostly, if that
{"-quake4", "q4", "FTE-Quake4", {"q4base/pak00.pk4"}, NULL, {"q4base", "*fteq4"}, "Quake 4"},
{"-et", "et", "FTE-EnemyTerritory", {"etmain/pak0.pk3"}, NULL, {"etmain", "*fteet"}, "Wolfenstein - Enemy Territory"},
{"-et", NULL, "FTE-EnemyTerritory", {"etmain/pak0.pk3"}, NULL, {"etmain", "*fteet"}, "Wolfenstein - Enemy Territory"},
{"-jk2", "jk2", "FTE-JK2", {"base/assets0.pk3"}, NULL, {"base", "*ftejk2"}, "Jedi Knight II: Jedi Outcast"},
{"-warsow", "warsow", "FTE-Warsow", {"basewsw/pak0.pk3"}, NULL, {"basewsw", "*ftewsw"}, "Warsow"},
#endif
#if !defined(QUAKETC) && !defined(MINIMAL)
{"-doom", "doom", "FTE-Doom", {"doom.wad"}, NULL, {"*", "*ftedoom"}, "Doom"},
{"-doom2", "doom2", "FTE-Doom2", {"doom2.wad"}, NULL, {"*", "*ftedoom"}, "Doom2"},
{"-doom3", "doom3", "FTE-Doom3", {"doom3.wad"}, NULL, {"based3", "*ftedoom3"},"Doom3"},
@ -2315,6 +2349,10 @@ const gamemode_info_t gamemode_info[] = {
//for the luls
{"-diablo2", NULL, "FTE-Diablo2", {"d2music.mpq"}, NULL, {"*", "*fted2"}, "Diablo 2"},
//can run in windows, needs hl gamecode enabled.
{"-halflife", "halflife", "FTE-HalfLife", {"valve/liblist.gam"}, NULL, {"valve", "*ftehl"}, "Half-Life"},
#endif
{NULL}
};
@ -2401,7 +2439,7 @@ vfsfile_t *CL_OpenFileInPackage(searchpathfuncs_t *search, char *name)
vfsfile_t *f;
flocation_t loc;
char e, *n;
char *ext;
char ext[8];
char *end;
int i;
@ -2429,7 +2467,7 @@ vfsfile_t *CL_OpenFileInPackage(searchpathfuncs_t *search, char *name)
}
else
{
ext = COM_FileExtension(name);
COM_FileExtension(name, ext, sizeof(ext));
for (i = 0; i < sizeof(searchpathformats)/sizeof(searchpathformats[0]); i++)
{
if (!searchpathformats[i].extension || !searchpathformats[i].OpenNew)
@ -2556,8 +2594,19 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags)
searchpath_t *oldpaths;
searchpath_t *next;
int i;
int orderkey;
char syspath[MAX_OSPATH];
FS_FlushFSHashReally();
COM_AssertMainThread("FS_ReloadPackFilesFlags");
COM_WorkerFullSync();
orderkey = 0;
if (com_purepaths)
for (next = com_purepaths; next; next = next->nextpure)
next->orderkey = ++orderkey;
if (fs_puremode < 2)
for (next = com_purepaths; next; next = next->nextpure)
next->orderkey = ++orderkey;
oldpaths = com_searchpaths;
com_searchpaths = NULL;
@ -2616,15 +2665,23 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags)
else if (*dir == '*')
{
//paths with a leading * are private, and not announced to clients that ask what the current gamedir is.
FS_AddGameDirectory(&oldpaths, dir+1, va("%s%s", com_gamepath, dir+1), reloadflags, SPF_EXPLICIT|SPF_PRIVATE);
Q_snprintfz(syspath, sizeof(syspath), "%s%s", com_gamepath, dir+1);
FS_AddGameDirectory(&oldpaths, dir+1, syspath, reloadflags, SPF_EXPLICIT|SPF_PRIVATE);
if (com_homepathenabled)
FS_AddGameDirectory(&oldpaths, dir+1, va("%s%s", com_homepath, dir+1), reloadflags, SPF_EXPLICIT|SPF_PRIVATE);
{
Q_snprintfz(syspath, sizeof(syspath), "%s%s", com_homepath, dir+1);
FS_AddGameDirectory(&oldpaths, dir+1, syspath, reloadflags, SPF_EXPLICIT|SPF_PRIVATE);
}
}
else
{
FS_AddGameDirectory(&oldpaths, dir, va("%s%s", com_gamepath, dir), reloadflags, SPF_EXPLICIT);
Q_snprintfz(syspath, sizeof(syspath), "%s%s", com_gamepath, dir);
FS_AddGameDirectory(&oldpaths, dir, syspath, reloadflags, SPF_EXPLICIT);
if (com_homepathenabled)
FS_AddGameDirectory(&oldpaths, dir, va("%s%s", com_homepath, dir), reloadflags, SPF_EXPLICIT);
{
Q_snprintfz(syspath, sizeof(syspath), "%s%s", com_homepath, dir);
FS_AddGameDirectory(&oldpaths, dir, syspath, reloadflags, SPF_EXPLICIT);
}
}
}
}
@ -2746,9 +2803,10 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags)
{
char local[MAX_OSPATH];
vfsfile_t *vfs;
char *ext = COM_FileExtension(pname);
char ext[8];
void *handle;
int i;
COM_FileExtension(pname, ext, sizeof(ext));
if (FS_GenCachedPakName(pname, va("%i", crc), local, sizeof(local)))
{
@ -2825,6 +2883,21 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags)
}
i = orderkey;
orderkey = 0;
next = NULL;
if (com_purepaths)
for (next = com_purepaths; next; next = next->nextpure)
if (next->orderkey != ++orderkey)
break;
if (!next && fs_puremode < 2)
for (next = com_purepaths; next; next = next->nextpure)
if (next->orderkey != ++orderkey)
break;
if (next || i != orderkey)//some path changed. make sure the fs cache is flushed.
FS_FlushFSHashReally(false);
#ifndef SERVERONLY
Shader_NeedReload(true);
#endif
@ -2834,20 +2907,32 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags)
void FS_UnloadPackFiles(void)
{
FS_ReloadPackFilesFlags(1);
if (Sys_LockMutex(fs_thread_mutex))
{
FS_ReloadPackFilesFlags(1);
Sys_UnlockMutex(fs_thread_mutex);
}
}
void FS_ReloadPackFiles(void)
{
FS_ReloadPackFilesFlags(~0);
if (Sys_LockMutex(fs_thread_mutex))
{
FS_ReloadPackFilesFlags(~0);
Sys_UnlockMutex(fs_thread_mutex);
}
}
void FS_ReloadPackFiles_f(void)
{
if (atoi(Cmd_Argv(1)))
FS_ReloadPackFilesFlags(atoi(Cmd_Argv(1)));
else
FS_ReloadPackFilesFlags(~0);
if (Sys_LockMutex(fs_thread_mutex))
{
if (atoi(Cmd_Argv(1)))
FS_ReloadPackFilesFlags(atoi(Cmd_Argv(1)));
else
FS_ReloadPackFilesFlags(~0);
Sys_UnlockMutex(fs_thread_mutex);
}
}
#if defined(_WIN32) && !defined(WINRT)
@ -3120,10 +3205,10 @@ qboolean Sys_FindGameData(const char *poshname, const char *gamename, char *base
}
#endif
void FS_Shutdown(void)
static void FS_FreePaths(void)
{
searchpath_t *next;
FS_FlushFSHashReally();
FS_FlushFSHashReally(true);
//
// free up any current game dir info
@ -3149,6 +3234,12 @@ void FS_Shutdown(void)
FS_Manifest_Free(fs_manifest);
fs_manifest = NULL;
}
void FS_Shutdown(void)
{
FS_FreePaths();
Sys_DestroyMutex(fs_thread_mutex);
fs_thread_mutex = NULL;
}
//returns false if the directory is not suitable.
//returns true if it contains a known package. if we don't actually know of any packages that it should have, we just have to assume that its okay.
@ -3591,7 +3682,11 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs)
if (!man)
{
vfsfile_t *f;
f = VFSOS_Open(va("%sdefault.fmf", newbasedir), "rb");
#ifdef BRANDING_NAME
f = VFSOS_Open(va("%s"STRINGIFY(BRANDING_NAME)".fmf", newbasedir), "rb");
if (!f)
#endif
f = VFSOS_Open(va("%sdefault.fmf", newbasedir), "rb");
if (f)
{
size_t len = VFS_GETLEN(f);
@ -3641,7 +3736,7 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs)
}
else
{
FS_Shutdown();
FS_FreePaths();
reloadconfigs = true;
}
@ -3714,48 +3809,53 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs)
}
#endif
FS_ReloadPackFilesFlags(~0);
FS_BeginManifestUpdates();
COM_CheckRegistered();
if (allowreloadconfigs)
if (Sys_LockMutex(fs_thread_mutex))
{
for (i = 0; conffile[i]; i++)
FS_ReloadPackFilesFlags(~0);
FS_BeginManifestUpdates();
COM_CheckRegistered();
Sys_UnlockMutex(fs_thread_mutex);
if (allowreloadconfigs)
{
FS_FLocateFile(conffile[i], FSLFRT_IFFOUND, &loc);
if (confpath[i] != (loc.search?loc.search->handle:NULL))
for (i = 0; conffile[i]; i++)
{
reloadconfigs = true;
Con_DPrintf("Reloading configs because %s has changed\n", conffile[i]);
FS_FLocateFile(conffile[i], FSLFRT_IFFOUND, &loc);
if (confpath[i] != (loc.search?loc.search->handle:NULL))
{
reloadconfigs = true;
Con_DPrintf("Reloading configs because %s has changed\n", conffile[i]);
}
}
if (reloadconfigs)
{
//FIXME: flag this instead and do it after a delay
Cvar_ForceSet(&fs_gamename, man->formalname?man->formalname:"FTE");
Cvar_ForceSet(&com_protocolname, man->protocolname?man->protocolname:"FTE");
if (isDedicated)
{
#ifndef CLIENTONLY
SV_ExecInitialConfigs(man->defaultexec?man->defaultexec:"");
#endif
}
else
{
#ifndef SERVERONLY
CL_ExecInitialConfigs(man->defaultexec?man->defaultexec:"");
#endif
}
}
}
if (reloadconfigs)
{
//FIXME: flag this instead and do it after a delay
Cvar_ForceSet(&fs_gamename, man->formalname?man->formalname:"FTE");
Cvar_ForceSet(&com_protocolname, man->protocolname?man->protocolname:"FTE");
if (isDedicated)
{
#ifndef CLIENTONLY
SV_ExecInitialConfigs(man->defaultexec?man->defaultexec:"");
#endif
}
else
{
#ifndef SERVERONLY
CL_ExecInitialConfigs(man->defaultexec?man->defaultexec:"");
#endif
}
}
//rebuild the cache now, should be safe to waste some cycles on it
COM_FlushFSCache(false, true);
}
//rebuild the cache now, should be safe to waste some cycles on it
FS_RebuildFSHash();
// COM_Effectinfo_Clear();
#ifndef SERVERONLY
Validation_FlushFileList(); //prevent previous hacks from making a difference.
@ -3916,6 +4016,33 @@ void FS_ShowManifest_f(void)
else
Con_Printf("no manifest loaded...\n");
}
int FS_ThreadTest(void*arg)
{
vfsfile_t *f = NULL;
char startdata[256];
char lastdata[256];
while(!f)
{
if (Sys_LockMutex(fs_thread_mutex))
{
f = FS_OpenVFS("gfx/pop.lmp", "rb", FS_GAME);
Sys_UnlockMutex(fs_thread_mutex);
}
}
VFS_READ(f, startdata, sizeof(startdata));
VFS_CLOSE(f);
for(;;)
{
Sys_LockMutex(fs_thread_mutex);
f = FS_OpenVFS("gfx/pop.lmp", "rb", FS_GAME);
Sys_UnlockMutex(fs_thread_mutex);
VFS_READ(f, lastdata, sizeof(lastdata));
VFS_CLOSE(f);
if (memcmp(startdata, lastdata, sizeof(lastdata)))
Con_Printf("FS_ThreadTest failed\n");
}
}
/*
================
COM_InitFilesystem
@ -4075,6 +4202,8 @@ void COM_InitFilesystem (void)
if (com_homepathenabled)
Con_TPrintf("Using home directory \"%s\"\n", com_homepath);
fs_thread_mutex = Sys_CreateMutex();
#ifdef PLUGINS
Plug_Initialise(false);
#endif

View File

@ -1,7 +1,16 @@
#include "hash.h"
/*
Threading:
When the main thread will harm the filesystem tree/hash, it will first lock fs_thread_mutex (FIXME: make a proper rwlock).
Worker threads must thus lock that mutex for any opens (to avoid it changing underneath it), but can unlock it as soon as the open call returns.
Files may be shared between threads, but not simultaneously.
The filesystem driver is responsible for closing the pak/pk3 once all files are closed, and must ensure that opens+reads+closes as well as archive closure are thread safe.
*/
#define FSVER 2
#define FF_NOTFOUND (0u) //file wasn't found
#define FF_FOUND (1u<<0u) //file was found
#define FF_SYMLINK (1u<<1u) //file contents are the name of a different file (symlink). do a recursive lookup on the name
@ -16,6 +25,7 @@ extern hashtable_t filesystemhash; //this table is the one to build your hash re
extern int fs_hash_dups; //for tracking efficiency. no functional use.
extern int fs_hash_files; //for tracking efficiency. no functional use.
extern qboolean fs_readonly; //if true, fopen(, "w") should always fail.
extern void *fs_thread_mutex;
struct searchpath_s;
struct searchpathfuncs_s

View File

@ -17,10 +17,12 @@ typedef struct pack_s
{
searchpathfuncs_t pub;
char descname[MAX_OSPATH];
vfsfile_t *handle;
unsigned int filepos; //the pos the subfiles left it at (to optimize calls to vfs_seek)
int numfiles;
mpackfile_t *files;
void *mutex;
vfsfile_t *handle;
unsigned int filepos; //the pos the subfiles left it at (to optimize calls to vfs_seek)
int references; //seeing as all vfiles from a pak file use the parent's vfsfile, we need to keep the parent open until all subfiles are closed.
} pack_t;
@ -65,14 +67,20 @@ static void QDECL FSPAK_GetPathDetails(searchpathfuncs_t *handle, char *out, siz
}
static void QDECL FSPAK_ClosePath(searchpathfuncs_t *handle)
{
qboolean stillopen;
pack_t *pak = (void*)handle;
pak->references--;
if (pak->references > 0)
if (!Sys_LockMutex(pak->mutex))
return; //ohnoes
stillopen = --pak->references > 0;
Sys_UnlockMutex(pak->mutex);
if (stillopen)
return; //not free yet
VFS_CLOSE (pak->handle);
Sys_DestroyMutex(pak->mutex);
if (pak->files)
Z_Free(pak->files);
Z_Free(pak);
@ -193,11 +201,17 @@ static int QDECL VFSPAK_ReadBytes (struct vfsfile_s *vfs, void *buffer, int byte
return -1;
}
if (vfsp->parentpak->filepos != vfsp->currentpos)
VFS_SEEK(vfsp->parentpak->handle, vfsp->currentpos);
read = VFS_READ(vfsp->parentpak->handle, buffer, bytestoread);
vfsp->currentpos += read;
vfsp->parentpak->filepos = vfsp->currentpos;
if (Sys_LockMutex(vfsp->parentpak->mutex))
{
if (vfsp->parentpak->filepos != vfsp->currentpos)
VFS_SEEK(vfsp->parentpak->handle, vfsp->currentpos);
read = VFS_READ(vfsp->parentpak->handle, buffer, bytestoread);
vfsp->currentpos += read;
vfsp->parentpak->filepos = vfsp->currentpos;
Sys_UnlockMutex(vfsp->parentpak->mutex);
}
else
read = 0;
return read;
}
@ -243,7 +257,13 @@ static vfsfile_t *QDECL FSPAK_OpenVFS(searchpathfuncs_t *handle, flocation_t *lo
vfs = Z_Malloc(sizeof(vfspack_t));
vfs->parentpak = pack;
if (!Sys_LockMutex(pack->mutex))
{
Z_Free(vfs);
return NULL;
}
vfs->parentpak->references++;
Sys_UnlockMutex(pack->mutex);
vfs->startpos = loc->offset;
vfs->length = loc->len;
@ -364,6 +384,8 @@ searchpathfuncs_t *QDECL FSPAK_LoadArchive (vfsfile_t *file, const char *desc)
pack->references++;
pack->mutex = Sys_CreateMutex();
// Con_TPrintf ("Added packfile %s (%i files)\n", desc, numpackfiles);
pack->pub.fsver = FSVER;

View File

@ -197,7 +197,7 @@ vfsfile_t *VFSOS_Open(const char *osname, const char *mode)
qboolean needsflush;
f = VFSSTDIO_Open(osname, mode, &needsflush);
if (needsflush)
FS_FlushFSHashReally();
FS_FlushFSHashReally(true);
return f;
}
#endif

View File

@ -264,13 +264,12 @@ typedef struct zipfile_s
unsigned int numfiles;
zpackfile_t *files;
#ifdef HASH_FILESYSTEM
hashtable_t hash;
#endif
//info about the underlying file
void *mutex;
qofs_t curpos; //cache position to avoid excess seeks
qofs_t rawsize;
vfsfile_t *raw;
int references; //number of files open inside, so things don't crash if is closed in the wrong order.
} zipfile_t;
@ -286,12 +285,18 @@ static void QDECL FSZIP_GetPathDetails(searchpathfuncs_t *handle, char *out, siz
}
static void QDECL FSZIP_ClosePath(searchpathfuncs_t *handle)
{
qboolean stillopen;
zipfile_t *zip = (void*)handle;
if (--zip->references > 0)
return; //not yet time
if (!Sys_LockMutex(zip->mutex))
return; //ohnoes
stillopen = --zip->references > 0;
Sys_UnlockMutex(zip->mutex);
if (stillopen)
return; //not free yet
VFS_CLOSE(zip->raw);
Sys_DestroyMutex(zip->mutex);
if (zip->files)
Z_Free(zip->files);
Z_Free(zip);
@ -483,8 +488,14 @@ qofs_t FSZIP_Decompress_Read(struct decompressstate *st, qbyte *buffer, qofs_t b
if (sz)
{
//feed it.
VFS_SEEK(st->source->raw, st->cofs);
st->strm.avail_in = VFS_READ(st->source->raw, st->inbuffer, sz);
if (Sys_LockMutex(st->source->mutex))
{
VFS_SEEK(st->source->raw, st->cofs);
st->strm.avail_in = VFS_READ(st->source->raw, st->inbuffer, sz);
Sys_UnlockMutex(st->source->mutex);
}
else
st->strm.avail_in = 0;
st->strm.next_in = st->inbuffer;
st->cofs += st->strm.avail_in;
}
@ -532,13 +543,16 @@ static int QDECL VFSZIP_ReadBytes (struct vfsfile_s *file, void *buffer, int byt
{
read = FSZIP_Decompress_Read(vfsz->decompress, buffer, bytestoread);
}
else
else if (Sys_LockMutex(vfsz->parent->mutex))
{
VFS_SEEK(vfsz->parent->raw, vfsz->pos+vfsz->startpos);
if (vfsz->pos + bytestoread > vfsz->length)
bytestoread = max(0, vfsz->length - vfsz->pos);
read = VFS_READ(vfsz->parent->raw, buffer, bytestoread);
Sys_UnlockMutex(vfsz->parent->mutex);
}
else
read = 0;
vfsz->pos += read;
return read;
@ -677,7 +691,18 @@ static vfsfile_t *QDECL FSZIP_OpenVFS(searchpathfuncs_t *handle, flocation_t *lo
}
}
zip->references++;
if (Sys_LockMutex(zip->mutex))
{
zip->references++;
Sys_UnlockMutex(zip->mutex);
}
else
{
if (vfsz->decompress)
FSZIP_Decompress_Destroy(vfsz->decompress);
Z_Free(vfsz);
return NULL;
}
return (vfsfile_t*)vfsz;
}
@ -784,8 +809,12 @@ static qboolean FSZIP_ValidateLocalHeader(zipfile_t *zip, zpackfile_t *zfile, qo
qbyte localdata[SIZE_LOCALENTRY];
qofs_t localstart = zfile->localpos;
if (!Sys_LockMutex(zip->mutex))
return false; //ohnoes
VFS_SEEK(zip->raw, localstart);
VFS_READ(zip->raw, localdata, sizeof(localdata));
Sys_UnlockMutex(zip->mutex);
//make sure we found the right sort of table.
if (localdata[0] != 'P' ||
@ -818,8 +847,11 @@ static qboolean FSZIP_ValidateLocalHeader(zipfile_t *zip, zpackfile_t *zfile, qo
unsigned short extrachunk_tag;
unsigned short extrachunk_len;
if (!Sys_LockMutex(zip->mutex))
return false; //ohnoes
VFS_SEEK(zip->raw, localstart);
VFS_READ(zip->raw, extradata, sizeof(extradata));
Sys_UnlockMutex(zip->mutex);
while(extra+4 < extraend)
@ -1278,6 +1310,7 @@ searchpathfuncs_t *QDECL FSZIP_LoadArchive (vfsfile_t *packhandle, const char *d
}
zip->references = 1;
zip->mutex = Sys_CreateMutex();
// Con_TPrintf ("Added zipfile %s (%i files)\n", desc, zip->numfiles);

File diff suppressed because it is too large Load Diff

View File

@ -5701,7 +5701,7 @@ void NET_CloseServer(void)
void NET_InitServer(void)
{
if (sv_listen_nq.value || sv_listen_dp.value || sv_listen_qw.value || sv_listen_q3.value)
if (sv_listen_nq.value || sv_listen_dp.value || sv_listen_qw.value || sv_listen_q3.ival)
{
if (!svs.sockets)
{

View File

@ -99,7 +99,7 @@ struct msurface_s;
void P_InitParticleSystem(void);
void P_Shutdown(void);
void P_LoadedModel(struct model_s *mod); /*checks a model's various effects*/
void P_DefaultTrail (struct model_s *model);
void P_DefaultTrail (unsigned int modelflags, int *trailid, int *trailpalidx);
void P_EmitEffect (vec3_t pos, int type, trailstate_t **tsk);//this is just a wrapper
#define P_FindParticleType pe->FindParticleType
@ -129,7 +129,7 @@ typedef struct {
qboolean (*ParticleQuery) (int type, int body, char *outstr, int outstrlen);
int (*RunParticleEffectTypeString) (vec3_t org, vec3_t dir, float count, char *name);
int (*ParticleTrail) (vec3_t startpos, vec3_t end, int type, int dlkey, trailstate_t **tsk);
int (*ParticleTrail) (vec3_t startpos, vec3_t end, int type, int dlkey, vec3_t dlaxis[3], trailstate_t **tsk);
int (*RunParticleEffectState) (vec3_t org, vec3_t dir, float count, int typenum, trailstate_t **tsk);
void (*RunParticleWeather) (vec3_t minb, vec3_t maxb, vec3_t dir, float count, int colour, char *efname);
void (*RunParticleCube) (int typenum, vec3_t minb, vec3_t maxb, vec3_t dir_min, vec3_t dir_max, float count, int colour, qboolean gravity, float jitter); //typenum may be P_INVALID

View File

@ -921,6 +921,17 @@ qintptr_t VARGS Plug_Net_SetTLSClient(void *offset, quintptr_t mask, const qintp
#endif
#endif
qintptr_t VARGS Plug_VFS_Open(void *offset, quintptr_t mask, const qintptr_t *arg)
{
char *fname = VM_POINTER(arg[0]);
vfsfile_t **handle = VM_POINTER(arg[1]);
char *mode = VM_POINTER(arg[2]);
*handle = FS_OpenVFS(fname, mode, FS_GAME);
if (*handle)
return true;
return false;
}
qintptr_t VARGS Plug_FS_Open(void *offset, quintptr_t mask, const qintptr_t *arg)
{
//modes:
@ -1307,6 +1318,8 @@ void Plug_Initialise(qboolean fromgamedir)
Plug_RegisterBuiltin("Net_Close", Plug_Net_Close, 0);
#endif
Plug_RegisterBuiltin("VFS_Open", Plug_VFS_Open, PLUG_BIF_DLLONLY);
Plug_RegisterBuiltin("FS_Open", Plug_FS_Open, 0);
Plug_RegisterBuiltin("FS_Read", Plug_Net_Recv, 0);
Plug_RegisterBuiltin("FS_Write", Plug_Net_Send, 0);
@ -1645,7 +1658,8 @@ void Plug_Close(plugin_t *plug)
prev->next = plug->next;
}
Con_Printf("Closing plugin %s\n", plug->name);
if (!com_fatalerror)
Con_Printf("Closing plugin %s\n", plug->name);
//ensure any active contexts provided by the plugin are closed (stuff with destroy callbacks)
#if defined(PLUGINS) && !defined(NOMEDIA) && !defined(SERVERONLY)

View File

@ -119,7 +119,7 @@ int PM_PointContents (vec3_t p)
//check world.
pm = pmove.physents[0].model;
if (!pm || pm->needload)
if (!pm || pm->loadstate != MLS_LOADED)
return FTECONTENTS_EMPTY;
pc = pm->funcs.PointContents(pm, NULL, p);
@ -471,7 +471,7 @@ trace_t PM_PlayerTrace (vec3_t start, vec3_t end, unsigned int solidmask)
if (pe->forcecontentsmask && !(pe->forcecontentsmask & solidmask))
continue;
if (!pe->model || pe->model->needload)
if (!pe->model || pe->model->loadstate != MLS_LOADED)
{
vec3_t mins, maxs;

View File

@ -19,6 +19,7 @@ cvar_t pr_droptofloorunits = CVAR("pr_droptofloorunits", "");
cvar_t pr_brokenfloatconvert = CVAR("pr_brokenfloatconvert", "0");
cvar_t pr_tempstringcount = CVAR("pr_tempstringcount", "");//"16");
cvar_t pr_tempstringsize = CVAR("pr_tempstringsize", "4096");
cvar_t pr_sourcedir = CVARD("pr_sourcedir", "src", "Subdirectory where your qc source is located. Used by the internal compiler and qc debugging functionality.");
cvar_t pr_enable_uriget = CVAR("pr_enable_uriget", "1");
cvar_t pr_enable_profiling = CVARD("pr_enable_profiling", "0", "Enables profiling support. Will run more slowly. Change the map and then use the profile_ssqc/profile_csqc commands to see the results.");
int tokenizeqc(const char *str, qboolean dpfuckage);
@ -34,6 +35,7 @@ void PF_Common_RegisterCvars(void)
Cvar_Register (&pr_tempstringsize, cvargroup_progs);
Cvar_Register (&pr_enable_uriget, cvargroup_progs);
Cvar_Register (&pr_enable_profiling, cvargroup_progs);
Cvar_Register (&pr_sourcedir, cvargroup_progs);
#ifdef RAGDOLL
Cmd_AddCommand("skel_info", skel_info_f);
@ -158,7 +160,9 @@ int QDECL QCEditor (pubprogfuncs_t *prinst, char *filename, int line, int statem
if (line == -1)
return line;
#ifndef CLIENTONLY
SV_EndRedirect();
#endif
if (developer.value)
{
f = FS_OpenVFS(filename, "rb", FS_GAME);
@ -320,7 +324,7 @@ void VARGS PR_BIError(pubprogfuncs_t *progfuncs, char *format, ...)
else
{
PR_StackTrace(progfuncs, false);
PR_AbortStack(progfuncs);
// PR_AbortStack(progfuncs);
progfuncs->parms->Abort ("%s", string);
}
}
@ -776,8 +780,10 @@ void QCBUILTIN PF_checkpvs(pubprogfuncs_t *prinst, struct globalvars_s *pr_globa
float *viewpos = G_VECTOR(OFS_PARM0);
wedict_t *ent = G_WEDICT(prinst, OFS_PARM1);
if (!world->worldmodel || world->worldmodel->needload)
if (!world->worldmodel || world->worldmodel->loadstate != MLS_LOADED)
G_FLOAT(OFS_RETURN) = false;
else if (!world->worldmodel->funcs.FatPVS)
G_FLOAT(OFS_RETURN) = true;
else
{
//FIXME: Make all alternatives of FatPVS not recalulate the pvs.
@ -1511,6 +1517,8 @@ pf_fopen_files_t pf_fopen_files[MAX_QC_FILES];
//fallbackread can be NULL, if the qc is not allowed to read that (original) file at all.
qboolean QC_FixFileName(const char *name, const char **result, const char **fallbackread)
{
char ext[8];
if (strchr(name, ':') || //dos/win absolute path, ntfs ADS, amiga drives. reject them all.
strchr(name, '\\') || //windows-only paths.
*name == '/' || //absolute path was given - reject
@ -1521,7 +1529,7 @@ qboolean QC_FixFileName(const char *name, const char **result, const char **fall
*fallbackread = name;
//if its a user config, ban any fallback locations so that csqc can't read passwords or whatever.
if ((!strchr(name, '/') || strnicmp(name, "configs/", 8)) && !stricmp(COM_FileExtension(name), "cfg"))
if ((!strchr(name, '/') || strnicmp(name, "configs/", 8)) && !stricmp(COM_FileExtension(name, ext, sizeof(ext)), "cfg"))
*fallbackread = NULL;
*result = va("data/%s", name);
return true;
@ -1534,6 +1542,7 @@ void QCBUILTIN PF_fopen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
int fsize = G_FLOAT(OFS_PARM2);
const char *fallbackread;
int i;
size_t insize;
for (i = 0; i < MAX_QC_FILES; i++)
if (!pf_fopen_files[i].data)
@ -1596,11 +1605,11 @@ void QCBUILTIN PF_fopen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
break;
case FRIK_FILE_READ: //read
case FRIK_FILE_READNL: //read whole file
pf_fopen_files[i].data = FS_LoadMallocFile(pf_fopen_files[i].name);
fsize = FS_LoadFile(pf_fopen_files[i].name, &pf_fopen_files[i].data);
if (!pf_fopen_files[i].data && fallbackread)
{
Q_strncpyz(pf_fopen_files[i].name, fallbackread, sizeof(pf_fopen_files[i].name));
pf_fopen_files[i].data = FS_LoadMallocFile(pf_fopen_files[i].name);
fsize = FS_LoadFile(pf_fopen_files[i].name, &pf_fopen_files[i].data);
}
if (pf_fopen_files[i].data)
@ -1611,12 +1620,12 @@ void QCBUILTIN PF_fopen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
else
G_FLOAT(OFS_RETURN) = -1;
pf_fopen_files[i].bufferlen = pf_fopen_files[i].len = com_filesize;
pf_fopen_files[i].bufferlen = pf_fopen_files[i].len = fsize;
pf_fopen_files[i].ofs = 0;
break;
case FRIK_FILE_APPEND: //append
pf_fopen_files[i].data = FS_LoadMallocFile(pf_fopen_files[i].name);
pf_fopen_files[i].ofs = pf_fopen_files[i].bufferlen = pf_fopen_files[i].len = com_filesize;
pf_fopen_files[i].data = FS_LoadMallocFile(pf_fopen_files[i].name, &insize);
pf_fopen_files[i].ofs = pf_fopen_files[i].bufferlen = pf_fopen_files[i].len = insize;
if (pf_fopen_files[i].data)
{
G_FLOAT(OFS_RETURN) = i + FIRST_QC_FILE_INDEX;
@ -1691,7 +1700,7 @@ void QCBUILTIN PF_fclose (pubprogfuncs_t *prinst, struct globalvars_s *pr_global
if (fnum < 0 || fnum >= MAX_QC_FILES)
{
Con_Printf("PF_fclose: File out of range\n");
Con_Printf("PF_fclose: File out of range (%g)\n", G_FLOAT(OFS_PARM0));
return; //out of range
}
@ -2105,7 +2114,7 @@ void QCBUILTIN PF_callfunction (pubprogfuncs_t *prinst, struct globalvars_s *pr_
void QCBUILTIN PF_loadfromfile (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *filename = PR_GetStringOfs(prinst, OFS_PARM0);
const char *file = COM_LoadTempFile(filename);
const char *file = COM_LoadTempFile(filename, NULL);
int size;
@ -4086,7 +4095,7 @@ void QCBUILTIN PF_droptofloor (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
const float *gravitydir;
extern const vec3_t standardgravity;
ent = PROG_TO_WEDICT(prinst, pr_global_struct->self);
ent = PROG_TO_WEDICT(prinst, *world->g.self);
if (ent->xv->gravitydir[2] || ent->xv->gravitydir[1] || ent->xv->gravitydir[0])
gravitydir = ent->xv->gravitydir;
@ -4164,10 +4173,11 @@ FIXME: add gravitydir support
float World_changeyaw (wedict_t *ent);
void QCBUILTIN PF_changeyaw (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
world_t *w = prinst->parms->user;
wedict_t *ent;
// float ideal, current, move, speed;
ent = PROG_TO_WEDICT(prinst, pr_global_struct->self);
ent = PROG_TO_WEDICT(prinst, *w->g.self);
World_changeyaw(ent);
/*
@ -4207,10 +4217,11 @@ void QCBUILTIN PF_changeyaw (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
//FIXME: support gravitydir
void QCBUILTIN PF_changepitch (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
edict_t *ent;
world_t *w = prinst->parms->user;
wedict_t *ent;
float ideal, current, move, speed;
ent = PROG_TO_EDICT(prinst, pr_global_struct->self);
ent = PROG_TO_WEDICT(prinst, *w->g.self);
current = anglemod( ent->v->angles[1] );
ideal = ent->xv->idealpitch;
speed = ent->xv->pitch_speed;

View File

@ -534,6 +534,26 @@ pbool QDECL ED_CanFree (edict_t *ed);
#define CLIENTTYPE_BOT 2
#define CLIENTTYPE_NOTACLIENT 3
enum
{
RESSTATE_NOTKNOWN = 0,
RESSTATE_NOTLOADED = 1,
RESSTATE_LOADING = 2,
RESSTATE_FAILED = 3,
RESSTATE_LOADED = 4,
RESSTATE_UNSUPPORTED = -1
};
enum
{
RESTYPE_MODEL,
RESTYPE_SOUND,
RESTYPE_PARTICLE,
RESTYPE_SHADER,
RESTYPE_SKIN,
RESTYPE_TEXTURE
};
//shared constants
typedef enum
{
@ -629,7 +649,8 @@ enum lightfield_e
lfield_cubemapname=9,
lfield_ambientscale=10,
lfield_diffusescale=11,
lfield_specularscale=12
lfield_specularscale=12,
lfield_rotation=13
};
enum csqc_input_event
{

View File

@ -813,32 +813,33 @@ enum clcq2_ops_e
// temp entity events
//
enum {
TE_SPIKE = 0,
TE_SUPERSPIKE = 1,
TE_GUNSHOT = 2,
TE_EXPLOSION = 3,
TE_TAREXPLOSION = 4,
TE_LIGHTNING1 = 5,
TE_LIGHTNING2 = 6,
TE_WIZSPIKE = 7,
TE_KNIGHTSPIKE = 8,
TE_LIGHTNING3 = 9,
TE_LAVASPLASH = 10,
TE_TELEPORT = 11,
TE_SPIKE = 0,
TE_SUPERSPIKE = 1,
TE_GUNSHOT = 2,
TE_EXPLOSION = 3,
TE_TAREXPLOSION = 4,
TE_LIGHTNING1 = 5,
TE_LIGHTNING2 = 6,
TE_WIZSPIKE = 7,
TE_KNIGHTSPIKE = 8,
TE_LIGHTNING3 = 9,
TE_LAVASPLASH = 10,
TE_TELEPORT = 11,
TEQW_BLOOD = 12, //implemented as a particle() in nq
TENQ_EXPLOSION2 = 12, //remapped to TEQW_EXPLOSION2 for qw
TEQW_LIGHTNINGBLOOD = 13, //implemented as a particle() in nq
TENQ_BEAM = 13, //remapped to TEQW_BEAM for qw
TEQW_BLOOD = 12, //implemented as a particle() in nq
TENQ_EXPLOSION2 = 12, //remapped to TEQW_EXPLOSION2 for qw
TEQW_LIGHTNINGBLOOD = 13, //implemented as a particle() in nq
TENQ_BEAM = 13, //remapped to TEQW_BEAM for qw
#ifdef PEXT_TE_BULLET
TE_BULLET = 14,
TE_SUPERBULLET = 15,
TE_BULLET = 14,
TE_SUPERBULLET = 15,
#endif
TE_RAILTRAIL = 17, //use the builtin, luke.
TEQW_BEAM = 18, //use the builtin, luke.
TEQW_EXPLOSION2 = 19, //use the builtin, luke.
TE_RAILTRAIL = 17, //use the builtin, luke.
TEQW_BEAM = 18, //use the builtin, luke.
TEQW_EXPLOSION2 = 19, //use the builtin, luke.
TE_EXPLOSIONNOSPRITE = 20, //use the builtin, luke.
// hexen 2
TEH2_STREAM_LIGHTNING_SMALL = 24,

View File

@ -20,6 +20,7 @@ vm_fopen_files_t vm_fopen_files[MAX_VM_FILES];
int VM_fopen (char *name, int *handle, int fmode, int owner)
{
int i;
size_t insize;
if (!handle)
return FS_FLocateFile(name, FSLFRT_IFFOUND, NULL);
@ -45,8 +46,8 @@ int VM_fopen (char *name, int *handle, int fmode, int owner)
switch (fmode)
{
case VM_FS_READ:
vm_fopen_files[i].data = FS_LoadMallocFile(name);
vm_fopen_files[i].bufferlen = vm_fopen_files[i].len = com_filesize;
vm_fopen_files[i].data = FS_LoadMallocFile(name, &insize);
vm_fopen_files[i].bufferlen = vm_fopen_files[i].len = insize;
vm_fopen_files[i].ofs = 0;
if (vm_fopen_files[i].data)
break;

View File

@ -98,9 +98,12 @@ qboolean Sys_GetDesktopParameters(int *width, int *height, int *bpp, int *refres
void Sys_SetThreadName(unsigned int dwThreadID, char *threadName);
#endif
void Sys_ThreadsInit(void);
qboolean Sys_IsThread(void *thread);
void *Sys_CreateThread(char *name, int (*func)(void *), void *args, int priority, int stacksize);
void Sys_WaitOnThread(void *thread);
void Sys_DetachThread(void *thread);
void Sys_ThreadAbort(void);
#define THREADP_IDLE -5
#define THREADP_NORMAL 0
@ -116,10 +119,16 @@ void Sys_DestroyMutex(void *mutex);
void *Sys_CreateConditional(void);
qboolean Sys_LockConditional(void *condv);
qboolean Sys_UnlockConditional(void *condv);
qboolean Sys_ConditionWait(void *condv);
qboolean Sys_ConditionSignal(void *condv);
qboolean Sys_ConditionBroadcast(void *condv);
qboolean Sys_ConditionWait(void *condv); //lock first
qboolean Sys_ConditionSignal(void *condv); //lock first
qboolean Sys_ConditionBroadcast(void *condv); //lock first
void Sys_DestroyConditional(void *condv);
#else
#define Sys_CreateMutex() NULL
#define Sys_LockMutex(m) true
#define Sys_UnlockMutex(m) true
#define Sys_DestroyMutex(m)
#define Sys_IsThread(t) !t
#endif
void Sys_Sleep(double seconds);

View File

@ -1,187 +1,204 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
//well, linux or cygwin (windows with posix emulation layer), anyway...
#include "quakedef.h"
#ifdef MULTITHREAD
#include <limits.h>
#include <pthread.h>
/* Thread creation calls */
typedef void *(*pfunction_t)(void *);
void *Sys_CreateThread(char *name, int (*func)(void *), void *args, int priority, int stacksize)
{
pthread_t *thread;
pthread_attr_t attr;
thread = (pthread_t *)malloc(sizeof(pthread_t));
if (!thread)
return NULL;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
if (stacksize < PTHREAD_STACK_MIN*2)
stacksize = PTHREAD_STACK_MIN*2;
pthread_attr_setstacksize(&attr, stacksize);
if (pthread_create(thread, &attr, (pfunction_t)func, args))
{
free(thread);
thread = NULL;
}
pthread_attr_destroy(&attr);
return (void *)thread;
}
void Sys_WaitOnThread(void *thread)
{
int err;
err = pthread_join(*(pthread_t *)thread, NULL);
if (err)
printf("pthread_join(%p) failed, error %s\n", thread, strerror(err));
free(thread);
}
/* Mutex calls */
void *Sys_CreateMutex(void)
{
pthread_mutex_t *mutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
if (mutex && !pthread_mutex_init(mutex, NULL))
return mutex;
return NULL;
}
qboolean Sys_TryLockMutex(void *mutex)
{
return !pthread_mutex_trylock(mutex);
}
qboolean Sys_LockMutex(void *mutex)
{
return !pthread_mutex_lock(mutex);
}
qboolean Sys_UnlockMutex(void *mutex)
{
return !pthread_mutex_unlock(mutex);
}
void Sys_DestroyMutex(void *mutex)
{
pthread_mutex_destroy(mutex);
free(mutex);
}
/* Conditional wait calls */
typedef struct condvar_s
{
pthread_mutex_t *mutex;
pthread_cond_t *cond;
} condvar_t;
void *Sys_CreateConditional(void)
{
condvar_t *condv;
pthread_mutex_t *mutex;
pthread_cond_t *cond;
condv = (condvar_t *)malloc(sizeof(condvar_t));
if (!condv)
return NULL;
mutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
if (!mutex)
return NULL;
cond = (pthread_cond_t *)malloc(sizeof(pthread_cond_t));
if (!cond)
return NULL;
if (!pthread_mutex_init(mutex, NULL))
{
if (!pthread_cond_init(cond, NULL))
{
condv->cond = cond;
condv->mutex = mutex;
return (void *)condv;
}
else
pthread_mutex_destroy(mutex);
}
free(cond);
free(mutex);
free(condv);
return NULL;
}
qboolean Sys_LockConditional(void *condv)
{
return !pthread_mutex_lock(((condvar_t *)condv)->mutex);
}
qboolean Sys_UnlockConditional(void *condv)
{
return !pthread_mutex_unlock(((condvar_t *)condv)->mutex);
}
qboolean Sys_ConditionWait(void *condv)
{
return !pthread_cond_wait(((condvar_t *)condv)->cond, ((condvar_t *)condv)->mutex);
}
qboolean Sys_ConditionSignal(void *condv)
{
return !pthread_cond_signal(((condvar_t *)condv)->cond);
}
qboolean Sys_ConditionBroadcast(void *condv)
{
return !pthread_cond_broadcast(((condvar_t *)condv)->cond);
}
void Sys_DestroyConditional(void *condv)
{
condvar_t *cv = (condvar_t *)condv;
pthread_cond_destroy(cv->cond);
pthread_mutex_destroy(cv->mutex);
free(cv->cond);
free(cv->mutex);
free(cv);
}
#endif
void Sys_Sleep (double seconds)
{
struct timespec ts;
ts.tv_sec = (time_t)seconds;
seconds -= ts.tv_sec;
ts.tv_nsec = seconds * 1000000000.0;
nanosleep(&ts, NULL);
}
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
//well, linux or cygwin (windows with posix emulation layer), anyway...
#include "quakedef.h"
#ifdef MULTITHREAD
#include <limits.h>
#include <pthread.h>
/* Thread creation calls */
typedef void *(*pfunction_t)(void *);
static pthread_t mainthread;
void Sys_ThreadsInit(void)
{
mainthread = pthread_self();
}
qboolean Sys_IsThread(void *thread)
{
if (!thread)
thread = &mainthread;
return pthread_equal(pthread_self(), *(pthread_t*)thread);
}
void Sys_ThreadAbort(void)
{
pthread_exit(NULL);
}
void *Sys_CreateThread(char *name, int (*func)(void *), void *args, int priority, int stacksize)
{
pthread_t *thread;
pthread_attr_t attr;
thread = (pthread_t *)malloc(sizeof(pthread_t));
if (!thread)
return NULL;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
if (stacksize < PTHREAD_STACK_MIN*2)
stacksize = PTHREAD_STACK_MIN*2;
pthread_attr_setstacksize(&attr, stacksize);
if (pthread_create(thread, &attr, (pfunction_t)func, args))
{
free(thread);
thread = NULL;
}
pthread_attr_destroy(&attr);
return (void *)thread;
}
void Sys_WaitOnThread(void *thread)
{
int err;
err = pthread_join(*(pthread_t *)thread, NULL);
if (err)
printf("pthread_join(%p) failed, error %s\n", thread, strerror(err));
free(thread);
}
/* Mutex calls */
void *Sys_CreateMutex(void)
{
pthread_mutex_t *mutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
if (mutex && !pthread_mutex_init(mutex, NULL))
return mutex;
return NULL;
}
qboolean Sys_TryLockMutex(void *mutex)
{
return !pthread_mutex_trylock(mutex);
}
qboolean Sys_LockMutex(void *mutex)
{
return !pthread_mutex_lock(mutex);
}
qboolean Sys_UnlockMutex(void *mutex)
{
return !pthread_mutex_unlock(mutex);
}
void Sys_DestroyMutex(void *mutex)
{
pthread_mutex_destroy(mutex);
free(mutex);
}
/* Conditional wait calls */
typedef struct condvar_s
{
pthread_mutex_t *mutex;
pthread_cond_t *cond;
} condvar_t;
void *Sys_CreateConditional(void)
{
condvar_t *condv;
pthread_mutex_t *mutex;
pthread_cond_t *cond;
condv = (condvar_t *)malloc(sizeof(condvar_t));
if (!condv)
return NULL;
mutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
if (!mutex)
return NULL;
cond = (pthread_cond_t *)malloc(sizeof(pthread_cond_t));
if (!cond)
return NULL;
if (!pthread_mutex_init(mutex, NULL))
{
if (!pthread_cond_init(cond, NULL))
{
condv->cond = cond;
condv->mutex = mutex;
return (void *)condv;
}
else
pthread_mutex_destroy(mutex);
}
free(cond);
free(mutex);
free(condv);
return NULL;
}
qboolean Sys_LockConditional(void *condv)
{
return !pthread_mutex_lock(((condvar_t *)condv)->mutex);
}
qboolean Sys_UnlockConditional(void *condv)
{
return !pthread_mutex_unlock(((condvar_t *)condv)->mutex);
}
qboolean Sys_ConditionWait(void *condv)
{
return !pthread_cond_wait(((condvar_t *)condv)->cond, ((condvar_t *)condv)->mutex);
}
qboolean Sys_ConditionSignal(void *condv)
{
return !pthread_cond_signal(((condvar_t *)condv)->cond);
}
qboolean Sys_ConditionBroadcast(void *condv)
{
return !pthread_cond_broadcast(((condvar_t *)condv)->cond);
}
void Sys_DestroyConditional(void *condv)
{
condvar_t *cv = (condvar_t *)condv;
pthread_cond_destroy(cv->cond);
pthread_mutex_destroy(cv->mutex);
free(cv->cond);
free(cv->mutex);
free(cv);
}
#endif
void Sys_Sleep (double seconds)
{
struct timespec ts;
ts.tv_sec = (time_t)seconds;
seconds -= ts.tv_sec;
ts.tv_nsec = seconds * 1000000000.0;
nanosleep(&ts, NULL);
}

View File

@ -33,40 +33,17 @@ PVOID WINAPI AddVectoredExceptionHandler(ULONG FirstHandler, PVECTORED_EXCEPTION
#endif
#endif
#if !defined(WINRT) && defined(MULTITHREAD)
#include <process.h>
/* Thread creation calls */
typedef struct threadwrap_s
{
int (*func)(void *);
void *args;
} threadwrap_t;
// the thread call is wrapped so we don't need WINAPI everywhere
unsigned int WINAPI threadwrapper(void *args)
{
threadwrap_t tw;
tw.func = ((threadwrap_t *)args)->func;
tw.args = ((threadwrap_t *)args)->args;
free(args);
tw.func(tw.args);
#ifndef WIN32CRTDLL
_endthreadex(0);
#endif
return 0;
}
#if defined(_DEBUG) && defined(_MSC_VER)
const DWORD MS_VC_EXCEPTION=0x406D1388;
#pragma pack(push,8)
typedef struct tagTHREADNAME_INFO
{
DWORD dwType; // Must be 0x1000.
LPCSTR szName; // Pointer to name (in user addr space).
DWORD dwThreadID; // Thread ID (-1=caller thread).
DWORD dwFlags; // Reserved for future use, must be zero.
DWORD dwType; // Must be 0x1000.
LPCSTR szName; // Pointer to name (in user addr space).
DWORD dwThreadID; // Thread ID (-1=caller thread).
DWORD dwFlags; // Reserved for future use, must be zero.
} THREADNAME_INFO;
#pragma pack(pop)
void Sys_SetThreadName(unsigned int dwThreadID, char *threadName)
@ -87,9 +64,42 @@ void Sys_SetThreadName(unsigned int dwThreadID, char *threadName)
}
#endif
#if !defined(WINRT) && defined(MULTITHREAD)
#include <process.h>
/* Thread creation calls */
typedef struct threadwrap_s
{
int (*func)(void *);
void *args;
char name[1];
} threadwrap_t;
// the thread call is wrapped so we don't need WINAPI everywhere
unsigned int WINAPI threadwrapper(void *args)
{
threadwrap_t tw;
tw.func = ((threadwrap_t *)args)->func;
tw.args = ((threadwrap_t *)args)->args;
#if defined(_DEBUG) && defined(_MSC_VER)
Sys_SetThreadName(GetCurrentThreadId(), ((threadwrap_t *)args)->name);
#endif
#ifdef CATCHCRASH
AddVectoredExceptionHandler(true, nonmsvc_CrashExceptionHandler);
#endif
free(args);
tw.func(tw.args);
#ifndef WIN32CRTDLL
_endthreadex(0);
#endif
return 0;
}
void *Sys_CreateThread(char *name, int (*func)(void *), void *args, int priority, int stacksize)
{
threadwrap_t *tw = (threadwrap_t *)malloc(sizeof(threadwrap_t));
threadwrap_t *tw = (threadwrap_t *)malloc(sizeof(threadwrap_t)+strlen(name));
HANDLE handle;
unsigned int tid;
@ -99,6 +109,7 @@ void *Sys_CreateThread(char *name, int (*func)(void *), void *args, int priority
stacksize += 128; // wrapper overhead, also prevent default stack size
tw->func = func;
tw->args = args;
strcpy(tw->name, name);
#ifdef WIN32CRTDLL
handle = (HANDLE)CreateThread(NULL, stacksize, &threadwrapper, (void *)tw, 0, &tid);
#else
@ -110,12 +121,7 @@ void *Sys_CreateThread(char *name, int (*func)(void *), void *args, int priority
return NULL;
}
#if defined(_DEBUG) && defined(_MSC_VER)
Sys_SetThreadName(tid, name);
#endif
#ifdef CATCHCRASH
AddVectoredExceptionHandler(true, nonmsvc_CrashExceptionHandler);
#endif
return (void *)handle;
}
@ -131,30 +137,94 @@ void Sys_WaitOnThread(void *thread)
CloseHandle((HANDLE)thread);
}
//used on fatal errors.
void Sys_ThreadAbort(void)
{
ExitThread(0);
}
static DWORD mainthread;
void Sys_ThreadsInit(void)
{
mainthread = GetCurrentThreadId();
}
qboolean Sys_IsThread(void *thread)
{
if (!thread)
return mainthread == GetCurrentThreadId();
return GetThreadId(thread) == GetCurrentThreadId();
}
/* Mutex calls */
/*
Note that a 'mutex' in win32 terminology is a cross-process/kernel object
A critical section is a single-process object, and thus can be provided more cheaply
*/
void *Sys_CreateMutex(void)
{
return (void *)CreateMutex(NULL, 0, NULL);
#ifdef _DEBUG
//linux's pthread code doesn't like me recursively locking mutexes, so add some debug-only code to catch that on windows too so that we don't get nasty surprises.
CRITICAL_SECTION *mutex = malloc(sizeof(*mutex)+sizeof(int));
*(int*)(1+(CRITICAL_SECTION*)mutex) = 0;
#else
CRITICAL_SECTION *mutex = malloc(sizeof(*mutex));
#endif
InitializeCriticalSection(mutex);
return (void *)mutex;
}
qboolean Sys_TryLockMutex(void *mutex)
{
return WaitForSingleObject(mutex, 0) == WAIT_OBJECT_0;
#ifdef _DEBUG
if (!mutex)
{
Con_Printf("Invalid mutex\n");
return false;
}
#endif
if (TryEnterCriticalSection(mutex))
{
#ifdef _DEBUG
if (*(int*)(1+(CRITICAL_SECTION*)mutex))
Con_Printf("Double lock\n");
*(int*)(1+(CRITICAL_SECTION*)mutex)+=1;
#endif
return true;
}
return false;
}
qboolean Sys_LockMutex(void *mutex)
{
return WaitForSingleObject(mutex, INFINITE) == WAIT_OBJECT_0;
#ifdef _DEBUG
if (!mutex)
{
Con_Printf("Invalid mutex\n");
return false;
}
#endif
EnterCriticalSection(mutex);
#ifdef _DEBUG
if (*(int*)(1+(CRITICAL_SECTION*)mutex))
Con_Printf("Double lock\n");
*(int*)(1+(CRITICAL_SECTION*)mutex)+=1;
#endif
return true;
}
qboolean Sys_UnlockMutex(void *mutex)
{
return !!ReleaseMutex(mutex);
#ifdef _DEBUG
*(int*)(1+(CRITICAL_SECTION*)mutex)-=1;
#endif
LeaveCriticalSection(mutex);
return true;
}
void Sys_DestroyMutex(void *mutex)
{
CloseHandle(mutex);
DeleteCriticalSection(mutex);
free(mutex);
}
/* Conditional wait calls */
@ -164,19 +234,17 @@ http://msdn.microsoft.com/en-us/library/ms682052(VS.85).aspx
Note this uses Slim Reader/Writer locks (Vista+ exclusive)
or critical sections.
The condition variable implementation is based on the libSDL implementation.
This code could probably be made more efficient with the use of events or
different mechanisms but for now the main concern is a correct and
complete solution.
The condition variable implementation is based on http://www.cs.wustl.edu/~schmidt/win32-cv-1.html.
(the libsdl-based stuff was too buggy)
*/
typedef struct condvar_s
{
int waiting;
int signals;
CRITICAL_SECTION countlock;
int waiters;
int release;
int waitgeneration;
CRITICAL_SECTION countlock;
CRITICAL_SECTION mainlock;
HANDLE wait_sem;
HANDLE wait_done;
HANDLE evnt;
} condvar_t;
void *Sys_CreateConditional(void)
@ -187,21 +255,17 @@ void *Sys_CreateConditional(void)
if (!cv)
return NULL;
cv->waiting = 0;
cv->signals = 0;
cv->waiters = 0;
cv->release = 0;
cv->waitgeneration = 0;
InitializeCriticalSection (&cv->mainlock);
InitializeCriticalSection (&cv->countlock);
cv->wait_sem = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
cv->wait_done = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
cv->evnt = CreateEvent(NULL, TRUE, FALSE, NULL);
if (cv->wait_sem && cv->wait_done)
if (cv->evnt)
return (void *)cv;
// something failed so deallocate everything
if (cv->wait_done)
CloseHandle(cv->wait_done);
if (cv->wait_sem)
CloseHandle(cv->wait_sem);
DeleteCriticalSection(&cv->countlock);
DeleteCriticalSection(&cv->mainlock);
free(cv);
@ -223,87 +287,94 @@ qboolean Sys_UnlockConditional(void *condv)
qboolean Sys_ConditionWait(void *condv)
{
qboolean done;
condvar_t *cv = (condvar_t *)condv;
qboolean success;
DWORD status;
int mygen;
// increase count for non-signaled waiting threads
EnterCriticalSection(&cv->countlock);
cv->waiting++;
cv->waiters++;
mygen = cv->waitgeneration;
LeaveCriticalSection(&cv->countlock);
LeaveCriticalSection(&cv->mainlock); // unlock as per condition variable definition
// wait on a signal
#if 0
success = (WaitForSingleObject(cv->wait_sem, INFINITE) != WAIT_FAILED);
for(;;)
{
#if 1
success = (WaitForSingleObject(cv->evnt, INFINITE) != WAIT_FAILED);
#else
do
{
MSG msg;
while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
DispatchMessage (&msg);
status = MsgWaitForMultipleObjects(1, &cv->wait_sem, FALSE, INFINITE, QS_SENDMESSAGE|QS_POSTMESSAGE);
} while (status == (WAIT_OBJECT_0+1));
success = status != WAIT_FAILED;
do
{
MSG msg;
while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
DispatchMessage (&msg);
status = MsgWaitForMultipleObjects(1, &cv->evnt, FALSE, INFINITE, QS_SENDMESSAGE|QS_POSTMESSAGE);
} while (status == (WAIT_OBJECT_0+1));
success = status != WAIT_FAILED;
#endif
// update waiting count and alert signaling thread that we're done to avoid the deadlock condition
EnterCriticalSection(&cv->countlock);
if (cv->signals > 0)
{
ReleaseSemaphore(cv->wait_done, cv->signals, NULL);
cv->signals = 0;
EnterCriticalSection(&cv->countlock);
done = cv->release > 0 && cv->waitgeneration != mygen;
LeaveCriticalSection(&cv->countlock);
if (done)
break;
}
cv->waiting--;
LeaveCriticalSection(&cv->countlock);
EnterCriticalSection(&cv->mainlock); // lock as per condition variable definition
return success;
// update waiting count and alert signaling thread that we're done to avoid the deadlock condition
EnterCriticalSection(&cv->countlock);
cv->waiters--;
cv->release--;
done = cv->release == 0;
LeaveCriticalSection(&cv->countlock);
if (done)
ResetEvent(cv->evnt);
return true;
}
qboolean Sys_ConditionSignal(void *condv)
{
condvar_t *cv = (condvar_t *)condv;
EnterCriticalSection(&cv->mainlock);
// if there are non-signaled waiting threads, we signal one and wait on the response
EnterCriticalSection(&cv->countlock);
if (cv->waiting > cv->signals)
if (cv->waiters > cv->release)
{
cv->signals++;
ReleaseSemaphore(cv->wait_sem, 1, NULL);
LeaveCriticalSection(&cv->countlock);
WaitForSingleObject(cv->wait_done, INFINITE);
SetEvent(cv->evnt);
cv->release++;
cv->waitgeneration++;
}
else
LeaveCriticalSection(&cv->countlock);
LeaveCriticalSection(&cv->countlock);
return true;
LeaveCriticalSection(&cv->mainlock);
return true;
}
qboolean Sys_ConditionBroadcast(void *condv)
{
condvar_t *cv = (condvar_t *)condv;
EnterCriticalSection(&cv->mainlock);
// if there are non-signaled waiting threads, we signal all of them and wait on all the responses back
EnterCriticalSection(&cv->countlock);
if (cv->waiting > cv->signals)
if (cv->waiters > 0)
{
int i, num_waiting;
num_waiting = (cv->waiting - cv->signals);
cv->signals = cv->waiting;
ReleaseSemaphore(cv->wait_sem, num_waiting, NULL);
LeaveCriticalSection(&cv->countlock);
// there's no call to wait for the same object multiple times so we need to loop through
// and burn up the semaphore count
for (i = 0; i < num_waiting; i++)
WaitForSingleObject(cv->wait_done, INFINITE);
SetEvent(cv->evnt);
cv->release = cv->waiters;
cv->waitgeneration++;
}
else
LeaveCriticalSection(&cv->countlock);
LeaveCriticalSection(&cv->countlock);
LeaveCriticalSection(&cv->mainlock);
return true;
}
@ -312,8 +383,11 @@ void Sys_DestroyConditional(void *condv)
{
condvar_t *cv = (condvar_t *)condv;
CloseHandle(cv->wait_done);
CloseHandle(cv->wait_sem);
//make sure noone is still trying to poke it while shutting down
// Sys_LockConditional(condv);
// Sys_UnlockConditional(condv);
CloseHandle(cv->evnt);
DeleteCriticalSection(&cv->countlock);
DeleteCriticalSection(&cv->mainlock);
free(cv);

View File

@ -171,7 +171,7 @@ void T_LoadString(void)
//count new lines
strings_loaded = true;
strings_count = 0;
strings_list = FS_LoadMallocFile("strings.txt");
strings_list = FS_LoadMallocFile("strings.txt", NULL);
if (!strings_list)
return;
@ -237,7 +237,7 @@ void T_LoadInfoString(void)
//count new lines
info_strings_loaded = true;
info_strings_count = 0;
info_strings_list = FS_LoadMallocFile("infolist.txt");
info_strings_list = FS_LoadMallocFile("infolist.txt", NULL);
if (!info_strings_list)
return;

View File

@ -289,5 +289,16 @@ qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, vec3_t axis
qboolean World_MoveToGoal (world_t *world, wedict_t *ent, float dist);
qboolean World_GetEntGravityAxis(wedict_t *ent, vec3_t axis[3]);
//
// sv_phys.c
//
void WPhys_Init(void);
void World_Physics_Frame(world_t *w);
void SV_SetMoveVars(void);
void WPhys_RunNewmis (world_t *w);
qboolean SV_Physics (void);
void WPhys_CheckVelocity (world_t *w, wedict_t *ent);
trace_t WPhys_Trace_Toss (world_t *w, wedict_t *ent, wedict_t *ignore);
void SV_ProgStartFrame (void);
void WPhys_RunEntity (world_t *w, wedict_t *ent);
qboolean WPhys_RunThink (world_t *w, wedict_t *ent);

View File

@ -509,6 +509,8 @@ void Hunk_TempFree(void)
{
hnktemps_t *nt;
COM_AssertMainThread("Hunk_TempFree");
while (hnktemps)
{
#if TEMPDEBUG>0
@ -543,8 +545,10 @@ void Hunk_TempFree(void)
void *Hunk_TempAllocMore (int size)
{
void *buf;
#if TEMPDEBUG>0
hnktemps_t *nt;
COM_AssertMainThread("Hunk_TempAllocMore");
nt = (hnktemps_t*)malloc(size + sizeof(hnktemps_t) + TEMPDEBUG*2);
if (!nt)
return NULL;
@ -559,6 +563,7 @@ void *Hunk_TempAllocMore (int size)
return buf;
#else
hnktemps_t *nt;
COM_AssertMainThread("Hunk_TempAllocMore");
nt = (hnktemps_t*)malloc(size + sizeof(hnktemps_t));
if (!nt)
return NULL;

View File

@ -204,10 +204,10 @@ typedef struct
unsigned int curlmode;
shader_t *shader_rtlight[LSHADER_MODES];
texid_t curtex[MAX_TMUS];
unsigned int texflags[MAX_TMUS];
unsigned int tmuflags[MAX_TMUS];
ID3D11SamplerState *cursamplerstate[MAX_TMUS];
ID3D11SamplerState *sampstate[(SHADER_PASS_NEAREST|SHADER_PASS_CLAMP|SHADER_PASS_DEPTHCMP)+1];
ID3D11SamplerState *sampstate[(SHADER_PASS_IMAGE_FLAGS|SHADER_PASS_DEPTHCMP)+1];
ID3D11DepthStencilState *depthstates[1u<<4]; //index, its fairly short.
blendstates_t *blendstates; //list. this could get big.
@ -254,28 +254,38 @@ static d3d11backend_t shaderstate;
extern int be_maxpasses;
static void BE_CreateSamplerStates(void)
void D3D11_UpdateFiltering(image_t *imagelist, int filtermip[3], int filterpic[3], int mipcap[2], float anis)
{
D3D11_SAMPLER_DESC sampdesc;
int flags;
for (flags = 0; flags <= (SHADER_PASS_CLAMP|SHADER_PASS_NEAREST|SHADER_PASS_DEPTHCMP); flags++)
for (flags = 0; flags <= (SHADER_PASS_IMAGE_FLAGS|SHADER_PASS_DEPTHCMP); flags++)
{
if (flags & SHADER_PASS_DEPTHCMP)
{
if (flags & SHADER_PASS_NEAREST)
sampdesc.Filter = D3D11_FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT;
else
sampdesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT;
sampdesc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL;
}
int *filter;
sampdesc.Filter = 0;
filter = (flags & SHADER_PASS_UIPIC)?filterpic:filtermip;
if ((filter[2] && !(flags & SHADER_PASS_NEAREST)) || (flags & SHADER_PASS_LINEAR))
sampdesc.Filter |= D3D11_FILTER_TYPE_LINEAR<<D3D11_MAG_FILTER_SHIFT;
else
sampdesc.Filter |= D3D11_FILTER_TYPE_POINT<<D3D11_MAG_FILTER_SHIFT;
//d3d11 has no no-mip feature
if ((filter[1]==1 && !(flags & SHADER_PASS_NEAREST)) || (flags & SHADER_PASS_LINEAR))
sampdesc.Filter |= D3D11_FILTER_TYPE_LINEAR<<D3D11_MIP_FILTER_SHIFT;
else
sampdesc.Filter |= D3D11_FILTER_TYPE_POINT<<D3D11_MIP_FILTER_SHIFT;
if ((filter[0] && !(flags & SHADER_PASS_NEAREST)) || (flags & SHADER_PASS_LINEAR))
sampdesc.Filter |= D3D11_FILTER_TYPE_LINEAR<<D3D11_MIN_FILTER_SHIFT;
else
sampdesc.Filter |= D3D11_FILTER_TYPE_POINT<<D3D11_MIN_FILTER_SHIFT;
//switch to anisotropic filtering if all three filters are linear and anis is set
if (sampdesc.Filter == D3D11_FILTER_MIN_MAG_MIP_LINEAR && anis > 1)
sampdesc.Filter = D3D11_FILTER_ANISOTROPIC;
if (flags & SHADER_PASS_DEPTHCMP)
sampdesc.Filter |= D3D11_COMPARISON_FILTERING_BIT;
if (flags & SHADER_PASS_DEPTHCMP)
sampdesc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL;
else
{
if (flags & SHADER_PASS_NEAREST)
sampdesc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
else
sampdesc.Filter = /*D3D11_FILTER_MIN_MAG_MIP_POINT;*/D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;/*D3D11_FILTER_MIN_MAG_MIP_LINEAR*/;
sampdesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
}
if (flags & SHADER_PASS_CLAMP)
{
sampdesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
@ -289,14 +299,27 @@ static void BE_CreateSamplerStates(void)
sampdesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
}
sampdesc.MipLODBias = 0.0f;
sampdesc.MaxAnisotropy = 1;
sampdesc.MaxAnisotropy = bound(1, anis, 16);
sampdesc.BorderColor[0] = 0;
sampdesc.BorderColor[1] = 0;
sampdesc.BorderColor[2] = 0;
sampdesc.BorderColor[3] = 0;
sampdesc.MinLOD = 0;
sampdesc.MaxLOD = D3D11_FLOAT32_MAX;
if (flags & SHADER_PASS_NOMIPMAP)
{ //only ever use the biggest mip if multiple are present
sampdesc.MinLOD = 0;
sampdesc.MaxLOD = 0;
}
else
{
sampdesc.MinLOD = mipcap[0];
sampdesc.MaxLOD = mipcap[1];
}
if (shaderstate.sampstate[flags])
ID3D11SamplerState_Release(shaderstate.sampstate[flags]);
shaderstate.sampstate[flags] = NULL;
//returns the same pointer for dupes, supposedly, so no need to check that
ID3D11Device_CreateSamplerState(pD3DDev11, &sampdesc, &shaderstate.sampstate[flags]);
}
}
@ -313,7 +336,7 @@ static void BE_DestroyVariousStates(void)
if (d3ddevctx && i)
ID3D11DeviceContext_PSSetSamplers(d3ddevctx, 0, i, shaderstate.cursamplerstate);
for (flags = 0; flags <= (SHADER_PASS_CLAMP|SHADER_PASS_NEAREST|SHADER_PASS_DEPTHCMP); flags++)
for (flags = 0; flags <= (SHADER_PASS_IMAGE_FLAGS|SHADER_PASS_DEPTHCMP); flags++)
{
if (shaderstate.sampstate[flags])
ID3D11SamplerState_Release(shaderstate.sampstate[flags]);
@ -384,7 +407,8 @@ static void BE_ApplyTMUState(unsigned int tu, unsigned int flags)
{
ID3D11SamplerState *nstate;
flags = flags & (SHADER_PASS_CLAMP|SHADER_PASS_NEAREST|SHADER_PASS_DEPTHCMP);
flags = (flags & (SHADER_PASS_IMAGE_FLAGS|SHADER_PASS_DEPTHCMP));
flags |= shaderstate.texflags[tu];
nstate = shaderstate.sampstate[flags];
if (nstate != shaderstate.cursamplerstate[tu])
{
@ -717,7 +741,7 @@ void D3D11BE_Init(void)
for (i = 0; i < MAXRLIGHTMAPS; i++)
shaderstate.dummybatch.lightmap[i] = -1;
BE_CreateSamplerStates();
// BE_CreateSamplerStates();
// FTable_Init();
@ -856,14 +880,16 @@ static unsigned int allocindexbuffer(void **dest, unsigned int entries)
}
#endif
ID3D11ShaderResourceView *D3D11_Image_View(const texid_t *id);
static void BindTexture(unsigned int tu, const texid_t *id)
ID3D11ShaderResourceView *D3D11_Image_View(const texid_t id);
static void BindTexture(unsigned int tu, const texid_t id)
{
ID3D11ShaderResourceView *view = D3D11_Image_View(id);
if (shaderstate.pendingtextures[tu] != view)
{
shaderstate.textureschanged = true;
shaderstate.pendingtextures[tu] = view;
if (id)
shaderstate.texflags[tu] = id->flags&SHADER_PASS_IMAGE_FLAGS;
}
}
@ -882,52 +908,51 @@ void D3D11BE_UnbindAllTextures(void)
static void SelectPassTexture(unsigned int tu, const shaderpass_t *pass)
{
extern texid_t r_whiteimage, missing_texture_gloss, missing_texture_normal;
texid_t foo;
switch(pass->texgen)
{
default:
case T_GEN_DIFFUSE:
BindTexture(tu, &shaderstate.curtexnums->base);
BindTexture(tu, shaderstate.curtexnums->base);
break;
case T_GEN_NORMALMAP:
if (TEXVALID(shaderstate.curtexnums->bump))
BindTexture(tu, &shaderstate.curtexnums->bump);
BindTexture(tu, shaderstate.curtexnums->bump);
else
BindTexture(tu, &missing_texture_normal);
BindTexture(tu, missing_texture_normal);
break;
case T_GEN_SPECULAR:
if (TEXVALID(shaderstate.curtexnums->specular))
BindTexture(tu, &shaderstate.curtexnums->specular);
BindTexture(tu, shaderstate.curtexnums->specular);
else
BindTexture(tu, &missing_texture_gloss);
BindTexture(tu, missing_texture_gloss);
break;
case T_GEN_UPPEROVERLAY:
BindTexture(tu, &shaderstate.curtexnums->upperoverlay);
BindTexture(tu, shaderstate.curtexnums->upperoverlay);
break;
case T_GEN_LOWEROVERLAY:
BindTexture(tu, &shaderstate.curtexnums->loweroverlay);
BindTexture(tu, shaderstate.curtexnums->loweroverlay);
break;
case T_GEN_FULLBRIGHT:
BindTexture(tu, &shaderstate.curtexnums->fullbright);
BindTexture(tu, shaderstate.curtexnums->fullbright);
break;
case T_GEN_ANIMMAP:
BindTexture(tu, &pass->anim_frames[(int)(pass->anim_fps * shaderstate.curtime) % pass->anim_numframes]);
BindTexture(tu, pass->anim_frames[(int)(pass->anim_fps * shaderstate.curtime) % pass->anim_numframes]);
break;
case T_GEN_3DMAP:
case T_GEN_CUBEMAP:
case T_GEN_SINGLEMAP:
BindTexture(tu, &pass->anim_frames[0]);
BindTexture(tu, pass->anim_frames[0]);
break;
case T_GEN_DELUXMAP:
{
int lmi = shaderstate.curbatch->lightmap[0];
if (lmi < 0 || !lightmap[lmi]->hasdeluxe)
BindTexture(tu, &r_nulltex);
BindTexture(tu, r_nulltex);
else
{
lmi+=1;
BindTexture(tu, &lightmap[lmi]->lightmap_texture);
BindTexture(tu, lightmap[lmi]->lightmap_texture);
}
}
break;
@ -935,9 +960,9 @@ static void SelectPassTexture(unsigned int tu, const shaderpass_t *pass)
{
int lmi = shaderstate.curbatch->lightmap[0];
if (lmi < 0)
BindTexture(tu, &r_whiteimage);
BindTexture(tu, r_whiteimage);
else
BindTexture(tu, &lightmap[lmi]->lightmap_texture);
BindTexture(tu, lightmap[lmi]->lightmap_texture);
}
break;
@ -948,28 +973,26 @@ static void SelectPassTexture(unsigned int tu, const shaderpass_t *pass)
#ifndef NOMEDIA
if (pass->cin)
{
foo = Media_UpdateForShader(pass->cin);
BindTexture(tu, &foo);
BindTexture(tu, Media_UpdateForShader(pass->cin));
break;
}
#endif
BindTexture(tu, &r_nulltex);
BindTexture(tu, r_nulltex);
break;
case T_GEN_LIGHTCUBEMAP: //light's projected cubemap
BindTexture(tu, &shaderstate.curdlight->cubetexture);
BindTexture(tu, shaderstate.curdlight->cubetexture);
break;
case T_GEN_SHADOWMAP: //light's depth values.
#ifdef RTLIGHTS
if (shaderstate.curdlight)
{
foo = D3D11_GetShadowMap(shaderstate.curdlight->fov>0);
BindTexture(tu, &foo);
BindTexture(tu, D3D11_GetShadowMap(shaderstate.curdlight->fov>0));
break;
}
#endif
BindTexture(tu, &r_nulltex);
BindTexture(tu, r_nulltex);
break;
case T_GEN_CURRENTRENDER://copy the current screen to a texture, and draw that
@ -983,7 +1006,7 @@ static void SelectPassTexture(unsigned int tu, const shaderpass_t *pass)
case T_GEN_RIPPLEMAP: //ripplemap image (water surface distortions-as-fbo)
case T_GEN_SOURCECUBE: //used for render-to-texture targets
BindTexture(tu, &r_nulltex);
BindTexture(tu, r_nulltex);
break;
}
@ -1899,7 +1922,6 @@ static void BE_RenderMeshProgram(const shader_t *s, unsigned int vertcount, unsi
BE_ApplyUniforms(p, perm);
D3D11BE_ApplyShaderBits(s->passes->shaderbits, &s->passes->becache);
/*activate tmus*/
@ -2156,7 +2178,7 @@ qboolean D3D11BE_GenerateRTLightShader(unsigned int lmode)
return false;
return true;
}
qboolean D3D11BE_SelectDLight(dlight_t *dl, vec3_t colour, unsigned int lmode)
qboolean D3D11BE_SelectDLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], unsigned int lmode)
{
if (!D3D11BE_GenerateRTLightShader(lmode))
{

View File

@ -11,298 +11,31 @@ extern D3D_FEATURE_LEVEL d3dfeaturelevel;
void D3D11BE_UnbindAllTextures(void);
//FIXME: need support for cubemaps.
typedef struct d3dtexture_s
ID3D11ShaderResourceView *D3D11_Image_View(const texid_t id)
{
texcom_t com;
ID3D11ShaderResourceView *view;
struct d3dtexture_s *prev;
struct d3dtexture_s *next;
ID3D11Texture2D *tex2d;
char name[1];
} d3d11texture_t;
static d3d11texture_t *d3d11textures;
ID3D11ShaderResourceView *D3D11_Image_View(const texid_t *id)
{
d3d11texture_t *info = (d3d11texture_t*)id->ref;
if (!info)
if (!id || !id->ptr)
return NULL;
if (!info->view)
ID3D11Device_CreateShaderResourceView(pD3DDev11, (ID3D11Resource *)info->tex2d, NULL, &info->view);
return info->view;
}
void D3D11_Image_Shutdown(void)
{
//destroy all named textures
while(d3d11textures)
{
d3d11texture_t *t = d3d11textures;
d3d11textures = t->next;
if (t->view)
ID3D11ShaderResourceView_Release(t->view);
if (t->tex2d)
ID3D11Texture2D_Release(t->tex2d);
free(t);
}
if (!id->ptr2)
ID3D11Device_CreateShaderResourceView(pD3DDev11, (ID3D11Resource *)id->ptr, NULL, (ID3D11ShaderResourceView**)&id->ptr2);
return id->ptr2;
}
void D3D11_DestroyTexture (texid_t tex)
{
d3d11texture_t *t = (d3d11texture_t*)tex.ref;
ID3D11Texture2D *tx = tex.ptr;
if (!t)
if (!tex)
return;
if (t->view)
ID3D11ShaderResourceView_Release(t->view);
if (t->tex2d)
ID3D11Texture2D_Release(t->tex2d);
t->view = NULL;
t->tex2d = NULL;
if (tex->ptr2)
ID3D11ShaderResourceView_Release((ID3D11ShaderResourceView*)tex->ptr2);
tex->ptr2 = NULL;
if (t->prev)
t->prev->next = t->next;
else
d3d11textures = t->next;
if (t->next)
t->next->prev = t->prev;
t->prev = NULL;
t->next = NULL;
free(t);
}
static d3d11texture_t *d3d_lookup_texture(const char *ident)
{
d3d11texture_t *tex;
if (*ident)
{
for (tex = d3d11textures; tex; tex = tex->next)
if (!strcmp(tex->name, ident))
return tex;
}
tex = calloc(1, sizeof(*tex)+strlen(ident));
strcpy(tex->name, ident);
tex->view = NULL;
tex->tex2d = NULL;
tex->next = d3d11textures;
tex->prev = NULL;
d3d11textures = tex;
if (tex->next)
tex->next->prev = tex;
return tex;
}
extern cvar_t gl_picmip;
extern cvar_t gl_picmip2d;
static texid_t ToTexID(d3d11texture_t *tex)
{
texid_t tid;
tid.ref = &tex->com;
if (!tex->view)
ID3D11Device_CreateShaderResourceView(pD3DDev11, (ID3D11Resource *)tex->tex2d, NULL, &tex->view);
tid.ptr = NULL;//(void*)0xdeadbeef;
return tid;
}
//outpitch = width*4
static void D3D_Resize32(void *out, int outpitch, int outwidth, int outheight, const void *in, int inwidth, int inheight)
{
int x, y;
int iny;
unsigned int *row;
const unsigned int *inrow;
for (y = 0; y < outheight; y++)
{
row = (unsigned int*)((char*)out + outpitch*y);
iny = (y * inheight) / outheight;
inrow = (const unsigned int*)in + inwidth*iny;
for (x = 0; x < outwidth; x++)
{
row[x] = inrow[(x * inwidth)/outwidth];
}
}
}
static void D3D_MipMap (qbyte *out, int outwidth, int outheight, const qbyte *in, int inwidth, int inheight)
{
int i, j;
const qbyte *inrow;
//with npot
int rowwidth = inwidth*4; //rowwidth is the byte width of the input
inrow = in;
for (i=0 ; i<outheight ; i++, inrow+=rowwidth*2)
{
for (in = inrow, j=0 ; j<outwidth ; j++, out+=4, in+=8)
{
out[0] = (in[0] + in[4] + in[rowwidth+0] + in[rowwidth+4])>>2;
out[1] = (in[1] + in[5] + in[rowwidth+1] + in[rowwidth+5])>>2;
out[2] = (in[2] + in[6] + in[rowwidth+2] + in[rowwidth+6])>>2;
out[3] = (in[3] + in[7] + in[rowwidth+3] + in[rowwidth+7])>>2;
}
}
}
static void *D3D11_AllocNewTextureData(void *datargba, int datawidth, int dataheight, int width, int height, unsigned int flags)
{
HRESULT hr;
ID3D11Texture2D *tx = NULL;
D3D11_TEXTURE2D_DESC tdesc = {0};
D3D11_SUBRESOURCE_DATA subresdesc[64] = {0};
int i;
int owidth, oheight;
qboolean fakenpot = false;
tdesc.Width = width;
tdesc.Height = height;
tdesc.MipLevels = (!datargba || (flags & IF_NOMIPMAP))?1:0; //0 generates mipmaps automagically
tdesc.ArraySize = 1;
tdesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
tdesc.SampleDesc.Count = 1;
tdesc.SampleDesc.Quality = 0;
tdesc.Usage = datargba?D3D11_USAGE_IMMUTABLE:D3D11_USAGE_DYNAMIC;
tdesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
tdesc.CPUAccessFlags = (datargba)?0:D3D11_CPU_ACCESS_WRITE;
tdesc.MiscFlags = 0;
//first mip level
subresdesc[0].SysMemPitch = width*4;
subresdesc[0].SysMemSlicePitch = width*height*4;
if (!datargba)
{
subresdesc[0].pSysMem = NULL;
//one mip, but no data
i = 1;
}
else
{
if (datawidth != width || dataheight != height)
{
fakenpot = true;
subresdesc[0].pSysMem = malloc(width*height*4);
D3D_Resize32((void*)subresdesc[0].pSysMem, width*4, width, height, datargba, datawidth, dataheight);
}
else
subresdesc[0].pSysMem = datargba;
for (i = 1; i < 64 && width > 1 && height > 1 && !(flags & IF_NOMIPMAP); i++)
{
owidth = width;
oheight = height;
width /= 2;
height /= 2;
subresdesc[i].pSysMem = malloc(width*height*4);
subresdesc[i].SysMemPitch = width*4;
subresdesc[i].SysMemSlicePitch = width*height*4;
D3D_MipMap((void*)subresdesc[i].pSysMem, width, height, subresdesc[i-1].pSysMem, owidth, oheight);
}
}
tdesc.MipLevels = i; //0 generates mipmaps automagically
hr = ID3D11Device_CreateTexture2D(pD3DDev11, &tdesc, (subresdesc[0].pSysMem?subresdesc:NULL), &tx);
if (FAILED(hr))
{
Con_Printf("Failed to create texture\n");
tx = NULL;
}
for (i = fakenpot?0:1; i < tdesc.MipLevels; i++)
{
free((void*)subresdesc[i].pSysMem);
}
return tx;
}
texid_t D3D11_AllocNewTexture(const char *ident, int width, int height, unsigned int flags)
{
d3d11texture_t *t = d3d_lookup_texture("");
texid_t id;
if (t->tex2d)
return ToTexID(t);
t->tex2d = D3D11_AllocNewTextureData(NULL, 0, 0, width, height, flags);
t->com.width = width;
t->com.height = height;
id = ToTexID(t);
if (!t->tex2d)
{
D3D11_DestroyTexture(id);
return r_nulltex;
}
return id;
}
static void D3D11_RoundDimensions(int *scaled_width, int *scaled_height, qboolean mipmap, qboolean clamp)
{
int maxsize;
if (D3D_HAVE_FULL_NPOT() || (!mipmap && clamp))
{ //NPOT is a simple extension that relaxes errors.
//featurelevel 9 supports npot but only if there's no mipmapping or texture coord wrapping.
TRACE(("dbg: D3D11_RoundDimensions: npot\n"));
}
else
{
int width = *scaled_width;
int height = *scaled_height;
for (*scaled_width = 1 ; *scaled_width < width ; *scaled_width<<=1)
;
for (*scaled_height = 1 ; *scaled_height < height ; *scaled_height<<=1)
;
}
if (mipmap)
{
TRACE(("dbg: GL_RoundDimensions: %i\n", gl_picmip.ival));
*scaled_width >>= gl_picmip.ival;
*scaled_height >>= gl_picmip.ival;
}
else
{
*scaled_width >>= gl_picmip2d.ival;
*scaled_height >>= gl_picmip2d.ival;
}
if (d3dfeaturelevel>=D3D_FEATURE_LEVEL_11_0)
maxsize = 16384;
else if (d3dfeaturelevel>=D3D_FEATURE_LEVEL_10_0)
maxsize = 8192;
else if (d3dfeaturelevel>=D3D_FEATURE_LEVEL_9_3)
maxsize = 4096;
else
maxsize = 2048;
if (gl_max_size.ival && maxsize > gl_max_size.ival)
maxsize = gl_max_size.ival;
TRACE(("dbg: GL_RoundDimensions: %i\n", maxsize));
if (maxsize)
{
if (*scaled_width > maxsize)
*scaled_width = maxsize;
if (*scaled_height > maxsize)
*scaled_height = maxsize;
}
if (*scaled_width < 1)
*scaled_width = 1;
if (*scaled_height < 1)
*scaled_height = 1;
if (tex->ptr)
ID3D11Texture2D_Release((ID3D11Texture2D*)tex->ptr);
tex->ptr = NULL;
}
#if 0
static void Upload_Texture_32(ID3D11Texture2D *tex, unsigned int *data, int datawidth, int dataheight, unsigned int flags)
{
int x, y;
@ -373,377 +106,117 @@ static void Upload_Texture_32(ID3D11Texture2D *tex, unsigned int *data, int data
ID3D11DeviceContext_Unmap(d3ddevctx, (ID3D11Resource*)tex, 0);
#endif
}
#endif
//create a basic shader from a 32bit image
static void D3D11_LoadTexture_32(d3d11texture_t *tex, unsigned int *data, int width, int height, int flags)
qboolean D3D11_LoadTextureMips(image_t *tex, struct pendingtextureinfo *mips)
{
int nwidth, nheight;
HRESULT hr;
D3D11_TEXTURE2D_DESC tdesc = {0};
D3D11_SUBRESOURCE_DATA subresdesc[sizeof(mips->mip) / sizeof(mips->mip[0])];
int i;
/*
if (!(flags & TF_MANDATORY))
tdesc.Width = mips->mip[0].width;
tdesc.Height = mips->mip[0].height;
tdesc.ArraySize = 1;
tdesc.SampleDesc.Count = 1;
tdesc.SampleDesc.Quality = 0;
tdesc.Usage = mips->mip[0].data?D3D11_USAGE_IMMUTABLE:D3D11_USAGE_DYNAMIC;
tdesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
tdesc.CPUAccessFlags = (mips->mip[0].data)?0:D3D11_CPU_ACCESS_WRITE;
tdesc.MiscFlags = 0;
if (mips->type == PTI_CUBEMAP)
{
Con_Printf("Texture upload missing flags\n");
return NULL;
tdesc.ArraySize *= 6;
tdesc.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE;
}
*/
else if (mips->type == PTI_3D)
return false; //nyi
nwidth = width;
nheight = height;
D3D11_RoundDimensions(&nwidth, &nheight, !(flags & IF_NOMIPMAP), flags & IF_CLAMP);
if (!tex->tex2d || tex->com.width != nwidth || tex->com.height != nheight)
switch(mips->encoding)
{
tex->com.width = nwidth;
tex->com.height = nheight;
if (tex->tex2d)
ID3D11Texture2D_Release(tex->tex2d);
case PTI_RGBA8:
tdesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
break;
case PTI_RGBX8:
tdesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; //d3d11 has no alphaless format. be sure to proprly disable alpha in the shader.
break;
case PTI_BGRA8:
tdesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
break;
case PTI_BGRX8:
tdesc.Format = DXGI_FORMAT_B8G8R8X8_UNORM;
break;
tex->tex2d = D3D11_AllocNewTextureData(data, width, height, nwidth, nheight, flags);
return;
case PTI_S3RGB1: //d3d11 provides no way to disable alpha with dxt1. be sure to proprly disable alpha in the shader.
case PTI_S3RGBA1:
tdesc.Format = DXGI_FORMAT_BC1_UNORM;
break;
case PTI_S3RGBA3:
tdesc.Format = DXGI_FORMAT_BC2_UNORM;
break;
case PTI_S3RGBA5:
tdesc.Format = DXGI_FORMAT_BC3_UNORM;
break;
}
else
Upload_Texture_32(tex->tex2d, data, width, height, flags);
}
static void D3D11_LoadTexture_8(d3d11texture_t *tex, unsigned char *data, unsigned int *pal32, int width, int height, int flags, enum uploadfmt fmt)
{
static unsigned trans[1024*1024];
int i, s;
qboolean noalpha;
int p;
if (width*height > 1024*1024)
Sys_Error("GL_Upload8: image too big (%i*%i)", width, height);
s = width*height;
// if there are no transparent pixels, make it a 3 component
// texture even if it was specified as otherwise
if (fmt == TF_8PAL24)
if (!mips->mip[0].data)
{
unsigned char *pal24 = (void*)pal32;
//strictly bgr little endian.
for (i=0 ; i<s ; i++)
{
p = data[i];
trans[i] = (pal24[p*3+0] << 0) | (pal24[p*3+1] << 8) | (pal24[p*3+2] << 16) | (255<<24);
}
}
else if (fmt == TF_TRANS8_FULLBRIGHT)
{
noalpha = true;
for (i=0 ; i<s ; i++)
{
p = data[i];
if (p > 255-vid.fullbright)
trans[i] = pal32[p];
else
{
noalpha = false;
trans[i] = 0;
}
}
}
else if ((fmt!=TF_SOLID8) && !(flags & IF_NOALPHA))
{
noalpha = true;
for (i=0 ; i<s ; i++)
{
p = data[i];
if (p == 255)
{
noalpha = false;
trans[i] = 0;
}
else
trans[i] = pal32[p];
}
switch(fmt)
{
default:
if (noalpha)
fmt = TF_SOLID8;
break;
case TF_H2_T7G1:
fmt = TF_TRANS8;
for (i=0 ; i<s ; i++)
{
p = data[i];
if (p == 0)
trans[i] &= 0x00ffffff;
else if( p & 1 )
{
trans[i] &= 0x00ffffff;
trans[i] |= ( ( int )( 255 * 0.5 ) ) << 24;
}
else
{
trans[i] |= 0xff000000;
}
}
break;
case TF_H2_TRANS8_0:
fmt = TF_TRANS8;
for (i=0 ; i<s ; i++)
{
p = data[i];
if (p == 0)
trans[i] &= 0x00ffffff;
}
break;
/* case TF_H2_T4A4:
fmt = TF_TRANS8;
for (i=0 ; i<s ; i++)
{
p = data[i];
trans[i] = d_8to24rgbtable[ColorIndex[p>>4]] & 0x00ffffff;
trans[i] |= ( int )ColorPercent[p&15] << 24;
//trans[i] = 0x7fff0000;
}
break;
*/
}
subresdesc[0].pSysMem = NULL;
//one mip, but no data. happens with rendertargets
tdesc.MipLevels = 1;
}
else
{
for (i=(s&~3)-4 ; i>=0 ; i-=4)
for (i = 0; i < mips->mipcount; i++)
{
trans[i] = pal32[data[i]];
trans[i+1] = pal32[data[i+1]];
trans[i+2] = pal32[data[i+2]];
trans[i+3] = pal32[data[i+3]];
}
for (i=s&~3 ; i<s ; i++) //wow, funky
{
trans[i] = pal32[data[i]];
subresdesc[i].pSysMem = mips->mip[i].data;
subresdesc[i].SysMemPitch = mips->mip[i].width*4;
subresdesc[i].SysMemSlicePitch = mips->mip[i].width*mips->mip[i].height*4;
}
tdesc.MipLevels = i/tdesc.ArraySize;
}
D3D11_LoadTexture_32(tex, trans, width, height, flags);
}
void D3D11_Upload (texid_t id, const char *name, enum uploadfmt fmt, void *data, void *palette, int width, int height, unsigned int flags)
{
d3d11texture_t *tex = (d3d11texture_t *)id.ref;
switch (fmt)
D3D11_DestroyTexture(tex);
hr = ID3D11Device_CreateTexture2D(pD3DDev11, &tdesc, (mips->mip[0].data?subresdesc:NULL), (ID3D11Texture2D**)&tex->ptr);
for (i = 0; i < mips->mipcount; i++)
{
case TF_RGBX32:
flags |= IF_NOALPHA;
//fall through
case TF_RGBA32:
Upload_Texture_32(tex->tex2d, data, width, height, flags);
if (tex->view)
{
tex->view->lpVtbl->Release(tex->view);
tex->view = NULL;
}
ToTexID(tex);
break;
case TF_8PAL24:
D3D11_LoadTexture_8(tex, data, palette, width, height, flags, fmt);
if (tex->view)
{
tex->view->lpVtbl->Release(tex->view);
tex->view = NULL;
}
ToTexID(tex);
break;
case TF_TRANS8:
OutputDebugString(va("D3D11_LoadTextureFmt doesn't support fmt TF_TRANS8 (%s)\n", fmt, name));
break;
default:
OutputDebugString(va("D3D11_LoadTextureFmt doesn't support fmt %i (%s)\n", fmt, name));
break;
if (mips->mip[i].needfree)
BZ_Free(mips->mip[i].data);
}
}
if (mips->extrafree)
BZ_Free(mips->extrafree);
return !FAILED(hr);
}
void D3D11_UploadLightmap(lightmapinfo_t *lm)
{
d3d11texture_t *tex;
extern cvar_t gl_lightmap_nearest;
struct pendingtextureinfo mips;
image_t *tex;
lm->modified = false;
if (!TEXVALID(lm->lightmap_texture))
{
lm->lightmap_texture = R_AllocNewTexture("***lightmap***", LMBLOCK_WIDTH, LMBLOCK_HEIGHT, 0);
if (!lm->lightmap_texture.ref)
lm->lightmap_texture = Image_CreateTexture("***lightmap***", NULL, (gl_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR));
if (!lm->lightmap_texture)
return;
}
tex = (d3d11texture_t*)lm->lightmap_texture.ref;
tex = lm->lightmap_texture;
if (!tex->tex2d)
tex->tex2d = D3D11_AllocNewTextureData(lm->lightmaps, lm->width, lm->height, lm->width, lm->height, 0);
else
{
if (tex->view)
{
ID3D11ShaderResourceView_Release(tex->view);
tex->view = NULL;
}
Upload_Texture_32(tex->tex2d, (void*)lm->lightmaps, lm->width, lm->height, 0);
}
tex->com.width = lm->width;
tex->com.height = lm->height;
mips.extrafree = NULL;
mips.type = PTI_2D;
mips.mip[0].data = lm->lightmaps;
mips.mip[0].needfree = false;
mips.mip[0].width = lm->width;
mips.mip[0].height = lm->height;
mips.encoding = PTI_RGBX8;
mips.mipcount = 1;
D3D11_LoadTextureMips(tex, &mips);
tex->width = lm->width;
tex->height = lm->height;
lm->lightmap_texture = ToTexID(tex);
}
static void genNormalMap(unsigned int *nmap, qbyte *pixels, int w, int h, float scale)
{
int i, j, wr, hr;
unsigned char r, g, b;
float sqlen, reciplen, nx, ny, nz;
const float oneOver255 = 1.0f/255.0f;
float c, cx, cy, dcx, dcy;
wr = w;
hr = h;
for (i=0; i<h; i++)
{
for (j=0; j<w; j++)
{
/* Expand [0,255] texel values to the [0,1] range. */
c = pixels[i*wr + j] * oneOver255;
/* Expand the texel to its right. */
cx = pixels[i*wr + (j+1)%wr] * oneOver255;
/* Expand the texel one up. */
cy = pixels[((i+1)%hr)*wr + j] * oneOver255;
dcx = scale * (c - cx);
dcy = scale * (c - cy);
/* Normalize the vector. */
sqlen = dcx*dcx + dcy*dcy + 1;
reciplen = 1.0f/(float)sqrt(sqlen);
nx = dcx*reciplen;
ny = -dcy*reciplen;
nz = reciplen;
/* Repack the normalized vector into an RGB unsigned qbyte
vector in the normal map image. */
r = (qbyte) (128 + 127*nx);
g = (qbyte) (128 + 127*ny);
b = (qbyte) (128 + 127*nz);
/* The highest resolution mipmap level always has a
unit length magnitude. */
nmap[i*w+j] = LittleLong ((pixels[i*wr + j] << 24)|(b << 16)|(g << 8)|(r)); // <AWE> Added support for big endian.
}
}
}
texid_t D3D11_LoadTexture (const char *identifier, int width, int height, enum uploadfmt fmt, void *data, unsigned int flags)
{
d3d11texture_t *tex;
switch (fmt)
{
case TF_TRANS8_FULLBRIGHT:
{
qbyte *d = data;
unsigned int c = width * height;
while (c)
{
if (d[--c] > 255 - vid.fullbright)
break;
}
/*reject it if there's no fullbrights*/
if (!c)
return r_nulltex;
}
break;
case TF_INVALID:
case TF_RGBA32:
case TF_BGRA32:
case TF_RGBX32:
case TF_RGB24:
case TF_BGR24_FLIP:
case TF_SOLID8:
case TF_TRANS8:
case TF_HEIGHT8:
case TF_HEIGHT8PAL:
case TF_H2_T7G1:
case TF_H2_TRANS8_0:
case TF_H2_T4A4:
case TF_PALETTES:
case TF_8PAL24:
case TF_8PAL32:
break;
}
tex = d3d_lookup_texture(identifier);
if (tex->tex2d) //already loaded
return ToTexID(tex);
switch (fmt)
{
case TF_HEIGHT8PAL:
{
extern cvar_t r_shadow_bumpscale_basetexture;
unsigned int *norm = malloc(width*height*4);
genNormalMap(norm, data, width, height, r_shadow_bumpscale_basetexture.value);
D3D11_LoadTexture_32(tex, norm, width, height, flags);
free(norm);
return ToTexID(tex);
}
case TF_HEIGHT8:
{
extern cvar_t r_shadow_bumpscale_basetexture;
unsigned int *norm = malloc(width*height*4);
genNormalMap(norm, data, width, height, r_shadow_bumpscale_basetexture.value);
D3D11_LoadTexture_32(tex, norm, width, height, flags);
free(norm);
return ToTexID(tex);
}
case TF_SOLID8:
case TF_TRANS8:
case TF_H2_T7G1:
case TF_H2_TRANS8_0:
case TF_H2_T4A4:
case TF_TRANS8_FULLBRIGHT:
D3D11_LoadTexture_8(tex, data, d_8to24rgbtable, width, height, flags, fmt);
return ToTexID(tex);
case TF_RGBX32:
flags |= IF_NOALPHA;
case TF_RGBA32:
D3D11_LoadTexture_32(tex, data, width, height, flags);
return ToTexID(tex);
default:
OutputDebugString(va("D3D11_LoadTexture doesn't support fmt %i (%s)\n", fmt, identifier));
return r_nulltex;
}
}
texid_t D3D11_LoadCompressed (const char *name)
{
return r_nulltex;
}
texid_t D3D11_FindTexture (const char *identifier, unsigned int flags)
{
d3d11texture_t *tex = d3d_lookup_texture(identifier);
if (tex->tex2d)
return ToTexID(tex);
return r_nulltex;
}
texid_t D3D11_LoadTexture8Pal32 (const char *identifier, int width, int height, qbyte *data, qbyte *palette32, unsigned int flags)
{
d3d11texture_t *tex = d3d_lookup_texture(identifier);
D3D11_LoadTexture_8(tex, data, (unsigned int *)palette32, width, height, flags, TF_SOLID8);
return ToTexID(tex);
}
texid_t D3D11_LoadTexture8Pal24 (const char *identifier, int width, int height, qbyte *data, qbyte *palette24, unsigned int flags)
{
unsigned int pal32[256];
int i;
for (i = 0; i < 256; i++)
{
pal32[i] = (255<<24) |
(palette24[i*3+2]<<16) |
(palette24[i*3+1]<<8) |
(palette24[i*3+0]<<0);
}
return D3D11_LoadTexture8Pal32(identifier, width, height, data, (qbyte*)pal32, flags);
lm->lightmap_texture = tex;
}
#ifdef RTLIGHTS
@ -755,29 +228,26 @@ static const int shadowfmts[][3] =
{DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_D16_UNORM},
{DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM}
};
d3d11texture_t shadowmap_texture[2];
image_t shadowmap_texture[2];
ID3D11DepthStencilView *shadowmap_dsview[2];
ID3D11RenderTargetView *shadowmap_rtview[2];
texid_t D3D11_GetShadowMap(int id)
{
d3d11texture_t *tex = &shadowmap_texture[id];
texid_t tid;
if (!tex->tex2d)
texid_t tex = &shadowmap_texture[id];
if (!tex->ptr)
{
return r_nulltex;
}
tid.ref = &tex->com;
if (!tex->view)
if (!tex->ptr2)
{
D3D11_SHADER_RESOURCE_VIEW_DESC desc;
desc.Format = shadowfmts[shadowfmt][0];
desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
desc.Texture2D.MostDetailedMip = 0;
desc.Texture2D.MipLevels = -1;
ID3D11Device_CreateShaderResourceView(pD3DDev11, (ID3D11Resource *)tex->tex2d, &desc, &tex->view);
ID3D11Device_CreateShaderResourceView(pD3DDev11, (ID3D11Resource *)tex->ptr, &desc, (ID3D11ShaderResourceView**)&tex->ptr2);
}
tid.ptr = NULL;
return tid;
return tex;
}
void D3D11_TerminateShadowMap(void)
{
@ -787,9 +257,7 @@ void D3D11_TerminateShadowMap(void)
if (shadowmap_dsview[i])
ID3D11DepthStencilView_Release(shadowmap_dsview[i]);
shadowmap_dsview[i] = NULL;
if (shadowmap_texture[i].tex2d)
ID3D11DepthStencilView_Release(shadowmap_texture[i].tex2d);
shadowmap_texture[i].tex2d = NULL;
D3D11_DestroyTexture(&shadowmap_texture[i]);
}
}
qboolean D3D11_BeginShadowMap(int id, int w, int h)
@ -817,9 +285,9 @@ qboolean D3D11_BeginShadowMap(int id, int w, int h)
texdesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
// Create the texture
if (!shadowmap_texture[id].tex2d)
if (!shadowmap_texture[id].ptr)
{
hr = ID3D11Device_CreateTexture2D(pD3DDev11, &texdesc, NULL, &shadowmap_texture[id].tex2d);
hr = ID3D11Device_CreateTexture2D(pD3DDev11, &texdesc, NULL, (ID3D11Texture2D **)&shadowmap_texture[id].ptr);
if (FAILED(hr))
return false;
}
@ -827,7 +295,7 @@ qboolean D3D11_BeginShadowMap(int id, int w, int h)
if (shadowfmt == 2)
{
hr = ID3D11Device_CreateRenderTargetView(pD3DDev11, (ID3D11Resource *)shadowmap_texture[id].tex2d, NULL, &shadowmap_rtview[id]);
hr = ID3D11Device_CreateRenderTargetView(pD3DDev11, (ID3D11Resource *)shadowmap_texture[id].ptr, NULL, &shadowmap_rtview[id]);
}
else
{
@ -836,7 +304,7 @@ qboolean D3D11_BeginShadowMap(int id, int w, int h)
rtdesc.Flags = 0;
rtdesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
rtdesc.Texture2D.MipSlice = 0;
hr = ID3D11Device_CreateDepthStencilView(pD3DDev11, (ID3D11Resource *)shadowmap_texture[id].tex2d, &rtdesc, &shadowmap_dsview[id]);
hr = ID3D11Device_CreateDepthStencilView(pD3DDev11, (ID3D11Resource *)shadowmap_texture[id].ptr, &rtdesc, &shadowmap_dsview[id]);
}
if (FAILED(hr))
return false;

View File

@ -172,7 +172,8 @@ typedef struct
vbo_t *batchvbo;
shader_t *shader_rtlight;
texid_t curtex[MAX_TMUS];
IDirect3DTexture9 *curtex[MAX_TMUS];
unsigned int curtexflags[MAX_TMUS];
unsigned int tmuflags[MAX_TMUS];
mesh_t **meshlist;
@ -205,6 +206,9 @@ typedef struct
unsigned int wbatch;
unsigned int maxwbatches;
batch_t *wbatches;
int mipfilter[3];
int picfilter[3];
} d3dbackend_t;
typedef struct
@ -253,9 +257,11 @@ static IDirect3DVertexDeclaration9 *vertexdecls[D3D_VDEC_MAX];
static void BE_ApplyTMUState(unsigned int tu, unsigned int flags)
{
if ((flags ^ shaderstate.tmuflags[tu]) & SHADER_PASS_CLAMP)
unsigned int delta = shaderstate.tmuflags[tu] ^ flags;
if (!delta)
return;
if (delta & SHADER_PASS_CLAMP)
{
shaderstate.tmuflags[tu] ^= SHADER_PASS_CLAMP;
if (flags & SHADER_PASS_CLAMP)
{
IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
@ -269,22 +275,44 @@ static void BE_ApplyTMUState(unsigned int tu, unsigned int flags)
IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_ADDRESSW, D3DTADDRESS_WRAP);
}
}
if ((flags ^ shaderstate.tmuflags[tu]) & SHADER_PASS_NOMIPMAP)
if (delta & (SHADER_PASS_NOMIPMAP|SHADER_PASS_NEAREST|SHADER_PASS_LINEAR|SHADER_PASS_UIPIC))
{
shaderstate.tmuflags[tu] ^= SHADER_PASS_NOMIPMAP;
/*lightmaps don't use mipmaps*/
if (flags & SHADER_PASS_NOMIPMAP)
{
IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_MIPFILTER, D3DTEXF_NONE);
IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
}
int min, mip, mag;
int *filter = (flags & SHADER_PASS_UIPIC)?shaderstate.picfilter:shaderstate.mipfilter;
if ((filter[2] && !(flags & SHADER_PASS_NEAREST)) || (flags & SHADER_PASS_LINEAR))
mag = D3DTEXF_LINEAR;
else
{
IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
}
mag = D3DTEXF_POINT;
if (filter[1] == -1 || (flags & IF_NOMIPMAP))
mip = D3DTEXF_NONE;
else if ((filter[1] && !(flags & SHADER_PASS_NEAREST)) || (flags & SHADER_PASS_LINEAR))
mip = D3DTEXF_LINEAR;
else
mip = D3DTEXF_POINT;
if ((filter[0] && !(flags & SHADER_PASS_NEAREST)) || (flags & SHADER_PASS_LINEAR))
min = D3DTEXF_LINEAR;
else
min = D3DTEXF_POINT;
IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_MINFILTER, min);
IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_MIPFILTER, mip);
IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_MAGFILTER, mag);
}
shaderstate.tmuflags[tu] = flags;
}
//d3d9 is all sampler state
void D3D9_UpdateFiltering(image_t *imagelist, int filtermip[3], int filterpic[3], int mipcap[2], float anis)
{
int i;
memcpy(shaderstate.mipfilter, filtermip, sizeof(shaderstate.mipfilter));
memcpy(shaderstate.picfilter, filterpic, sizeof(shaderstate.picfilter));
for (i = 0; i < MAX_TMUS; i++)
{
shaderstate.tmuflags[i] = ~shaderstate.tmuflags[i];
BE_ApplyTMUState(i, ~shaderstate.tmuflags[i]);
}
}
@ -655,12 +683,20 @@ static unsigned int allocindexbuffer(void **dest, unsigned int entries)
return offset/sizeof(index_t);
}
static void BindTexture(unsigned int tu, void *id)
static void BindTexture(unsigned int tu, texid_t tex)
{
if (shaderstate.curtex[tu].ptr != id)
IDirect3DTexture9 *dt;
if (tex)
{
shaderstate.curtex[tu].ptr = id;
IDirect3DDevice9_SetTexture (pD3DDev9, tu, id);
dt = tex->ptr;
shaderstate.curtexflags[tu] = tex->flags & SHADER_PASS_IMAGE_FLAGS;
}
else
dt = NULL;
if (shaderstate.curtex[tu] != dt)
{
shaderstate.curtex[tu] = dt;
IDirect3DDevice9_SetTexture (pD3DDev9, tu, (void*)dt);
}
}
@ -673,48 +709,48 @@ static void SelectPassTexture(unsigned int tu, shaderpass_t *pass)
{
default:
case T_GEN_DIFFUSE:
if (shaderstate.curtexnums->base.ptr)
BindTexture(tu, shaderstate.curtexnums->base.ptr);
if (shaderstate.curtexnums->base)
BindTexture(tu, shaderstate.curtexnums->base);
else
BindTexture(tu, missing_texture.ptr);
BindTexture(tu, missing_texture);
break;
case T_GEN_NORMALMAP:
BindTexture( tu, shaderstate.curtexnums->bump.ptr);
BindTexture( tu, shaderstate.curtexnums->bump);
break;
case T_GEN_SPECULAR:
BindTexture(tu, shaderstate.curtexnums->specular.ptr);
BindTexture(tu, shaderstate.curtexnums->specular);
break;
case T_GEN_UPPEROVERLAY:
BindTexture(tu, shaderstate.curtexnums->upperoverlay.ptr);
BindTexture(tu, shaderstate.curtexnums->upperoverlay);
break;
case T_GEN_LOWEROVERLAY:
BindTexture(tu, shaderstate.curtexnums->loweroverlay.ptr);
BindTexture(tu, shaderstate.curtexnums->loweroverlay);
break;
case T_GEN_FULLBRIGHT:
BindTexture(tu, shaderstate.curtexnums->fullbright.ptr);
BindTexture(tu, shaderstate.curtexnums->fullbright);
break;
case T_GEN_ANIMMAP:
BindTexture(tu, pass->anim_frames[(int)(pass->anim_fps * shaderstate.curtime) % pass->anim_numframes].ptr);
BindTexture(tu, pass->anim_frames[(int)(pass->anim_fps * shaderstate.curtime) % pass->anim_numframes]);
break;
case T_GEN_SINGLEMAP:
BindTexture(tu, pass->anim_frames[0].ptr);
BindTexture(tu, pass->anim_frames[0]);
break;
case T_GEN_DELUXMAP:
BindTexture(tu, shaderstate.curdeluxmap.ptr);
BindTexture(tu, shaderstate.curdeluxmap);
break;
case T_GEN_LIGHTMAP:
BindTexture(tu, shaderstate.curlightmap.ptr);
BindTexture(tu, shaderstate.curlightmap);
break;
/*case T_GEN_CURRENTRENDER:
FIXME: no code to grab the current screen and convert to a texture
break;*/
case T_GEN_VIDEOMAP:
BindTexture(tu, Media_UpdateForShader(pass->cin).ptr);
BindTexture(tu, Media_UpdateForShader(pass->cin));
break;
}
BE_ApplyTMUState(tu, pass->flags);
BE_ApplyTMUState(tu, shaderstate.curtexflags[tu]|pass->flags);
if (tu == 0)
{
@ -2158,7 +2194,7 @@ void D3D9BE_SelectMode(backendmode_t mode)
BE_ApplyShaderBits(SBITS_MASK_BITS);
}
qboolean D3D9BE_SelectDLight(dlight_t *dl, vec3_t colour, unsigned int lmode)
qboolean D3D9BE_SelectDLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], unsigned int lmode)
{
shaderstate.curdlight = dl;
VectorCopy(colour, shaderstate.curdlight_colours);
@ -2525,17 +2561,22 @@ static void BE_UploadLightmaps(qboolean force)
if (lightmap[i]->modified)
{
IDirect3DTexture9 *tex = lm->lightmap_texture.ptr;
extern cvar_t gl_lightmap_nearest;
IDirect3DTexture9 *tex;
D3DLOCKED_RECT lock;
RECT rect;
glRect_t *theRect = &lm->rectchange;
int r;
if (!lm->lightmap_texture)
lm->lightmap_texture = Image_CreateTexture("", NULL, (gl_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR)|IF_NOMIPMAP);
tex = lm->lightmap_texture->ptr;
if (!tex)
{
lm->lightmap_texture = R_AllocNewTexture("***lightmap***", lm->width, lm->height, 0);
tex = lm->lightmap_texture.ptr;
IDirect3DDevice9_CreateTexture(pD3DDev9, lm->width, lm->height, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &tex, NULL);
if (!tex)
continue;
lm->lightmap_texture->ptr = tex;
}
lm->modified = 0;
@ -2713,10 +2754,10 @@ void D3D9BE_SubmitBatch(batch_t *batch)
shaderstate.curtexnums = batch->skin?batch->skin:&batch->shader->defaulttextures;
shaderstate.curbatch = batch;
shaderstate.flags = batch->flags;
if (batch->lightmap[0] < 0)
shaderstate.curlightmap = r_nulltex;
else
if ((unsigned)batch->lightmap[0] < (unsigned)numlightmaps)
shaderstate.curlightmap = lightmap[batch->lightmap[0]]->lightmap_texture;
else
shaderstate.curlightmap = r_nulltex;
BE_DrawMeshChain_Internal();
}

View File

@ -8,156 +8,6 @@
#include <d3d9.h>
extern LPDIRECT3DDEVICE9 pD3DDev9;
typedef struct d3dtexture_s
{
texcom_t com;
struct d3dtexture_s *next;
texid_t tex;
char name[1];
} d3dtexture_t;
static d3dtexture_t *d3dtextures;
void D3D9_Image_Shutdown(void)
{
LPDIRECT3DTEXTURE9 tx;
while(d3dtextures)
{
d3dtexture_t *t = d3dtextures;
d3dtextures = t->next;
tx = t->tex.ptr;
if (tx)
IDirect3DTexture9_Release(tx);
free(t);
}
}
static d3dtexture_t *d3d_lookup_texture(const char *ident)
{
d3dtexture_t *tex;
if (*ident)
{
for (tex = d3dtextures; tex; tex = tex->next)
if (!strcmp(tex->name, ident))
return tex;
}
tex = calloc(1, sizeof(*tex)+strlen(ident));
strcpy(tex->name, ident);
tex->tex.ptr = NULL;
tex->tex.ref = &tex->com;
tex->next = d3dtextures;
d3dtextures = tex;
return tex;
}
extern cvar_t gl_picmip;
extern cvar_t gl_picmip2d;
texid_t D3D9_AllocNewTexture(const char *ident, int width, int height, unsigned int flags)
{
IDirect3DTexture9 *tx;
/*unconditionally allocate a new texture*/
d3dtexture_t *tex = calloc(1, sizeof(*tex)+strlen(ident));
strcpy(tex->name, ident);
tex->tex.ptr = NULL;
tex->tex.ref = &tex->com;
tex->next = d3dtextures;
d3dtextures = tex;
if (!tex->tex.ptr)
{
if (!FAILED(IDirect3DDevice9_CreateTexture(pD3DDev9, width, height, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &tx, NULL)))
tex->tex.ptr = tx;
}
return tex->tex;
}
void D3D9_DestroyTexture (texid_t tex)
{
d3dtexture_t **link;
for (link = &d3dtextures; *link; link = &(*link)->next)
{
if (*link == (d3dtexture_t*)tex.ref)
{
*link = (*link)->next;
if (tex.ptr)
IDirect3DTexture9_Release((IDirect3DTexture9*)tex.ptr);
return;
}
}
}
static void D3D9_RoundDimensions(int *scaled_width, int *scaled_height, qboolean mipmap)
{
// if (gl_config.arb_texture_non_power_of_two) //NPOT is a simple extension that relaxes errors.
// {
// TRACE(("dbg: GL_RoundDimensions: GL_ARB_texture_non_power_of_two\n"));
// }
// else
{
int width = *scaled_width;
int height = *scaled_height;
for (*scaled_width = 1 ; *scaled_width < width ; *scaled_width<<=1)
;
for (*scaled_height = 1 ; *scaled_height < height ; *scaled_height<<=1)
;
}
if (mipmap)
{
TRACE(("dbg: GL_RoundDimensions: %i\n", gl_picmip.ival));
*scaled_width >>= gl_picmip.ival;
*scaled_height >>= gl_picmip.ival;
}
else
{
*scaled_width >>= gl_picmip2d.ival;
*scaled_height >>= gl_picmip2d.ival;
}
TRACE(("dbg: GL_RoundDimensions: %i\n", gl_max_size.ival));
if (gl_max_size.ival)
{
if (*scaled_width > gl_max_size.ival)
*scaled_width = gl_max_size.ival;
if (*scaled_height > gl_max_size.ival)
*scaled_height = gl_max_size.ival;
}
if (*scaled_width < 1)
*scaled_width = 1;
if (*scaled_height < 1)
*scaled_height = 1;
}
#if 0
static void D3D_MipMap (qbyte *out, int outwidth, int outheight, qbyte *in, int inwidth, int inheight)
{
int i, j;
qbyte *inrow;
//with npot
int rowwidth = inwidth*4; //rowwidth is the byte width of the input
inrow = in;
for (i=0 ; i<outheight ; i++, inrow+=rowwidth*2)
{
for (in = inrow, j=0 ; j<outwidth ; j++, out+=4, in+=8)
{
out[0] = (in[0] + in[4] + in[rowwidth+0] + in[rowwidth+4])>>2;
out[1] = (in[1] + in[5] + in[rowwidth+1] + in[rowwidth+5])>>2;
out[2] = (in[2] + in[6] + in[rowwidth+2] + in[rowwidth+6])>>2;
out[3] = (in[3] + in[7] + in[rowwidth+3] + in[rowwidth+7])>>2;
}
}
}
#endif
static void Upload_Texture_32(LPDIRECT3DTEXTURE9 tex, unsigned int *data, int width, int height, unsigned int flags)
{
int x, y;
@ -228,332 +78,99 @@ static void Upload_Texture_32(LPDIRECT3DTEXTURE9 tex, unsigned int *data, int wi
IDirect3DTexture9_UnlockRect(tex, 0);
}
//create a basic shader from a 32bit image
static void D3D9_LoadTexture_32(d3dtexture_t *tex, unsigned int *data, int width, int height, int flags)
void D3D9_DestroyTexture (texid_t tex)
{
int nwidth, nheight;
if (!tex)
return;
/*
if (!(flags & TF_MANDATORY))
{
Con_Printf("Texture upload missing flags\n");
return NULL;
}
*/
nwidth = width;
nheight = height;
D3D9_RoundDimensions(&nwidth, &nheight, !(flags & IF_NOMIPMAP));
if (!tex->tex.ptr)
{
LPDIRECT3DTEXTURE9 newsurf;
IDirect3DDevice9_CreateTexture(pD3DDev9, nwidth, nheight, (flags & IF_NOMIPMAP)?1:0, ((flags & IF_NOMIPMAP)?0:D3DUSAGE_AUTOGENMIPMAP), D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &newsurf, NULL);
if (!newsurf)
return;
tex->tex.ptr = newsurf;
}
tex->com.width = width;
tex->com.height = height;
Upload_Texture_32(tex->tex.ptr, data, width, height, flags);
if (tex->ptr)
IDirect3DTexture9_Release((IDirect3DTexture9*)tex->ptr);
tex->ptr = NULL;
}
static void D3D9_LoadTexture_8(d3dtexture_t *tex, unsigned char *data, unsigned int *pal32, int width, int height, int flags, enum uploadfmt fmt)
qboolean D3D9_LoadTextureMips(image_t *tex, struct pendingtextureinfo *mips)
{
static unsigned trans[1024*1024];
int i, s;
qboolean noalpha;
int p;
qbyte *fte_restrict out, *fte_restrict in;
int x, y, i;
D3DLOCKED_RECT lock;
D3DFORMAT fmt;
D3DSURFACE_DESC desc;
IDirect3DTexture9 *dt;
qboolean swap = false;
if (width*height > 1024*1024)
Sys_Error("GL_Upload8: image too big (%i*%i)", width, height);
s = width*height;
// if there are no transparent pixels, make it a 3 component
// texture even if it was specified as otherwise
if (fmt == TF_TRANS8_FULLBRIGHT)
switch(mips->encoding)
{
for (i=0 ; i<s ; i++)
{
p = data[i];
noalpha = true;
if (p > 255-vid.fullbright)
trans[i] = pal32[p];
else
{
noalpha = false;
trans[i] = 0;
}
}
case PTI_RGBA8:
fmt = D3DFMT_A8R8G8B8;
swap = true;
break;
case PTI_RGBX8:
fmt = D3DFMT_X8R8G8B8;
swap = true;
break;
case PTI_BGRA8:
fmt = D3DFMT_A8R8G8B8;
break;
case PTI_BGRX8:
fmt = D3DFMT_X8R8G8B8;
break;
//too lazy to support these for now
case PTI_S3RGB1:
case PTI_S3RGBA1:
case PTI_S3RGBA3:
case PTI_S3RGBA5:
return false;
default: //no idea
return false;
}
else if ((fmt!=TF_SOLID8) && !(flags & IF_NOALPHA))
if (FAILED(IDirect3DDevice9_CreateTexture(pD3DDev9, mips->mip[0].width, mips->mip[0].height, mips->mipcount, 0, fmt, D3DPOOL_MANAGED, &dt, NULL)))
return false;
for (i = 0; i < mips->mipcount; i++)
{
noalpha = true;
for (i=0 ; i<s ; i++)
IDirect3DTexture9_GetLevelDesc(dt, i, &desc);
if (mips->mip[i].height != desc.Height || mips->mip[i].width != desc.Width)
{
p = data[i];
if (p == 255)
{
noalpha = false;
trans[i] = 0;
}
else
trans[i] = pal32[p];
IDirect3DTexture9_Release(dt);
return false;
}
switch(fmt)
IDirect3DTexture9_LockRect(dt, i, &lock, NULL, D3DLOCK_NOSYSLOCK|D3DLOCK_DISCARD);
//can't do it in one go. pitch might contain padding or be upside down.
if (swap)
{
default:
if (noalpha)
fmt = TF_SOLID8;
break;
case TF_H2_T7G1:
fmt = TF_TRANS8;
for (i=0 ; i<s ; i++)
for (y = 0, out = lock.pBits, in = mips->mip[i].data; y < mips->mip[i].height; y++, out += lock.Pitch, in += mips->mip[i].width*4)
{
p = data[i];
if (p == 0)
trans[i] &= 0x00ffffff;
else if( p & 1 )
for (x = 0; x < mips->mip[i].width*4; x+=4)
{
trans[i] &= 0x00ffffff;
trans[i] |= ( ( int )( 255 * 0.5 ) ) << 24;
}
else
{
trans[i] |= 0xff000000;
out[x+0] = in[x+2];
out[x+1] = in[x+1];
out[x+2] = in[x+0];
out[x+3] = in[x+3];
}
}
break;
case TF_H2_TRANS8_0:
fmt = TF_TRANS8;
for (i=0 ; i<s ; i++)
{
p = data[i];
if (p == 0)
trans[i] &= 0x00ffffff;
}
break;
/* case TF_H2_T4A4:
fmt = TF_TRANS8;
for (i=0 ; i<s ; i++)
{
p = data[i];
trans[i] = d_8to24rgbtable[ColorIndex[p>>4]] & 0x00ffffff;
trans[i] |= ( int )ColorPercent[p&15] << 24;
//trans[i] = 0x7fff0000;
}
break;
*/
}
}
else
{
for (i=(s&~3)-4 ; i>=0 ; i-=4)
else
{
trans[i] = pal32[data[i]];
trans[i+1] = pal32[data[i+1]];
trans[i+2] = pal32[data[i+2]];
trans[i+3] = pal32[data[i+3]];
}
for (i=s&~3 ; i<s ; i++) //wow, funky
{
trans[i] = pal32[data[i]];
for (y = 0, out = lock.pBits, in = mips->mip[i].data; y < mips->mip[i].height; y++, out += lock.Pitch, in += mips->mip[i].width*4)
memcpy(out, in, mips->mip[i].width*4);
}
IDirect3DTexture9_UnlockRect(dt, i);
}
D3D9_LoadTexture_32(tex, trans, width, height, flags);
D3D9_DestroyTexture(tex);
tex->ptr = dt;
return true;
}
static void genNormalMap(unsigned int *nmap, qbyte *pixels, int w, int h, float scale)
void D3D9_UploadLightmap(lightmapinfo_t *lm)
{
int i, j, wr, hr;
unsigned char r, g, b;
float sqlen, reciplen, nx, ny, nz;
const float oneOver255 = 1.0f/255.0f;
float c, cx, cy, dcx, dcy;
wr = w;
hr = h;
for (i=0; i<h; i++)
{
for (j=0; j<w; j++)
{
/* Expand [0,255] texel values to the [0,1] range. */
c = pixels[i*wr + j] * oneOver255;
/* Expand the texel to its right. */
cx = pixels[i*wr + (j+1)%wr] * oneOver255;
/* Expand the texel one up. */
cy = pixels[((i+1)%hr)*wr + j] * oneOver255;
dcx = scale * (c - cx);
dcy = scale * (c - cy);
/* Normalize the vector. */
sqlen = dcx*dcx + dcy*dcy + 1;
reciplen = 1.0f/(float)sqrt(sqlen);
nx = dcx*reciplen;
ny = -dcy*reciplen;
nz = reciplen;
/* Repack the normalized vector into an RGB unsigned qbyte
vector in the normal map image. */
r = (qbyte) (128 + 127*nx);
g = (qbyte) (128 + 127*ny);
b = (qbyte) (128 + 127*nz);
/* The highest resolution mipmap level always has a
unit length magnitude. */
nmap[i*w+j] = LittleLong ((pixels[i*wr + j] << 24)|(b << 16)|(g << 8)|(r)); // <AWE> Added support for big endian.
}
}
}
void D3D9_Upload (texid_t tex, const char *name, enum uploadfmt fmt, void *data, void *palette, int width, int height, unsigned int flags)
{
switch (fmt)
{
case TF_RGBX32:
flags |= IF_NOALPHA;
//fall through
case TF_RGBA32:
tex.ref->width = width;
tex.ref->height = height;
Upload_Texture_32(tex.ptr, data, width, height, flags);
break;
case TF_8PAL24:
{
qbyte *pal24 = palette;
unsigned int pal32[256];
int i;
for (i = 0; i < 256; i++)
{
pal32[i] = 0x00000000 |
(pal24[i*3+2]<<24) |
(pal24[i*3+1]<<8) |
(pal24[i*3+0]<<0);
}
D3D9_LoadTexture_8((d3dtexture_t*)tex.ref, data, (unsigned int *)pal32, width, height, flags, fmt);
}
break;
default:
OutputDebugString(va("D3D9_Upload doesn't support fmt %i (%s)", fmt, name));
break;
}
}
texid_t D3D9_LoadTexture (const char *identifier, int width, int height, enum uploadfmt fmt, void *data, unsigned int flags)
{
d3dtexture_t *tex;
switch (fmt)
{
case TF_TRANS8_FULLBRIGHT:
{
qbyte *d = data;
unsigned int c = width * height;
while (c)
{
if (d[--c] > 255 - vid.fullbright)
break;
}
/*reject it if there's no fullbrights*/
if (!c)
return r_nulltex;
}
break;
case TF_INVALID:
case TF_RGBA32:
case TF_BGRA32:
case TF_RGBX32:
case TF_RGB24:
case TF_BGR24_FLIP:
case TF_SOLID8:
case TF_TRANS8:
case TF_HEIGHT8:
case TF_HEIGHT8PAL:
case TF_H2_T7G1:
case TF_H2_TRANS8_0:
case TF_H2_T4A4:
case TF_PALETTES:
case TF_8PAL24:
case TF_8PAL32:
break;
}
tex = d3d_lookup_texture(identifier);
switch (fmt)
{
case TF_HEIGHT8PAL:
{
texid_t t;
extern cvar_t r_shadow_bumpscale_basetexture;
unsigned int *norm = malloc(width*height*4);
genNormalMap(norm, data, width, height, r_shadow_bumpscale_basetexture.value);
t = D3D9_LoadTexture(identifier, width, height, TF_RGBA32, data, flags);
free(norm);
return t;
}
case TF_HEIGHT8:
{
extern cvar_t r_shadow_bumpscale_basetexture;
unsigned int *norm = malloc(width*height*4);
genNormalMap(norm, data, width, height, r_shadow_bumpscale_basetexture.value);
D3D9_LoadTexture_32(tex, norm, width, height, flags);
free(norm);
return tex->tex;
}
case TF_SOLID8:
case TF_TRANS8:
case TF_H2_T7G1:
case TF_H2_TRANS8_0:
case TF_H2_T4A4:
case TF_TRANS8_FULLBRIGHT:
D3D9_LoadTexture_8(tex, data, d_8to24rgbtable, width, height, flags, fmt);
return tex->tex;
case TF_RGBX32:
flags |= IF_NOALPHA;
case TF_RGBA32:
D3D9_LoadTexture_32(tex, data, width, height, flags);
return tex->tex;
default:
OutputDebugString(va("D3D9_LoadTexture doesn't support fmt %i (%s)\n", fmt, identifier));
return r_nulltex;
}
}
texid_t D3D9_LoadCompressed (const char *name)
{
return r_nulltex;
}
texid_t D3D9_FindTexture (const char *identifier, unsigned int flags)
{
d3dtexture_t *tex = d3d_lookup_texture(identifier);
if (tex->tex.ptr)
return tex->tex;
return r_nulltex;
}
texid_t D3D9_LoadTexture8Pal32 (const char *identifier, int width, int height, qbyte *data, qbyte *palette32, unsigned int flags)
{
d3dtexture_t *tex = d3d_lookup_texture(identifier);
D3D9_LoadTexture_8(tex, data, (unsigned int *)palette32, width, height, flags, TF_SOLID8);
return tex->tex;
}
texid_t D3D9_LoadTexture8Pal24 (const char *identifier, int width, int height, qbyte *data, qbyte *palette24, unsigned int flags)
{
unsigned int pal32[256];
int i;
for (i = 0; i < 256; i++)
{
pal32[i] = 0x00000000 |
(palette24[i*3+2]<<24) |
(palette24[i*3+1]<<8) |
(palette24[i*3+0]<<0);
}
return D3D9_LoadTexture8Pal32(identifier, width, height, data, (qbyte*)pal32, flags);
}
#endif

View File

@ -734,43 +734,6 @@ static qboolean D3D9_VID_Init(rendererstate_t *info, unsigned char *palette)
return true;
}
/*a new model has been loaded*/
static void (D3D9_R_NewMap) (void)
{
r_worldentity.model = cl.worldmodel;
#ifdef MAP_PROC
if (cl.worldmodel && cl.worldmodel->fromgame == fg_doom3)
D3_GenerateAreas(cl.worldmodel);
#endif
/*wipe any lingering particles*/
P_ClearParticles();
CL_RegisterParticles();
R_AnimateLight();
Surf_DeInit();
Surf_WipeStains();
Surf_BuildLightmaps();
TP_NewMap();
R_SetSky(cl.skyname);
#ifdef RTLIGHTS
Sh_PreGenerateLights();
#endif
}
extern mleaf_t *r_viewleaf, *r_oldviewleaf;
extern mleaf_t *r_viewleaf2, *r_oldviewleaf2;
static void (D3D9_R_PreNewMap) (void)
{
r_viewleaf = NULL;
r_oldviewleaf = NULL;
r_viewleaf2 = NULL;
r_oldviewleaf2 = NULL;
}
static void (D3D9_VID_DeInit) (void)
{
/*final shutdown, kill the video stuff*/
@ -1111,7 +1074,6 @@ static void (D3D9_R_DeInit) (void)
R_GAliasFlushSkinCache(true);
Surf_DeInit();
Shader_Shutdown();
D3D9_Image_Shutdown();
}
@ -1238,22 +1200,14 @@ rendererinfo_t d3d9rendererinfo =
D3D9_Draw_Init,
D3D9_Draw_Shutdown,
D3D9_LoadTexture,
D3D9_LoadTexture8Pal24,
D3D9_LoadTexture8Pal32,
D3D9_LoadCompressed,
D3D9_FindTexture,
D3D9_AllocNewTexture,
D3D9_Upload,
D3D9_UpdateFiltering,
D3D9_LoadTextureMips,
D3D9_DestroyTexture,
D3D9_R_Init,
D3D9_R_DeInit,
D3D9_R_RenderView,
D3D9_R_NewMap,
D3D9_R_PreNewMap,
D3D9_VID_Init,
D3D9_VID_DeInit,
D3D9_VID_SwapBuffers,

View File

@ -740,6 +740,18 @@ static qboolean initD3D11Device(HWND hWnd, rendererstate_t *info, PFN_D3D11_CREA
{
}
r_config.texture_non_power_of_two = flevel>=D3D_FEATURE_LEVEL_10_0; //npot MUST be supported on all d3d10+ cards.
r_config.texture_non_power_of_two_pic = true; //always supported in d3d11, supposedly.
r_config.npot_rounddown = false;
if (flevel>=D3D_FEATURE_LEVEL_11_0)
r_config.maxtexturesize = 16384;
else if (flevel>=D3D_FEATURE_LEVEL_10_0)
r_config.maxtexturesize = 8192;
else if (flevel>=D3D_FEATURE_LEVEL_9_3)
r_config.maxtexturesize = 4096;
else
r_config.maxtexturesize = 2048;
vid.numpages = scd.BufferCount;
if (!D3D11Shader_Init(flevel))
{
@ -901,43 +913,6 @@ static qboolean D3D11_VID_Init(rendererstate_t *info, unsigned char *palette)
}
#endif
/*a new model has been loaded*/
static void (D3D11_R_NewMap) (void)
{
r_worldentity.model = cl.worldmodel;
#ifdef MAP_PROC
if (cl.worldmodel && cl.worldmodel->fromgame == fg_doom3)
D3_GenerateAreas(cl.worldmodel);
#endif
/*wipe any lingering particles*/
P_ClearParticles();
CL_RegisterParticles();
R_AnimateLight();
Surf_DeInit();
Surf_WipeStains();
Surf_BuildLightmaps();
TP_NewMap();
R_SetSky(cl.skyname);
#ifdef RTLIGHTS
Sh_PreGenerateLights();
#endif
}
extern mleaf_t *r_viewleaf, *r_oldviewleaf;
extern mleaf_t *r_viewleaf2, *r_oldviewleaf2;
static void (D3D11_R_PreNewMap) (void)
{
r_viewleaf = NULL;
r_oldviewleaf = NULL;
r_viewleaf2 = NULL;
r_oldviewleaf2 = NULL;
}
static void (D3D11_VID_DeInit) (void)
{
D3D11BE_Shutdown();
@ -1282,24 +1257,23 @@ static void (D3D11_SCR_UpdateScreen) (void)
static void (D3D11_Draw_Init) (void)
static void D3D11_Draw_Init (void)
{
R2D_Init();
}
static void (D3D11_Draw_Shutdown) (void)
static void D3D11_Draw_Shutdown (void)
{
R2D_Shutdown();
}
static void (D3D11_R_Init) (void)
static void D3D11_R_Init (void)
{
}
static void (D3D11_R_DeInit) (void)
static void D3D11_R_DeInit (void)
{
R_GAliasFlushSkinCache(true);
Surf_DeInit();
Shader_Shutdown();
D3D11_Image_Shutdown();
}
@ -1389,7 +1363,7 @@ static void (D3D11_R_RenderView) (void)
// }
if (!(r_refdef.flags & RDF_NOWORLDMODEL))
if (!r_worldentity.model || r_worldentity.model->needload || !cl.worldmodel)
if (!r_worldentity.model || r_worldentity.model->loadstate != MLS_LOADED || !cl.worldmodel)
{
D3D11_Set2D ();
R2D_ImageColours(0, 0, 0, 1);
@ -1427,6 +1401,10 @@ rendererinfo_t d3d11rendererinfo =
D3D11_Draw_Init,
D3D11_Draw_Shutdown,
D3D11_UpdateFiltering,
D3D11_LoadTextureMips,
D3D11_DestroyTexture,
/*
D3D11_LoadTexture,
D3D11_LoadTexture8Pal24,
D3D11_LoadTexture8Pal32,
@ -1435,14 +1413,11 @@ rendererinfo_t d3d11rendererinfo =
D3D11_AllocNewTexture,
D3D11_Upload,
D3D11_DestroyTexture,
*/
D3D11_R_Init,
D3D11_R_DeInit,
D3D11_R_RenderView,
D3D11_R_NewMap,
D3D11_R_PreNewMap,
D3D11_VID_Init,
D3D11_VID_DeInit,
D3D11_PresentOrCrash,

View File

@ -265,7 +265,6 @@ Global
{4877586B-E85B-4DF8-BCCE-59D31514D240}.GLDebug|Win32.ActiveCfg = Debug|Win32
{4877586B-E85B-4DF8-BCCE-59D31514D240}.GLDebug|x64.ActiveCfg = Debug|Win32
{4877586B-E85B-4DF8-BCCE-59D31514D240}.GLRelease|Win32.ActiveCfg = Release|Win32
{4877586B-E85B-4DF8-BCCE-59D31514D240}.GLRelease|Win32.Build.0 = Release|Win32
{4877586B-E85B-4DF8-BCCE-59D31514D240}.GLRelease|x64.ActiveCfg = Release|Win32
{4877586B-E85B-4DF8-BCCE-59D31514D240}.MDebug|Win32.ActiveCfg = Debug|Win32
{4877586B-E85B-4DF8-BCCE-59D31514D240}.MDebug|x64.ActiveCfg = Release|Win32
@ -613,7 +612,6 @@ Global
{74542CA7-48C1-4664-9007-66F751131EA3}.GLDebug|Win32.Build.0 = Debug|Win32
{74542CA7-48C1-4664-9007-66F751131EA3}.GLDebug|x64.ActiveCfg = Debug|Win32
{74542CA7-48C1-4664-9007-66F751131EA3}.GLRelease|Win32.ActiveCfg = Release|Win32
{74542CA7-48C1-4664-9007-66F751131EA3}.GLRelease|Win32.Build.0 = Release|Win32
{74542CA7-48C1-4664-9007-66F751131EA3}.GLRelease|x64.ActiveCfg = Release|Win32
{74542CA7-48C1-4664-9007-66F751131EA3}.MDebug|Win32.ActiveCfg = Debug|Win32
{74542CA7-48C1-4664-9007-66F751131EA3}.MDebug|Win32.Build.0 = Debug|Win32
@ -638,10 +636,8 @@ Global
{75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.D3DRelease|Win32.Build.0 = Release|Win32
{75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.D3DRelease|x64.ActiveCfg = Release|Win32
{75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.Debug Dedicated Server|Win32.ActiveCfg = Debug|Win32
{75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.Debug Dedicated Server|Win32.Build.0 = Debug|Win32
{75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.Debug Dedicated Server|x64.ActiveCfg = Debug|Win32
{75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.Debug|Win32.ActiveCfg = Debug|Win32
{75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.Debug|Win32.Build.0 = Debug|Win32
{75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.Debug|x64.ActiveCfg = Debug|Win32
{75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.GLDebug|Win32.ActiveCfg = Debug|Win32
{75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.GLDebug|x64.ActiveCfg = Debug|Win32
@ -652,7 +648,6 @@ Global
{75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.MDebug|Win32.Build.0 = Debug|Win32
{75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.MDebug|x64.ActiveCfg = Debug|Win32
{75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.MinGLDebug|Win32.ActiveCfg = Debug|Win32
{75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.MinGLDebug|Win32.Build.0 = Debug|Win32
{75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.MinGLDebug|x64.ActiveCfg = Debug|Win32
{75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.MinGLRelease|Win32.ActiveCfg = Release|Win32
{75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.MinGLRelease|Win32.Build.0 = Release|Win32
@ -671,6 +666,11 @@ Global
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{4735677B-6D5A-4BE6-A945-CB32DEADBEEF} = {EB5DFF7C-C0A8-426C-BC66-524162350F1B}
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E} = {EB5DFF7C-C0A8-426C-BC66-524162350F1B}
{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365} = {EB5DFF7C-C0A8-426C-BC66-524162350F1B}
{4735677B-6D5A-4BE6-A945-CB32A7282F56} = {EB5DFF7C-C0A8-426C-BC66-524162350F1B}
{75D91BDE-CC30-4C53-BF33-5F69EF13A61B} = {EB5DFF7C-C0A8-426C-BC66-524162350F1B}
{4877586B-E85B-4DF8-BCCE-59D31514D240} = {8CED01C6-2C61-4EC5-90B6-574D9756D773}
{32B12987-DF8C-4E40-B07C-B18586A4CA65} = {8CED01C6-2C61-4EC5-90B6-574D9756D773}
{873CCE24-3549-49D4-A4B4-653F91B1532A} = {8CED01C6-2C61-4EC5-90B6-574D9756D773}
@ -678,11 +678,6 @@ Global
{72269FEE-293D-40BC-A7AE-E429F4496869} = {8CED01C6-2C61-4EC5-90B6-574D9756D773}
{6ABD62A3-C5A0-43E8-BA4F-84606057774F} = {8CED01C6-2C61-4EC5-90B6-574D9756D773}
{74542CA7-48C1-4664-9007-66F751131EA3} = {8CED01C6-2C61-4EC5-90B6-574D9756D773}
{4735677B-6D5A-4BE6-A945-CB32DEADBEEF} = {EB5DFF7C-C0A8-426C-BC66-524162350F1B}
{4735677B-6D5A-4BE6-A945-CB32A7282F56} = {EB5DFF7C-C0A8-426C-BC66-524162350F1B}
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E} = {EB5DFF7C-C0A8-426C-BC66-524162350F1B}
{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365} = {EB5DFF7C-C0A8-426C-BC66-524162350F1B}
{75D91BDE-CC30-4C53-BF33-5F69EF13A61B} = {EB5DFF7C-C0A8-426C-BC66-524162350F1B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
AMDCaProjectFile = C:\Games\Quake\wip\engine\dotnet2005\CodeAnalyst\ftequake.caw

View File

@ -737,7 +737,7 @@
</Configuration>
<Configuration
Name="GLDebug|x64"
OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"

View File

@ -47,10 +47,6 @@ extern cvar_t gl_part_flame, r_fullbrightSkins, r_fb_models, ruleset_allow_fbmod
extern cvar_t r_noaliasshadows;
extern char loadname[32]; // for hunk tags
extern cvar_t gl_ati_truform;
extern cvar_t r_vertexdlights;
extern cvar_t mod_md3flags;
@ -128,6 +124,7 @@ static void Mod_ComposeSkin(char *texture, struct cctx_s *cctx)
{
float x=0, y=0;
float w, h;
int iw=0, ih=0;
float r=1,g=1,b=1,a=1;
int l;
char *s, tname[MAX_QPATH];
@ -146,13 +143,18 @@ static void Mod_ComposeSkin(char *texture, struct cctx_s *cctx)
//load the image and set some default sizes, etc.
sourceimg = R2D_SafeCachePic(tname);
if (sourceimg) //no shader? no point in doing anything.
if (!sourceimg || R_GetShaderSizes(sourceimg, &iw, &ih, true) != 1) //no shader? no point in doing anything.
{
w = sourceimg->width;
h = sourceimg->height;
w = 0;
h = 0;
sourceimg = NULL;
}
else
w = h = 0;
{
w = iw;
h = ih;
}
while(*s)
{
@ -267,6 +269,7 @@ skinid_t Mod_ReadSkinFile(const char *skinname, const char *skintext)
//body
if (com_tokentype != TTP_LINEENDING)
{
//fixme: this blocks waiting for the textures to load.
struct cctx_s cctx;
memset(&cctx, 0, sizeof(cctx));
@ -362,7 +365,7 @@ skinid_t Mod_RegisterSkinFile(const char *skinname)
if (!strcmp(skinname, registeredskins[id]->skinname))
return id+1;
}
f = FS_LoadMallocFile(skinname);
f = FS_LoadMallocFile(skinname, NULL);
if (!f)
return 0;
id = Mod_ReadSkinFile(skinname, f);
@ -592,6 +595,8 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
if (!cl.players[e->playerindex].qwskin)
Skin_Find(&cl.players[e->playerindex]);
plskin = cl.players[e->playerindex].qwskin;
// if (plskin && plskin->failedload)
// plskin = NULL;
}
else
plskin = NULL;
@ -649,7 +654,7 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
if (e->skinnum >= 0 && e->skinnum < inf->numskins)
skins += e->skinnum;
if (!skins->numshaders)
if (!skins->numframes)
{
/*model has a skin, but has no framegroups*/
skins = NULL;
@ -659,15 +664,20 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
else
{
subframe = cl.time*skins->skinspeed;
subframe = subframe%skins->numshaders;
subframe = subframe%skins->numframes;
shader = skins->ofsshaders[subframe];
shader = skins->frame[subframe].shader;
}
}
if (shader)
{
if (!plskin && (TEXVALID(shader->defaulttextures.loweroverlay) || TEXVALID(shader->defaulttextures.upperoverlay)))
return shader; //the shader can do its own colourmapping.
if (!plskin)
{
//do this for the loading case too, in the hope that it'll avoid generating a per-player skin at all
if ((shader->defaulttextures.loweroverlay && (shader->defaulttextures.loweroverlay->status == TEX_LOADING || shader->defaulttextures.loweroverlay->status == TEX_LOADED)) ||
(shader->defaulttextures.upperoverlay && (shader->defaulttextures.upperoverlay->status == TEX_LOADING || shader->defaulttextures.upperoverlay->status == TEX_LOADED)))
return shader;
}
if (shader->prog && shader->prog->permu[PERMUTATION_UPPERLOWER].handle.glsl && !h2playertranslations)
{ //this shader can do permutations. this means we can generate only a black image, with separate top+bottom textures.
tc = 0xfe000000;
@ -743,7 +753,7 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
inwidth = plskin->width;
inheight = plskin->height;
if (!original && TEXVALID(plskin->textures.base))
if (!original && TEXLOADED(plskin->textures.base))
{
cm->texnum.loweroverlay = plskin->textures.loweroverlay;
cm->texnum.upperoverlay = plskin->textures.upperoverlay;
@ -761,9 +771,9 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
}
if (!original)
{
if (skins->ofstexels)
if (skins->numframes && skins->frame[subframe].texels)
{
original = skins->ofstexels[subframe];
original = skins->frame[subframe].texels;
inwidth = skins->skinwidth;
inheight = skins->skinheight;
}
@ -1017,12 +1027,12 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
return NULL;
}
if (!skins->numshaders)
if (!skins->numframes)
return NULL;
frame = cl.time*skins->skinspeed;
frame = frame%skins->numshaders;
return skins->ofsshaders[frame];
frame = frame%skins->numframes;
return skins->frame[frame].shader;
}
#if defined(RTLIGHTS)
@ -1223,6 +1233,12 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
dist);
add = cl_dlights[i].radius - Length(dist);
#ifdef RTLIGHTS
//if world lighting is on, there may be no lightmap influence even if r_dynamic is on.
if (r_shadow_realtime_world.ival)
add *= r_shadow_realtime_world_lightmaps.value;
#endif
if (add > 0)
{
add*=5;
@ -1454,7 +1470,7 @@ void R_GAlias_GenerateBatches(entity_t *e, batch_t **batches)
b->buildmeshes = R_GAlias_DrawBatch;
b->ent = e;
#ifdef Q3BSPS
b->fog = CM_FogForOrigin(e->origin);
b->fog = Mod_FogForOrigin(cl.worldmodel, e->origin);
#endif
b->mesh = NULL;
b->firstmesh = 0;
@ -1946,173 +1962,253 @@ void GL_GenerateNormals(float *orgs, float *normals, int *indicies, int numtris,
#ifdef Q3CLIENT
//q3 lightning gun
static void R_DB_LightningBeam(batch_t *batch)
//q3 lightning gun / q3 railgun / q2 beams
static void R_Beam_GenerateTrisoup(entity_t *e, int bemode)
{
entity_t *e = batch->ent;
vec3_t v;
vec3_t dir, cr;
float scale = e->scale;
float length;
float lightmap;
unsigned int batchflags = 0;
vecV_t *xyz;
vec2_t *st;
vec4_t *rgba;
scenetris_t *t;
shader_t *shader = NULL;
float scale, length;
vec3_t dir, v, cr;
static vecV_t points[4];
static vec2_t texcoords[4] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
static index_t indexarray[6] = {0, 1, 2, 0, 2, 3};
static vec4_t colors[4];
static mesh_t mesh;
static mesh_t *meshptr = &mesh;
if (batch->ent == &r_worldentity)
if (e->forcedshader)
{
mesh.numindexes = 0;
mesh.numindexes = 0;
shader = e->forcedshader;
if (!shader)
shader = R_RegisterShader("q2beam", SUF_NONE,
"{\n"
"{\n"
"map $whiteimage\n"
"rgbgen vertex\n"
"alphagen vertex\n"
"blendfunc blend\n"
"}\n"
"}\n"
);
}
else
return;
batchflags = 0;
// if (e->flags & RF_NOSHADOW)
batchflags |= BEF_NOSHADOWS;
if (e->flags & RF_ADDITIVE)
batchflags |= BEF_FORCEADDITIVE;
if (e->flags & RF_TRANSLUCENT)
batchflags |= BEF_FORCETRANSPARENT;
if (e->flags & RF_NODEPTHTEST)
batchflags |= BEF_FORCENODEPTH;
if (e->flags & RF_FORCECOLOURMOD)
batchflags |= BEF_FORCECOLOURMOD;
if (shader->flags & SHADER_NODLIGHT)
batchflags |= BEF_NODLIGHT;
if ((batchflags & BEF_NODLIGHT) || (shader->flags & SHADER_NODLIGHT) || bemode != BEM_STANDARD)
{
//unlit sprites are just fullbright
lightmap = 1;
}
else
{
extern cvar_t r_shadow_realtime_world_lightmaps;
//lit sprites need to sample the world lighting. with rtlights that generally means they're 0.
#ifdef RTLIGHTS
if (r_shadow_realtime_world.ival)
lightmap = r_shadow_realtime_world_lightmaps.value;
else
#endif
lightmap = 1;
}
scale *= -10;
if (cl_numstris && cl_stris[cl_numstris-1].shader == shader && cl_stris[cl_numstris-1].flags == batchflags)
t = &cl_stris[cl_numstris-1];
else
{
if (cl_numstris == cl_maxstris)
{
cl_maxstris += 8;
cl_stris = BZ_Realloc(cl_stris, sizeof(*cl_stris)*cl_maxstris);
}
t = &cl_stris[cl_numstris++];
t->shader = shader;
t->numidx = 0;
t->numvert = 0;
t->firstidx = cl_numstrisidx;
t->firstvert = cl_numstrisvert;
t->flags = batchflags;
}
if (cl_numstrisidx+6 > cl_maxstrisidx)
{
cl_maxstrisidx=cl_numstrisidx+6 + 64;
cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx);
}
if (cl_numstrisvert+4 > cl_maxstrisvert)
{
cl_maxstrisvert+=64;
cl_strisvertv = BZ_Realloc(cl_strisvertv, sizeof(*cl_strisvertv)*cl_maxstrisvert);
cl_strisvertt = BZ_Realloc(cl_strisvertt, sizeof(*cl_strisvertt)*cl_maxstrisvert);
cl_strisvertc = BZ_Realloc(cl_strisvertc, sizeof(*cl_strisvertc)*cl_maxstrisvert);
}
xyz = &cl_strisvertv[cl_numstrisvert];
st = &cl_strisvertt[cl_numstrisvert];
rgba = &cl_strisvertc[cl_numstrisvert];
cl_strisidx[cl_numstrisidx++] = t->numvert+0;
cl_strisidx[cl_numstrisidx++] = t->numvert+1;
cl_strisidx[cl_numstrisidx++] = t->numvert+2;
cl_strisidx[cl_numstrisidx++] = t->numvert+0;
cl_strisidx[cl_numstrisidx++] = t->numvert+2;
cl_strisidx[cl_numstrisidx++] = t->numvert+3;
t->numidx += 6;
t->numvert += 4;
cl_numstrisvert += 4;
scale = e->scale*10;
if (!scale)
scale = 10;
VectorSubtract(e->origin, e->oldorigin, dir);
length = Length(dir);
//this seems to be about right.
texcoords[2][0] = length/128;
texcoords[3][0] = length/128;
Vector2Set(st[0], 0, 1);
Vector2Set(st[1], 0, 0);
Vector2Set(st[2], length/128, 0);
Vector2Set(st[3], length/128, 1);
VectorSubtract(r_refdef.vieworg, e->origin, v);
CrossProduct(v, dir, cr);
VectorNormalize(cr);
VectorMA(e->origin, -scale/2, cr, points[0]);
VectorMA(e->origin, scale/2, cr, points[1]);
VectorMA(e->origin, -scale/2, cr, xyz[0]);
VectorMA(e->origin, scale/2, cr, xyz[1]);
VectorSubtract(r_refdef.vieworg, e->oldorigin, v);
CrossProduct(v, dir, cr);
VectorNormalize(cr);
VectorMA(e->oldorigin, scale/2, cr, points[2]);
VectorMA(e->oldorigin, -scale/2, cr, points[3]);
VectorMA(e->oldorigin, scale/2, cr, xyz[2]);
VectorMA(e->oldorigin, -scale/2, cr, xyz[3]);
/*this is actually meant to be 4 separate quads at 45 degrees from each other*/
Vector4Copy(e->shaderRGBAf, colors[0]);
Vector4Copy(e->shaderRGBAf, colors[1]);
Vector4Copy(e->shaderRGBAf, colors[2]);
Vector4Copy(e->shaderRGBAf, colors[3]);
batch->ent = &r_worldentity;
batch->mesh = &meshptr;
memset(&mesh, 0, sizeof(mesh));
mesh.vbofirstelement = 0;
mesh.vbofirstvert = 0;
mesh.xyz_array = points;
mesh.indexes = indexarray;
mesh.numindexes = sizeof(indexarray)/sizeof(indexarray[0]);
mesh.colors4f_array[0] = (vec4_t*)colors;
mesh.normals_array = NULL;
mesh.numvertexes = 4;
mesh.st_array = texcoords;
}
//q3 railgun beam
static void R_DB_RailgunBeam(batch_t *batch)
{
entity_t *e = batch->ent;
vec3_t v;
vec3_t dir, cr;
float scale = e->scale;
float length;
static mesh_t mesh;
static mesh_t *meshptr = &mesh;
static vecV_t points[4];
static vec2_t texcoords[4] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
static index_t indexarray[6] = {0, 1, 2, 0, 2, 3};
static vec4_t colors[4];
if (batch->ent == &r_worldentity)
if (e->shaderRGBAf[0] != 0 || e->shaderRGBAf[1] != 0 || e->shaderRGBAf[2] != 0 || (batchflags & BEF_FORCECOLOURMOD))
{
mesh.numindexes = 0;
mesh.numindexes = 0;
return;
if (e->shaderRGBAf[0] > 1)
e->shaderRGBAf[0] = 1;
if (e->shaderRGBAf[1] > 1)
e->shaderRGBAf[1] = 1;
if (e->shaderRGBAf[2] > 1)
e->shaderRGBAf[2] = 1;
}
else
{
e->shaderRGBAf[0] = 1;
e->shaderRGBAf[1] = 1;
e->shaderRGBAf[2] = 1;
}
if (!e->forcedshader)
return;
if (!scale)
scale = 10;
VectorSubtract(e->origin, e->oldorigin, dir);
length = Length(dir);
//this seems to be about right.
texcoords[2][0] = length/128;
texcoords[3][0] = length/128;
VectorSubtract(r_refdef.vieworg, e->origin, v);
CrossProduct(v, dir, cr);
VectorNormalize(cr);
VectorMA(e->origin, -scale/2, cr, points[0]);
VectorMA(e->origin, scale/2, cr, points[1]);
VectorSubtract(r_refdef.vieworg, e->oldorigin, v);
CrossProduct(v, dir, cr);
VectorNormalize(cr);
VectorMA(e->oldorigin, scale/2, cr, points[2]);
VectorMA(e->oldorigin, -scale/2, cr, points[3]);
Vector4Copy(e->shaderRGBAf, colors[0]);
Vector4Copy(e->shaderRGBAf, colors[1]);
Vector4Copy(e->shaderRGBAf, colors[2]);
Vector4Copy(e->shaderRGBAf, colors[3]);
batch->ent = &r_worldentity;
batch->mesh = &meshptr;
memset(&mesh, 0, sizeof(mesh));
mesh.vbofirstelement = 0;
mesh.vbofirstvert = 0;
mesh.xyz_array = points;
mesh.indexes = indexarray;
mesh.numindexes = sizeof(indexarray)/sizeof(indexarray[0]);
mesh.colors4f_array[0] = (vec4_t*)colors;
mesh.normals_array = NULL;
mesh.numvertexes = 4;
mesh.st_array = texcoords;
VectorScale(e->shaderRGBAf, lightmap, rgba[0]);
rgba[0][3] = e->shaderRGBAf[3];
Vector4Copy(rgba[0], rgba[1]);
Vector4Copy(rgba[0], rgba[2]);
Vector4Copy(rgba[0], rgba[3]);
}
#endif
static void R_DB_Sprite(batch_t *batch)
static void R_Sprite_GenerateTrisoup(entity_t *e, int bemode)
{
entity_t *e = batch->ent;
vec3_t point;
mspriteframe_t *frame, genframe;
mspriteframe_t genframe;
vec3_t spraxis[3];
msprite_t *psprite;
vec3_t sprorigin;
unsigned int sprtype;
float lightmap;
unsigned int batchflags = 0;
vecV_t *xyz;
vec2_t *st;
vec4_t *rgba;
scenetris_t *t;
static vec2_t texcoords[4]={{0, 1},{0,0},{1,0},{1,1}};
static index_t indexes[6] = {0, 1, 2, 0, 2, 3};
static vecV_t vertcoords[4];
static avec4_t colours[4];
static mesh_t mesh;
static mesh_t *meshptr = &mesh;
extern cvar_t gl_blendsprites;
shader_t *shader = NULL;
mspriteframe_t *frame;
if (batch->ent == &r_worldentity)
if (!e->model || e->model->type != mod_sprite || e->forcedshader)
{
mesh.numindexes = 0;
mesh.numindexes = 0;
return;
frame = NULL;
shader = e->forcedshader;
if (!shader)
shader = R_RegisterShader("q2beam", SUF_NONE,
"{\n"
"{\n"
"map $whiteimage\n"
"rgbgen vertex\n"
"alphagen vertex\n"
"blendfunc blend\n"
"}\n"
"}\n"
);
}
else
{
if (!(e->flags & RF_WEAPONMODEL))
{
if (R_CullEntityBox (e, e->model->mins, e->model->maxs))
return;
#ifdef RTLIGHTS
if (BE_LightCullModel(e->origin, e->model))
return;
}
else
{
if (BE_LightCullModel(r_origin, e->model))
return;
#endif
}
// don't even bother culling, because it's just a single
// polygon without a surface cache
frame = R_GetSpriteFrame(e);
shader = frame->shader;
}
if (e->flags & RF_WEAPONMODEL && r_refdef.playerview->viewentity > 0)
batchflags = 0;
// if (e->flags & RF_NOSHADOW)
batchflags |= BEF_NOSHADOWS;
if (e->flags & RF_ADDITIVE)
batchflags |= BEF_FORCEADDITIVE;
if (e->flags & RF_TRANSLUCENT)
batchflags |= BEF_FORCETRANSPARENT;
if (e->flags & RF_NODEPTHTEST)
batchflags |= BEF_FORCENODEPTH;
if (e->flags & RF_FORCECOLOURMOD)
batchflags |= BEF_FORCECOLOURMOD;
if (shader->flags & SHADER_NODLIGHT)
batchflags |= BEF_NODLIGHT;
if ((batchflags & BEF_NODLIGHT) || (shader->flags & SHADER_NODLIGHT) || bemode != BEM_STANDARD)
{
//unlit sprites are just fullbright
lightmap = 1;
}
else
{
extern cvar_t r_shadow_realtime_world_lightmaps;
//lit sprites need to sample the world lighting. with rtlights that generally means they're 0.
#ifdef RTLIGHTS
if (r_shadow_realtime_world.ival)
lightmap = r_shadow_realtime_world_lightmaps.value;
else
#endif
lightmap = 1;
}
if ((e->flags & RF_WEAPONMODEL) && r_refdef.playerview->viewentity > 0)
{
sprorigin[0] = r_refdef.playerview->vw_origin[0];
sprorigin[1] = r_refdef.playerview->vw_origin[1];
@ -2122,14 +2218,59 @@ static void R_DB_Sprite(batch_t *batch)
VectorMA(sprorigin, e->origin[2], r_refdef.playerview->vw_axis[2], sprorigin);
VectorMA(sprorigin, 12, vpn, sprorigin);
batch->flags |= BEF_FORCENODEPTH;
batchflags |= BEF_FORCENODEPTH;
}
else
VectorCopy(e->origin, sprorigin);
if (!e->model || e->forcedshader)
if (cl_numstris && cl_stris[cl_numstris-1].shader == shader && cl_stris[cl_numstris-1].flags == batchflags)
t = &cl_stris[cl_numstris-1];
else
{
if (cl_numstris == cl_maxstris)
{
cl_maxstris += 8;
cl_stris = BZ_Realloc(cl_stris, sizeof(*cl_stris)*cl_maxstris);
}
t = &cl_stris[cl_numstris++];
t->shader = shader;
t->numidx = 0;
t->numvert = 0;
t->firstidx = cl_numstrisidx;
t->firstvert = cl_numstrisvert;
t->flags = batchflags;
}
if (cl_numstrisidx+6 > cl_maxstrisidx)
{
cl_maxstrisidx=cl_numstrisidx+6 + 64;
cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx);
}
if (cl_numstrisvert+4 > cl_maxstrisvert)
{
cl_maxstrisvert+=64;
cl_strisvertv = BZ_Realloc(cl_strisvertv, sizeof(*cl_strisvertv)*cl_maxstrisvert);
cl_strisvertt = BZ_Realloc(cl_strisvertt, sizeof(*cl_strisvertt)*cl_maxstrisvert);
cl_strisvertc = BZ_Realloc(cl_strisvertc, sizeof(*cl_strisvertc)*cl_maxstrisvert);
}
xyz = &cl_strisvertv[cl_numstrisvert];
st = &cl_strisvertt[cl_numstrisvert];
rgba = &cl_strisvertc[cl_numstrisvert];
cl_strisidx[cl_numstrisidx++] = t->numvert+0;
cl_strisidx[cl_numstrisidx++] = t->numvert+1;
cl_strisidx[cl_numstrisidx++] = t->numvert+2;
cl_strisidx[cl_numstrisidx++] = t->numvert+0;
cl_strisidx[cl_numstrisidx++] = t->numvert+2;
cl_strisidx[cl_numstrisidx++] = t->numvert+3;
t->numidx += 6;
t->numvert += 4;
cl_numstrisvert += 4;
if (!frame)
{
genframe.shader = e->forcedshader;
genframe.up = genframe.left = -1;
genframe.down = genframe.right = 1;
sprtype = SPR_VP_PARALLEL;
@ -2139,12 +2280,9 @@ static void R_DB_Sprite(batch_t *batch)
{
// don't even bother culling, because it's just a single
// polygon without a surface cache
frame = R_GetSpriteFrame (e);
psprite = e->model->meshinfo;
sprtype = psprite->type;
}
if (!frame->shader)
return;
switch(sprtype)
{
@ -2179,14 +2317,17 @@ static void R_DB_Sprite(batch_t *batch)
VectorCopy(vright, spraxis[1]);
break;
}
spraxis[2][0]*=e->scale;
spraxis[2][1]*=e->scale;
spraxis[2][2]*=e->scale;
spraxis[1][0]*=e->scale;
spraxis[1][1]*=e->scale;
spraxis[1][2]*=e->scale;
if (e->scale)
{
spraxis[2][0]*=e->scale;
spraxis[2][1]*=e->scale;
spraxis[2][2]*=e->scale;
spraxis[1][0]*=e->scale;
spraxis[1][1]*=e->scale;
spraxis[1][2]*=e->scale;
}
if (e->shaderRGBAf[0] != 0 || e->shaderRGBAf[1] != 0 || e->shaderRGBAf[2] != 0 || (batch->flags & BEF_FORCECOLOURMOD))
if (e->shaderRGBAf[0] != 0 || e->shaderRGBAf[1] != 0 || e->shaderRGBAf[2] != 0 || (batchflags & BEF_FORCECOLOURMOD))
{
if (e->shaderRGBAf[0] > 1)
e->shaderRGBAf[0] = 1;
@ -2202,120 +2343,28 @@ static void R_DB_Sprite(batch_t *batch)
e->shaderRGBAf[2] = 1;
}
Vector4Copy(e->shaderRGBAf, colours[0]);
Vector4Copy(e->shaderRGBAf, colours[1]);
Vector4Copy(e->shaderRGBAf, colours[2]);
Vector4Copy(e->shaderRGBAf, colours[3]);
VectorScale(e->shaderRGBAf, lightmap, rgba[0]);
rgba[0][3] = e->shaderRGBAf[3];
Vector4Copy(rgba[0], rgba[1]);
Vector4Copy(rgba[0], rgba[2]);
Vector4Copy(rgba[0], rgba[3]);
VectorSubtract(sprorigin, e->origin, sprorigin);
if (!e->scale)
e->scale = 1;
VectorSet(e->axis[0], 1/e->scale, 0, 0);
VectorSet(e->axis[1], 0, 1/e->scale, 0);
VectorSet(e->axis[2], 0, 0, 1/e->scale);
Vector2Set(st[0], 0, 1);
Vector2Set(st[1], 0, 0);
Vector2Set(st[2], 1, 0);
Vector2Set(st[3], 1, 1);
VectorMA (sprorigin, frame->down, spraxis[2], point);
VectorMA (point, frame->left, spraxis[1], vertcoords[0]);
VectorMA (point, frame->left, spraxis[1], xyz[0]);
VectorMA (sprorigin, frame->up, spraxis[2], point);
VectorMA (point, frame->left, spraxis[1], vertcoords[1]);
VectorMA (point, frame->left, spraxis[1], xyz[1]);
VectorMA (sprorigin, frame->up, spraxis[2], point);
VectorMA (point, frame->right, spraxis[1], vertcoords[2]);
VectorMA (point, frame->right, spraxis[1], xyz[2]);
VectorMA (sprorigin, frame->down, spraxis[2], point);
VectorMA (point, frame->right, spraxis[1], vertcoords[3]);
batch->mesh = &meshptr;
memset(&mesh, 0, sizeof(mesh));
mesh.vbofirstelement = 0;
mesh.vbofirstvert = 0;
mesh.xyz_array = vertcoords;
mesh.indexes = indexes;
mesh.numindexes = sizeof(indexes)/sizeof(indexes[0]);
mesh.colors4f_array[0] = colours;
mesh.normals_array = NULL;
mesh.numvertexes = 4;
mesh.st_array = texcoords;
mesh.istrifan = true;
}
static void R_Sprite_GenerateBatch(entity_t *e, batch_t **batches, void (*drawfunc)(batch_t *batch))
{
extern cvar_t gl_blendsprites;
shader_t *shader = NULL;
batch_t *b;
shadersort_t sort;
int j;
if (!e->model || e->model->type != mod_sprite || e->forcedshader)
{
shader = e->forcedshader;
if (!shader)
shader = R_RegisterShader("q2beam", SUF_NONE,
"{\n"
"{\n"
"map $whiteimage\n"
"rgbgen vertex\n"
"alphagen vertex\n"
"blendfunc blend\n"
"}\n"
"}\n"
);
}
else
{
// don't even bother culling, because it's just a single
// polygon without a surface cache
shader = R_GetSpriteFrame(e)->shader;
}
if (!shader)
return;
b = BE_GetTempBatch();
if (!b)
return;
b->flags = 0;
sort = shader->sort;
if (e->flags & RF_ADDITIVE)
{
b->flags |= BEF_FORCEADDITIVE;
if (sort < SHADER_SORT_ADDITIVE)
sort = SHADER_SORT_ADDITIVE;
}
if (e->flags & RF_TRANSLUCENT || (gl_blendsprites.ival && drawfunc == R_DB_Sprite))
{
b->flags |= BEF_FORCETRANSPARENT;
if (SHADER_SORT_PORTAL < sort && sort < SHADER_SORT_BLEND)
sort = SHADER_SORT_BLEND;
}
if (e->flags & RF_NODEPTHTEST)
{
b->flags |= BEF_FORCENODEPTH;
if (sort < SHADER_SORT_BANNER)
sort = SHADER_SORT_BANNER;
}
b->buildmeshes = drawfunc;
b->ent = e;
#ifdef Q3BSPS
b->fog = CM_FogForOrigin(e->origin);
#endif
b->mesh = NULL;
b->firstmesh = 0;
b->meshes = 1;
b->skin = &shader->defaulttextures;
b->texture = NULL;
b->shader = shader;
for (j = 0; j < MAXRLIGHTMAPS; j++)
b->lightmap[j] = -1;
b->surf_first = 0;
b->flags |= BEF_NODLIGHT|BEF_NOSHADOWS;
b->vbo = NULL;
b->next = batches[sort];
batches[sort] = b;
VectorMA (point, frame->right, spraxis[1], xyz[3]);
}
static void R_DB_Poly(batch_t *batch)
@ -2333,11 +2382,12 @@ static void R_DB_Poly(batch_t *batch)
mesh.numindexes = cl_stris[i].numidx;
mesh.numvertexes = cl_stris[i].numvert;
}
void BE_GenPolyBatches(batch_t **batches)
static void BE_GenPolyBatches(batch_t **batches)
{
shader_t *shader = NULL;
batch_t *b;
unsigned int i = cl_numstris, j;
unsigned int sort;
while (i-- > 0)
{
@ -2363,10 +2413,19 @@ void BE_GenPolyBatches(batch_t **batches)
for (j = 0; j < MAXRLIGHTMAPS; j++)
b->lightmap[j] = -1;
b->surf_first = i;
b->flags = BEF_NODLIGHT|BEF_NOSHADOWS | cl_stris[i].flags;
b->flags = cl_stris[i].flags;
b->vbo = 0;
b->next = batches[shader->sort];
batches[shader->sort] = b;
sort = shader->sort;
if ((b->flags & BEF_FORCEADDITIVE) && sort < SHADER_SORT_ADDITIVE)
sort = SHADER_SORT_ADDITIVE;
if ((b->flags & BEF_FORCETRANSPARENT) && SHADER_SORT_PORTAL < sort && sort < SHADER_SORT_BLEND)
sort = SHADER_SORT_BLEND;
if ((b->flags & BEF_FORCENODEPTH) && sort < SHADER_SORT_BANNER)
sort = SHADER_SORT_BANNER;
b->next = batches[sort];
batches[sort] = b;
}
}
void R_HalfLife_GenerateBatches(entity_t *e, batch_t **batches);
@ -2376,6 +2435,8 @@ void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemo
entity_t *ent;
unsigned int orig_numstris = cl_numstris;
unsigned int orig_numvisedicts = cl_numvisedicts;
unsigned int orig_numstrisidx = cl_numstrisidx;
unsigned int orig_numstrisvert = cl_numstrisvert;
/*clear the batch list*/
for (i = 0; i < SHADER_SORT_COUNT; i++)
@ -2424,11 +2485,13 @@ void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemo
default:
if (!ent->model)
continue;
if (ent->model->needload)
if (ent->model->loadstate == MLS_NOTLOADED)
{
if (!Mod_LoadModel(ent->model, MLV_WARN))
continue;
}
if (ent->model->loadstate != MLS_LOADED)
continue;
if (cl.lerpents && (cls.allow_anyparticles)) //allowed or static
{
@ -2459,7 +2522,7 @@ void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemo
R_GAlias_GenerateBatches(ent, batches);
break;
case mod_sprite:
R_Sprite_GenerateBatch(ent, batches, R_DB_Sprite);
R_Sprite_GenerateTrisoup(ent, bemode);
break;
case mod_halflife:
#ifdef HALFLIFEMODELS
@ -2473,17 +2536,15 @@ void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemo
}
break;
case RT_SPRITE:
R_Sprite_GenerateBatch(ent, batches, R_DB_Sprite);
R_Sprite_GenerateTrisoup(ent, bemode);
break;
#ifdef Q3CLIENT
case RT_BEAM:
case RT_RAIL_RINGS:
case RT_LIGHTNING:
R_Sprite_GenerateBatch(ent, batches, R_DB_LightningBeam);
continue;
case RT_RAIL_CORE:
R_Sprite_GenerateBatch(ent, batches, R_DB_RailgunBeam);
R_Beam_GenerateTrisoup(ent, bemode);
continue;
#endif
@ -2499,8 +2560,17 @@ void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemo
if (cl_numstris)
BE_GenPolyBatches(batches);
while(orig_numstris < cl_numstris)
cl_stris[orig_numstris++].shader = NULL;
cl_numstris = orig_numstris;
cl_numvisedicts = orig_numvisedicts;
/* cl_numstrisidx = orig_numstrisidx;
cl_numstrisvert = orig_numstrisvert;
if (cl_numstris)
{ //fix this up, in case they got merged.
cl_stris[cl_numstris-1].numvert = cl_numstrisvert - cl_stris[cl_numstris-1].firstvert;
cl_stris[cl_numstris-1].numidx = cl_numstrisidx - cl_stris[cl_numstris-1].firstidx;
}
*/ cl_numvisedicts = orig_numvisedicts;
}
#endif // defined(GLQUAKE)

View File

@ -378,13 +378,13 @@ void GL_MTBind(int tmu, int target, texid_t texnum)
GL_SelectTexture(tmu);
#ifndef FORCESTATE
if (shaderstate.currenttextures[tmu] == texnum.num)
if (shaderstate.currenttextures[tmu] == texnum->num)
return;
#endif
shaderstate.currenttextures[tmu] = texnum.num;
shaderstate.currenttextures[tmu] = texnum->num;
if (target)
qglBindTexture (target, texnum.num);
qglBindTexture (target, texnum->num);
if (
#ifndef FORCESTATE
@ -403,13 +403,14 @@ void GL_MTBind(int tmu, int target, texid_t texnum)
void GL_LazyBind(int tmu, int target, texid_t texnum)
{
int glnum = texnum?texnum->num:0;
#ifndef FORCESTATE
if (shaderstate.currenttextures[tmu] != texnum.num)
if (shaderstate.currenttextures[tmu] != glnum)
#endif
{
GL_SelectTexture(tmu);
shaderstate.currenttextures[shaderstate.currenttmu] = texnum.num;
shaderstate.currenttextures[shaderstate.currenttmu] = glnum;
#ifndef FORCESTATE
if (shaderstate.curtexturetype[tmu] != target)
@ -432,7 +433,7 @@ void GL_LazyBind(int tmu, int target, texid_t texnum)
}
if (target)
qglBindTexture (target, texnum.num);
qglBindTexture (target, glnum);
}
}
@ -1029,7 +1030,10 @@ static void T_Gen_CurrentRender(int tmu)
}
// copy the scene to texture
if (!TEXVALID(shaderstate.temptexture))
TEXASSIGN(shaderstate.temptexture, GL_AllocNewTexture("***$currentrender***", vwidth, vheight, 0));
{
TEXASSIGN(shaderstate.temptexture, Image_CreateTexture("***$currentrender***", NULL, 0));
qglGenTextures(1, &shaderstate.temptexture->num);
}
GL_MTBind(tmu, GL_TEXTURE_2D, shaderstate.temptexture);
qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, vwidth, vheight, 0);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@ -1072,28 +1076,28 @@ static void Shader_BindTextureForPass(int tmu, const shaderpass_t *pass)
}
break;
case T_GEN_DIFFUSE:
if (shaderstate.curtexnums && TEXVALID(shaderstate.curtexnums->base))
if (shaderstate.curtexnums && TEXLOADED(shaderstate.curtexnums->base))
t = shaderstate.curtexnums->base;
else
t = missing_texture;
break;
case T_GEN_NORMALMAP:
t = (shaderstate.curtexnums && TEXVALID(shaderstate.curtexnums->bump))?shaderstate.curtexnums->bump:missing_texture_normal;
t = (shaderstate.curtexnums && TEXLOADED(shaderstate.curtexnums->bump))?shaderstate.curtexnums->bump:missing_texture_normal;
break;
case T_GEN_SPECULAR:
if (TEXVALID(shaderstate.curtexnums->specular))
if (shaderstate.curtexnums && TEXLOADED(shaderstate.curtexnums->specular))
t = shaderstate.curtexnums->specular;
else
t = missing_texture_gloss;
break;
case T_GEN_UPPEROVERLAY:
if (shaderstate.curtexnums && TEXVALID(shaderstate.curtexnums->upperoverlay))
if (shaderstate.curtexnums && TEXLOADED(shaderstate.curtexnums->upperoverlay))
t = shaderstate.curtexnums->upperoverlay;
else
t = r_nulltex;
break;
case T_GEN_LOWEROVERLAY:
if (shaderstate.curtexnums && TEXVALID(shaderstate.curtexnums->loweroverlay))
if (shaderstate.curtexnums && TEXLOADED(shaderstate.curtexnums->loweroverlay))
t = shaderstate.curtexnums->loweroverlay;
else
t = r_nulltex;
@ -1275,8 +1279,8 @@ void GenerateFogTexture(texid_t *tex, float density, float zscale)
}
if (!TEXVALID(*tex))
*tex = R_AllocNewTexture("***fog***", FOGS, FOGT, 0);
R_Upload(*tex, "fog", TF_RGBA32, fogdata, NULL, FOGS, FOGT, IF_CLAMP|IF_NOMIPMAP);
*tex = Image_CreateTexture("***fog***", NULL, IF_CLAMP|IF_NOMIPMAP);
Image_Upload(*tex, TF_RGBA32, fogdata, NULL, FOGS, FOGT, IF_CLAMP|IF_NOMIPMAP);
}
void GLBE_DestroyFBOs(void)
@ -1285,22 +1289,22 @@ void GLBE_DestroyFBOs(void)
GLBE_FBO_Destroy(&shaderstate.fbo_reflectrefrac);
GLBE_FBO_Destroy(&shaderstate.fbo_lprepass);
if (shaderstate.tex_reflection.num)
if (shaderstate.tex_reflection)
{
R_DestroyTexture(shaderstate.tex_reflection);
shaderstate.tex_reflection = r_nulltex;
}
if (shaderstate.tex_refraction.num)
if (shaderstate.tex_refraction)
{
R_DestroyTexture(shaderstate.tex_refraction);
shaderstate.tex_refraction = r_nulltex;
}
if (shaderstate.tex_refractiondepth.num)
if (shaderstate.tex_refractiondepth)
{
R_DestroyTexture(shaderstate.tex_refractiondepth);
shaderstate.tex_refractiondepth = r_nulltex;
}
if (shaderstate.temptexture.num)
if (shaderstate.temptexture)
{
R_DestroyTexture(shaderstate.temptexture);
shaderstate.temptexture = r_nulltex;
@ -1488,7 +1492,6 @@ static void tcgen_fog(float *st, unsigned int numverts, float *xyz, mfog_t *fog)
{
z = DotProduct(xyz, zmat) + zmat[3];
st[0] = z;
st[1] = realtime - (int)realtime;
if (fog->visibleplane)
point = (DotProduct(xyz, fog->visibleplane->normal) - fog->visibleplane->dist);
@ -2737,11 +2740,11 @@ static void DrawPass(const shaderpass_t *pass)
for (i = 0; i < lastpass; i++)
{
if (pass[i].texgen == T_GEN_UPPEROVERLAY && !TEXVALID(shaderstate.curtexnums->upperoverlay))
if (pass[i].texgen == T_GEN_UPPEROVERLAY && !TEXLOADED(shaderstate.curtexnums->upperoverlay))
continue;
if (pass[i].texgen == T_GEN_LOWEROVERLAY && !TEXVALID(shaderstate.curtexnums->loweroverlay))
if (pass[i].texgen == T_GEN_LOWEROVERLAY && !TEXLOADED(shaderstate.curtexnums->loweroverlay))
continue;
if (pass[i].texgen == T_GEN_FULLBRIGHT && !TEXVALID(shaderstate.curtexnums->fullbright))
if (pass[i].texgen == T_GEN_FULLBRIGHT && !TEXLOADED(shaderstate.curtexnums->fullbright))
continue;
break;
}
@ -2752,11 +2755,11 @@ static void DrawPass(const shaderpass_t *pass)
tmu = 0;
for (; i < lastpass; i++)
{
if (pass[i].texgen == T_GEN_UPPEROVERLAY && !TEXVALID(shaderstate.curtexnums->upperoverlay))
if (pass[i].texgen == T_GEN_UPPEROVERLAY && !TEXLOADED(shaderstate.curtexnums->upperoverlay))
continue;
if (pass[i].texgen == T_GEN_LOWEROVERLAY && !TEXVALID(shaderstate.curtexnums->loweroverlay))
if (pass[i].texgen == T_GEN_LOWEROVERLAY && !TEXLOADED(shaderstate.curtexnums->loweroverlay))
continue;
if (pass[i].texgen == T_GEN_FULLBRIGHT && !TEXVALID(shaderstate.curtexnums->fullbright))
if (pass[i].texgen == T_GEN_FULLBRIGHT && !TEXLOADED(shaderstate.curtexnums->fullbright))
continue;
Shader_BindTextureForPass(tmu, pass+i);
attr |= (1u<<(VATTR_LEG_TMU0+tmu));
@ -3193,15 +3196,15 @@ static void BE_RenderMeshProgram(const shader_t *shader, const shaderpass_t *pas
}
if (p->permu[perm|PERMUTATION_FRAMEBLEND].handle.glsl && shaderstate.sourcevbo->coord2.gl.addr)
perm |= PERMUTATION_FRAMEBLEND;
if (TEXVALID(shaderstate.curtexnums->bump) && p->permu[perm|PERMUTATION_BUMPMAP].handle.glsl)
if (TEXLOADED(shaderstate.curtexnums->bump) && p->permu[perm|PERMUTATION_BUMPMAP].handle.glsl)
perm |= PERMUTATION_BUMPMAP;
if (TEXVALID(shaderstate.curtexnums->fullbright) && p->permu[perm|PERMUTATION_FULLBRIGHT].handle.glsl)
if (TEXLOADED(shaderstate.curtexnums->fullbright) && p->permu[perm|PERMUTATION_FULLBRIGHT].handle.glsl)
perm |= PERMUTATION_FULLBRIGHT;
if ((TEXVALID(shaderstate.curtexnums->loweroverlay) || TEXVALID(shaderstate.curtexnums->upperoverlay)) && p->permu[perm|PERMUTATION_UPPERLOWER].handle.glsl)
if ((TEXLOADED(shaderstate.curtexnums->loweroverlay) || TEXLOADED(shaderstate.curtexnums->upperoverlay)) && p->permu[perm|PERMUTATION_UPPERLOWER].handle.glsl)
perm |= PERMUTATION_UPPERLOWER;
if (r_refdef.globalfog.density && p->permu[perm|PERMUTATION_FOG].handle.glsl)
perm |= PERMUTATION_FOG;
if (p->permu[perm|PERMUTATION_DELUXE].handle.glsl && TEXVALID(shaderstate.curtexnums->bump) && shaderstate.curbatch->lightmap[0] >= 0 && lightmap[shaderstate.curbatch->lightmap[0]]->hasdeluxe)
if (p->permu[perm|PERMUTATION_DELUXE].handle.glsl && TEXLOADED(shaderstate.curtexnums->bump) && shaderstate.curbatch->lightmap[0] >= 0 && lightmap[shaderstate.curbatch->lightmap[0]]->hasdeluxe)
perm |= PERMUTATION_DELUXE;
#if MAXRLIGHTMAPS > 1
if (shaderstate.curbatch->lightmap[1] >= 0 && p->permu[perm|PERMUTATION_LIGHTSTYLES].handle.glsl)
@ -3496,7 +3499,7 @@ static qboolean GLBE_RegisterLightShader(int mode)
}
#endif
qboolean GLBE_SelectDLight(dlight_t *dl, vec3_t colour, unsigned int lmode)
qboolean GLBE_SelectDLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], unsigned int lmode)
{
extern cvar_t gl_specular;
@ -3507,16 +3510,16 @@ qboolean GLBE_SelectDLight(dlight_t *dl, vec3_t colour, unsigned int lmode)
/*simple info*/
shaderstate.lightradius = dl->radius;
VectorCopy(dl->origin, shaderstate.lightorg);
shaderstate.lightcolourscale[2] *= gl_specular.value;
VectorCopy(colour, shaderstate.lightcolours);
#ifdef RTLIGHTS
VectorCopy(dl->lightcolourscales, shaderstate.lightcolourscale);
shaderstate.lightcolourscale[2] *= gl_specular.value;
if (lmode & LSHADER_SPOT)
shaderstate.lightcubemap = r_nulltex;
else
shaderstate.lightcubemap = dl->cubetexture;
if (TEXVALID(shaderstate.lightcubemap) && GLBE_RegisterLightShader(shaderstate.lightmode | LSHADER_CUBE))
if (TEXLOADED(shaderstate.lightcubemap) && GLBE_RegisterLightShader(shaderstate.lightmode | LSHADER_CUBE))
shaderstate.lightmode |= LSHADER_CUBE;
if (!GLBE_RegisterLightShader(shaderstate.lightmode))
return false;
@ -3528,19 +3531,19 @@ qboolean GLBE_SelectDLight(dlight_t *dl, vec3_t colour, unsigned int lmode)
float proj[16];
extern cvar_t r_shadow_shadowmapping_nearclip;
Matrix4x4_CM_Projection_Far(proj, dl->fov, dl->fov, r_shadow_shadowmapping_nearclip.value, dl->radius);
Matrix4x4_CM_ModelViewMatrixFromAxis(view, dl->axis[0], dl->axis[1], dl->axis[2], dl->origin);
Matrix4x4_CM_ModelViewMatrixFromAxis(view, axis[0], axis[1], axis[2], dl->origin);
Matrix4_Multiply(proj, view, shaderstate.lightprojmatrix);
}
else if (shaderstate.lightmode & (LSHADER_SMAP|LSHADER_CUBE))
{
Matrix4x4_CM_LightMatrixFromAxis(shaderstate.lightprojmatrix, dl->axis[0], dl->axis[1], dl->axis[2], dl->origin);
Matrix4x4_CM_LightMatrixFromAxis(shaderstate.lightprojmatrix, axis[0], axis[1], axis[2], dl->origin);
/*
vec3_t down;
vec3_t back;
vec3_t right;
VectorScale(dl->axis[2], -1, down);
VectorScale(dl->axis[1], 1, right);
VectorScale(dl->axis[0], 1, back);
VectorScale(axis[2], -1, down);
VectorScale(axis[1], 1, right);
VectorScale(axis[0], 1, back);
Matrix4x4_CM_ModelViewMatrixFromAxis(shaderstate.lightprojmatrix, down, back, right, dl->origin);
*/
}
@ -3643,6 +3646,8 @@ static void BE_LegacyLighting(void)
//vbo-only mesh.
if (!mesh->xyz_array)
return;
if (!mesh->normals_array)
return;
col = coloursarray[0] + mesh->vbofirstvert*4;
ldir = texcoordarray[0] + mesh->vbofirstvert*3;
@ -3659,10 +3664,10 @@ static void BE_LegacyLighting(void)
}
}
if (shaderstate.curtexnums->bump.num && gl_config.arb_texture_cube_map && gl_config.arb_texture_env_dot3 && gl_config.arb_texture_env_combine && be_maxpasses >= 4)
if (TEXVALID(shaderstate.curtexnums->bump) && gl_config.arb_texture_cube_map && gl_config.arb_texture_env_dot3 && gl_config.arb_texture_env_combine && be_maxpasses >= 4)
{ //we could get this down to 2 tmus by arranging for the dot3 result to be written the alpha buffer. But then we'd need to have an alpha buffer too.
if (!shaderstate.normalisationcubemap.num)
if (!shaderstate.normalisationcubemap)
shaderstate.normalisationcubemap = GenerateNormalisationCubeMap();
//tmu0: normalmap+replace+regular tex coords
@ -3973,7 +3978,7 @@ static void DrawMeshes(void)
GenerateFogTexture(&shaderstate.fogtexture, shaderstate.curbatch->fog->shader->fog_dist, 2048);
shaderstate.fogfar = 1.0f/2048; /*scaler for z coords*/
while(shaderstate.lastpasstmus>0)
while(shaderstate.lastpasstmus>1)
{
GL_LazyBind(--shaderstate.lastpasstmus, 0, r_nulltex);
}
@ -4300,7 +4305,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
if (shaderstate.mode == BEM_LIGHT)
continue;
if (batch->shader->flags & SHADER_NOSHADOWS)
if (shaderstate.mode == BEM_DEPTHONLY)
if (shaderstate.mode == BEM_STENCIL || shaderstate.mode == BEM_DEPTHONLY) //fixme: depthonly is not just shadows.
continue;
if (batch->shader->flags & SHADER_SKY)
{
@ -4333,9 +4338,10 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
{
vrect_t orect = r_refdef.vrect;
pxrect_t oprect = r_refdef.pxrect;
if (!shaderstate.tex_reflection.num)
if (!shaderstate.tex_reflection)
{
shaderstate.tex_reflection = GL_AllocNewTexture("***tex_reflection***", vid.pixelwidth/2, vid.pixelheight/2, 0);
shaderstate.tex_reflection = Image_CreateTexture("***tex_reflection***", NULL, 0);
qglGenTextures(1, &shaderstate.tex_reflection->num);
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_reflection);
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, vid.pixelwidth/2, vid.pixelheight/2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@ -4370,9 +4376,10 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
vrect_t ovrect = r_refdef.vrect;
pxrect_t oprect = r_refdef.pxrect;
if (!shaderstate.tex_refraction.num)
if (!shaderstate.tex_refraction)
{
shaderstate.tex_refraction = GL_AllocNewTexture("***tex_refraction***", vid.pixelwidth/2, vid.pixelheight/2, 0);
shaderstate.tex_refraction = Image_CreateTexture("***tex_refraction***", NULL, 0);
qglGenTextures(1, &shaderstate.tex_refraction->num);
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_refraction);
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, vid.pixelwidth/2, vid.pixelheight/2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@ -4382,9 +4389,10 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
}
if (batch->shader->flags & SHADER_HASREFRACTDEPTH)
{
if (!shaderstate.tex_refractiondepth.num)
if (!shaderstate.tex_refractiondepth)
{
shaderstate.tex_refractiondepth = GL_AllocNewTexture("***tex_refractiondepth***", vid.pixelwidth/2, vid.pixelheight/2, 0);
shaderstate.tex_refractiondepth = Image_CreateTexture("***tex_refractiondepth***", NULL, 0);
qglGenTextures(1, &shaderstate.tex_refractiondepth->num);
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_refractiondepth);
qglTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24_ARB, vid.pixelwidth/2, vid.pixelheight/2, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@ -4427,10 +4435,11 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
{
vrect_t orect = r_refdef.vrect;
pxrect_t oprect = r_refdef.pxrect;
if (!shaderstate.tex_ripplemap.num)
if (!shaderstate.tex_ripplemap)
{
//FIXME: can we use RGB8 instead?
shaderstate.tex_ripplemap = GL_AllocNewTexture("***tex_ripplemap***", vid.pixelwidth/2, vid.pixelheight/2, 0);
shaderstate.tex_ripplemap = Image_CreateTexture("***tex_ripplemap***", NULL, 0);
qglGenTextures(1, &shaderstate.tex_ripplemap->num);
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_ripplemap);
qglTexImage2D(GL_TEXTURE_2D, 0, /*(gl_config.glversion>3.1)?GL_RGBA8_SNORM:*/GL_RGBA16F_ARB, vid.pixelwidth/2, vid.pixelheight/2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@ -4526,7 +4535,9 @@ static void BE_UpdateLightmaps(void)
lm->modified = false;
if (!TEXVALID(lm->lightmap_texture))
{
TEXASSIGN(lm->lightmap_texture, R_AllocNewTexture("***lightmap***", lm->width, lm->height, IF_LINEAR|IF_NOMIPMAP));
extern cvar_t gl_lightmap_nearest;
TEXASSIGN(lm->lightmap_texture, Image_CreateTexture("***lightmap***", NULL, (gl_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR)|IF_NOMIPMAP));
qglGenTextures(1, &lm->lightmap_texture->num);
GL_MTBind(0, GL_TEXTURE_2D, lm->lightmap_texture);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@ -4570,7 +4581,7 @@ void GLBE_BaseEntTextures(void)
batch_t **ob = shaderstate.mbatches;
shaderstate.mbatches = batches;
BE_GenModelBatches(batches, shaderstate.curdlight, shaderstate.mode);
GLBE_SubmitMeshes(false, SHADER_SORT_PORTAL, SHADER_SORT_DECAL);
GLBE_SubmitMeshes(false, SHADER_SORT_PORTAL, SHADER_SORT_SEETHROUGH+1);
GLBE_SelectEntity(&r_worldentity);
shaderstate.mbatches = ob;
}
@ -4714,7 +4725,7 @@ int GLBE_FBO_Update(fbostate_t *state, unsigned int enables, texid_t *destcol, i
}
if (enables & FBO_TEX_DEPTH)
{
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, destdepth.num, 0);
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, destdepth->num, 0);
//fixme: no stencil
}
else if (enables & FBO_RB_DEPTH)
@ -4748,7 +4759,7 @@ int GLBE_FBO_Update(fbostate_t *state, unsigned int enables, texid_t *destcol, i
}
for (i = 0; i < mrt; i++)
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+i, GL_TEXTURE_2D, destcol[i].num, 0);
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+i, GL_TEXTURE_2D, destcol[i]->num, 0);
i = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (GL_FRAMEBUFFER_COMPLETE_EXT != i)
@ -4921,7 +4932,8 @@ void GLBE_DrawLightPrePass(qbyte *vis)
if (!TEXVALID(shaderstate.tex_normals))
{
shaderstate.tex_normals = GL_AllocNewTexture("***prepass normals***", vid.pixelwidth, vid.pixelheight, 0);
shaderstate.tex_normals = Image_CreateTexture("***prepass normals***", NULL, 0);
qglGenTextures(1, &shaderstate.tex_normals->num);
r_lightprepass.modified = true;
}
if (r_lightprepass.modified)
@ -4935,7 +4947,8 @@ void GLBE_DrawLightPrePass(qbyte *vis)
if (!TEXVALID(shaderstate.tex_diffuse))
{
shaderstate.tex_diffuse = GL_AllocNewTexture("***prepass diffuse***", vid.pixelwidth, vid.pixelheight, 0);
shaderstate.tex_diffuse = Image_CreateTexture("***prepass diffuse***", NULL, 0);
qglGenTextures(1, &shaderstate.tex_diffuse->num);
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_diffuse);
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, vid.pixelwidth, vid.pixelheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@ -5006,6 +5019,7 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis)
TRACE(("GLBE_DrawWorld: %i %p\n", drawworld, vis));
//reset batches if we needed more mem, to avoid allocations mid-frame.
if (!r_refdef.recurse)
{
if (shaderstate.wbatch + 50 > shaderstate.maxwbatches)
@ -5018,6 +5032,7 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis)
shaderstate.wbatch = 0;
}
//if the video mode changed, update any fbos (hopefully this won't happen on mirrors)
if (shaderstate.oldwidth != vid.pixelwidth || shaderstate.oldheight != vid.pixelheight)
{
GLBE_DestroyFBOs(); //will be recreated on demand
@ -5148,6 +5163,8 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis)
void GLBE_VBO_Begin(vbobctx_t *ctx, unsigned int maxsize)
{
COM_AssertMainThread("GLBE_VBO_Begin");
ctx->maxsize = maxsize;
ctx->pos = 0;
ctx->fallback = NULL;

Some files were not shown because too many files have changed in this diff Show More