diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 9fa3e02a2..bb289a9a8 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -1362,6 +1362,20 @@ void CL_RotateAroundTag(entity_t *ent, int num, int tagent, int tagnum) } } +void V_AddAxisEntity(entity_t *in) +{ + entity_t *ent; + + if (cl_numvisedicts == MAX_VISEDICTS) + { + Con_Printf("Visedict list is full!\n"); + return; // object list is full + } + ent = &cl_visedicts[cl_numvisedicts]; + cl_numvisedicts++; + + *ent = *in; +} void V_AddEntity(entity_t *in) { entity_t *ent; diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 742a28802..9323e4d32 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -36,6 +36,8 @@ cvar_t cl_netfps = {"cl_netfps", "0"}; cvar_t cl_smartjump = {"cl_smartjump", "1"}; +cvar_t cl_prydoncursor = {"cl_prydoncursor", "0"}; //for dp protocol + usercmd_t independantphysics[MAX_SPLITS]; @@ -551,7 +553,10 @@ void CL_FinishMove (usercmd_t *cmd, int msecs, int pnum) // from the last level // if (++cl.movemessages <= 2) + { + cmd->buttons = 0; return; + } // // figure button bits // @@ -584,21 +589,50 @@ void CL_FinishMove (usercmd_t *cmd, int msecs, int pnum) cmd->impulse = 0; } -cvar_t cl_prydoncursor = {"cl_prydoncursor", "0"}; +float cursor_screen[2]; + +void CL_DrawPrydonCursor(void) +{ + if (cls.protocol == CP_NETQUAKE) + if (nq_dp_protocol >= 6) + if (cl_prydoncursor.value) + { + mpic_t *pic = Draw_SafeCachePic(va("gfx/prydoncursor%03i.lmp", (int)cl_prydoncursor.value)); + if (pic) + Draw_Pic((cursor_screen[0] + 1) * 0.5 * vid.width, (cursor_screen[1] + 1) * 0.5 * vid.height, pic); + else + Draw_Character((cursor_screen[0] + 1) * 0.5 * vid.width, (cursor_screen[1] + 1) * 0.5 * vid.height, '+'); + } +} + void ML_UnProject(vec3_t in, vec3_t out, vec3_t viewangles, vec3_t vieworg, float wdivh, float fovy); -void CL_UpdatePrydonCursor(float cursor_screen[2], vec3_t cursor_start, vec3_t cursor_impact, int *entnum) +void CL_UpdatePrydonCursor(usercmd_t *from, float cursor_screen[2], vec3_t cursor_start, vec3_t cursor_impact, int *entnum) { float modelview[16]; vec3_t cursor_end; - trace_t tr; - vec3_t temp, scale; + vec3_t temp; + vec3_t cursor_impact_normal; if (!cl_prydoncursor.value) { //center the cursor cursor_screen[0] = 0; cursor_screen[1] = 0; } + else + { + cursor_screen[0] += from->sidemove/10000.0f; + cursor_screen[1] -= from->forwardmove/10000.0f; + if (cursor_screen[0] < -1) + cursor_screen[0] = -1; + if (cursor_screen[1] < -1) + cursor_screen[1] = -1; + + if (cursor_screen[0] > 1) + cursor_screen[0] = 1; + if (cursor_screen[1] > 1) + cursor_screen[1] = 1; + } /* if (cl.cmd.cursor_screen[0] < -1) @@ -625,32 +659,28 @@ void CL_UpdatePrydonCursor(float cursor_screen[2], vec3_t cursor_start, vec3_t c // cursor_screen[0] = bound(-1, cursor_screen[0], 1); // cursor_screen[1] = bound(-1, cursor_screen[1], 1); - scale[0] = -tan(r_refdef.fov_x * M_PI / 360.0); - scale[1] = -tan(r_refdef.fov_y * M_PI / 360.0); - scale[2] = 1; - - // trace distance - VectorScale(scale, 1000000, scale); - - - VectorCopy(cl.simorg[0], cursor_start); - temp[0] = cursor_screen[0]; - temp[1] = cursor_screen[1]; + VectorCopy(vec3_origin, cursor_start); + temp[0] = (cursor_screen[0]+1)/2; + temp[1] = (-cursor_screen[1]+1)/2; temp[2] = 1; -// ML_UnProject(temp, cursor_end, cl.viewangles[0], cl.simorg[0], vid.width/vid.height, 90); - ML_ModelViewMatrix(modelview, cl.viewangles[0], cl.simorg[0]); - Matrix4_Transform3(modelview, temp, cursor_end); + ML_UnProject(temp, cursor_end, cl.viewangles[0], vec3_origin, (float)vid.width/vid.height, scr_fov.value ); + VectorScale(cursor_end, 100000, cursor_end); + + VectorAdd(cursor_start, cl.simorg[0], cursor_start); + VectorAdd(cursor_end, cl.simorg[0], cursor_end); + cursor_start[2]+=cl.viewheight[0]; + cursor_end[2]+=cl.viewheight[0]; + CL_SetSolidEntities(); //don't bother with players, they don't exist in NQ... - tr = PM_PlayerTrace(cursor_start, cursor_end); - VectorCopy(tr.endpos, cursor_impact); + TraceLineN(cursor_start, cursor_end, cursor_impact, cursor_impact_normal); // CL_SelectTraceLine(cursor_start, cursor_end, cursor_impact, entnum); // makes sparks where cursor is //CL_SparkShower(cl.cmd.cursor_impact, cl.cmd.cursor_normal, 5, 0); -// P_RunParticleEffectType(cursor_impact, vec3_origin, 1, 0); +// P_RunParticleEffectType(cursor_impact, vec3_origin, 1, pt_gunshot); //P_ParticleTrail(cursor_start, cursor_impact, 0, NULL); } @@ -660,7 +690,6 @@ void CLNQ_SendMove (usercmd_t *cmd, int pnum, sizebuf_t *buf) int bits; int i; - float cursor_screen[2]; vec3_t cursor_start, cursor_impact; int cursor_entitynumber=0;//I hate warnings as errors @@ -704,7 +733,7 @@ void CLNQ_SendMove (usercmd_t *cmd, int pnum, sizebuf_t *buf) if (nq_dp_protocol >= 6) { - CL_UpdatePrydonCursor(cursor_screen, cursor_start, cursor_impact, &cursor_entitynumber); + CL_UpdatePrydonCursor(cmd, cursor_screen, cursor_start, cursor_impact, &cursor_entitynumber); MSG_WriteLong (buf, bits); } else @@ -1021,6 +1050,9 @@ void CL_SendCmd (float frametime) extern cvar_t cl_maxfps; + vec3_t cursor_start, cursor_impact; + int cursor_entitynumber=0;//I hate warnings as errors + if (cls.demoplayback != DPB_NONE) { if (cls.demoplayback == DPB_MVD) @@ -1512,6 +1544,8 @@ void CL_InitInput (void) Cvar_Register (&cl_netfps, inputnetworkcvargroup); Cvar_Register (&cl_smartjump, inputnetworkcvargroup); + + Cvar_Register (&cl_prydoncursor, inputnetworkcvargroup); } /* diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 74b8e4b72..baa8f3e21 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // cl_main.c -- client main loop +#include #include "quakedef.h" #include "winquake.h" #include @@ -32,8 +33,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define WINAVI #endif -#include - // we need to declare some mouse variables here, because the menu system // references them even when on a unix system. @@ -1670,6 +1669,16 @@ void CL_ConnectionlessPacket (void) MSG_BeginReading (); MSG_ReadLong (); // skip the -1 + Cmd_TokenizeString(net_message.data+4, false, false); + + if (net_message.cursize == sizeof(net_message_buffer)) + net_message.data[sizeof(net_message_buffer)-1] = '\0'; + else + net_message.data[net_message.cursize] = '\0'; + + if (Plug_ConnectionlessClientPacket(net_message.data+4, net_message.cursize-4)) + return; + c = MSG_ReadByte (); if (cls.demoplayback == DPB_NONE) @@ -1994,6 +2003,10 @@ void CLNQ_ConnectionlessPacket(void) cls.state = ca_connected; Con_TPrintf (TLC_CONNECTED); allowremotecmd = false; // localid required now for remote cmds + + //send a dummy packet. + //this makes our local nat think we initialised the conversation. + NET_SendPacket(NS_CLIENT, 9, "\xff\xff\xff\xff""dummy", net_from); return; case CCREP_REJECT: diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index b9969066a..90c011ba9 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -2208,7 +2208,10 @@ void CL_ParseStartSoundPacket(void) if (ent > MAX_EDICTS) Host_EndGame ("CL_ParseStartSoundPacket: ent = %i", ent); - S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation); +#ifdef PEXT_CSQC + if (!CSQC_StartSound(ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation)) +#endif + S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation); if (ent == cl.playernum[0]+1) diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index 9e30ae6a4..6e537379d 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -760,6 +760,9 @@ void SCR_CalcRefdef (void) } r_refdef.fov_x = scr_fov.value; + if (cl.stats[0][STAT_VIEWZOOM]) + r_refdef.fov_x *= cl.stats[0][STAT_VIEWZOOM]/255.0f; + if (r_refdef.fov_x < 10) r_refdef.fov_x = 10; else if (r_refdef.fov_x > 170) @@ -1893,6 +1896,8 @@ void SCR_DrawTwoDimensional(int uimenu, qboolean nohud) Plug_SBar (); #endif SCR_ShowPics_Draw(); + + CL_DrawPrydonCursor(); } else SCR_DrawFPS (); diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index 70be33e79..52976f331 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -110,7 +110,7 @@ typedef enum #define TE_STREAM_FAMINE 32 -#define MAX_BEAMS 32 +#define MAX_BEAMS 64 typedef struct { int entity; @@ -305,8 +305,9 @@ beam_t *CL_NewBeam (int entity, int tag) { beam_t *b; int i; -// override any beam with the same entity - if (entity) // allow multiple world beams + +// override any beam with the same entity (unless they used world) + if (entity) { for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) if (b->entity == entity && b->tag == tag) @@ -327,25 +328,13 @@ beam_t *CL_NewBeam (int entity, int tag) } #define STREAM_ATTACHED 16 #define STREAM_TRANSLUCENT 32 -void CL_ParseBeam (int tent) +void CL_AddBeam (int tent, int ent, vec3_t start, vec3_t end) //fixme: use TE_ numbers instead of 0 - 5 { - int ent; - vec3_t start, end; beam_t *b; model_t *m; int btype, etype; - ent = MSG_ReadShort (); - - start[0] = MSG_ReadCoord (); - start[1] = MSG_ReadCoord (); - start[2] = MSG_ReadCoord (); - - end[0] = MSG_ReadCoord (); - end[1] = MSG_ReadCoord (); - end[2] = MSG_ReadCoord (); - switch(tent) { case 0: @@ -362,6 +351,7 @@ void CL_ParseBeam (int tent) case 1: if (ent < 0 && ent >= -MAX_CLIENTS) //based on the railgun concept - this adds a rogue style TE_BEAM effect. { + case 5: m = Mod_ForName("progs/beam.mdl", false); //remember to precache! btype = P_FindParticleType("te_beam"); etype = P_FindParticleType("te_beam_end"); @@ -424,6 +414,23 @@ void CL_ParseBeam (int tent) VectorCopy (start, b->start); VectorCopy (end, b->end); } +void CL_ParseBeam (int tent) +{ + int ent; + vec3_t start, end; + + ent = MSG_ReadShort (); + + start[0] = MSG_ReadCoord (); + start[1] = MSG_ReadCoord (); + start[2] = MSG_ReadCoord (); + + end[0] = MSG_ReadCoord (); + end[1] = MSG_ReadCoord (); + end[2] = MSG_ReadCoord (); + + CL_AddBeam(tent, ent, start, end); +} void CL_ParseStream (int type) { int ent; @@ -580,7 +587,7 @@ void CL_ParseTEnt (void) dlight_t *dl; int rnd; // explosion_t *ex; - int cnt; + int cnt, colour; type = MSG_ReadByte (); switch (type) @@ -1129,8 +1136,7 @@ void CL_ParseTEnt (void) // stain (Hopefully this is close to how DP does it) R_AddStain(pos, -10, -10, -10, 30); - // TODO: DP also has a decal, should this be simulated or should we just - // use a particle effect and let the user decide what to do with it? + P_ParticleTrail(pos, pos2, P_FindParticleType("te_plasmaburn"), NULL); break; case DPTE_TEI_G3: //nexuiz's nex beam @@ -1187,13 +1193,86 @@ void CL_ParseTEnt (void) break; case DPTE_PARTICLECUBE: - #pragma message("CL_ParseTEnt: effect DPTE_PARTICLECUBE not implemented") - case DPTE_PARTICLERAIN: - #pragma message("CL_ParseTEnt: effect DPTE_PARTICLERAIN not implemented") - case DPTE_PARTICLESNOW: - #pragma message("CL_ParseTEnt: effect DPTE_PARTICLESNOW not implemented") + { + vec3_t dir; + int jitter; + int gravity; - default: + //min + pos[0] = MSG_ReadCoord(); + pos[1] = MSG_ReadCoord(); + pos[2] = MSG_ReadCoord(); + + //max + pos2[0] = MSG_ReadCoord(); + pos2[1] = MSG_ReadCoord(); + pos2[2] = MSG_ReadCoord(); + + //dir + dir[0] = MSG_ReadCoord(); + dir[1] = MSG_ReadCoord(); + dir[2] = MSG_ReadCoord(); + + cnt = MSG_ReadShort(); //count + colour = MSG_ReadByte (); //colour + gravity = MSG_ReadByte (); //gravity flag + jitter = MSG_ReadCoord(); //jitter + + P_RunParticleCube(pos, pos2, dir, cnt, colour, gravity, jitter); + } + break; + case DPTE_PARTICLERAIN: + { + vec3_t dir; + + //min + pos[0] = MSG_ReadCoord(); + pos[1] = MSG_ReadCoord(); + pos[2] = MSG_ReadCoord(); + + //max + pos2[0] = MSG_ReadCoord(); + pos2[1] = MSG_ReadCoord(); + pos2[2] = MSG_ReadCoord(); + + //dir + dir[0] = MSG_ReadCoord(); + dir[1] = MSG_ReadCoord(); + dir[2] = MSG_ReadCoord(); + + cnt = MSG_ReadShort(); //count + colour = MSG_ReadByte (); //colour + + P_RunParticleWeather(pos, pos2, dir, cnt, colour, "rain"); + } + break; + case DPTE_PARTICLESNOW: + { + vec3_t dir; + + //min + pos[0] = MSG_ReadCoord(); + pos[1] = MSG_ReadCoord(); + pos[2] = MSG_ReadCoord(); + + //max + pos2[0] = MSG_ReadCoord(); + pos2[1] = MSG_ReadCoord(); + pos2[2] = MSG_ReadCoord(); + + //dir + dir[0] = MSG_ReadCoord(); + dir[1] = MSG_ReadCoord(); + dir[2] = MSG_ReadCoord(); + + cnt = MSG_ReadShort(); //count + colour = MSG_ReadByte (); //colour + + P_RunParticleWeather(pos, pos2, dir, cnt, colour, "snow"); + } + break; + + default: Host_EndGame ("CL_ParseTEnt: bad type - %i", type); } } @@ -2168,32 +2247,37 @@ void CL_UpdateBeams (void) } // if coming from the player, update the start position - if (b->flags & 1 && b->entity == (autocam[0]?spec_track[0]:(cl.playernum[0]+1))) // entity 0 is the world + if (b->flags & 1 && b->entity == (autocam[0]?spec_track[0]:(cl.playernum[0]+1)) && b->entity>0 && b->entity<= MAX_CLIENTS) // entity 0 is the world { + player_state_t *pl; // VectorSubtract(cl.simorg, b->start, org); // VectorAdd(b->end, org, b->end); //move the end point by simorg-start - VectorCopy (cl.simorg[0], b->start); //move the start point to view origin - b->start[2] += cl.crouch[0]; - if (v_viewheight.value) + pl = &cl.frames[cl.parsecount&UPDATE_MASK].playerstate[b->entity-1]; + if (pl->messagenum == cl.parsecount) { - if (v_viewheight.value <= -7) - b->start[2] += -7; - else if (v_viewheight.value >= 4) - b->start[2] += 4; - else - b->start[2] += v_viewheight.value; - } + VectorCopy (cl.simorg[0], b->start); //move the start point to view origin + b->start[2] += cl.crouch[0]; + if (v_viewheight.value) + { + if (v_viewheight.value <= -7) + b->start[2] += -7; + else if (v_viewheight.value >= 4) + b->start[2] += 4; + else + b->start[2] += v_viewheight.value; + } - //rotate the end point to face in the view direction. This gives a smoother shafting. turning looks great. - if (cl_truelightning.value) - { - VectorSubtract (b->end, b->start, dist); - d = VectorNormalize(dist); - AngleVectors (cl.simangles[0], b->end, dist, org); - VectorMA(b->start, d, b->end, b->end); - b->end[2] += cl.viewheight[0]; + //rotate the end point to face in the view direction. This gives a smoother shafting. turning looks great. + if (cl_truelightning.value) + { + VectorSubtract (b->end, b->start, dist); + d = VectorNormalize(dist); + AngleVectors (cl.simangles[0], b->end, dist, org); + VectorMA(b->start, d, b->end, b->end); + b->end[2] += cl.viewheight[0]; + } } } else if (b->flags & STREAM_ATTACHED) diff --git a/engine/client/client.h b/engine/client/client.h index 64e20a70b..8c90a0b49 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -290,7 +290,8 @@ typedef struct CP_QUAKEWORLD, CP_NETQUAKE, CP_QUAKE2, - CP_QUAKE3 + CP_QUAKE3, + CP_PLUGIN } protocol; qboolean resendinfo; @@ -660,6 +661,7 @@ void CL_ParseTEnt (qboolean nqprot); void CL_ParseTEnt (void); #endif void CL_UpdateTEnts (void); +void CL_AddBeam (int tent, int ent, vec3_t start, vec3_t end); void CL_ClearState (void); @@ -786,6 +788,8 @@ qboolean CSQC_StuffCmd(char *cmd); qboolean CSQC_CenterPrint(char *cmd); qboolean CSQC_ConsoleCommand(char *cmd); qboolean CSQC_KeyPress(int key, qboolean down); +int CSQC_StartSound(int entnum, int channel, char *soundname, vec3_t pos, float vol, float attenuation); +void CSQC_ParseEntities(void); #endif // diff --git a/engine/client/image.c b/engine/client/image.c index e507c26ff..244eac5e3 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -1687,8 +1687,6 @@ qbyte *Read32BitImageFile(qbyte *buf, int len, int *width, int *height) return NULL; } -int GL_LoadTexture8Bump (char *identifier, int width, int height, unsigned char *data, qboolean mipmap); - int image_width, image_height; qbyte *COM_LoadFile (char *path, int usehunk); int Mod_LoadHiResTexture(char *name, char *subpath, qboolean mipmap, qboolean alpha, qboolean colouradjust) @@ -1790,6 +1788,7 @@ int Mod_LoadReplacementTexture(char *name, char *subpath, qboolean mipmap, qbool return Mod_LoadHiResTexture(name, subpath, mipmap, alpha, gammaadjust); } +extern cvar_t r_shadow_bumpscale_bumpmap; int Mod_LoadBumpmapTexture(char *name, char *subpath) { char *buf, *data; @@ -1852,7 +1851,7 @@ int Mod_LoadBumpmapTexture(char *name, char *subpath) if ((data = ReadTargaFile(buf, com_filesize, &image_width, &image_height, 2))) //Only load a greyscale image. { TRACE(("dbg: Mod_LoadBumpmapTexture: tga %s loaded\n", name)); - len = GL_LoadTexture8Bump(name, image_width, image_height, data, true); + len = GL_LoadTexture8Bump(name, image_width, image_height, data, true, r_shadow_bumpscale_bumpmap.value); BZ_Free(data); } else diff --git a/engine/client/in_raw.h b/engine/client/in_raw.h index e8862d1fe..e680783ac 100644 --- a/engine/client/in_raw.h +++ b/engine/client/in_raw.h @@ -1,5 +1,9 @@ // Raw input includes +#ifndef WINUSERAPI +#define WINUSERAPI +#endif + #ifndef RIM_TYPEMOUSE #define WM_INPUT 255 @@ -116,4 +120,4 @@ WINUSERAPI UINT WINAPI GetRawInputDeviceInfoW(HANDLE,UINT,LPVOID,PUINT); WINUSERAPI UINT WINAPI GetRawInputDeviceList(PRAWINPUTDEVICELIST,PUINT,UINT); WINUSERAPI UINT WINAPI GetRegisteredRawInputDevices(PRAWINPUTDEVICE,PUINT,UINT); WINUSERAPI BOOL WINAPI RegisterRawInputDevices(PCRAWINPUTDEVICE,UINT,UINT); -#endif \ No newline at end of file +#endif diff --git a/engine/client/in_win.c b/engine/client/in_win.c index a38b5b5aa..76e572d17 100644 --- a/engine/client/in_win.c +++ b/engine/client/in_win.c @@ -241,10 +241,10 @@ static JOYINFOEX ji; #define RI_INVALID_POS 0x80000000 // raw input dynamic functions -typedef WINUSERAPI INT (WINAPI *pGetRawInputDeviceList)(OUT PRAWINPUTDEVICELIST pRawInputDeviceList, IN OUT PINT puiNumDevices, IN UINT cbSize); -typedef WINUSERAPI INT(WINAPI *pGetRawInputData)(IN HRAWINPUT hRawInput, IN UINT uiCommand, OUT LPVOID pData, IN OUT PINT pcbSize, IN UINT cbSizeHeader); -typedef WINUSERAPI INT(WINAPI *pGetRawInputDeviceInfoA)(IN HANDLE hDevice, IN UINT uiCommand, OUT LPVOID pData, IN OUT PINT pcbSize); -typedef WINUSERAPI BOOL (WINAPI *pRegisterRawInputDevices)(IN PCRAWINPUTDEVICE pRawInputDevices, IN UINT uiNumDevices, IN UINT cbSize); +typedef INT (WINAPI *pGetRawInputDeviceList)(OUT PRAWINPUTDEVICELIST pRawInputDeviceList, IN OUT PINT puiNumDevices, IN UINT cbSize); +typedef INT(WINAPI *pGetRawInputData)(IN HRAWINPUT hRawInput, IN UINT uiCommand, OUT LPVOID pData, IN OUT PINT pcbSize, IN UINT cbSizeHeader); +typedef INT(WINAPI *pGetRawInputDeviceInfoA)(IN HANDLE hDevice, IN UINT uiCommand, OUT LPVOID pData, IN OUT PINT pcbSize); +typedef BOOL (WINAPI *pRegisterRawInputDevices)(IN PCRAWINPUTDEVICE pRawInputDevices, IN UINT uiNumDevices, IN UINT cbSize); pGetRawInputDeviceList _GRIDL; pGetRawInputData _GRID; @@ -1395,6 +1395,13 @@ static void ProcessMouse(mouse_t *mouse, usercmd_t *cmd, int pnum) mouse_x *= sensitivity.value*in_sensitivityscale; mouse_y *= sensitivity.value*in_sensitivityscale; + if (cl.stats[pnum][STAT_VIEWZOOM]) + { + mouse_x *= cl.stats[pnum][STAT_VIEWZOOM]/255.0f; + mouse_y *= cl.stats[pnum][STAT_VIEWZOOM]/255.0f; + } + + if (!cmd) { if (mx || my) diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index ce78a7a84..c52c0feff 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -828,6 +828,7 @@ float filmstarttime; int soundpos; #pragma comment( lib, "vfw32.lib" ) #endif +static qbyte *framedata; //this buffer holds the image data temporarily.. #define MFT_CAPTURE 5 //fixme @@ -908,6 +909,12 @@ qboolean Media_PlayFilm(char *name) media_filmtype = MFT_NONE; + if (framedata) + { + BZ_Free(framedata); + framedata = NULL; + } + if (!name || !*name) //clear only. return false; @@ -963,6 +970,8 @@ qboolean Media_PlayFilm(char *name) if (key_dest != key_console) scr_con_current=0; media_filmtype = MFT_ROQ; + + framedata = BZ_Malloc(roqfilm->width*roqfilm->height*4); return true; } #ifdef WINAVI @@ -1011,6 +1020,7 @@ qboolean Media_PlayFilm(char *name) AVIStreamInfo(pavivideo, &psi, sizeof(psi)); filmwidth=psi.rcFrame.right-psi.rcFrame.left; // Width Is Right Side Of Frame Minus Left filmheight=psi.rcFrame.bottom-psi.rcFrame.top; // Height Is Bottom Of Frame Minus Top + framedata = BZ_Malloc(filmwidth*filmheight*4); num_frames=AVIStreamLength(pavivideo); // The Last Frame Of The Stream filmfps=1000.0f*(float)num_frames/(float)AVIStreamSampleToTime(pavivideo,num_frames); // Calculate Rough Milliseconds Per Frame @@ -1088,7 +1098,6 @@ soundpos=0; qboolean Media_ShowFilm(void) { // sfx_t *s; - static qbyte framedata[1024*1024*4]; static float lastframe=0; // soundcardinfo_t *sc; diff --git a/engine/client/merged.h b/engine/client/merged.h index 78af6239d..7f922a085 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -103,7 +103,8 @@ extern void FNC(Mod_NowLoadExternal) (void); extern void FNC(Mod_Think) (void); extern qboolean FNC(Mod_GetTag) (struct model_s *model, int tagnum, int frame, int frame2, float f2ness, float f1time, float f2time, float *transforms); -extern int FNC(Mod_TagNumForName) (struct model_s *model, char *name); +extern int FNC(Mod_TagNumForName) (struct model_s *model, char *name); +extern int FNC(Mod_SkinForName) (struct model_s *model, char *name); #undef FNC @@ -183,6 +184,7 @@ typedef struct { void (*Mod_Think) (void); qboolean(*Mod_GetTag) (struct model_s *model, int tagnum, int frame1, int frame2, float f2ness, float f1time, float f2time, float *result); int (*Mod_TagNumForName) (struct model_s *model, char *name); + int (*Mod_SkinForName) (struct model_s *model, char *name); qboolean (*VID_Init) (rendererstate_t *info, unsigned char *palette); diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 1f81b041d..0d367116c 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -21,6 +21,8 @@ static unsigned int csqcchecksum; static qboolean csqcwantskeys; static csqctreadstate_t *csqcthreads; qboolean csqc_resortfrags; +qboolean csqc_drawsbar; +qboolean csqc_addcrosshair; cvar_t pr_csmaxedicts = {"pr_csmaxedicts", "3072"}; cvar_t cl_csqcdebug = {"cl_csqcdebug", "0"}; //prints entity numbers which arrive (so I can tell people not to apply it to players...) @@ -38,6 +40,8 @@ cvar_t cl_csqcdebug = {"cl_csqcdebug", "0"}; //prints entity numbers which arriv globalfunction(ent_update, "CSQC_Ent_Update"); \ globalfunction(ent_remove, "CSQC_Ent_Remove"); \ \ + globalfunction(serversound, "CSQC_ServerSound"); \ + \ /*These are pointers to the csqc's globals.*/ \ globalfloat(time, "time"); /*float Written before entering most qc functions*/ \ globalentity(self, "self"); /*entity Written before entering most qc functions*/ \ @@ -68,6 +72,8 @@ cvar_t cl_csqcdebug = {"cl_csqcdebug", "0"}; //prints entity numbers which arriv globalvector(pmove_vel, "pmove_vel"); \ globalvector(pmove_mins, "pmove_mins"); \ globalvector(pmove_maxs, "pmove_maxs"); \ + globalfloat(pmove_jump_held, "pmove_jump_held"); \ + globalfloat(pmove_waterjumptime, "pmove_waterjumptime"); \ globalfloat(input_timelength, "input_timelength"); \ globalvector(input_angles, "input_angles"); \ globalvector(input_movevalues, "input_movevalues"); \ @@ -146,11 +152,14 @@ static void CSQC_FindGlobals(void) fieldfloat(fatness); /*expand models X units along thier normals.*/ \ fieldfloat(skin); \ fieldfloat(colormap); \ - fieldfloat(frame); \ fieldfloat(flags); \ - fieldfloat(oldframe); \ + fieldfloat(frame); \ + fieldfloat(frame2); \ + fieldfloat(frame1time); \ + fieldfloat(frame2time); \ fieldfloat(lerpfrac); \ fieldfloat(renderflags);\ + fieldfloat(forceshader);\ \ fieldfloat(drawmask); /*So that the qc can specify all rockets at once or all bannanas at once*/ \ fieldfunction(predraw); /*If present, is called just before it's drawn.*/ \ @@ -164,7 +173,7 @@ static void CSQC_FindGlobals(void) fieldentity(chain); \ fieldentity(groundentity); \ \ - fieldvector(solid); \ + fieldfloat(solid); \ fieldvector(mins); \ fieldvector(maxs); \ fieldvector(absmins); \ @@ -196,6 +205,7 @@ typedef struct csqcedict_s csqcentvars_t *v; //add whatever you wish here + trailstate_t *trailstate; } csqcedict_t; static csqcedict_t *csqc_edicts; //consider this 'world' @@ -216,7 +226,8 @@ csqcfields //any *64->int32 casts are erroneous, it's biased off NULL. #undef fieldfunction } -static csqcedict_t *csqcent[MAX_EDICTS]; +static csqcedict_t **csqcent; +static int maxcsqcentities; #define RETURN_SSTRING(s) (((string_t *)pr_globals)[OFS_RETURN] = PR_SetString(prinst, s)) //static - exe will not change it. char *PF_TempStr(progfuncs_t *prinst); @@ -299,6 +310,7 @@ void PF_infoget (progfuncs_t *prinst, struct globalvars_s *pr_globals); void PF_strncmp (progfuncs_t *prinst, struct globalvars_s *pr_globals); void PF_strcasecmp (progfuncs_t *prinst, struct globalvars_s *pr_globals); void PF_strncasecmp (progfuncs_t *prinst, struct globalvars_s *pr_globals); +void PF_strpad (progfuncs_t *prinst, struct globalvars_s *pr_globals); //these functions are from pr_menu.dat void PF_CL_is_cached_pic (progfuncs_t *prinst, struct globalvars_s *pr_globals); @@ -328,14 +340,14 @@ void PF_search_getfilename (progfuncs_t *prinst, struct globalvars_s *pr_globals void PF_fclose_progs (progfuncs_t *prinst); char *PF_VarString (progfuncs_t *prinst, int first, struct globalvars_s *pr_globals); +int QCEditor (progfuncs_t *prinst, char *filename, int line, int nump, char **parms); - -void CL_CS_LinkEdict(csqcedict_t *ent) +void CL_CS_LinkEdict(csqcedict_t *ent, qboolean touchtriggers) { //FIXME: use some sort of area grid ? VectorAdd(ent->v->origin, ent->v->mins, ent->v->absmins); @@ -354,7 +366,7 @@ trace_t CL_Move(vec3_t v1, vec3_t mins, vec3_t maxs, vec3_t v2, float nomonsters memset(&trace, 0, sizeof(trace)); trace.fraction = 1; - cl.worldmodel->funcs.Trace(cl.worldmodel, 0, 0, v1, v2, vec3_origin, vec3_origin, &trace); + cl.worldmodel->funcs.Trace(cl.worldmodel, 0, 0, v1, v2, mins, maxs, &trace); //why use trace.endpos instead? //so that if we hit a wall early, we don't have a box covering the whole world because of a shotgun trace. @@ -407,6 +419,8 @@ static void PF_cs_remove (progfuncs_t *prinst, struct globalvars_s *pr_globals) return; } + P_DelinkTrailstate(&ed->trailstate); + ED_Free (prinst, (void*)ed); } @@ -517,15 +531,129 @@ void EularToQuaternian(vec3_t angles, float *quat) #define CSQCRF_VIEWMODEL 1 //Not drawn in mirrors #define CSQCRF_EXTERNALMODEL 2 //drawn ONLY in mirrors #define CSQCRF_DEPTHHACK 4 //fun depthhack -#define CSQCRF_ADDATIVE 8 //add instead of blend +#define CSQCRF_ADDITIVE 8 //add instead of blend #define CSQCRF_USEAXIS 16 //use v_forward/v_right/v_up as an axis/matrix - predraw is needed to use this properly +#define CSQCRF_NOSHADOW 32 //don't cast shadows upon other entities (can still be self shadowing, if the engine wishes, and not additive) -void PF_R_AddEntity(progfuncs_t *prinst, struct globalvars_s *pr_globals) +static model_t *CSQC_GetModelForIndex(int index) +{ + if (index == 0) + return NULL; + else if (index > 0 && index < MAX_MODELS) + return cl.model_precache[index]; + else if (index < 0 && index > -MAX_CSQCMODELS) + return cl.model_csqcprecache[-index]; + else + return NULL; +} + +static qboolean CopyCSQCEdictToEntity(csqcedict_t *in, entity_t *out) +{ + int i; + model_t *model; + + i = in->v->modelindex; + if (i == 0) + return false; + else if (i > 0 && i < MAX_MODELS) + model = cl.model_precache[i]; + else if (i < 0 && i > -MAX_CSQCMODELS) + model = cl.model_csqcprecache[-i]; + else + return false; //there might be other ent types later as an extension that stop this. + + if (!model) + { + Con_Printf("CopyCSQCEdictToEntity: model wasn't precached!\n"); + return false; + } + + memset(out, 0, sizeof(*out)); + out->model = model; + + if (in->v->renderflags) + { + i = in->v->renderflags; + if (i & CSQCRF_VIEWMODEL) + out->flags |= Q2RF_DEPTHHACK; + if (i & CSQCRF_EXTERNALMODEL) + out->flags |= Q2RF_EXTERNALMODEL; + if (i & CSQCRF_DEPTHHACK) + out->flags |= Q2RF_DEPTHHACK; + if (i & CSQCRF_ADDITIVE) + out->flags |= Q2RF_ADDATIVE; + //CSQCRF_USEAXIS is below + if (i & CSQCRF_NOSHADOW) + out->flags |= RF_NOSHADOW; + } + + out->frame = in->v->frame; + out->oldframe = in->v->frame2; + out->lerpfrac = in->v->lerpfrac; + VectorCopy(in->v->origin, out->origin); + if ((int)in->v->renderflags & CSQCRF_USEAXIS) + { + VectorCopy(csqcg.forward, out->axis[0]); + VectorNegate(csqcg.right, out->axis[1]); + VectorCopy(csqcg.up, out->axis[2]); + } + else + { + VectorCopy(in->v->angles, out->angles); + out->angles[0]*=-1; + AngleVectors(out->angles, out->axis[0], out->axis[1], out->axis[2]); + VectorInverse(out->axis[1]); + } + + out->frame1time = in->v->frame1time; + out->frame2time = in->v->frame2time; + + if (!in->v->alpha) + out->alpha = 1; + else + out->alpha = in->v->alpha; + if (!in->v->scale) + out->scale = 1; + else + out->scale = in->v->scale; + out->skinnum = in->v->skin; + out->fatness = in->v->fatness; +#ifdef Q3SHADERS + out->forcedshader = *(int*)&in->v->forceshader; +#endif + + out->keynum = -1; + + return true; +} + +static void PF_cs_makestatic (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ //still does a remove. + csqcedict_t *in = (void*)G_EDICT(prinst, OFS_PARM0); + entity_t *ent; + + if (cl.num_statics >= MAX_STATIC_ENTITIES) + { + Con_Printf ("Too many static entities"); + + PF_cs_remove(prinst, pr_globals); + return; + } + + ent = &cl_static_entities[cl.num_statics]; + if (CopyCSQCEdictToEntity(in, ent)) + { + cl.num_statics++; + R_AddEfrags(ent); + } + + PF_cs_remove(prinst, pr_globals); +} + +static void PF_R_AddEntity(progfuncs_t *prinst, struct globalvars_s *pr_globals) { csqcedict_t *in = (void*)G_EDICT(prinst, OFS_PARM0); entity_t ent; - int i; - model_t *model; if (in->v->predraw) { @@ -533,68 +661,13 @@ void PF_R_AddEntity(progfuncs_t *prinst, struct globalvars_s *pr_globals) *csqcg.self = EDICT_TO_PROG(prinst, (void*)in); PR_ExecuteProgram(prinst, in->v->predraw); *csqcg.self = oldself; + + if (in->isfree) + return; //bummer... } - i = in->v->modelindex; - if (i == 0) - return; - else if (i > 0 && i < MAX_MODELS) - model = cl.model_precache[i]; - else if (i < 0 && i > -MAX_CSQCMODELS) - model = cl.model_csqcprecache[-i]; - else - return; //there might be other ent types later as an extension that stop this. - - memset(&ent, 0, sizeof(ent)); - ent.model = model; - - if (!ent.model) - { - Con_Printf("PF_R_AddEntity: model wasn't precached!\n"); - return; - } - - if (in->v->renderflags) - { - i = in->v->renderflags; - if (i & CSQCRF_VIEWMODEL) - ent.flags |= Q2RF_WEAPONMODEL; - if (i & CSQCRF_EXTERNALMODEL) - ent.flags |= Q2RF_EXTERNALMODEL; - if (i & CSQCRF_DEPTHHACK) - ent.flags |= Q2RF_DEPTHHACK; - if (i & CSQCRF_ADDATIVE) - ent.flags |= Q2RF_ADDATIVE; - //CSQCRF_USEAXIS is below - } - - ent.frame = in->v->frame; - ent.oldframe = in->v->oldframe; - ent.lerpfrac = in->v->lerpfrac; - - ent.angles[0] = in->v->angles[0]; - ent.angles[1] = in->v->angles[1]; - ent.angles[2] = in->v->angles[2]; - - VectorCopy(in->v->origin, ent.origin); - if ((int)in->v->renderflags & CSQCRF_USEAXIS) - { - VectorCopy(csqcg.forward, ent.axis[0]); - VectorNegate(csqcg.right, ent.axis[1]); - VectorCopy(csqcg.up, ent.axis[2]); - } - else - { - AngleVectors(ent.angles, ent.axis[0], ent.axis[1], ent.axis[2]); - VectorInverse(ent.axis[1]); - } - - ent.alpha = in->v->alpha; - ent.scale = in->v->scale; - ent.skinnum = in->v->skin; - ent.fatness = in->v->fatness; - - V_AddEntity(&ent); + if (CopyCSQCEdictToEntity(in, &ent)) + V_AddAxisEntity(&ent); /* { @@ -697,6 +770,9 @@ static void PF_R_ClearScene (progfuncs_t *prinst, struct globalvars_s *pr_global r_refdef.fov_x = scr_fov.value; r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height); */ + + csqc_addcrosshair = false; + csqc_drawsbar = false; } typedef enum @@ -705,8 +781,8 @@ typedef enum VF_MIN_X = 2, VF_MIN_Y = 3, VF_SIZE = 4, - VF_SIZE_Y = 5, - VF_SIZE_X = 6, + VF_SIZE_X = 5, + VF_SIZE_Y = 6, VF_VIEWPORT = 7, VF_FOV = 8, VF_FOVX = 9, @@ -719,6 +795,9 @@ typedef enum VF_ANGLES_X = 16, VF_ANGLES_Y = 17, VF_ANGLES_Z = 18, + VF_DRAWWORLD = 19, + VF_NOENGINESBAR = 20, + VF_DRAWCROSSHAIR = 21, VF_PERSPECTIVE = 200 } viewflags; @@ -792,6 +871,16 @@ static void PF_R_SetViewFlag(progfuncs_t *prinst, struct globalvars_s *pr_global r_refdef.vrect.y = p[1]; break; + case VF_DRAWWORLD: + r_refdef.flags = r_refdef.flags&~Q2RDF_NOWORLDMODEL | (*p?0:Q2RDF_NOWORLDMODEL); + break; + case VF_NOENGINESBAR: + csqc_drawsbar = !*p; + break; + case VF_DRAWCROSSHAIR: + csqc_addcrosshair = *p; + break; + case VF_PERSPECTIVE: r_refdef.useperspective = *p; break; @@ -841,6 +930,11 @@ static void PF_R_RenderScene(progfuncs_t *prinst, struct globalvars_s *pr_global #endif vid.recalc_refdef = 1; + + if (csqc_drawsbar) + Sbar_Draw(); + if (csqc_addcrosshair) + Draw_Crosshair(); } static void PF_cs_getstatf(progfuncs_t *prinst, struct globalvars_s *pr_globals) @@ -889,19 +983,19 @@ static void PF_cs_SetOrigin(progfuncs_t *prinst, struct globalvars_s *pr_globals VectorCopy(org, ent->v->origin); - CL_CS_LinkEdict(ent); + CL_CS_LinkEdict(ent, false); } static void PF_cs_SetSize(progfuncs_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_PARM1); + float *maxs = G_VECTOR(OFS_PARM2); VectorCopy(mins, ent->v->mins); VectorCopy(maxs, ent->v->maxs); - CL_CS_LinkEdict(ent); + CL_CS_LinkEdict(ent, false); } static void PF_cs_traceline(progfuncs_t *prinst, struct globalvars_s *pr_globals) @@ -1199,6 +1293,19 @@ static void PF_cs_pointparticles (progfuncs_t *prinst, struct globalvars_s *pr_g P_RunParticleEffectType(org, vel, count, effectnum); } +static void PF_cs_trailparticles (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + int efnum = G_FLOAT(OFS_PARM0)-1; + csqcedict_t *ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM1); + float *start = G_VECTOR(OFS_PARM2); + float *end = G_VECTOR(OFS_PARM3); + + if (!ent->entnum) //world trails are non-state-based. + P_ParticleTrail(start, end, efnum, NULL); + else + P_ParticleTrail(start, end, efnum, &ent->trailstate); +} + static void PF_cs_particlesloaded (progfuncs_t *prinst, struct globalvars_s *pr_globals) { char *effectname = PR_GetStringOfs(prinst, OFS_PARM0); @@ -1252,6 +1359,9 @@ static void PF_cs_runplayerphysics (progfuncs_t *prinst, struct globalvars_s *pr int msecs; extern vec3_t player_mins; extern vec3_t player_maxs; + + if (!cl.worldmodel) + return; //urm.. /* int sequence; // just for debugging prints @@ -1307,12 +1417,18 @@ typedef struct { pmove.sequence = *csqcg.clientcommandframe; pmove.pm_type = PM_NORMAL; + pmove.jump_msec = 0;//(cls.z_ext & Z_EXT_PM_TYPE) ? 0 : from->jump_msec; + if (csqcg.pmove_jump_held) + pmove.jump_held = *csqcg.pmove_jump_held; + if (csqcg.pmove_waterjumptime) + pmove.waterjumptime = *csqcg.pmove_waterjumptime; + //set up the movement command msecs = *csqcg.input_timelength*1000 + 0.5f; //precision inaccuracies. :( - pmove.angles[0] = ANGLE2SHORT(csqcg.input_angles[0]); - pmove.angles[1] = ANGLE2SHORT(csqcg.input_angles[1]); - pmove.angles[2] = ANGLE2SHORT(csqcg.input_angles[2]); + pmove.cmd.angles[0] = ANGLE2SHORT(csqcg.input_angles[0]); + pmove.cmd.angles[1] = ANGLE2SHORT(csqcg.input_angles[1]); + pmove.cmd.angles[2] = ANGLE2SHORT(csqcg.input_angles[2]); pmove.cmd.forwardmove = csqcg.input_movevalues[0]; pmove.cmd.sidemove = csqcg.input_movevalues[1]; pmove.cmd.upmove = csqcg.input_movevalues[2]; @@ -1333,7 +1449,10 @@ typedef struct { PM_PlayerMove(1); } - + if (csqcg.pmove_jump_held) + *csqcg.pmove_jump_held = pmove.jump_held; + if (csqcg.pmove_waterjumptime) + *csqcg.pmove_waterjumptime = pmove.waterjumptime; VectorCopy(pmove.origin, csqcg.pmove_org); VectorCopy(pmove.velocity, csqcg.pmove_vel); } @@ -1442,7 +1561,7 @@ void PF_cs_sound(progfuncs_t *prinst, struct globalvars_s *pr_globals) entity = (csqcedict_t*)G_EDICT(prinst, OFS_PARM0); channel = G_FLOAT(OFS_PARM1); sample = PR_GetStringOfs(prinst, OFS_PARM2); - volume = G_FLOAT(OFS_PARM3) * 255; + volume = G_FLOAT(OFS_PARM3); attenuation = G_FLOAT(OFS_PARM4); sfx = S_PrecacheSound(sample); @@ -1801,6 +1920,116 @@ static void PF_cl_te_customflash (progfuncs_t *prinst, struct globalvars_s *pr_g dl->color[2] = colour[2]*0.5f; } +static void PF_cl_te_bloodshower (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ +} +static void PF_cl_te_particlecube (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + float *minb = G_VECTOR(OFS_PARM0); + float *maxb = G_VECTOR(OFS_PARM1); + float *vel = G_VECTOR(OFS_PARM2); + float howmany = G_FLOAT(OFS_PARM3); + float color = G_FLOAT(OFS_PARM4); + float gravity = G_FLOAT(OFS_PARM5); + float jitter = G_FLOAT(OFS_PARM6); + + P_RunParticleCube(minb, maxb, vel, howmany, color, gravity, jitter); +} +static void PF_cl_te_spark (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ +} +static void PF_cl_te_smallflash (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ +} +static void PF_cl_te_explosion2 (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ +} +static void PF_cl_te_lightning1 (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + csqcedict_t *ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM0); + float *start = G_VECTOR(OFS_PARM1); + float *end = G_VECTOR(OFS_PARM1); + + CL_AddBeam(0, ent->entnum+MAX_EDICTS, start, end); +} +static void PF_cl_te_lightning2 (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + csqcedict_t *ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM0); + float *start = G_VECTOR(OFS_PARM1); + float *end = G_VECTOR(OFS_PARM1); + + CL_AddBeam(1, ent->entnum+MAX_EDICTS, start, end); +} +static void PF_cl_te_lightning3 (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + csqcedict_t *ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM0); + float *start = G_VECTOR(OFS_PARM1); + float *end = G_VECTOR(OFS_PARM1); + + CL_AddBeam(2, ent->entnum+MAX_EDICTS, start, end); +} +static void PF_cl_te_beam (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + csqcedict_t *ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM0); + float *start = G_VECTOR(OFS_PARM1); + float *end = G_VECTOR(OFS_PARM1); + + CL_AddBeam(5, ent->entnum+MAX_EDICTS, start, end); +} +static void PF_cl_te_plasmaburn (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ +} +static void PF_cl_te_explosionrgb (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + float *org = G_VECTOR(OFS_PARM0); + float *colour = G_VECTOR(OFS_PARM1); + + dlight_t *dl; + extern cvar_t r_explosionlight; + extern sfx_t *cl_sfx_r_exp3; + + P_ParticleExplosion (org); + + // light + if (r_explosionlight.value) + { + dl = CL_AllocDlight (0); + VectorCopy (org, dl->origin); + dl->radius = 150 + bound(0, r_explosionlight.value, 1)*200; + dl->die = cl.time + 0.5; + dl->decay = 300; + + dl->color[0] = 0.4f*colour[0]; + dl->color[1] = 0.4f*colour[1]; + dl->color[2] = 0.4f*colour[2]; + dl->channelfade[0] = 0; + dl->channelfade[1] = 0; + dl->channelfade[2] = 0; + } + + S_StartSound (-2, 0, cl_sfx_r_exp3, org, 1, 1); +} +static void PF_cl_te_particlerain (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + float *min = G_VECTOR(OFS_PARM0); + float *max = G_VECTOR(OFS_PARM1); + float *vel = G_VECTOR(OFS_PARM2); + float howmany = G_FLOAT(OFS_PARM3); + float colour = G_FLOAT(OFS_PARM4); + + P_RunParticleWeather(min, max, vel, howmany, colour, "rain"); +} +static void PF_cl_te_particlesnow (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + float *min = G_VECTOR(OFS_PARM0); + float *max = G_VECTOR(OFS_PARM1); + float *vel = G_VECTOR(OFS_PARM2); + float howmany = G_FLOAT(OFS_PARM3); + float colour = G_FLOAT(OFS_PARM4); + + P_RunParticleWeather(min, max, vel, howmany, colour, "snow"); +} + void CSQC_RunThreads(void) { csqctreadstate_t *state = csqcthreads, *next; @@ -1866,7 +2095,7 @@ void PF_cs_droptofloor (progfuncs_t *prinst, struct globalvars_s *pr_globals) else { VectorCopy (trace.endpos, ent->v->origin); - SV_LinkEdict (ent, false); + CL_CS_LinkEdict (ent, false); ent->v->flags = (int)ent->v->flags | FL_ONGROUND; ent->v->groundentity = EDICT_TO_PROG(prinst, trace.ent); G_FLOAT(OFS_RETURN) = 1; @@ -1881,25 +2110,12 @@ static void PF_cs_copyentity (progfuncs_t *prinst, struct globalvars_s *pr_globa out = (csqcedict_t*)G_EDICT(prinst, OFS_PARM1); memcpy(out->v, in->v, csqcentsize); + + CL_CS_LinkEdict (out, false); } //these are the builtins that still need to be added. #define PF_cs_tracetoss PF_Fixme -#define PF_cs_makestatic PF_Fixme -#define PF_cl_te_bloodshower PF_Fixme -#define PF_cl_te_particlecube PF_Fixme -#define PF_cl_te_spark PF_Fixme -#define PF_cl_te_smallflash PF_Fixme -#define PF_cl_te_explosion2 PF_Fixme -#define PF_cl_te_lightning1 PF_Fixme -#define PF_cl_te_lightning2 PF_Fixme -#define PF_cl_te_lightning3 PF_Fixme -#define PF_cl_te_beam PF_Fixme -#define PF_cl_te_plasmaburn PF_Fixme -#define PF_cl_te_explosionrgb PF_Fixme -#define PF_cl_te_particlerain PF_Fixme -#define PF_cl_te_particlesnow PF_Fixme -#define PF_cs_gettagindex PF_Fixme #define PF_cs_gettaginfo PF_Fixme #define PS_cs_setattachment PF_Fixme #define PF_cs_break PF_Fixme @@ -1928,6 +2144,127 @@ static void PF_Stub (progfuncs_t *prinst, struct globalvars_s *pr_globals) Con_Printf("Obsolete csqc builtin (%i) executed\n", prinst->lastcalledbuiltinnumber); } +void PF_rotatevectorsbytag (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + csqcedict_t *ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM0); + int tagnum = G_FLOAT(OFS_PARM1); + + float *srcorg = ent->v->origin; + int modelindex = ent->v->modelindex; + int frame1 = ent->v->frame; + int frame2 = ent->v->frame2; + float lerp = ent->v->lerpfrac; + float frame1time = ent->v->frame1time; + float frame2time = ent->v->frame2time; + + float *retorg = G_VECTOR(OFS_RETURN); + + model_t *mod = CSQC_GetModelForIndex(modelindex); + float transforms[12]; + float src[12]; + float dest[12]; + int i; + + if (Mod_GetTag) + if (Mod_GetTag(mod, tagnum, frame1, frame2, lerp, frame1time, frame2time, transforms)) + { +// VectorNegate(transforms+0, transforms+0); +// VectorNegate(transforms+4, transforms+4); +// VectorNegate(transforms+8, transforms+8); + + VectorCopy(csqcg.forward, src+0); + VectorNegate(csqcg.right, src+4); + VectorCopy(csqcg.up, src+8); + + R_ConcatRotationsPad((void*)src, (void*)transforms, (void*)dest); + + VectorCopy(dest+0, csqcg.forward); + VectorNegate(dest+4, csqcg.right); + VectorCopy(dest+8, csqcg.up); + + VectorCopy(srcorg, retorg); + for (i = 0 ; i < 3 ; i++) + { + retorg[0] += transforms[i*4+3]*src[4*i+0]; + retorg[1] += transforms[i*4+3]*src[4*i+1]; + retorg[2] += transforms[i*4+3]*src[4*i+2]; + } + return; + } + + VectorCopy(srcorg, retorg); +} +static void PF_cs_gettagindex (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + csqcedict_t *ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM0); + char *tagname = PR_GetStringOfs(prinst, OFS_PARM1); + + model_t *mod = CSQC_GetModelForIndex(ent->v->modelindex); + if (Mod_TagNumForName) + G_FLOAT(OFS_RETURN) = Mod_TagNumForName(mod, tagname); + else + G_FLOAT(OFS_RETURN) = 0; +} +static void PF_rotatevectorsbyangles (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + float *ang = G_VECTOR(OFS_PARM0); + vec3_t src[3], trans[3], res[3]; + ang[0]*=-1; + AngleVectors(ang, trans[0], trans[1], trans[2]); + ang[0]*=-1; + VectorInverse(trans[1]); + + VectorCopy(csqcg.forward, src[0]); + VectorNegate(csqcg.right, src[1]); + VectorCopy(csqcg.up, src[2]); + + R_ConcatRotations(trans, src, res); + + VectorCopy(res[0], csqcg.forward); + VectorNegate(res[1], csqcg.right); + VectorCopy(res[2], csqcg.up); +} +static void PF_rotatevectorsbymatrix (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + vec3_t src[3], trans[3], res[3]; + + VectorCopy(G_VECTOR(OFS_PARM0), src[0]); + VectorNegate(G_VECTOR(OFS_PARM1), src[1]); + VectorCopy(G_VECTOR(OFS_PARM2), src[2]); + + VectorCopy(csqcg.forward, src[0]); + VectorNegate(csqcg.right, src[1]); + VectorCopy(csqcg.up, src[2]); + + R_ConcatRotations(src, trans, res); + + VectorCopy(res[0], csqcg.forward); + VectorNegate(res[1], csqcg.right); + VectorCopy(res[2], csqcg.up); +} +static void PF_skinforname (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + int modelindex = G_FLOAT(OFS_PARM0); + char *str = PF_VarString(prinst, 1, pr_globals); + model_t *mod = CSQC_GetModelForIndex(modelindex); + + + if (Mod_SkinForName) + G_FLOAT(OFS_RETURN) = Mod_SkinForName(mod, str); + else + G_FLOAT(OFS_RETURN) = -1; +} +static void PF_shaderforname (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + char *str = PF_VarString(prinst, 0, pr_globals); +#ifdef Q3SHADERS + G_INT(OFS_RETURN) = R_RegisterSkin(str); +#else + G_INT(OFS_RETURN) = 0; +#endif +} + + #define PF_FixTen PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme //prefixes: @@ -2158,7 +2495,7 @@ PF_ReadAngle, // #??? float() readangle (EXT_CSQC) PF_ReadString, // #??? string() readstring (EXT_CSQC) PF_ReadFloat, // #??? string() readfloat (EXT_CSQC) PF_WasFreed, // #??? float(entity) wasfreed (EXT_CSQC) (should be availabe on server too) -PF_Fixme, +PF_cs_trailparticles, // #??? void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC), //180 PF_FixTen, @@ -2201,14 +2538,24 @@ PF_str2chr, // #222 float(string str, float index) str2chr (FTE_STRINGS) PF_chr2str, // #223 string(float chr, ...) chr2str (FTE_STRINGS) PF_strconv, // #224 string(float ccase, float redalpha, float redchars, string str, ...) strconv (FTE_STRINGS) -PF_infoadd, // #225 string(string old, string key, string value) infoadd -PF_infoget, // #226 string(string info, string key) infoget -PF_strncmp, // #227 float(string s1, string s2, float len) strncmp (FTE_STRINGS) -PF_strcasecmp, // #228 float(string s1, string s2) strcasecmp (FTE_STRINGS) -PF_strncasecmp, // #229 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS) +PF_strpad, // #225 string(float ccase, float redalpha, float redchars, string str, ...) strconv (FTE_STRINGS) +PF_infoadd, // #226 string(string old, string key, string value) infoadd +PF_infoget, // #227 string(string info, string key) infoget +PF_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS) +PF_strcasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS) //230 -PF_FixTen, +PF_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS) +PF_Fixme, // #231 clientstat +PF_Fixme, // #232 runclientphys +PF_Fixme, // #233 float(entity ent) isbackbuffered +PF_rotatevectorsbytag, // #234 + +PF_rotatevectorsbyangles, // #235 +PF_rotatevectorsbymatrix, // #236 +PF_skinforname, // #237 +PF_shaderforname, // #238 +PF_Fixme, // #239 //240 PF_FixTen, @@ -2333,6 +2680,15 @@ PF_Fixme, // #459 //460 PF_FixTen, + +//470 +PF_FixTen, +//480 +PF_FixTen, +//490 +PF_FixTen, +//500 +PF_FixTen, }; static int csqc_numbuiltins = sizeof(csqc_builtins)/sizeof(csqc_builtins[0]); @@ -2411,10 +2767,12 @@ qbyte *CSQC_PRLoadFile (char *path, void *buffer, int bufsize) //pretend it doesn't file = COM_LoadStackFile(path, buffer, bufsize); +#ifndef _DEBUG if (!cls.demoplayback) //allow any csqc when playing a demo if (!strcmp(path, "csprogs.dat")) //Fail to load any csprogs who's checksum doesn't match. if (Com_BlockChecksum(buffer, com_filesize) != csqcchecksum) return NULL; +#endif return file; } @@ -2468,14 +2826,14 @@ qboolean CSQC_Init (unsigned int checksum) csqcprogparms.sv_edicts = (edict_t **)&csqc_edicts; csqcprogparms.sv_num_edicts = &num_csqc_edicts; - csqcprogparms.useeditor = NULL;//sorry... QCEditor;//void (*useeditor) (char *filename, int line, int nump, char **parms); + csqcprogparms.useeditor = QCEditor;//void (*useeditor) (char *filename, int line, int nump, char **parms); csqctime = Sys_DoubleTime(); if (!csqcprogs) { in_sensitivityscale = 1; csqcprogs = InitProgs(&csqcprogparms); - PR_Configure(csqcprogs, -1, 1); + PR_Configure(csqcprogs, -1, 16); CSQC_InitFields(); //let the qclib know the field order that the engine needs. @@ -2493,7 +2851,7 @@ qboolean CSQC_Init (unsigned int checksum) PF_InitTempStrings(csqcprogs); - memset(csqcent, 0, sizeof(csqcent)); + memset(csqcent, 0, sizeof(*csqcent)*maxcsqcentities); csqcentsize = PR_InitEnts(csqcprogs, pr_csmaxedicts.value); @@ -2616,6 +2974,41 @@ qboolean CSQC_CenterPrint(char *cmd) //this protocol allows up to 32767 edicts. #ifdef PEXT_CSQC + +int CSQC_StartSound(int entnum, int channel, char *soundname, vec3_t pos, float vol, float attenuation) +{ + void *pr_globals; + char *str; + csqcedict_t *ent; + + if (!csqcprogs || !csqcg.serversound) + return false; + + if (entnum >= maxcsqcentities) + { + maxcsqcentities = entnum+64; + csqcent = BZ_Realloc(csqcent, sizeof(*csqcent)*maxcsqcentities); + } + ent = csqcent[entnum]; + if (!ent) + return false; + + pr_globals = PR_globals(csqcprogs, PR_CURRENT); + + str = PF_TempStr(csqcprogs); + Q_strncpyz(str, soundname, MAXTEMPBUFFERLEN); + + *csqcg.self = EDICT_TO_PROG(csqcprogs, (void*)ent); + G_FLOAT(OFS_PARM0) = channel; + G_INT(OFS_PARM1) = PR_SetString(csqcprogs, str); + VectorCopy(pos, G_VECTOR(OFS_PARM2)); + G_FLOAT(OFS_PARM3) = vol; + G_FLOAT(OFS_PARM4) = attenuation; + + PR_ExecuteProgram(csqcprogs, csqcg.serversound); + return G_FLOAT(OFS_RETURN); +} + void CSQC_ParseEntities(void) { csqcedict_t *ent; @@ -2640,7 +3033,7 @@ void CSQC_ParseEntities(void) for(;;) { entnum = MSG_ReadShort(); - if (!entnum) + if (!entnum || msg_badread) break; if (entnum & 0x8000) { //remove @@ -2649,8 +3042,11 @@ void CSQC_ParseEntities(void) if (!entnum) Host_EndGame("CSQC cannot remove world!\n"); - if (entnum >= MAX_EDICTS) - Host_EndGame("CSQC recieved too many edicts!\n"); + if (entnum >= maxcsqcentities) + { + maxcsqcentities = entnum+64; + csqcent = BZ_Realloc(csqcent, sizeof(*csqcent)*maxcsqcentities); + } if (cl_csqcdebug.value) Con_Printf("Remove %i\n", entnum); @@ -2666,8 +3062,11 @@ void CSQC_ParseEntities(void) } else { - if (entnum >= MAX_EDICTS) - Host_EndGame("CSQC recieved too many edicts!\n"); + if (entnum >= maxcsqcentities) + { + maxcsqcentities = entnum+64; + csqcent = BZ_Realloc(csqcent, sizeof(*csqcent)*maxcsqcentities); + } if (cl.csqcdebug) { diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index 3db5cf035..c3b0c57d0 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -4,6 +4,9 @@ #ifdef RGLQUAKE #include "glquake.h" +#ifdef Q3SHADERS +#include "shader.h" +#endif #endif int MP_TranslateFTEtoDPCodes(int code); @@ -384,20 +387,35 @@ void PF_CL_drawstring (progfuncs_t *prinst, struct globalvars_s *pr_globals) pos[0] += size[0]; } } +#ifdef Q3SHADERS +void GLDraw_ShaderPic (int x, int y, int width, int height, shader_t *pic, float r, float g, float b, float a); +#endif //float drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag) = #456; void PF_CL_drawpic (progfuncs_t *prinst, struct globalvars_s *pr_globals) { float *pos = G_VECTOR(OFS_PARM0); char *picname = PR_GetStringOfs(prinst, OFS_PARM1); - mpic_t *p = Draw_SafeCachePic(picname); float *size = G_VECTOR(OFS_PARM2); float *rgb = G_VECTOR(OFS_PARM3); float alpha = G_FLOAT(OFS_PARM4); float flag = G_FLOAT(OFS_PARM5); + mpic_t *p; + #ifdef RGLQUAKE if (qrenderer == QR_OPENGL) { +#ifdef Q3SHADERS + shader_t *s; + + s = R_RegisterCustom(picname, NULL); + if (s) + { + GLDraw_ShaderPic(pos[0], pos[1], size[0], size[1], s, rgb[0], rgb[1], rgb[2], alpha); + return; + } +#endif + if (flag == 1) //add qglBlendFunc(GL_SRC_ALPHA, GL_ONE); else if(flag == 2) //modulate @@ -409,6 +427,8 @@ void PF_CL_drawpic (progfuncs_t *prinst, struct globalvars_s *pr_globals) } #endif + p = Draw_SafeCachePic(picname); + if (Draw_ImageColours) Draw_ImageColours(rgb[0], rgb[1], rgb[2], alpha); if (Draw_Image) diff --git a/engine/client/r_partset.c b/engine/client/r_partset.c index 6bde8a42c..6b8bfa218 100644 --- a/engine/client/r_partset.c +++ b/engine/client/r_partset.c @@ -867,11 +867,44 @@ char *particle_set_spikeset = " blend add\n" " areaspread 0\n" " areaspreadvert 0\n" +"}\n" + +//the default svc_particle effect. +"r_part pe_default\n" +"{\n" +" texture \"particles/quake\"\n" +" count 1\n" +" scale 4\n" +" veladd 15\n" +" alpha 1\n" +" die 0.4\n" +" alphachange 0\n" +" diesubrand 0.4\n" +" gravity 40\n" +" areaspread 8\n" +" areaspreadvert 8\n" +" spawnmode box\n" "}\n"; + + + +/////////////////////////////////////////////////////////////// + + + + + + + + + + + char *particle_set_highfps = //submitted by 'ShadowWalker' + //fixme: replace with something more effective "r_part t_gib\n" "{\n" " texture \"particles/bloodtrail\"\n" @@ -1122,7 +1155,25 @@ char *particle_set_highfps = //submitted by 'ShadowWalker' " areaspreadvert 0\n" "}\n"; -char *particle_set_faithful = + + + + + + +///////////////////////////////////////////////////////////////////// + + + + + + + + + + +char *particle_set_faithful = //Created from origional quake by TimeServ. + //The aim being to clone the old effects exactly. "r_part t_gib\n" "{\n" " texture \"particles/quake\"\n" diff --git a/engine/client/render.h b/engine/client/render.h index bfba7b706..44173e55a 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -255,6 +255,8 @@ void R_SetVrect (vrect_t *pvrect, vrect_t *pvrectin, int lineadj); void GLMod_Init (void); qboolean GLMod_GetTag(struct model_s *model, int tagnum, int frame, int frame2, float f2ness, float f1time, float f2time, float *result); int GLMod_TagNumForName(struct model_s *model, char *name); +int GLMod_SkinNumForName(struct model_s *model, char *name); + void GLMod_ClearAll (void); struct model_s *GLMod_ForName (char *name, qboolean crash); struct model_s *GLMod_FindName (char *name); diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 773cabcb3..767f8e8d1 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -102,7 +102,8 @@ cvar_t r_fullbrightSkins = {"r_fullbrightSkins", "1", NULL, CVAR_SEMICHEAT}; cvar_t r_fb_models = {"gl_fb_models", "1", NULL, CVAR_SEMICHEAT|CVAR_RENDERERLATCH}; //as it can highlight the gun a little... ooo nooo.... cvar_t r_fb_bmodels = {"gl_fb_bmodels", "1", NULL, CVAR_SEMICHEAT|CVAR_RENDERERLATCH}; //as it can highlight the gun a little... ooo nooo.... - +cvar_t r_shadow_bumpscale_basetexture = {"r_shadow_bumpscale_basetexture", "4"}; +cvar_t r_shadow_bumpscale_bumpmap = {"r_shadow_bumpscale_bumpmap", "10"}; cvar_t gl_nocolors = {"gl_nocolors","0"}; cvar_t gl_load24bit = {"gl_load24bit", "1"}; cvar_t vid_conwidth = {"vid_conwidth", "640", NULL, CVAR_ARCHIVE}; @@ -117,17 +118,21 @@ cvar_t gl_savecompressedtex = {"gl_savecompressedtex", "0"}; extern cvar_t gl_dither; extern cvar_t gl_maxdist; -#ifdef SPECULAR -cvar_t gl_specular = {"gl_specular", "0"}; -#endif cvar_t gl_detail = {"gl_detail", "0", NULL, CVAR_ARCHIVE}; cvar_t gl_detailscale = {"gl_detailscale", "5"}; cvar_t gl_overbright = {"gl_overbright", "0", NULL, CVAR_ARCHIVE}; cvar_t r_shadows = {"r_shadows", "0", NULL, CVAR_ARCHIVE|CVAR_RENDERERLATCH}; cvar_t r_shadow_realtime_world = {"r_shadow_realtime_world", "0", NULL, CVAR_CHEAT}; +cvar_t r_shadow_realtime_world_lightmaps = {"r_shadow_realtime_world_lightmaps", "0.8", NULL, CVAR_CHEAT}; cvar_t r_noaliasshadows = {"r_noaliasshadows", "0", NULL, CVAR_ARCHIVE}; cvar_t gl_maxshadowlights = {"gl_maxshadowlights", "2", NULL, CVAR_ARCHIVE}; cvar_t gl_bump = {"gl_bump", "0", NULL, CVAR_ARCHIVE|CVAR_RENDERERLATCH}; +cvar_t r_shadow_glsl_offsetmapping = {"r_shadow_glsl_offsetmapping", "0"}; +cvar_t r_shadow_glsl_offsetmapping_scale = {"r_shadow_glsl_offsetmapping_scale", "-0.04"}; +cvar_t r_shadow_glsl_offsetmapping_bias = {"r_shadow_glsl_offsetmapping_bias", "0.04"}; +#ifdef SPECULAR +cvar_t gl_specular = {"gl_specular", "0"}; +#endif cvar_t gl_lightmapmode = {"gl_lightmapmode", "", NULL, CVAR_ARCHIVE}; cvar_t gl_ati_truform = {"gl_ati_truform", "0"}; @@ -254,6 +259,8 @@ void GLRenderer_Init(void) Cvar_Register (&r_shadows, GLRENDEREROPTIONS); Cvar_Register (&r_noaliasshadows, GLRENDEREROPTIONS); Cvar_Register (&gl_maxshadowlights, GLRENDEREROPTIONS); + Cvar_Register (&r_shadow_bumpscale_basetexture, GLRENDEREROPTIONS); + Cvar_Register (&r_shadow_bumpscale_bumpmap, GLRENDEREROPTIONS); Cvar_Register (&gl_part_flame, GRAPHICALNICETIES); Cvar_Register (&gl_part_torch, GRAPHICALNICETIES); @@ -276,6 +283,10 @@ void GLRenderer_Init(void) Cvar_Register (&gl_smoothfont, GRAPHICALNICETIES); Cvar_Register (&gl_bump, GRAPHICALNICETIES); + Cvar_Register (&r_shadow_glsl_offsetmapping, GRAPHICALNICETIES); + Cvar_Register (&r_shadow_glsl_offsetmapping_scale, GRAPHICALNICETIES); + Cvar_Register (&r_shadow_glsl_offsetmapping_bias, GRAPHICALNICETIES); + Cvar_Register (&gl_contrast, GLRENDEREROPTIONS); #ifdef R_XFLIP Cvar_Register (&r_xflip, GLRENDEREROPTIONS); @@ -584,6 +595,7 @@ void (*Mod_NowLoadExternal) (void); void (*Mod_Think) (void); qboolean (*Mod_GetTag) (struct model_s *model, int tagnum, int frame, int frame2, float f2ness, float f1time, float f2time, float *transforms); int (*Mod_TagNumForName) (struct model_s *model, char *name); +int (*Mod_SkinForName) (struct model_s *model, char *name); @@ -698,6 +710,7 @@ rendererinfo_t dedicatedrendererinfo = { NULL, //Mod_GetTag NULL, //fixme: server will need this one at some point. + NULL, NULL, //VID_Init, NULL, //VID_DeInit, @@ -890,6 +903,7 @@ rendererinfo_t openglrendererinfo = { GLMod_GetTag, GLMod_TagNumForName, + GLMod_SkinNumForName, GLVID_Init, GLVID_DeInit, @@ -1268,6 +1282,7 @@ void R_SetRenderer(int wanted) Mod_GetTag = ri->Mod_GetTag; Mod_TagNumForName = ri->Mod_TagNumForName; + Mod_SkinForName = ri->Mod_SkinForName; SCR_UpdateScreen = ri->SCR_UpdateScreen; } @@ -1582,7 +1597,7 @@ TRACE(("dbg: R_ApplyRenderer: reloading ALL models\n")); if (!cl.model_precache[i]) { - Con_Printf ("\nThe required model file '%s' could not be found or downloaded.\n\n" + Con_Printf ("\nThe required model file '%s' could not be found.\n\n" , cl.model_name[i]); Con_Printf ("You may need to download or purchase a client " "pack in order to play on this server.\n\n"); @@ -1591,6 +1606,28 @@ TRACE(("dbg: R_ApplyRenderer: reloading ALL models\n")); return false; } } +#ifdef CSQC_DAT + for (i=1 ; inext) S_UpdateCard(sc); @@ -1340,7 +1351,7 @@ void S_ExtraUpdate (void) if (snd_noextraupdate.value) return; // don't pollute timings - S_UpdateCapture(); + S_RunCapture(); for (sc = sndcardinfo; sc; sc = sc->next) S_Update_(sc); diff --git a/engine/client/snd_linux.c b/engine/client/snd_linux.c index b56196923..365ea7302 100644 --- a/engine/client/snd_linux.c +++ b/engine/client/snd_linux.c @@ -272,8 +272,3 @@ static int OSS_InitCard(soundcardinfo_t *sc, int cardnum) int (*pOSS_InitCard) (soundcardinfo_t *sc, int cardnum) = &OSS_InitCard; - - -void S_UpdateCapture(void) -{ -} diff --git a/engine/client/sound.h b/engine/client/sound.h index d8ec718e8..d011935d9 100644 --- a/engine/client/sound.h +++ b/engine/client/sound.h @@ -145,8 +145,6 @@ void S_DoRestart (void); //plays streaming audio void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels, int width); -//tells the audio capture routines to grab a bit more and send it to voice chat server. -void S_UpdateCapture(void); void CLVC_Poll (void); void SNDVC_MicInput(qbyte *buffer, int samples, int freq, int width); diff --git a/engine/client/textedit.c b/engine/client/textedit.c index 5b41e8e6d..e39f052d0 100644 --- a/engine/client/textedit.c +++ b/engine/client/textedit.c @@ -307,10 +307,22 @@ void EditorOpenFile(char *name) firstblock->datalength = len; memcpy(firstblock->data, line, len); - if (svprogfuncs) - if (svprogfuncs->ToggleBreak(svprogfuncs, OpenEditorFile+strlen(com_gamedir)+1, i, 3)) + if (editprogfuncs) { - firstblock->flags |= FB_BREAK; + if (editprogfuncs->ToggleBreak(editprogfuncs, OpenEditorFile+strlen(com_gamedir)+1, i, 3)) + { + firstblock->flags |= FB_BREAK; + } + } + else + { + if (svprogfuncs) + { + if (svprogfuncs->ToggleBreak(svprogfuncs, OpenEditorFile+strlen(com_gamedir)+1, i, 3)) + { + firstblock->flags |= FB_BREAK; + } + } } i++; @@ -505,7 +517,6 @@ void Editor_Key(int key) case K_F9: { int f = 0; -#ifndef CLIENTONLY if (editprogfuncs) { if (editprogfuncs->ToggleBreak(editprogfuncs, OpenEditorFile+4, cursorlinenum, 2)) @@ -513,6 +524,14 @@ void Editor_Key(int key) else f |= 2; } +#ifndef CLIENTONLY + else if (svprogfuncs) + { + if (svprogfuncs->ToggleBreak(svprogfuncs, OpenEditorFile+4, cursorlinenum, 2)) + f |= 1; + else + f |= 2; + } #endif if (f & 1) @@ -926,7 +945,7 @@ void Editor_Draw(void) */ } -int QCLibEditor(char *filename, int line, int nump, char **parms) +int QCLibEditor(progfuncs_t *prfncs, char *filename, int line, int nump, char **parms) { if (editormodal || !developer.value) return line; //whoops @@ -958,6 +977,8 @@ int QCLibEditor(char *filename, int line, int nump, char **parms) return line; } + editprogfuncs = prfncs; + if (!strncmp(OpenEditorFile, "src/", 4)) { if (!editoractive || strcmp(OpenEditorFile+4, filename)) @@ -980,8 +1001,6 @@ int QCLibEditor(char *filename, int line, int nump, char **parms) } } - editprogfuncs = svprogfuncs; - for (cursorlinenum = 1, cursorblock = firstblock; cursorlinenum < line && cursorblock->next; cursorlinenum++) cursorblock=cursorblock->next; @@ -993,7 +1012,7 @@ int QCLibEditor(char *filename, int line, int nump, char **parms) while(editormodal && editoractive && editprogfuncs) { - key_dest = key_editor; +// key_dest = key_editor; scr_disabled_for_loading=false; SCR_UpdateScreen(); Sys_SendKeyEvents(); diff --git a/engine/client/valid.c b/engine/client/valid.c index 74e3447a4..e11261b5c 100644 --- a/engine/client/valid.c +++ b/engine/client/valid.c @@ -1,4 +1,422 @@ #include "quakedef.h" +#include + +typedef struct f_query_s +{ + char *query; + char *serverinfo; + char *c_userinfo[MAX_CLIENTS]; + qboolean c_exist[MAX_CLIENTS]; + + unsigned short crc; + double timestamp; +} +f_query_t; + +#define F_QUERIES_REMEMBERED 5 +f_query_t f_last_queries[F_QUERIES_REMEMBERED]; +int f_last_query_pos = 0; + +typedef struct f_modified_s { + char name[MAX_QPATH]; + qboolean ismodified; + struct f_modified_s *next; +} f_modified_t; + +f_modified_t *f_modified_list; +qboolean care_f_modified; +qboolean f_modified_particles; + + +cvar_t allow_f_version = {"allow_f_version", "1"}; +cvar_t allow_f_server = {"allow_f_server", "1"}; +cvar_t allow_f_modified = {"allow_f_modified", "1"}; +cvar_t allow_f_skins = {"allow_f_skins", "1"}; +cvar_t auth_validateclients = {"auth_validateclients", "1"}; + + +void CRC_AddBlock (unsigned short *crcvalue, qbyte *start, int count) +{ + while (count--) + CRC_ProcessByte(crcvalue, *start++); +} +unsigned short SCRC_GetQueryStateCrc(char *f_query_string) +{ + unsigned short crc; + int i; + char *tmp; + + CRC_Init(&crc); + + // add query + CRC_AddBlock(&crc, f_query_string, strlen(f_query_string)); + + // add snapshot of serverinfo + tmp = Info_ValueForKey(cl.serverinfo, "deathmatch"); + CRC_AddBlock(&crc, tmp, strlen(tmp)); + tmp = Info_ValueForKey(cl.serverinfo, "teamplay"); + CRC_AddBlock(&crc, tmp, strlen(tmp)); + tmp = Info_ValueForKey(cl.serverinfo, "hostname"); + CRC_AddBlock(&crc, tmp, strlen(tmp)); + tmp = Info_ValueForKey(cl.serverinfo, "*progs"); + CRC_AddBlock(&crc, tmp, strlen(tmp)); + tmp = Info_ValueForKey(cl.serverinfo, "map"); + CRC_AddBlock(&crc, tmp, strlen(tmp)); + tmp = Info_ValueForKey(cl.serverinfo, "spawn"); + CRC_AddBlock(&crc, tmp, strlen(tmp)); + tmp = Info_ValueForKey(cl.serverinfo, "watervis"); + CRC_AddBlock(&crc, tmp, strlen(tmp)); + tmp = Info_ValueForKey(cl.serverinfo, "fraglimit"); + CRC_AddBlock(&crc, tmp, strlen(tmp)); + tmp = Info_ValueForKey(cl.serverinfo, "*gamedir"); + CRC_AddBlock(&crc, tmp, strlen(tmp)); + tmp = Info_ValueForKey(cl.serverinfo, "timelimit"); + CRC_AddBlock(&crc, tmp, strlen(tmp)); + + // add snapshot of userinfo for every connected client + for (i=0; i < MAX_CLIENTS; i++) + if (cl.players[i].name[0]) + { + tmp = Info_ValueForKey(cl.players[i].userinfo, "name"); + CRC_AddBlock(&crc, tmp, strlen(tmp)); + tmp = Info_ValueForKey(cl.players[i].userinfo, "team"); + CRC_AddBlock(&crc, tmp, strlen(tmp)); + } + + // done + return crc; +} + +#if 1 + +#define SECURITY_INIT_BAD_CHECKSUM 1 +#define SECURITY_INIT_BAD_VERSION 2 +#define SECURITY_INIT_ERROR 3 +#define SECURITY_INIT_NOPROC 4 + +typedef struct signed_buffer_s { + qbyte *buf; + unsigned long size; +} signed_buffer_t; + +typedef signed_buffer_t *(*Security_Verify_Response_t) (int, unsigned char *); +typedef int (*Security_Init_t) (char *); +typedef signed_buffer_t *(*Security_Generate_Crc_t) (int); +typedef signed_buffer_t *(*Security_IsModelModified_t) (char *, int, qbyte *, int); +typedef void (*Security_Supported_Binaries_t) (void *); +typedef void (*Security_Shutdown_t) (void); + + +Security_Verify_Response_t Security_Verify_Response; +Security_Init_t Security_Init; +Security_Generate_Crc_t Security_Generate_Crc; +Security_IsModelModified_t Security_IsModelModified; +Security_Supported_Binaries_t Security_Supported_Binaries; +Security_Shutdown_t Security_Shutdown; + + +void *secmodule; + +void ValidationPrintVersion(char *f_query_string) +{ + f_query_t *this_query; + unsigned short query_crc; + unsigned long crc; + char answer; + char name[128]; + char sr[256]; + int i; + + switch(qrenderer) + { +#ifdef RGLQUAKE + case QR_OPENGL: + *sr = *""; + break; +#endif +#ifdef SWQUAKE + case QR_SOFTWARE: + strcpy(sr, (r_pixbytes==4?"32bpp":"8bpp")); + break; +#endif + default: + *sr = *""; + break; + } + if (Security_Generate_Crc && allow_f_version.value) + { + signed_buffer_t *resp; + query_crc = SCRC_GetQueryStateCrc(f_query_string); + + // + // remember this f_version + // + this_query = &f_last_queries[f_last_query_pos++ % F_QUERIES_REMEMBERED]; + this_query->timestamp = realtime; + this_query->crc = query_crc; + if (this_query->query) + BZ_Free(this_query->query); + this_query->query = BZ_Malloc(strlen(f_query_string)+1); + strcpy(this_query->query, f_query_string); + if (this_query->serverinfo) + BZ_Free(this_query->serverinfo); + this_query->serverinfo = BZ_Malloc(strlen(cl.serverinfo)+1); + strcpy(this_query->serverinfo, cl.serverinfo); + for (i=0; i < MAX_CLIENTS; i++) + { + if (this_query->c_userinfo[i]) + { + BZ_Free(this_query->c_userinfo[i]); + this_query->c_userinfo[i] = NULL; + } + this_query->c_exist[i] = false; + + if (cl.players[i].name[0]) + { + this_query->c_exist[i] = true; + this_query->c_userinfo[i] = BZ_Malloc(strlen(cl.players[i].userinfo)+1); + strcpy(this_query->c_userinfo[i], cl.players[i].userinfo); + } + } + + resp = Security_Generate_Crc(cl.playernum[0]); + + //now send the data. + +// SPipe_WriteChar(f_write, SECURE_CMD_GETVERSION); +// SPipe_WriteString(f_write, f_query_string); +// SPipe_WriteString(f_write, cl.serverinfo); +// SPipe_WriteString(f_write, cl.players[cl.playernum[0]].userinfo); + + // get answer +// SPipe_ReadChar(f_read, &answer); +// SPipe_ReadString(f_read, name, 64); +// SPipe_ReadUlong(f_read, &crc); +/* + if (answer == SECURE_ANSWER_OK) + { + // reply + Cbuf_AddText("say ", RESTRICT_LOCAL); + Cbuf_AddText(name, RESTRICT_LOCAL); + if (*sr) + Cbuf_AddText(va("/%s/%s", q_renderername, sr), RESTRICT_LOCAL);//extra info + else + Cbuf_AddText(va("/%s", q_renderername), RESTRICT_LOCAL);//extra info + Cbuf_AddText(" ", RESTRICT_LOCAL); + Cbuf_AddText(va("%04x", query_crc), RESTRICT_LOCAL); + Cbuf_AddText(va("%08x", crc), RESTRICT_LOCAL); + Cbuf_AddText("\n", RESTRICT_LOCAL); + return; + } +*/ + } + + if (*sr) + Cbuf_AddText (va("say "DISTRIBUTION"Quake v%4.3f-%i "PLATFORM"/%s/%s\n", VERSION, build_number(), q_renderername, sr), RESTRICT_RCON); + else + Cbuf_AddText (va("say "DISTRIBUTION"Quake v%4.3f-%i "PLATFORM"/%s\n", VERSION, build_number(), q_renderername), RESTRICT_RCON); +} +void Validation_FilesModified (void) +{ +} +void Validation_CheckIfResponse(char *text) +{ + //client name, version type(os-renderer where it matters, os/renderer where renderer doesn't), 12 char hex crc + int f_query_client; + int i; + char *crc; + char *versionstring; + + if (!Security_Verify_Response) + return; //valid or not, we can't check it. + + if (!auth_validateclients.value) + return; + + //do the parsing. + { + char *comp; + int namelen; + + for (crc = text + strlen(text) - 1; crc > text; crc--) + if ((unsigned)*crc > ' ') + break; + + //find the crc. + for (i = 0; i < 29; i++) + { + if (crc <= text) + return; //not enough chars. + if ((unsigned)crc[-1] <= ' ') + break; + crc--; + } + + //we now want 3 string seperated tokens, so the first starts at the fourth found ' ' + 1 + i = 7; + for (comp = crc-1; ; comp--) + { + if (comp < text) + return; + if (*comp == ' ') + { + i--; + if (!i) + break; + } + + } + + versionstring = comp+1; + if (comp <= text) + return; //not enough space for the 'name:' + if (*(comp-1) != ':') + return; //whoops. not a say. + + namelen = comp - text-1; + + for (f_query_client = 0; f_query_client < MAX_CLIENTS; f_query_client++) + { + if (strlen(cl.players[f_query_client].name) == namelen) + if (!strncmp(cl.players[f_query_client].name, text, namelen)) + break; + } + if (f_query_client == MAX_CLIENTS) + return; //looks like a validation, but it's not from a known client. + } + + //now do the validation + { + f_query_t *query = NULL; + int itemp; + char buffer[10]; + unsigned short query_crc = 0; + unsigned long user_crc = 0; + unsigned long auth_crc = 0; + char auth_answer; + + int slot; + signed_buffer_t *resp; + + //easy lame way to get the crc from hex. + Q_strncpyS(buffer, crc, 4); + buffer[4] = '\0'; + itemp = 0; + sscanf(buffer, "%x", &itemp); + query_crc = (unsigned long) itemp; + + Q_strncpyS(buffer, crc+4, 8); + buffer[8] = '\0'; + itemp = 0; + sscanf(buffer, "%x", &itemp); + user_crc = (unsigned long) itemp; + + // + // find that query + // +/* for (i=f_last_query_pos; i > f_last_query_pos-F_QUERIES_REMEMBERED; i--) + { + if (query_crc == f_last_queries[i % F_QUERIES_REMEMBERED].crc && + realtime - 5 < f_last_queries[i % F_QUERIES_REMEMBERED].timestamp) + { + query = &f_last_queries[i % F_QUERIES_REMEMBERED]; + } + } + + if (query == NULL) + return; // reply to unknown query + + if (!query->c_exist[f_query_client]) + return; // should never happen +*/ + resp = Security_Verify_Response(f_query_client, crc); + + if (resp && resp->size && *resp->buf) + Con_Printf("Authentication Successful.\n"); + else// if (!resp) + Con_Printf("^1^bAUTHENTICATION FAILED.\n"); + /* + typedef signed_buffer_t *(*Security_Verify_Response_t) (int, unsigned char *); + // write request + SPipe_WriteChar(f_write, SECURE_CMD_CHECKVERSION2); + SPipe_WriteString(f_write, query->query); + SPipe_WriteString(f_write, query->serverinfo); + SPipe_WriteString(f_write, query->c_userinfo[f_query_client]); + SPipe_WriteString(f_write, versionstring); + + // get answer + SPipe_ReadChar(f_read, &auth_answer); + SPipe_ReadUlong(f_read, &auth_crc); + + if (auth_answer == SECURE_ANSWER_YES && auth_crc == user_crc) + { + Con_Printf("Authentication Successful.\n"); + } + else + Con_Printf("^1^bAUTHENTICATION FAILED.\n"); + */ + } +} + +void InitValidation(void) +{ + Cvar_Register(&allow_f_version, "Authentication"); + Cvar_Register(&allow_f_server, "Authentication"); + Cvar_Register(&allow_f_modified, "Authentication"); + Cvar_Register(&allow_f_skins, "Authentication"); + + secmodule = LoadLibrary("fteqw-security.dll"); + if (secmodule) + { + Security_Verify_Response = (void*)GetProcAddress(secmodule, "Security_Verify_Response"); + Security_Init = (void*)GetProcAddress(secmodule, "Security_Init"); + Security_Generate_Crc = (void*)GetProcAddress(secmodule, "Security_Generate_Crc"); + Security_IsModelModified = (void*)GetProcAddress(secmodule, "Security_IsModelModified"); + Security_Supported_Binaries = (void*)GetProcAddress(secmodule, "Security_Supported_Binaries"); + Security_Shutdown = (void*)GetProcAddress(secmodule, "Security_Shutdown"); + } + + if (Security_Init) + { + switch(Security_Init(va("%s %.2f %i", DISTRIBUTION, VERSION, build_number()))) + { + case SECURITY_INIT_BAD_CHECKSUM: + Con_Printf("Checksum failed. Security module does not support this build. Go upgrade it.\n"); + break; + case SECURITY_INIT_BAD_VERSION: + Con_Printf("Version failed. Security module does not support this version. Go upgrade.\n"); + break; + case SECURITY_INIT_ERROR: + Con_Printf("'Generic' security error. Stop hacking.\n"); + break; + case SECURITY_INIT_NOPROC: + Con_Printf("/proc/* does not exist. You will need to upgrade your kernel.\n"); + break; + case 0: + Cvar_Register(&auth_validateclients, "Authentication"); + return; + } + Security_Verify_Response = NULL; + Security_Init = NULL; + Security_Generate_Crc = NULL; + Security_IsModelModified = NULL; + Security_Supported_Binaries = NULL; + Security_Shutdown = NULL; + FreeLibrary(secmodule); + } +} + +void Validation_IncludeFile(char *filename, char *file, int filelen) +{ +} + +qboolean f_modified_particles; +qboolean care_f_modified; + + + +#else + #ifdef RGLQUAKE #include "glquake.h" //overkill @@ -223,59 +641,6 @@ int SPipe_WriteString(qpipe write_pipe, char *string) return true; } -void CRC_AddBlock (unsigned short *crcvalue, qbyte *start, int count) -{ - while (count--) - CRC_ProcessByte(crcvalue, *start++); -} - -unsigned short SCRC_GetQueryStateCrc(char *f_query_string) -{ - unsigned short crc; - int i; - char *tmp; - - CRC_Init(&crc); - - // add query - CRC_AddBlock(&crc, f_query_string, strlen(f_query_string)); - - // add snapshot of serverinfo - tmp = Info_ValueForKey(cl.serverinfo, "deathmatch"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); - tmp = Info_ValueForKey(cl.serverinfo, "teamplay"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); - tmp = Info_ValueForKey(cl.serverinfo, "hostname"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); - tmp = Info_ValueForKey(cl.serverinfo, "*progs"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); - tmp = Info_ValueForKey(cl.serverinfo, "map"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); - tmp = Info_ValueForKey(cl.serverinfo, "spawn"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); - tmp = Info_ValueForKey(cl.serverinfo, "watervis"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); - tmp = Info_ValueForKey(cl.serverinfo, "fraglimit"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); - tmp = Info_ValueForKey(cl.serverinfo, "*gamedir"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); - tmp = Info_ValueForKey(cl.serverinfo, "timelimit"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); - - // add snapshot of userinfo for every connected client - for (i=0; i < MAX_CLIENTS; i++) - if (cl.players[i].name[0]) - { - tmp = Info_ValueForKey(cl.players[i].userinfo, "name"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); - tmp = Info_ValueForKey(cl.players[i].userinfo, "team"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); - } - - // done - return crc; -} - void InitValidation(void) { char *read, *write; @@ -397,18 +762,6 @@ void Validation_IncludeFile(char *filename, char *file, int filelen) } } -void Validation_FlushFileList(void) -{ - f_modified_t *fm; - while(f_modified_list) - { - fm = f_modified_list->next; - - Z_Free(f_modified_list); - f_modified_list = fm; - } -} - void ValidationPrintVersion(char *f_query_string) { f_query_t *this_query; @@ -505,27 +858,6 @@ void ValidationPrintVersion(char *f_query_string) Cbuf_AddText (va("say "DISTRIBUTION"Quake v%4.3f-%i "PLATFORM"/%s\n", VERSION, build_number(), q_renderername), RESTRICT_RCON); } -void Validation_Skins(void) -{ - extern cvar_t r_fullbrightSkins, r_fb_models; - int percent = r_fullbrightSkins.value*100; - if (percent < 0) - percent = 0; - if (percent > cls.allow_fbskins*100) - percent = cls.allow_fbskins*100; - if (percent) - Cbuf_AddText(va("say all player skins %i%% fullbright%s\n", percent, r_fb_models.value?" (plus luma)":""), RESTRICT_LOCAL); - else if (r_fb_models.value) - Cbuf_AddText("say luma textures only\n", RESTRICT_LOCAL); - else - Cbuf_AddText("say Only cheaters use full bright skins\n", RESTRICT_LOCAL); -} - -void Validation_Server(void) -{ - Cbuf_AddText(va("say server is %s\n", NET_AdrToString(cls.netchan.remote_address)), RESTRICT_LOCAL); -} - void Validation_CheckIfResponse(char *text) { //client name, version type(os-renderer where it matters, os/renderer where renderer doesn't), 12 char hex crc @@ -654,3 +986,39 @@ void Validation_CheckIfResponse(char *text) Con_Printf("^1^bAUTHENTICATION FAILED.\n"); } } + + +#endif + +void Validation_FlushFileList(void) +{ + f_modified_t *fm; + while(f_modified_list) + { + fm = f_modified_list->next; + + Z_Free(f_modified_list); + f_modified_list = fm; + } +} + +void Validation_Server(void) +{ + Cbuf_AddText(va("say server is %s\n", NET_AdrToString(cls.netchan.remote_address)), RESTRICT_LOCAL); +} + +void Validation_Skins(void) +{ + extern cvar_t r_fullbrightSkins, r_fb_models; + int percent = r_fullbrightSkins.value*100; + if (percent < 0) + percent = 0; + if (percent > cls.allow_fbskins*100) + percent = cls.allow_fbskins*100; + if (percent) + Cbuf_AddText(va("say all player skins %i%% fullbright%s\n", percent, r_fb_models.value?" (plus luma)":""), RESTRICT_LOCAL); + else if (r_fb_models.value) + Cbuf_AddText("say luma textures only\n", RESTRICT_LOCAL); + else + Cbuf_AddText("say Only cheaters use full bright skins\n", RESTRICT_LOCAL); +} diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index 4765ad543..28f162afc 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -99,6 +99,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define SP2MODELS //quake2 sprite models #define MD2MODELS //quake2 alias models #define MD3MODELS //quake3 alias models + #define MD5MODELS //doom3 models #define ZYMOTICMODELS //zymotic skeletal models. #define HUFFNETWORK //huffman network compression #define HALFLIFEMODELS //halflife model support (experimental) diff --git a/engine/common/cmd.c b/engine/common/cmd.c index 4da274a1d..fae43656f 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -1156,7 +1156,7 @@ void Cmd_TokenizeString (char *text, qboolean expandmacros, qboolean qctokenize) while (1) { // skip whitespace up to a /n - while (*text && *text <= ' ' && *text != '\n') + while (*text && (unsigned)*text <= ' ' && *text != '\n') { text++; } diff --git a/engine/common/common.c b/engine/common/common.c index e59dbca8b..50fa04d46 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -1389,7 +1389,10 @@ void COM_StripExtension (char *in, char *out) while(*s != '/' && s != out) { if (*s == '.') + { *s = 0; + break; + } s--; } @@ -1688,7 +1691,7 @@ char *COM_StringParse (char *data, qboolean expandmacros, qboolean qctokenize) // skip whitespace skipwhite: - while ( (c = *data), c <= ' ' && c != '\n') + while ( (c = *data), (unsigned)c <= ' ' && c != '\n') { if (c == 0) return NULL; // end of file; @@ -1824,7 +1827,7 @@ skipwhite: data++; len++; c = *data; - } while (c>32 && !(qctokenize && (c == '\n' || c == '{' || c == '}' || c == ')' || c == '(' || c == ']' || c == '[' || c == '\'' || c == ':' || c == ',' || c == ';'))); + } while ((unsigned)c>32 && !(qctokenize && (c == '\n' || c == '{' || c == '}' || c == ')' || c == '(' || c == ']' || c == '[' || c == '\'' || c == ':' || c == ',' || c == ';'))); com_token[len] = 0; diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index 41310e3e4..d7075a86e 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -27,6 +27,7 @@ extern qboolean r_usinglits; #endif +extern cvar_t r_shadow_bumpscale_basetexture; //these are in model.c (or gl_model.c) void GLMod_LoadVertexes (lump_t *l); @@ -1115,7 +1116,7 @@ void *Mod_LoadWall(char *name) oin = (qbyte *)wal+wal->offsets[0]; for (j = 0; j < wal->width*wal->height; j++) in[j] = (d_q28to24table[oin[j]*3+0] + d_q28to24table[oin[j]*3+1] + d_q28to24table[oin[j]*3+2])/3; - tex->gl_texturenumbumpmap = GL_LoadTexture8Bump (va("%s_bump", wal->name), tex->width, tex->height, in, true); + tex->gl_texturenumbumpmap = GL_LoadTexture8Bump (va("%s_bump", wal->name), tex->width, tex->height, in, true, r_shadow_bumpscale_basetexture.value); texture_mode = GL_LINEAR; } else diff --git a/engine/common/mathlib.c b/engine/common/mathlib.c index 4a236105e..265e334b4 100644 --- a/engine/common/mathlib.c +++ b/engine/common/mathlib.c @@ -513,6 +513,29 @@ void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]) in1[2][2] * in2[2][3] + in1[2][3]; } +void R_ConcatRotationsPad (float in1[3][4], float in2[3][4], float out[3][4]) +{ + out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + + in1[0][2] * in2[2][0]; + out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + + in1[0][2] * in2[2][1]; + out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + + in1[0][2] * in2[2][2]; + + out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + + in1[1][2] * in2[2][0]; + out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + + in1[1][2] * in2[2][1]; + out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + + in1[1][2] * in2[2][2]; + + out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + + in1[2][2] * in2[2][0]; + out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + + in1[2][2] * in2[2][1]; + out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + + in1[2][2] * in2[2][2]; +} /* =================== @@ -804,9 +827,9 @@ void Matrix4_Transform4(float *matrix, float *vector, float *product) void Matrix4_Transform3(float *matrix, float *vector, float *product) { - product[0] = matrix[0]*vector[0] + matrix[4]*vector[1] + matrix[8]*vector[2] + matrix[12]*vector[3]; - product[1] = matrix[1]*vector[0] + matrix[5]*vector[1] + matrix[9]*vector[2] + matrix[13]*vector[3]; - product[2] = matrix[2]*vector[0] + matrix[6]*vector[1] + matrix[10]*vector[2] + matrix[14]*vector[3]; + product[0] = matrix[0]*vector[0] + matrix[4]*vector[1] + matrix[8]*vector[2] + matrix[12]; + product[1] = matrix[1]*vector[0] + matrix[5]*vector[1] + matrix[9]*vector[2] + matrix[13]; + product[2] = matrix[2]*vector[0] + matrix[6]*vector[1] + matrix[10]*vector[2] + matrix[14]; } void ML_ModelViewMatrix(float *modelview, vec3_t viewangles, vec3_t vieworg) @@ -896,33 +919,76 @@ void ML_ProjectionMatrix(float *proj, float wdivh, float fovy) proj[15] = 0; } +typedef struct { + float m[4][4]; +} matrix4x4_t; + +void Matrix4x4_Invert_Simple (matrix4x4_t *out, const matrix4x4_t *in1) +{ + // we only support uniform scaling, so assume the first row is enough + // (note the lack of sqrt here, because we're trying to undo the scaling, + // this means multiplying by the inverse scale twice - squaring it, which + // makes the sqrt a waste of time) +#if 1 + double scale = 1.0 / (in1->m[0][0] * in1->m[0][0] + in1->m[0][1] * in1->m[0][1] + in1->m[0][2] * in1->m[0][2]); +#else + double scale = 3.0 / sqrt + (in1->m[0][0] * in1->m[0][0] + in1->m[0][1] * in1->m[0][1] + in1->m[0][2] * in1->m[0][2] + + in1->m[1][0] * in1->m[1][0] + in1->m[1][1] * in1->m[1][1] + in1->m[1][2] * in1->m[1][2] + + in1->m[2][0] * in1->m[2][0] + in1->m[2][1] * in1->m[2][1] + in1->m[2][2] * in1->m[2][2]); + scale *= scale; +#endif + + // invert the rotation by transposing and multiplying by the squared + // recipricol of the input matrix scale as described above + out->m[0][0] = (float)(in1->m[0][0] * scale); + out->m[0][1] = (float)(in1->m[1][0] * scale); + out->m[0][2] = (float)(in1->m[2][0] * scale); + out->m[1][0] = (float)(in1->m[0][1] * scale); + out->m[1][1] = (float)(in1->m[1][1] * scale); + out->m[1][2] = (float)(in1->m[2][1] * scale); + out->m[2][0] = (float)(in1->m[0][2] * scale); + out->m[2][1] = (float)(in1->m[1][2] * scale); + out->m[2][2] = (float)(in1->m[2][2] * scale); + + // invert the translate + out->m[0][3] = -(in1->m[0][3] * out->m[0][0] + in1->m[1][3] * out->m[0][1] + in1->m[2][3] * out->m[0][2]); + out->m[1][3] = -(in1->m[0][3] * out->m[1][0] + in1->m[1][3] * out->m[1][1] + in1->m[2][3] * out->m[1][2]); + out->m[2][3] = -(in1->m[0][3] * out->m[2][0] + in1->m[1][3] * out->m[2][1] + in1->m[2][3] * out->m[2][2]); + + // don't know if there's anything worth doing here + out->m[3][0] = 0; + out->m[3][1] = 0; + out->m[3][2] = 0; + out->m[3][3] = 1; +} + //screen->3d void ML_UnProject(vec3_t in, vec3_t out, vec3_t viewangles, vec3_t vieworg, float wdivh, float fovy) { float modelview[16]; float proj[16]; + float tempm[16]; ML_ModelViewMatrix(modelview, viewangles, vieworg); ML_ProjectionMatrix(proj, wdivh, fovy); + Matrix4_Multiply(proj, modelview, tempm); + + Matrix4x4_Invert_Simple(proj, tempm); { float v[4], tempv[4]; - v[0] = in[0]; - v[1] = in[1]; - v[2] = in[2]; + v[0] = in[0]*2-1; + v[1] = in[1]*2-1; + v[2] = in[2]*2-1; v[3] = 1; - Matrix4_Multiply(modelview, v, tempv); - Matrix4_Multiply(proj, tempv, v); + Matrix4_Transform4(proj, v, tempv); - v[0] /= v[3]; - v[1] /= v[3]; - v[2] /= v[3]; - - out[0] = (1+v[0])/2; - out[1] = (1+v[1])/2; - out[2] = (1+v[2])/2; + out[0] = tempv[0]; + out[1] = tempv[1]; + out[2] = tempv[2]; } } diff --git a/engine/common/mathlib.h b/engine/common/mathlib.h index 3752f6ca0..44cbd6e58 100644 --- a/engine/common/mathlib.h +++ b/engine/common/mathlib.h @@ -47,9 +47,9 @@ extern int nanmask; #define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2]) #define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];} #define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];} -#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];} +#define VectorCopy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];(b)[2]=(a)[2];} #define VectorClear(a) (a[0]=a[1]=a[2]=0) -#define VectorNegate(a,b) (b[0]=-a[0],b[1]=-a[1],b[2]=-a[2]) +#define VectorNegate(a,b) ((b)[0]=-(a)[0],(b)[1]=-(a)[1],(b)[2]=-(a)[2]) #define VectorLength(a) Length(a) void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc); diff --git a/engine/common/net.h b/engine/common/net.h index ff37f369c..3e7c25e28 100644 --- a/engine/common/net.h +++ b/engine/common/net.h @@ -30,9 +30,9 @@ typedef struct netadrtype_t type; union { - qbyte ip[4]; - qbyte ip6[16]; - qbyte ipx[10]; + qbyte ip[4]; + qbyte ip6[16]; + qbyte ipx[10]; }; unsigned short port; diff --git a/engine/common/particles.h b/engine/common/particles.h index ccf0f559f..ac467962b 100644 --- a/engine/common/particles.h +++ b/engine/common/particles.h @@ -160,6 +160,8 @@ void P_TorchEffect (vec3_t pos, int type); //particles centered around a model, void P_BlobExplosion (vec3_t org); //tarbaby explosion or TF emp. void P_ParticleExplosion (vec3_t org); //rocket explosion (sprite is allocated seperatly :( ) void P_LavaSplash (vec3_t org); //cthon dying, or a gas grenade. +void P_RunParticleCube(vec3_t minb, vec3_t maxb, vec3_t dir, float count, int colour, qboolean gravity, float jitter); +void P_RunParticleWeather(vec3_t minb, vec3_t maxb, vec3_t dir, float count, int colour, char *efname); //the core spawn function for trails. (trailstate can be null) int P_ParticleTrail (vec3_t start, vec3_t end, int type, trailstate_t **trailstate); diff --git a/engine/common/plugin.c b/engine/common/plugin.c index 1c9b74026..620913a54 100644 --- a/engine/common/plugin.c +++ b/engine/common/plugin.c @@ -23,6 +23,9 @@ typedef struct plugin_s { int sbarlevel[3]; //0 - main sbar, 1 - supplementry sbar sections (make sure these can be switched off), 2 - overlays (scoreboard). menus kill all. int reschange; + //protocol-in-a-plugin + int connectionlessclientpacket; + struct plugin_s *next; } plugin_t; @@ -37,6 +40,7 @@ void Plug_RegisterBuiltin(char *name, Plug_Builtin_t bi, int flags); #define PLUG_BIF_QVMONLY 2 void Plug_Init(void); +void Plug_Close(plugin_t *plug); void Plug_Tick(void); qboolean Plugin_ExecuteString(void); @@ -45,6 +49,7 @@ void Plug_Shutdown(void); static plugin_t *plugs; static plugin_t *menuplug; //plugin that has the current menu +static plugin_t *protocolclientplugin; typedef struct { @@ -165,7 +170,7 @@ plugin_t *Plug_Load(char *file) for (newplug = plugs; newplug; newplug = newplug->next) { if (!stricmp(newplug->name, file)) - return NULL; + return newplug; } newplug = Z_Malloc(sizeof(plugin_t)+strlen(file)+1); @@ -176,11 +181,17 @@ plugin_t *Plug_Load(char *file) currentplug = newplug; if (newplug->vm) { + Con_Printf("Created plugin %s\n", file); + newplug->next = plugs; plugs = newplug; argarray = 4; - VM_Call(newplug->vm, 0, Plug_FindBuiltin("Plug_GetEngineFunction"-4, ~0, &argarray)); + if (!VM_Call(newplug->vm, 0, Plug_FindBuiltin("Plug_GetEngineFunction"-4, ~0, &argarray))) + { + Plug_Close(newplug); + return NULL; + } if (newplug->reschange) VM_Call(newplug->vm, newplug->reschange, vid.width, vid.height); @@ -238,6 +249,8 @@ int Plug_ExportToEngine(void *offset, unsigned int mask, const long *arg) currentplug->sbarlevel[1] = arg[1]; else if (!strcmp(name, "SbarOverlay")) //overlay - scoreboard type stuff. currentplug->sbarlevel[2] = arg[1]; + else if (!strcmp(name, "ConnectionlessClientPacket")) + currentplug->connectionlessclientpacket = arg[1]; else return 0; return 1; @@ -1072,6 +1085,45 @@ int Plug_Net_Send(void *offset, unsigned int mask, const long *arg) return -2; } } +int Plug_Net_SendTo(void *offset, unsigned int mask, const long *arg) +{ + int written; + int handle = VM_LONG(arg[0]); + void *src = VM_POINTER(arg[1]); + int srclen = VM_LONG(arg[2]); + + netadr_t *address = VM_POINTER(arg[3]); + + + struct sockaddr_qstorage sockaddr; + if (handle == -1) + { + NET_SendPacket(NS_CLIENT, srclen, src, *address); + return srclen; + } + + NetadrToSockadr(address, &sockaddr); + + if (handle < 0 || handle >= pluginstreamarraylen || pluginstreamarray[handle].plugin != currentplug) + return -2; + switch(pluginstreamarray[handle].type) + { + case STREAM_SOCKET: + written = sendto(pluginstreamarray[handle].socket, src, srclen, 0, (struct sockaddr*)&sockaddr, sizeof(sockaddr)); + if (written < 0) + { + if (qerrno == EWOULDBLOCK) + return -1; + else + return -2; + } + else if (written == 0) + return -2; //closed by remote connection. + return written; + default: + return -2; + } +} int Plug_Net_Close(void *offset, unsigned int mask, const long *arg) { int handle = VM_LONG(arg[0]); @@ -1096,7 +1148,8 @@ void Plug_Load_f(void) { Con_Printf("Loads a plugin\n"); Con_Printf("plug_load [pluginpath]\n"); - Con_Printf("example pluginpath: plugins/blahx86.so\n"); + Con_Printf("example pluginpath: plugins/blah\n"); + Con_Printf("will load blahx86.dll or blah.so\n"); return; } if (!Plug_Load(plugin)) @@ -1156,16 +1209,20 @@ void Plug_Init(void) Plug_RegisterBuiltin("Net_TCPConnect", Plug_Net_TCPConnect, 0); Plug_RegisterBuiltin("Net_Recv", Plug_Net_Recv, 0); Plug_RegisterBuiltin("Net_Send", Plug_Net_Send, 0); + Plug_RegisterBuiltin("Net_SendTo", Plug_Net_SendTo, 0); Plug_RegisterBuiltin("Net_Close", Plug_Net_Close, 0); Plug_RegisterBuiltin("Media_ShowFrameRGBA_32", Plug_Media_ShowFrameRGBA_32, 0); + if (plug_loaddefault.value) + { #ifdef _WIN32 - COM_EnumerateFiles("plugins/*x86.dll", Plug_Emumerated, "x86.dll"); + COM_EnumerateFiles("plugins/*x86.dll", Plug_Emumerated, "x86.dll"); #elif defined(__linux__) - COM_EnumerateFiles("plugins/*x86.so", Plug_Emumerated, "x86.so"); + COM_EnumerateFiles("plugins/*x86.so", Plug_Emumerated, "x86.so"); #endif - COM_EnumerateFiles("plugins/*.qvm", Plug_Emumerated, ".qvm"); + COM_EnumerateFiles("plugins/*.qvm", Plug_Emumerated, ".qvm"); + } } void Plug_Tick(void) @@ -1240,6 +1297,32 @@ qboolean Plug_Menu_Event(int eventtype, int param) //eventtype = draw/keydown/ke return ret; } +int Plug_ConnectionlessClientPacket(char *buffer, int size) +{ + for (currentplug = plugs; currentplug; currentplug = currentplug->next) + { + if (currentplug->connectionlessclientpacket) + { + switch (VM_Call(currentplug->vm, currentplug->connectionlessclientpacket, buffer, size, &net_from)) + { + case 0: + continue; //wasn't handled + case 1: + currentplug = NULL; //was handled with no apparent result + return true; + case 2: +#ifndef SERVERONLY + cls.protocol = CP_PLUGIN; //woo, the plugin wants to connect to them! + protocolclientplugin = currentplug; +#endif + currentplug = NULL; + return true; + } + } + } + return false; +} + void Plug_SBar(void) { plugin_t *oc=currentplug; @@ -1329,6 +1412,12 @@ void Plug_Close(plugin_t *plug) menuplug = NULL; key_dest = key_game; } + if (protocolclientplugin == plug) + { + protocolclientplugin = NULL; + if (cls.protocol == CP_PLUGIN) + cls.protocol = CP_UNKNOWN; + } } void Plug_Close_f(void) diff --git a/engine/common/pmovetst.c b/engine/common/pmovetst.c index 9d5ba87b2..00a270184 100644 --- a/engine/common/pmovetst.c +++ b/engine/common/pmovetst.c @@ -268,10 +268,8 @@ PM_PlayerTrace trace_t PM_PlayerTrace (vec3_t start, vec3_t end) { trace_t trace, total; - hull_t *hull; int i; physent_t *pe; - vec3_t mins, maxs; // fill in a default trace memset (&total, 0, sizeof(trace_t)); @@ -282,7 +280,6 @@ trace_t PM_PlayerTrace (vec3_t start, vec3_t end) for (i=0 ; i< pmove.numphysent ; i++) { pe = &pmove.physents[i]; - // get the clipping hull // trace a line through the apropriate clipping hull PM_TransformedHullCheck (pe->model, start, end, &trace, pe->origin, pe->angles); diff --git a/engine/common/protocol.h b/engine/common/protocol.h index 86e8cf7b5..5ffb028df 100644 --- a/engine/common/protocol.h +++ b/engine/common/protocol.h @@ -848,6 +848,7 @@ typedef struct q1usercmd_s //ROGUE #define Q2RF_ADDATIVE 0x00080000 +#define RF_NOSHADOW 0x00100000 // player_state_t->refdef flags #define Q2RDF_UNDERWATER 1 // warp the screen as apropriate diff --git a/engine/ftequake/FTEQuake.dev b/engine/ftequake/FTEQuake.dev index 4f9b6a4a8..53601af07 100644 --- a/engine/ftequake/FTEQuake.dev +++ b/engine/ftequake/FTEQuake.dev @@ -1,7 +1,7 @@ [Project] FileName=FTEQuake.dev Name=FTEQuake -UnitCount=142 +UnitCount=133 Type=0 Ver=1 ObjFiles="" @@ -108,16 +108,6 @@ OverrideBuildCmd=0 BuildCmd= [Unit9] -FileName=..\common\md5.c -CompileCpp=0 -Folder=Common -Compile=1 -Link=1 -Priority=1000 -OverrideBuildCmd=0 -BuildCmd= - -[Unit10] FileName=..\common\net_chan.c CompileCpp=0 Folder=Common @@ -127,7 +117,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit11] +[Unit10] FileName=..\common\net_wins.c CompileCpp=0 Folder=Common @@ -137,7 +127,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit12] +[Unit11] FileName=..\common\pmove.c CompileCpp=0 Folder=Common @@ -147,7 +137,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit13] +[Unit12] FileName=..\common\pmovetst.c CompileCpp=0 Folder=Common @@ -157,7 +147,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit14] +[Unit13] FileName=..\common\q1bsp.c CompileCpp=0 Folder=Common @@ -167,7 +157,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit15] +[Unit14] FileName=..\common\q2pmove.c CompileCpp=0 Folder=Common @@ -177,7 +167,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit16] +[Unit15] FileName=..\common\qvm.c CompileCpp=0 Folder=Common @@ -187,7 +177,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit17] +[Unit16] FileName=..\common\translate.c CompileCpp=0 Folder=Common @@ -197,7 +187,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd=$(CC) -c translate.c -o ../build/translate.o $(CFLAGS) -[Unit18] +[Unit17] FileName=..\common\cmd.c CompileCpp=0 Folder=Common @@ -207,11 +197,21 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= +[Unit18] +FileName=..\client\cd_win.c +CompileCpp=0 +Folder=Client +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + [VersionInfo] Major=2 Minor=5 Release=5 -Build=36 +Build=46 LanguageID=2057 CharsetID=1252 CompanyName= @@ -226,16 +226,6 @@ ProductVersion= AutoIncBuildNr=1 [Unit19] -FileName=..\client\cd_win.c -CompileCpp=0 -Folder=Client -Compile=1 -Link=1 -Priority=1000 -OverrideBuildCmd=0 -BuildCmd= - -[Unit20] FileName=..\client\r_partset.c CompileCpp=0 Folder=Client @@ -245,7 +235,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit21] +[Unit20] FileName=..\client\cl_demo.c CompileCpp=0 Folder=Client @@ -255,7 +245,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit22] +[Unit21] FileName=..\client\cl_ents.c CompileCpp=0 Folder=Client @@ -265,7 +255,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit23] +[Unit22] FileName=..\client\cl_input.c CompileCpp=0 Folder=Client @@ -275,7 +265,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit24] +[Unit23] FileName=..\client\cl_main.c CompileCpp=0 Folder=Client @@ -285,7 +275,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit25] +[Unit24] FileName=..\client\cl_parse.c CompileCpp=0 Folder=Client @@ -295,7 +285,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit26] +[Unit25] FileName=..\client\cl_pred.c CompileCpp=0 Folder=Client @@ -305,7 +295,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit27] +[Unit26] FileName=..\client\cl_screen.c CompileCpp=0 Folder=Client @@ -315,7 +305,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit28] +[Unit27] FileName=..\client\cl_tent.c CompileCpp=0 Folder=Client @@ -325,7 +315,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit29] +[Unit28] FileName=..\client\cl_ui.c CompileCpp=0 Folder=Client @@ -335,7 +325,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit30] +[Unit29] FileName=..\client\clq2_cin.c CompileCpp=0 Folder=Client @@ -345,7 +335,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit31] +[Unit30] FileName=..\client\clq2_ents.c CompileCpp=0 Folder=Client @@ -355,7 +345,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit32] +[Unit31] FileName=..\client\console.c CompileCpp=0 Folder=Client @@ -365,7 +355,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit33] +[Unit32] FileName=..\client\fragstats.c CompileCpp=0 Folder=Client @@ -375,7 +365,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit34] +[Unit33] FileName=..\client\image.c CompileCpp=0 Folder=Client @@ -385,7 +375,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit35] +[Unit34] FileName=..\client\in_win.c CompileCpp=0 Folder=Client @@ -395,7 +385,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit36] +[Unit35] FileName=..\client\keys.c CompileCpp=0 Folder=Client @@ -405,7 +395,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit37] +[Unit36] FileName=..\client\m_items.c CompileCpp=0 Folder=Client @@ -415,7 +405,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit38] +[Unit37] FileName=..\client\m_master.c CompileCpp=0 Folder=Client @@ -425,7 +415,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit39] +[Unit38] FileName=..\client\m_mp3.c CompileCpp=0 Folder=Client @@ -435,7 +425,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit40] +[Unit39] FileName=..\client\m_multi.c CompileCpp=0 Folder=Client @@ -445,7 +435,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit41] +[Unit40] FileName=..\client\m_options.c CompileCpp=0 Folder=Client @@ -455,7 +445,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit42] +[Unit41] FileName=..\client\m_script.c CompileCpp=0 Folder=Client @@ -465,7 +455,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit43] +[Unit42] FileName=..\client\m_single.c CompileCpp=0 Folder=Client @@ -475,7 +465,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit44] +[Unit43] FileName=..\client\menu.c CompileCpp=0 Folder=Client @@ -485,7 +475,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit45] +[Unit44] FileName=..\client\net_master.c CompileCpp=0 Folder=Client @@ -495,7 +485,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit46] +[Unit45] FileName=..\client\r_bulleten.c CompileCpp=0 Folder=Client @@ -505,7 +495,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit47] +[Unit46] FileName=..\client\r_efrag.c CompileCpp=0 Folder=Client @@ -515,7 +505,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit48] +[Unit47] FileName=..\client\r_part.c CompileCpp=0 Folder=Client @@ -525,7 +515,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit49] +[Unit48] FileName=..\client\cl_cam.c CompileCpp=0 Folder=Client @@ -535,7 +525,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit50] +[Unit49] FileName=..\client\zqtp.c CompileCpp=0 Folder=Client @@ -545,7 +535,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit51] +[Unit50] FileName=..\client\renderque.c CompileCpp=0 Folder=Client @@ -555,7 +545,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit52] +[Unit51] FileName=..\client\roq_read.c CompileCpp=0 Folder=Client @@ -565,7 +555,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit53] +[Unit52] FileName=..\client\sbar.c CompileCpp=0 Folder=Client @@ -575,7 +565,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit54] +[Unit53] FileName=..\client\skin.c CompileCpp=0 Folder=Client @@ -585,7 +575,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit55] +[Unit54] FileName=..\client\snd_dma.c CompileCpp=0 Folder=Client @@ -595,7 +585,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit56] +[Unit55] FileName=..\client\snd_mem.c CompileCpp=0 Folder=Client @@ -605,7 +595,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit57] +[Unit56] FileName=..\client\snd_mix.c CompileCpp=0 Folder=Client @@ -615,7 +605,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit58] +[Unit57] FileName=..\client\snd_mp3.c CompileCpp=0 Folder=Client @@ -625,7 +615,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit59] +[Unit58] FileName=..\client\snd_ov.c CompileCpp=0 Folder=Client @@ -635,7 +625,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit60] +[Unit59] FileName=..\client\snd_win.c CompileCpp=0 Folder=Client @@ -645,7 +635,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit61] +[Unit60] FileName=..\client\sys_win.c CompileCpp=0 Folder=Client @@ -655,7 +645,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit62] +[Unit61] FileName=..\client\teamplay.c CompileCpp=0 Folder=Client @@ -665,7 +655,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit63] +[Unit62] FileName=..\client\textedit.c CompileCpp=0 Folder=Client @@ -675,7 +665,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit64] +[Unit63] FileName=..\client\valid.c CompileCpp=0 Folder=Client @@ -685,7 +675,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit65] +[Unit64] FileName=..\client\view.c CompileCpp=0 Folder=Client @@ -695,7 +685,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit66] +[Unit65] FileName=..\client\wad.c CompileCpp=0 Folder=Client @@ -705,7 +695,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit67] +[Unit66] FileName=..\client\renderer.c CompileCpp=0 Folder=Client @@ -715,7 +705,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit68] +[Unit67] FileName=..\gl\ltface.c CompileCpp=0 Folder=gl @@ -725,7 +715,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit69] +[Unit68] FileName=..\gl\gl_backend.c CompileCpp=0 Folder=gl @@ -735,7 +725,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit70] +[Unit69] FileName=..\gl\gl_draw.c CompileCpp=0 Folder=gl @@ -745,7 +735,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit71] +[Unit70] FileName=..\gl\gl_hlmdl.c CompileCpp=0 Folder=gl @@ -755,7 +745,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit72] +[Unit71] FileName=..\gl\gl_model.c CompileCpp=0 Folder=gl @@ -765,7 +755,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit73] +[Unit72] FileName=..\gl\gl_ngraph.c CompileCpp=0 Folder=gl @@ -775,7 +765,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit74] +[Unit73] FileName=..\gl\gl_ppl.c CompileCpp=0 Folder=gl @@ -785,7 +775,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit75] +[Unit74] FileName=..\gl\gl_rlight.c CompileCpp=0 Folder=gl @@ -795,7 +785,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit76] +[Unit75] FileName=..\gl\gl_rmain.c CompileCpp=0 Folder=gl @@ -805,7 +795,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit77] +[Unit76] FileName=..\gl\gl_rmisc.c CompileCpp=0 Folder=gl @@ -815,7 +805,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit78] +[Unit77] FileName=..\gl\gl_rsurf.c CompileCpp=0 Folder=gl @@ -825,7 +815,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit79] +[Unit78] FileName=..\gl\gl_screen.c CompileCpp=0 Folder=gl @@ -835,7 +825,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit80] +[Unit79] FileName=..\gl\gl_vidcommon.c CompileCpp=0 Folder=gl @@ -845,47 +835,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit82] -FileName=..\gl\gl_warp.c -CompileCpp=0 -Folder=gl -Compile=1 -Link=1 -Priority=1000 -OverrideBuildCmd=0 -BuildCmd= - -[Unit83] -FileName=..\gl\glmod_doom.c -CompileCpp=0 -Folder=gl -Compile=1 -Link=1 -Priority=1000 -OverrideBuildCmd=0 -BuildCmd= - -[Unit84] -FileName=..\gl\gl_alias.c -CompileCpp=0 -Folder=gl -Compile=1 -Link=1 -Priority=1000 -OverrideBuildCmd=0 -BuildCmd= - -[Unit85] -FileName=..\server\world.c -CompileCpp=0 -Folder=server -Compile=1 -Link=1 -Priority=1000 -OverrideBuildCmd=0 -BuildCmd= - -[Unit81] +[Unit80] FileName=..\gl\gl_vidnt.c CompileCpp=0 Folder=gl @@ -895,7 +845,37 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit86] +[Unit82] +FileName=..\gl\glmod_doom.c +CompileCpp=0 +Folder=gl +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit83] +FileName=..\gl\gl_alias.c +CompileCpp=0 +Folder=gl +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit84] +FileName=..\server\world.c +CompileCpp=0 +Folder=server +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit85] FileName=..\server\pr_cmds.c CompileCpp=0 Folder=server @@ -905,7 +885,17 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit87] +[Unit81] +FileName=..\gl\gl_warp.c +CompileCpp=0 +Folder=gl +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit86] FileName=..\server\savegame.c CompileCpp=0 Folder=server @@ -915,7 +905,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit88] +[Unit87] FileName=..\server\sv_ccmds.c CompileCpp=0 Folder=server @@ -925,7 +915,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit89] +[Unit88] FileName=..\server\sv_chat.c CompileCpp=0 Folder=server @@ -935,7 +925,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit90] +[Unit89] FileName=..\server\sv_demo.c CompileCpp=0 Folder=server @@ -945,7 +935,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit91] +[Unit90] FileName=..\server\sv_ents.c CompileCpp=0 Folder=server @@ -955,7 +945,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit92] +[Unit91] FileName=..\server\sv_init.c CompileCpp=0 Folder=server @@ -965,7 +955,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit93] +[Unit92] FileName=..\server\sv_main.c CompileCpp=0 Folder=server @@ -975,7 +965,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit94] +[Unit93] FileName=..\server\sv_master.c CompileCpp=0 Folder=server @@ -985,7 +975,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit95] +[Unit94] FileName=..\server\sv_move.c CompileCpp=0 Folder=server @@ -995,7 +985,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit96] +[Unit95] FileName=..\server\sv_mvd.c CompileCpp=0 Folder=server @@ -1005,7 +995,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit97] +[Unit96] FileName=..\server\sv_nchan.c CompileCpp=0 Folder=server @@ -1015,7 +1005,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit98] +[Unit97] FileName=..\server\sv_phys.c CompileCpp=0 Folder=server @@ -1025,7 +1015,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit99] +[Unit98] FileName=..\server\sv_rankin.c CompileCpp=0 Folder=server @@ -1035,7 +1025,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit100] +[Unit99] FileName=..\server\sv_send.c CompileCpp=0 Folder=server @@ -1045,7 +1035,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit101] +[Unit100] FileName=..\server\sv_sys_win.c CompileCpp=0 Folder=server @@ -1055,7 +1045,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit102] +[Unit101] FileName=..\server\sv_user.c CompileCpp=0 Folder=server @@ -1065,7 +1055,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit103] +[Unit102] FileName=..\server\svmodel.c CompileCpp=0 Folder=server @@ -1075,7 +1065,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit104] +[Unit103] FileName=..\server\svq2_ents.c CompileCpp=0 Folder=server @@ -1085,7 +1075,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit105] +[Unit104] FileName=..\server\svq2_game.c CompileCpp=0 Folder=server @@ -1095,7 +1085,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit106] +[Unit105] FileName=..\server\net_preparse.c CompileCpp=0 Folder=server @@ -1105,7 +1095,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit107] +[Unit106] FileName=..\qclib\qcdecomp.c CompileCpp=0 Folder=qclib @@ -1115,7 +1105,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit108] +[Unit107] FileName=..\qclib\hash.c CompileCpp=0 Folder=qclib @@ -1125,7 +1115,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit109] +[Unit108] FileName=..\qclib\initlib.c CompileCpp=0 Folder=qclib @@ -1135,7 +1125,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit110] +[Unit109] FileName=..\qclib\pr_edict.c CompileCpp=0 Folder=qclib @@ -1145,7 +1135,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit111] +[Unit110] FileName=..\qclib\Pr_exec.c CompileCpp=0 Folder=qclib @@ -1155,7 +1145,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit112] +[Unit111] FileName=..\qclib\pr_multi.c CompileCpp=0 Folder=qclib @@ -1165,7 +1155,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit113] +[Unit112] FileName=..\qclib\qcc_cmdlib.c CompileCpp=0 Folder=qclib @@ -1175,7 +1165,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit114] +[Unit113] FileName=..\qclib\qcc_pr_comp.c CompileCpp=0 Folder=qclib @@ -1185,7 +1175,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit115] +[Unit114] FileName=..\qclib\qcc_pr_lex.c CompileCpp=0 Folder=qclib @@ -1195,47 +1185,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit117] -FileName=..\qclib\qcd_main.c -CompileCpp=0 -Folder=qclib -Compile=1 -Link=1 -Priority=1000 -OverrideBuildCmd=0 -BuildCmd= - -[Unit118] -FileName=..\qclib\Comprout.c -CompileCpp=0 -Folder=qclib -Compile=1 -Link=1 -Priority=1000 -OverrideBuildCmd=0 -BuildCmd= - -[Unit119] -FileName=..\http\ftpclient.c -CompileCpp=0 -Folder=inet -Compile=1 -Link=1 -Priority=1000 -OverrideBuildCmd=0 -BuildCmd= - -[Unit120] -FileName=..\http\ftpserver.c -CompileCpp=0 -Folder=inet -Compile=1 -Link=1 -Priority=1000 -OverrideBuildCmd=0 -BuildCmd= - -[Unit116] +[Unit115] FileName=..\qclib\QccMain.c CompileCpp=0 Folder=qclib @@ -1245,7 +1195,37 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit121] +[Unit117] +FileName=..\qclib\Comprout.c +CompileCpp=0 +Folder=qclib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit118] +FileName=..\http\ftpclient.c +CompileCpp=0 +Folder=inet +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit119] +FileName=..\http\ftpserver.c +CompileCpp=0 +Folder=inet +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit120] FileName=..\http\httpclient.c CompileCpp=0 Folder=inet @@ -1255,7 +1235,17 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit122] +[Unit116] +FileName=..\qclib\qcd_main.c +CompileCpp=0 +Folder=qclib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit121] FileName=..\http\httpserver.c CompileCpp=0 Folder=inet @@ -1265,7 +1255,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit123] +[Unit122] FileName=..\http\iwebiface.c CompileCpp=0 Folder=inet @@ -1275,7 +1265,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit124] +[Unit123] FileName=..\http\webgen.c CompileCpp=0 Folder=inet @@ -1285,8 +1275,9 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit125] +[Unit124] FileName=..\server\worlda.s +CompileCpp=0 Folder=Common Compile=1 Link=0 @@ -1294,7 +1285,7 @@ Priority=1000 OverrideBuildCmd=1 BuildCmd=$(CC) -c worlda.s -o ../build/world.o $(CFLAGS) -[Unit126] +[Unit125] FileName=..\common\math.s Folder=Common Compile=0 @@ -1303,8 +1294,17 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= +[Unit126] +FileName=..\client\sys_wina.s +Folder=Common +Compile=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + [Unit127] -FileName=..\email\imapnoti.c +FileName=..\irc\ircclient.c CompileCpp=0 Folder=inet Compile=1 @@ -1314,9 +1314,9 @@ OverrideBuildCmd=0 BuildCmd= [Unit128] -FileName=..\email\pop3noti.c +FileName=..\client\pr_menu.c CompileCpp=0 -Folder=inet +Folder=Client Compile=1 Link=1 Priority=1000 @@ -1324,9 +1324,9 @@ OverrideBuildCmd=0 BuildCmd= [Unit129] -FileName=..\email\sv_pop3.c +FileName=..\common\plugin.c CompileCpp=0 -Folder=inet +Folder=Common Compile=1 Link=1 Priority=1000 @@ -1334,9 +1334,9 @@ OverrideBuildCmd=0 BuildCmd= [Unit130] -FileName=..\email\sv_smtp.c +FileName=..\client\pr_csqc.c CompileCpp=0 -Folder=inet +Folder=Client Compile=1 Link=1 Priority=1000 @@ -1344,18 +1344,19 @@ OverrideBuildCmd=0 BuildCmd= [Unit131] -FileName=..\client\sys_wina.s -Folder=Common -Compile=0 -Link=0 +FileName=..\gl\gl_shader.c +Folder=gl +Compile=1 +Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= +CompileCpp=0 [Unit132] -FileName=..\nqnet\net_wipx.c +FileName=..\client\m_download.c CompileCpp=0 -Folder=nq +Folder=Client Compile=1 Link=1 Priority=1000 @@ -1363,9 +1364,9 @@ OverrideBuildCmd=0 BuildCmd= [Unit133] -FileName=..\nqnet\net_win.c +FileName=..\client\snd_directx.c CompileCpp=0 -Folder=nq +Folder=Client Compile=1 Link=1 Priority=1000 diff --git a/engine/ftequake/ftequake.dsp b/engine/ftequake/ftequake.dsp index 9fe2ad627..71d0955ec 100644 --- a/engine/ftequake/ftequake.dsp +++ b/engine/ftequake/ftequake.dsp @@ -106,7 +106,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /G5 /ML /W3 /GX /ZI /Od /I "..\client" /I "../common" /I "../server" /I "../gl" /I "../sw" /I "../qclib" /I "../libs" /I "../libs/dxsdk7/include" /D "_DEBUG" /D "GLQUAKE" /D "WIN32" /D "_WINDOWS" /FR".\GLDebug/" /Fp".\GLDebug/qwcl.pch" /Yu"quakedef.h" /Fo".\GLDebug/" /Fd".\GLDebug/" /FD /c +# ADD CPP /nologo /G5 /W3 /GX /ZI /Od /I "..\client" /I "../common" /I "../server" /I "../gl" /I "../sw" /I "../qclib" /I "../libs" /I "../libs/dxsdk7/include" /D "_DEBUG" /D "GLQUAKE" /D "WIN32" /D "_WINDOWS" /FR".\GLDebug/" /Fp".\GLDebug/qwcl.pch" /Yu"quakedef.h" /Fo".\GLDebug/" /Fd".\GLDebug/" /FD /c # SUBTRACT CPP /X # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 @@ -117,7 +117,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept -# ADD LINK32 comctl32.lib wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:windows /debug /machine:I386 /out:"../../fteglqw_dbg.exe" /libpath:"../libs/dxsdk7/lib" +# ADD LINK32 comctl32.lib wsock32.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"../../fteglqw_dbg.exe" /libpath:"../libs/dxsdk7/lib" # SUBTRACT LINK32 /pdb:none !ELSEIF "$(CFG)" == "ftequake - Win32 GLRelease" @@ -2638,8 +2638,6 @@ SOURCE=..\gl\gl_alias.c !ELSEIF "$(CFG)" == "ftequake - Win32 Debug Dedicated Server" -# PROP Exclude_From_Build 1 - !ELSEIF "$(CFG)" == "ftequake - Win32 Release Dedicated Server" # PROP BASE Exclude_From_Build 1 diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c index 1cbe05017..f3d5310b1 100644 --- a/engine/gl/gl_alias.c +++ b/engine/gl/gl_alias.c @@ -112,7 +112,8 @@ typedef struct { //frame is an index into this typedef struct { #ifdef SKELETALMODELS - qboolean isskeletal; + qboolean isheirachical; //for models with transforms, states that bones need to be transformed from thier parent. + //this is actually bad, and can result in bones shortening as they interpolate. #endif int numposes; float rate; @@ -153,6 +154,7 @@ typedef struct { float skinspeed; int texnums; int ofstexnums; + char name [MAX_QPATH]; } galiasskin_t; typedef struct { @@ -236,13 +238,18 @@ qboolean GLMod_Trace(model_t *model, int forcehullnum, int frame, vec3_t start, group = (galiasgroup_t*)((char*)mod + mod->groupofs); pose = (galiaspose_t*)((char*)&group[0] + group[0].poseofs); posedata = (float*)((char*)pose + pose->ofsverts); - if (group->isskeletal && !mod->sharesverts) + if (mod->numbones && !mod->sharesverts) { float bonepose[MAX_BONES][12]; posedata = alloca(mod->numverts*sizeof(vec3_t)); frac = 1; - R_LerpBones(&frac, (float**)posedata, 1, (galiasbone_t*)((char*)mod + mod->ofsbones), mod->numbones, bonepose); - R_TransformVerticies(bonepose, (galisskeletaltransforms_t*)((char*)mod + mod->ofstransforms), mod->numtransforms, posedata); + if (group->isheirachical) + { + R_LerpBones(&frac, (float**)posedata, 1, (galiasbone_t*)((char*)mod + mod->ofsbones), mod->numbones, bonepose); + R_TransformVerticies(bonepose, (galisskeletaltransforms_t*)((char*)mod + mod->ofstransforms), mod->numtransforms, posedata); + } + else + R_TransformVerticies((void*)posedata, (galisskeletaltransforms_t*)((char*)mod + mod->ofstransforms), mod->numtransforms, posedata); } for (i = 0; i < mod->numindexes; i+=3) @@ -440,24 +447,42 @@ static void R_LerpBones(float *plerp, float **pose, int poses, galiasbone_t *bon int i, k, b; float *matrix, m[12]; - // vertex weighted skeletal - // interpolate matrices and concatenate them to their parents - for (i = 0;i < bonecount;i++) + if (poses == 1) { - for (k = 0;k < 12;k++) - m[k] = 0; - for (b = 0;b < poses;b++) + // vertex weighted skeletal + // interpolate matrices and concatenate them to their parents + for (i = 0;i < bonecount;i++) { - matrix = pose[b] + i*12; - - for (k = 0;k < 12;k++) - m[k] += matrix[k] * plerp[b]; + matrix = pose[0] + i*12; + + if (bones[i].parent >= 0) + R_ConcatTransforms((void*)bonepose[bones[i].parent], (void*)matrix, (void*)bonepose[i]); + else + for (k = 0;k < 12;k++) //parentless + bonepose[i][k] = matrix[k]; + } + } + else + { + // vertex weighted skeletal + // interpolate matrices and concatenate them to their parents + for (i = 0;i < bonecount;i++) + { + for (k = 0;k < 12;k++) + m[k] = 0; + for (b = 0;b < poses;b++) + { + matrix = pose[b] + i*12; + + for (k = 0;k < 12;k++) + m[k] += matrix[k] * plerp[b]; + } + if (bones[i].parent >= 0) + R_ConcatTransforms((void*)bonepose[bones[i].parent], (void*)m, (void*)bonepose[i]); + else + for (k = 0;k < 12;k++) //parentless + bonepose[i][k] = m[k]; } - if (bones[i].parent >= 0) - R_ConcatTransforms((void*)bonepose[bones[i].parent], (void*)m, (void*)bonepose[i]); - else - for (k = 0;k < 12;k++) //parentless - bonepose[i][k] = m[k]; } } static void R_TransformVerticies(float bonepose[MAX_BONES][12], galisskeletaltransforms_t *weights, int numweights, float *xyzout) @@ -477,14 +502,40 @@ static void R_TransformVerticies(float bonepose[MAX_BONES][12], galisskeletaltra } } #ifndef SERVERONLY -static void R_BuildSkeletalMesh(mesh_t *mesh, float *plerp, float **pose, int poses, galiasbone_t *bones, int bonecount, galisskeletaltransforms_t *weights, int numweights) +static void R_BuildSkeletalMesh(mesh_t *mesh, float *plerp, float **pose, int poses, galiasbone_t *bones, int bonecount, galisskeletaltransforms_t *weights, int numweights, qboolean usehierarchy) { float bonepose[MAX_BONES][12]; - int i, k; - float *matrix, m[12]; + int i, k, l; + float m[12]; - R_LerpBones(plerp, pose, poses, bones, bonecount, bonepose); + if (usehierarchy) + R_LerpBones(plerp, pose, poses, bones, bonecount, bonepose); + else + { + if (poses == 1) + memcpy(bonepose, pose[0], sizeof(float)*12*bonecount); + else if (poses == 2) + { + for (i = 0; i < bonecount*12; i++) + { + ((float*)bonepose)[i] = pose[0][i]*plerp[0] + pose[1][i]*plerp[1]; + } + } + else + { + for (i = 0; i < bonecount; i++) + { + for (l = 0; l < 12; l++) + bonepose[i][l] = 0; + for (k = 0; k < poses; k++) + { + for (l = 0; l < 12; l++) + bonepose[i][l] += pose[k][i*12+l] * plerp[k]; + } + } + } + } // blend the vertex bone weights // memset(outhead, 0, mesh->numvertexes * sizeof(mesh->xyz_array[0])); @@ -507,7 +558,59 @@ static void R_BuildSkeletalMesh(mesh_t *mesh, float *plerp, float **pose, int po */ } + memset(mesh->xyz_array, 0, mesh->numvertexes*sizeof(vec3_t)); R_TransformVerticies(bonepose, weights, numweights, (float*)mesh->xyz_array); + + + + +#if 0 //draws the bones + qglColor3f(1, 0, 0); + { + int i; + int p; + vec3_t org, dest; + + qglBegin(GL_LINES); + for (i = 0; i < bonecount; i++) + { + p = bones[i].parent; + if (p < 0) + p = 0; + qglVertex3f(bonepose[i][3], bonepose[i][7], bonepose[i][11]); + qglVertex3f(bonepose[p][3], bonepose[p][7], bonepose[p][11]); + } + qglEnd(); + qglBegin(GL_LINES); + for (i = 0; i < bonecount; i++) + { + p = bones[i].parent; + if (p < 0) + p = 0; + org[0] = bonepose[i][3]; org[1] = bonepose[i][7]; org[2] = bonepose[i][11]; + qglVertex3fv(org); + qglVertex3f(bonepose[p][3], bonepose[p][7], bonepose[p][11]); + dest[0] = org[0]+bonepose[i][0];dest[1] = org[1]+bonepose[i][1];dest[2] = org[2]+bonepose[i][2]; + qglVertex3fv(org); + qglVertex3fv(dest); + qglVertex3fv(dest); + qglVertex3f(bonepose[p][3], bonepose[p][7], bonepose[p][11]); + dest[0] = org[0]+bonepose[i][4];dest[1] = org[1]+bonepose[i][5];dest[2] = org[2]+bonepose[i][6]; + qglVertex3fv(org); + qglVertex3fv(dest); + qglVertex3fv(dest); + qglVertex3f(bonepose[p][3], bonepose[p][7], bonepose[p][11]); + dest[0] = org[0]+bonepose[i][8];dest[1] = org[1]+bonepose[i][9];dest[2] = org[2]+bonepose[i][10]; + qglVertex3fv(org); + qglVertex3fv(dest); + qglVertex3fv(dest); + qglVertex3f(bonepose[p][3], bonepose[p][7], bonepose[p][11]); + } + qglEnd(); + + mesh->numindexes = 0; //don't draw this mesh, as that would obscure the bones. :( + } +#endif } #endif #endif @@ -602,7 +705,7 @@ static qboolean R_GAliasBuildMesh(mesh_t *mesh, galiasinfo_t *inf, int frame1, i if (frame1 >= inf->groups) { Con_DPrintf("Too high frame %i (%s)\n", frame1, currententity->model->name); - frame1 = 0; + frame1 %= inf->groups; } if (frame2 >= inf->groups) { @@ -660,12 +763,17 @@ static qboolean R_GAliasBuildMesh(mesh_t *mesh, galiasinfo_t *inf, int frame1, i //we don't support meshes with one group skeletal and annother not. #ifdef SKELETALMODELS - if (g1->isskeletal) + if (inf->numbones) { int l=0; float plerp[4]; float *pose[4]; float mlerp; //minor lerp, poses within a group. + qboolean hirachy; + + if (g1->isheirachical != g2->isheirachical) + lerp = 0; + hirachy = g1->isheirachical; mlerp = (fg1time)*g1->rate; frame1=mlerp; @@ -705,7 +813,7 @@ static qboolean R_GAliasBuildMesh(mesh_t *mesh, galiasinfo_t *inf, int frame1, i plerp[4] = 0; l = 1; */ - R_BuildSkeletalMesh(mesh, plerp, pose, l, (galiasbone_t *)((char*)inf+inf->ofsbones), inf->numbones, (galisskeletaltransforms_t *)((char*)inf+inf->ofstransforms), inf->numtransforms); + R_BuildSkeletalMesh(mesh, plerp, pose, l, (galiasbone_t *)((char*)inf+inf->ofsbones), inf->numbones, (galisskeletaltransforms_t *)((char*)inf+inf->ofstransforms), inf->numtransforms, hirachy); return false; } #endif @@ -1016,6 +1124,8 @@ static galiastexnum_t *GL_ChooseSkin(galiasinfo_t *inf, char *modelname, entity_ skins = (galiasskin_t*)((char *)inf + inf->ofsskins); if (e->skinnum >= 0 && e->skinnum < inf->numskins) skins += e->skinnum; + else + Con_DPrintf("Skin number out of range\n"); if (!skins->texnums) return NULL; @@ -1176,13 +1286,14 @@ void GL_DrawAliasMesh_Sketch (mesh_t *mesh) qglEnableClientState( GL_NORMAL_ARRAY ); } - if (mesh->colors_array) + qglColor3f(1,1,1); +/* if (mesh->colors_array) { qglColorPointer(4, GL_UNSIGNED_BYTE, 0, mesh->colors_array); qglEnableClientState( GL_COLOR_ARRAY ); } else - qglDisableClientState( GL_COLOR_ARRAY ); +*/ qglDisableClientState( GL_COLOR_ARRAY ); qglDrawElements(GL_TRIANGLES, mesh->numindexes, GL_UNSIGNED_INT, mesh->indexes); @@ -1190,7 +1301,10 @@ void GL_DrawAliasMesh_Sketch (mesh_t *mesh) qglDisableClientState( GL_COLOR_ARRAY ); qglDisableClientState( GL_NORMAL_ARRAY ); - qglColor3f(0, 0, 0); + if (mesh->colors_array) + qglColor4ub(0, 0, 0, mesh->colors_array[0][3]); + else + qglColor3f(0, 0, 0); qglBegin(GL_LINES); for (i = 0; i < mesh->numindexes; i+=3) { @@ -1463,6 +1577,19 @@ void R_DrawGAliasModel (entity_t *e) VectorVectors(mesh.lightaxis[2], mesh.lightaxis[1], mesh.lightaxis[0]); VectorInverse(mesh.lightaxis[1]); } + + if (e->flags & Q2RF_GLOW) + { + shadelight[0] += sin(cl.time)*0.25; + shadelight[1] += sin(cl.time)*0.25; + shadelight[2] += sin(cl.time)*0.25; + } + +/* + VectorClear(ambientlight); + VectorClear(shadelight); +*/ + /* an = e->angles[1]/180*M_PI; shadevector[0] = cos(-an); @@ -1725,7 +1852,10 @@ void R_DrawGAliasModel (entity_t *e) qglEnable(GL_BLEND); qglColor4f(1, 1, 1, e->alpha*r_fb_models.value); c_alias_polys += mesh.numindexes/3; + + qglBlendFunc (GL_SRC_ALPHA, GL_ONE); GL_DrawAliasMesh(&mesh, skin->fullbright); + qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } } } @@ -1803,52 +1933,101 @@ qglColor3f(0,0,1); } //returns result in the form of the result vector -void RotateLightVector(vec3_t angles, vec3_t origin, vec3_t lightpoint, vec3_t result) +void RotateLightVector(vec3_t *axis, vec3_t origin, vec3_t lightpoint, vec3_t result) { - vec3_t f, r, u, offs; - - angles[0]*=-1; - AngleVectors(angles, f, r, u); - angles[0]*=-1; + vec3_t offs; offs[0] = lightpoint[0] - origin[0]; offs[1] = lightpoint[1] - origin[1]; offs[2] = lightpoint[2] - origin[2]; - result[0] = DotProduct (offs, f); - result[1] = -DotProduct (offs, r); - result[2] = DotProduct (offs, u); + result[0] = DotProduct (offs, axis[0]); + result[1] = DotProduct (offs, axis[1]); + result[2] = DotProduct (offs, axis[2]); } void GL_LightMesh (mesh_t *mesh, vec3_t lightpos, vec3_t colours, float radius) { vec3_t dir; int i; - float dot; + float dot, d, f, a; + vec3_t bcolours; + vec3_t *xyz = mesh->xyz_array; vec3_t *normals = mesh->normals_array; byte_vec4_t *out = mesh->colors_array; + bcolours[0] = colours[0]*255; + bcolours[1] = colours[1]*255; + bcolours[2] = colours[2]*255; + + if (!out) + return; //urm.. + if (normals) { for (i = 0; i < mesh->numvertexes; i++) { VectorSubtract(lightpos, xyz[i], dir); dot = DotProduct(dir, normals[i]); - out[i][0] = colours[0]*dot; - out[i][1] = colours[1]*dot; - out[i][2] = colours[2]*dot; + if (dot > 0) + { + d = DotProduct(dir, dir)/radius; + a = 1/d; + if (a>0) + { + a *= dot/sqrt(d); + f = a*bcolours[0]; + if (f > 255) + f = 255; + else if (f < 0) + f = 0; + out[i][0] = f; + + f = a*bcolours[1]; + if (f > 255) + f = 255; + else if (f < 0) + f = 0; + out[i][1] = f; + + f = a*bcolours[2]; + if (f > 255) + f = 255; + else if (f < 0) + f = 0; + out[i][2] = f; + } + else + { + out[i][0] = 0; + out[i][1] = 0; + out[i][2] = 0; + } + } + else + { + out[i][0] = 0; + out[i][1] = 0; + out[i][2] = 0; + } out[i][3] = 255; } } else { + if (bcolours[0] > 255) + bcolours[0] = 255; + if (bcolours[1] > 255) + bcolours[1] = 255; + if (bcolours[2] > 255) + bcolours[2] = 255; for (i = 0; i < mesh->numvertexes; i++) { VectorSubtract(lightpos, xyz[i], dir); - out[i][0] = colours[0]; - out[i][1] = colours[1]; - out[i][2] = colours[2]; + out[i][0] = bcolours[0]; + out[i][1] = bcolours[1]; + out[i][2] = bcolours[2]; out[i][3] = 255; } } @@ -1856,13 +2035,13 @@ void GL_LightMesh (mesh_t *mesh, vec3_t lightpos, vec3_t colours, float radius) void R_DrawGAliasModelLighting (entity_t *e, vec3_t lightpos, vec3_t colours, float radius) { - return; //not ready yet -#if 0 +#if 1 model_t *clmodel = e->model; vec3_t mins, maxs; vec3_t lightdir; galiasinfo_t *inf; + galiastexnum_t *tex; mesh_t mesh; if (e->flags & Q2RF_VIEWERMODEL) @@ -1878,56 +2057,78 @@ void R_DrawGAliasModelLighting (entity_t *e, vec3_t lightpos, vec3_t colours, fl VectorAdd (e->origin, clmodel->mins, mins); VectorAdd (e->origin, clmodel->maxs, maxs); - if (!(e->flags & Q2RF_WEAPONMODEL)) - if (R_CullBox (mins, maxs)) - return; +// if (!(e->flags & Q2RF_WEAPONMODEL)) +// if (R_CullBox (mins, maxs)) +// return; - RotateLightVector(e->angles, e->origin, lightpos, lightdir); + + RotateLightVector(e->axis, e->origin, lightpos, lightdir); GL_DisableMultitexture(); GL_TexEnv(GL_MODULATE); if (gl_smoothmodels.value) - glShadeModel (GL_SMOOTH); + qglShadeModel (GL_SMOOTH); if (gl_affinemodels.value) - glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); + qglHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); if (e->flags & Q2RF_DEPTHHACK) - glDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin)); + qglDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin)); - glColor3f(colours[0], colours[1], colours[2]); + qglColor3f(colours[0], colours[1], colours[2]); + qglColor4f(1, 1, 1, 1); - glPushMatrix(); + qglPushMatrix(); R_RotateForEntity(e); inf = GLMod_Extradata (clmodel); if (gl_ati_truform.value) - glEnable(GL_PN_TRIANGLES_ATI); + qglEnable(GL_PN_TRIANGLES_ATI); + qglEnable(GL_TEXTURE_2D); + + qglEnable(GL_POLYGON_OFFSET_FILL); + + GL_TexEnv(GL_REPLACE); +// qglDisable(GL_STENCIL_TEST); + qglEnable(GL_BLEND); + qglEnable(GL_ALPHA_TEST); //if you used an alpha channel where you shouldn't have, more fool you. + qglBlendFunc(GL_ONE, GL_ONE); +// qglDepthFunc(GL_ALWAYS); while(inf) { - R_GAliasBuildMesh(&mesh, inf, e->frame, e->oldframe, e->lerptime, e->alpha); + R_GAliasBuildMesh(&mesh, inf, e->frame, e->oldframe, e->lerpfrac, e->alpha, e->frame1time, e->frame2time); + mesh.colors_array = tempColours; + + tex = GL_ChooseSkin(inf, clmodel->name, e); GL_LightMesh(&mesh, lightdir, colours, radius); - - GL_DrawAliasMesh(&mesh, 0); + GL_DrawAliasMesh(&mesh, tex->base); if (inf->nextsurf) inf = (galiasinfo_t*)((char *)inf + inf->nextsurf); else inf = NULL; } - glPopMatrix(); + currententity->fatness=0; + qglPopMatrix(); if (gl_ati_truform.value) - glDisable(GL_PN_TRIANGLES_ATI); + qglDisable(GL_PN_TRIANGLES_ATI); GL_TexEnv(GL_REPLACE); - glShadeModel (GL_FLAT); + qglShadeModel (GL_FLAT); if (gl_affinemodels.value) - glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + qglHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + qglDisable(GL_POLYGON_OFFSET_FILL); if (e->flags & Q2RF_DEPTHHACK) - glDepthRange (gldepthmin, gldepthmax); + qglDepthRange (gldepthmin, gldepthmax); + + qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + qglDisable(GL_BLEND); + qglDisable(GL_TEXTURE_2D); + + R_IBrokeTheArrays(); #endif } @@ -1947,7 +2148,7 @@ void R_DrawGAliasShadowVolume(entity_t *e, vec3_t lightpos, float radius) if (r_noaliasshadows.value) return; - RotateLightVector(e->angles, e->origin, lightpos, lightorg); + RotateLightVector(e->axis, e->origin, lightpos, lightorg); if (Length(lightorg) > radius + clmodel->radius) return; @@ -2097,68 +2298,114 @@ void GL_GenerateNormals(float *orgs, float *normals, int *indicies, int numtris, } +char **skinfilelist; int skinfilecount; +static qboolean VARGS TryAddSkin(char *skinname, ...) +{ + va_list argptr; + char string[MAX_QPATH]; + + //make sure we don't add it twice + int i; + + + va_start (argptr, skinname); + _vsnprintf (string,sizeof(string)-1, skinname,argptr); + va_end (argptr); + string[MAX_QPATH-1] = '\0'; + + for (i = 0; i < skinfilecount; i++) + { + if (!strcmp(skinfilelist[i], string)) + return true; //already added + } + + if (!COM_FCheckExists(string)) + return false; + + skinfilelist = BZ_Realloc(skinfilelist, sizeof(*skinfilelist)*(skinfilecount+1)); + skinfilelist[skinfilecount] = Z_Malloc(strlen(string)+1); + strcpy(skinfilelist[skinfilecount], string); + skinfilecount++; + return true; +} + +int GL_EnumerateSkins(char *name, int size, void *param) +{ + TryAddSkin(name); + return true; +} + int GL_BuildSkinFileList(char *modelname) { + int i; char skinfilename[MAX_QPATH]; - for (skinfilecount = 0; ; skinfilecount++) + + //flush the old list + for (i = 0; i < skinfilecount; i++) { - _snprintf(skinfilename, sizeof(skinfilename)-1, "%s_%i.skin", modelname, skinfilecount); - if (!COM_FCheckExists(skinfilename)) - break; + Z_Free(skinfilelist[i]); + skinfilelist[i] = NULL; } + skinfilecount=0; + + COM_StripExtension(modelname, skinfilename); + + //try and add numbered skins, and then try fixed names. + for (i = 0; ; i++) + { + if (!TryAddSkin("%s_%i.skin", modelname, i)) + { + if (i == 0) + { + if (!TryAddSkin("%s_default.skin", skinfilename, i)) + break; + } + else if (i == 1) + { + if (!TryAddSkin("%s_blue.skin", skinfilename, i)) + break; + } + else if (i == 2) + { + if (!TryAddSkin("%s_red.skin", skinfilename, i)) + break; + } + else if (i == 3) + { + if (!TryAddSkin("%s_green.skin", skinfilename, i)) + break; + } + else if (i == 4) + { + if (!TryAddSkin("%s_yellow.skin", skinfilename, i)) + break; + } + else + break; + } + } + + COM_EnumerateFiles(va("%s_*.skin", modelname), GL_EnumerateSkins, NULL); + COM_EnumerateFiles(va("%s_*.skin", skinfilename), GL_EnumerateSkins, NULL); return skinfilecount; } //This is a hack. It uses an assuption about q3 player models. -void GL_ParseQ3SkinFile(char *out, char *surfname, char *modelname, int skinnum) +void GL_ParseQ3SkinFile(char *out, char *surfname, char *modelname, int skinnum, char *skinfilename) { const char *f = NULL, *p; int len; - char line[256]; - if (!f) - { - strcpy(line, modelname); - strcat(line, "_0.skin"); - f = COM_LoadTempFile2(line); - } + if (skinnum >= skinfilecount) + return; - if (!f) - { - if (skinnum == 4) - { - COM_StripExtension(modelname, line); - strcat(line, "_yellow.skin"); - f = COM_LoadTempFile2(line); - } - else if (skinnum == 3) - { - COM_StripExtension(modelname, line); - strcat(line, "_green.skin"); - f = COM_LoadTempFile2(line); - } - else if (skinnum == 2) - { - COM_StripExtension(modelname, line); - strcat(line, "_red.skin"); - f = COM_LoadTempFile2(line); - } - else if (skinnum == 1) - { - COM_StripExtension(modelname, line); - strcat(line, "_blue.skin"); - f = COM_LoadTempFile2(line); - } - if (!f) - { - COM_StripExtension(modelname, line); - strcat(line, "_default.skin"); - f = COM_LoadTempFile2(line); - } - } + if (skinfilename) + strcpy(skinfilename, skinfilelist[skinnum]); + + f = COM_LoadTempFile2(skinfilelist[skinnum]); while(f) { @@ -2224,7 +2471,7 @@ void GL_LoadSkinFile(galiastexnum_t *texnum, char *surfacename, int skinnumber, char shadername[MAX_QPATH]; Q_strncpyz(shadername, surfacename, sizeof(shadername)); - GL_ParseQ3SkinFile(shadername, surfacename, loadmodel->name, skinnumber); + GL_ParseQ3SkinFile(shadername, surfacename, loadmodel->name, skinnumber, NULL); texnum->base = Mod_LoadHiResTexture(shadername, "models", true, true, true); } @@ -2404,11 +2651,11 @@ static void *Q1_LoadSkins (daliasskintype_t *pskintype, qboolean alpha) //LH's naming scheme ("models" is likly to be ignored) fbtexture = 0; - _snprintf(skinname, sizeof(skinname), "%s_%i", loadmodel->name, i); + _snprintf(skinname, sizeof(skinname), "%s_%i.", loadmodel->name, i); texture = Mod_LoadReplacementTexture(skinname, "models", true, false, true); if (texture) { - _snprintf(skinname, sizeof(skinname), "%s_%i_luma", loadmodel->name, i); + _snprintf(skinname, sizeof(skinname), "%s_%i_luma.", loadmodel->name, i); fbtexture = Mod_LoadReplacementTexture(skinname, "models", true, false, true); } else @@ -2472,12 +2719,12 @@ static void *Q1_LoadSkins (daliasskintype_t *pskintype, qboolean alpha) //LH naming scheme if (!texture) { - sprintf(skinname, "%s_%i_%i", loadmodel->name, i, t); + sprintf(skinname, "%s_%i_%i.", loadmodel->name, i, t); texture = Mod_LoadReplacementTexture(skinname, "models", true, false, true); } if (!fbtexture && r_fb_models.value) { - sprintf(skinname, "%s_%i_%i_luma", loadmodel->name, i, t); + sprintf(skinname, "%s_%i_%i_luma.", loadmodel->name, i, t); fbtexture = Mod_LoadReplacementTexture(skinname, "models", true, true, true); } @@ -3155,15 +3402,15 @@ qboolean Mod_GetTag(model_t *model, int tagnum, int frame1, int frame2, float f2 if (t1 == t2) { result[0] = t1->ang[0][0]; - result[1] = t1->ang[1][0]; - result[2] = t1->ang[2][0]; + result[1] = t1->ang[0][1]; + result[2] = t1->ang[0][2]; result[3] = t1->org[0]; - result[4] = t1->ang[0][1]; + result[4] = t1->ang[1][0]; result[5] = t1->ang[1][1]; - result[6] = t1->ang[2][1]; + result[6] = t1->ang[1][2]; result[7] = t1->org[1]; - result[8] = t1->ang[0][2]; - result[9] = t1->ang[1][2]; + result[8] = t1->ang[2][0]; + result[9] = t1->ang[2][1]; result[10] = t1->ang[2][2]; result[11] = t1->org[2]; } @@ -3171,15 +3418,15 @@ qboolean Mod_GetTag(model_t *model, int tagnum, int frame1, int frame2, float f2 { float f1ness = 1-f2ness; result[0] = t1->ang[0][0]*f1ness + t2->ang[0][0]*f2ness; - result[1] = t1->ang[1][0]*f1ness + t2->ang[1][0]*f2ness; - result[2] = t1->ang[2][0]*f1ness + t2->ang[2][0]*f2ness; + result[1] = t1->ang[0][1]*f1ness + t2->ang[0][1]*f2ness; + result[2] = t1->ang[0][2]*f1ness + t2->ang[0][2]*f2ness; result[3] = t1->org[0]*f1ness + t2->org[0]*f2ness; - result[4] = t1->ang[0][1]*f1ness + t2->ang[0][1]*f2ness; + result[4] = t1->ang[1][0]*f1ness + t2->ang[1][0]*f2ness; result[5] = t1->ang[1][1]*f1ness + t2->ang[1][1]*f2ness; - result[6] = t1->ang[2][1]*f1ness + t2->ang[2][1]*f2ness; + result[6] = t1->ang[1][2]*f1ness + t2->ang[1][2]*f2ness; result[7] = t1->org[1]*f1ness + t2->org[1]*f2ness; - result[8] = t1->ang[0][2]*f1ness + t2->ang[0][2]*f2ness; - result[9] = t1->ang[1][2]*f1ness + t2->ang[1][2]*f2ness; + result[8] = t1->ang[2][0]*f1ness + t2->ang[2][0]*f2ness; + result[9] = t1->ang[2][1]*f1ness + t2->ang[2][1]*f2ness; result[10] = t1->ang[2][2]*f1ness + t2->ang[2][2]*f2ness; result[11] = t1->org[2]*f1ness + t2->org[2]*f2ness; } @@ -3224,8 +3471,25 @@ int Mod_TagNumForName(model_t *model, char *name) return 0; } +int GLMod_SkinNumForName(model_t *model, char *name) +{ + int i; + galiasinfo_t *inf; + galiasskin_t *skin; + if (!model || model->type != mod_alias) + return -1; + inf = Mod_Extradata(model); + skin = (galiasskin_t*)((char*)inf+inf->ofsskins); + for (i = 0; i < inf->numskins; i++, skin++) + { + if (!strcmp(skin->name, name)) + return i; + } + + return -1; +} @@ -3336,6 +3600,7 @@ void GL_LoadQ3Model(model_t *mod, void *buffer) int size; + int externalskins; md3Header_t *header; md3Surface_t *surf; @@ -3355,6 +3620,8 @@ void GL_LoadQ3Model(model_t *mod, void *buffer) parent = NULL; root = NULL; + externalskins = GL_BuildSkinFileList(mod->name); + min[0] = min[1] = min[2] = 0; max[0] = max[1] = max[2] = 0; @@ -3369,7 +3636,6 @@ void GL_LoadQ3Model(model_t *mod, void *buffer) galias->groups = header->numFrames; galias->numverts = surf->numVerts; galias->numindexes = surf->numTriangles*3; - galias->numskins = 1; if (parent) parent->nextsurf = (qbyte *)galias - (qbyte *)parent; else @@ -3450,17 +3716,19 @@ void GL_LoadQ3Model(model_t *mod, void *buffer) } #ifndef SERVERONLY - if (surf->numShaders) + if (surf->numShaders+externalskins) { #ifndef Q3SHADERS char name[1024]; extern int gl_bumpmappingpossible; #endif - skin = Hunk_Alloc(surf->numShaders*((sizeof(galiasskin_t)+sizeof(galiastexnum_t)))); + char shadname[1024]; + + skin = Hunk_Alloc((surf->numShaders+externalskins)*((sizeof(galiasskin_t)+sizeof(galiastexnum_t)))); galias->ofsskins = (qbyte *)skin - (qbyte *)galias; - texnum = (galiastexnum_t *)(skin + surf->numShaders); + texnum = (galiastexnum_t *)(skin + surf->numShaders+externalskins); inshader = (md3Shader_t *)((qbyte *)surf + surf->ofsShaders); - for (i = 0; i < surf->numShaders; i++) + for (i = 0; i < surf->numShaders+externalskins; i++) { skin->texnums = 1; skin->ofstexnums = (qbyte *)texnum - (qbyte *)skin; @@ -3469,41 +3737,53 @@ void GL_LoadQ3Model(model_t *mod, void *buffer) skin->skinheight = 0; skin->skinspeed = 0; - if (!*inshader->name) //'fix' the shader by looking the surface name up in a skin file. This isn't perfect, but it does the job for basic models. - GL_ParseQ3SkinFile(inshader->name, surf->name, loadmodel->name, 0); + if (i >= surf->numShaders) + shadname[0] = 0; + else + strcpy(shadname, inshader->name); + + if (!*shadname) //'fix' the shader by looking the surface name up in a skin file. This isn't perfect, but it does the job for basic models. + GL_ParseQ3SkinFile(shadname, surf->name, loadmodel->name, i, skin->name); + else + Q_strncpyz(skin->name, shadname, sizeof(skin->name)); + #ifdef Q3SHADERS - texnum->shader = R_RegisterSkin(inshader->name); + texnum->shader = R_RegisterSkin(shadname); + + if (r_shadows.value) //real-time shadows requires a texture to lighten the model with, even if it has a shader. + //fixme: this should be read from the shader. + texnum->base = Mod_LoadHiResTexture(shadname, "models", true, true, true); #else - texnum->base = Mod_LoadHiResTexture(inshader->name, "models", true, true, true); + texnum->base = Mod_LoadHiResTexture(shadname, "models", true, true, true); if (!texnum->base) { strcpy(name, loadmodel->name); - strcpy(COM_SkipPath(name), COM_SkipPath(inshader->name)); //eviile eh? + strcpy(COM_SkipPath(name), COM_SkipPath(shadname)); //eviile eh? texnum->base = Mod_LoadHiResTexture(name, "models", true, true, true); } texnum->bump = 0; if (gl_bumpmappingpossible) { - COM_StripExtension(inshader->name, name); //go for the normalmap + COM_StripExtension(shadname, name); //go for the normalmap strcat(name, "_norm"); texnum->bump = Mod_LoadHiResTexture(name, "models", true, true, false); if (!texnum->bump) { strcpy(name, loadmodel->name); - COM_StripExtension(COM_SkipPath(inshader->name), COM_SkipPath(name)); + COM_StripExtension(COM_SkipPath(shadname), COM_SkipPath(name)); strcat(name, "_norm"); texnum->bump = Mod_LoadHiResTexture(name, "models", true, true, false); if (!texnum->bump) { - COM_StripExtension(inshader->name, name); //bother, go for heightmap and convert + COM_StripExtension(shadname, name); //bother, go for heightmap and convert strcat(name, "_bump"); texnum->bump = Mod_LoadBumpmapTexture(name, "models"); if (!texnum->bump) { strcpy(name, loadmodel->name); - strcpy(COM_SkipPath(name), COM_SkipPath(inshader->name)); //eviile eh? + strcpy(COM_SkipPath(name), COM_SkipPath(shadname)); //eviile eh? COM_StripExtension(name, name); strcat(name, "_bump"); texnum->bump = Mod_LoadBumpmapTexture(name, "models"); @@ -3513,13 +3793,13 @@ void GL_LoadQ3Model(model_t *mod, void *buffer) } if (r_fb_models.value) { - COM_StripExtension(inshader->name, name); //go for the normalmap + COM_StripExtension(shadname, name); //go for the normalmap strcat(name, "_luma"); texnum->fullbright = Mod_LoadHiResTexture(name, "models", true, true, true); if (!texnum->base) { strcpy(name, loadmodel->name); - strcpy(COM_SkipPath(name), COM_SkipPath(inshader->name)); //eviile eh? + strcpy(COM_SkipPath(name), COM_SkipPath(shadname)); //eviile eh? COM_StripExtension(name, name); strcat(name, "_luma"); texnum->fullbright = Mod_LoadBumpmapTexture(name, "models"); @@ -3527,9 +3807,11 @@ void GL_LoadQ3Model(model_t *mod, void *buffer) } #endif + inshader++; skin++; texnum++; } + galias->numskins = i; } #endif @@ -3827,7 +4109,7 @@ void GLMod_LoadZymoticModel(model_t *mod, void *buffer) for (i = 0; i < header->numscenes; i++, grp++, inscene++) { - grp->isskeletal = 1; + grp->isheirachical = 1; grp->rate = BigFloat(inscene->framerate); grp->numposes = BigLong(inscene->length); grp->poseofs = (char*)matrix - (char*)grp; @@ -3876,5 +4158,778 @@ void GLMod_LoadZymoticModel(model_t *mod, void *buffer) mod->funcs.Trace = GLMod_Trace; } -#endif -#endif +#endif //ZYMOTICMODELS + +#ifdef MD5MODELS + +static void GenMatrix(float x, float y, float z, float qx, float qy, float qz, float result[12]) +{ + float qw; + { //figure out qw + float term = 1 - (qx*qx) - (qy*qy) - (qz*qz); + if (term < 0) + qw = 0; + else + qw = - (float) sqrt(term); + } + + { //generate the matrix + /* + float xx = qx * qx; + float xy = qx * qy; + float xz = qx * qz; + float xw = qx * qw; + float yy = qy * qy; + float yz = qy * qz; + float yw = qy * qw; + float zz = qz * qz; + float zw = qz * qw; + result[0*4+0] = 1 - 2 * ( yy + zz ); + result[0*4+1] = 2 * ( xy - zw ); + result[0*4+2] = 2 * ( xz + yw ); + result[0*4+3] = x; + result[1*4+0] = 2 * ( xy + zw ); + result[1*4+1] = 1 - 2 * ( xx + zz ); + result[1*4+2] = 2 * ( yz - xw ); + result[1*4+3] = y; + result[2*4+0] = 2 * ( xz - yw ); + result[2*4+1] = 2 * ( yz + xw ); + result[2*4+2] = 1 - 2 * ( xx + yy ); + result[2*4+3] = z; + */ + + float xx, xy, xz, xw, yy, yz, yw, zz, zw; + float x2, y2, z2; + x2 = qx + qx; + y2 = qy + qy; + z2 = qz + qz; + + xx = qx * x2; xy = qx * y2; xz = qx * z2; + yy = qy * y2; yz = qy * z2; zz = qz * z2; + xw = qw * x2; yw = qw * y2; zw = qw * z2; + + result[0*4+0] = 1.0f - (yy + zz); + result[1*4+0] = xy + zw; + result[2*4+0] = xz - yw; + + result[0*4+1] = xy - zw; + result[1*4+1] = 1.0f - (xx + zz); + result[2*4+1] = yz + xw; + + result[0*4+2] = xz + yw; + result[1*4+2] = yz - xw; + result[2*4+2] = 1.0f - (xx + yy); + + result[0*4+3] = x; + result[1*4+3] = y; + result[2*4+3] = z; + } +} + +galiasinfo_t *GLMod_ParseMD5MeshModel(char *buffer) +{ +#define EXPECT(x) buffer = COM_Parse(buffer); if (strcmp(com_token, x)) Sys_Error("MD5MESH: expected %s", x); + int numjoints = 0; + int nummeshes = 0; + qboolean foundjoints = false; + int meshnum = 0; + int i; + + galiasbone_t *bones; + galiasgroup_t *pose; + galiasinfo_t *inf, *root, *lastsurf; + float *posedata; + galiasskin_t *skin; + galiastexnum_t *texnum; + + float x, y, z, qx, qy, qz; + + + + buffer = COM_Parse(buffer); + if (strcmp(com_token, "MD5Version")) + Sys_Error("MD5 model without MD5Version identifier first\n"); + + buffer = COM_Parse(buffer); + if (atoi(com_token) != 10) + Sys_Error("MD5 model with unsupported MD5Version\n"); + + + root = Hunk_Alloc(sizeof(galiasinfo_t)); + lastsurf = NULL; + + for(;;) + { + buffer = COM_Parse(buffer); + if (!buffer) + break; + + if (!strcmp(com_token, "commandline")) + { //we don't need this + buffer = strchr(buffer, '\"'); + buffer = strchr((char*)buffer+1, '\"')+1; +// buffer = COM_Parse(buffer); + } + else if (!strcmp(com_token, "numJoints")) + { + if (numjoints) + Sys_Error("MD5MESH: numMeshes was already declared"); + buffer = COM_Parse(buffer); + numjoints = atoi(com_token); + if (numjoints <= 0) + Sys_Error("MD5MESH: Needs some joints"); + } + else if (!strcmp(com_token, "numMeshes")) + { + if (nummeshes) + Sys_Error("MD5MESH: numMeshes was already declared"); + buffer = COM_Parse(buffer); + nummeshes = atoi(com_token); + if (nummeshes <= 0) + Sys_Error("MD5MESH: Needs some meshes"); + } + else if (!strcmp(com_token, "joints")) + { + if (foundjoints) + Sys_Error("MD5MESH: Duplicate joints section"); + foundjoints=true; + if (!numjoints) + Sys_Error("MD5MESH: joints section before (or without) numjoints"); + + bones = Hunk_Alloc(sizeof(*bones) * numjoints); + pose = Hunk_Alloc(sizeof(galiasgroup_t)); + posedata = Hunk_Alloc(sizeof(float)*12 * numjoints); + pose->isheirachical = false; + pose->rate = 1; + pose->numposes = 1; + pose->poseofs = (char*)posedata - (char*)pose; + + EXPECT("{"); + //"name" parent (x y z) (s t u) + //stu are a normalized quaternion, which we will convert to a 3*4 matrix for no apparent reason + + for (i = 0; i < numjoints; i++) + { + buffer = COM_Parse(buffer); + Q_strncpyz(bones[i].name, com_token, sizeof(bones[i].name)); + buffer = COM_Parse(buffer); + bones[i].parent = atoi(com_token); + if (bones[i].parent >= i) + Sys_Error("MD5MESH: joints parent's must be lower"); + if ((bones[i].parent < 0 && i) || (!i && bones[i].parent!=-1)) + Sys_Error("MD5MESH: Only the root joint may have a negative parent"); + + EXPECT("("); + buffer = COM_Parse(buffer); + x = atof(com_token); + buffer = COM_Parse(buffer); + y = atof(com_token); + buffer = COM_Parse(buffer); + z = atof(com_token); + EXPECT(")"); + EXPECT("("); + buffer = COM_Parse(buffer); + qx = atof(com_token); + buffer = COM_Parse(buffer); + qy = atof(com_token); + buffer = COM_Parse(buffer); + qz = atof(com_token); + EXPECT(")"); + GenMatrix(x, y, z, qx, qy, qz, posedata+i*12); + } + EXPECT("}"); + } + else if (!strcmp(com_token, "mesh")) + { + int numverts = 0; + int numweights = 0; + int numtris = 0; + + int num; + int vnum; + + int numusableweights = 0; + int *firstweightlist = NULL; + int *numweightslist = NULL; + + galisskeletaltransforms_t *trans; + float *stcoord; + int *indexes; + float w; + + vec4_t *rawweight = NULL; + int *rawweightbone = NULL; + + + if (!nummeshes) + Sys_Error("MD5MESH: mesh section before (or without) nummeshes"); + if (!foundjoints) + Sys_Error("MD5MESH: mesh must come after joints"); + + if (!lastsurf) + { + lastsurf = root; + inf = root; + } + else + { + inf = Hunk_Alloc(sizeof(*inf)); + lastsurf->nextsurf = (char*)inf - (char*)lastsurf; + lastsurf = inf; + } + + skin = Hunk_Alloc(sizeof(*skin)); + texnum = Hunk_Alloc(sizeof(*texnum)); + + inf->ofsbones = (char*)bones - (char*)inf; + inf->numbones = numjoints; + inf->groups = 1; + inf->groupofs = (char*)pose - (char*)inf; + inf->numskins = 1; + inf->ofsskins = (char*)skin - (char*)inf; + skin->texnums = 1; + skin->skinspeed = 1; + skin->ofstexnums = (char*)texnum - (char*)skin; + EXPECT("{"); + for(;;) + { + buffer = COM_Parse(buffer); + if (!buffer) + Sys_Error("MD5MESH: unexpected eof"); + + if (!strcmp(com_token, "shader")) + { + buffer = COM_Parse(buffer); + // texnum->shader = R_RegisterSkin(com_token); + texnum->base = Mod_LoadHiResTexture(com_token, "models", true, true, true); + } + else if (!strcmp(com_token, "numverts")) + { + if (numverts) + Sys_Error("MD5MESH: numverts was already specified"); + buffer = COM_Parse(buffer); + numverts = atoi(com_token); + if (numverts < 0) + Sys_Error("MD5MESH: numverts cannot be negative"); + + firstweightlist = Z_Malloc(sizeof(*firstweightlist) * numverts); + numweightslist = Z_Malloc(sizeof(*numweightslist) * numverts); + stcoord = Hunk_Alloc(sizeof(float)*2*numverts); + inf->ofs_st_array = (char*)stcoord - (char*)inf; + inf->numverts = numverts; + } + else if (!strcmp(com_token, "vert")) + { //vert num ( s t ) firstweight numweights + + buffer = COM_Parse(buffer); + num = atoi(com_token); + if (num < 0 || num >= numverts) + Sys_Error("MD5MESH: vertex out of range"); + + EXPECT("("); + buffer = COM_Parse(buffer); + stcoord[num*2+0] = atof(com_token); + buffer = COM_Parse(buffer); + stcoord[num*2+1] = atof(com_token); + EXPECT(")"); + buffer = COM_Parse(buffer); + firstweightlist[num] = atoi(com_token); + buffer = COM_Parse(buffer); + numweightslist[num] = atoi(com_token); + + numusableweights += numweightslist[num]; + } + else if (!strcmp(com_token, "numtris")) + { + if (numtris) + Sys_Error("MD5MESH: numtris was already specified"); + buffer = COM_Parse(buffer); + numtris = atoi(com_token); + if (numtris < 0) + Sys_Error("MD5MESH: numverts cannot be negative"); + + indexes = Hunk_Alloc(sizeof(int)*3*numtris); + inf->ofs_indexes = (char*)indexes - (char*)inf; + inf->numindexes = numtris*3; + } + else if (!strcmp(com_token, "tri")) + { + buffer = COM_Parse(buffer); + num = atoi(com_token); + if (num < 0 || num >= numtris) + Sys_Error("MD5MESH: vertex out of range"); + + buffer = COM_Parse(buffer); + indexes[num*3+0] = atoi(com_token); + buffer = COM_Parse(buffer); + indexes[num*3+1] = atoi(com_token); + buffer = COM_Parse(buffer); + indexes[num*3+2] = atoi(com_token); + } + else if (!strcmp(com_token, "numweights")) + { + if (numweights) + Sys_Error("MD5MESH: numweights was already specified"); + buffer = COM_Parse(buffer); + numweights = atoi(com_token); + + rawweight = Z_Malloc(sizeof(*rawweight)*numweights); + rawweightbone = Z_Malloc(sizeof(*rawweightbone)*numweights); + } + else if (!strcmp(com_token, "weight")) + { + //weight num bone scale ( x y z ) + buffer = COM_Parse(buffer); + num = atoi(com_token); + if (num < 0 || num >= numweights) + Sys_Error("MD5MESH: weight out of range"); + + buffer = COM_Parse(buffer); + rawweightbone[num] = atoi(com_token); + if (rawweightbone[num] < 0 || rawweightbone[num] >= numjoints) + Sys_Error("MD5MESH: weight specifies bad bone"); + buffer = COM_Parse(buffer); + w = atof(com_token); + + EXPECT("("); + buffer = COM_Parse(buffer); + rawweight[num][0] = w*atof(com_token); + buffer = COM_Parse(buffer); + rawweight[num][1] = w*atof(com_token); + buffer = COM_Parse(buffer); + rawweight[num][2] = w*atof(com_token); + EXPECT(")"); + rawweight[num][3] = w; + } + else if (!strcmp(com_token, "}")) + break; + else + Sys_Error("MD5MESH: Unrecognised token inside mesh (%s)", com_token); + + } + + trans = Hunk_Alloc(sizeof(*trans)*numusableweights); + inf->ofstransforms = (char*)trans - (char*)inf; + + for (num = 0, vnum = 0; num < numverts; num++) + { + if (numweightslist[num] <= 0) + Sys_Error("MD5MESH: weights not set on vertex"); + while(numweightslist[num]) + { + trans[vnum].vertexindex = num; + trans[vnum].boneindex = rawweightbone[firstweightlist[num]]; + trans[vnum].org[0] = rawweight[firstweightlist[num]][0]; + trans[vnum].org[1] = rawweight[firstweightlist[num]][1]; + trans[vnum].org[2] = rawweight[firstweightlist[num]][2]; + trans[vnum].org[3] = rawweight[firstweightlist[num]][3]; + vnum++; + firstweightlist[num]++; + numweightslist[num]--; + } + } + inf->numtransforms = vnum; + + if (firstweightlist) + Z_Free(firstweightlist); + if (numweightslist) + Z_Free(numweightslist); + if (rawweight) + Z_Free(rawweight); + if (rawweightbone) + Z_Free(rawweightbone); + } + else + Sys_Error("Unrecognised token in MD5 model (%s)", com_token); + } + + if (!lastsurf) + Sys_Error("MD5MESH: No meshes"); + + return root; +#undef EXPECT +} + +void GLMod_LoadMD5MeshModel(model_t *mod, void *buffer) +{ + int numjoints = 0; + int nummeshes = 0; + qboolean foundjoints = false; + int meshnum = 0; + + galiasinfo_t *root; + int hunkstart, hunkend, hunktotal; + + + loadmodel=mod; + + Mod_DoCRC(mod, buffer, com_filesize); + + hunkstart = Hunk_LowMark (); + + + root = GLMod_ParseMD5MeshModel(buffer); + + + hunkend = Hunk_LowMark (); + + mod->flags = Mod_ReadFlagsFromMD1(mod->name, 0); //file replacement - inherit flags from any defunc mdl files. + + Hunk_Alloc(0); + hunktotal = hunkend - hunkstart; + + Cache_Alloc (&mod->cache, hunktotal, loadname); + mod->type = mod_alias; + if (!mod->cache.data) + { + Hunk_FreeToLowMark (hunkstart); + return; + } + memcpy (mod->cache.data, root, hunktotal); + + Hunk_FreeToLowMark (hunkstart); + + + mod->funcs.Trace = GLMod_Trace; +} + +galiasgroup_t GLMod_ParseMD5Anim(char *buffer, galiasinfo_t *prototype, void**poseofs) +{ +#define EXPECT(x) buffer = COM_Parse(buffer); if (strcmp(com_token, x)) Sys_Error("MD5ANIM: expected %s", x); + unsigned int i, j; + + galiasgroup_t grp; + + unsigned int parent; + unsigned int numframes; + unsigned int numjoints; + float framespersecond; + unsigned int numanimatedparts; + galiasbone_t *bonelist; + + unsigned char *boneflags; + unsigned int *firstanimatedcomponants; + + float *animatedcomponants; + float *baseframe; //6 componants. + float *posedata; + float tx, ty, tz, qx, qy, qz; + int fac, flags; + + EXPECT("MD5Version"); + EXPECT("10"); + + EXPECT("commandline"); + buffer = COM_Parse(buffer); + + EXPECT("numFrames"); + buffer = COM_Parse(buffer); + numframes = atoi(com_token); + + EXPECT("numJoints"); + buffer = COM_Parse(buffer); + numjoints = atoi(com_token); + + EXPECT("frameRate"); + buffer = COM_Parse(buffer); + framespersecond = atof(com_token); + + EXPECT("numAnimatedComponents"); + buffer = COM_Parse(buffer); + numanimatedparts = atoi(com_token); + + firstanimatedcomponants = BZ_Malloc(sizeof(int)*numjoints); + animatedcomponants = BZ_Malloc(sizeof(float)*numanimatedparts); + boneflags = BZ_Malloc(sizeof(unsigned char)*numjoints); + baseframe = BZ_Malloc(sizeof(float)*12*numjoints); + + *poseofs = posedata = Hunk_Alloc(sizeof(float)*12*numjoints*numframes); + + if (prototype) + { + if (prototype->numbones != numjoints) + Sys_Error("MD5ANIM: number of bones doesn't match"); + bonelist = (char*)prototype + prototype->ofsbones; + } + else + { + bonelist = Hunk_Alloc(sizeof(galiasbone_t)*numjoints); + prototype->ofsbones = (char*)bonelist - (char*)prototype; + prototype->numbones = numjoints; + } + + EXPECT("hierarchy"); + EXPECT("{"); + for (i = 0; i < numjoints; i++, bonelist++) + { + buffer = COM_Parse(buffer); + if (prototype) + { + if (strcmp(bonelist->name, com_token)) + Sys_Error("MD5ANIM: bone name doesn't match (%s)", com_token); + } + else + Q_strncpyz(bonelist->name, com_token, sizeof(bonelist->name)); + buffer = COM_Parse(buffer); + parent = atoi(com_token); + if (prototype) + { + if (bonelist->parent != parent) + Sys_Error("MD5ANIM: bone name doesn't match (%s)", com_token); + } + else + bonelist->parent = parent; + + buffer = COM_Parse(buffer); + boneflags[i] = atoi(com_token); + buffer = COM_Parse(buffer); + firstanimatedcomponants[i] = atoi(com_token); + } + EXPECT("}"); + + EXPECT("bounds"); + EXPECT("{"); + for (i = 0; i < numframes; i++) + { + EXPECT("("); + buffer = COM_Parse(buffer); + buffer = COM_Parse(buffer); + buffer = COM_Parse(buffer); + EXPECT(")"); + EXPECT("("); + buffer = COM_Parse(buffer); + buffer = COM_Parse(buffer); + buffer = COM_Parse(buffer); + EXPECT(")"); + } + EXPECT("}"); + + EXPECT("baseframe"); + EXPECT("{"); + for (i = 0; i < numjoints; i++) + { + EXPECT("("); + buffer = COM_Parse(buffer); + baseframe[i*6+0] = atof(com_token); + buffer = COM_Parse(buffer); + baseframe[i*6+1] = atof(com_token); + buffer = COM_Parse(buffer); + baseframe[i*6+2] = atof(com_token); + EXPECT(")"); + EXPECT("("); + buffer = COM_Parse(buffer); + baseframe[i*6+3] = atof(com_token); + buffer = COM_Parse(buffer); + baseframe[i*6+4] = atof(com_token); + buffer = COM_Parse(buffer); + baseframe[i*6+5] = atof(com_token); + EXPECT(")"); + } + EXPECT("}"); + + for (i = 0; i < numframes; i++) + { + EXPECT("frame"); + EXPECT(va("%i", i)); + EXPECT("{"); + for (j = 0; j < numanimatedparts; j++) + { + buffer = COM_Parse(buffer); + animatedcomponants[j] = atof(com_token); + } + EXPECT("}"); + + for (j = 0; j < numjoints; j++) + { + fac = firstanimatedcomponants[j]; + flags = boneflags[j]; + + if (flags&1) + tx = animatedcomponants[fac++]; + else + tx = baseframe[j*6+0]; + if (flags&2) + ty = animatedcomponants[fac++]; + else + ty = baseframe[j*6+1]; + if (flags&4) + tz = animatedcomponants[fac++]; + else + tz = baseframe[j*6+2]; + if (flags&8) + qx = animatedcomponants[fac++]; + else + qx = baseframe[j*6+3]; + if (flags&16) + qy = animatedcomponants[fac++]; + else + qy = baseframe[j*6+4]; + if (flags&32) + qz = animatedcomponants[fac++]; + else + qz = baseframe[j*6+5]; + + GenMatrix(tx, ty, tz, qx, qy, qz, posedata+12*(j+numjoints*i)); + } + } + + BZ_Free(firstanimatedcomponants); + BZ_Free(animatedcomponants); + BZ_Free(boneflags); + BZ_Free(baseframe); + + grp.isheirachical = true; + grp.numposes = numframes; + grp.rate = framespersecond; + + return grp; +#undef EXPECT +} + +/* +EXTERNALANIM + +//File what specifies md5 model/anim stuff. + +model test/imp.md5mesh + +group test/idle1.md5anim +clampgroup test/idle1.md5anim +frames test/idle1.md5anim + +*/ +void GLMod_LoadCompositeAnim(model_t *mod, void *buffer) +{ + #define EXPECT(x) buffer = COM_Parse(buffer); if (strcmp(com_token, x)) Sys_Error("MD5MESH: expected %s", x); + int numjoints = 0; + int nummeshes = 0; + qboolean foundjoints = false; + int meshnum = 0; + int i; + + char *file; + galiasinfo_t *root = NULL; + int numgroups = 0; + galiasgroup_t *grouplist = NULL; + galiasgroup_t *newgroup = NULL; + void **poseofs; + int hunkstart, hunkend, hunktotal; + + + loadmodel=mod; + + Mod_DoCRC(mod, buffer, com_filesize); + + hunkstart = Hunk_LowMark (); + + + + + buffer = COM_Parse(buffer); + if (strcmp(com_token, "EXTERNALANIM")) + Sys_Error("EXTERNALANIM: header is not compleate"); + + buffer = COM_Parse(buffer); + if (!strcmp(com_token, "model")) + { + buffer = COM_Parse(buffer); + file = COM_LoadTempFile2(com_token); + + if (!file) //FIXME: make non fatal somehow.. + Sys_Error("Couldn't open %s", com_token); + + root = GLMod_ParseMD5MeshModel(file); + newgroup = (galiasgroup_t*)((char*)root + root->groupofs); + + grouplist = BZ_Malloc(sizeof(galiasgroup_t)*(numgroups+root->groups)); + memcpy(grouplist, newgroup, sizeof(galiasgroup_t)*(numgroups+root->groups)); + poseofs = BZ_Malloc(sizeof(galiasgroup_t)*(numgroups+root->groups)); + for (i = 0; i < root->groups; i++) + { + grouplist[numgroups] = newgroup[i]; + poseofs[numgroups] = (char*)&newgroup[i] + newgroup[i].poseofs; + numgroups++; + } + } + else + { + Sys_Error("EXTERNALANIM: model must be defined immediatly after the header"); + return; + } + for (;;) + { + buffer = COM_Parse(buffer); + if (!buffer) + break; + + if (!strcmp(com_token, "group")) + { + grouplist = BZ_Realloc(grouplist, sizeof(galiasgroup_t)*(numgroups+1)); + poseofs = BZ_Realloc(poseofs, sizeof(*poseofs)*(numgroups+1)); + buffer = COM_Parse(buffer); + file = COM_LoadTempFile2(com_token); + if (file) //FIXME: make non fatal somehow.. + { + grouplist[numgroups] = GLMod_ParseMD5Anim(file, root, &poseofs[numgroups]); + numgroups++; + } + } + else if (!strcmp(com_token, "clampgroup")) + { + Sys_Error("EXTERNALANIM: clampgroup not yet supported"); + return; + } + else if (!strcmp(com_token, "frames")) + { + Sys_Error("EXTERNALANIM: frames not yet supported"); + return; + } + else + { + Sys_Error("EXTERNALANIM: unrecognised token"); + return; + } + } + + newgroup = grouplist; + grouplist = Hunk_Alloc(sizeof(galiasgroup_t)*numgroups); + for(;;) + { + root->groupofs = (char*)grouplist - (char*)root; + root->groups = numgroups; + if (!root->nextsurf) + break; + root = (char*)root + root->nextsurf; + } + for (i = 0; i < numgroups; i++) + { + grouplist[i] = newgroup[i]; + grouplist[i].poseofs = (char*)poseofs[i] - (char*)&grouplist[i]; + } + + + hunkend = Hunk_LowMark (); + + mod->flags = Mod_ReadFlagsFromMD1(mod->name, 0); //file replacement - inherit flags from any defunc mdl files. + + Hunk_Alloc(0); + hunktotal = hunkend - hunkstart; + + Cache_Alloc (&mod->cache, hunktotal, loadname); + mod->type = mod_alias; + if (!mod->cache.data) + { + Hunk_FreeToLowMark (hunkstart); + return; + } + memcpy (mod->cache.data, root, hunktotal); + + Hunk_FreeToLowMark (hunkstart); + + + mod->funcs.Trace = GLMod_Trace; +} + +#endif //MD5MODELS + +#endif // defined(RGLQUAKE) || defined(SERVERONLY) diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index 9fe3cda38..abeaa5fc1 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -1442,6 +1442,60 @@ void GLDraw_Pic (int x, int y, mpic_t *pic) GL_DrawMesh(&draw_mesh, gl->texnum); } +#ifdef Q3SHADERS +void GLDraw_ShaderPic (int x, int y, int width, int height, shader_t *pic, float r, float g, float b, float a) +{ + meshbuffer_t mb; + + if (!pic) + return; + + R_IBrokeTheArrays(); + + mb.entity = &r_worldentity; + mb.shader = pic; + mb.fog = NULL; + mb.mesh = &draw_mesh; + mb.infokey = 0; + mb.dlightbits = 0; + + + draw_mesh_xyz[0][0] = x; + draw_mesh_xyz[0][1] = y; + draw_mesh_st[0][0] = 0; + draw_mesh_st[0][1] = 0; + + draw_mesh_xyz[1][0] = x+width; + draw_mesh_xyz[1][1] = y; + draw_mesh_st[1][0] = 1; + draw_mesh_st[1][1] = 0; + + draw_mesh_xyz[2][0] = x+width; + draw_mesh_xyz[2][1] = y+height; + draw_mesh_st[2][0] = 1; + draw_mesh_st[2][1] = 1; + + draw_mesh_xyz[3][0] = x; + draw_mesh_xyz[3][1] = y+height; + draw_mesh_st[3][0] = 0; + draw_mesh_st[3][1] = 1; + + draw_mesh_colors[0][0] = r*255; + draw_mesh_colors[0][1] = g*255; + draw_mesh_colors[0][2] = b*255; + draw_mesh_colors[0][3] = a*255; + ((int*)draw_mesh_colors)[1] = ((int*)draw_mesh_colors)[0]; + ((int*)draw_mesh_colors)[2] = ((int*)draw_mesh_colors)[0]; + ((int*)draw_mesh_colors)[3] = ((int*)draw_mesh_colors)[0]; + + draw_mesh.colors_array = draw_mesh_colors; + + R_PushMesh(&draw_mesh, mb.shader->features | MF_COLORS | MF_NONBATCHED); + R_RenderMeshBuffer ( &mb, false ); + draw_mesh.colors_array = NULL; +} +#endif + void GLDraw_ScalePic (int x, int y, int width, int height, mpic_t *pic) { glpic_t *gl; @@ -2903,7 +2957,7 @@ unsigned int * genNormalMap(qbyte *pixels, int w, int h, float scale) /* The highest resolution mipmap level always has a unit length magnitude. */ - nmap[i*w+j] = LittleLong ((255 << 24)|(b << 16)|(g << 8)|(r)); // Added support for big endian. + nmap[i*w+j] = LittleLong ((pixels[i*wr + j] << 24)|(b << 16)|(g << 8)|(r)); // Added support for big endian. } } @@ -2911,7 +2965,7 @@ unsigned int * genNormalMap(qbyte *pixels, int w, int h, float scale) } //PENTA -void GL_UploadBump(qbyte *data, int width, int height, qboolean mipmap) +void GL_UploadBump(qbyte *data, int width, int height, qboolean mipmap, float bumpscale) { unsigned char *scaled = uploadmemorybuffer; int scaled_width, scaled_height; @@ -2938,10 +2992,7 @@ void GL_UploadBump(qbyte *data, int width, int height, qboolean mipmap) GL_Resample8BitTexture (data, width, height, scaled, scaled_width, scaled_height); } -// if (is_overriden) -// nmap = (qbyte *)genNormalMap(scaled,scaled_width,scaled_height,10.0f); -// else - nmap = (qbyte *)genNormalMap(scaled,scaled_width,scaled_height,4.0f); + nmap = (qbyte *)genNormalMap(scaled,scaled_width,scaled_height,bumpscale); qglTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA , scaled_width, scaled_height, 0, @@ -3563,7 +3614,7 @@ int GL_LoadTexture8Grey (char *identifier, int width, int height, unsigned char return texture_extension_number-1; } -int GL_LoadTexture8Bump (char *identifier, int width, int height, unsigned char *data, qboolean mipmap) +int GL_LoadTexture8Bump (char *identifier, int width, int height, unsigned char *data, qboolean mipmap, float bumpscale) { // qboolean noalpha; // int p, s; @@ -3599,7 +3650,7 @@ int GL_LoadTexture8Bump (char *identifier, int width, int height, unsigned char { GL_Bind(texture_extension_number ); - GL_UploadBump (data, width, height, mipmap); + GL_UploadBump (data, width, height, mipmap, bumpscale); } texture_extension_number++; diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 3a68bfa17..af1530b1f 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -30,6 +30,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "shader.h" #endif +extern cvar_t r_shadow_bumpscale_basetexture; extern int gl_bumpmappingpossible; qboolean isnotmap = true; //used to not warp ammo models. @@ -57,6 +58,9 @@ void Mod_LoadGroupModel (model_t *mod, void *buffer); #ifdef ZYMOTICMODELS void GLMod_LoadZymoticModel(model_t *mod, void *buffer); #endif +#ifdef MD5MODELS +void GLMod_LoadMD5MeshModel(model_t *mod, void *buffer); +#endif model_t *GLMod_LoadModel (model_t *mod, qboolean crash); #ifdef DOOMWADS @@ -678,8 +682,23 @@ couldntload: break; #endif default: - Con_Printf("Unrecognised model format %i\n", LittleLong(*(unsigned *)buf)); - goto couldntload; + //check for text based headers + COM_Parse((char*)buf); + if (!strcmp(com_token, "MD5Version")) + { + GLMod_LoadMD5MeshModel (mod, buf); + break; + } + else if (!strcmp(com_token, "EXTERNALANIM")) + { + GLMod_LoadCompositeAnim (mod, buf); + break; + } + else + { + Con_Printf("Unrecognised model format %i\n", LittleLong(*(unsigned *)buf)); + goto couldntload; + } } P_DefaultTrail(mod); @@ -1060,7 +1079,7 @@ TRACE(("dbg: GLMod_LoadTextures: inittexturedescs\n")); for (j = 0; j < pixels; j++) base[j] = (host_basepal[base[j]*3] + host_basepal[base[j]*3+1] + host_basepal[base[j]*3+2]) / 3; - tx->gl_texturenumbumpmap = GL_LoadTexture8Bump(altname, tx->width, tx->height, base, true); //normalise it and then bump it. + tx->gl_texturenumbumpmap = GL_LoadTexture8Bump(altname, tx->width, tx->height, base, true, r_shadow_bumpscale_basetexture.value); //normalise it and then bump it. } //don't do any complex quake 8bit -> glossmap. It would likly look a little ugly... @@ -1187,7 +1206,6 @@ TRACE(("dbg: GLMod_LoadTextures: inittexturedescs\n")); } } -int GL_LoadTexture8Bump (char *identifier, int width, int height, unsigned char *data, qboolean mipmap); void GLMod_NowLoadExternal(void) { extern int gl_bumpmappingpossible; @@ -1247,7 +1265,7 @@ void GLMod_NowLoadExternal(void) *heightmap++ = (data[j*4+0] + data[j*4+1] + data[j*4+2])/3; } - tx->gl_texturenumbumpmap = GL_LoadTexture8Bump (va("%s_bump", tx->name), width, height, heightmap-j, true); + tx->gl_texturenumbumpmap = GL_LoadTexture8Bump (va("%s_bump", tx->name), width, height, heightmap-j, true, r_shadow_bumpscale_basetexture.value); } } } diff --git a/engine/gl/gl_ppl.c b/engine/gl/gl_ppl.c index 0196fb2cd..70c294663 100644 --- a/engine/gl/gl_ppl.c +++ b/engine/gl/gl_ppl.c @@ -1,3 +1,7 @@ +//FIXME: Light visibility is decided from weather the light's pvs overlaps the view pvs. +//This doesn't take light radius into account. This means that lights around corners that will never be visible are drawn in full per-pixel goodness. +//This is bad. lights*3, 33% framerate for no worthwhile effect. + #include "quakedef.h" #ifdef RGLQUAKE #include "glquake.h" @@ -9,6 +13,13 @@ void GL_SelectTexture (GLenum target); void R_RenderDynamicLightmaps (msurface_t *fa); void R_BlendLightmaps (void); + +void PPL_BeginShadowMesh(dlight_t *dl); +void PPL_FinishShadowMesh(dlight_t *dl); +void PPL_FlushShadowMesh(dlight_t *dl); +void PPL_Shadow_Cache_Surface(msurface_t *surf); //only caches for lighting +void PPL_Shadow_Cache_Leaf(mleaf_t *leaf); + extern qboolean r_inmirror; extern int gldepthfunc; extern int *lightmap_textures; @@ -23,6 +34,10 @@ extern cvar_t gl_part_flame; extern cvar_t gl_part_flame; extern cvar_t gl_maxshadowlights; extern cvar_t r_shadow_realtime_world; +extern cvar_t r_shadow_realtime_world_lightmaps; +extern cvar_t r_shadow_glsl_offsetmapping; +extern cvar_t r_shadow_glsl_offsetmapping_scale; +extern cvar_t r_shadow_glsl_offsetmapping_bias; extern int detailtexture; extern cvar_t gl_bump; extern cvar_t gl_specular; @@ -33,6 +48,8 @@ extern cvar_t r_drawflat; extern cvar_t r_wallcolour; extern cvar_t r_floorcolour; +float r_lightmapintensity; //1 or r_shadow_realtime_world_lightmaps + int overbright; extern lightmapinfo_t **lightmap; @@ -78,11 +95,21 @@ qboolean PPL_ShouldDraw(void) return true; } - +typedef struct { + int count; + msurface_t **s; +} shadowmeshsurfs_t; typedef struct shadowmesh_s { int numindicies; + int numverts; int *indicies; vec3_t *verts; + + //we also have a list of all the surfaces that this light lights. + int numsurftextures; + shadowmeshsurfs_t *litsurfs; + + unsigned char *litleaves; } shadowmesh_t; @@ -1137,29 +1164,44 @@ static void PPL_BaseChain_Flat(msurface_t *first) int vi=-10; glRect_t *theRect; - if (r_wallcolour.modified) - { - char *s; - r_wallcolour.modified = false; + if (!r_lightmapintensity) + { //these are bad. :( - s = COM_Parse(r_wallcolour.string); - wallcolour[0] = atof(com_token); - s = COM_Parse(s); - wallcolour[1] = atof(com_token); - s = COM_Parse(s); - wallcolour[2] = atof(com_token); + PPL_EnableVertexArrays(); + qglColor4f(0,0,0,1); + qglDisable(GL_TEXTURE_2D); //texturing? who wants texturing?!?! + for (s = first; s ; s=s->texturechain) + PPL_GenerateArrays(s); + PPL_FlushArrays(); + qglEnable(GL_TEXTURE_2D); //texturing? who wants texturing?!?! + return; } - if (r_floorcolour.modified) + else { - char *s; - r_floorcolour.modified = false; + if (r_wallcolour.modified) + { + char *s; + r_wallcolour.modified = false; - s = COM_Parse(r_floorcolour.string); - floorcolour[0] = atof(com_token); - s = COM_Parse(s); - floorcolour[1] = atof(com_token); - s = COM_Parse(s); - floorcolour[2] = atof(com_token); + s = COM_Parse(r_wallcolour.string); + wallcolour[0] = atof(com_token); + s = COM_Parse(s); + wallcolour[1] = atof(com_token); + s = COM_Parse(s); + wallcolour[2] = atof(com_token); + } + if (r_floorcolour.modified) + { + char *s; + r_floorcolour.modified = false; + + s = COM_Parse(r_floorcolour.string); + floorcolour[0] = atof(com_token); + s = COM_Parse(s); + floorcolour[1] = atof(com_token); + s = COM_Parse(s); + floorcolour[2] = atof(com_token); + } } PPL_EnableVertexArrays(); @@ -1349,7 +1391,7 @@ static void PPL_BaseChain_NPR_Sketch(msurface_t *first) static void PPL_BaseTextureChain(msurface_t *first) { texture_t *t; - if (r_drawflat.value) + if (r_drawflat.value||!r_lightmapintensity) { if (r_drawflat.value == 2) { @@ -1831,8 +1873,14 @@ void PPL_BaseEntTextures(void) switch (currententity->model->type) { + //FIXME: We want to depth sort with particles, but we also want depth. :( + //Until then, we have broken model lighting. case mod_alias: - RQ_AddDistReorder(PPL_DrawEnt, currententity, NULL, currententity->origin); +// R_DrawGAliasModel (currententity); + if (currententity->flags & Q2RF_WEAPONMODEL) + RQ_AddDistReorder(PPL_DrawEnt, currententity, NULL, r_refdef.vieworg); + else + RQ_AddDistReorder(PPL_DrawEnt, currententity, NULL, currententity->origin); break; case mod_brush: @@ -1893,6 +1941,10 @@ PERMUTATION_GENERIC = 0, PERMUTATION_BUMPMAP = 1, PERMUTATION_SPECULAR = 2, PERMUTATION_BUMP_SPEC = 3, +PERMUTATION_OFFSET = 4, +PERMUTATION_OFFSET_BUMP = 5, +PERMUTATION_OFFSET_SPEC = 6, +PERMUTATION_OFFSET_BUMP_SPEC = 7, PERMUTATIONS }; @@ -1901,6 +1953,8 @@ int ppl_light_shader_eyeposition[PERMUTATIONS]; int ppl_light_shader_lightposition[PERMUTATIONS]; int ppl_light_shader_lightcolour[PERMUTATIONS]; int ppl_light_shader_lightradius[PERMUTATIONS]; +int ppl_light_shader_offset_scale[PERMUTATIONS]; +int ppl_light_shader_offset_bias[PERMUTATIONS]; void PPL_CreateLightTexturesProgram(void) { @@ -1910,7 +1964,11 @@ void PPL_CreateLightTexturesProgram(void) "", "#define BUMP\n", "#define SPECULAR\n", - "#define SPECULAR\n#define BUMP\n" + "#define SPECULAR\n#define BUMP\n", + "#define USEOFFSETMAPPING\n", + "#define USEOFFSETMAPPING\n#define BUMP\n", + "#define USEOFFSETMAPPING\n#define SPECULAR\n", + "#define USEOFFSETMAPPING\n#define SPECULAR\n#define BUMP\n" }; char *vert = "varying vec2 tcbase;\n" @@ -1918,7 +1976,7 @@ void PPL_CreateLightTexturesProgram(void) "varying vec3 LightVector;\n" "uniform vec3 LightPosition;\n" - "#ifdef SPECULAR\n" + "#if defined(SPECULAR) || defined(USEOFFSETMAPPING)\n" "uniform vec3 EyePosition;\n" "varying vec3 EyeVector;\n" "#endif\n" @@ -1934,7 +1992,7 @@ void PPL_CreateLightTexturesProgram(void) " LightVector.y = dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n" " LightVector.z = dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n" - "#ifdef SPECULAR\n" + "#if defined(SPECULAR)||defined(USEOFFSETMAPPING)\n" " vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;\n" " EyeVector.x = dot(eyeminusvertex, gl_MultiTexCoord1.xyz);\n" " EyeVector.y = dot(eyeminusvertex, gl_MultiTexCoord2.xyz);\n" @@ -1945,7 +2003,7 @@ void PPL_CreateLightTexturesProgram(void) char *frag = "uniform sampler2D baset;\n" - "#if defined(BUMP) || defined(SPECULAR)\n" + "#if defined(BUMP) || defined(SPECULAR) || defined(USEOFFSETMAPPING)\n" "uniform sampler2D bumpt;\n" "#endif\n" "#ifdef SPECULAR\n" @@ -1958,13 +2016,28 @@ void PPL_CreateLightTexturesProgram(void) "uniform float lightradius;\n" "uniform vec3 LightColour;\n" - "#ifdef SPECULAR\n" + "#if defined(SPECULAR) || defined(USEOFFSETMAPPING)\n" "varying vec3 EyeVector;\n" "#endif\n" +"#ifdef USEOFFSETMAPPING\n" +"uniform float OffsetMapping_Scale;\n" +"uniform float OffsetMapping_Bias;\n" +"#endif\n" + "void main (void)\n" "{\n" +"#ifdef USEOFFSETMAPPING\n" +" // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n" +" vec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n" +" vec2 TexCoordOffset = tcbase + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(bumpt, tcbase).w);\n" +" TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(bumpt, TexCoordOffset).w);\n" +" TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(bumpt, TexCoordOffset).w);\n" +"#define tcbase TexCoordOffset\n" +"#endif\n" + + "#ifdef BUMP\n" " vec3 bases = vec3(texture2D(baset, tcbase));\n" "#else\n" @@ -2009,12 +2082,129 @@ void PPL_CreateLightTexturesProgram(void) ppl_light_shader_lightposition [i]= qglGetUniformLocationARB(ppl_light_shader[i], "LightPosition"); ppl_light_shader_lightcolour[i] = qglGetUniformLocationARB(ppl_light_shader[i], "LightColour"); ppl_light_shader_lightradius[i] = qglGetUniformLocationARB(ppl_light_shader[i], "lightradius"); + ppl_light_shader_offset_scale[i] = qglGetUniformLocationARB(ppl_light_shader[i], "OffsetMapping_Scale"); + ppl_light_shader_offset_bias[i] = qglGetUniformLocationARB(ppl_light_shader[i], "OffsetMapping_Bias"); GLSlang_UseProgram(0); } } }; + +void PPL_LightTexturesFP_Cached(model_t *model, vec3_t modelorigin, dlight_t *light, vec3_t colour) +{ + int i, j; + texture_t *t; + msurface_t *s; + int p, lp=-1; + extern cvar_t gl_specular; + shadowmesh_t *shm = light->worldshadowmesh; + + + vec3_t relativelightorigin; + vec3_t relativeeyeorigin; + + if (qglGetError()) + Con_Printf("GL Error before lighttextures\n"); + + VectorSubtract(light->origin, modelorigin, relativelightorigin); + VectorSubtract(r_refdef.vieworg, modelorigin, relativeeyeorigin); + + qglEnable(GL_BLEND); + GL_TexEnv(GL_MODULATE); + qglBlendFunc(GL_ONE, GL_ONE); + qglDisableClientState(GL_COLOR_ARRAY); + if (qglGetError()) + Con_Printf("GL Error early in lighttextures\n"); + + for (j=0 ; jnumsurftextures ; j++) + { + if (!shm->litsurfs[j].count) + continue; + + s = shm->litsurfs[j].s[0]; + t = s->texinfo->texture; + t = GLR_TextureAnimation (t); + + for (i=0 ; ilitsurfs[j].count ; i++) + { + s = shm->litsurfs[j].s[i]; + + if (s->visframe != r_framecount) + continue; + + if (s->flags & SURF_PLANEBACK) + {//inverted normal. + if (DotProduct(s->plane->normal, relativelightorigin)-s->plane->dist > lightradius) + continue; + } + else + { + if (-DotProduct(s->plane->normal, relativelightorigin)+s->plane->dist > lightradius) + continue; + } + + // if ((s->flags & SURF_DRAWTURB) && r_wateralphaval != 1.0) + // continue; // draw translucent water later + + + + p = 0; + if (t->gl_texturenumbumpmap && ppl_light_shader[p|PERMUTATION_BUMPMAP]) + p |= PERMUTATION_BUMPMAP; + if (gl_specular.value && t->gl_texturenumspec && ppl_light_shader[p|PERMUTATION_SPECULAR]) + p |= PERMUTATION_SPECULAR; + if (r_shadow_glsl_offsetmapping.value && t->gl_texturenumbumpmap && ppl_light_shader[p|PERMUTATION_OFFSET]) + p |= PERMUTATION_OFFSET; + + if (p != lp) + { + lp = p; + GLSlang_UseProgram(ppl_light_shader[p]); + if (ppl_light_shader_eyeposition[p] != -1) + qglUniform3fvARB(ppl_light_shader_eyeposition[p], 1, relativeeyeorigin); + qglUniform3fvARB(ppl_light_shader_lightposition[p], 1, relativelightorigin); + qglUniform3fvARB(ppl_light_shader_lightcolour[p], 1, colour); + qglUniform1fARB(ppl_light_shader_lightradius[p], light->radius); + + if (ppl_light_shader_offset_scale[p]!=-1) + qglUniform1fARB(ppl_light_shader_offset_scale[p], r_shadow_glsl_offsetmapping_scale.value); + if (ppl_light_shader_offset_bias[p]!=-1) + qglUniform1fARB(ppl_light_shader_offset_bias[p], r_shadow_glsl_offsetmapping_bias.value); + } + + + if (p & PERMUTATION_BUMPMAP) + GL_MBind(GL_TEXTURE1_ARB, t->gl_texturenumbumpmap); + if (p & PERMUTATION_SPECULAR) + GL_MBind(GL_TEXTURE2_ARB, t->gl_texturenumspec); + + GL_MBind(GL_TEXTURE0_ARB, t->gl_texturenum); + qglEnableClientState(GL_TEXTURE_COORD_ARRAY); + + + + qglMultiTexCoord3fARB(GL_TEXTURE1_ARB, s->texinfo->vecs[0][0], s->texinfo->vecs[0][1], s->texinfo->vecs[0][2]); + qglMultiTexCoord3fARB(GL_TEXTURE2_ARB, -s->texinfo->vecs[1][0], -s->texinfo->vecs[1][1], -s->texinfo->vecs[1][2]); + + if (s->flags & SURF_PLANEBACK) + qglMultiTexCoord3fARB(GL_TEXTURE3_ARB, -s->plane->normal[0], -s->plane->normal[1], -s->plane->normal[2]); + else + qglMultiTexCoord3fARB(GL_TEXTURE3_ARB, s->plane->normal[0], s->plane->normal[1], s->plane->normal[2]); + + qglTexCoordPointer(2, GL_FLOAT, 0, s->mesh->st_array); + + qglVertexPointer(3, GL_FLOAT, 0, s->mesh->xyz_array); + qglDrawElements(GL_TRIANGLES, s->mesh->numindexes, GL_UNSIGNED_INT, s->mesh->indexes); + } + } + GLSlang_UseProgram(0); + qglDisableClientState(GL_TEXTURE_COORD_ARRAY); + + if (qglGetError()) + Con_Printf("GL Error during lighttextures\n"); +} + void PPL_LightTexturesFP(model_t *model, vec3_t modelorigin, dlight_t *light, vec3_t colour) { int i; @@ -2128,7 +2318,10 @@ void PPL_LightTextures(model_t *model, vec3_t modelorigin, dlight_t *light, vec3 if (ppl_light_shader[0]) { - PPL_LightTexturesFP(model, modelorigin, light, colour); + if (model == cl.worldmodel && light->worldshadowmesh) + PPL_LightTexturesFP_Cached(model, modelorigin, light, colour); + else + PPL_LightTexturesFP(model, modelorigin, light, colour); return; } @@ -2934,6 +3127,27 @@ qboolean PPL_VisOverlaps(qbyte *v1, qbyte *v2) } return false; } +qboolean PPL_LeafInView(qbyte *lightvis) +{ + int i; + int m = (cl.worldmodel->numleafs+7)/8; + mleaf_t *wl = cl.worldmodel->leafs; + unsigned char lv; + for (i = 0; i < m; i++) + { + lv = lightvis[i]; + if (lv&1 && wl[(i<<3)+0].visframe == r_visframecount) return true; + if (lv&2 && wl[(i<<3)+1].visframe == r_visframecount) return true; + if (lv&4 && wl[(i<<3)+2].visframe == r_visframecount) return true; + if (lv&8 && wl[(i<<3)+3].visframe == r_visframecount) return true; + if (lv&16 && wl[(i<<3)+4].visframe == r_visframecount) return true; + if (lv&32 && wl[(i<<3)+5].visframe == r_visframecount) return true; + if (lv&64 && wl[(i<<3)+6].visframe == r_visframecount) return true; + if (lv&128 && wl[(i<<3)+7].visframe == r_visframecount) return true; + } + + return false; +} void PPL_RecursiveWorldNode_r (mnode_t *node) { @@ -2967,6 +3181,7 @@ void PPL_RecursiveWorldNode_r (mnode_t *node) if (node->contents < 0) { pleaf = (mleaf_t *)node; + PPL_Shadow_Cache_Leaf(pleaf); mark = pleaf->firstmarksurface; c = pleaf->nummarksurfaces; @@ -3051,6 +3266,11 @@ void PPL_RecursiveWorldNode_r (mnode_t *node) fabs(surf->center[2] - lightorg[2]) > lightradius+surf->radius) continue; */ + + PPL_Shadow_Cache_Surface(surf); + + + #define PROJECTION_DISTANCE (float)(lightradius*2)//0x7fffffff //build a list of the edges that are to be drawn. @@ -3470,14 +3690,6 @@ void PPL_RecursiveWorldNode (dlight_t *dl) float *v1, *v2; vec3_t v3, v4; - if (dl->worldshadowmesh) - { - qglEnableClientState(GL_VERTEX_ARRAY); - qglVertexPointer(3, GL_FLOAT, 0, dl->worldshadowmesh->verts); - qglDrawElements(GL_TRIANGLES, dl->worldshadowmesh->numindicies, GL_UNSIGNED_INT, dl->worldshadowmesh->indicies); - return; - } - lightradius = dl->radius; lightorg[0] = dl->origin[0]+0.5; @@ -3488,6 +3700,17 @@ void PPL_RecursiveWorldNode (dlight_t *dl) modelorg[1] = lightorg[1]; modelorg[2] = lightorg[2]; + if (dl->worldshadowmesh) + { + qglEnableClientState(GL_VERTEX_ARRAY); + qglVertexPointer(3, GL_FLOAT, 0, dl->worldshadowmesh->verts); + qglDrawRangeElements(GL_TRIANGLES, 0, dl->worldshadowmesh->numverts, dl->worldshadowmesh->numindicies, GL_UNSIGNED_INT, dl->worldshadowmesh->indicies); + return; + } + + PPL_BeginShadowMesh(dl); + + qglEnableClientState(GL_VERTEX_ARRAY); if (qglGetError()) @@ -3579,6 +3802,8 @@ void PPL_RecursiveWorldNode (dlight_t *dl) varray_vc=0; firstedge=0; + + PPL_FinishShadowMesh(dl); } void PPL_DrawBrushModelShadow(dlight_t *dl, entity_t *e) @@ -3591,7 +3816,7 @@ void PPL_DrawBrushModelShadow(dlight_t *dl, entity_t *e) model_t *model; msurface_t *surf; - RotateLightVector(e->angles, e->origin, dl->origin, lightorg); + RotateLightVector(e->axis, e->origin, dl->origin, lightorg); qglPushMatrix(); R_RotateForEntity(e); @@ -3727,6 +3952,9 @@ void PPL_UpdateNodeShadowFrames(qbyte *lvis) int i; mnode_t *node; + if (!lvis) //using a cached light, we don't need shadowframes + return; + #ifdef Q3BSPS @@ -4025,7 +4253,7 @@ void CL_NewDlight (int key, float x, float y, float z, float radius, float time, int type); //generates stencil shadows of the world geometry. //redraws world geometry -void PPL_AddLight(dlight_t *dl) +qboolean PPL_AddLight(dlight_t *dl) { int i; int sdecrw; @@ -4069,24 +4297,45 @@ void PPL_AddLight(dlight_t *dl) } if (colour[0] < 0.1 && colour[1] < 0.1 && colour[2] < 0.1) - return; //just switch these off. + return false; //just switch these off. if (PPL_ScissorForBox(mins, maxs)) - return; //was culled. + return false; //was culled. - if (cl.worldmodel->fromgame == fg_quake2 || cl.worldmodel->fromgame == fg_quake3) - i = cl.worldmodel->funcs.LeafForPoint(r_refdef.vieworg, cl.worldmodel); + if (dl->worldshadowmesh) + { + if (!PPL_LeafInView(dl->worldshadowmesh->litleaves)) + return false; +/* + if (cl.worldmodel->fromgame == fg_quake2 || cl.worldmodel->fromgame == fg_quake3) + i = cl.worldmodel->funcs.LeafForPoint(r_refdef.vieworg, cl.worldmodel); + else + i = r_viewleaf - cl.worldmodel->leafs; + vvis = cl.worldmodel->funcs.LeafPVS(i, cl.worldmodel, vvisb); + + // if (!(lvis[i>>3] & (1<<(i&7)))) //light might not be visible, but it's effects probably should be. + // return; + if (!PPL_VisOverlaps(dl->worldshadowmesh->litleaves, vvis)) //The two viewing areas do not intersect. + return; +*/ + lvis = NULL; + } else - i = r_viewleaf - cl.worldmodel->leafs; + { + if (cl.worldmodel->fromgame == fg_quake2 || cl.worldmodel->fromgame == fg_quake3) + i = cl.worldmodel->funcs.LeafForPoint(r_refdef.vieworg, cl.worldmodel); + else + i = r_viewleaf - cl.worldmodel->leafs; - leaf = cl.worldmodel->funcs.LeafForPoint(dl->origin, cl.worldmodel); - lvis = cl.worldmodel->funcs.LeafPVS(leaf, cl.worldmodel, lvisb); - vvis = cl.worldmodel->funcs.LeafPVS(i, cl.worldmodel, vvisb); + leaf = cl.worldmodel->funcs.LeafForPoint(dl->origin, cl.worldmodel); + lvis = cl.worldmodel->funcs.LeafPVS(leaf, cl.worldmodel, lvisb); + vvis = cl.worldmodel->funcs.LeafPVS(i, cl.worldmodel, vvisb); -// if (!(lvis[i>>3] & (1<<(i&7)))) //light might not be visible, but it's effects probably should be. -// return; - if (!PPL_VisOverlaps(lvis, vvis)) //The two viewing areas do not intersect. - return; + // if (!(lvis[i>>3] & (1<<(i&7)))) //light might not be visible, but it's effects probably should be. + // return; + if (!PPL_VisOverlaps(lvis, vvis)) //The two viewing areas do not intersect. + return false; + } PPL_EnableVertexArrays(); @@ -4147,7 +4396,7 @@ void PPL_AddLight(dlight_t *dl) qglStencilOpSeparateATI(GL_BACK, GL_KEEP, sincrw, GL_KEEP); qglStencilOpSeparateATI(GL_FRONT, GL_KEEP, sdecrw, GL_KEEP); - PPL_UpdateNodeShadowFrames(lvisb); + PPL_UpdateNodeShadowFrames(lvis); PPL_RecursiveWorldNode(dl); PPL_DrawShadowMeshes(dl); qglStencilOpSeparateATI(GL_FRONT_AND_BACK, GL_KEEP, GL_KEEP, GL_KEEP); @@ -4172,7 +4421,7 @@ void PPL_AddLight(dlight_t *dl) qglStencilOp(GL_KEEP, sdecrw, GL_KEEP); qglStencilFunc( GL_ALWAYS, 1, ~0 ); - PPL_UpdateNodeShadowFrames(lvisb); + PPL_UpdateNodeShadowFrames(lvis); PPL_RecursiveWorldNode(dl); PPL_DrawShadowMeshes(dl); @@ -4218,10 +4467,39 @@ void PPL_AddLight(dlight_t *dl) qglEnable(GL_DEPTH_TEST); qglDepthMask(0); - qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); qglCullFace(GL_FRONT); +#if 0 //draw the stencil stuff to the red channel +/* { +#pragma comment(lib, "opengl32.lib"); + static char buffer[1024*1024*8]; + glReadPixels(0, 0, vid.width, vid.height, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, buffer); + glDrawPixels(vid.width, vid.height, GL_GREEN, GL_UNSIGNED_BYTE, buffer); + } +*/ + + qglMatrixMode(GL_PROJECTION); + qglPushMatrix(); + qglMatrixMode(GL_MODELVIEW); + qglPushMatrix(); + GL_Set2D(); + + qglColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE); + qglStencilFunc( GL_GREATER, 1, ~0 ); + Draw_ConsoleBackground(480); + + qglColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE); + qglStencilFunc( GL_LESS, 1, ~0 ); + Draw_ConsoleBackground(480); + + qglMatrixMode(GL_PROJECTION); + qglPopMatrix(); + qglMatrixMode(GL_MODELVIEW); + qglPopMatrix(); +#endif + + qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); } qglColor3f(1,1,1); @@ -4244,6 +4522,8 @@ void PPL_AddLight(dlight_t *dl) qglStencilFunc( GL_ALWAYS, 0, ~0 ); qglDisable(GL_SCISSOR_TEST); + + return true; } #endif @@ -4259,10 +4539,17 @@ void PPL_DrawWorld (void) float furthest; #endif int i; + int numlights; vec3_t mins, maxs; int maxshadowlights = gl_maxshadowlights.value; + + if (!r_shadow_realtime_world.value) + r_lightmapintensity = 1; + else + r_lightmapintensity = r_shadow_realtime_world_lightmaps.value; + /* if (!lightmap) { @@ -4298,6 +4585,7 @@ void PPL_DrawWorld (void) // Con_Printf("GL Error on entities\n"); #ifdef PPL + numlights = 0; RSpeedRemark(); if (r_shadows.value && qglStencilFunc && gl_canstencil) { @@ -4325,11 +4613,11 @@ void PPL_DrawWorld (void) maxs[2] = l->origin[2] + l->radius; if (R_CullBox(mins, maxs)) continue; -// if (R_CullSphere(l->origin, l->radius*1.1)) -// continue; + if (R_CullSphere(l->origin, l->radius)) + continue; #if 1 - if (!maxshadowlights--) + if (maxshadowlights-- <= 0) continue; #else VectorSubtract(l->origin, r_refdef.vieworg, mins) @@ -4371,7 +4659,8 @@ void PPL_DrawWorld (void) l->color[2]*=10; } TRACE(("dbg: calling PPL_AddLight\n")); - PPL_AddLight(l); + if (PPL_AddLight(l)) + numlights++; if(!l->isstatic) { l->color[0]/=10; @@ -4387,6 +4676,7 @@ void PPL_DrawWorld (void) } RSpeedEnd(RSPEED_STENCILSHADOWS); #endif +// Con_Printf("%i lights\n", numlights); // if (qglGetError()) // Con_Printf("GL Error on shadow lighting\n"); @@ -4428,4 +4718,268 @@ void PPL_CreateShaderObjects(void) PPL_LoadSpecularFragmentProgram(); } -#endif +void PPL_FlushShadowMesh(dlight_t *dl) +{ + int tn; + shadowmesh_t *sm; + sm = dl->worldshadowmesh; + if (sm) + { + dl->worldshadowmesh = NULL; + for (tn = 0; tn < sm->numsurftextures; tn++) + if (sm->litsurfs[tn].count) + BZ_Free(sm->litsurfs); + BZ_Free(sm->indicies); + BZ_Free(sm->verts); + BZ_Free(sm); + } +} + +//okay, so this is a bit of a hack... +qboolean buildingmesh; +void (APIENTRY *realBegin) (GLenum); +void (APIENTRY *realEnd) (void); +void (APIENTRY *realVertex3f) (GLfloat x, GLfloat y, GLfloat z); +void (APIENTRY *realVertex3fv) (const GLfloat *v); +void (APIENTRY *realVertexPointer) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void (APIENTRY *realDrawArrays) (GLenum mode, GLint first, GLsizei count); +void (APIENTRY *realDrawElements) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); + +#define inc 128 +int sh_type; +int sh_index[64*64]; +int sh_vertnum; //vertex number (set to 0 at SH_Begin) +int sh_maxverts; +int sh_numverts; //total emitted +int sh_maxindicies; +int sh_numindicies; +float *sh_vertexpointer; +int sh_vpstride; +shadowmesh_t *sh_shmesh; +void APIENTRY SH_Begin (GLenum e) +{ + sh_type = e; +} +void APIENTRY SH_End (void) +{ + int i; + int v1, v2; + switch(sh_type) + { + case GL_POLYGON: + i = (sh_numindicies+(sh_vertnum-2)*3+inc+5)&~(inc-1); //and a bit of padding + if (sh_maxindicies != i) + { + sh_maxindicies = i; + sh_shmesh->indicies = BZ_Realloc(sh_shmesh->indicies, i * sizeof(*sh_shmesh->indicies)); + } + //decompose the poly into a triangle fan. + v1 = sh_index[0]; + v2 = sh_index[1]; + for (i = 2; i < sh_vertnum; i++) + { + sh_shmesh->indicies[sh_numindicies++] = v1; + sh_shmesh->indicies[sh_numindicies++] = v2; + sh_shmesh->indicies[sh_numindicies++] = v2 = sh_index[i]; + } + sh_vertnum = 0; + break; + case GL_TRIANGLES: + i = (sh_numindicies+(sh_vertnum)+inc+5)&~(inc-1); //and a bit of padding + if (sh_maxindicies != i) + { + sh_maxindicies = i; + sh_shmesh->indicies = BZ_Realloc(sh_shmesh->indicies, i * sizeof(*sh_shmesh->indicies)); + } + //add the extra triangles + for (i = 0; i < sh_vertnum; i+=3) + { + sh_shmesh->indicies[sh_numindicies++] = sh_index[i+0]; + sh_shmesh->indicies[sh_numindicies++] = sh_index[i+1]; + sh_shmesh->indicies[sh_numindicies++] = sh_index[i+2]; + } + sh_vertnum = 0; + break; + case GL_QUADS: + i = (sh_numindicies+(sh_vertnum/4)*6+inc+5)&~(inc-1); //and a bit of padding + if (sh_maxindicies != i) + { + sh_maxindicies = i; + sh_shmesh->indicies = BZ_Realloc(sh_shmesh->indicies, i * sizeof(*sh_shmesh->indicies)); + } + //add the extra triangles + for (i = 0; i < sh_vertnum; i+=4) + { + sh_shmesh->indicies[sh_numindicies++] = sh_index[i+0]; + sh_shmesh->indicies[sh_numindicies++] = sh_index[i+1]; + sh_shmesh->indicies[sh_numindicies++] = sh_index[i+2]; + + sh_shmesh->indicies[sh_numindicies++] = sh_index[i+0]; + sh_shmesh->indicies[sh_numindicies++] = sh_index[i+2]; + sh_shmesh->indicies[sh_numindicies++] = sh_index[i+3]; + } + sh_vertnum = 0; + break; + default: + if (sh_vertnum) + Sys_Error("SH_End: verticies were left"); + } +} +void APIENTRY SH_Vertex3f (GLfloat x, GLfloat y, GLfloat z) +{ + int i; + if (sh_vertnum > sizeof(sh_index)/sizeof(sh_index[0])) + Sys_Error("SH_End: too many verticies"); + +//add the verts as we go + i = (sh_numverts+inc+5)&~(inc-1); //and a bit of padding + if (sh_maxverts != i) + { + sh_maxverts = i; + sh_shmesh->verts = BZ_Realloc(sh_shmesh->verts, i * sizeof(*sh_shmesh->verts)); + } + + sh_shmesh->verts[sh_numverts][0] = x; + sh_shmesh->verts[sh_numverts][1] = y; + sh_shmesh->verts[sh_numverts][2] = z; + + sh_index[sh_vertnum] = sh_numverts; + sh_vertnum++; + sh_numverts++; + + switch(sh_type) + { + case GL_POLYGON: + break; + case GL_TRIANGLES: + if (sh_vertnum == 3) + SH_End(); + break; + case GL_QUADS: + if (sh_vertnum == 4) + SH_End(); + break; + default: + Sys_Error("SH_Vertex3f: bad type"); + } +} +void APIENTRY SH_Vertex3fv (const GLfloat *v) +{ + SH_Vertex3f(v[0], v[1], v[2]); +} +void APIENTRY SH_VertexPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + sh_vertexpointer = pointer; + sh_vpstride = stride/4; + if (!sh_vpstride) + sh_vpstride = 3; +} +void APIENTRY SH_DrawArrays (GLenum mode, GLint first, GLsizei count) +{ + int i; + SH_Begin(mode); + count+=first; + for (i = first; i < count; i++) + SH_Vertex3fv(sh_vertexpointer + i*sh_vpstride); + SH_End(); +} +void APIENTRY SH_DrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) +{ + int i; + SH_Begin(mode); + for (i = 0; i < count; i++) + SH_Vertex3fv(sh_vertexpointer + (((int*)indices)[i])*sh_vpstride); + SH_End(); +} + +void PPL_Shadow_Cache_Surface(msurface_t *surf) +{ + int i; + if (!buildingmesh) + return; + + for (i = 0; i < cl.worldmodel->numtextures; i++) + if (surf->texinfo->texture == cl.worldmodel->textures[i]) + break; + + sh_shmesh->litsurfs[i].s = BZ_Realloc(sh_shmesh->litsurfs[i].s, sizeof(void*)*(sh_shmesh->litsurfs[i].count+1)); + sh_shmesh->litsurfs[i].s[sh_shmesh->litsurfs[i].count] = surf; + sh_shmesh->litsurfs[i].count++; +} + +void PPL_Shadow_Cache_Leaf(mleaf_t *leaf) +{ + int i; + if (!buildingmesh) + return; + + i = leaf - cl.worldmodel->leafs; + sh_shmesh->litleaves[i>>3] = 1<<(i&7); +} + +void PPL_BeginShadowMesh(dlight_t *dl) +{ + PPL_FlushShadowMesh(dl); + + if (buildingmesh) + return; + if (!dl->isstatic) + return; + + sh_maxverts = 0; + sh_numverts = 0; + sh_vertnum = 0; + sh_maxindicies = 0; + sh_numindicies = 0; + + buildingmesh = true; + realBegin = qglBegin; + realEnd = qglEnd; + realVertex3f = qglVertex3f; + realVertex3fv = qglVertex3fv; + realVertexPointer = qglVertexPointer; + realDrawArrays = qglDrawArrays; + realDrawElements = qglDrawElements; + + qglBegin = SH_Begin; + qglEnd = SH_End; + qglVertex3f = SH_Vertex3f; + qglVertex3fv = SH_Vertex3fv; + qglVertexPointer = SH_VertexPointer; + qglDrawArrays = SH_DrawArrays; + qglDrawElements = SH_DrawElements; + + sh_shmesh = Z_Malloc(sizeof(*sh_shmesh) + (cl.worldmodel->numleafs+7)/8); + sh_shmesh->litsurfs = Z_Malloc(sizeof(shadowmeshsurfs_t)*cl.worldmodel->numtextures); + sh_shmesh->numsurftextures=cl.worldmodel->numtextures; + + sh_shmesh->litleaves = (unsigned char*)(sh_shmesh+1); +} +void PPL_FinishShadowMesh(dlight_t *dl) +{ + int i; + if (!buildingmesh) + return; + + qglBegin = realBegin; + qglEnd = realEnd; + qglVertex3f = realVertex3f; + qglVertex3fv = realVertex3fv; + qglVertexPointer = realVertexPointer; + qglDrawArrays = realDrawArrays; + qglDrawElements = realDrawElements; + buildingmesh = false; + + dl->worldshadowmesh = sh_shmesh; + sh_shmesh->numindicies = sh_numindicies; + sh_shmesh->numverts = sh_numverts; + + sh_shmesh = NULL; +} + +#endif //ifdef GLQUAKE + + + + + diff --git a/engine/gl/gl_screen.c b/engine/gl/gl_screen.c index d54ef79c0..d66d8a5a9 100644 --- a/engine/gl/gl_screen.c +++ b/engine/gl/gl_screen.c @@ -222,6 +222,9 @@ void GLSCR_UpdateScreen (void) Media_RecordFrame(); #endif GLR_BrightenScreen(); + + if (key_dest == key_console) + Con_DrawConsole(vid_conheight.value/2, false); GL_EndRendering (); GL_DoSwap(); RSpeedEnd(RSPEED_TOTALREFRESH); diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 9bd511c95..4752d98cb 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -1828,7 +1828,7 @@ void Shader_DefaultSkin(char *shortname, shader_t *s) { shaderpass_t *pass; pass = &s->passes[0]; - pass->flags = SHADER_PASS_BLEND|SHADER_PASS_DEPTHWRITE; + pass->flags = SHADER_PASS_DEPTHWRITE; pass->anim_frames[0] = Mod_LoadHiResTexture(shortname, NULL, true, true, true);//GL_FindImage (shortname, 0); pass->depthfunc = GL_LEQUAL; pass->rgbgen = RGB_GEN_LIGHTING_DIFFUSE; @@ -1847,7 +1847,7 @@ void Shader_DefaultSkin(char *shortname, shader_t *s) s->numpasses = 1; s->numdeforms = 0; - s->flags = SHADER_BLEND|SHADER_DEPTHWRITE|SHADER_CULL_FRONT; + s->flags = SHADER_DEPTHWRITE|SHADER_CULL_FRONT; s->features = MF_STCOORDS|MF_NORMALS; s->sort = SHADER_SORT_OPAQUE; s->registration_sequence = 1;//fizme: registration_sequence; @@ -2027,7 +2027,11 @@ shader_t *R_RegisterSkin (char *name) } shader_t *R_RegisterCustom (char *name, void(*defaultgen)(char *name, shader_t*)) { - return &r_shaders[R_LoadShader (name, defaultgen)]; + int i; + i = R_LoadShader (name, defaultgen); + if (i < 0) + return NULL; + return &r_shaders[i]; } #endif diff --git a/engine/gl/gl_vidnt.c b/engine/gl/gl_vidnt.c index f7189e59b..6234f6f78 100644 --- a/engine/gl/gl_vidnt.c +++ b/engine/gl/gl_vidnt.c @@ -843,18 +843,25 @@ void GL_DoSwap (void) // handle the mouse state when windowed if that's changed if (modestate == MS_WINDOWED) { - if (!_windowed_mouse.value) { - if (windowed_mouse) { + if (!_windowed_mouse.value) + { + if (windowed_mouse) + { IN_DeactivateMouse (); IN_ShowMouse (); windowed_mouse = false; } - } else { + } + else + { windowed_mouse = true; - if ((key_dest == key_game||mouseusedforgui) && !mouseactive && ActiveApp) { + if ((key_dest == key_game||mouseusedforgui) && !mouseactive && ActiveApp) + { IN_ActivateMouse (); IN_HideMouse (); - } else if (mouseactive && !(key_dest == key_game || mouseusedforgui)) { + } + else if (mouseactive && key_dest == key_console) + {//!(key_dest == key_game || mouseusedforgui)) { IN_DeactivateMouse (); IN_ShowMouse (); } diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index 04e5fc9c4..b15f6a3df 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -114,7 +114,7 @@ void GL_Upload8 (qbyte *data, int width, int height, qboolean mipmap, qboolean void GL_Upload8_EXT (qbyte *data, int width, int height, qboolean mipmap, qboolean alpha); #endif int GL_LoadTexture (char *identifier, int width, int height, qbyte *data, qboolean mipmap, qboolean alpha); -int GL_LoadTexture8Bump (char *identifier, int width, int height, unsigned char *data, qboolean mipmap); +int GL_LoadTexture8Bump (char *identifier, int width, int height, unsigned char *data, qboolean mipmap, float bumpscale); int GL_LoadTexture8Pal24 (char *identifier, int width, int height, qbyte *data, qbyte *palette24, qboolean mipmap, qboolean alpha); int GL_LoadTexture32 (char *identifier, int width, int height, unsigned *data, qboolean mipmap, qboolean alpha); int GL_LoadCompressed(char *name); @@ -347,7 +347,7 @@ typedef struct { //gl_ppl.c void PPL_DrawWorld (void); -void RotateLightVector(vec3_t angles, vec3_t origin, vec3_t lightpoint, vec3_t result); +void RotateLightVector(vec3_t *angles, vec3_t origin, vec3_t lightpoint, vec3_t result); #endif diff --git a/engine/qclib/comprout.c b/engine/qclib/comprout.c index 81a81f426..c57c84967 100644 --- a/engine/qclib/comprout.c +++ b/engine/qclib/comprout.c @@ -82,7 +82,7 @@ pbool CompileParams(progfuncs_t *progfuncs, int doall, int nump, char **parms) if (!externs->useeditor) printf("Error in %s on line %i\n", errorfile, errorline); else - externs->useeditor(errorfile, errorline, nump, parms); + externs->useeditor(progfuncs, errorfile, errorline, nump, parms); } return false; } @@ -108,7 +108,7 @@ int Comp_Begin(progfuncs_t *progfuncs, int nump, char **parms) { PostCompile(); if (*errorfile) - externs->useeditor(errorfile, errorline, nump, parms); + externs->useeditor(progfuncs, errorfile, errorline, nump, parms); return false; } @@ -125,7 +125,7 @@ int Comp_Continue(progfuncs_t *progfuncs) { PostCompile(); if (*errorfile) - externs->useeditor(errorfile, errorline, comp_nump, comp_parms); + externs->useeditor(progfuncs, errorfile, errorline, comp_nump, comp_parms); return false; } @@ -136,7 +136,7 @@ int Comp_Continue(progfuncs_t *progfuncs) PostCompile(); if (*errorfile) - externs->useeditor(errorfile, errorline, comp_nump, comp_parms); + externs->useeditor(progfuncs, errorfile, errorline, comp_nump, comp_parms); return false; } diff --git a/engine/qclib/execloop.h b/engine/qclib/execloop.h index 070830772..3df6b7aa1 100644 --- a/engine/qclib/execloop.h +++ b/engine/qclib/execloop.h @@ -654,12 +654,12 @@ reeval: //array/structure reading/riting. case OP_GLOBALADDRESS: - OPC->_int = ENGINEPOINTER(&OPA->_int + OPB->_int/4); + OPC->_int = ENGINEPOINTER(&OPA->_int + OPB->_int); break; case OP_POINTER_ADD: //pointer to 32 bit (remember to *3 for vectors) OPC->_int = OPA->_int + OPB->_int*4; break; - + case OP_LOADA_I: case OP_LOADA_F: case OP_LOADA_FLD: diff --git a/engine/qclib/execloop16d.h b/engine/qclib/execloop16d.h index 070830772..3df6b7aa1 100644 --- a/engine/qclib/execloop16d.h +++ b/engine/qclib/execloop16d.h @@ -654,12 +654,12 @@ reeval: //array/structure reading/riting. case OP_GLOBALADDRESS: - OPC->_int = ENGINEPOINTER(&OPA->_int + OPB->_int/4); + OPC->_int = ENGINEPOINTER(&OPA->_int + OPB->_int); break; case OP_POINTER_ADD: //pointer to 32 bit (remember to *3 for vectors) OPC->_int = OPA->_int + OPB->_int*4; break; - + case OP_LOADA_I: case OP_LOADA_F: case OP_LOADA_FLD: diff --git a/engine/qclib/execloop32.h b/engine/qclib/execloop32.h index 070830772..3df6b7aa1 100644 --- a/engine/qclib/execloop32.h +++ b/engine/qclib/execloop32.h @@ -654,12 +654,12 @@ reeval: //array/structure reading/riting. case OP_GLOBALADDRESS: - OPC->_int = ENGINEPOINTER(&OPA->_int + OPB->_int/4); + OPC->_int = ENGINEPOINTER(&OPA->_int + OPB->_int); break; case OP_POINTER_ADD: //pointer to 32 bit (remember to *3 for vectors) OPC->_int = OPA->_int + OPB->_int*4; break; - + case OP_LOADA_I: case OP_LOADA_F: case OP_LOADA_FLD: diff --git a/engine/qclib/execloop32d.h b/engine/qclib/execloop32d.h index 070830772..3df6b7aa1 100644 --- a/engine/qclib/execloop32d.h +++ b/engine/qclib/execloop32d.h @@ -654,12 +654,12 @@ reeval: //array/structure reading/riting. case OP_GLOBALADDRESS: - OPC->_int = ENGINEPOINTER(&OPA->_int + OPB->_int/4); + OPC->_int = ENGINEPOINTER(&OPA->_int + OPB->_int); break; case OP_POINTER_ADD: //pointer to 32 bit (remember to *3 for vectors) OPC->_int = OPA->_int + OPB->_int*4; break; - + case OP_LOADA_I: case OP_LOADA_F: case OP_LOADA_FLD: diff --git a/engine/qclib/initlib.c b/engine/qclib/initlib.c index 68f627fa1..9a95cb17e 100644 --- a/engine/qclib/initlib.c +++ b/engine/qclib/initlib.c @@ -321,6 +321,8 @@ eval_t *GetEdictFieldValue(progfuncs_t *progfuncs, struct edict_s *ed, char *nam struct edict_s *ProgsToEdict (progfuncs_t *progfuncs, int progs) { + if ((unsigned)progs >= maxedicts) + progs = 0; return (struct edict_s *)PROG_TO_EDICT(progfuncs, progs); } int EdictToProgs (progfuncs_t *progfuncs, struct edict_s *ed) diff --git a/engine/qclib/pr_exec.c b/engine/qclib/pr_exec.c index 9b081872f..308875a78 100644 --- a/engine/qclib/pr_exec.c +++ b/engine/qclib/pr_exec.c @@ -730,7 +730,7 @@ static char *lastfile = 0; lastline = pr_progstate[pn].linenums[statement]; lastfile = f->s_file+progfuncs->stringtable; - lastline = externs->useeditor(lastfile, lastline, 0, NULL); + lastline = externs->useeditor(progfuncs, lastfile, lastline, 0, NULL); if (pr_progstate[pn].linenums[statement] != lastline) { @@ -750,7 +750,7 @@ static char *lastfile = 0; else if (f) //annoying. { if (externs->useeditor) - externs->useeditor(f->s_file+progfuncs->stringtable, -1, 0, NULL); + externs->useeditor(progfuncs, f->s_file+progfuncs->stringtable, -1, 0, NULL); return statement; } diff --git a/engine/qclib/progslib.h b/engine/qclib/progslib.h index f3e631e2f..c00712a4a 100644 --- a/engine/qclib/progslib.h +++ b/engine/qclib/progslib.h @@ -166,7 +166,7 @@ typedef struct progexterns_s { struct edict_s **sv_edicts; //pointer to the engine's reference to world. int *sv_num_edicts; //pointer to the engine's edict count. - int (*useeditor) (char *filename, int line, int nump, char **parms); //called on syntax errors or step-by-step debugging. + int (*useeditor) (progfuncs_t *prinst, char *filename, int line, int nump, char **parms); //called on syntax errors or step-by-step debugging. } progparms_t, progexterns_t; void QC_AddSharedVar(progfuncs_t *progfuncs, int start, int size); diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 69b998875..a43f6adcb 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -44,7 +44,7 @@ cvar_t saved4 = {"saved4", "0", NULL, CVAR_ARCHIVE}; cvar_t temp1 = {"temp1", "0", NULL, CVAR_ARCHIVE}; cvar_t noexit = {"noexit", "0", NULL}; -cvar_t pr_maxedicts = {"pr_maxedicts", "2000", NULL, CVAR_LATCH}; +cvar_t pr_maxedicts = {"pr_maxedicts", "2048", NULL, CVAR_LATCH}; cvar_t pr_imitatemvdsv = {"pr_imitatemvdsv", "0", NULL, CVAR_LATCH}; cvar_t pr_fixbrokenqccarrays = {"pr_fixbrokenqccarrays", "1", NULL, CVAR_LATCH}; @@ -291,13 +291,13 @@ void VARGS PR_CB_Free(void *mem) BZ_Free(mem); } void PF_break (progfuncs_t *prinst, struct globalvars_s *pr_globals); -int QCLibEditor(char *filename, int line, int nump, char **parms); -int QCEditor (char *filename, int line, int nump, char **parms) +int QCLibEditor(progfuncs_t *prinst, char *filename, int line, int nump, char **parms); +int QCEditor (progfuncs_t *prinst, char *filename, int line, int nump, char **parms) { #ifdef TEXTEDITOR static char oldfuncname[64]; if (!parms) - return QCLibEditor(filename, line, nump, parms); + return QCLibEditor(prinst, filename, line, nump, parms); else { if (!nump && !strncmp(oldfuncname, *parms, sizeof(oldfuncname))) @@ -1211,6 +1211,8 @@ void Q_InitProgs(void) } sv.max_edicts = pr_maxedicts.value; + if (sv.max_edicts > MAX_EDICTS) + sv.max_edicts = MAX_EDICTS; pr_edict_size = PR_InitEnts(svprogfuncs, sv.max_edicts); } @@ -5326,7 +5328,7 @@ void PF_substring (progfuncs_t *prinst, struct globalvars_s *pr_globals) if (start < 0) start = strlen(s)-start; if (length < 0) - length = strlen(s)-start; + length = strlen(s)-start+(length+1); if (start >= strlen(s) || length<=0 || !*s) { @@ -9466,9 +9468,6 @@ void PR_RegisterFields(void) //it's just easier to do it this way. fieldfloat(fatness); fieldentity(view2); fieldvector(movement); - PR_RegisterFieldVar(svprogfuncs, ev_float, "buttonforward", (int)&((entvars_t*)0)->movement[0], -1); - PR_RegisterFieldVar(svprogfuncs, ev_float, "buttonright", (int)&((entvars_t*)0)->movement[1], -1); - PR_RegisterFieldVar(svprogfuncs, ev_float, "buttonup", (int)&((entvars_t*)0)->movement[2], -1); fieldfloat(fteflags); fieldfloat(vweapmodelindex); @@ -9478,6 +9477,8 @@ void PR_RegisterFields(void) //it's just easier to do it this way. fieldentity(viewmodelforclient); fieldentity(exteriormodeltoclient); + fieldfloat(viewzoom); + fieldentity(tag_entity); fieldfloat(tag_index); diff --git a/engine/server/progdefs.h b/engine/server/progdefs.h index b876cbfc9..8851c5392 100644 --- a/engine/server/progdefs.h +++ b/engine/server/progdefs.h @@ -185,6 +185,8 @@ typedef struct entvars_s int viewmodelforclient; int exteriormodeltoclient; + float viewzoom; + int tag_entity; float tag_index; diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 9289cb031..978cfc038 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -551,6 +551,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us svs.clients[i].num_backbuf = 0; svs.clients[i].datagram.cursize = 0; } + svs.clients[i].csqcactive = false; } if (sv_bigcoords.value) diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 6337f7b58..2ca2d0321 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -148,7 +148,7 @@ cvar_t watervis = {"watervis", "" , NULL, CVAR_SERVERINFO}; cvar_t rearview = {"rearview", "" , NULL, CVAR_SERVERINFO}; cvar_t allow_luma = {"allow_luma", "1", NULL, CVAR_SERVERINFO}; cvar_t allow_bump = {"allow_bump", "1", NULL, CVAR_SERVERINFO}; -cvar_t allow_skybox = {"allow_skybox", "1", NULL, CVAR_SERVERINFO}; +cvar_t allow_skybox = {"allow_skybox", "", NULL, CVAR_SERVERINFO}; cvar_t sv_allow_splitscreen = {"allow_splitscreen", "",NULL,CVAR_SERVERINFO}; cvar_t fbskins = {"fbskins", "0", NULL, CVAR_SERVERINFO}; //to get rid of lame fuhquake fbskins cvar_t mirrors = {"mirrors", "" , NULL, CVAR_SERVERINFO}; @@ -1103,7 +1103,7 @@ qboolean SV_ChallengePasses(int challenge) return false; } -void SV_RejectMessage(int protocol, char *format, ...) +void VARGS SV_RejectMessage(int protocol, char *format, ...) { va_list argptr; char string[8192]; @@ -2047,6 +2047,10 @@ qboolean SV_ConnectionlessPacket (void) return true; } } + else if (!strcmp(c,"\xad\xad\xad\xad""getchallenge")) + { + SVC_GetChallenge (); + } else if (!strcmp(c,"getchallenge")) { SVC_GetChallenge (); diff --git a/engine/server/sv_mvd.c b/engine/server/sv_mvd.c index 05740a56d..44216d4bf 100644 --- a/engine/server/sv_mvd.c +++ b/engine/server/sv_mvd.c @@ -1689,15 +1689,13 @@ void SV_MVD_Record_f (void) _snprintf (name, MAX_OSPATH+MAX_MVD_NAME, "%s/%s/%s", com_gamedir, sv_demoDir.string, newname); - Sys_mkdir(va("%s/%s", com_gamedir, sv_demoDir.string)); - -// -// open the demo file -// COM_StripExtension(name, name); COM_DefaultExtension(name, ".mvd"); + COM_CreatePath(name); - + // + // open the demo file and start recording + // SV_MVD_Record (SV_InitRecordFile(name)); } diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index fabfaa4e6..639d34b6c 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -547,7 +547,8 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int switch (client->protocol) { case SCP_BAD: - break; + continue; //a bot. + #ifdef NQPROT case SCP_NETQUAKE: case SCP_DARKPLACES6: @@ -663,23 +664,45 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int } inrange: - #ifdef NQPROT - if (!ISQWCLIENT(client)) + switch (client->protocol) { - if (reliable) { + case SCP_BAD: + continue; //a bot. + +#ifdef NQPROT + case SCP_NETQUAKE: + case SCP_DARKPLACES6: + case SCP_DARKPLACES7: //extra prediction stuff + if (reliable) + { ClientReliableCheckBlock(client, sv.nqmulticast.cursize); ClientReliableWrite_SZ(client, sv.nqmulticast.data, sv.nqmulticast.cursize); - } else + } + else SZ_Write (&client->datagram, sv.nqmulticast.data, sv.nqmulticast.cursize); - } - else - #endif - { - if (reliable) { + + break; +#endif +#ifdef Q2SERVER + case SCP_QUAKE2: + if (reliable) + { + ClientReliableCheckBlock(client, sv.q2multicast.cursize); + ClientReliableWrite_SZ(client, sv.q2multicast.data, sv.q2multicast.cursize); + } + else + SZ_Write (&client->datagram, sv.q2multicast.data, sv.q2multicast.cursize); + break; +#endif + case SCP_QUAKEWORLD: + if (reliable) + { ClientReliableCheckBlock(client, sv.multicast.cursize); ClientReliableWrite_SZ(client, sv.multicast.data, sv.multicast.cursize); - } else + } + else SZ_Write (&client->datagram, sv.multicast.data, sv.multicast.cursize); + break; } } } @@ -1220,7 +1243,11 @@ void SV_UpdateClientStats (client_t *client, int pnum) stats[STAT_ROCKETS] = ent->v->ammo_rockets; stats[STAT_CELLS] = ent->v->ammo_cells; if (!client->spectator) + { stats[STAT_ACTIVEWEAPON] = ent->v->weapon; + if (client->csqcactive) + stats[STAT_WEAPONFRAME] = ent->v->weaponframe; + } // stuff the sigil bits into the high bits of items for sbar if (pr_items2) @@ -1236,7 +1263,10 @@ void SV_UpdateClientStats (client_t *client, int pnum) stats[STAT_VIEW2] = 0; #endif - stats[STAT_VIEWZOOM] = 255; + if (!ent->v->viewzoom) + stats[STAT_VIEWZOOM] = 255; + else + stats[STAT_VIEWZOOM] = ent->v->viewzoom*255; SV_UpdateQCStats(ent, stats); diff --git a/engine/server/world.c b/engine/server/world.c index 84cdb4bc1..941f89aeb 100644 --- a/engine/server/world.c +++ b/engine/server/world.c @@ -1089,34 +1089,31 @@ trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t max trace_t SVQ2_ClipMoveToEntity (q2edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end) { trace_t trace; - /* - vec3_t offset; - vec3_t start_l, end_l; - hull_t *hull; - -// fill in a default trace - memset (&trace, 0, sizeof(trace_t)); - trace.fraction = 1; - trace.allsolid = true; - VectorCopy (end, trace.endpos); + model_t *model; // get the clipping hull - hull = SVQ2_HullForEntity (ent, mins, maxs, offset); - - VectorSubtract (start, offset, start_l); - VectorSubtract (end, offset, end_l); + if (ent->s.solid == Q2SOLID_BSP) + { + model = sv.models[(int)ent->s.modelindex]; + if (!model || model->type != mod_brush) + SV_Error("SOLID_BSP with non bsp model"); + } + else + { + vec3_t boxmins, boxmaxs; + VectorSubtract (ent->mins, maxs, boxmins); + VectorSubtract (ent->maxs, mins, boxmaxs); + SV_HullForBox(boxmins, boxmaxs); + model = NULL; + } // trace a line through the apropriate clipping hull - TransformedTrace(ent->s.modelindex, start_l, end_l, &trace, ent->s.angles); - -// fix trace up by the offset - if (trace.fraction != 1) - VectorAdd (trace.endpos, offset, trace.endpos); + TransformedTrace(model, 0, 0, start, end, mins, maxs, &trace, ent->s.origin, ent->s.angles); // did we clip the move? if (trace.fraction < 1 || trace.startsolid ) trace.ent = (edict_t *)ent; -*/ + return trace; } #endif