From fb214142a33701fd033c5dc27cda5802aba7852c Mon Sep 17 00:00:00 2001 From: Spoike Date: Tue, 17 Jan 2012 07:57:46 +0000 Subject: [PATCH] tcpconnect fixes lots of hexen2 fixes fixed clipped decals again, still not using any... fixed zips over 2g rewrote bloom to use glsl. should be slightly more usable now. lots more hexen2 fixes git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@3957 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/Makefile | 40 +- engine/client/cl_ents.c | 12 +- engine/client/cl_main.c | 18 +- engine/client/cl_parse.c | 14 +- engine/client/cl_pred.c | 11 + engine/client/cl_screen.c | 85 ++- engine/client/cl_tent.c | 107 ++- engine/client/cl_ui.c | 2 +- engine/client/client.h | 4 +- engine/client/console.c | 4 +- engine/client/m_mp3.c | 26 +- engine/client/p_classic.c | 58 +- engine/client/p_null.c | 1 + engine/client/p_script.c | 571 +++++++++++++-- engine/client/pr_csqc.c | 36 +- engine/client/pr_menu.c | 9 - engine/client/r_2d.c | 22 +- engine/client/r_d3.c | 6 +- engine/client/r_part.c | 10 +- engine/client/r_partset.c | 302 +++++++- engine/client/r_surf.c | 18 +- engine/client/renderer.c | 6 +- engine/client/sbar.c | 7 +- engine/client/snd_mem.c | 4 +- engine/client/sys_droid.c | 895 ++++++++++++------------ engine/client/view.c | 32 +- engine/common/bspfile.h | 92 ++- engine/common/cmd.c | 17 +- engine/common/com_mesh.c | 20 +- engine/common/fs.c | 40 +- engine/common/fs_pak.c | 2 +- engine/common/fs_win32.c | 6 +- engine/common/fs_zip.c | 96 ++- engine/common/gl_q2bsp.c | 25 +- engine/common/net.h | 2 +- engine/common/net_wins.c | 37 +- engine/common/particles.h | 1 + engine/common/pmove.c | 7 +- engine/common/pmove.h | 1 + engine/common/pmovetst.c | 4 +- engine/common/pr_common.h | 2 +- engine/common/q1bsp.c | 4 +- engine/common/q2pmove.c | 2 +- engine/common/translate.c | 3 +- engine/common/unzip.c | 6 +- engine/common/world.h | 9 +- engine/dotnet2005/ftequake.vcproj | 328 +++++++++ engine/droid/res/drawable-hdpi/icon.png | Bin 4147 -> 9070 bytes engine/droid/res/drawable-ldpi/icon.png | Bin 1723 -> 3472 bytes engine/droid/res/drawable-mdpi/icon.png | Bin 2574 -> 5493 bytes engine/gl/gl_backend.c | 70 +- engine/gl/gl_bloom.c | 212 ++++++ engine/gl/gl_draw.c | 12 +- engine/gl/gl_font.c | 134 +++- engine/gl/gl_heightmap.c | 9 +- engine/gl/gl_model.h | 5 +- engine/gl/gl_rmain.c | 6 +- engine/gl/gl_rmisc.c | 1 + engine/gl/gl_screen.c | 2 +- engine/gl/gl_shader.c | 186 ++--- engine/gl/gl_vidcommon.c | 119 +++- engine/gl/gl_viddroid.c | 6 +- engine/gl/glmod_doom.c | 734 +++++++++++++++++-- engine/gl/glquake.h | 6 +- engine/gl/ltface.c | 2 +- engine/partcfgs/h2part.cfg | 302 +++++++- engine/qclib/execloop.h | 6 +- engine/qclib/pr_comp.h | 9 +- engine/qclib/pr_exec.c | 7 +- engine/qclib/qcc.h | 3 +- engine/qclib/qcc_pr_comp.c | 340 +++++---- engine/qclib/qcc_pr_lex.c | 31 +- engine/qclib/qccmain.c | 8 +- engine/qclib/qcdecomp.c | 2 + engine/server/net_preparse.c | 19 +- engine/server/pr_cmds.c | 149 +++- engine/server/savegame.c | 38 +- engine/server/server.h | 3 + engine/server/sv_ents.c | 4 +- engine/server/sv_init.c | 4 +- engine/server/sv_main.c | 21 +- engine/server/sv_move.c | 12 +- engine/server/sv_phys.c | 30 +- engine/server/sv_user.c | 67 +- engine/server/svhl_game.c | 2 +- engine/server/svq3_game.c | 4 +- engine/server/world.c | 82 +-- engine/shaders/generatebuiltinsl.c | 132 ++++ engine/shaders/glsl/bloom_blur.glsl | 24 + engine/shaders/glsl/bloom_filter.glsl | 20 + engine/shaders/glsl/bloom_final.glsl | 27 + 91 files changed, 4584 insertions(+), 1270 deletions(-) create mode 100644 engine/shaders/generatebuiltinsl.c create mode 100644 engine/shaders/glsl/bloom_blur.glsl create mode 100644 engine/shaders/glsl/bloom_filter.glsl create mode 100644 engine/shaders/glsl/bloom_final.glsl diff --git a/engine/Makefile b/engine/Makefile index 30c3b34aa..17e408e17 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -55,12 +55,25 @@ endif DROID_NDK_PATH?=~/droid/android-ndk-r6b DROID_SDK_PATH?=~/droid/android-sdk-linux_x86 +ANT?=ant +JAVATOOL="$(JAVA_HOME)"/bin/ ifeq ($(FTE_TARGET),droid) + #if we're running under windows, then we want to run some other binary + ifeq ($(shell uname -o 2>&1 | grep Cygwin),) + #set up for linux + NDK_PATH:=$(shell echo $(DROID_NDK_PATH)) + SDK_PATH:=$(shell echo $(DROID_SDK_PATH)) + TOOLCHAIN:=$(NDK_PATH)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi- + else + #we're running upon windows + NDK_PATH:=$(shell cygpath -m $(DROID_NDK_PATH)) + SDK_PATH:=$(shell cygpath -m $(DROID_SDK_PATH)) + TOOLCHAIN:=$(NDK_PATH)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/bin/arm-linux-androideabi- + #make can't cope with absolute paths in dependancy files + NODEPS = 1 + endif - NDK_PATH:=$(shell echo $(DROID_NDK_PATH)) - SDK_PATH:=$(shell echo $(DROID_SDK_PATH)) - - DROID_API_LEVEL=3 + DROID_API_LEVEL=4 #there are 3 ABI targets #armv5 (works on all arm droids) @@ -68,8 +81,8 @@ ifeq ($(FTE_TARGET),droid) #armv7+neon DROID_ABI?=-mfloat-abi=softfp - STRIP=$(NDK_PATH)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-strip - CC=$(NDK_PATH)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc -I$(NDK_PATH)/platforms/android-$(DROID_API_LEVEL)/arch-arm/usr/include/ -DANDROID $(DROID_ABI) + STRIP=$(TOOLCHAIN)strip + CC=$(TOOLCHAIN)gcc -I$(NDK_PATH)/platforms/android-$(DROID_API_LEVEL)/arch-arm/usr/include/ -DANDROID $(DROID_ABI) DO_LD=$(CC) -Wl,-soname,libftedroid.so -shared -Wl,--no-undefined -Wl,-z,noexecstack --sysroot=$(NDK_PATH)/platforms/android-$(DROID_API_LEVEL)/arch-arm -L$(NDK_PATH)/platforms/android-$(DROID_API_LEVEL)/arch-arm/usr/lib -o $@ $(LTO_LD) $(WCFLAGS) $(CFLAGS) -llog -lc -lz -lm endif @@ -1166,7 +1179,8 @@ distclean: clean #makes an ant project for us droid/build.xml: - cd droid && PATH=$$PATH:$(DROID_SDK_PATH)/tools:$(DROID_NDK_PATH) android update project -t 1 -p . -n FTEDroid + -cd droid && PATH=$$PATH:$(DROID_SDK_PATH)/tools:$(DROID_NDK_PATH) android update project -t 1 -p . -n FTEDroid + -cd droid && PATH=$$PATH:$(DROID_SDK_PATH)/tools:$(DROID_NDK_PATH) android.bat update project -t 1 -p . -n FTEDroid #build FTE as a library, then build the java+package (release) droid/ftekeystore: @@ -1180,26 +1194,26 @@ droid/ftekeystore: @echo Just press control-c if you don\'t want to proceed. @echo Morality warning: never distribute droid/ftekeystore - always do make distclean before distributing. @echo - keytool -genkey -v -keystore $@ -alias autogen -keyalg RSA -keysize 2048 -validity 10000 + $(JAVATOOL)keytool -genkey -v -keystore $@ -alias autogen -keyalg RSA -keysize 2048 -validity 10000 droid-rel: droid/build.xml droid/ftekeystore $(MAKE) FTE_TARGET=droid gl-rel mkdir -p droid/libs/armeabi @cp $(RELEASE_DIR)/libftedroid.so droid/libs/armeabi/ - @cd droid && ant release + @cd droid && $(ANT) release @echo @echo @echo Signing package... I hope you remember your password. @echo - jarsigner -digestalg SHA1 -sigalg MD5withRSA -keystore droid/ftekeystore droid/bin/FTEDroid-unsigned.apk autogen + $(JAVATOOL)jarsigner -digestalg SHA1 -sigalg MD5withRSA -keystore droid/ftekeystore droid/bin/FTEDroid-release-unsigned.apk autogen -rm -f $(RELEASE_DIR)/FTEDroid.apk - $(DROID_SDK_PATH)/tools/zipalign 4 droid/bin/FTEDroid-unsigned.apk $(RELEASE_DIR)/FTEDroid.apk + $(DROID_SDK_PATH)/tools/zipalign 4 droid/bin/FTEDroid-release-unsigned.apk $(RELEASE_DIR)/FTEDroid.apk droid-opt: droid/build.xml droid/ftekeystore $(MAKE) FTE_TARGET=droid gl-rel mkdir -p droid/libs/armeabi @cp $(RELEASE_DIR)/libftedroid.so droid/libs/armeabi/ - @cd droid && ant release + @cd droid && $(ANT) release cp droid/bin/FTEDroid-unsigned.apk $(RELEASE_DIR)/FTEDroid.apk #build FTE as a library, then build the java+package (release). also installs it onto the 'current' device. @@ -1207,6 +1221,6 @@ droid-dbg: droid/build.xml $(MAKE) FTE_TARGET=droid gl-dbg @mkdir -p droid/libs/armeabi @cp $(DEBUG_DIR)/libftedroid.so droid/libs/armeabi/ - @cd droid && ant debug install + @cd droid && $(ANT) debug && $(ANT) debug install cp droid/bin/FTEDroid-debug.apk $(DEBUG_DIR)/FTEDroid.apk diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 3fcea1f38..b0ff0b031 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -945,7 +945,7 @@ void CLNQ_ParseEntity(unsigned int bits) { int i; int num, pnum; - entity_state_t *state, *from; + entity_state_t *state;//, *from; entity_state_t *base; static float lasttime; packet_entities_t *pack; @@ -995,7 +995,7 @@ void CLNQ_ParseEntity(unsigned int bits) state = &pack->entities[pack->num_entities++]; } - from = CL_FindOldPacketEntity(num); //this could be optimised. +// from = CL_FindOldPacketEntity(num); //this could be optimised. if (!CL_CheckBaselines(num)) Host_EndGame("CLNQ_ParseEntity: check baselines failed with size %i", num); @@ -1132,14 +1132,6 @@ void CLNQ_ParseEntity(unsigned int bits) if (bits & DPU_MODEL2) state->modelindex |= MSG_ReadByte() << 8; } - if (cls.demoplayback != DPB_NONE) - for (pnum = 0; pnum < cl.splitclients; pnum++) - if (num == cl.viewentity[pnum]) - { - state->angles[0] = cl.viewangles[pnum][0]/-3; - state->angles[1] = cl.viewangles[pnum][1]; - state->angles[2] = cl.viewangles[pnum][2]; - } } #endif #ifdef PEXT_SETVIEW diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 7a918c23e..f9f8110f5 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -795,11 +795,15 @@ void CL_CheckForResend (void) CLQ3_SendAuthPacket(adr); #endif - if (connect_tries == 0) - NET_EnsureRoute(cls.sockets, "conn", cls.servername, false); - Con_TPrintf (TLC_CONNECTINGTO, cls.servername); + if (connect_tries == 0) + if (!NET_EnsureRoute(cls.sockets, "conn", cls.servername, false)) + { + Con_Printf ("Unable to establish connection to %s\n", cls.servername); + return; + } + contype |= 1; /*always try qw type connections*/ // if ((connect_tries&3)==3) || (connect_defaultport==26000)) contype |= 2; /*try nq connections periodically (or if its the default nq port)*/ @@ -2286,7 +2290,7 @@ void CL_ConnectionlessPacket (void) } } - if (cls.demoplayback == DPB_NONE) + if (cls.demoplayback == DPB_NONE && net_from.type != NA_LOOPBACK) Con_TPrintf (TL_ST_COLON, NET_AdrToString (adr, sizeof(adr), net_from)); // Con_DPrintf ("%s", net_message.data + 4); @@ -2521,7 +2525,8 @@ void CL_ConnectionlessPacket (void) #ifdef Q2CLIENT client_connect: //fixme: make function #endif - Con_TPrintf (TLC_GOTCONNECTION); + if (net_from.type != NA_LOOPBACK) + Con_TPrintf (TLC_GOTCONNECTION); if (cls.state >= ca_connected) { if (cls.demoplayback == DPB_NONE) @@ -2537,7 +2542,8 @@ client_connect: //fixme: make function #endif CL_SendClientCommand(true, "new"); cls.state = ca_connected; - Con_TPrintf (TLC_CONNECTED); + if (cls.netchan.remote_address.type != NA_LOOPBACK) + Con_TPrintf (TLC_CONNECTED); allowremotecmd = false; // localid required now for remote cmds total_loading_size = 100; diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 49f9caf6d..35464d077 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -5320,17 +5320,17 @@ void CLQW_ParseServerMessage (void) cl.completed_time = cl.gametime; vid.recalc_refdef = true; // go to full screen for (i=0 ; i<3 ; i++) - cl.simorg[0][i] = MSG_ReadCoord (); + cl.simorg[destsplit][i] = MSG_ReadCoord (); for (i=0 ; i<3 ; i++) - cl.simangles[0][i] = MSG_ReadAngle (); - VectorClear (cl.simvel[0]); - - VectorCopy (cl.simvel[0], cl.simvel[1]); - VectorCopy (cl.simangles[0], cl.simangles[1]); - VectorCopy (cl.simorg[0], cl.simorg[1]); + cl.simangles[destsplit][i] = MSG_ReadAngle (); + VectorClear (cl.simvel[destsplit]); break; case svc_finale: + if (!cl.intermission) + for (i = 0; i < MAX_SPLITS; i++) + cl.simorg[i][2] += cl.viewheight[i]; + cl.intermission = 2; cl.completed_time = cl.gametime; vid.recalc_refdef = true; // go to full screen diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index 703d6e8bb..db447f404 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -1002,8 +1002,19 @@ out: void CL_PredictMove (void) { int i; + + //work out which packet entities are solid + CL_SetSolidEntities (); + + // Set up prediction for other players + CL_SetUpPlayerPrediction(false); + + // do client side motion prediction for (i = 0; i < cl.splitclients; i++) CL_PredictMovePNum(i); + + // Set up prediction for other players + CL_SetUpPlayerPrediction(true); } diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index d95c0d87c..79e09779b 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -254,6 +254,7 @@ typedef struct { unsigned int flags; conchar_t string[1024]; + char titleimage[MAX_QPATH]; unsigned int charcount; float time_start; // for slow victory printing float time_off; @@ -332,8 +333,12 @@ void SCR_CenterPrint (int pnum, char *str, qboolean skipgamecode) p = &scr_centerprint[pnum]; p->flags = 0; + p->titleimage[0] = 0; if (cl.intermission) - p->flags |= CPRINT_TYPEWRITER | CPRINT_PERSIST; + { + p->flags |= CPRINT_TYPEWRITER | CPRINT_PERSIST | CPRINT_TALIGN; + Q_strncpyz(p->titleimage, "gfx/finale.lmp", sizeof(p->titleimage)); + } while (*str == '/') { @@ -344,17 +349,31 @@ void SCR_CenterPrint (int pnum, char *str, qboolean skipgamecode) break; } else if (str[1] == 'P') + { p->flags |= CPRINT_PERSIST | CPRINT_BACKGROUND; + p->flags &= ~CPRINT_TALIGN; + } else if (str[1] == 'O') - p->flags = CPRINT_OBITUARTY; + p->flags ^= CPRINT_OBITUARTY; else if (str[1] == 'B') - p->flags |= CPRINT_BALIGN; //Note: you probably want to add some blank lines... + p->flags ^= CPRINT_BALIGN; //Note: you probably want to add some blank lines... else if (str[1] == 'T') - p->flags |= CPRINT_TALIGN; + p->flags ^= CPRINT_TALIGN; else if (str[1] == 'L') - p->flags |= CPRINT_LALIGN; + p->flags ^= CPRINT_LALIGN; else if (str[1] == 'R') - p->flags |= CPRINT_RALIGN; + p->flags ^= CPRINT_RALIGN; + else if (str[1] == 'I') + { + char *e = strchr(str+=2, ':'); + int l = e - str; + if (l >= sizeof(p->titleimage)) + l = sizeof(p->titleimage)-1; + strncpy(p->titleimage, str, l); + p->titleimage[l] = 0; + str = e+1; + continue; + } else break; str += 2; @@ -403,6 +422,7 @@ void SCR_DrawCenterString (vrect_t *rect, cprint_t *p) int top; int bottom; int remaining; + shader_t *pic; conchar_t *line_start[MAX_CPRINT_LINES]; conchar_t *line_end[MAX_CPRINT_LINES]; @@ -417,20 +437,51 @@ void SCR_DrawCenterString (vrect_t *rect, cprint_t *p) p->erase_center = 0; + if (*p->titleimage) + pic = R2D_SafeCachePic (p->titleimage); + else + pic = NULL; + if (p->flags & CPRINT_BACKGROUND) { //hexen2 style plaque. - if (rect->width > 320) + if (rect->width > (pic?pic->width:320)) { - rect->x = (rect->x + rect->width/2) - (160); - rect->width = 320; + rect->x = (rect->x + rect->width/2) - ((pic?pic->width:320) / 2); + rect->width = pic?pic->width:320; } + if (rect->width < 32) return; rect->x += 16; rect->width -= 32; + + /*keep the text inside the image too*/ + if (pic) + { + if (rect->height > (pic->height)) + { + rect->y = (rect->y + rect->height/2) - (pic->height/2); + rect->height = pic->height; + } + rect->y += 16; + rect->height -= 32; + } } - Font_BeginString(font_conchar, rect->x, rect->y, &left, &top); + y = rect->y; + + if (pic) + { + if (!(p->flags & CPRINT_BACKGROUND)) + { + y+= 16; + R2D_ScalePic ( (vid.width-pic->width)/2, 16, pic->width, pic->height, pic); + y+= pic->height; + y+= 8; + } + } + + Font_BeginString(font_conchar, rect->x, y, &left, &top); Font_BeginString(font_conchar, rect->x+rect->width, rect->y+rect->height, &right, &bottom); linecount = Font_LineBreaks(p->string, p->string + p->charcount, right - left, MAX_CPRINT_LINES, line_start, line_end); @@ -441,8 +492,6 @@ void SCR_DrawCenterString (vrect_t *rect, cprint_t *p) else if (p->flags & CPRINT_OBITUARTY) //'obituary' messages appear at the bottom of the screen y = (bottom-top - Font_CharHeight()*linecount) * 0.65 + top; - else if (p->flags & CPRINT_TYPEWRITER) - Font_BeginString(font_conchar, 48, rect->y, &y, &top); else { if (linecount <= 4) @@ -463,7 +512,10 @@ void SCR_DrawCenterString (vrect_t *rect, cprint_t *p) px = rect->x; py = ( y * vid.height) / (float)vid.pixelheight; pw = rect->width+8; - Draw_TextBox(px-16, py-8-8, pw/8, linecount+2); + if (*p->titleimage) + R2D_ScalePic (px-16, py-16, pw + 16, linecount*8 + 32, pic); + else + Draw_TextBox(px-16, py-8-8, pw/8, linecount+2); } for (l = 0; l < linecount; l++, y += Font_CharHeight()) @@ -545,6 +597,8 @@ void SCR_DrawCursor(int prydoncursornum) p = R2D_SafeCachePic(va("gfx/prydoncursor%03i.lmp", prydoncursornum)); else p = R2D_SafeCachePic(cl_cursor.string); + if (!p) + p = R2D_SafeCachePic("gfx/cursor.lmp"); if (p) { R2D_ImageColours(1, 1, 1, 1); @@ -1007,7 +1061,7 @@ void SCR_CrosshairPosition(int pnum, int *x, int *y) memset(&tr, 0, sizeof(tr)); tr.fraction = 1; - cl.worldmodel->funcs.Trace(cl.worldmodel, 0, 0, NULL, start, end, vec3_origin, vec3_origin, &tr); + cl.worldmodel->funcs.NativeTrace(cl.worldmodel, 0, 0, NULL, start, end, vec3_origin, vec3_origin, MASK_WORLDSOLID, &tr); start[2]-=16; if (tr.fraction == 1) { @@ -2105,7 +2159,7 @@ void SCR_TileClear (void) if (cl.splitclients>1) return; //splitclients always takes the entire screen. -#ifdef PLUGINS +/*#ifdef PLUGINS if (plug_sbar.ival) { if (scr_vrect.x > 0) @@ -2132,6 +2186,7 @@ void SCR_TileClear (void) } else #endif + */ { if (scr_vrect.x > 0) { diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index fdc08b169..736b4dab1 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -202,7 +202,9 @@ typedef struct int type; vec3_t angles; + vec3_t avel; int flags; + float gravity; float alpha; float start; float framerate; @@ -389,6 +391,7 @@ void P_LoadedModel(model_t *mod) P_DefaultTrail(mod); } +void CL_RefreshCustomTEnts(void); void CL_RegisterParticles(void) { model_t *mod; @@ -460,6 +463,8 @@ void CL_RegisterParticles(void) ptfte_lightning3_end = P_FindParticleType("TE_LIGHTNING3_END"); ptfte_bullet = P_FindParticleType("TE_BULLET"); ptfte_superbullet = P_FindParticleType("TE_SUPERBULLET"); + + CL_RefreshCustomTEnts(); } #ifdef Q2CLIENT @@ -512,6 +517,18 @@ void CL_ClearTEnts (void) memset (&cl_explosions, 0, sizeof(cl_explosions)); } +static void CL_ClearExplosion(explosion_t *exp) +{ + exp->gravity = 0; + exp->flags = 0; + exp->model = NULL; + exp->firstframe = -1; + exp->framerate = 10; + VectorClear(exp->velocity); + VectorClear(exp->angles); + VectorClear(exp->avel); +} + /* ================= CL_AllocExplosion @@ -527,8 +544,7 @@ explosion_t *CL_AllocExplosion (void) { if (!cl_explosions[i].model) { - cl_explosions[i].firstframe = -1; - cl_explosions[i].framerate = 10; + CL_ClearExplosion(&cl_explosions[i]); return &cl_explosions[i]; } } @@ -536,8 +552,7 @@ explosion_t *CL_AllocExplosion (void) if (i == explosions_running && i != MAX_EXPLOSIONS) { explosions_running++; - cl_explosions[i].firstframe = -1; - cl_explosions[i].framerate = 10; + CL_ClearExplosion(&cl_explosions[i]); return &cl_explosions[i]; } @@ -551,8 +566,7 @@ explosion_t *CL_AllocExplosion (void) time = cl_explosions[i].start; index = i; } - cl_explosions[index].firstframe = -1; - cl_explosions[index].framerate = 10; + CL_ClearExplosion(&cl_explosions[index]); return &cl_explosions[index]; } @@ -828,6 +842,10 @@ void CL_ParseStream (int type) b->model = Mod_ForName("models/stmedgaz.mdl", true); b->particleeffect = P_FindParticleType("te_stream_gaze"); break; + case TEH2_STREAM_FAMINE: + b->model = Mod_ForName("models/fambeam.mdl", true); + b->particleeffect = P_FindParticleType("te_stream_famine"); + break; default: Con_Printf("CL_ParseStream: type %i\n", type); break; @@ -1649,14 +1667,14 @@ void CL_ParseCustomTEnt(void) } else { + MSG_ReadPos (pos); + VectorCopy(pos, pos2); + if (t->netstyle & CTE_CUSTOMCOUNT) count = MSG_ReadByte(); else count = 1; - MSG_ReadPos (pos); - VectorCopy(pos, pos2); - if (t->netstyle & CTE_CUSTOMVELOCITY) { dir[0] = MSG_ReadCoord(); @@ -1717,6 +1735,12 @@ void CL_ParseCustomTEnt(void) */ } } +void CL_RefreshCustomTEnts(void) +{ + int i; + for (i = 0; i < sizeof(customtenttype)/sizeof(customtenttype[0]); i++) + customtenttype[i].particleeffecttype = P_FindParticleType(customtenttype[i].name); +} void CL_ClearCustomTEnts(void) { int i; @@ -1849,9 +1873,11 @@ void CL_ParseParticleEffect4 (void) P_RunParticleEffect4 (org, radius, color, effect, msgcount); } -void CL_SpawnSpriteEffect(vec3_t org, vec3_t dir, model_t *model, int startframe, int framecount, int framerate, float alpha) +void CL_SpawnSpriteEffect(vec3_t org, vec3_t dir, model_t *model, int startframe, int framecount, float framerate, float alpha, float randspin, float gravity) { explosion_t *ex; + vec3_t spos; + float dlen; ex = CL_AllocExplosion (); VectorCopy (org, ex->origin); @@ -1862,12 +1888,25 @@ void CL_SpawnSpriteEffect(vec3_t org, vec3_t dir, model_t *model, int startframe ex->framerate = framerate; ex->alpha = alpha; - ex->angles[0] = 0; - ex->angles[1] = 0; - ex->angles[2] = 0; + if (randspin) + { + ex->angles[0] = frandom()*360; + ex->angles[1] = frandom()*360; + ex->angles[2] = frandom()*360; + + ex->avel[0] = crandom()*randspin; + ex->avel[1] = crandom()*randspin; + ex->avel[2] = crandom()*randspin; + } + ex->gravity = gravity; if (dir) + { VectorCopy(dir, ex->velocity); + dlen = -10/VectorLength(dir); + VectorMA(ex->origin, dlen, dir, spos); + TraceLineN(spos, org, ex->origin, NULL); + } else VectorClear(ex->velocity); } @@ -1900,7 +1939,7 @@ void CL_ParseEffect (qboolean effect2) framerate = MSG_ReadByte(); - CL_SpawnSpriteEffect(org, vec3_origin, cl.model_precache[modelindex], startframe, framecount, framerate, 1); + CL_SpawnSpriteEffect(org, vec3_origin, cl.model_precache[modelindex], startframe, framecount, framerate, 1, 0, 0); } #ifdef Q2CLIENT @@ -2999,6 +3038,12 @@ void CL_UpdateExplosions (void) explosion_t *ex; entity_t *ent; int lastrunningexplosion = -1; + vec3_t pos, norm; + static float oldtime; + float frametime = cl.time - oldtime; + if (frametime < 0 || frametime > 100) + frametime = 0; + oldtime = cl.time; for (i=0, ex=cl_explosions; i < explosions_running; i++, ex++) { @@ -3031,7 +3076,37 @@ void CL_UpdateExplosions (void) ent = CL_NewTempEntity (); if (!ent) return; - VectorMA (ex->origin, f, ex->velocity, ent->origin); + + if (ex->gravity) + { + VectorMA(ex->origin, frametime, ex->velocity, pos); + if (ex->velocity[0] || ex->velocity[1] || ex->velocity[2]) + { + VectorClear(norm); + if (TraceLineN(ex->origin, pos, ent->origin, norm)) + { + float sc = DotProduct(ex->velocity, norm) * -1.5; + VectorMA(ex->velocity, sc, norm, ex->velocity); + VectorScale(ex->velocity, 0.9, ex->velocity); + if (norm[2] > 0.7 && DotProduct(ex->velocity, ex->velocity) < 10) + { + VectorClear(ex->velocity); + VectorClear(ex->avel); + } + } + else + ex->velocity[2] -= ex->gravity * frametime; + VectorCopy(ent->origin, ex->origin); + } + else + VectorCopy(ex->origin, ent->origin); + } + else + { + VectorMA (ex->origin, f, ex->velocity, ent->origin); + } + VectorMA(ex->angles, frametime, ex->avel, ex->angles); + VectorCopy (ex->oldorigin, ent->oldorigin); VectorCopy (ex->angles, ent->angles); ent->skinnum = ex->skinnum; @@ -3055,7 +3130,7 @@ void CL_UpdateExplosions (void) ent->shaderRGBAf[1] = ((d_8to24rgbtable[ex->skinnum & 0xFF] >> 8) & 0xFF)/255.0; ent->shaderRGBAf[2] = ((d_8to24rgbtable[ex->skinnum & 0xFF] >> 16) & 0xFF)/255.0; } - else + else if (ex->skinnum < 0) { ent->skinnum = 7*f/(numframes); } diff --git a/engine/client/cl_ui.c b/engine/client/cl_ui.c index 236871728..be49307c5 100644 --- a/engine/client/cl_ui.c +++ b/engine/client/cl_ui.c @@ -592,7 +592,7 @@ void VQ3_RenderView(const q3refdef_t *ref) #ifdef GLQUAKE if (qrenderer == QR_OPENGL) { - GL_Set2D (); + GL_Set2D (false); } #endif diff --git a/engine/client/client.h b/engine/client/client.h index 84d323552..27481eb8a 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -221,7 +221,7 @@ typedef struct typedef struct { int destcolor[3]; - int percent; // 0-256 + float percent; // 0-256 } cshift_t; #define CSHIFT_CONTENTS 0 @@ -995,7 +995,7 @@ void CL_ParseParticleEffect4 (void); void CLDP_ParseTrailParticles(void); void CLDP_ParsePointParticles(qboolean compact); -void CL_SpawnSpriteEffect(vec3_t org, vec3_t dir, struct model_s *model, int startframe, int framecount, int framerate, float alpha); /*called from the particlesystem*/ +void CL_SpawnSpriteEffect(vec3_t org, vec3_t dir, struct model_s *model, int startframe, int framecount, float framerate, float alpha, float randspin, float gravity); /*called from the particlesystem*/ // // cl_ents.c diff --git a/engine/client/console.c b/engine/client/console.c index 472c8db0d..70916bb46 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -603,7 +603,7 @@ void Con_PrintCon (console_t *con, char *txt) #if defined(_WIN32) && !defined(NOMEDIA) if (con->current) - TTS_SayConString(con->current+1); + TTS_SayConString((conchar_t*)(con->current+1)); #endif con->current->newer = Z_Malloc(sizeof(conline_t) + sizeof(conchar_t)); @@ -844,7 +844,7 @@ void Con_DrawInput (int left, int right, int y) if (con_current->commandcompletion) { - if (text[1] == '/' || Cmd_IsCommand(text+1)) + if (cl_chatmode.ival && (text[1] == '/' || (cl_chatmode.ival == 2 && Cmd_IsCommand(text+1)))) { //color the first token yellow, it's a valid command for (p = 1; (maskedtext[p]&CON_CHARMASK)>' '; p++) maskedtext[p] = (maskedtext[p]&CON_CHARMASK) | (COLOR_YELLOW<filmstarttime = curtime; cin->avi.resettimer = 0; + newframe = 0; + newframei = newframe; } - - newframe = (((curtime - cin->filmstarttime) * cin->avi.vidinfo.dwRate) / cin->avi.vidinfo.dwScale) + cin->avi.vidinfo.dwInitialFrames; - newframei = newframe; - - if (newframei>=cin->avi.num_frames) - cin->ended = true; - - if (newframei == cin->currentframe) + else { - cin->outunchanged = true; - return true; + newframe = (((curtime - cin->filmstarttime) * cin->avi.vidinfo.dwRate) / cin->avi.vidinfo.dwScale) + cin->avi.vidinfo.dwInitialFrames; + newframei = newframe; + + if (newframei>=cin->avi.num_frames) + cin->ended = true; + + if (newframei == cin->currentframe) + { + cin->outunchanged = true; + return true; + } } cin->outunchanged = false; @@ -2905,7 +2909,7 @@ void TTS_SayChatString(char **stringtosay) return; } - TTS_SayAsciiString(stringtosay); + TTS_SayAsciiString(*stringtosay); } void TTS_SayConString(conchar_t *stringtosay) { diff --git a/engine/client/p_classic.c b/engine/client/p_classic.c index 878167f62..3315cb4d9 100644 --- a/engine/client/p_classic.c +++ b/engine/client/p_classic.c @@ -125,8 +125,6 @@ static int PClassic_FindParticleType(char *name) return BLOBEXPLOSION_POINT; if (!stricmp("te_lavasplash", name)) return LAVASPLASH_POINT; - if (!stricmp("te_lavasplash", name)) - return LAVASPLASH_POINT; if (!stricmp("te_explosion", name)) return EXPLOSION_POINT; if (!stricmp("te_teleport", name)) @@ -135,6 +133,61 @@ static int PClassic_FindParticleType(char *name) return P_INVALID; } +qboolean PClassic_Query(int type, int body, char *outstr, int outstrlen) +{ + char *n = NULL; + switch(type) + { + case ROCKET_TRAIL: + n = "tr_rocket"; + break; + case ALT_ROCKET_TRAIL: + n = "tr_altrocket"; + break; + case BLOOD_TRAIL: + n = "tr_slightblood"; + break; + case GRENADE_TRAIL: + n = "tr_grenade"; + break; + case BIG_BLOOD_TRAIL: + n = "tr_blood"; + break; + case TRACER1_TRAIL: + n = "tr_wizspike"; + break; + case TRACER2_TRAIL: + n = "tr_knightspike"; + break; + case VOOR_TRAIL: + n = "tr_vorespike"; + break; + + case BLOBEXPLOSION_POINT: + n = "te_tarexplosion"; + break; + case LAVASPLASH_POINT: + n = "te_lavasplash"; + break; + case EXPLOSION_POINT: + n = "te_explosion"; + break; + case TELEPORTSPLASH_POINT: + n = "te_teleport"; + break; + } + + if (!n) + return false; + + if (body == 0) + { + Q_strncpyz(outstr, n, outstrlen); + return true; + } + return false; +} + //returns a valid effect if both its existance is known, and it is fully functional static int PClassic_ParticleTypeForName(char *name) { @@ -860,6 +913,7 @@ particleengine_t pe_classic = PClassic_ParticleTypeForName, PClassic_FindParticleType, + PClassic_Query, PClassic_RunParticleEffectTypeString, PClassic_ParticleTrail, diff --git a/engine/client/p_null.c b/engine/client/p_null.c index 24d99a5a7..d0e268f68 100644 --- a/engine/client/p_null.c +++ b/engine/client/p_null.c @@ -62,6 +62,7 @@ particleengine_t pe_null = PNULL_ParticleTypeForName, PNULL_FindParticleType, + NULL, PNULL_RunParticleEffectTypeString, PNULL_ParticleTrail, diff --git a/engine/client/p_script.c b/engine/client/p_script.c index 78ee7f2c2..0812db715 100644 --- a/engine/client/p_script.c +++ b/engine/client/p_script.c @@ -159,17 +159,21 @@ typedef struct { float scale; float rotation; } ramp_t; +typedef struct { + char name[MAX_QPATH]; + model_t *model; + float framestart; + float frameend; + float framerate; + float alpha; +} partmodels_t; // TODO: merge in alpha with rgb to gain benefit of vector opts typedef struct part_type_s { char name[MAX_QPATH]; char texname[MAX_QPATH]; - char modelname[MAX_QPATH]; - model_t *model; - float modelframestart; - float modelframeend; - float modelframerate; - float modelalpha; + int nummodels; + partmodels_t *models; vec3_t rgb; //initial colour float alpha; @@ -184,7 +188,7 @@ typedef struct part_type_s { float scale; //initial scale float scalerand; //with up to this much extra float die, randdie; //how long it lasts (plus some rand) - float randomvel, randomvelvert; //random velocity (unaligned) + float randomvel, randomvelvert, randomvelvertbias; //random velocity (unaligned=worldspace) float veladd; //scale the incoming velocity by this much float orgadd; //spawn the particle this far along its velocity direction float spawnvel, spawnvelvert; //spawn the particle with a velocity based upon its spawn type (generally so it flies outwards) @@ -504,10 +508,12 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn) texnums_t tn; char *defaultshader; char *namepostfix; + int i; if (qrenderer == QR_NONE) return; - ptype->model = NULL; + for (i = 0; i < ptype->nummodels; i++) + ptype->models[i].model = NULL; if (*ptype->texname) { @@ -535,7 +541,7 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn) "rgbgen vertex\n" "alphagen vertex\n" "}\n" -// "polygonoffset\n" + "polygonoffset\n" "}\n" ; break; @@ -551,7 +557,7 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn) "rgbgen vertex\n" "alphagen vertex\n" "}\n" -// "polygonoffset\n" + "polygonoffset\n" "}\n" ; break; @@ -567,7 +573,7 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn) "rgbgen vertex\n" "alphagen vertex\n" "}\n" -// "polygonoffset\n" + "polygonoffset\n" "}\n" ; break; @@ -583,7 +589,7 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn) "rgbgen vertex\n" "alphagen vertex\n" "}\n" -// "polygonoffset\n" + "polygonoffset\n" "}\n" ; break; @@ -599,7 +605,7 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn) "rgbgen vertex\n" "alphagen vertex\n" "}\n" -// "polygonoffset\n" + "polygonoffset\n" "}\n" ; break; @@ -744,6 +750,8 @@ static void P_ParticleEffect_f(void) st = ptype->skytris; if (ptype->ramp) BZ_Free(ptype->ramp); + if (ptype->models) + BZ_Free(ptype->models); while (ptype->particles) // empty particle list { @@ -951,17 +959,35 @@ static void P_ParticleEffect_f(void) setalphadelta = true; } else if (!strcmp(var, "die")) + { ptype->die = atof(value); + if (Cmd_Argc()>2) + ptype->randdie = atof(Cmd_Argv(2)) - ptype->die; + } else if (!strcmp(var, "diesubrand")) ptype->randdie = atof(value); else if (!strcmp(var, "randomvel")) { ptype->randomvel = atof(value); - if (Cmd_Argc()>2) + if (Cmd_Argc()>3) + { + ptype->randomvelvertbias = atof(Cmd_Argv(2)); + ptype->randomvelvert = atof(Cmd_Argv(3)); + ptype->randomvelvert -= ptype->randomvelvertbias; /*make vert be the total range*/ + ptype->randomvelvert /= 2; /*vert is actually +/- 1, not 0 to 1, so rescale it*/ + ptype->randomvelvertbias += ptype->randomvelvert; /*and bias must be centered to the range*/ + } + else if (Cmd_Argc()>2) + { ptype->randomvelvert = atof(Cmd_Argv(2)); + ptype->randomvelvertbias = 0; + } else + { ptype->randomvelvert = ptype->randomvel; + ptype->randomvelvertbias = 0; + } } else if (!strcmp(var, "veladd")) ptype->veladd = atof(value); @@ -1002,11 +1028,13 @@ static void P_ParticleEffect_f(void) } else if (!strcmp(var, "model")) { - Q_strncpyz(ptype->modelname, Cmd_Argv(1), sizeof(ptype->modelname)); - ptype->modelframestart = atof(Cmd_Argv(2)); - ptype->modelframeend = atof(Cmd_Argv(3)); - ptype->modelframerate = atof(Cmd_Argv(4)); - ptype->modelalpha = atof(Cmd_Argv(5)); + ptype->models = BZ_Realloc(ptype->models, sizeof(partmodels_t)*(ptype->nummodels+1)); + Q_strncpyz(ptype->models[ptype->nummodels].name, Cmd_Argv(1), sizeof(ptype->models[ptype->nummodels].name)); + ptype->models[ptype->nummodels].framestart = atof(Cmd_Argv(2)); + ptype->models[ptype->nummodels].frameend = atof(Cmd_Argv(3)); + ptype->models[ptype->nummodels].framerate = atof(Cmd_Argv(4)); + ptype->models[ptype->nummodels].alpha = atof(Cmd_Argv(5)); + ptype->nummodels++; } else if (!strcmp(var, "colorindex")) { @@ -1407,6 +1435,168 @@ static void P_ParticleEffect_f(void) r_plooksdirty = true; } +qboolean PScript_Query(int typenum, int body, char *outstr, int outstrlen) +{ + int i; + part_type_t *ptype = &part_type[typenum]; + if (typenum < 0 || typenum >= numparticletypes) + return false; + + if (body == 0) + { + Q_strncpyz(outstr, ptype->name, outstrlen); + return true; + } + + if (body == 1) + { + *outstr = 0; + if (!ptype->loaded) + return true; + + Q_strncatz(outstr, va("//this functionality is incomplete\n"), outstrlen); + + for (i = 0; i < ptype->nummodels; i++) + { + Q_strncatz(outstr, va("model %s %g %g %g %g\n", ptype->models[i].name, ptype->models[i].framestart, ptype->models[i].frameend, ptype->models[i].framerate, ptype->models[i].alpha), outstrlen); + } + + if (*ptype->texname) + Q_strncatz(outstr, va("texture %s\n", ptype->texname), outstrlen); + if (ptype->count) + Q_strncatz(outstr, va("count %g\n", ptype->count), outstrlen); + + if (ptype->rgb[0] || ptype->rgb[1] || ptype->rgb[2]) + Q_strncatz(outstr, va("rgb %g %g %g\n", ptype->rgb[0]*255, ptype->rgb[1]*255, ptype->rgb[2]*255), outstrlen); + if (ptype->rgbrand[0] || ptype->rgbrand[1] || ptype->rgbrand[2]) + Q_strncatz(outstr, va("rgbrand %g %g %g\n", ptype->rgbrand[0]*255, ptype->rgbrand[1]*255, ptype->rgbrand[2]*255), outstrlen); + if (ptype->rgbrandsync[0] || ptype->rgbrandsync[1] || ptype->rgbrandsync[2]) + Q_strncatz(outstr, va("rgbrandsync %g %g %g\n", ptype->rgbrandsync[0], ptype->rgbrandsync[1], ptype->rgbrandsync[2]), outstrlen); + if (ptype->rgbchange[0] || ptype->rgbchange[1] || ptype->rgbchange[2]) + Q_strncatz(outstr, va("rgbchange %g %g %g\n", ptype->rgbchange[0]*255, ptype->rgbchange[1]*255, ptype->rgbchange[2]*255), outstrlen); + if (ptype->rgbchangetime) + Q_strncatz(outstr, va("rgbchangetime %g\n", ptype->rgbchangetime), outstrlen); + + if (ptype->colorindex) + Q_strncatz(outstr, va("colorindex %i\n", ptype->colorindex), outstrlen); + if (ptype->colorrand) + Q_strncatz(outstr, va("colorrand %i\n", ptype->colorrand), outstrlen); + + if (ptype->alpha) + Q_strncatz(outstr, va("alpha %g\n", ptype->alpha), outstrlen); + if (ptype->alpharand) + Q_strncatz(outstr, va("alpharand %g\n", ptype->alpharand), outstrlen); + if (ptype->alphachange) + Q_strncatz(outstr, va("alphadelta %g\n", ptype->alphachange), outstrlen); + + if (ptype->scale || ptype->scalerand) + Q_strncatz(outstr, va("scale %g %g\n", ptype->scale, ptype->scale+ptype->scalerand), outstrlen); +// if (ptype->looks.scalefactor) + Q_strncatz(outstr, va("scalefactor %g\n", ptype->looks.scalefactor), outstrlen); + if (ptype->scaledelta) + Q_strncatz(outstr, va("scaledelta %g\n", ptype->scaledelta), outstrlen); + + if (ptype->die || ptype->randdie) + Q_strncatz(outstr, va("die %g %g\n", ptype->die, ptype->die+ptype->randdie), outstrlen); + + if (ptype->randomvel || ptype->randomvelvert || ptype->randomvelvertbias) + Q_strncatz(outstr, va("randomvel %g %g %g\n", ptype->randomvel, ptype->randomvelvertbias - ptype->randomvelvert, ptype->randomvelvertbias + ptype->randomvelvert), outstrlen); + + if (ptype->veladd) + Q_strncatz(outstr, va("veladd %g\n", ptype->veladd), outstrlen); + if (ptype->orgadd) + Q_strncatz(outstr, va("orgadd %g\n", ptype->orgadd), outstrlen); + + if (ptype->spawnvel || ptype->spawnvelvert) + Q_strncatz(outstr, va("spawnvel %g %g\n", ptype->spawnvel, ptype->spawnvelvert), outstrlen); + + if (ptype->assoc != P_INVALID) + Q_strncatz(outstr, va("assoc %s\n", part_type[ptype->assoc].name), outstrlen); + + Q_strncatz(outstr, va("tcoords %g %g %g %g %g %i %g\n", ptype->s1, ptype->t1, ptype->s2, ptype->t2, 1.0f, ptype->randsmax, ptype->texsstride), outstrlen); + + Q_strncatz(outstr, va("rotationstart %g %g\n", ptype->rotationstartmin*180/M_PI, (ptype->rotationstartmin+ptype->rotationstartrand)*180/M_PI), outstrlen); + Q_strncatz(outstr, va("rotationspeed %g %g\n", ptype->rotationmin*180/M_PI, (ptype->rotationmin+ptype->rotationrand)*180/M_PI), outstrlen); + return true; + +#if 0 + plooks_t *slooks; //shared looks, so state switches don't apply between particles so much + plooks_t looks; + + float spawntime; //time limit for trails + float spawnchance; //if < 0, particles might not spawn so many + + float scaledelta; + int countextra; + float count; + float countrand; + + int cliptype; + int inwater; + float clipcount; + int emit; + float emittime; + float emitrand; + float emitstart; + + float areaspread; + float areaspreadvert; + + float spawnparam1; + float spawnparam2; +/* float spawnparam3; */ + + float offsetup; // make this into a vec3_t later with dir, possibly for mdls + + enum { + SM_BOX, //box = even spread within the area + SM_CIRCLE, //circle = around edge of a circle + SM_BALL, //ball = filled sphere + SM_SPIRAL, //spiral = spiral trail + SM_TRACER, //tracer = tracer trail + SM_TELEBOX, //telebox = q1-style telebox + SM_LAVASPLASH, //lavasplash = q1-style lavasplash + SM_UNICIRCLE, //unicircle = uniform circle + SM_FIELD, //field = synced field (brightfield, etc) + SM_DISTBALL // uneven distributed ball + } spawnmode; + + float gravity; + vec3_t friction; + float clipbounce; + int stainonimpact; + + vec3_t dl_rgb; + float dl_radius; + float dl_time; + vec4_t dl_decay; + vec3_t stain_rgb; + float stain_radius; + + enum {RAMP_NONE, RAMP_DELTA, RAMP_ABSOLUTE} rampmode; + int rampindexes; + ramp_t *ramp; + + int loaded; + particle_t *particles; + clippeddecal_t *clippeddecals; + beamseg_t *beams; + skytris_t *skytris; + struct part_type_s *nexttorun; + + unsigned int flags; +#define PT_CITRACER 0x008 // Q1-style tracer behavior for colorindex +#define PT_INVFRAMETIME 0x010 // apply inverse frametime to count (causes emits to be per frame) +#define PT_AVERAGETRAIL 0x020 // average trail points from start to end, useful with t_lightning, etc +#define PT_NOSTATE 0x040 // don't use trailstate for this emitter (careful with assoc...) +#define PT_NOSPREADFIRST 0x080 // don't randomize org/vel for first generated particle +#define PT_NOSPREADLAST 0x100 // don't randomize org/vel for last generated particle +#endif + } + + return false; +} + #if _DEBUG // R_BeamInfo_f - debug junk static void P_BeamInfo_f (void) @@ -2405,14 +2595,248 @@ static vec2_t avelocities[NUMVERTEXNORMALS]; // float timescale = 0.01; -static void PScript_EffectSpawned(part_type_t *ptype, vec3_t org, vec3_t dir, int dlkey) + +static void PScript_ApplyOrgVel(vec3_t oorg, vec3_t ovel, vec3_t eforg, vec3_t efdir, int pno, int pmax, part_type_t *ptype) { - if (*ptype->modelname) + vec3_t ofsvec, arsvec; + + float k,l,m; + int spawnspc, i=pno, j; + + + l=0; + j=0; + k=0; + m=0; + + spawnspc = 8; + switch (ptype->spawnmode) { - if (!ptype->model) - ptype->model = Mod_ForName(ptype->modelname, false); - if (ptype->model && !ptype->model->needload) - CL_SpawnSpriteEffect(org, dir, ptype->model, ptype->modelframestart, (ptype->modelframeend?ptype->modelframeend:(ptype->model->numframes - ptype->modelframestart)), ptype->modelframerate?ptype->modelframerate:10, ptype->modelalpha?ptype->modelalpha:1); + case SM_UNICIRCLE: + m = pmax; + if (ptype->looks.type == PT_BEAM) + m--; + + if (m < 1) + m = 0; + else + m = (M_PI*2)/m; + + if (ptype->spawnparam1) /* use for weird shape hacks */ + m *= ptype->spawnparam1; + break; + case SM_TELEBOX: + spawnspc = 4; + l = -ptype->areaspreadvert; + case SM_LAVASPLASH: + j = k = -ptype->areaspread; + if (ptype->spawnparam1) + m = ptype->spawnparam1; + else + m = 0.55752; /* default weird number for tele/lavasplash used in vanilla Q1 */ + + if (ptype->spawnparam2) + spawnspc = (int)ptype->spawnparam2; + break; + case SM_FIELD: + if (!avelocities[0][0]) + { + for (j=0 ; jrandomvel; + ovel[1] = crandom()*ptype->randomvel; + ovel[2] = crandom()*ptype->randomvelvert + ptype->randomvelvertbias; + + // handle spawn modes (org/vel) + switch (ptype->spawnmode) + { + case SM_BOX: + ofsvec[0] = crandom(); + ofsvec[1] = crandom(); + ofsvec[2] = crandom(); + + arsvec[0] = ofsvec[0]*ptype->areaspread; + arsvec[1] = ofsvec[1]*ptype->areaspread; + arsvec[2] = ofsvec[2]*ptype->areaspreadvert; + break; + case SM_TELEBOX: + ofsvec[0] = k; + ofsvec[1] = j; + ofsvec[2] = l+4; + VectorNormalize(ofsvec); + VectorScale(ofsvec, 1.0-(frandom())*m, ofsvec); + + // org is just like the original + arsvec[0] = j + (rand()%spawnspc); + arsvec[1] = k + (rand()%spawnspc); + arsvec[2] = l + (rand()%spawnspc); + + // advance telebox loop + j += spawnspc; + if (j >= ptype->areaspread) + { + j = -ptype->areaspread; + k += spawnspc; + if (k >= ptype->areaspread) + { + k = -ptype->areaspread; + l += spawnspc; + if (l >= ptype->areaspreadvert) + l = -ptype->areaspreadvert; + } + } + break; + case SM_LAVASPLASH: + // calc directions, org with temp vector + ofsvec[0] = k + (rand()%spawnspc); + ofsvec[1] = j + (rand()%spawnspc); + ofsvec[2] = 256; + + arsvec[0] = ofsvec[0]; + arsvec[1] = ofsvec[1]; + arsvec[2] = frandom()*ptype->areaspreadvert; + + VectorNormalize(ofsvec); + VectorScale(ofsvec, 1.0-(frandom())*m, ofsvec); + + // advance splash loop + j += spawnspc; + if (j >= ptype->areaspread) + { + j = -ptype->areaspread; + k += spawnspc; + if (k >= ptype->areaspread) + k = -ptype->areaspread; + } + break; + case SM_UNICIRCLE: + ofsvec[0] = cos(m*i); + ofsvec[1] = sin(m*i); + ofsvec[2] = 0; + VectorScale(ofsvec, ptype->areaspread, arsvec); + break; + case SM_FIELD: + arsvec[0] = cl.time * (avelocities[i][0] + m); + arsvec[1] = cl.time * (avelocities[i][1] + m); + arsvec[2] = cos(arsvec[1]); + + ofsvec[0] = arsvec[2]*cos(arsvec[0]); + ofsvec[1] = arsvec[2]*sin(arsvec[0]); + ofsvec[2] = -sin(arsvec[1]); + + arsvec[0] = r_avertexnormals[j][0]*ptype->areaspread + ofsvec[0]*BEAMLENGTH; + arsvec[1] = r_avertexnormals[j][1]*ptype->areaspread + ofsvec[1]*BEAMLENGTH; + arsvec[2] = r_avertexnormals[j][2]*ptype->areaspreadvert + ofsvec[2]*BEAMLENGTH; + + VectorNormalize(ofsvec); + + j++; + if (j >= NUMVERTEXNORMALS) + { + j = 0; + m += 0.1762891; // some BS number to try to "randomize" things + } + break; + case SM_DISTBALL: + { + float rdist; + + rdist = ptype->spawnparam2 - crandom()*(1-(crandom() * ptype->spawnparam1)); + + // this is a strange spawntype, which is based on the fact that + // crandom()*crandom() provides something similar to an exponential + // probability curve + ofsvec[0] = hrandom(); + ofsvec[1] = hrandom(); + if (ptype->areaspreadvert) + ofsvec[2] = hrandom(); + else + ofsvec[2] = 0; + + VectorNormalize(ofsvec); + VectorScale(ofsvec, rdist, ofsvec); + + arsvec[0] = ofsvec[0]*ptype->areaspread; + arsvec[1] = ofsvec[1]*ptype->areaspread; + arsvec[2] = ofsvec[2]*ptype->areaspreadvert; + } + break; + default: // SM_BALL, SM_CIRCLE + ofsvec[0] = hrandom(); + ofsvec[1] = hrandom(); + if (ptype->areaspreadvert) + ofsvec[2] = hrandom(); + else + ofsvec[2] = 0; + + VectorNormalize(ofsvec); + if (ptype->spawnmode != SM_CIRCLE) + VectorScale(ofsvec, frandom(), ofsvec); + + arsvec[0] = ofsvec[0]*ptype->areaspread; + arsvec[1] = ofsvec[1]*ptype->areaspread; + arsvec[2] = ofsvec[2]*ptype->areaspreadvert; + break; + } + + oorg[0] = eforg[0] + arsvec[0]; + oorg[1] = eforg[1] + arsvec[1]; + oorg[2] = eforg[2] + arsvec[2] + ptype->offsetup; + + // apply arsvec+ofsvec + if (efdir) + { + ovel[0] += efdir[0]*ptype->veladd+ofsvec[0]*ptype->spawnvel; + ovel[1] += efdir[1]*ptype->veladd+ofsvec[1]*ptype->spawnvel; + ovel[2] += efdir[2]*ptype->veladd+ofsvec[2]*ptype->spawnvelvert; + + oorg[0] += efdir[0]*ptype->orgadd; + oorg[1] += efdir[1]*ptype->orgadd; + oorg[2] += efdir[2]*ptype->orgadd; + } + else + { + ovel[0] += ofsvec[0]*ptype->spawnvel; + ovel[1] += ofsvec[1]*ptype->spawnvel; + ovel[2] += ofsvec[2]*ptype->spawnvelvert - ptype->veladd; + + oorg[2] -= ptype->orgadd; + } +} + +static void PScript_EffectSpawned(part_type_t *ptype, vec3_t org, vec3_t dir, int dlkey, float countscale) +{ + if (ptype->nummodels) + { + int count = ptype->countextra + countscale*(ptype->count+ptype->countrand*frandom()); + int i; + partmodels_t *mod; + if (!ptype->countextra && !ptype->count) + count = countscale; + for (i = 0; i < count; i++) + { + mod = &ptype->models[rand() % ptype->nummodels]; + if (!mod->model) + mod->model = Mod_ForName(mod->name, false); + if (mod->model && !mod->model->needload) + { + vec3_t morg, mdir; + PScript_ApplyOrgVel(morg, mdir, org, dir, i, count, ptype); + CL_SpawnSpriteEffect(morg, mdir, mod->model, mod->framestart, (mod->frameend?mod->frameend:(mod->model->numframes - mod->framestart)), mod->framerate?mod->framerate:10, ptype->alpha?ptype->alpha:1, ptype->rotationmin*180/M_PI, ptype->gravity); + } + } } if (ptype->dl_radius) { @@ -2489,7 +2913,7 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count, while(ptype) { - PScript_EffectSpawned(ptype, org, dir, 0); + PScript_EffectSpawned(ptype, org, dir, 0, count); if (ptype->looks.type == PT_DECAL) { @@ -2531,7 +2955,7 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count, VectorSubtract(org, t2, tangent); VectorAdd(org, t2, t2); - if (cl.worldmodel->funcs.Trace (cl.worldmodel, 0, 0, NULL, tangent, t2, vec3_origin, vec3_origin, &tr)) + if (cl.worldmodel->funcs.NativeTrace (cl.worldmodel, 0, 0, NULL, tangent, t2, vec3_origin, vec3_origin, MASK_WORLDSOLID, &tr)) { if (tr.fraction < dist) { @@ -2546,17 +2970,19 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count, VectorNormalize(dir); VectorNormalize(vec); - CrossProduct(dir, vec, tangent); + CrossProduct(dir, vec, t2); + Matrix4x4_CM_Transform3(Matrix4x4_CM_NewRotation(frandom()*360, dir[0], dir[1], dir[2]), t2, tangent); CrossProduct(dir, tangent, t2); sw = ptype->s2 - ptype->s1; sb = ptype->s1 + sw/2; tw = ptype->t2 - ptype->t1; tb = ptype->t1 + tw/2; - sw /= ptype->scale; - tw /= ptype->scale; + m = ptype->scale + frandom() * ptype->scalerand; + sw /= m; + tw /= m; - decalcount = Q1BSP_ClipDecal(org, dir, tangent, t2, ptype->scale, &decverts); + decalcount = Q1BSP_ClipDecal(org, dir, tangent, t2, m, &decverts); while(decalcount) { if (!free_decals) @@ -2787,7 +3213,7 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count, // randomvel p->vel[0] = crandom()*ptype->randomvel; p->vel[1] = crandom()*ptype->randomvel; - p->vel[2] = crandom()*ptype->randomvelvert; + p->vel[2] = crandom()*ptype->randomvelvert + ptype->randomvelvertbias; // handle spawn modes (org/vel) switch (ptype->spawnmode) @@ -3298,7 +3724,7 @@ static void P_ParticleTrailDraw (vec3_t startpos, vec3_t end, part_type_t *ptype else ts = NULL; - PScript_EffectSpawned(ptype, start, vec3_origin, dlkey); + PScript_EffectSpawned(ptype, start, vec3_origin, dlkey, 1); if (ptype->assoc>=0) { @@ -4128,42 +4554,41 @@ static void GL_DrawParticleBeam(int count, beamseg_t **blist, plooks_t *type) } } -static void GL_DrawClippedDecal(int count, clippeddecal_t **dlist, plooks_t *type) +static void R_AddClippedDecal(scenetris_t *t, clippeddecal_t *d, plooks_t *type) { - clippeddecal_t *d; - - while (count--) + if (cl_numstrisvert+4 > cl_maxstrisvert) { - d = *dlist++; - - if (pscripttmesh.numvertexes >= BUFFERVERTS-3) - { - pscripttmesh.numindexes = pscripttmesh.numvertexes; - BE_DrawMesh_Single(type->shader, &pscripttmesh, NULL, &type->shader->defaulttextures, 0); - pscripttmesh.numvertexes = 0; - } - - Vector4Copy(d->rgba, pscriptcolours[pscripttmesh.numvertexes+0]); - Vector4Copy(d->rgba, pscriptcolours[pscripttmesh.numvertexes+1]); - Vector4Copy(d->rgba, pscriptcolours[pscripttmesh.numvertexes+2]); - - Vector2Copy(d->texcoords[0], pscripttexcoords[pscripttmesh.numvertexes+0]); - Vector2Copy(d->texcoords[1], pscripttexcoords[pscripttmesh.numvertexes+1]); - Vector2Copy(d->texcoords[2], pscripttexcoords[pscripttmesh.numvertexes+2]); - - VectorCopy(d->vertex[0], pscriptverts[pscripttmesh.numvertexes+0]); - VectorCopy(d->vertex[1], pscriptverts[pscripttmesh.numvertexes+1]); - VectorCopy(d->vertex[2], pscriptverts[pscripttmesh.numvertexes+2]); - - pscripttmesh.numvertexes += 3; + cl_maxstrisvert+=64*4; + cl_strisvertv = BZ_Realloc(cl_strisvertv, sizeof(*cl_strisvertv)*cl_maxstrisvert); + cl_strisvertt = BZ_Realloc(cl_strisvertt, sizeof(*cl_strisvertt)*cl_maxstrisvert); + cl_strisvertc = BZ_Realloc(cl_strisvertc, sizeof(*cl_strisvertc)*cl_maxstrisvert); } - if (pscripttmesh.numvertexes) + Vector4Copy(d->rgba, cl_strisvertc[cl_numstrisvert+0]); + Vector4Copy(d->rgba, cl_strisvertc[cl_numstrisvert+1]); + Vector4Copy(d->rgba, cl_strisvertc[cl_numstrisvert+2]); + + Vector2Copy(d->texcoords[0], cl_strisvertt[cl_numstrisvert+0]); + Vector2Copy(d->texcoords[1], cl_strisvertt[cl_numstrisvert+1]); + Vector2Copy(d->texcoords[2], cl_strisvertt[cl_numstrisvert+2]); + + VectorCopy(d->vertex[0], cl_strisvertv[cl_numstrisvert+0]); + VectorCopy(d->vertex[1], cl_strisvertv[cl_numstrisvert+1]); + VectorCopy(d->vertex[2], cl_strisvertv[cl_numstrisvert+2]); + + if (cl_numstrisidx+3 > cl_maxstrisidx) { - pscripttmesh.numindexes = pscripttmesh.numvertexes; - BE_DrawMesh_Single(type->shader, &pscripttmesh, NULL, &type->shader->defaulttextures, 0); - pscripttmesh.numvertexes = 0; + cl_maxstrisidx += 64*3; + cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx); } + cl_strisidx[cl_numstrisidx++] = (cl_numstrisvert - t->firstvert) + 0; + cl_strisidx[cl_numstrisidx++] = (cl_numstrisvert - t->firstvert) + 1; + cl_strisidx[cl_numstrisidx++] = (cl_numstrisvert - t->firstvert) + 2; + + cl_numstrisvert += 3; + + t->numvert += 3; + t->numidx += 3; } static void R_AddTexturedParticle(scenetris_t *t, particle_t *p, plooks_t *type) @@ -4339,6 +4764,23 @@ static void PScript_DrawParticleTypes (void) { if (type->clippeddecals) { + if (cl_numstris && cl_stris[cl_numstris-1].shader == type->looks.shader) + scenetri = &cl_stris[cl_numstris-1]; + else + { + if (cl_numstris == cl_maxstris) + { + cl_maxstris+=8; + cl_stris = BZ_Realloc(cl_stris, sizeof(*cl_stris)*cl_maxstris); + } + scenetri = &cl_stris[cl_numstris++]; + scenetri->shader = type->looks.shader; + scenetri->firstidx = cl_numstrisidx; + scenetri->firstvert = cl_numstrisvert; + scenetri->numvert = 0; + scenetri->numidx = 0; + } + for ( ;; ) { dkill = type->clippeddecals; @@ -4393,7 +4835,7 @@ static void PScript_DrawParticleTypes (void) d->rgba[3] += pframetime*type->alphachange; } - GL_DrawClippedDecal(1, &d, &type->looks); + R_AddClippedDecal(scenetri, d, type->slooks); } } @@ -4857,6 +5299,7 @@ particleengine_t pe_script = PScript_ParticleTypeForName, PScript_FindParticleType, + PScript_Query, PScript_RunParticleEffectTypeString, PScript_ParticleTrail, diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 953ee9a64..5a9f38a6d 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -1095,17 +1095,8 @@ static void QCBUILTIN PF_R_ClearScene (progfuncs_t *prinst, struct globalvars_s if (cl.worldmodel) { - //work out which packet entities are solid - CL_SetSolidEntities (); - - // Set up prediction for other players - CL_SetUpPlayerPrediction(false); - // do client side motion prediction CL_PredictMove (); - - // Set up prediction for other players - CL_SetUpPlayerPrediction(true); } skel_dodelete(csqcprogs); @@ -1383,7 +1374,7 @@ static void QCBUILTIN PF_R_RenderScene(progfuncs_t *prinst, struct globalvars_s #ifdef GLQUAKE if (qrenderer == QR_OPENGL) { - GL_Set2D (); + GL_Set2D (false); } #endif #ifdef D3DQUAKE @@ -1932,6 +1923,28 @@ static void QCBUILTIN PF_cs_particleeffectnum (progfuncs_t *prinst, struct globa } } +static void QCBUILTIN PF_cs_particleeffectquery (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + int id = G_FLOAT(OFS_PARM0); + qboolean body = G_FLOAT(OFS_PARM1); + char retstr[8192]; + + if (csqc_isdarkplaces) + { + //keep the effectinfo synced between server and client. + id = COM_Effectinfo_ForName(COM_Effectinfo_ForNumber(id)); + } + else + id = id - 1; + + if (pe->ParticleQuery && pe->ParticleQuery(id, body, retstr, sizeof(retstr))) + { + RETURN_TSTRING(retstr); + } + else + G_INT(OFS_RETURN) = 0; +} + static void QCBUILTIN PF_cs_sendevent (progfuncs_t *prinst, struct globalvars_s *pr_globals) { csqcedict_t *ent; @@ -2486,7 +2499,7 @@ void QCBUILTIN PF_cl_effect(progfuncs_t *prinst, struct globalvars_s *pr_globals mdl = Mod_ForName(name, false); if (mdl) - CL_SpawnSpriteEffect(org, NULL, mdl, startframe, endframe, framerate, 1); + CL_SpawnSpriteEffect(org, NULL, mdl, startframe, endframe, framerate, 1, 0, 0); else Con_Printf("PF_cl_effect: Couldn't load model %s\n", name); } @@ -4289,6 +4302,7 @@ static struct { {"dynamiclight_get", PF_R_DynamicLight_Get, 372}, {"dynamiclight_set", PF_R_DynamicLight_Set, 373}, + {"particleeffectquery", PF_cs_particleeffectquery, 374}, //400 {"copyentity", PF_cs_copyentity, 400}, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY) diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index ebe9ceda6..ba87a0352 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -2022,15 +2022,6 @@ void MP_Draw(void) if (setjmp(mp_abort)) return; -#ifdef GLQUAKE - if (qrenderer == QR_OPENGL) - { - GL_TexEnv(GL_MODULATE); - qglDisable(GL_ALPHA_TEST); - qglEnable(GL_BLEND); - } -#endif - menutime = Sys_DoubleTime(); if (mp_time) *mp_time = menutime; diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index 9a1cc7a9b..48a7995b4 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -275,12 +275,21 @@ mpic_t *R2D_SafeCachePic (char *path) char *failedpic; //easier this way mpic_t *R2D_SafePicFromWad (char *name) { - char newname[32]; + char newnamewad[32]; + char newnamegfx[32]; shader_t *s; - snprintf(newname, sizeof(newname), "gfx/%s.lmp", name); - s = R_RegisterPic(newname); + + snprintf(newnamewad, sizeof(newnamewad), "wad/%s.lmp", name); + snprintf(newnamegfx, sizeof(newnamegfx), "gfx/%s.lmp", name); + + s = R_RegisterPic(newnamewad); if (!(s->flags & SHADER_NOIMAGE)) return s; + + s = R_RegisterPic(newnamegfx); + if (!(s->flags & SHADER_NOIMAGE)) + return s; + failedpic = name; return NULL; } @@ -693,7 +702,7 @@ void R2D_ScreenAngle_Callback(struct cvar_s *var, char *oldvalue) R_PolyBlend ============ */ -//bright flashes and stuff +//bright flashes and stuff, game only, doesn't touch sbar void R2D_PolyBlend (void) { if (!sw_blend[3]) @@ -703,7 +712,7 @@ void R2D_PolyBlend (void) return; R2D_ImageColours (sw_blend[0], sw_blend[1], sw_blend[2], sw_blend[3]); - R2D_ScalePic(0, 0, vid.width, vid.height, shader_polyblend); + R2D_ScalePic(r_refdef.vrect.x, r_refdef.vrect.y, r_refdef.vrect.width, r_refdef.vrect.height, shader_polyblend); R2D_ImageColours (1, 1, 1, 1); } @@ -734,6 +743,9 @@ void R2D_BrightenScreen (void) } R2D_ImageColours (1, 1, 1, 1); + /*make sure the hud is drawn if needed*/ + Sbar_Changed(); + RSpeedEnd(RSPEED_PALETTEFLASHES); } diff --git a/engine/client/r_d3.c b/engine/client/r_d3.c index 47bb0936f..91b9c2156 100644 --- a/engine/client/r_d3.c +++ b/engine/client/r_d3.c @@ -823,7 +823,7 @@ return; D3_RecursiveSurfCheck (node->child[side^1], midf, p2f, mid, p2); } -qboolean D3_Trace (struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, struct trace_s *trace) +qboolean D3_Trace (struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, unsigned int hitcontentsmask, struct trace_s *trace) { int i; float e1,e2; @@ -1281,7 +1281,7 @@ qboolean D3_LoadMap_CollisionMap(model_t *mod, char *buf) mod->entities = FS_LoadMallocFile(va("%s.map", token)); mod->funcs.FindTouchedLeafs = D3_FindTouchedLeafs; - mod->funcs.Trace = D3_Trace; + mod->funcs.NativeTrace = D3_Trace; mod->funcs.PointContents = D3_PointContents; mod->funcs.FatPVS = D3_FatPVS; mod->funcs.LeafnumForPoint = D3_LeafnumForPoint; @@ -1304,4 +1304,4 @@ qboolean D3_LoadMap_CollisionMap(model_t *mod, char *buf) return true; } -#endif \ No newline at end of file +#endif diff --git a/engine/client/r_part.c b/engine/client/r_part.c index b5f26a141..249a4d857 100644 --- a/engine/client/r_part.c +++ b/engine/client/r_part.c @@ -181,7 +181,7 @@ void P_Shutdown(void) qboolean Q2TraceLineN (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal) { vec3_t nul = {0,0,0}; - trace_t trace = CM_BoxTrace(pmove.physents[0].model, start, end, nul, nul, MASK_SOLID); + trace_t trace = CM_BoxTrace(pmove.physents[0].model, start, end, nul, nul, MASK_WORLDSOLID); if (trace.fraction < 1) { @@ -223,10 +223,10 @@ qboolean TraceLineN (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal) { AngleVectors(pe->angles, axis[0], axis[1], axis[2]); VectorNegate(axis[1], axis[1]); - pe->model->funcs.Trace(pe->model, 0, 0, axis, ts, te, vec3_origin, vec3_origin, &trace); + pe->model->funcs.NativeTrace(pe->model, 0, 0, axis, ts, te, vec3_origin, vec3_origin, MASK_WORLDSOLID, &trace); } else - pe->model->funcs.Trace(pe->model, 0, 0, NULL, ts, te, vec3_origin, vec3_origin, &trace); + pe->model->funcs.NativeTrace(pe->model, 0, 0, NULL, ts, te, vec3_origin, vec3_origin, MASK_WORLDSOLID, &trace); if (trace.fraction<1) { VectorSubtract(trace.endpos, ts, delta); @@ -250,8 +250,8 @@ qboolean TraceLineN (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal) normal[1] = -delta[1]; normal[2] = -delta[2]; } - VectorCopy (start, impact); - return true; + VectorCopy (end, impact); + return false; } } diff --git a/engine/client/r_partset.c b/engine/client/r_partset.c index 96d71e4c7..f0ea34091 100644 --- a/engine/client/r_partset.c +++ b/engine/client/r_partset.c @@ -1823,6 +1823,26 @@ char *particle_set_minimal = char *particle_set_h2part = +"r_part t_rocket\n" +"{\n" +"texture \"particles/fteparticlefont.tga\"\n" +"tcoords 1 1 63 63 256 2 64\n" +"step 32\n" +"scale 64\n" +"alpha 0.6\n" +"die 1\n" +"randomvel 64\n" +"veladd 10\n" +"rotationspeed 90\n" +"rotationstart 0 360\n" +"rgb 16 32 16\n" +"rgbrand 16 64 16\n" +"gravity 200\n" +"scalefactor 0.8\n" +"scaledelta -10\n" +"stains 2\n" +"}\n" + "r_part ce_white_smoke_05\n" "{\n" "model models/whtsmk1.spr 0 0 20 0.5\n" @@ -1974,7 +1994,7 @@ char *particle_set_h2part = "}\n" "r_part ce_magic_missile_explosion\n" "{\n" -"model models/mm_explod.spr 0 0 20 1\n" +"model models/mm_expld.spr 0 0 20 1\n" "}\n" // ce_ghost "r_part ce_bone_explosion\n" @@ -2051,6 +2071,286 @@ char *particle_set_h2part = "{\n" "model models/biggy.spr 0 0 20 1\n" "}\n" + +"r_part ce_boneshard\n" +"{\n" +"model models/boneshot.mdl 0 1 1 1\n" +"rotationspeed 425\n" +"veladd 2\n" +"}\n" +"r_part ce_boneshrapnel\n" +"{\n" +"model models/boneshrd.mdl 0 1 1 1\n" +"rotationspeed 425\n" +"veladd 2\n" +"}\n" + +"r_part ce_chunk_greystone\n" +"{\n" +"model models/schunk1.mdl 0 1 0.25 1\n" +"model models/schunk2.mdl 0 1 0.25 1\n" +"model models/schunk3.mdl 0 1 0.25 1\n" +"model models/schunk4.mdl 0 1 0.25 1\n" +"randomvel 210 70 280\n" +"spawnorg 0\n" +"gravity 800\n" +"rotationspeed 425\n" +"}\n" +"r_part ce_chunk_wood\n" +"{\n" +"model models/splnter1.mdl 0 1 0.25 1\n" +"model models/splnter2.mdl 0 1 0.25 1\n" +"model models/splnter3.mdl 0 1 0.25 1\n" +"model models/splnter4.mdl 0 1 0.25 1\n" +"randomvel 210 70 280\n" +"spawnorg 0\n" +"gravity 800\n" +"rotationspeed 425\n" +"}\n" +"r_part ce_chunk_metal\n" +"{\n" +"model models/metlchk1.mdl 0 1 0.25 1\n" +"model models/metlchk2.mdl 0 1 0.25 1\n" +"model models/metlchk3.mdl 0 1 0.25 1\n" +"model models/metlchk4.mdl 0 1 0.25 1\n" +"randomvel 210 70 280\n" +"spawnorg 0\n" +"gravity 800\n" +"rotationspeed 425\n" +"}\n" +"r_part ce_chunk_flesh\n" +"{\n" +"model models/flesh1.mdl 0 1 0.25 1\n" +"model models/flesh2.mdl 0 1 0.25 1\n" +"model models/flesh3.mdl 0 1 0.25 1\n" +"randomvel 210 70 280\n" +"spawnorg 0\n" +"gravity 800\n" +"rotationspeed 425\n" +"}\n" +//r_part ce_chunk_fire +//{ +//} +"r_part ce_chunk_clay\n" +"{\n" +"model models/clshard1.mdl 0 1 0.25 1\n" +"model models/clshard2.mdl 0 1 0.25 1\n" +"model models/clshard3.mdl 0 1 0.25 1\n" +"model models/clshard4.mdl 0 1 0.25 1\n" +"randomvel 210 70 280\n" +"spawnorg 0\n" +"gravity 800\n" +"rotationspeed 425\n" +"}\n" +"r_part ce_chunk_leaves\n" +"{\n" +"model models/leafchk1.mdl 0 1 0.25 1\n" +"model models/leafchk2.mdl 0 1 0.25 1\n" +"model models/leafchk3.mdl 0 1 0.25 1\n" +"randomvel 210 70 280\n" +"spawnorg 0\n" +"gravity 800\n" +"rotationspeed 425\n" +"}\n" +"r_part ce_chunk_hay\n" +"{\n" +"model models/hay1.mdl 0 1 0.25 1\n" +"model models/hay2.mdl 0 1 0.25 1\n" +"model models/hay3.mdl 0 1 0.25 1\n" +"randomvel 210 70 280\n" +"spawnorg 0\n" +"gravity 800\n" +"rotationspeed 425\n" +"}\n" +"r_part ce_chunk_brownstone\n" +"{\n" +"model models/schunk1.mdl 1 1 0.25 1\n" +"model models/schunk2.mdl 1 1 0.25 1\n" +"model models/schunk3.mdl 1 1 0.25 1\n" +"model models/schunk4.mdl 1 1 0.25 1\n" +"randomvel 210 70 280\n" +"spawnorg 0\n" +"gravity 800\n" +"rotationspeed 425\n" +"}\n" +"r_part ce_chunk_cloth\n" +"{\n" +"model models/clthchk1.mdl 0 1 0.25 1\n" +"model models/clthchk2.mdl 0 1 0.25 1\n" +"model models/clthchk3.mdl 0 1 0.25 1\n" +"randomvel 210 70 280\n" +"spawnorg 0\n" +"gravity 800\n" +"rotationspeed 425\n" +"}\n" +"r_part ce_chunk_wood_leaf\n" +"{\n" +"model models/splnter1.mdl 0 1 0.25 1\n" +"model models/splnter2.mdl 0 1 0.25 1\n" +"model models/splnter3.mdl 0 1 0.25 1\n" +"model models/splnter4.mdl 0 1 0.25 1\n" +"model models/leafchk1.mdl 0 1 0.25 1\n" +"model models/leafchk2.mdl 0 1 0.25 1\n" +"model models/leafchk3.mdl 0 1 0.25 1\n" +"randomvel 210 70 280\n" +"spawnorg 0\n" +"gravity 800\n" +"rotationspeed 425\n" + +"}\n" +"r_part ce_chunk_wood_metal\n" +"{\n" +"model models/splnter1.mdl 0 1 0.25 1\n" +"model models/splnter2.mdl 0 1 0.25 1\n" +"model models/splnter3.mdl 0 1 0.25 1\n" +"model models/splnter4.mdl 0 1 0.25 1\n" +"model models/metlchk1.mdl 0 1 0.25 1\n" +"model models/metlchk2.mdl 0 1 0.25 1\n" +"model models/metlchk3.mdl 0 1 0.25 1\n" +"model models/metlchk4.mdl 0 1 0.25 1\n" +"randomvel 210 70 280\n" +"spawnorg 0\n" +"gravity 800\n" +"rotationspeed 425\n" +"}\n" +"r_part ce_chunk_wood_stone\n" +"{\n" +"model models/splnter1.mdl 0 1 0.25 1\n" +"model models/splnter2.mdl 0 1 0.25 1\n" +"model models/splnter3.mdl 0 1 0.25 1\n" +"model models/splnter4.mdl 0 1 0.25 1\n" +"model models/schunk1.mdl 0 1 0.25 1\n" +"model models/schunk2.mdl 0 1 0.25 1\n" +"model models/schunk3.mdl 0 1 0.25 1\n" +"model models/schunk4.mdl 0 1 0.25 1\n" +"randomvel 210 70 280\n" +"spawnorg 0\n" +"gravity 800\n" +"rotationspeed 425\n" +"}\n" +"r_part ce_chunk_metal_stone\n" +"{\n" +"model models/metlchk1.mdl 0 1 0.25 1\n" +"model models/metlchk2.mdl 0 1 0.25 1\n" +"model models/metlchk3.mdl 0 1 0.25 1\n" +"model models/metlchk4.mdl 0 1 0.25 1\n" +"model models/schunk1.mdl 0 1 0.25 1\n" +"model models/schunk2.mdl 0 1 0.25 1\n" +"model models/schunk3.mdl 0 1 0.25 1\n" +"model models/schunk4.mdl 0 1 0.25 1\n" +"randomvel 210 70 280\n" +"spawnorg 0\n" +"gravity 800\n" +"rotationspeed 425\n" +"}\n" +"r_part ce_chunk_metal_cloth\n" +"{\n" +"model models/metlchk1.mdl 0 1 0.25 1\n" +"model models/metlchk2.mdl 0 1 0.25 1\n" +"model models/metlchk3.mdl 0 1 0.25 1\n" +"model models/metlchk4.mdl 0 1 0.25 1\n" +"model models/clthchk1.mdl 0 1 0.25 1\n" +"model models/clthchk2.mdl 0 1 0.25 1\n" +"model models/clthchk3.mdl 0 1 0.25 1\n" +"randomvel 210 70 280\n" +"spawnorg 0\n" +"gravity 800\n" +"rotationspeed 425\n" +"}\n" +"r_part ce_chunk_webs\n" +"{\n" +"model models/shard1.mdl 3 1 0.25 0.5\n" +"model models/shard2.mdl 3 1 0.25 0.5\n" +"model models/shard3.mdl 3 1 0.25 0.5\n" +"model models/shard4.mdl 3 1 0.25 0.5\n" +"model models/shard5.mdl 3 1 0.25 0.5\n" +"randomvel 210 70 280\n" +"spawnorg 0\n" +"gravity 500\n" +"rotationspeed 425\n" +"}\n" +"r_part ce_chunk_glass\n" +"{\n" +"model models/shard1.mdl 0 1 0.25 1\n" +"model models/shard2.mdl 0 1 0.25 1\n" +"model models/shard3.mdl 0 1 0.25 1\n" +"model models/shard4.mdl 0 1 0.25 1\n" +"model models/shard5.mdl 0 1 0.25 1\n" +"randomvel 210 70 280\n" +"spawnorg 0\n" +"gravity 800\n" +"rotationspeed 425\n" +"}\n" +"r_part ce_chunk_ice\n" +"{\n" +"model models/shard.mdl 0 1 0.25 0.5\n" +"model models/shard.mdl 1 1 0.25 0.5\n" +"randomvel 210 70 280\n" +"spawnorg 0\n" +"gravity 800\n" +"}\n" +"r_part ce_chunk_clearglass\n" +"{\n" +"model models/shard1.mdl 1 1 0.25 0.5\n" +"model models/shard2.mdl 1 1 0.25 0.5\n" +"model models/shard3.mdl 1 1 0.25 0.5\n" +"model models/shard4.mdl 1 1 0.25 0.5\n" +"model models/shard5.mdl 1 1 0.25 0.5\n" +"randomvel 210 70 280\n" +"spawnorg 0\n" +"gravity 800\n" +"rotationspeed 425\n" +"}\n" +"r_part ce_chunk_redglass\n" +"{\n" +"model models/shard1.mdl 2 1 0.25 1\n" +"model models/shard2.mdl 2 1 0.25 1\n" +"model models/shard3.mdl 2 1 0.25 1\n" +"model models/shard4.mdl 2 1 0.25 1\n" +"model models/shard5.mdl 2 1 0.25 1\n" +"randomvel 210 70 280\n" +"spawnorg 0\n" +"gravity 800\n" +"rotationspeed 425\n" +"}\n" +"r_part ce_chunk_acid\n" +"{\n" +"model models/sucwp2p.mdl 0 1 0.25 1\n" +"randomvel 210 70 280\n" +"spawnorg 0\n" +"gravity 800\n" +"rotationspeed 425\n" +"}\n" +"r_part ce_chunk_meteor\n" +"{\n" +"model models/tempmetr.mdl 0 1 0.25 1\n" +"randomvel 360\n" +"spawnorg 0\n" +"gravity 800\n" +"rotationspeed 425\n" +"}\n" +"r_part ce_chunk_greenflesh\n" +"{\n" +"model models/sflesh1.mdl 0 1 0.25 1\n" +"model models/sflesh2.mdl 0 1 0.25 1\n" +"model models/sflesh3.mdl 0 1 0.25 1\n" +"randomvel 210 70 280\n" +"spawnorg 0\n" +"gravity 800\n" +"rotationspeed 425\n" +"}\n" +"r_part ce_chunk_bone\n" +"{\n" +"model models/clshard1.mdl 1 1 0.25 1\n" +"model models/clshard2.mdl 1 1 0.25 1\n" +"model models/clshard3.mdl 1 1 0.25 1\n" +"model models/clshard4.mdl 1 1 0.25 1\n" +"randomvel 210 70 280\n" +"spawnorg 0\n" +"gravity 800\n" +"rotationspeed 425\n" +"}\n" + ; diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index e78c607d3..3c27f0df2 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -1165,17 +1165,10 @@ void Surf_RenderDynamicLightmaps (msurface_t *fa) glRect_t *theRect; int smax, tmax; - if (!fa->mesh) - return; - //surfaces without lightmaps if (fa->lightmaptexturenum<0) return; - //surfaces with lightmaps that do not animate, supposedly - if (fa->texinfo->flags & (TI_SKY|TI_TRANS33|TI_TRANS66|TI_WARP)) - return; - // check for lightmap modification if (!fa->samples) { @@ -1271,10 +1264,6 @@ void Surf_RenderAmbientLightmaps (msurface_t *fa, int ambient) if (fa->lightmaptexturenum<0) return; - //surfaces with lightmaps that do not animate, supposedly - if (fa->texinfo->flags & (TI_SKY|TI_TRANS33|TI_TRANS66|TI_WARP)) - return; - if (fa->cached_light[0] != ambient || fa->cached_colour[0] != 0xff) goto dynamic; @@ -2031,7 +2020,7 @@ void Surf_DrawWorld (void) currententity = &r_worldentity; #ifdef MAP_DOOM - if (currentmodel->fromgame = fg_doom) + if (currentmodel->fromgame == fg_doom) GLR_DoomWorld(); else #endif @@ -2431,6 +2420,11 @@ static void Surf_CreateSurfaceLightmap (msurface_t *surf, int shift) surf->lightmaptexturenum = -1; if (surf->texinfo->flags & TEX_SPECIAL) surf->lightmaptexturenum = -1; + + //surfaces with lightmaps that do not animate, supposedly + if (surf->texinfo->flags & (TI_SKY|TI_TRANS33|TI_TRANS66|TI_WARP)) + surf->lightmaptexturenum = -1; + if (surf->lightmaptexturenum<0) { surf->lightmaptexturenum = -1; diff --git a/engine/client/renderer.c b/engine/client/renderer.c index ffe3da2a9..4998c74d8 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -312,12 +312,13 @@ cvar_t r_shadow_bumpscale_bumpmap = SCVAR ("r_shadow_bumpscale_bumpmap", "10" cvar_t r_glsl_offsetmapping = CVARF ("r_glsl_offsetmapping", "0", CVAR_ARCHIVE); cvar_t r_glsl_offsetmapping_scale = CVAR ("r_glsl_offsetmapping_scale", "0.04"); +cvar_t r_glsl_offsetmapping_reliefmapping = CVARF("r_glsl_offsetmapping_reliefmapping", "1", CVAR_RENDERERLATCH); cvar_t r_shadow_realtime_world = SCVARF ("r_shadow_realtime_world", "0", CVAR_ARCHIVE); cvar_t r_shadow_realtime_world_shadows = SCVARF ("r_shadow_realtime_world_shadows", "1", CVAR_ARCHIVE); cvar_t r_shadow_realtime_dlight = SCVARF ("r_shadow_realtime_dlight", "1", CVAR_ARCHIVE); cvar_t r_shadow_realtime_dlight_shadows = SCVARF ("r_shadow_realtime_dlight_shadows", "1", CVAR_ARCHIVE); -cvar_t r_shadow_realtime_world_lightmaps = SCVARF ("r_shadow_realtime_world_lightmaps", "0.8", 0); +cvar_t r_shadow_realtime_world_lightmaps = SCVARF ("r_shadow_realtime_world_lightmaps", "0", 0); cvar_t r_vertexdlights = SCVAR ("r_vertexdlights", "0"); @@ -386,6 +387,7 @@ void GLRenderer_Init(void) Cvar_Register (&r_deluxemapping, GRAPHICALNICETIES); Cvar_Register (&r_glsl_offsetmapping, GRAPHICALNICETIES); Cvar_Register (&r_glsl_offsetmapping_scale, GRAPHICALNICETIES); + Cvar_Register (&r_glsl_offsetmapping_reliefmapping, GRAPHICALNICETIES); Cvar_Register (&gl_contrast, GLRENDEREROPTIONS); #ifdef R_XFLIP @@ -965,6 +967,8 @@ qboolean R_ApplyRenderer_Load (rendererstate_t *newr) if (host_basepal) BZ_Free(host_basepal); host_basepal = (qbyte *)FS_LoadMallocFile ("gfx/palette.lmp"); + if (!host_basepal) + host_basepal = (qbyte *)FS_LoadMallocFile ("wad/playpal"); if (!host_basepal) { qbyte *pcx=NULL; diff --git a/engine/client/sbar.c b/engine/client/sbar.c index 41d07b640..639006306 100644 --- a/engine/client/sbar.c +++ b/engine/client/sbar.c @@ -2494,17 +2494,15 @@ void Sbar_Draw (void) Sbar_Voice(16); } -#ifdef GLQUAKE if (cl_sbar.value == 1 || scr_viewsize.value<100) { if (cl.splitclients==1 && sbar_rect.x>0) { // left - R2D_TileClear (0, sbar_rect.height - sb_lines, sbar_rect.x, sb_lines); + R2D_TileClear (0, sbar_rect.height - sb_lines, sbar_rect.x, sb_lines); } if (sbar_rect.x + 320 <= sbar_rect.width && !headsup) R2D_TileClear (sbar_rect.x + 320, sbar_rect.height - sb_lines, sbar_rect.width - (320), sb_lines); } -#endif if (sb_lines > 0) @@ -3288,8 +3286,5 @@ void Sbar_FinaleOverlay (void) if (UI_DrawFinale()>0) return; #endif - pic = R2D_SafeCachePic ("gfx/finale.lmp"); - if (pic) - R2D_ScalePic ( (vid.width-pic->width)/2, 16, pic->width, pic->height, pic); } diff --git a/engine/client/snd_mem.c b/engine/client/snd_mem.c index b2a50f110..08143abfa 100644 --- a/engine/client/snd_mem.c +++ b/engine/client/snd_mem.c @@ -676,7 +676,7 @@ sfxcache_t *S_LoadDoomSound (sfx_t *s, qbyte *data, int datalen, int sndspeed) { // format data from Unofficial Doom Specs v1.6 unsigned short *dataus; - int samples, rate, len; + int samples, rate; if (datalen < 8) return NULL; @@ -695,7 +695,7 @@ sfxcache_t *S_LoadDoomSound (sfx_t *s, qbyte *data, int datalen, int sndspeed) if (datalen != samples) return NULL; - COM_CharBias(data, sc->length); + COM_CharBias(data, datalen); ResampleSfx (s, rate, 1, 1, samples, -1, data); diff --git a/engine/client/sys_droid.c b/engine/client/sys_droid.c index ae1c005b5..447cf31b5 100644 --- a/engine/client/sys_droid.c +++ b/engine/client/sys_droid.c @@ -1,447 +1,448 @@ -#include -#include - -#include - -#include "quakedef.h" -#include -#include -#include -#include -#include - -#ifndef isDedicated -#ifdef SERVERONLY -qboolean isDedicated = true; -#else -qboolean isDedicated = false; -#endif -#endif -void *sys_window; /*public so the renderer can attach to the correct place*/ -static qboolean sys_running = false; - - -#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, DISTRIBUTION"Droid", __VA_ARGS__)) -#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, DISTRIBUTION"Droid", __VA_ARGS__)) - -static void *sys_memheap; -static unsigned int sys_lastframe; -JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_frame(JNIEnv *env, jobject obj) -{ - #ifdef SERVERONLY - SV_Frame(); - #else - unsigned int now = Sys_Milliseconds(); - double tdelta = (now - sys_lastframe) * 0.001; - Host_Frame(tdelta); - sys_lastframe = now; - #endif -} - -JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_init(JNIEnv *env, jobject obj, - jint width, jint height) -{ - vid.pixelwidth = width; - vid.pixelheight = height; - if (!sys_running) - { - quakeparms_t parms; - parms.basedir = "/sdcard/fte"; - parms.argc = 0; - parms.argv = NULL; - parms.memsize = sys_memheap = 8*1024*1024; - parms.membase = malloc(parms.memsize); - if (!parms.membase) - { - Sys_Printf("Unable to alloc heap\n"); - return; - } - - Sys_Printf("Starting up\n"); - - COM_InitArgv(parms.argc, parms.argv); - TL_InitLanguages(); - #ifdef SERVERONLY - SV_Init(&parms); - #else - Host_Init(&parms); - #endif - sys_running = true; - sys_lastframe = Sys_Milliseconds(); - } -} -JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_keypress(JNIEnv *env, jobject obj, - jint down, jint keycode, jint unicode) -{ - Key_Event(0, keycode, unicode, down); -} - -int mousecursor_x, mousecursor_y; -float mouse_x, mouse_y; -static float omouse_x, omouse_y; -JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_motion(JNIEnv *env, jobject obj, - jint act, jfloat x, jfloat y) -{ - static float totalmoved; - static qboolean down; - float dx, dy; - - dx = x - omouse_x; - dy = y - omouse_y; - omouse_x = x; - omouse_y = y; - mousecursor_x = x; - mousecursor_y = y; - - if (down) - { - mouse_x += dx; - mouse_y += dy; - totalmoved += fabs(dx) + fabs(dy); - } - - switch(act) - { - case 0: /*move*/ - break; - case 1: /*down*/ - totalmoved = 0; - down = true; - break; - case 2: /*up*/ - down = false; - /*if it didn't move far, treat it as a regular click, if it did move a little then sorry if you just wanted a small turn!*/ - if (totalmoved < 3) - { - Key_Event(0, K_MOUSE1, 0, 1); - Key_Event(0, K_MOUSE1, 0, 0); - } - break; - } -} -JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_accelerometer(JNIEnv *env, jobject obj, - jfloat x, jfloat y, jfloat z) -{ -// Con_Printf("Accelerometer: %f %f %f\n", x, y, z); -} - -static int secbase; -double Sys_DoubleTime(void) -{ - struct timeval tp; - struct timezone tzp; - - gettimeofday(&tp, &tzp); - - if (!secbase) - { - secbase = tp.tv_sec; - return tp.tv_usec/1000000.0; - } - - return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0; -} -unsigned int Sys_Milliseconds(void) -{ - struct timeval tp; - struct timezone tzp; - - gettimeofday(&tp, &tzp); - - if (!secbase) - { - secbase = tp.tv_sec; - return tp.tv_usec/1000; - } - - return (tp.tv_sec - secbase)*1000 + tp.tv_usec/1000; -} - -void Sys_Shutdown(void) -{ - free(sys_memheap); -} -void Sys_Quit(void) -{ -#ifndef SERVERONLY - Host_Shutdown (); -#else - SV_Shutdown(); -#endif - - exit (0); -} -void Sys_Error (const char *error, ...) -{ - va_list argptr; - char string[1024]; - - va_start (argptr, error); - vsnprintf (string,sizeof(string)-1, error,argptr); - va_end (argptr); - - LOGW("%s", string); - - exit(1); -} -void Sys_Printf (char *fmt, ...) -{ - va_list argptr; - char string[1024]; - - va_start (argptr, fmt); - vsnprintf (string,sizeof(string)-1, fmt,argptr); - va_end (argptr); - - LOGI("%s", string); -} -void Sys_Warn (char *fmt, ...) -{ - va_list argptr; - char string[1024]; - - va_start (argptr, fmt); - vsnprintf (string,sizeof(string)-1, fmt,argptr); - va_end (argptr); - - LOGW("%s", string); -} - -void Sys_CloseLibrary(dllhandle_t *lib) -{ - dlclose(lib); -} -dllhandle_t *Sys_LoadLibrary(const char *name, dllfunction_t *funcs) -{ - dllhandle_t *h; - h = dlopen(name, RTLD_LAZY); - return h; -} -void *Sys_GetAddressForName(dllhandle_t *module, const char *exportname) -{ - return dlsym(module, exportname); -} -void *Sys_GetGameAPI (void *parms) -{ - return NULL; -} -void Sys_UnloadGame(void) -{ -} -char *Sys_ConsoleInput (void) -{ - return NULL; -} -void Sys_mkdir (char *path) //not all pre-unix systems have directories (including dos 1) -{ -} -qboolean Sys_remove (char *path) -{ - return false; -} -void Sys_Init(void) -{ -} - -qboolean Sys_GetDesktopParameters(int *width, int *height, int *bpp, int *refreshrate) -{ - *width = 320; - *height = 240; - *bpp = 16; - *refreshrate = 60; - return false; -} -qboolean Sys_RandomBytes(qbyte *string, int len) -{ - qboolean res = false; - int fd = open("/dev/urandom", 0); - if (fd >= 0) - { - res = (read(fd, string, len) == len); - close(fd); - } - - return res; -} - -void Sys_ServerActivity(void) -{ - /*FIXME: flash window*/ -} - -qboolean Sys_InitTerminal(void) -{ - /*switching to dedicated mode, show text window*/ - return false; -} -void Sys_CloseTerminal(void) -{ -} - -char *Sys_GetClipboard(void) -{ - return NULL; -} -void Sys_CloseClipboard(char *buf) -{ -} -void Sys_SaveClipboard(char *text) -{ -} - -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *), void *parm) -{ - DIR *dir; - char apath[MAX_OSPATH]; - char file[MAX_OSPATH]; - char truepath[MAX_OSPATH]; - char *s; - struct dirent *ent; - struct stat st; - -//printf("path = %s\n", gpath); -//printf("match = %s\n", match); - - if (!gpath) - gpath = ""; - *apath = '\0'; - - Q_strncpyz(apath, match, sizeof(apath)); - for (s = apath+strlen(apath)-1; s >= apath; s--) - { - if (*s == '/') - { - s[1] = '\0'; - match += s - apath+1; - break; - } - } - if (s < apath) //didn't find a '/' - *apath = '\0'; - - Q_snprintfz(truepath, sizeof(truepath), "%s/%s", gpath, apath); - - -//printf("truepath = %s\n", truepath); -//printf("gamepath = %s\n", gpath); -//printf("apppath = %s\n", apath); -//printf("match = %s\n", match); - dir = opendir(truepath); - if (!dir) - { - Con_DPrintf("Failed to open dir %s\n", truepath); - return true; - } - do - { - ent = readdir(dir); - if (!ent) - break; - if (*ent->d_name != '.') - { - if (wildcmp(match, ent->d_name)) - { - Q_snprintfz(file, sizeof(file), "%s/%s", truepath, ent->d_name); - - if (stat(file, &st) == 0) - { - Q_snprintfz(file, sizeof(file), "%s%s%s", apath, ent->d_name, S_ISDIR(st.st_mode)?"/":""); - - if (!func(file, st.st_size, parm)) - { - closedir(dir); - return false; - } - } - else - printf("Stat failed for \"%s\"\n", file); - } - } - } while(1); - closedir(dir); - - return true; -} - -/* -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *), void *parm) -{ - qboolean go = true; - const char *f; - - struct AAssetDir *ad; - ad = AAssetManager_openDir(assetmgr, gpath); - - while(go && (f = AAssetDir_getNextFileName(ad))) - { - if (wildcmp(match, f)) - { -Sys_Printf("Found %s\n", f); - go = func(f, 0, parm); - } - } - - AAssetDir_close(ad); - return 0; -} -typedef struct -{ - vfsfile_t funcs; - AAsset *handle; -} assetfile_t; -static int AF_ReadBytes(vfsfile_t *h, void *buf, int len) -{ - assetfile_t *f = (assetfile_t*)h; - return AAsset_read(f->handle, buf, len); -} -static qboolean AF_Seek(vfsfile_t *h, unsigned long offs) -{ - assetfile_t *f = (assetfile_t*)h; - AAsset_seek(f->handle, offs, SEEK_SET); - return true; -} -static unsigned long AF_Tell(vfsfile_t *h) -{ - assetfile_t *f = (assetfile_t*)h; - return AAsset_seek(f->handle, 0, SEEK_CUR); -} -static unsigned long AF_GetSize(vfsfile_t *h) -{ - assetfile_t *f = (assetfile_t*)h; - return AAsset_getLength(f->handle); -} - -static void AF_Close(vfsfile_t *h) -{ - assetfile_t *f = (assetfile_t*)h; - AAsset_close(f->handle); - Z_Free(f); -} -static void AF_Flush(vfsfile_t *h) -{ -} -vfsfile_t *Sys_OpenAsset(char *fname) -{ - assetfile_t *file; - AAsset *a; - a = AAssetManager_open(assetmgr, fname, AASSET_MODE_UNKNOWN); - if (!a) - { - Sys_Printf("Unable to open asset %s\n", fname); - return NULL; - } - Sys_Printf("opened asset %s\n", fname); - - file = Z_Malloc(sizeof(assetfile_t)); - file->funcs.ReadBytes = AF_ReadBytes; - file->funcs.WriteBytes = NULL; - file->funcs.Seek = AF_Seek; - file->funcs.Tell = AF_Tell; - file->funcs.GetLen = AF_GetSize; - file->funcs.Close = AF_Close; - file->funcs.Flush = AF_Flush; - file->handle = a; - - return (vfsfile_t*)file; -} -*/ +#include +#include + +#include + +#include "quakedef.h" +#include +#include +#include +#include +#include + +#ifndef isDedicated +#ifdef SERVERONLY +qboolean isDedicated = true; +#else +qboolean isDedicated = false; +#endif +#endif +void *sys_window; /*public so the renderer can attach to the correct place*/ +static qboolean sys_running = false; + + +#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, DISTRIBUTION"Droid", __VA_ARGS__)) +#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, DISTRIBUTION"Droid", __VA_ARGS__)) + +static void *sys_memheap; +static unsigned int sys_lastframe; +JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_frame(JNIEnv *env, jobject obj) +{ + #ifdef SERVERONLY + SV_Frame(); + #else + unsigned int now = Sys_Milliseconds(); + double tdelta = (now - sys_lastframe) * 0.001; + Host_Frame(tdelta); + sys_lastframe = now; + #endif +} + +JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_init(JNIEnv *env, jobject obj, + jint width, jint height) +{ + vid.pixelwidth = width; + vid.pixelheight = height; + if (!sys_running) + { + quakeparms_t parms; + parms.basedir = "/sdcard/fte"; + parms.argc = 0; + parms.argv = NULL; + parms.memsize = sys_memheap = 8*1024*1024; + parms.membase = malloc(parms.memsize); + if (!parms.membase) + { + Sys_Printf("Unable to alloc heap\n"); + return; + } + + Sys_Printf("Starting up\n"); + + COM_InitArgv(parms.argc, parms.argv); + TL_InitLanguages(); + #ifdef SERVERONLY + SV_Init(&parms); + #else + Host_Init(&parms); + #endif + sys_running = true; + sys_lastframe = Sys_Milliseconds(); + } +} +JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_keypress(JNIEnv *env, jobject obj, + jint down, jint keycode, jint unicode) +{ + Key_Event(0, keycode, unicode, down); +} + +int mousecursor_x, mousecursor_y; +float mouse_x, mouse_y; +static float omouse_x, omouse_y; +JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_motion(JNIEnv *env, jobject obj, + jint act, jfloat x, jfloat y) +{ + static float totalmoved; + static qboolean down; + float dx, dy; + + dx = x - omouse_x; + dy = y - omouse_y; + omouse_x = x; + omouse_y = y; + mousecursor_x = x; + mousecursor_y = y; + + if (down) + { + mouse_x += dx; + mouse_y += dy; + totalmoved += fabs(dx) + fabs(dy); + } + + switch(act) + { + case 0: /*move*/ + break; + case 1: /*down*/ + totalmoved = 0; + down = true; + break; + case 2: /*up*/ + down = false; + /*if it didn't move far, treat it as a regular click, if it did move a little then sorry if you just wanted a small turn!*/ + if (totalmoved < 3) + { + Key_Event(0, K_MOUSE1, 0, 1); + Key_Event(0, K_MOUSE1, 0, 0); + } + break; + } +} +JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_accelerometer(JNIEnv *env, jobject obj, + jfloat x, jfloat y, jfloat z) +{ +// Con_Printf("Accelerometer: %f %f %f\n", x, y, z); +} + +static int secbase; +double Sys_DoubleTime(void) +{ + struct timeval tp; + struct timezone tzp; + + gettimeofday(&tp, &tzp); + + if (!secbase) + { + secbase = tp.tv_sec; + return tp.tv_usec/1000000.0; + } + + return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0; +} +unsigned int Sys_Milliseconds(void) +{ + struct timeval tp; + struct timezone tzp; + + gettimeofday(&tp, &tzp); + + if (!secbase) + { + secbase = tp.tv_sec; + return tp.tv_usec/1000; + } + + return (tp.tv_sec - secbase)*1000 + tp.tv_usec/1000; +} + +void Sys_Shutdown(void) +{ + free(sys_memheap); +} +void Sys_Quit(void) +{ +#ifndef SERVERONLY + Host_Shutdown (); +#else + SV_Shutdown(); +#endif + + exit (0); +} +void Sys_Error (const char *error, ...) +{ + va_list argptr; + char string[1024]; + + va_start (argptr, error); + vsnprintf (string,sizeof(string)-1, error,argptr); + va_end (argptr); + + LOGW("%s", string); + + exit(1); +} +void Sys_Printf (char *fmt, ...) +{ + va_list argptr; + char string[1024]; + + va_start (argptr, fmt); + vsnprintf (string,sizeof(string)-1, fmt,argptr); + va_end (argptr); + + LOGI("%s", string); +} +void Sys_Warn (char *fmt, ...) +{ + va_list argptr; + char string[1024]; + + va_start (argptr, fmt); + vsnprintf (string,sizeof(string)-1, fmt,argptr); + va_end (argptr); + + LOGW("%s", string); +} + +void Sys_CloseLibrary(dllhandle_t *lib) +{ + dlclose(lib); +} +dllhandle_t *Sys_LoadLibrary(const char *name, dllfunction_t *funcs) +{ + dllhandle_t *h; + h = dlopen(name, RTLD_LAZY); + return h; +} +void *Sys_GetAddressForName(dllhandle_t *module, const char *exportname) +{ + return dlsym(module, exportname); +} +void *Sys_GetGameAPI (void *parms) +{ + return NULL; +} +void Sys_UnloadGame(void) +{ +} +char *Sys_ConsoleInput (void) +{ + return NULL; +} +void Sys_mkdir (char *path) //not all pre-unix systems have directories (including dos 1) +{ + mkdir(path, 0777); +} +qboolean Sys_remove (char *path) +{ + return !unlink(path); +} +void Sys_Init(void) +{ +} + +qboolean Sys_GetDesktopParameters(int *width, int *height, int *bpp, int *refreshrate) +{ + *width = 320; + *height = 240; + *bpp = 16; + *refreshrate = 60; + return false; +} +qboolean Sys_RandomBytes(qbyte *string, int len) +{ + qboolean res = false; + int fd = open("/dev/urandom", 0); + if (fd >= 0) + { + res = (read(fd, string, len) == len); + close(fd); + } + + return res; +} + +void Sys_ServerActivity(void) +{ + /*FIXME: flash window*/ +} + +qboolean Sys_InitTerminal(void) +{ + /*switching to dedicated mode, show text window*/ + return false; +} +void Sys_CloseTerminal(void) +{ +} + +char *Sys_GetClipboard(void) +{ + return NULL; +} +void Sys_CloseClipboard(char *buf) +{ +} +void Sys_SaveClipboard(char *text) +{ +} + +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *), void *parm) +{ + DIR *dir; + char apath[MAX_OSPATH]; + char file[MAX_OSPATH]; + char truepath[MAX_OSPATH]; + char *s; + struct dirent *ent; + struct stat st; + +//printf("path = %s\n", gpath); +//printf("match = %s\n", match); + + if (!gpath) + gpath = ""; + *apath = '\0'; + + Q_strncpyz(apath, match, sizeof(apath)); + for (s = apath+strlen(apath)-1; s >= apath; s--) + { + if (*s == '/') + { + s[1] = '\0'; + match += s - apath+1; + break; + } + } + if (s < apath) //didn't find a '/' + *apath = '\0'; + + Q_snprintfz(truepath, sizeof(truepath), "%s/%s", gpath, apath); + + +//printf("truepath = %s\n", truepath); +//printf("gamepath = %s\n", gpath); +//printf("apppath = %s\n", apath); +//printf("match = %s\n", match); + dir = opendir(truepath); + if (!dir) + { + Con_DPrintf("Failed to open dir %s\n", truepath); + return true; + } + do + { + ent = readdir(dir); + if (!ent) + break; + if (*ent->d_name != '.') + { + if (wildcmp(match, ent->d_name)) + { + Q_snprintfz(file, sizeof(file), "%s/%s", truepath, ent->d_name); + + if (stat(file, &st) == 0) + { + Q_snprintfz(file, sizeof(file), "%s%s%s", apath, ent->d_name, S_ISDIR(st.st_mode)?"/":""); + + if (!func(file, st.st_size, parm)) + { + closedir(dir); + return false; + } + } + else + printf("Stat failed for \"%s\"\n", file); + } + } + } while(1); + closedir(dir); + + return true; +} + +/* +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *), void *parm) +{ + qboolean go = true; + const char *f; + + struct AAssetDir *ad; + ad = AAssetManager_openDir(assetmgr, gpath); + + while(go && (f = AAssetDir_getNextFileName(ad))) + { + if (wildcmp(match, f)) + { +Sys_Printf("Found %s\n", f); + go = func(f, 0, parm); + } + } + + AAssetDir_close(ad); + return 0; +} +typedef struct +{ + vfsfile_t funcs; + AAsset *handle; +} assetfile_t; +static int AF_ReadBytes(vfsfile_t *h, void *buf, int len) +{ + assetfile_t *f = (assetfile_t*)h; + return AAsset_read(f->handle, buf, len); +} +static qboolean AF_Seek(vfsfile_t *h, unsigned long offs) +{ + assetfile_t *f = (assetfile_t*)h; + AAsset_seek(f->handle, offs, SEEK_SET); + return true; +} +static unsigned long AF_Tell(vfsfile_t *h) +{ + assetfile_t *f = (assetfile_t*)h; + return AAsset_seek(f->handle, 0, SEEK_CUR); +} +static unsigned long AF_GetSize(vfsfile_t *h) +{ + assetfile_t *f = (assetfile_t*)h; + return AAsset_getLength(f->handle); +} + +static void AF_Close(vfsfile_t *h) +{ + assetfile_t *f = (assetfile_t*)h; + AAsset_close(f->handle); + Z_Free(f); +} +static void AF_Flush(vfsfile_t *h) +{ +} +vfsfile_t *Sys_OpenAsset(char *fname) +{ + assetfile_t *file; + AAsset *a; + a = AAssetManager_open(assetmgr, fname, AASSET_MODE_UNKNOWN); + if (!a) + { + Sys_Printf("Unable to open asset %s\n", fname); + return NULL; + } + Sys_Printf("opened asset %s\n", fname); + + file = Z_Malloc(sizeof(assetfile_t)); + file->funcs.ReadBytes = AF_ReadBytes; + file->funcs.WriteBytes = NULL; + file->funcs.Seek = AF_Seek; + file->funcs.Tell = AF_Tell; + file->funcs.GetLen = AF_GetSize; + file->funcs.Close = AF_Close; + file->funcs.Flush = AF_Flush; + file->handle = a; + + return (vfsfile_t*)file; +} +*/ diff --git a/engine/client/view.c b/engine/client/view.c index 7a050a06c..b63d668d2 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -527,6 +527,20 @@ void V_BonusFlash_f (void) cl.cshifts[CSHIFT_BONUS].percent = 50*v_bonusflash.value; } } +void V_DarkFlash_f (void) +{ + cl.cshifts[CSHIFT_BONUS].destcolor[0] = 0; + cl.cshifts[CSHIFT_BONUS].destcolor[1] = 0; + cl.cshifts[CSHIFT_BONUS].destcolor[2] = 0; + cl.cshifts[CSHIFT_BONUS].percent = 255; +} +void V_WhiteFlash_f (void) +{ + cl.cshifts[CSHIFT_BONUS].destcolor[0] = 255; + cl.cshifts[CSHIFT_BONUS].destcolor[1] = 255; + cl.cshifts[CSHIFT_BONUS].destcolor[2] = 255; + cl.cshifts[CSHIFT_BONUS].percent = 255; +} /* ============= @@ -693,7 +707,7 @@ void V_UpdatePalette (qboolean force) float newhw_blend[4]; int ir, ig, ib; float ftime; - static float oldtime; + static double oldtime; RSpeedMark(); ftime = cl.time - oldtime; @@ -1269,8 +1283,8 @@ void R_DrawNameTags(void) #ifdef GLQUAKE if (qrenderer == QR_OPENGL) { - void GL_Set2D (void); - GL_Set2D(); +// void GL_Set2D (void); +// GL_Set2D(false); } #endif @@ -1468,18 +1482,8 @@ void V_RenderView (void) CL_TransitionEntities(); - //work out which packet entities are solid - CL_SetSolidEntities (); - - // Set up prediction for other players - CL_SetUpPlayerPrediction(false); - - // do client side motion prediction CL_PredictMove (); - // Set up prediction for other players - CL_SetUpPlayerPrediction(true); - // build a refresh entity list CL_EmitEntities (); @@ -1514,6 +1518,8 @@ void V_Init (void) #endif Cmd_AddCommand ("v_cshift", V_cshift_f); Cmd_AddCommand ("bf", V_BonusFlash_f); + Cmd_AddCommand ("df", V_DarkFlash_f); + Cmd_AddCommand ("wf", V_WhiteFlash_f); // Cmd_AddCommand ("centerview", V_StartPitchDrift); Cvar_Register (&v_centermove, VIEWVARS); diff --git a/engine/common/bspfile.h b/engine/common/bspfile.h index c7b1e57db..300faa8fc 100644 --- a/engine/common/bspfile.h +++ b/engine/common/bspfile.h @@ -152,16 +152,6 @@ typedef struct #define Q1CONTENTS_LAVA -5 #define Q1CONTENTS_SKY -6 -#define FTECONTENTS_EMPTY 0 -#define FTECONTENTS_SOLID 1 -#define FTECONTENTS_WATER 2 -#define FTECONTENTS_SLIME 4 -#define FTECONTENTS_LAVA 8 -#define FTECONTENTS_SKY 16 -#define FTECONTENTS_LADDER 32 -#define FTECONTENTS_FLUID (FTECONTENTS_WATER|FTECONTENTS_SLIME|FTECONTENTS_LAVA|FTECONTENTS_SKY) //sky is a fluid for q1 code. -#define FTECONTENTS_PLAYERCLIP 64 - // !!! if this is changed, it must be changed in asm_i386.h too !!! typedef struct { @@ -507,15 +497,27 @@ typedef struct // these definitions also need to be in q_shared.h! +#define FTECONTENTS_EMPTY 0 +#define FTECONTENTS_SOLID 1 + //2 + //4 +#define FTECONTENTS_LAVA 8 +#define FTECONTENTS_SLIME 16 +#define FTECONTENTS_WATER 32 +//#define FTECONTENTS_LADDER 32 +#define FTECONTENTS_FLUID (FTECONTENTS_WATER|FTECONTENTS_SLIME|FTECONTENTS_LAVA|FTECONTENTS_SKY) //sky is a fluid for q1 code. +#define FTECONTENTS_PLAYERCLIP 0x00010000 +#define FTECONTENTS_BODY 0x02000000 +#define FTECONTENTS_SKY 0x80000000 + // lower bits are stronger, and will eat weaker brushes completely -#define Q2CONTENTS_SOLID 1 // an eye is never valid in a solid +#define Q2CONTENTS_SOLID FTECONTENTS_SOLID //1 #define Q2CONTENTS_WINDOW 2 // translucent, but not watery #define Q2CONTENTS_AUX 4 -#define Q2CONTENTS_LAVA 8 -#define Q2CONTENTS_SLIME 16 -#define Q2CONTENTS_WATER 32 +#define Q2CONTENTS_LAVA FTECONTENTS_LAVA //8 +#define Q2CONTENTS_SLIME FTECONTENTS_SLIME //16 +#define Q2CONTENTS_WATER FTECONTENTS_WATER //32 #define Q2CONTENTS_MIST 64 -#define Q2LAST_VISIBLE_CONTENTS 64 // remaining contents are non-visible, and don't eat brushes @@ -534,15 +536,45 @@ typedef struct #define Q2CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity -#define Q2CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game +#define Q2CONTENTS_MONSTER FTECONTENTS_BODY //0x2000000 // should never be on a brush, only in game #define Q2CONTENTS_DEADMONSTER 0x4000000 #define Q2CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs #define Q2CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans #define Q2CONTENTS_LADDER 0x20000000 -#define Q3CONTENTS_SOLID Q2CONTENTS_SOLID // should never be on a brush, only in game -#define Q3CONTENTS_BODY 0x2000000 // should never be on a brush, only in game -#define Q3CONTENTS_TRANSLUCENT 0x20000000 + +#define Q3CONTENTS_SOLID FTECONTENTS_SOLID //1 // should never be on a brush, only in game + //2 + //4 +#define Q3CONTENTS_LAVA FTECONTENTS_LAVA //8 +#define Q3CONTENTS_SLIME FTECONTENTS_SLIME //16 +#define Q3CONTENTS_WATER FTECONTENTS_WATER //32 + //64 +#define Q3CONTENTS_NOTTEAM1 0x00000080 +#define Q3CONTENTS_NOTTEAM2 0x00000100 +#define Q3CONTENTS_NOBOTCLIP 0x00000200 + //0x00000400 + //0x00000800 + //0x00001000 + //0x00002000 + //0x00004000 +#define Q3CONTENTS_AREAPORTAL 0x00008000 +#define Q3CONTENTS_PLAYERCLIP Q2CONTENTS_PLAYERCLIP //0x00010000 +#define Q3CONTENTS_MONSTERCLIP Q2CONTENTS_MONSTERCLIP //0x00020000 +#define Q3CONTENTS_TELEPORTER 0x00040000 +#define Q3CONTENTS_JUMPPAD 0x00080000 +#define Q3CONTENTS_CLUSTERPORTAL 0x00100000 +#define Q3CONTENTS_DONOTENTER 0x00200000 +#define Q3CONTENTS_BOTCLIP 0x00400000 +#define Q3CONTENTS_MOVER 0x00800000 +#define Q3CONTENTS_ORIGIN Q2CONTENTS_ORIGIN //0x01000000 +#define Q3CONTENTS_BODY 0x02000000 +#define Q3CONTENTS_CORPSE Q2CONTENTS_DEADMONSTER //0x04000000 +#define Q3CONTENTS_DETAIL Q2CONTENTS_DETAIL //0x08000000 +#define Q3CONTENTS_STRUCTURAL 0x10000000 +#define Q3CONTENTS_TRANSLUCENT 0x20000000 +#define Q3CONTENTS_TRIGGER 0x40000000 +#define Q3CONTENTS_NODROP FTECONTENTS_SKY //0x80000000 //Texinfo flags - warning: these mix with q3 surface flags @@ -562,16 +594,18 @@ typedef struct //Surface flags #define Q3SURF_LADDER 0x8 //wee -// content masks -#define MASK_ALL (-1) -#define MASK_SOLID (Q2CONTENTS_SOLID|Q2CONTENTS_WINDOW) -#define MASK_PLAYERSOLID (Q2CONTENTS_SOLID|Q2CONTENTS_PLAYERCLIP|Q2CONTENTS_WINDOW|Q2CONTENTS_MONSTER) -#define MASK_DEADSOLID (Q2CONTENTS_SOLID|Q2CONTENTS_PLAYERCLIP|Q2CONTENTS_WINDOW) -#define MASK_MONSTERSOLID (Q2CONTENTS_SOLID|Q2CONTENTS_MONSTERCLIP|Q2CONTENTS_WINDOW|Q2CONTENTS_MONSTER) -#define MASK_WATER (Q2CONTENTS_WATER|Q2CONTENTS_LAVA|Q2CONTENTS_SLIME) -#define MASK_OPAQUE (Q2CONTENTS_SOLID|Q2CONTENTS_SLIME|Q2CONTENTS_LAVA) -#define MASK_SHOT (Q2CONTENTS_SOLID|Q2CONTENTS_MONSTER|Q2CONTENTS_WINDOW|Q2CONTENTS_DEADMONSTER) -#define MASK_CURRENT (Q2CONTENTS_CURRENT_0|Q2CONTENTS_CURRENT_90|Q2CONTENTS_CURRENT_180|Q2CONTENTS_CURRENT_270|Q2CONTENTS_CURRENT_UP|Q2CONTENTS_CURRENT_DOWN) +// content masks. Allow q2contents_window in here +//#define MASK_ALL (-1) +#define MASK_WORLDSOLID (FTECONTENTS_SOLID|Q2CONTENTS_WINDOW) /*default trace type for something simple that ignores non-bsp stuff*/ +#define MASK_POINTSOLID (FTECONTENTS_SOLID|Q2CONTENTS_WINDOW|FTECONTENTS_BODY) /*default trace type for an entity of no size*/ +#define MASK_BOXSOLID (FTECONTENTS_SOLID|FTECONTENTS_PLAYERCLIP|Q2CONTENTS_WINDOW|FTECONTENTS_BODY) /*default trace type for an entity that does have size*/ +#define MASK_PLAYERSOLID MASK_BOXSOLID +//#define MASK_DEADSOLID (Q2CONTENTS_SOLID|Q2CONTENTS_PLAYERCLIP|Q2CONTENTS_WINDOW) +//#define MASK_MONSTERSOLID (Q2CONTENTS_SOLID|Q2CONTENTS_MONSTERCLIP|Q2CONTENTS_WINDOW|Q2CONTENTS_MONSTER) +#define MASK_WATER (FTECONTENTS_WATER|FTECONTENTS_LAVA|FTECONTENTS_SLIME) +//#define MASK_OPAQUE (Q2CONTENTS_SOLID|Q2CONTENTS_SLIME|Q2CONTENTS_LAVA) +//#define MASK_SHOT (Q2CONTENTS_SOLID|Q2CONTENTS_MONSTER|Q2CONTENTS_WINDOW|Q2CONTENTS_DEADMONSTER) +#define Q2MASK_CURRENT (Q2CONTENTS_CURRENT_0|Q2CONTENTS_CURRENT_90|Q2CONTENTS_CURRENT_180|Q2CONTENTS_CURRENT_270|Q2CONTENTS_CURRENT_UP|Q2CONTENTS_CURRENT_DOWN) diff --git a/engine/common/cmd.c b/engine/common/cmd.c index ac7357a30..b2006e14f 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -2121,6 +2121,19 @@ const char *retstring(const char *s) strcpy(ret->str, s); return ret->str; } +const char *retint(int f) +{ + char s[1024]; + tempstack_t *ret; + if (!f) + return ""; + sprintf(s, "%d", f); + ret = (tempstack_t*)Z_Malloc(sizeof(tempstack_t)+strlen(s)); + ret->next = ifstack; + ifstack=ret; + strcpy(ret->str, s); + return ret->str; +} const char *retfloat(float f) { char s[1024]; @@ -2185,7 +2198,7 @@ const char *If_Token(const char *func, const char **end) else if (!strcmp(com_token, "int")) { func = If_Token(s, end); - return retfloat(atof(func)); + return retint(atoi(func)); } else if (!strcmp(com_token, "strlen")) { @@ -2627,7 +2640,7 @@ void Cmd_set_f(void) return; text = Cmd_Argv(2); } - else if (dpcompat_set.ival) + else if (dpcompat_set.ival && !docalc) { text = Cmd_Argv(2); /*desc = Cmd_Argv(3)*/ diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index 81ba92221..5b2d1a937 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -1662,7 +1662,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, galiasinfo_t *inf, int surfnum, ent //The whole reason why model loading is supported in the server. -qboolean Mod_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, trace_t *trace) +qboolean Mod_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int contentsmask, trace_t *trace) { galiasinfo_t *mod = Mod_Extradata(model); galiasgroup_t *group; @@ -2765,6 +2765,8 @@ qboolean Mod_LoadQ1Model (model_t *mod, void *buffer) #endif galias->nextsurf = 0; + loadmodel->numframes = pq1inmodel->numframes; + //skins skinstart = (daliasskintype_t *)((char*)pq1inmodel+hdrsize); @@ -2977,7 +2979,7 @@ qboolean Mod_LoadQ1Model (model_t *mod, void *buffer) Hunk_FreeToLowMark (hunkstart); - mod->funcs.Trace = Mod_Trace; + mod->funcs.NativeTrace = Mod_Trace; return true; } @@ -3317,7 +3319,7 @@ qboolean Mod_LoadQ2Model (model_t *mod, void *buffer) Hunk_FreeToLowMark (hunkstart); - mod->funcs.Trace = Mod_Trace; + mod->funcs.NativeTrace = Mod_Trace; return true; } @@ -4108,7 +4110,7 @@ qboolean Mod_LoadQ3Model(model_t *mod, void *buffer) Hunk_FreeToLowMark (hunkstart); - mod->funcs.Trace = Mod_Trace; + mod->funcs.NativeTrace = Mod_Trace; return true; } @@ -4438,7 +4440,7 @@ qboolean Mod_LoadZymoticModel(model_t *mod, void *buffer) Hunk_FreeToLowMark (hunkstart); - mod->funcs.Trace = Mod_Trace; + mod->funcs.NativeTrace = Mod_Trace; return true; } @@ -5124,7 +5126,7 @@ qboolean Mod_LoadPSKModel(model_t *mod, void *buffer) Hunk_FreeToLowMark (hunkstart); - mod->funcs.Trace = Mod_Trace; + mod->funcs.NativeTrace = Mod_Trace; return true; } @@ -5479,7 +5481,7 @@ qboolean Mod_LoadDarkPlacesModel(model_t *mod, void *buffer) Hunk_FreeToLowMark (hunkstart); - mod->funcs.Trace = Mod_Trace; + mod->funcs.NativeTrace = Mod_Trace; return true; } @@ -6609,7 +6611,7 @@ qboolean Mod_LoadMD5MeshModel(model_t *mod, void *buffer) Hunk_FreeToLowMark (hunkstart); - mod->funcs.Trace = Mod_Trace; + mod->funcs.NativeTrace = Mod_Trace; return true; } @@ -6816,7 +6818,7 @@ qboolean Mod_LoadCompositeAnim(model_t *mod, void *buffer) Hunk_FreeToLowMark (hunkstart); - mod->funcs.Trace = Mod_Trace; + mod->funcs.NativeTrace = Mod_Trace; return true; } diff --git a/engine/common/fs.c b/engine/common/fs.c index 7550ca293..dc3aa3ff5 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -231,6 +231,8 @@ void COM_Path_f (void) Con_Printf ("Pure paths:\n"); for (s=com_purepaths ; s ; s=s->nextpure) { + if (s->referenced) + Con_Printf("*"); s->funcs->PrintPath(s->handle); } Con_Printf ("----------\n"); @@ -243,6 +245,8 @@ void COM_Path_f (void) if (s == com_base_searchpaths) Con_Printf ("----------\n"); + if (s->referenced) + Con_Printf("*"); s->funcs->PrintPath(s->handle); } } @@ -529,9 +533,9 @@ int FS_FLocateFile(const char *filename, FSLF_ReturnType_e returntype, flocation { if (search->funcs->FindFile(search->handle, loc, filename, pf)) { + search->referenced |= fs_referencetype; if (loc) { - search->referenced |= fs_referencetype; loc->search = search; len = loc->len; } @@ -670,7 +674,7 @@ char *FS_GetPackNames(char *buffer, int buffersize, int referencedonly, qboolean if (referencedonly == 0 && !search->referenced) continue; if (referencedonly == 2 && search->referenced) - Q_strncatz(buffer, "*", sizeof(buffer)); + Q_strncatz(buffer, "*", buffersize); if (!ext) { @@ -1339,6 +1343,8 @@ static int FS_AddWildDataFiles (const char *descriptor, int size, void *vparam) if (!search->funcs->FindFile(search->handle, &loc, descriptor, NULL)) return true; //not found.. vfs = search->funcs->OpenVFS(search->handle, &loc, "rb"); + if (!vfs) + return true; pak = funcs->OpenNew (vfs, pakfile); if (!pak) return true; @@ -1727,7 +1733,7 @@ void COM_Gamedir (const char *dir) /*some modern non-compat settings*/ #define DMFCFG "set com_parseutf8 1\npm_airstep 1\nsv_demoExtensions 1\n" /*set some stuff so our regular qw client appears more like hexen2*/ -#define HEX2CFG "set r_particlesdesc \"spikeset tsshaft h2part\"\nset sv_maxspeed 640\nset watervis 1\nset r_wateralpha 0.5\nset sv_pupglow 1\nset cl_model_bobbing 1\nsv_sound_land \"fx/thngland.wav\"\n" +#define HEX2CFG "set_calc cl_playerclass int (random * 5) + 1\nset r_particlesdesc \"spikeset tsshaft h2part\"\nset sv_maxspeed 640\nset watervis 1\nset r_wateralpha 0.5\nset sv_pupglow 1\nset cl_model_bobbing 1\nsv_sound_land \"fx/thngland.wav\"\n" /*Q3's ui doesn't like empty model/headmodel/handicap cvars, even if the gamecode copes*/ #define Q3CFG "gl_overbright 2\nseta model sarge\nseta headmodel sarge\nseta handicap 100\n" @@ -1771,6 +1777,8 @@ const gamemode_info_t gamemode_info[] = { {"FTE-JK2", "jk2", "-jk2", {"base/assets0.pk3"}, NULL, {"base", "fte"}, "Jedi Knight II: Jedi Outcast"}, {"FTE-HalfLife", "hl", "-halflife", {"valve/liblist.gam"}, NULL, {"valve", "ftehl"}, "Half-Life"}, + {"FTE-Doom", "doom", "-doom", {"doom.wad"}, NULL, { "ftedoom"}, "Doom"}, + {"FTE-Doom2", "doom2", "-doom2", {"doom2.wad"}, NULL, { "ftedoom"}, "Doom2"}, {NULL} }; @@ -2013,6 +2021,24 @@ char *FSQ3_GenerateClientPacksList(char *buffer, int maxlen, int basechecksum) return buffer; } +#ifdef DOOMWADS +void FS_AddRootWads(void) +{ + vfsfile_t *vfs; + char *fname = "doom.wad"; + void *pak; + extern searchpathfuncs_t doomwadfilefuncs; + + vfs = FS_OpenVFS(fname, "rb", FS_ROOT); + + pak = doomwadfilefuncs.OpenNew(vfs, fname); + if (!pak) + return; + + FS_AddPathHandle(fname, fname, &doomwadfilefuncs, pak, true, false, false, (unsigned int)-1); +} +#endif + /* ================ FS_ReloadPackFiles @@ -2056,6 +2082,10 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags) com_base_searchpaths = NULL; +#ifdef DOOMWADS + FS_AddRootWads(); +#endif + while(oldpaths) { next = oldpaths->nextpure; @@ -2369,6 +2399,10 @@ void FS_StartupWithGame(int gamenum) Cvar_Set(&com_protocolname, gamemode_info[gamenum].protocolname); Cvar_ForceSet(&fs_gamename, gamemode_info[gamenum].poshname); +#ifdef DOOMWADS + FS_AddRootWads(); +#endif + // // start up with id1 by default // diff --git a/engine/common/fs_pak.c b/engine/common/fs_pak.c index 2b70aa948..6cb402032 100644 --- a/engine/common/fs_pak.c +++ b/engine/common/fs_pak.c @@ -389,7 +389,7 @@ searchpathfuncs_t packfilefuncs = { #ifdef DOOMWADS -void *FSPAK_LoadDoomWadFile (vfsfile_t *packhandle, char *desc) +void *FSPAK_LoadDoomWadFile (vfsfile_t *packhandle, const char *desc) { dwadheader_t header; int i; diff --git a/engine/common/fs_win32.c b/engine/common/fs_win32.c index 63b457fde..218698b54 100644 --- a/engine/common/fs_win32.c +++ b/engine/common/fs_win32.c @@ -57,6 +57,7 @@ static int VFSW32_WriteBytes (struct vfsfile_s *file, const void *buffer, int by } static qboolean VFSW32_Seek (struct vfsfile_s *file, unsigned long pos) { + unsigned long upper, lower; vfsw32file_t *intfile = (vfsw32file_t*)file; if (intfile->mmap) { @@ -64,7 +65,10 @@ static qboolean VFSW32_Seek (struct vfsfile_s *file, unsigned long pos) return true; } - return SetFilePointer(intfile->hand, pos, NULL, FILE_BEGIN) != INVALID_SET_FILE_POINTER; + lower = (pos & 0xffffffff); + upper = ((pos>>16)>>16); + + return SetFilePointer(intfile->hand, lower, &upper, FILE_BEGIN) != INVALID_SET_FILE_POINTER; } static unsigned long VFSW32_Tell (struct vfsfile_s *file) { diff --git a/engine/common/fs_zip.c b/engine/common/fs_zip.c index 7ebfec276..21291bfc5 100644 --- a/engine/common/fs_zip.c +++ b/engine/common/fs_zip.c @@ -468,18 +468,31 @@ typedef struct { int index; int startpos; } vfszip_t; -void VFSZIP_MakeActive(vfszip_t *vfsz) +qboolean VFSZIP_MakeActive(vfszip_t *vfsz) { int i; char buffer[8192]; //must be power of two if ((vfszip_t*)vfsz->parent->currentfile == vfsz) - return; //already us + return true; //already us if (vfsz->parent->currentfile) unzCloseCurrentFile(vfsz->parent->handle); unzLocateFileMy(vfsz->parent->handle, vfsz->index, vfsz->startpos); - unzOpenCurrentFile(vfsz->parent->handle); + if (unzOpenCurrentFile(vfsz->parent->handle) == UNZ_BADZIPFILE) + { + unz_file_info file_info; + buffer[0] = '?'; + buffer[1] = 0; + if (unzGetCurrentFileInfo (vfsz->parent->handle, &file_info, buffer, sizeof(buffer), NULL, 0, NULL, 0) != UNZ_OK) + Con_Printf("Zip Error\n"); + if (file_info.compression_method && file_info.compression_method != Z_DEFLATED) + Con_Printf("unsupported compression method on %s/%s\n", vfsz->parent->filename, buffer); + else + Con_Printf("corrupt file within zip, %s/%s\n", vfsz->parent->filename, buffer); + vfsz->parent->currentfile = NULL; + return false; + } if (vfsz->pos > 0) @@ -493,6 +506,7 @@ void VFSZIP_MakeActive(vfszip_t *vfsz) } vfsz->parent->currentfile = (vfsfile_t*)vfsz; + return true; } int VFSZIP_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestoread) @@ -505,7 +519,8 @@ int VFSZIP_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestoread) if (vfsz->iscompressed) { - VFSZIP_MakeActive(vfsz); + if (!VFSZIP_MakeActive(vfsz)) + return 0; read = unzReadCurrentFile(vfsz->parent->handle, buffer, bytestoread); } else @@ -535,37 +550,44 @@ qboolean VFSZIP_Seek (struct vfsfile_s *file, unsigned long pos) return VFS_SEEK(vfsz->defer, pos); //This is *really* inefficient - if (vfsz->parent->currentfile == file) - { - if (vfsz->iscompressed) - { //if they're going to seek on a file in a zip, let's just copy it out - char buffer[8192]; - unsigned int chunk; - unsigned int i; - unsigned int length; + if (vfsz->iscompressed) + { //if they're going to seek on a file in a zip, let's just copy it out + char buffer[8192]; + unsigned int chunk; + unsigned int i; + unsigned int length; - vfsz->defer = FS_OpenTemp(); - if (vfsz->defer) + vfsz->defer = FS_OpenTemp(); + if (vfsz->defer) + { + if (vfsz->pos) { unzCloseCurrentFile(vfsz->parent->handle); vfsz->parent->currentfile = NULL; //make it not us + } - length = vfsz->length; - i = 0; - vfsz->pos = 0; - VFSZIP_MakeActive(vfsz); - while (1) - { - chunk = length - i; - if (chunk > sizeof(buffer)) - chunk = sizeof(buffer); - if (chunk == 0) - break; - unzReadCurrentFile(vfsz->parent->handle, buffer, chunk); - VFS_WRITE(vfsz->defer, buffer, chunk); + length = vfsz->length; + i = 0; + vfsz->pos = 0; + if (!VFSZIP_MakeActive(vfsz)) + { + /*shouldn't really happen*/ + VFS_CLOSE(vfsz->defer); + vfsz->defer = NULL; + return false; + } - i += chunk; - } + while (1) + { + chunk = length - i; + if (chunk > sizeof(buffer)) + chunk = sizeof(buffer); + if (chunk == 0) + break; + unzReadCurrentFile(vfsz->parent->handle, buffer, chunk); + VFS_WRITE(vfsz->defer, buffer, chunk); + + i += chunk; } } @@ -574,10 +596,13 @@ qboolean VFSZIP_Seek (struct vfsfile_s *file, unsigned long pos) if (vfsz->defer) return VFS_SEEK(vfsz->defer, pos); + else + { + unzCloseCurrentFile(vfsz->parent->handle); + vfsz->parent->currentfile = NULL; //make it not us, so the next read starts at the right place + } } - - if (pos < 0 || pos > vfsz->length) return false; vfsz->pos = pos; @@ -653,6 +678,15 @@ vfsfile_t *FSZIP_OpenVFS(void *handle, flocation_t *loc, const char *mode) Z_Free(vfsz); return NULL; } + else if (!VFSZIP_MakeActive(vfsz)) /*this is called purely as a test*/ + { + /* + windows explorer tends to use deflate64 on large files, which zlib and thus we, do not support, thus this is a 'common' failure path + this might also trigger from other errors, of course. + */ + Z_Free(vfsz); + return NULL; + } zip->references++; diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index 827744db5..28ab04a82 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -3748,7 +3748,6 @@ cmodel_t *CM_LoadMap (char *name, char *filein, qboolean clientload, unsigned *c loadmodel->funcs.StainNode = GLR_Q2BSP_StainNode; loadmodel->funcs.MarkLights = Q2BSP_MarkLights; #endif - loadmodel->funcs.Trace = CM_Trace; loadmodel->funcs.PointContents = Q2BSP_PointContents; loadmodel->funcs.NativeTrace = CM_NativeTrace; loadmodel->funcs.NativeContents = CM_NativeContents; @@ -3845,7 +3844,6 @@ cmodel_t *CM_LoadMap (char *name, char *filein, qboolean clientload, unsigned *c loadmodel->funcs.MarkLights = NULL; loadmodel->funcs.LeafPVS = CM_LeafnumPVS; loadmodel->funcs.LeafnumForPoint = CM_PointLeafnum; - loadmodel->funcs.Trace = CM_Trace; loadmodel->funcs.PointContents = Q2BSP_PointContents; loadmodel->funcs.NativeTrace = CM_NativeTrace; loadmodel->funcs.NativeContents = CM_NativeContents; @@ -3896,7 +3894,6 @@ cmodel_t *CM_LoadMap (char *name, char *filein, qboolean clientload, unsigned *c loadmodel->funcs.MarkLights = Q2BSP_MarkLights; loadmodel->funcs.LeafPVS = CM_LeafnumPVS; loadmodel->funcs.LeafnumForPoint = CM_PointLeafnum; - loadmodel->funcs.Trace = CM_Trace; loadmodel->funcs.PointContents = Q2BSP_PointContents; loadmodel->funcs.NativeTrace = CM_NativeTrace; loadmodel->funcs.NativeContents = CM_NativeContents; @@ -4079,7 +4076,6 @@ void CM_InitBoxHull (void) #endif box_model.funcs.LeafPVS = CM_LeafnumPVS; box_model.funcs.LeafnumForPoint = CM_PointLeafnum; - box_model.funcs.Trace = CM_Trace; box_model.funcs.NativeContents = CM_NativeContents; box_model.funcs.NativeTrace = CM_NativeTrace; @@ -5180,14 +5176,6 @@ trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, return trace_trace; } -qboolean CM_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, trace_t *trace) -{ - if (maxs[0] - mins[0]) - *trace = CM_BoxTrace(model, start, end, mins, maxs, MASK_PLAYERSOLID); - else - *trace = CM_BoxTrace(model, start, end, mins, maxs, MASK_SOLID); - return trace->fraction != 1; -} qboolean CM_NativeTrace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int contents, trace_t *trace) { *trace = CM_BoxTrace(model, start, end, mins, maxs, contents); @@ -5707,18 +5695,7 @@ unsigned int Q2BSP_PointContents(model_t *mod, vec3_t axis[3], vec3_t p) { int pc, ret = FTECONTENTS_EMPTY; pc = CM_PointContents (mod, p); - if (pc & (Q2CONTENTS_SOLID|Q2CONTENTS_WINDOW)) - ret |= FTECONTENTS_SOLID; - if (pc & Q2CONTENTS_LAVA) - ret |= FTECONTENTS_LAVA; - if (pc & Q2CONTENTS_SLIME) - ret |= FTECONTENTS_SLIME; - if (pc & Q2CONTENTS_WATER) - ret |= FTECONTENTS_WATER; - if (pc & Q2CONTENTS_LADDER) - ret |= FTECONTENTS_LADDER; - - return ret; + return pc; } diff --git a/engine/common/net.h b/engine/common/net.h index 0fa0c28ca..523313feb 100644 --- a/engine/common/net.h +++ b/engine/common/net.h @@ -83,7 +83,7 @@ void NET_SendPacket (netsrc_t socket, int length, void *data, netadr_t to); int NET_LocalAddressForRemote(struct ftenet_connections_s *collection, netadr_t *remote, netadr_t *local, int idx); void NET_PrintAddresses(struct ftenet_connections_s *collection); qboolean NET_AddressSmellsFunny(netadr_t a); -void NET_EnsureRoute(struct ftenet_connections_s *collection, char *routename, char *host, qboolean islisten); +qboolean NET_EnsureRoute(struct ftenet_connections_s *collection, char *routename, char *host, qboolean islisten); qboolean NET_CompareAdr (netadr_t a, netadr_t b); qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b); diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index 9f57262ef..7ce1fd364 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -255,7 +255,7 @@ qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b) if (a.type == NA_LOOPBACK) return true; - if (a.type == NA_IP) + if (a.type == NA_IP || a.type == NA_TCP) { if ((memcmp(a.address.ip, b.address.ip, sizeof(a.address.ip)) == 0)) return true; @@ -507,6 +507,13 @@ char *NET_BaseAdrToString (char *s, int len, netadr_t a) a.address.ip[2], a.address.ip[3]); break; + case NA_TCP: + snprintf (s, len, "tcp://%i.%i.%i.%i", + a.address.ip[0], + a.address.ip[1], + a.address.ip[2], + a.address.ip[3]); + break; #ifdef IPPROTO_IPV6 case NA_BROADCAST_IP6: case NA_IPV6: @@ -2081,6 +2088,7 @@ closesvstream: if (con->generic.thesocket != INVALID_SOCKET && con->active < 256) { int newsock; + fromlen = sizeof(from); newsock = accept(con->generic.thesocket, (struct sockaddr*)&from, &fromlen); if (newsock != INVALID_SOCKET) { @@ -2126,6 +2134,7 @@ qboolean FTENET_TCPConnect_SendPacket(ftenet_generic_connection_t *gcon, int len if (NET_CompareAdr(to, st->remoteaddr)) { unsigned short slen = BigShort((unsigned short)length); +#pragma warningmsg("TCPConnect: these calls can fail, corrupting the message stream") send(st->socketnum, (char*)&slen, sizeof(slen), 0); send(st->socketnum, data, length, 0); @@ -2168,11 +2177,15 @@ ftenet_generic_connection_t *FTENET_TCPConnect_EstablishConnection(int affamily, netadr_t adr; struct sockaddr_qstorage qs; int family; + if (!strncmp(address, "tcp://", 6)) + address += 6; if (isserver) { if (!NET_PortToAdr(affamily, address, &adr)) return NULL; //couldn't resolve the name + if (adr.type == NA_IP) + adr.type = NA_TCP; temp = NetadrToSockadr(&adr, &qs); family = ((struct sockaddr_in*)&qs)->sin_family; @@ -2200,6 +2213,9 @@ ftenet_generic_connection_t *FTENET_TCPConnect_EstablishConnection(int affamily, { if (!NET_PortToAdr(affamily, address, &adr)) return NULL; //couldn't resolve the name + + if (adr.type == NA_IP) + adr.type = NA_TCP; newsocket = TCP_OpenStream(adr); if (newsocket == INVALID_SOCKET) return NULL; @@ -2218,7 +2234,7 @@ ftenet_generic_connection_t *FTENET_TCPConnect_EstablishConnection(int affamily, newcon->generic.SendPacket = FTENET_TCPConnect_SendPacket; newcon->generic.Close = FTENET_TCPConnect_Close; - newcon->generic.islisten = true; + newcon->generic.islisten = isserver; newcon->generic.addrtype[0] = adr.type; newcon->generic.addrtype[1] = NA_INVALID; @@ -2947,7 +2963,7 @@ void NET_SendPacket (netsrc_t netsrc, int length, void *data, netadr_t to) Con_Printf("No route - open some ports\n"); } -void NET_EnsureRoute(ftenet_connections_t *collection, char *routename, char *host, qboolean islisten) +qboolean NET_EnsureRoute(ftenet_connections_t *collection, char *routename, char *host, qboolean islisten) { netadr_t adr; NET_StringToAdr(host, &adr); @@ -2956,23 +2972,27 @@ void NET_EnsureRoute(ftenet_connections_t *collection, char *routename, char *ho { #ifdef TCPCONNECT case NA_TCP: - FTENET_AddToCollection(collection, routename, host, FTENET_TCP4Connect_EstablishConnection, islisten); + if (!FTENET_AddToCollection(collection, routename, host, FTENET_TCP4Connect_EstablishConnection, islisten)) + return false; break; #ifdef IPPROTO_IPV6 case NA_TCPV6: - FTENET_AddToCollection(collection, routename, host, FTENET_TCP6Connect_EstablishConnection, islisten); + if (!FTENET_AddToCollection(collection, routename, host, FTENET_TCP6Connect_EstablishConnection, islisten)) + return false; break; #endif #endif #ifdef IRCCONNECT case NA_IRC: - FTENET_AddToCollection(collection, routename, host, FTENET_IRCConnect_EstablishConnection, islisten); + if (!FTENET_AddToCollection(collection, routename, host, FTENET_IRCConnect_EstablishConnection, islisten)) + return false; break; #endif default: //not recognised, or not needed break; } + return true; } void NET_PrintAddresses(ftenet_connections_t *collection) @@ -3009,12 +3029,17 @@ int TCP_OpenStream (netadr_t remoteaddr) int newsocket; int temp; struct sockaddr_qstorage qs; + struct sockaddr_qstorage loc; temp = NetadrToSockadr(&remoteaddr, &qs); if ((newsocket = socket (((struct sockaddr_in*)&qs)->sin_family, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) return INVALID_SOCKET; +// memset(&loc, 0, sizeof(loc)); +// ((struct sockaddr*)&loc)->sa_family = ((struct sockaddr*)&loc)->sa_family; +// bind(newsocket, (struct sockaddr *)&loc, ((struct sockaddr_in*)&qs)->sin_family == AF_INET?sizeof(struct sockaddr_in):sizeof(struct sockaddr_in6)); + if (connect(newsocket, (struct sockaddr *)&qs, temp) == INVALID_SOCKET) { closesocket(newsocket); diff --git a/engine/common/particles.h b/engine/common/particles.h index f61e5cf5e..a8fd33316 100644 --- a/engine/common/particles.h +++ b/engine/common/particles.h @@ -126,6 +126,7 @@ typedef struct { int (*ParticleTypeForName) (char *name); int (*FindParticleType) (char *name); + qboolean (*ParticleQuery) (int type, int body, char *outstr, int outstrlen); int (*RunParticleEffectTypeString) (vec3_t org, vec3_t dir, float count, char *name); int (*ParticleTrail) (vec3_t startpos, vec3_t end, int type, int dlkey, trailstate_t **tsk); diff --git a/engine/common/pmove.c b/engine/common/pmove.c index 445e545eb..391e7c0cf 100644 --- a/engine/common/pmove.c +++ b/engine/common/pmove.c @@ -59,6 +59,7 @@ static void PM_AddTouchedEnt (int num) return; // already added pmove.touchindex[pmove.numtouch] = num; + VectorCopy(pmove.velocity, pmove.touchvel[pmove.numtouch]); pmove.numtouch++; } @@ -759,7 +760,7 @@ void PM_CategorizePosition (void) } } - if (cont & FTECONTENTS_LADDER) + if (cont & Q2CONTENTS_LADDER && pmove.physents[0].model->fromgame == fg_quake2) pmove.onladder = true; else pmove.onladder = false; @@ -785,7 +786,7 @@ void PM_CategorizePosition (void) pmove.onground = false; // too steep } } - if (cont & FTECONTENTS_LADDER && pmove.physents[0].model->fromgame == fg_quake2) + if (cont & Q2CONTENTS_LADDER && pmove.physents[0].model->fromgame == fg_quake2) { trace_t t; vec3_t flatforward, fwd1; @@ -812,7 +813,7 @@ void PM_CategorizePosition (void) //bsp objects marked as ladders mark regions to stand in to be classed as on a ladder. cont = PM_ExtraBoxContents(pmove.origin); - if (cont & FTECONTENTS_LADDER) + if ((cont & Q2CONTENTS_LADDER) && (pmove.physents[0].model->fromgame == fg_quake2 || pmove.physents[0].model->fromgame == fg_halflife)) { pmove.onladder = true; pmove.onground = false; // too steep diff --git a/engine/common/pmove.h b/engine/common/pmove.h index 7a6cf51ee..9cdacd2b5 100644 --- a/engine/common/pmove.h +++ b/engine/common/pmove.h @@ -74,6 +74,7 @@ typedef struct // results int numtouch; int touchindex[MAX_PHYSENTS]; + vec3_t touchvel[MAX_PHYSENTS]; qboolean onground; int groundent; // index in physents array, only valid // when onground is true diff --git a/engine/common/pmovetst.c b/engine/common/pmovetst.c index 1f5a32215..fd1128dd6 100644 --- a/engine/common/pmovetst.c +++ b/engine/common/pmovetst.c @@ -215,7 +215,7 @@ static qboolean PM_TransformedHullCheck (model_t *model, vec3_t start, vec3_t en { AngleVectors (angles, axis[0], axis[1], axis[2]); VectorNegate(axis[1], axis[1]); - model->funcs.Trace(model, 0, 0, axis, start_l, end_l, player_mins, player_maxs, trace); + model->funcs.NativeTrace(model, 0, 0, axis, start_l, end_l, player_mins, player_maxs, MASK_PLAYERSOLID, trace); } else { @@ -226,7 +226,7 @@ static qboolean PM_TransformedHullCheck (model_t *model, vec3_t start, vec3_t en if (start_l[i]+player_maxs[i] < model->mins[i] && end_l[i] + player_maxs[i] < model->mins[i]) return false; } - model->funcs.Trace(model, 0, 0, NULL, start_l, end_l, player_mins, player_maxs, trace); + model->funcs.NativeTrace(model, 0, 0, NULL, start_l, end_l, player_mins, player_maxs, MASK_PLAYERSOLID, trace); } } else diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index e2074813e..0d58dc449 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -458,4 +458,4 @@ enum lightfield_e lfield_ambientscale=10, lfield_diffusescale=11, lfield_specularscale=12 -}; \ No newline at end of file +}; diff --git a/engine/common/q1bsp.c b/engine/common/q1bsp.c index 31f36aebe..db3b98121 100644 --- a/engine/common/q1bsp.c +++ b/engine/common/q1bsp.c @@ -375,7 +375,7 @@ unsigned int Q1BSP_PointContents(model_t *model, vec3_t axis[3], vec3_t point) return Q1BSP_HullPointContents(&model->hulls[0], point); } -qboolean Q1BSP_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, trace_t *trace) +qboolean Q1BSP_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int hitcontentsmask, trace_t *trace) { hull_t *hull; vec3_t size; @@ -1390,6 +1390,6 @@ void Q1BSP_SetModelFuncs(model_t *mod) mod->funcs.LeafnumForPoint = Q1BSP_LeafnumForPoint; mod->funcs.LeafPVS = Q1BSP_LeafnumPVS; - mod->funcs.Trace = Q1BSP_Trace; + mod->funcs.NativeTrace = Q1BSP_Trace; mod->funcs.PointContents = Q1BSP_PointContents; } diff --git a/engine/common/q2pmove.c b/engine/common/q2pmove.c index c2ca58158..50c24f9f4 100644 --- a/engine/common/q2pmove.c +++ b/engine/common/q2pmove.c @@ -481,7 +481,7 @@ void PMQ2_AddCurrents (vec3_t wishvel) // add water currents // - if (q2pm->watertype & MASK_CURRENT) + if (q2pm->watertype & Q2MASK_CURRENT) /*FIXME: q3bsp*/ { memset(v, 0, sizeof(vec3_t)); diff --git a/engine/common/translate.c b/engine/common/translate.c index e4478ba24..7408b26a8 100644 --- a/engine/common/translate.c +++ b/engine/common/translate.c @@ -894,4 +894,5 @@ char *T_GetInfoString(int num) return info_strings_table[num]; } -#endif \ No newline at end of file +#endif + diff --git a/engine/common/unzip.c b/engine/common/unzip.c index ed5318350..0d1459332 100644 --- a/engine/common/unzip.c +++ b/engine/common/unzip.c @@ -209,7 +209,8 @@ local unsigned long unzlocal_SearchCentralDir(vfsfile_t *fin) { if (!VFS_SEEK(fin, uReadPos)) break; - if (VFS_READ(fin,buf,(unsigned int)uReadSize)!=uReadSize) break; + if (VFS_READ(fin,buf,uReadSize)!=uReadSize) + break; for (i=(int)uReadSize-3; (i--)>0;) if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && @@ -218,7 +219,8 @@ local unsigned long unzlocal_SearchCentralDir(vfsfile_t *fin) { break; } - if (uPosFound!=0) break; + if (uPosFound!=0) + break; } TRYFREE(buf); return uPosFound; diff --git a/engine/common/world.h b/engine/common/world.h index f2f725295..2fc20428b 100644 --- a/engine/common/world.h +++ b/engine/common/world.h @@ -103,11 +103,12 @@ typedef struct q2trace_s //13 #define FL_FINDABLE_NONSOLID (1<<14) //a cpqwsv feature #define FL_MOVECHAIN_ANGLE (1<<15) // hexen2 - when in a move chain, will update the angle -#define FL_LAGGEDMOVE (1<<16) - //17 +#define FLQW_LAGGEDMOVE (1<<16) +#define FLH2_HUNTFACE (1<<16) +#define FLH2_NOZ (1<<17) //18 //19 - //20 +#define FL_HUBSAVERESET (1<<20) //hexen2, ent is reverted to original state on map changes. #define FL_CLASS_DEPENDENT (1<<21) //hexen2 @@ -249,7 +250,7 @@ void VARGS WorldQ2_LinkEdict(world_t *w, q2edict_t *ent); void VARGS WorldQ2_UnlinkEdict(world_t *w, q2edict_t *ent); int VARGS WorldQ2_AreaEdicts (world_t *w, vec3_t mins, vec3_t maxs, q2edict_t **list, int maxcount, int areatype); -trace_t WorldQ2_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, q2edict_t *passedict); +trace_t WorldQ2_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int hitcontentsmask, q2edict_t *passedict); unsigned int Q2BSP_FatPVS (model_t *mod, vec3_t org, qbyte *buffer, unsigned int buffersize, qboolean add); qboolean Q2BSP_EdictInFatPVS(model_t *mod, struct pvscache_s *ent, qbyte *pvs); diff --git a/engine/dotnet2005/ftequake.vcproj b/engine/dotnet2005/ftequake.vcproj index 14a7abc98..4bfff5e75 100644 --- a/engine/dotnet2005/ftequake.vcproj +++ b/engine/dotnet2005/ftequake.vcproj @@ -20539,6 +20539,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -22015,6 +22179,170 @@ /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/engine/droid/res/drawable-hdpi/icon.png b/engine/droid/res/drawable-hdpi/icon.png index 8074c4c571b8cd19e27f4ee5545df367420686d7..8ac009c913ec859e7d32f998d34b8a3968ffea67 100644 GIT binary patch literal 9070 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 diff --git a/engine/droid/res/drawable-ldpi/icon.png b/engine/droid/res/drawable-ldpi/icon.png index 1095584ec21f71cd0afc9e0993aa2209671b590c..5b506ad387b2a65a783a01ecfcf5dd3cc9a9e46d 100644 GIT binary patch literal 3472 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 K^vZSJp8gM^2-&d! delta 1708 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 blIs5eNSY+j744LC00000NkvXXu0mjfLD}6m diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 6d995156b..2e68e61af 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -110,6 +110,7 @@ struct { int fbo_diffuse; texid_t tex_sourcecol; /*this is used by $sourcecolour tgen*/ texid_t tex_sourcedepth; + int fbo_depthless; qboolean force2d; int currenttmu; @@ -135,6 +136,7 @@ struct { mesh_t **meshes; unsigned int meshcount; float modelmatrix[16]; + float modelmatrixinv[16]; float modelviewmatrix[16]; int pendingvertexvbo; @@ -759,9 +761,7 @@ static void Shader_BindTextureForPass(int tmu, const shaderpass_t *pass, qboolea case T_GEN_3DMAP: t = pass->anim_frames[0]; - checkglerror(); GL_LazyBind(tmu, GL_TEXTURE_3D, t, useclientarray); - checkglerror(); return; case T_GEN_VIDEOMAP: @@ -2331,12 +2331,25 @@ static unsigned int BE_Program_Set_Attribute(const shaderprogparm_t *p, unsigned break; case SP_E_LMSCALE: - if (shaderstate.mode == BEM_DEPTHDARK) - qglUniform1fARB(p->handle[perm], 0.0f); - else if (shaderstate.curentity->model && shaderstate.curentity->model->engineflags & MDLF_NEEDOVERBRIGHT) - qglUniform1fARB(p->handle[perm], 1<handle[perm], 1.0f); + { + vec4_t colscale; + if (shaderstate.mode == BEM_DEPTHDARK) + { + VectorClear(colscale); + } + else if (shaderstate.curentity->model && shaderstate.curentity->model->engineflags & MDLF_NEEDOVERBRIGHT) + { + float sc = 1<shaderRGBAf, sc, colscale); + } + else + { + VectorCopy(shaderstate.curentity->shaderRGBAf, colscale); + } + colscale[3] = shaderstate.curentity->shaderRGBAf[3]; + + qglUniform4fvARB(p->handle[perm], 1, (GLfloat*)colscale); + } break; case SP_E_GLOWMOD: @@ -2426,19 +2439,15 @@ static unsigned int BE_Program_Set_Attribute(const shaderprogparm_t *p, unsigned { /*eye position in model space*/ vec3_t t2; - Matrix4x4_CM_Transform3(shaderstate.modelmatrix, r_origin, t2); + Matrix4x4_CM_Transform3(shaderstate.modelmatrixinv, r_origin, t2); qglUniform3fvARB(p->handle[perm], 1, t2); } break; case SP_LIGHTPOSITION: { /*light position in model space*/ - float inv[16]; vec3_t t2; - qboolean Matrix4_Invert(const float *m, float *out); - - Matrix4_Invert(shaderstate.modelmatrix, inv); - Matrix4x4_CM_Transform3(inv, shaderstate.lightorg, t2); + Matrix4x4_CM_Transform3(shaderstate.modelmatrixinv, shaderstate.lightorg, t2); qglUniform3fvARB(p->handle[perm], 1, t2); } break; @@ -2753,6 +2762,7 @@ void GLBE_SelectEntity(entity_t *ent) shaderstate.curentity = ent; currententity = ent; R_RotateForEntity(shaderstate.modelmatrix, shaderstate.modelviewmatrix, shaderstate.curentity, shaderstate.curentity->model); + Matrix4_Invert(shaderstate.modelmatrix, shaderstate.modelmatrixinv); if (qglLoadMatrixf) qglLoadMatrixf(shaderstate.modelviewmatrix); if (shaderstate.curentity->flags & Q2RF_DEPTHHACK && qglDepthRange) @@ -3260,9 +3270,7 @@ static void BE_UpdateLightmaps(void) glRect_t *theRect; lightmap[lm]->modified = false; theRect = &lightmap[lm]->rectchange; - checkglerror(); GL_MTBind(0, GL_TEXTURE_2D, lightmap_textures[lm]); - checkglerror(); switch (lightmap_bytes) { case 4: @@ -3285,7 +3293,6 @@ static void BE_UpdateLightmaps(void) theRect->t = LMBLOCK_HEIGHT; theRect->h = 0; theRect->w = 0; - checkglerror(); if (lightmap[lm]->deluxmodified) { @@ -3299,11 +3306,9 @@ static void BE_UpdateLightmaps(void) theRect->t = LMBLOCK_HEIGHT; theRect->h = 0; theRect->w = 0; - checkglerror(); } } } - checkglerror(); } batch_t *GLBE_GetTempBatch(void) @@ -3327,6 +3332,29 @@ void GLBE_BaseEntTextures(void) } #endif +void GLBE_RenderToTexture(texid_t sourcecol, texid_t sourcedepth, texid_t destcol, texid_t destdepth, qboolean usedepth) +{ + shaderstate.tex_sourcecol = sourcecol; + shaderstate.tex_sourcedepth = sourcedepth; + if (!destcol.num) + qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + else + { + if (!shaderstate.fbo_depthless) + { + qglGenFramebuffersEXT(1, &shaderstate.fbo_depthless); + qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shaderstate.fbo_depthless); + + qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + qglReadBuffer(GL_NONE); + } + else + qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shaderstate.fbo_depthless); + + qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, destcol.num, 0); + } +} + void GLBE_DrawLightPrePass(qbyte *vis, batch_t **batches) { extern cvar_t temp1; @@ -3461,8 +3489,6 @@ void GLBE_DrawWorld (qbyte *vis) batch_t *batches[SHADER_SORT_COUNT]; RSpeedLocals(); - checkglerror(); - GL_DoSwap(); if (!r_refdef.recurse) @@ -3552,8 +3578,6 @@ void GLBE_DrawWorld (qbyte *vis) BE_SelectEntity(&r_worldentity); shaderstate.curtime = shaderstate.updatetime = realtime; - checkglerror(); - shaderstate.identitylighting = 1; } #endif diff --git a/engine/gl/gl_bloom.c b/engine/gl/gl_bloom.c index 4dc5ae71e..5a4ad4e59 100644 --- a/engine/gl/gl_bloom.c +++ b/engine/gl/gl_bloom.c @@ -20,11 +20,223 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // gl_bloom.c: 2D lighting post process effect +/* +info about bloom algo: +bloom is basically smudging. +screen is nearest-downsampled to some usable scale and filtered to remove low-value light (this is what stops non-bright stuff from blooming) +this filtered image is then downsized multiple times +the downsized image is then blured +the downsized images are then blured horizontally, and then vertically. +final pass simply adds each blured level to the original image. +all samples are then added together for final rendering (with some kind of tone mapping if you want proper hdr). + +note: the horizontal/vertical bluring is a guassian filter +note: bloom comes from the fact that the most downsampled image doesn't have too many pixels. the pixels that it does have are spread over a large area. + +http://prideout.net/archive/bloom/ contains some sample code +*/ + + //http://www.quakesrc.org/forums/viewtopic.php?t=4340&start=0 #include "quakedef.h" #ifdef GLQUAKE +#include "shader.h" +#include "glquake.h" +cvar_t r_bloom = CVARAFD("r_bloom", "0", "gl_bloom", CVAR_ARCHIVE, "Enables bloom (light bleeding from bright objects)"); +static shader_t *bloomfilter; +static shader_t *bloomrescale; +static shader_t *bloomblur; +static shader_t *bloomfinal; + +#define MAXLEVELS 3 +texid_t scrtex; +texid_t pingtex[2][MAXLEVELS]; +static int scrwidth, scrheight; +static int texwidth[MAXLEVELS], texheight[MAXLEVELS]; + + + +void GLBE_RenderToTexture(texid_t sourcecol, texid_t sourcedepth, texid_t destcol, texid_t destdepth, qboolean usedepth); + +void R_BloomRegister(void) +{ + Cvar_Register (&r_bloom, "bloom"); +} +static void R_SetupBloomTextures(int w, int h) +{ + int i, j; + char name[64]; + if (w == scrwidth && h == scrheight) + return; + scrwidth = w; + scrheight = h; + w /= 2; + h /= 2; + for (i = 0; i < MAXLEVELS; i++) + { + w /= 2; + h /= 2; + /*I'm paranoid*/ + if (w < 4) + w = 4; + if (h < 4) + h = 4; + + texwidth[i] = w; + texheight[i] = h; + } + + /*we should be doing this outside of this code*/ + if (!TEXVALID(scrtex)) + scrtex = GL_AllocNewTexture("", scrwidth, scrheight); + GL_MTBind(0, GL_TEXTURE_2D, scrtex); + qglTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, scrwidth, scrheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + /*top level uses nearest sampling*/ + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + /*now create textures for each level*/ + for (j = 0; j < MAXLEVELS; j++) + { + for (i = 0; i < 2; i++) + { + if (!TEXVALID(pingtex[i][j])) + { + sprintf(name, "***bloom*%c*%i***", 'a'+i, j); + TEXASSIGN(pingtex[i][j], GL_AllocNewTexture(name, texwidth[j], texheight[j])); + } + GL_MTBind(0, GL_TEXTURE_2D, pingtex[i][j]); + qglTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, texwidth[j], texheight[j], 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + } + + + bloomfilter = R_RegisterShader("bloom_filter", + "{\n" + "cull none\n" + "program bloom_filter\n" + "{\n" + "map $sourcecolour\n" + "}\n" + "}\n"); + bloomrescale = R_RegisterShader("bloom_rescale", + "{\n" + "cull none\n" + "program default2d\n" + "{\n" + "map $sourcecolour\n" + "}\n" + "}\n"); + bloomblur = R_RegisterShader("bloom_blur", + "{\n" + "cull none\n" + "program bloom_blur\n" + "{\n" + "map $sourcecolour\n" + "}\n" + "}\n"); + bloomfinal = R_RegisterShader("bloom_final", + "{\n" + "cull none\n" + "program bloom_final\n" + "{\n" + "map $sourcecolour\n" + "}\n" + "{\n" + "map $diffuse\n" + "}\n" + "{\n" + "map $loweroverlay\n" + "}\n" + "{\n" + "map $upperoverlay\n" + "}\n" + "}\n"); + bloomfinal->defaulttextures.base = pingtex[0][0]; + bloomfinal->defaulttextures.loweroverlay = pingtex[0][1]; + bloomfinal->defaulttextures.upperoverlay = pingtex[0][2]; +} +void R_BloomBlend (void) +{ + int i; + + if (!gl_config.ext_framebuffer_objects) + return; + if (!gl_config.arb_shader_objects) + return; + + /*whu?*/ + if (!r_refdef.pxrect.width || !r_refdef.pxrect.height) + return; + + GL_Set2D(false); + + /*update textures if we need to resize them*/ + R_SetupBloomTextures(r_refdef.pxrect.width, r_refdef.pxrect.height); + + /*grab the screen, because we failed to do it earlier*/ + GL_MTBind(0, GL_TEXTURE_2D, scrtex); + qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.pxrect.x, r_refdef.pxrect.y - r_refdef.pxrect.height, r_refdef.pxrect.width, r_refdef.pxrect.height); + + /*filter the screen into a downscaled image*/ + GLBE_RenderToTexture(scrtex, r_nulltex, pingtex[0][0], r_nulltex, false); + qglViewport (0, 0, texwidth[0], texheight[0]); + R2D_ScalePic(0, vid.height, vid.width, -(int)vid.height, bloomfilter); + /*and downscale that multiple times*/ + for (i = 1; i < MAXLEVELS; i++) + { + GLBE_RenderToTexture(pingtex[0][i-1], r_nulltex, pingtex[0][i], r_nulltex, false); + qglViewport (0, 0, texwidth[i], texheight[i]); + R2D_ScalePic(0, vid.height, vid.width, -(int)vid.height, bloomrescale); + } + + /*gaussian filter the mips to bloom more smoothly*/ + for (i = 0; i < MAXLEVELS; i++) + { + /*must be 1.2th of a pixel*/ + r_worldentity.glowmod[0] = 1.2 / texwidth[i]; + r_worldentity.glowmod[1] = 0; + GLBE_RenderToTexture(pingtex[0][i], r_nulltex, pingtex[1][i], r_nulltex, false); + qglViewport (0, 0, texwidth[i], texheight[i]); + R2D_ScalePic(0, vid.height, vid.width, -(int)vid.height, bloomblur); + } + for (i = 0; i < MAXLEVELS; i++) + { + r_worldentity.glowmod[0] = 0; + r_worldentity.glowmod[1] = 1.2 / texheight[i]; + GLBE_RenderToTexture(pingtex[1][i], r_nulltex, pingtex[0][i], r_nulltex, false); + qglViewport (0, 0, texwidth[i], texheight[i]); + R2D_ScalePic(0, vid.height, vid.width, -(int)vid.height, bloomblur); + } + + GL_Set2D(false); + + /*combine them onto the screen*/ + GLBE_RenderToTexture(scrtex, r_nulltex, r_nulltex, r_nulltex, false); + R2D_ScalePic(r_refdef.vrect.x, r_refdef.vrect.y + r_refdef.vrect.height, r_refdef.vrect.width, -r_refdef.vrect.height, bloomfinal); +} +void R_InitBloomTextures(void) +{ + bloomfilter = NULL; + bloomblur = NULL; + bloomfinal = NULL; + scrwidth = 0, scrheight = 0; + + if (!gl_config.ext_framebuffer_objects) + return; + +} + +#elif defined(GLQUAKE) #include "glquake.h" /* diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index ab02beb20..bf6131909 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -191,7 +191,8 @@ static gltexture_t *GL_AllocNewGLTexture(char *ident, int w, int h) qglGenTextures(1, &glt->texnum.num); - Hash_Add(&gltexturetable, glt->identifier, glt, (bucket_t*)(glt+1)); + if (*glt->identifier) + Hash_Add(&gltexturetable, glt->identifier, glt, (bucket_t*)(glt+1)); return glt; } @@ -456,7 +457,7 @@ TRACE(("dbg: GLDraw_ReInit: Allocating upload buffers\n")); GL_BeginRendering (); TRACE(("dbg: GLDraw_ReInit: SCR_DrawLoading\n")); - GL_Set2D(); + GL_Set2D(false); qglClear(GL_COLOR_BUFFER_BIT); { @@ -539,7 +540,7 @@ GL_Set2D Setup as if the screen was 320*200 ================ */ -void GL_Set2D (void) +void GL_Set2D (qboolean flipped) { extern cvar_t gl_screenangle; float rad, ang; @@ -563,7 +564,10 @@ void GL_Set2D (void) } else { - Matrix4x4_CM_Orthographic(r_refdef.m_projection, 0, vid.width, vid.height, 0, -99999, 99999); + if (flipped) + Matrix4x4_CM_Orthographic(r_refdef.m_projection, 0, vid.width, 0, vid.height, -99999, 99999); + else + Matrix4x4_CM_Orthographic(r_refdef.m_projection, 0, vid.width, vid.height, 0, -99999, 99999); Matrix4x4_Identity(r_refdef.m_view); } r_refdef.time = realtime; diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index bf5513967..6d30b0e71 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -154,6 +154,7 @@ static const char *imgs[] = #define INVALIDPLANE ((1<<(8*sizeof(PLANEIDXTYPE)))-1) #define BITMAPPLANE ((1<<(8*sizeof(PLANEIDXTYPE)))-2) #define DEFAULTPLANE ((1<<(8*sizeof(PLANEIDXTYPE)))-3) +#define SINGLEPLANE ((1<<(8*sizeof(PLANEIDXTYPE)))-4) #define PLANEWIDTH (1<<8) #define PLANEHEIGHT PLANEWIDTH @@ -851,6 +852,46 @@ static texid_t Font_LoadDefaultConchars(void) Sys_Error("Unable to load any conchars\n"); } +typedef struct +{ + short width; + short height; + short leftoffset; // pixels to the left of origin + short topoffset; // pixels below the origin + int columnofs[1]; +} doompatch_t; +typedef struct +{ + unsigned char topdelta; // -1 is the last post in a column + unsigned char length; // length data bytes follows +} doomcolumn_t; +void Doom_ExpandPatch(doompatch_t *p, unsigned char *b, int stride) +{ + doomcolumn_t *col; + unsigned char *src, *dst; + int x, y; + for (x = 0; x < p->width; x++) + { + col = (doomcolumn_t *)((unsigned char *)p + p->columnofs[x]); + while(col->topdelta != 0xff) + { + //exploit protection + if (col->length + col->topdelta > p->height) + break; + + src = (unsigned char *)col + 3; /*why 3? why not, I suppose*/ + dst = b + stride*col->topdelta; + for (y = 0; y < col->length; y++) + { + *dst = *src++; + dst += stride; + } + col = (doomcolumn_t *)((unsigned char*)col + col->length + 4); + } + b++; + } +} + //creates a new font object from the given file, with each text row with the given height. //width is implicit and scales with height and choice of font. struct font_s *Font_LoadFont(int height, char *fontfilename) @@ -861,6 +902,70 @@ struct font_s *Font_LoadFont(int height, char *fontfilename) f = Z_Malloc(sizeof(*f)); f->charheight = height; +#ifdef DOOMWADS + if (!*fontfilename) + { + unsigned char buf[PLANEWIDTH*PLANEHEIGHT]; + int i; + int x=0,y=0,h=0; + doompatch_t *dp; + + memset(buf, 0, sizeof(buf)); + + for (i = '!'; i <= '_'; i++) + { + dp = NULL; + FS_LoadFile(va("wad/stcfn%.3d", i), &dp); + if (!dp) + break; + + /*make sure it can fit*/ + if (x + dp->width > PLANEWIDTH) + { + x = 0; + y += h; + h = 0; + } + + f->chars[i].advance = dp->width; /*this is how much line space the char takes*/ + f->chars[i].left = -dp->leftoffset; + f->chars[i].top = -dp->topoffset; + f->chars[i].nextchar = 0; + f->chars[i].pad = 0; + f->chars[i].texplane = SINGLEPLANE; + + f->chars[i].bmx = x; + f->chars[i].bmy = y; + f->chars[i].bmh = dp->height; + f->chars[i].bmw = dp->width; + + Doom_ExpandPatch(dp, &buf[y*PLANEWIDTH + x], PLANEWIDTH); + + x += dp->width; + if (dp->height > h) + { + h = dp->height; + if (h > f->charheight) + f->charheight = h; + } + + + FS_FreeFile(dp); + } + + /*if all loaded okay, replicate the chars to the quake-compat range (both white+red chars)*/ + if (i == '_'+1) + { + f->chars[' '].advance = 8; + f->singletexture = R_LoadTexture8("doomfont", PLANEWIDTH, PLANEHEIGHT, buf, 0, true); + for (i = 0xe000; i <= 0xe0ff; i++) + { + f->chars[i] = f->chars[toupper(i&0x7f)]; + } + return f; + } + } +#endif if (!strcmp(fontfilename, "gfx/tinyfont")) { unsigned int *img; @@ -1215,25 +1320,36 @@ int Font_DrawChar(int px, int py, unsigned int charcode) s1 = (float)(c->bmx+c->bmw)/PLANEWIDTH; t1 = (float)(c->bmy+c->bmh)/PLANEWIDTH; - if (c->texplane >= DEFAULTPLANE) + switch(c->texplane) { + case DEFAULTPLANE: sx = ((px+c->left)*(int)vid.width) / (float)vid.rotpixelwidth; sy = ((py+c->top)*(int)vid.height) / (float)vid.rotpixelheight; sw = ((curfont->charheight)*vid.width) / (float)vid.rotpixelwidth; sh = ((curfont->charheight)*vid.height) / (float)vid.rotpixelheight; - - if (c->texplane == DEFAULTPLANE) - v = Font_BeginChar(fontplanes.defaultfont); - else - v = Font_BeginChar(curfont->singletexture); - } - else - { + v = Font_BeginChar(fontplanes.defaultfont); + break; + case BITMAPPLANE: + sx = ((px+c->left)*(int)vid.width) / (float)vid.rotpixelwidth; + sy = ((py+c->top)*(int)vid.height) / (float)vid.rotpixelheight; + sw = ((curfont->charheight)*vid.width) / (float)vid.rotpixelwidth; + sh = ((curfont->charheight)*vid.height) / (float)vid.rotpixelheight; + v = Font_BeginChar(curfont->singletexture); + break; + case SINGLEPLANE: + sx = ((px+c->left)*(int)vid.width) / (float)vid.rotpixelwidth; + sy = ((py+c->top)*(int)vid.height) / (float)vid.rotpixelheight; + sw = ((c->bmw)*vid.width) / (float)vid.rotpixelwidth; + sh = ((c->bmh)*vid.height) / (float)vid.rotpixelheight; + v = Font_BeginChar(curfont->singletexture); + break; + default: sx = ((px+c->left)*(int)vid.width) / (float)vid.rotpixelwidth; sy = ((py+c->top)*(int)vid.height) / (float)vid.rotpixelheight; sw = ((c->bmw)*vid.width) / (float)vid.rotpixelwidth; sh = ((c->bmh)*vid.height) / (float)vid.rotpixelheight; v = Font_BeginChar(fontplanes.texnum[c->texplane]); + break; } font_texcoord[v+0][0] = s0; diff --git a/engine/gl/gl_heightmap.c b/engine/gl/gl_heightmap.c index 91d7cc876..9be1975eb 100644 --- a/engine/gl/gl_heightmap.c +++ b/engine/gl/gl_heightmap.c @@ -528,7 +528,7 @@ Heightmap_Trace Traces a line through a heightmap, sampling the terrain at various different positions. This is inprecise, only supports points (or vertical lines), and can often travel though sticky out bits of terrain. */ -qboolean Heightmap_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, trace_t *trace) +qboolean Heightmap_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int contentmask, trace_t *trace) { vec3_t org; vec3_t dir; @@ -589,10 +589,6 @@ qboolean Heightmap_Trace(model_t *model, int forcehullnum, int frame, vec3_t axi return trace->fraction != 1; } -qboolean Heightmap_NativeTrace(struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, unsigned int against, struct trace_s *trace) -{ - return Heightmap_Trace(model, hulloverride, frame, axis, p1, p2, mins, maxs, trace); -} #endif unsigned int Heightmap_FatPVS (model_t *mod, vec3_t org, qbyte *pvsbuffer, unsigned int pvssize, qboolean add) @@ -942,11 +938,10 @@ qboolean GL_LoadHeightmapModel (model_t *mod, void *buffer) } } - mod->funcs.Trace = Heightmap_Trace; + mod->funcs.NativeTrace = Heightmap_Trace; mod->funcs.PointContents = Heightmap_PointContents; mod->funcs.NativeContents = Heightmap_NativeBoxContents; - mod->funcs.NativeTrace = Heightmap_NativeTrace; mod->funcs.LightPointValues = Heightmap_LightPointValues; mod->funcs.StainNode = Heightmap_StainNode; diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index 69a2218cd..9713e73f5 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -172,10 +172,9 @@ BRUSH MODELS */ typedef struct { - //deals with FTECONTENTS (assumes against solid) + //model is being purged from memory. void (*PurgeModel) (struct model_s *mod); - qboolean (*Trace) (struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, struct trace_s *trace); unsigned int (*PointContents) (struct model_s *model, vec3_t axis[3], vec3_t p); unsigned int (*BoxContents) (struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs); @@ -515,7 +514,7 @@ int Q1BSP_ClipDecal(vec3_t center, vec3_t normal, vec3_t tangent1, vec3_t tangen void Q1BSP_MarkLights (dlight_t *light, int bit, mnode_t *node); void GLQ1BSP_LightPointValues(struct model_s *model, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir); -qboolean Q1BSP_Trace(struct model_s *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, struct trace_s *trace); +qboolean Q1BSP_Trace(struct model_s *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int hitcontentsmask, struct trace_s *trace); qboolean Q1BSP_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, struct trace_s *trace); unsigned int Q1BSP_FatPVS (struct model_s *mod, vec3_t org, qbyte *pvsbuffer, unsigned int buffersize, qboolean add); qboolean Q1BSP_EdictInFatPVS(struct model_s *mod, struct pvscache_s *ent, qbyte *pvs); diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index 26a763b14..dd3a8be3d 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -1145,7 +1145,7 @@ void GLR_RenderView (void) // Con_Printf ("%3i ms %4i wpoly %4i epoly\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys); } - if (qglGetError()) + while (qglGetError()) Con_Printf("GL Error drawing scene\n"); if (r_refdef.flags & Q2RDF_NOWORLDMODEL) @@ -1160,7 +1160,7 @@ void GLR_RenderView (void) { if (scenepp_waterwarp) { - GL_Set2D(); + GL_Set2D(false); R2D_ScalePic(0, 0, vid.width, vid.height, scenepp_waterwarp); } } @@ -1175,7 +1175,7 @@ void GLR_RenderView (void) shader_t *postproc = R_RegisterCustom(r_postprocshader.string, NULL, NULL); if (postproc) { - GL_Set2D(); + GL_Set2D(false); R2D_ScalePic(0, 0, vid.width, vid.height, postproc); } } diff --git a/engine/gl/gl_rmisc.c b/engine/gl/gl_rmisc.c index 5705c6712..2467b0d84 100644 --- a/engine/gl/gl_rmisc.c +++ b/engine/gl/gl_rmisc.c @@ -500,6 +500,7 @@ void GLR_NewMap (void) AngleVectors(r_worldentity.angles, r_worldentity.axis[0], r_worldentity.axis[1], r_worldentity.axis[2]); VectorInverse(r_worldentity.axis[1]); r_worldentity.model = cl.worldmodel; + Vector4Set(r_worldentity.shaderRGBAf, 1, 1, 1, 1); COM_StripExtension(COM_SkipPath(cl.worldmodel->name), namebuf, sizeof(namebuf)); diff --git a/engine/gl/gl_screen.c b/engine/gl/gl_screen.c index 25433900c..e6ccd2430 100644 --- a/engine/gl/gl_screen.c +++ b/engine/gl/gl_screen.c @@ -174,7 +174,7 @@ void GLSCR_UpdateScreen (void) else GL_DoSwap(); - GL_Set2D (); + GL_Set2D (false); if (!noworld) { diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 1f309245c..da6833c2e 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -43,6 +43,7 @@ static qboolean shader_rescan_needed; //cvars that affect shader generation cvar_t r_vertexlight = CVARFD("r_vertexlight", "0", CVAR_SHADERSYSTEM, "Hack loaded shaders to remove detail pass and lightmap sampling for faster rendering."); +extern cvar_t r_glsl_offsetmapping_reliefmapping; extern cvar_t r_deluxemapping; extern cvar_t r_fastturb, r_fastsky, r_skyboxname; extern cvar_t r_drawflat; @@ -804,7 +805,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip "#define FOG\n", NULL }; - char *permutationdefines[sizeof(permutationname)/sizeof(permutationname[0]) + 64]; + char *permutationdefines[sizeof(permutationname)/sizeof(permutationname[0]) + 64 + 1]; unsigned int nopermutation = ~0u; int nummodifiers; int p, n, pn; @@ -813,6 +814,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip char *cvarnames[64]; int cvartypes[64]; int cvarcount = 0; + qboolean onefailed = false; cvarnames[cvarcount] = NULL; @@ -891,36 +893,45 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip end = strchr(start, '#'); if (!end) end = start + strlen(start); - permutationdefines[nummodifiers] = malloc(10 + end - start); - memcpy(permutationdefines[nummodifiers], "#define ", 8); - memcpy(permutationdefines[nummodifiers]+8, start, end - start); - memcpy(permutationdefines[nummodifiers]+8+(end-start), "\n", 2); + if (nummodifiers < 64) + { + permutationdefines[nummodifiers] = malloc(10 + end - start); + memcpy(permutationdefines[nummodifiers], "#define ", 8); + memcpy(permutationdefines[nummodifiers]+8, start, end - start); + memcpy(permutationdefines[nummodifiers]+8+(end-start), "\n", 2); - for (start = permutationdefines[nummodifiers]+8; *start; start++) - *start = toupper(*start); - - nummodifiers++; + for (start = permutationdefines[nummodifiers]+8; *start; start++) + *start = toupper(*start); + nummodifiers++; + permutationdefines[nummodifiers] = NULL; + } } + for (p = 0; p < PERMUTATIONS; p++) { + if (nopermutation & p) + { + continue; + } + pn = nummodifiers; + for (n = 0; permutationname[n]; n++) + { + if (p & (1u<handle[p].glsl = GLSlang_CreateProgram(name, (((p & PERMUTATION_SKELETAL) && ver < 120)?120:ver), permutationdefines, script, script); + prog->handle[p].glsl = GLSlang_CreateProgram(name, (((p & PERMUTATION_SKELETAL) && ver < 120)?120:ver), permutationdefines, script, script, onefailed); + if (!prog->handle[p].glsl) + onefailed = true; if (!p && !prog->handle[p].glsl) break; } @@ -928,17 +939,6 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip #ifdef D3DQUAKE else if (qrenderer == QR_DIRECT3D) { - if (nopermutation & p) - { - continue; - } - pn = nummodifiers; - for (n = 0; permutationname[n]; n++) - { - if (p & (1u<passes, i = 0; i < s->numpasses; i++, pass++) + { + if ((pass->texgen == T_GEN_ANIMMAP || pass->texgen == T_GEN_SINGLEMAP) && !TEXVALID(s->defaulttextures.base)) + s->defaulttextures.base = pass->anim_frames[0]; + if (pass->texgen == T_GEN_VIDEOMAP && pass->cin && !TEXVALID(s->defaulttextures.base)) + s->defaulttextures.base = Media_UpdateForShader(pass->cin); + + } + pass = s->passes; for (i = 0; i < s->numpasses; i++, pass++) { @@ -4698,38 +4695,57 @@ void Shader_UpdateRegistration (void) void R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader) { - /*dlights/realtime lighting needs some stuff*/ - if (!TEXVALID(tn->base)) + if (!TEXVALID(shader->defaulttextures.base)) { - tn->base = R_LoadHiResTexture(shader->name, NULL, IF_NOALPHA); - } - if (TEXVALID(tn->base)) - shader->flags &= ~SHADER_NOIMAGE; + /*dlights/realtime lighting needs some stuff*/ + if (!TEXVALID(tn->base)) + { + tn->base = R_LoadHiResTexture(shader->name, NULL, IF_NOALPHA); + } + if (TEXVALID(tn->base)) + shader->flags &= ~SHADER_NOIMAGE; - if (r_loadbumpmapping) - { - if (!TEXVALID(tn->bump)) - tn->bump = R_LoadHiResTexture(va("%s_norm", shader->name), NULL, IF_NOALPHA); - if (!TEXVALID(tn->bump)) - tn->bump = R_LoadHiResTexture(va("%s_bump", shader->name), NULL, IF_NOALPHA); - if (!TEXVALID(tn->bump)) - tn->bump = R_LoadHiResTexture(va("normalmaps/%s", shader->name), NULL, IF_NOALPHA); + TEXASSIGN(shader->defaulttextures.base, tn->base); } - if (shader->flags & SHADER_HASTOPBOTTOM) + if (!TEXVALID(shader->defaulttextures.bump)) { - if (!TEXVALID(tn->loweroverlay)) - tn->loweroverlay = R_LoadHiResTexture(va("%s_pants", shader->name), NULL, 0); /*how rude*/ - if (!TEXVALID(tn->upperoverlay)) - tn->upperoverlay = R_LoadHiResTexture(va("%s_shirt", shader->name), NULL, 0); + if (r_loadbumpmapping) + { + if (!TEXVALID(tn->bump)) + tn->bump = R_LoadHiResTexture(va("%s_norm", shader->name), NULL, IF_NOALPHA); + if (!TEXVALID(tn->bump)) + tn->bump = R_LoadHiResTexture(va("%s_bump", shader->name), NULL, IF_NOALPHA); + if (!TEXVALID(tn->bump)) + tn->bump = R_LoadHiResTexture(va("normalmaps/%s", shader->name), NULL, IF_NOALPHA); + } + TEXASSIGN(shader->defaulttextures.bump, tn->bump); } - TEXASSIGN(shader->defaulttextures.base, tn->base); - TEXASSIGN(shader->defaulttextures.specular, tn->specular); - TEXASSIGN(shader->defaulttextures.fullbright, tn->fullbright); - TEXASSIGN(shader->defaulttextures.bump, tn->bump); - TEXASSIGN(shader->defaulttextures.loweroverlay, tn->loweroverlay); - TEXASSIGN(shader->defaulttextures.upperoverlay, tn->upperoverlay); + if (!TEXVALID(shader->defaulttextures.loweroverlay)) + { + if (shader->flags & SHADER_HASTOPBOTTOM) + { + if (!TEXVALID(tn->loweroverlay)) + tn->loweroverlay = R_LoadHiResTexture(va("%s_pants", shader->name), NULL, 0); /*how rude*/ + } + TEXASSIGN(shader->defaulttextures.loweroverlay, tn->loweroverlay); + } + + if (!TEXVALID(shader->defaulttextures.upperoverlay)) + { + if (shader->flags & SHADER_HASTOPBOTTOM) + { + if (!TEXVALID(tn->upperoverlay)) + tn->upperoverlay = R_LoadHiResTexture(va("%s_shirt", shader->name), NULL, 0); + } + TEXASSIGN(shader->defaulttextures.upperoverlay, tn->upperoverlay); + } + + if (!TEXVALID(shader->defaulttextures.specular)) + TEXASSIGN(shader->defaulttextures.specular, tn->specular); + if (!TEXVALID(shader->defaulttextures.fullbright)) + TEXASSIGN(shader->defaulttextures.fullbright, tn->fullbright); } void Shader_DefaultScript(char *shortname, shader_t *s, const void *args) diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index df1b5122f..0618dd84f 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -385,6 +385,29 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name), float ver) gl_config.nofixedfunc = false; } + gl_config.maxglslversion = 0; + if (gl_config.gles && gl_config.glversion >= 2) + gl_config.maxglslversion = 100; + else if (gl_config.glversion >= 2) + { +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C + const char *s = qglGetString (GL_SHADING_LANGUAGE_VERSION); + + if (s) + { + gl_config.maxglslversion = atoi(s) * 100; + while(*s >= '0' && *s <= '9') + s++; + if (*s == '.') + s++; + gl_config.maxglslversion += atoi(s); + } + else + gl_config.maxglslversion = 110; + } + else + gl_config.maxglslversion = 110; + //multitexture gl_mtexable = false; gl_mtexarbable = 0; @@ -828,6 +851,34 @@ static const char *glsl_hdrs[] = "#endif\n" "#endif\n" , + "sys/offsetmapping.h", + "uniform float cvar_r_glsl_offsetmapping_scale;\n" + "vec2 offsetmap(sampler2D normtex, vec2 base, vec3 eyevector)\n" + "{\n" + "#if defined(RELIEFMAPPING)\n" + "float i, f;\n" + "vec3 OffsetVector = vec3(normalize(eyevector.xyz).xy * cvar_r_glsl_offsetmapping_scale * vec2(1.0, -1.0), -1.0);\n" + "vec3 RT = vec3(vec2(base.xy"/* - OffsetVector.xy*OffsetMapping_Bias*/"), 1.0);\n" + "OffsetVector /= 10.0;\n" + "for(i = 1.0; i < 10.0; ++i)\n" + "RT += OffsetVector * step(texture2D(normtex, RT.xy).a, RT.z);\n" + "for(i = 0.0, f = 1.0; i < 5.0; ++i, f *= 0.5)\n" + "RT += OffsetVector * (step(texture2D(normtex, RT.xy).a, RT.z) * f - 0.5 * f);\n" + "return RT.xy;\n" + "#elif defined(OFFSETMAPPING)\n" + "vec2 OffsetVector = normalize(eyevector).xy * cvar_r_glsl_offsetmapping_scale * vec2(1.0, -1.0);\n" + "vec2 tc = base;\n" + "tc += OffsetVector;\n" + "OffsetVector *= 0.333;\n" + "tc -= OffsetVector * texture2D(normtex, tc).w;\n" + "tc -= OffsetVector * texture2D(normtex, tc).w;\n" + "tc -= OffsetVector * texture2D(normtex, tc).w;\n" + "return tc;\n" + "#else\n" + "return base;\n" + "#endif\n" + "}\n" + , NULL }; @@ -889,7 +940,7 @@ qboolean GLSlang_GenerateIncludes(int maxstrings, int *strings, const GLchar *pr // glslang helper api function definitions // type should be GL_FRAGMENT_SHADER_ARB or GL_VERTEX_SHADER_ARB -GLhandleARB GLSlang_CreateShader (char *name, int ver, char **precompilerconstants, const char *shadersource, GLenum shadertype) +GLhandleARB GLSlang_CreateShader (char *name, int ver, char **precompilerconstants, const char *shadersource, GLenum shadertype, qboolean silent) { GLhandleARB shader; GLint compiled; @@ -901,6 +952,10 @@ GLhandleARB GLSlang_CreateShader (char *name, int ver, char **precompilerconstan if (ver) { + /*required version not supported, don't even try*/ + if (ver > gl_config.maxglslversion) + return 0; + prstrings[strings] = va("#version %u\n", ver); length[strings] = strlen(prstrings[strings]); strings++; @@ -1011,31 +1066,34 @@ GLhandleARB GLSlang_CreateShader (char *name, int ver, char **precompilerconstan { qglGetShaderInfoLog_(shader, sizeof(str), NULL, str); qglDeleteShaderObject_(shader); - switch (shadertype) + if (!silent) { - case GL_FRAGMENT_SHADER_ARB: - Con_Printf("Fragment shader (%s) compilation error:\n----------\n%s----------\n", name, str); - break; - case GL_VERTEX_SHADER_ARB: - Con_Printf("Vertex shader (%s) compilation error:\n----------\n%s----------\n", name, str); - break; - default: - Con_Printf("Shader_CreateShader: This shouldn't happen ever\n"); - break; - } - Con_DPrintf("Shader \"%s\" source:\n", name); - for (i = 0; i < strings; i++) - { - int j; - if (length[i] < 0) - Con_DPrintf("%s", prstrings[i]); - else + switch (shadertype) { - for (j = 0; j < length[i]; j++) - Con_DPrintf("%c", prstrings[i][j]); + case GL_FRAGMENT_SHADER_ARB: + Con_Printf("Fragment shader (%s) compilation error:\n----------\n%s----------\n", name, str); + break; + case GL_VERTEX_SHADER_ARB: + Con_Printf("Vertex shader (%s) compilation error:\n----------\n%s----------\n", name, str); + break; + default: + Con_Printf("Shader_CreateShader: This shouldn't happen ever\n"); + break; } + Con_DPrintf("Shader \"%s\" source:\n", name); + for (i = 0; i < strings; i++) + { + int j; + if (length[i] < 0) + Con_DPrintf("%s", prstrings[i]); + else + { + for (j = 0; j < length[i]; j++) + Con_DPrintf("%c", prstrings[i][j]); + } + } + Con_DPrintf("%s\n", str); } - Con_DPrintf("%s\n", str); return 0; } @@ -1058,7 +1116,7 @@ GLhandleARB GLSlang_CreateShader (char *name, int ver, char **precompilerconstan return shader; } -GLhandleARB GLSlang_CreateProgramObject (GLhandleARB vert, GLhandleARB frag) +GLhandleARB GLSlang_CreateProgramObject (GLhandleARB vert, GLhandleARB frag, qboolean silent) { GLhandleARB program; GLint linked; @@ -1084,8 +1142,11 @@ GLhandleARB GLSlang_CreateProgramObject (GLhandleARB vert, GLhandleARB frag) if(!linked) { - qglGetProgramInfoLog_(program, sizeof(str), NULL, str); - Con_Printf("Program link error: %s\n", str); + if (!silent) + { + qglGetProgramInfoLog_(program, sizeof(str), NULL, str); + Con_Printf("Program link error: %s\n", str); + } qglDeleteProgramObject_(program); @@ -1094,7 +1155,7 @@ GLhandleARB GLSlang_CreateProgramObject (GLhandleARB vert, GLhandleARB frag) return program; } -GLhandleARB GLSlang_CreateProgram(char *name, int ver, char **precompilerconstants, char *vert, char *frag) +GLhandleARB GLSlang_CreateProgram(char *name, int ver, char **precompilerconstants, char *vert, char *frag, qboolean silent) { GLhandleARB handle; GLhandleARB vs; @@ -1107,13 +1168,13 @@ GLhandleARB GLSlang_CreateProgram(char *name, int ver, char **precompilerconstan if (!precompilerconstants) precompilerconstants = &nullconstants; - vs = GLSlang_CreateShader(name, ver, precompilerconstants, vert, GL_VERTEX_SHADER_ARB); - fs = GLSlang_CreateShader(name, ver, precompilerconstants, frag, GL_FRAGMENT_SHADER_ARB); + vs = GLSlang_CreateShader(name, ver, precompilerconstants, vert, GL_VERTEX_SHADER_ARB, silent); + fs = GLSlang_CreateShader(name, ver, precompilerconstants, frag, GL_FRAGMENT_SHADER_ARB, silent); if (!vs || !fs) handle = 0; else - handle = GLSlang_CreateProgramObject(vs, fs); + handle = GLSlang_CreateProgramObject(vs, fs, silent); //delete ignores 0s. qglDeleteShaderObject_(vs); qglDeleteShaderObject_(fs); diff --git a/engine/gl/gl_viddroid.c b/engine/gl/gl_viddroid.c index d2f54a737..517f59eb9 100644 --- a/engine/gl/gl_viddroid.c +++ b/engine/gl/gl_viddroid.c @@ -89,6 +89,10 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) Cons: GL_EndRendering call will not swap buffers. Buffers will be swapped on return to java. */ + if (gles2) + Sys_Printf("Loading GLES2 driver\n"); + else + Sys_Printf("Loading GLES1 driver\n"); sys_gl_module = Sys_LoadLibrary(gles2?"libGLESv2.so":"libGLESv1_CM.so", NULL); if (!sys_gl_module) { @@ -96,7 +100,7 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) return false; } - GLVID_SetPalette (palette); + GLVID_SetPalette (palette); GL_Init(GLES_GetSymbol); vid.recalc_refdef = 1; return true; diff --git a/engine/gl/glmod_doom.c b/engine/gl/glmod_doom.c index 7fea8452b..cbbd0b5c2 100644 --- a/engine/gl/glmod_doom.c +++ b/engine/gl/glmod_doom.c @@ -1,16 +1,11 @@ #include "quakedef.h" #ifdef MAP_DOOM -#ifdef GLQUAKE #include "glquake.h" #include "shader.h" -#include "doommap.h" - int SignbitsForPlane (mplane_t *out); int PlaneTypeForNormal ( vec3_t normal ); -#undef strncpy - //coded from file specifications provided by: //Matthew S Fell (msfell@aol.com) //Unofficial Doom Specs @@ -18,15 +13,6 @@ int PlaneTypeForNormal ( vec3_t normal ); //(aol suck) void Doom_SetModelFunc(model_t *mod); - -//skill/dm is appears in rather than quake's excuded in. -#define THING_EASY 1 -#define THING_MEDIUM 2 -#define THING_HARD 4 -#define THING_DEAF 8 -#define THING_DEATHMATCH 16 -//other bits are ignored - int Doom_SectorNearPoint(vec3_t p); //assumptions: @@ -38,6 +24,167 @@ int Doom_SectorNearPoint(vec3_t p); +enum { + THING_PLAYER = 1, + THING_PLAYER2 = 2, + THING_PLAYER3 = 3, + THING_PLAYER4 = 4, + THING_DMSPAWN = 11, + +//we need to balance weapons according to ammo types. + THING_WCHAINSAW = 2005, //-> quad + THING_WSHOTGUN1 = 2001, //-> ng + THING_WSHOTGUN2 = 82, //-> sng + THING_WCHAINGUN = 2002, //-> ssg + THING_WROCKETL = 2003, //-> lightning + THING_WPLASMA = 2004, //-> grenade + THING_WBFG = 2006 //-> rocket +} THING_TYPES; + +//thing flags +//skill/dm is appears in rather than quake's excuded in. +#define THING_EASY 1 +#define THING_MEDIUM 2 +#define THING_HARD 4 +#define THING_DEAF 8 +#define THING_DEATHMATCH 16 +//other bits are ignored + + + +typedef struct { + short xpos; + short ypos; + short angle; + unsigned short type; + unsigned short flags; +} dthing_t; + +typedef struct { + short xpos; + short ypos; +} ddoomvertex_t; + +typedef struct { + float xpos; + float ypos; +} mdoomvertex_t; + +typedef struct { + unsigned short vert[2]; + unsigned short flags; + short types; + short tag; + unsigned short sidedef[2]; //(0xffff is none for sidedef[1]) +} dlinedef_t; +#define LINEDEF_IMPASSABLE 1 +#define LINEDEF_BLOCKMONSTERS 2 +#define LINEDEF_TWOSIDED 4 +#define LINEDEF_UPPERUNPEGGED 8 +#define LINEDEF_LOWERUNPEGGED 16 +#define LINEDEF_SECRET 32 //seen as singlesided on automap, does nothing else. +#define LINEDEF_BLOCKSOUND 64 +#define LINEDEF_NOTONMAP 128 //doesn't appear on automap. +#define LINEDEF_STARTONMAP 256 +//others are ignored. + +typedef struct { + short texx; + short texy; + char uppertex[8]; + char lowertex[8]; + char middletex[8]; + unsigned short sector; +} dsidedef_t; +typedef struct { + float texx; + float texy; + int uppertex; + int lowertex; + int middletex; + unsigned short sector; +} msidedef_t; + +typedef struct { //figure out which linedef to use and throw the rest away. + unsigned short vert[2]; + short angle; + unsigned short linedef; + short direction; + short offset; +} dseg_t; + +typedef struct { + unsigned short vert[2]; + unsigned short linedef; + short direction; + unsigned short Partner; //the one on the other side of the owner's linedef +} dgl_seg1_t; + +typedef struct { + unsigned int vert[2]; + unsigned short linedef; + short direction; + unsigned int Partner; //the one on the other side of the owner's linedef +} dgl_seg3_t; + +typedef struct { + unsigned short segcount; + unsigned short first; +} dssector_t; + +typedef struct { + short x; + short y; + short dx; + short dy; + short y1upper; + short y1lower; + short x1lower; + short x1upper; + short y2upper; + short y2lower; + short x2lower; + short x2upper; + unsigned short node1; + unsigned short node2; +} ddoomnode_t; +#define NODE_IS_SSECTOR 0x8000 + +typedef struct { + short floorheight; + short ceilingheight; + char floortexture[8]; + char ceilingtexture[8]; + short lightlevel; + short specialtype; + short tag; +} dsector_t; + +typedef struct { + int visframe; + shader_t *floortex; + shader_t *ceilingtex; + + short floorheight; + short ceilingheight; + + qbyte lightlev; + qbyte pad; + int numflattris; + short tag; + short specialtype; + + unsigned short *flats; +} msector_t; + + +typedef struct { + short xorg; + short yorg; + short columns; + short rows; +} blockmapheader_t; + ddoomnode_t *nodel; dssector_t *ssectorsl; dthing_t *thingsl; @@ -64,9 +211,459 @@ extern model_t *loadmodel; extern char loadname[]; -#ifdef _MSC_VER -//#pragma comment (lib, "../../../glbsp/glbsp-2.05/plugin/libglbsp.a") + +//////////////////////////////////////////////////////////////////////////////////////////// +//physics + +/*walk the bsp tree*/ +int Doom_SectorNearPoint(vec3_t p) +{ + ddoomnode_t *node; + plane_t *plane; + int num; + int seg; + float d; + num = nodec-1; + while (1) + { + if (num & NODE_IS_SSECTOR) + { + num -= NODE_IS_SSECTOR; + for (seg = ssectorsl[num].first; seg < ssectorsl[num].first + ssectorsl[num].segcount; seg++) + if (segsl[seg].linedef != 0xffff) + break; + + return sidedefsm[linedefsl[segsl[seg].linedef].sidedef[segsl[seg].direction]].sector; + } + + node = nodel + num; + plane = nodeplanes + num; + +// if (plane->type < 3) +// d = p[plane->type] - plane->dist; +// else + d = DotProduct (plane->normal, p) - plane->dist; + if (d < 0) + num = node->node2; + else + num = node->node1; + } + + return num; +} + +int Doom_PointContents(model_t *model, vec3_t axis[3], vec3_t p) +{ + int sec = Doom_SectorNearPoint(p); + if (p[2] < sectorm[sec].floorheight) + return FTECONTENTS_SOLID; + if (p[2] > sectorm[sec].ceilingheight) + return FTECONTENTS_SOLID; + return FTECONTENTS_EMPTY; +} + +qboolean Doom_Trace(model_t *model, int hulloverride, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int contentstype, trace_t *trace) +{ +#if 0 +#define TRACESTEP 16 + unsigned short *linedefs; + dlinedef_t *ld; + int bmi, obmi; + vec3_t delta; + int sec1 = Doom_SectorNearPoint(start); + vec3_t p1, pointonplane, ofs; + float d1, d2, c1, c2, planedist; + plane_t *lp; + mdoomvertex_t *v1, *v2; + int j; + float p2f; + + float clipfrac; +#define DIST_EPSILON (0.03125) + +// Con_Printf("%i\n", sec1); + + if (start[2] < sectorm[sec1].floorheight-mins[2]) //whoops, started outside... ? + { + trace->fraction = 0; + trace->allsolid = trace->startsolid = true; + trace->endpos[0] = start[0]; + trace->endpos[1] = start[1]; + trace->endpos[2] = start[2]; //yeah, we do mean this - startsolid +// if (IS_NAN(trace->endpos[2])) +// Con_Printf("Nanny\n"); + trace->plane.normal[0] = 0; + trace->plane.normal[1] = 0; + trace->plane.normal[2] = 1; + trace->plane.dist = sectorm[sec1].floorheight-mins[2]; + + return false; + } + if (start[2] > sectorm[sec1].ceilingheight-maxs[2]) //whoops, started outside... ? + { + trace->fraction = 0; + trace->allsolid = trace->startsolid = true; + trace->endpos[0] = start[0]; + trace->endpos[1] = start[1]; + trace->endpos[2] = start[2]; + trace->plane.normal[0] = 0; + trace->plane.normal[1] = 0; + trace->plane.normal[2] = -1; + trace->plane.dist = -(sectorm[sec1].ceilingheight-maxs[2]); + return false; + } + + obmi = -1; + VectorSubtract(end, start, delta); + p2f = Length(delta)+DIST_EPSILON; + if (IS_NAN(p2f) || p2f > 100000) + p2f = 100000; + VectorNormalize(delta); + + trace->endpos[0] = end[0]; + trace->endpos[1] = end[1]; + trace->endpos[2] = end[2]; + + trace->fraction = 1; + while(1) + { + bmi = ((int)p1[0] - blockmapl->xorg)/128 + (((int)p1[1] - blockmapl->yorg)/128)*blockmapl->columns; +// Con_Printf("%i of %i ", bmi, blockmapl->rows*blockmapl->columns); + if (bmi >= 0 && bmi < blockmapl->rows*blockmapl->columns) + if (bmi != obmi) + { +#if 1 + short dummy; + linedefs = &dummy; + for (dummy = 0; dummy < linedefsc; dummy++) +#else + for(linedefs = (short*)blockmapl + blockmapofs[bmi]+1; *linedefs != 0xffff; linedefs++) #endif + { + ld = linedefsl + *linedefs; + if (ld->sidedef[1] != 0xffff) + { + if (sectorm[sidedefsm[ld->sidedef[0]].sector].floorheight == sectorm[sidedefsm[ld->sidedef[1]].sector].floorheight && + sectorm[sidedefsm[ld->sidedef[0]].sector].ceilingheight == sectorm[sidedefsm[ld->sidedef[1]].sector].ceilingheight) + continue; + } + + lp = lineplanes + *linedefs; + + if (1) + { //figure out how far to move the plane out by + for (j=0 ; j<2 ; j++) + { + if (lp->normal[j] < 0) + ofs[j] = maxs[j]; + else + ofs[j] = mins[j]; + } + ofs[2] = 0; + planedist = lp->dist - DotProduct (ofs, lp->normal); + } + else + planedist = lp->dist; + + d1 = DotProduct(lp->normal, start) - (planedist); + d2 = DotProduct(lp->normal, end) - (planedist); + if (d1 > 0 && d2 > 0) + continue; //both points on the front side. + if (d1 < 0) //start on back side + { + if (ld->sidedef[1] != 0xffff) //two sided (optimisation) + { + planedist = -planedist+lp->dist; + if (/*d1 < planedist*-1 &&*/ d1 > planedist*2) + { //right, we managed to end up just on the other side of a wall's plane. + v1 = &vertexesl[ld->vert[0]]; + v2 = &vertexesl[ld->vert[1]]; + if (!(d1 - d2)) + continue; + if (d1<0) //back to front. + c1 = (d1+DIST_EPSILON) / (d1 - d2); + else + c1 = (d1-DIST_EPSILON) / (d1 - d2); + c2 = 1-c1; + pointonplane[0] = start[0]*c2 + p2[0]*c1; +/* if (pointonplane[0] > v1->xpos+DIST_EPSILON*2+hull->clip_maxs[0] && pointonplane[0] > v2->xpos+DIST_EPSILON*2+hull->clip_maxs[0]) + continue; + if (pointonplane[0] < v1->xpos-DIST_EPSILON*2+hull->clip_mins[0] && pointonplane[0] < v2->xpos-DIST_EPSILON*2+hull->clip_mins[0]) + continue; +*/ pointonplane[1] = start[1]*c2 + p2[1]*c1; +/* if (pointonplane[1] > v1->ypos+DIST_EPSILON*2+hull->clip_maxs[1] && pointonplane[1] > v2->ypos+DIST_EPSILON*2+hull->clip_maxs[1]) + continue; + if (pointonplane[1] < v1->ypos-DIST_EPSILON*2+hull->clip_mins[1] && pointonplane[1] < v2->ypos-DIST_EPSILON*2+hull->clip_mins[1]) + continue; +*/ + pointonplane[2] = start[2]*c2 + p2[2]*c1; + + Con_Printf("Started in wall\n"); + j = sidedefsm[ld->sidedef[d1 < planedist]].sector; + //yup, we are in the thing + //prevent ourselves from entering the back-sector's floor/ceiling + if (pointonplane[2] < sectorm[j].floorheight-hull->clip_mins[2]) //whoops, started outside... ? + { + Con_Printf("Started in floor\n"); + trace->allsolid = trace->startsolid = false; + trace->endpos[2] = sectorm[j].floorheight-hull->clip_mins[2]; + trace->fraction = fabs(trace->endpos[2] - start[2]) / fabs(p2[2] - start[2]); + trace->endpos[0] = start[0]+delta[0]*trace->fraction*p2f; + trace->endpos[1] = start[1]+delta[1]*trace->fraction*p2f; + // if (IS_NAN(trace->endpos[2])) + // Con_Printf("Nanny\n"); + trace->plane.normal[0] = 0; + trace->plane.normal[1] = 0; + trace->plane.normal[2] = 1; + trace->plane.dist = sectorm[j].floorheight-hull->clip_mins[2]; + + continue; + } + if (pointonplane[2] > sectorm[j].ceilingheight-hull->clip_maxs[2]) //whoops, started outside... ? + { + Con_Printf("Started in ceiling\n"); + trace->allsolid = trace->startsolid = false; + trace->endpos[0] = pointonplane[0]; + trace->endpos[1] = pointonplane[1]; + trace->endpos[2] = sectorm[j].ceilingheight-hull->clip_maxs[2]; + trace->fraction = fabs(trace->endpos[2] - start[2]) / fabs(p2[2] - start[2]); + trace->plane.normal[0] = 0; + trace->plane.normal[1] = 0; + trace->plane.normal[2] = -1; + trace->plane.dist = -(sectorm[j].ceilingheight-hull->clip_maxs[2]); + continue; + } + } + } + if (d2 < 0) + continue; //both points on the reverse side. + } + + //line crosses plane. + + v1 = &vertexesl[ld->vert[0]]; + v2 = &vertexesl[ld->vert[1]]; + + if (d1<0) //back to front. + { + if (ld->sidedef[1] == 0xffff) + continue; //hack to allow them to pass + c1 = (d1+DIST_EPSILON) / (d1 - d2); + } + else + c1 = (d1-DIST_EPSILON) / (d1 - d2); + c2 = 1-c1; + pointonplane[0] = start[0]*c2 + p2[0]*c1; + if (pointonplane[0] > v1->xpos+DIST_EPSILON*2+hull->clip_maxs[0] && pointonplane[0] > v2->xpos+DIST_EPSILON*2+hull->clip_maxs[0]) + continue; + if (pointonplane[0] < v1->xpos-DIST_EPSILON*2+hull->clip_mins[0] && pointonplane[0] < v2->xpos-DIST_EPSILON*2+hull->clip_mins[0]) + continue; + pointonplane[1] = start[1]*c2 + p2[1]*c1; + if (pointonplane[1] > v1->ypos+DIST_EPSILON*2+hull->clip_maxs[1] && pointonplane[1] > v2->ypos+DIST_EPSILON*2+hull->clip_maxs[1]) + continue; + if (pointonplane[1] < v1->ypos-DIST_EPSILON*2+hull->clip_mins[1] && pointonplane[1] < v2->ypos-DIST_EPSILON*2+hull->clip_mins[1]) + continue; + pointonplane[2] = start[2]*c2 + p2[2]*c1; + + if (ld->flags & LINEDEF_IMPASSABLE || ld->sidedef[1] == 0xffff) //unconditionally unpassable. + { //unconditionally clipped. + } + else + { //ensure that the side we are passing on to passes the clip (no ceiling/floor clips happened first) + msector_t *sec2; + + if (d1<0) + sec2 = §orm[sidedefsm[ld->sidedef[1]].sector]; + else + sec2 = §orm[sidedefsm[ld->sidedef[0]].sector]; + + if (pointonplane[2] < sec2->floorheight-hull->clip_mins[2]) + { //hit the floor first. + c1 = fabs(sectorm[sec1].floorheight-hull->clip_mins[2] - start[2]); + c2 = fabs(p2[2] - start[2]); + if (!c2) + c1 = 1; + else + c1 = (c1-DIST_EPSILON) / c2; + if (trace->fraction > c1) + { +// Con_Printf("Hit floor\n"); + trace->fraction = c1; + trace->allsolid = trace->startsolid = true; + trace->endpos[0] = start[0] + trace->fraction*(p2[0]-start[0]); + trace->endpos[1] = start[1] + trace->fraction*(p2[1]-start[1]); + trace->endpos[2] = start[2] + trace->fraction*(p2[2]-start[2]); + trace->plane.normal[0] = 0; + trace->plane.normal[1] = 0; + trace->plane.normal[2] = 1; + trace->plane.dist = sectorm[sec1].floorheight-hull->clip_mins[2]; + } + continue; + } + + if (pointonplane[2] > sec2->ceilingheight-hull->clip_maxs[2]) + { //hit the floor first. + c1 = fabs((sectorm[sec1].ceilingheight-hull->clip_maxs[2]) - start[2]); + c2 = fabs(p2[2] - start[2]); + if (!c2) + c1 = 1; + else + c1 = (c1-DIST_EPSILON) / c2; + + + if (trace->fraction > c1) + { +// Con_Printf("Hit ceiling\n"); + trace->fraction = c1; + trace->allsolid = trace->startsolid = true; + trace->endpos[0] = start[0] + trace->fraction*(p2[0]-start[0]); + trace->endpos[1] = start[1] + trace->fraction*(p2[1]-start[1]); + trace->endpos[2] = start[2] + trace->fraction*(p2[2]-start[2]); + trace->plane.normal[0] = 0; + trace->plane.normal[1] = 0; + trace->plane.normal[2] = -1; + trace->plane.dist = -(sectorm[sec1].ceilingheight-hull->clip_maxs[2]); + } + continue; + } + + if (d1<0) + sec2 = §orm[sidedefsm[ld->sidedef[0]].sector]; + else + sec2 = §orm[sidedefsm[ld->sidedef[1]].sector]; + + if(sec2->ceilingheight == sec2->floorheight) + sec2->ceilingheight += 64; + + if (pointonplane[2] > sec2->floorheight-hull->clip_mins[2] && + pointonplane[2] < sec2->ceilingheight-hull->clip_maxs[2]) + { + Con_Printf("Two sided passed\n"); + continue; + } + +// Con_Printf("blocked by two sided line\n"); +// sec2->floorheight--; + } + + if (d1<0) //back to front. + c1 = (d1+DIST_EPSILON) / (d1 - d2); + else + c1 = (d1-DIST_EPSILON) / (d1 - d2); + + + clipfrac = c1; + + if (clipfrac < 0) + clipfrac = 0; + if (clipfrac > 1) + clipfrac = 1; + + if (trace->fraction > clipfrac) + { + trace->fraction = clipfrac; + VectorMA(pointonplane, 0, lp->normal, trace->endpos); + VectorMA(trace->endpos, -0.1, delta, trace->endpos); +// if (IS_NAN(trace->endpos[2])) +// Con_Printf("Buggy clipping\n"); + VectorCopy(lp->normal, trace->plane.normal); + trace->plane.dist = planedist; +// if (IS_NAN(trace->plane.normal[2])) +// Con_Printf("Buggy clipping\n"); + + if (clipfrac) + Con_Printf("Clip Wall %f\n", clipfrac); + } + } + + obmi = bmi; + } + + p1f += TRACESTEP; + if (p1f >= p2f) + break; + + VectorMA(p1, TRACESTEP, delta, p1); + } + +// VectorMA(start, p2f*trace->fraction, delta, p2); + + if (p2[2] != start[2]) + { + if (sec1 == Doom_SectorNearPoint(p2)) //special test. + { + if (p2[2] <= sectorm[sec1].floorheight-hull->clip_mins[2]) //whoops, started outside... ? + { + p1f = fabs(sectorm[sec1].floorheight-hull->clip_mins[2] - start[2]); + p2f = fabs(p2[2] - start[2]); + if (!p2f) + c1 = 1; + else + c1 = (p1f-DIST_EPSILON) / p2f; + if (trace->fraction > c1) + { + trace->fraction = c1; + trace->allsolid = trace->startsolid = false; + trace->endpos[0] = start[0] + trace->fraction*(p2[0]-start[0]); + trace->endpos[1] = start[1] + trace->fraction*(p2[1]-start[1]); + trace->endpos[2] = start[2] + trace->fraction*(p2[2]-start[2]); + trace->plane.normal[0] = 0; + trace->plane.normal[1] = 0; + trace->plane.normal[2] = 1; + trace->plane.dist = sectorm[sec1].floorheight-hull->clip_mins[2]; + } + +// if (IS_NAN(trace->endpos[2])) +// Con_Printf("Nanny\n"); + } + if (p2[2] >= sectorm[sec1].ceilingheight-hull->clip_maxs[2]) //whoops, started outside... ? + { + p1f = fabs(sectorm[sec1].ceilingheight-hull->clip_maxs[2] - start[2]); + p2f = fabs(p2[2] - start[2]); + if (!p2f) + c1 = 1; + else + c1 = (p1f-DIST_EPSILON) / p2f; + if (trace->fraction > c1) + { + trace->fraction = c1; + trace->allsolid = trace->startsolid = false; + trace->endpos[0] = start[0] + trace->fraction*(p2[0]-start[0]); + trace->endpos[1] = start[1] + trace->fraction*(p2[1]-start[1]); + trace->endpos[2] = start[2] + trace->fraction*(p2[2]-start[2]); + trace->plane.normal[0] = 0; + trace->plane.normal[1] = 0; + trace->plane.normal[2] = -1; + trace->plane.dist = -(sectorm[sec1].ceilingheight-hull->clip_maxs[2]); + } + +// if (IS_NAN(trace->endpos[2])) +// Con_Printf("Nanny\n"); + } + } + } + + //we made it all the way through. yay. + + trace->allsolid = trace->startsolid = false; +//Con_Printf("total = %f\n", trace->fraction); + return trace->fraction==1; +#endif +} + + + + + + + + + + + + + + @@ -130,7 +727,11 @@ typedef struct shader_t *shader; unsigned short width; unsigned short height; - batch_t *batch; + batch_t batch; + mesh_t *meshptr; + mesh_t mesh; + int maxverts; + int maxindicies; } gldoomtexture_t; gldoomtexture_t *gldoomtextures; int numgldoomtextures; @@ -138,9 +739,11 @@ int numgldoomtextures; static void GLR_DrawWall(int texnum, int s, int t, float x1, float y1, float frontfloor, float x2, float y2, float backfloor, qboolean unpegged, unsigned int colour4b) { gldoomtexture_t *tex = gldoomtextures+texnum; + mesh_t *mesh = &tex->mesh; float len = sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)); float s1, s2; float t1, t2; + unsigned int col; s1 = s/tex->width; s2 = s1 + len/tex->width; @@ -156,21 +759,44 @@ static void GLR_DrawWall(int texnum, int s, int t, float x1, float y1, float fro t2 = t1 + (backfloor-frontfloor)/tex->height; } + if (mesh->numvertexes+4 > tex->maxverts) + { + tex->maxverts = mesh->numvertexes+4; + mesh->colors4b_array = BZ_Realloc(mesh->colors4b_array, sizeof(*mesh->colors4b_array) * tex->maxverts); + mesh->xyz_array = BZ_Realloc(mesh->xyz_array, sizeof(*mesh->xyz_array) * tex->maxverts); + mesh->st_array = BZ_Realloc(mesh->st_array, sizeof(*mesh->st_array) * tex->maxverts); + } + if (mesh->numindexes+6 > tex->maxindicies) + { + tex->maxindicies = mesh->numvertexes+6; + mesh->indexes = BZ_Realloc(mesh->colors4b_array, sizeof(*mesh->indexes) * tex->maxindicies); + } -#if 0 - GL_Bind(tex->gltexture); + col = colour4b * 0x01010101; + ((unsigned int*)&col)[3] = 0xff; + *(unsigned int*)mesh->colors4b_array[mesh->numvertexes+0] = col; + *(unsigned int*)mesh->colors4b_array[mesh->numvertexes+1] = col; + *(unsigned int*)mesh->colors4b_array[mesh->numvertexes+2] = col; + *(unsigned int*)mesh->colors4b_array[mesh->numvertexes+3] = col; + VectorSet(mesh->xyz_array[mesh->numvertexes+0], x1, y1, frontfloor); + VectorSet(mesh->xyz_array[mesh->numvertexes+1], x1, y1, backfloor); + VectorSet(mesh->xyz_array[mesh->numvertexes+2], x2, y2, backfloor); + VectorSet(mesh->xyz_array[mesh->numvertexes+3], x2, y2, frontfloor); + Vector2Set(mesh->st_array[mesh->numvertexes+0], s1, t2); + Vector2Set(mesh->st_array[mesh->numvertexes+0], s1, t1); + Vector2Set(mesh->st_array[mesh->numvertexes+0], s2, t1); + Vector2Set(mesh->st_array[mesh->numvertexes+0], s2, t2); - qglBegin(GL_QUADS); - qglTexCoord2f(s1, t2); - qglVertex3f(x1, y1, frontfloor); - qglTexCoord2f(s1, t1); - qglVertex3f(x1, y1, backfloor); - qglTexCoord2f(s2, t1); - qglVertex3f(x2, y2, backfloor); - qglTexCoord2f(s2, t2); - qglVertex3f(x2, y2, frontfloor); - qglEnd(); -#endif + mesh->indexes[mesh->numindexes+0] = mesh->numvertexes; + mesh->indexes[mesh->numindexes+1] = mesh->numvertexes; + mesh->indexes[mesh->numindexes+2] = mesh->numvertexes; + + mesh->indexes[mesh->numindexes+0] = mesh->numvertexes; + mesh->indexes[mesh->numindexes+2] = mesh->numvertexes; + mesh->indexes[mesh->numindexes+3] = mesh->numvertexes; + + mesh->numvertexes += 4; + mesh->numindexes += 6; } static void GLR_DrawSSector(unsigned int ssec) @@ -404,7 +1030,8 @@ void GLR_DoomWorld(void) r_visframecount++; GLR_RecursiveDoomNode(nodec-1); } -#endif + + //find the first ssector, go through it's list/ //grab the lines into multiple arrays. @@ -420,8 +1047,6 @@ void GLR_DoomWorld(void) //pick a point, follow along the walls making a triangle fan, until an angle of > 180, throw out fan, rebuild arrays. //at new point, start a new fan. Be prepared to not be able to generate one. -#ifdef GLQUAKE - #define MAX_REGIONS 256 #define MAX_POLYVERTS (MAX_FLATTRIS*3) #define MAX_FLATTRIS 1024 @@ -647,7 +1272,6 @@ static unsigned short *Triangulate_Finish(int *numtris, unsigned short *old, int return out; } -#endif static void Triangulate_Sectors(dsector_t *sectorl, qboolean glbspinuse) { @@ -656,7 +1280,6 @@ static void Triangulate_Sectors(dsector_t *sectorl, qboolean glbspinuse) sectorm = Z_Malloc(sectorc * sizeof(*sectorm)); -#ifdef GLQUAKE if (glbspinuse) { for (i = 0; i < ssectorsc; i++) @@ -700,7 +1323,7 @@ static void Triangulate_Sectors(dsector_t *sectorl, qboolean glbspinuse) sectorm[sec].flats = Triangulate_Finish(§orm[sec].numflattris, sectorm[sec].flats, sectorm[sec].numflattris); } } -#endif + /* for (i = 0; i < ssectorsc; i++) { //only do linedefs. @@ -723,10 +1346,8 @@ static void Triangulate_Sectors(dsector_t *sectorl, qboolean glbspinuse) for (i = 0; i < sectorc; i++) { -#ifdef GLQUAKE sectorm[i].ceilingtex = Doom_LoadFlat(sectorl[i].ceilingtexture); sectorm[i].floortex = Doom_LoadFlat(sectorl[i].floortexture); -#endif sectorm[i].lightlev = sectorl[i].lightlevel; sectorm[i].specialtype = sectorl[i].specialtype; sectorm[i].tag = sectorl[i].tag; @@ -734,6 +1355,7 @@ static void Triangulate_Sectors(dsector_t *sectorl, qboolean glbspinuse) sectorm[i].floorheight = sectorl[i].floorheight; } } + #ifndef SERVERONLY static void *textures1; static void *textures2; @@ -899,7 +1521,7 @@ static int Doom_LoadPatch(char *name) strncpy(gldoomtextures[texnum].name, name, 8); - gldoomtextures[texnum].shader = R_RegisterShader(name, "{\n{\nmap $diffuse\n}\n}\n"); + gldoomtextures[texnum].shader = R_RegisterShader(name, "{\n{\nmap $diffuse\nrgbgen vertex\n}\n}\n"); if (textures1) { @@ -916,8 +1538,25 @@ static int Doom_LoadPatch(char *name) //all else failed. gldoomtextures[texnum].width = image_width; gldoomtextures[texnum].height = image_height; + gldoomtextures[texnum].meshptr = &gldoomtextures[texnum].mesh; + gldoomtextures[texnum].batch.mesh = &gldoomtextures[texnum].meshptr; + gldoomtextures[texnum].batch.next = loadmodel->batches[gldoomtextures[texnum].shader->sort]; + loadmodel->batches[gldoomtextures[texnum].shader->sort] = &gldoomtextures[texnum].batch; return texnum; } +static void Doom_Purge (struct model_s *mod) +{ + int texnum; + for (texnum = 0; texnum < numgldoomtextures; texnum++) + { + BZ_Free(gldoomtextures[texnum].mesh.colors4b_array); + BZ_Free(gldoomtextures[texnum].mesh.st_array); + BZ_Free(gldoomtextures[texnum].mesh.xyz_array); + BZ_Free(gldoomtextures[texnum].mesh.indexes); + } + BZ_Free(gldoomtextures); + gldoomtextures = NULL; +} #endif static void CleanWalls(dsidedef_t *sidedefsl) { @@ -1046,7 +1685,7 @@ void QuakifyThings(dthing_t *thingsl) point[1] = thingsl[i].ypos; point[2] = 0; sector = Doom_SectorNearPoint(point); - zpos = sectorm[sector].floorheight + 24; + zpos = sectorm[sector].floorheight + 24; //things have no z coord, so find the sector they're in spawnflags = SPAWNFLAG_NOT_EASY | SPAWNFLAG_NOT_MEDIUM | SPAWNFLAG_NOT_HARD | SPAWNFLAG_NOT_DEATHMATCH; if (thingsl[i].flags & THING_EASY) @@ -1424,34 +2063,38 @@ void Doom_LightPointValues(model_t *model, vec3_t point, vec3_t res_diffuse, vec res_ambient[2] = sec->lightlev; } +//return pvs bits for point unsigned int Doom_FatPVS(struct model_s *model, vec3_t org, qbyte *pvsbuffer, unsigned int buffersize, qboolean merge) { //FIXME: use REJECT lump. return 0; } +//check if an ent is within the given pvs qboolean Doom_EdictInFatPVS(struct model_s *model, struct pvscache_s *edict, qbyte *pvsbuffer) { //FIXME: use REJECT lump. return true; } + +//generate useful info for correct functioning of Doom_EdictInFatPVS. void Doom_FindTouchedLeafs(struct model_s *model, struct pvscache_s *ent, vec3_t cullmins, vec3_t cullmaxs) { //work out the sectors this ent is in for easy pvs. } +//requires lightmaps - not supported. void Doom_StainNode(struct mnode_s *node, float *parms) { - //not supported } +//requires lightmaps - not supported. void Doom_MarkLights(struct dlight_s *light, int bit, struct mnode_s *node) { - //not supported } void Doom_SetModelFunc(model_t *mod) { - //mod->funcs.PurgeModel = ; + mod->funcs.PurgeModel = Doom_Purge; mod->funcs.FatPVS = Doom_FatPVS; mod->funcs.EdictInFatPVS = Doom_EdictInFatPVS; @@ -1463,7 +2106,10 @@ void Doom_SetModelFunc(model_t *mod) // mod->funcs.LeafPVS) (struct model_s *model, int num, qbyte *buffer, unsigned int buffersize); - Doom_SetCollisionFuncs(mod); + mod->funcs.NativeTrace = Doom_Trace; + mod->funcs.PointContents = Doom_PointContents; + + //Doom_SetCollisionFuncs(mod); } #endif diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index 661f52573..57eb6731b 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -73,6 +73,7 @@ void ClearBounds (vec3_t mins, vec3_t maxs); #define GLclampd GLclampf #define GLdouble GLfloat #define GL_CLAMP GL_CLAMP_TO_EDGE + #define GL_NONE 0 #define GL_FILL (Sys_Error("GL_FILL was used"),0) #define GL_QUADS (Sys_Error("GL_QUADS was used"),0) @@ -153,6 +154,7 @@ qboolean GL_CheckExtension(char *extname); typedef struct { float glversion; + int maxglslversion; qboolean nofixedfunc; qboolean gles; qboolean tex_env_combine; @@ -332,7 +334,7 @@ void FTE_DEPRECATED R_IBrokeTheArrays(void); // #ifdef GLQUAKE texid_tf GL_LoadPicTexture (qpic_t *pic); -void GL_Set2D (void); +void GL_Set2D (qboolean flipped); #endif // @@ -832,7 +834,7 @@ extern FTEPFNGLUNIFORM1IARBPROC qglUniform1iARB; extern FTEPFNGLUNIFORM1FARBPROC qglUniform1fARB; //glslang helper api -GLhandleARB GLSlang_CreateProgram(char *name, int ver, char **precompilerconstants, char *vert, char *frag); +GLhandleARB GLSlang_CreateProgram(char *name, int ver, char **precompilerconstants, char *vert, char *frag, qboolean silent); GLint GLSlang_GetUniformLocation (int prog, char *name); void GL_SelectProgram(int program); #define GLSlang_UseProgram(prog) GL_SelectProgram(prog) diff --git a/engine/gl/ltface.c b/engine/gl/ltface.c index 159e60ac3..5f5d0c55f 100644 --- a/engine/gl/ltface.c +++ b/engine/gl/ltface.c @@ -61,7 +61,7 @@ vec_t CastRay (vec3_t p1, vec3_t p2) trace_t trace; vec3_t move; - lightmodel->funcs.Trace (lightmodel, 0, 0, NULL, p1, p2, vec3_origin, vec3_origin, &trace); + lightmodel->funcs.NativeTrace (lightmodel, 0, 0, NULL, p1, p2, vec3_origin, vec3_origin, FTECONTENTS_SOLID, &trace); if (trace.fraction < 1) return -1; diff --git a/engine/partcfgs/h2part.cfg b/engine/partcfgs/h2part.cfg index 28ef14570..cfc871b43 100644 --- a/engine/partcfgs/h2part.cfg +++ b/engine/partcfgs/h2part.cfg @@ -1,3 +1,23 @@ +r_part t_rocket +{ + texture "particles/fteparticlefont.tga" + tcoords 1 1 63 63 256 2 64 + step 32 + scale 64 + alpha 0.6 + die 1 + randomvel 64 + veladd 10 + rotationspeed 90 + rotationstart 0 360 + rgb 16 32 16 + rgbrand 16 64 16 + gravity 200 + scalefactor 0.8 + scaledelta -10 + stains 2 +} + r_part ce_white_smoke_05 { model models/whtsmk1.spr 0 0 20 0.5 @@ -149,7 +169,7 @@ r_part ce_new_explosion } r_part ce_magic_missile_explosion { - model models/mm_explod.spr 0 0 20 1 + model models/mm_expld.spr 0 0 20 1 } // ce_ghost r_part ce_bone_explosion @@ -226,3 +246,283 @@ r_part ce_floor_explosion3 { model models/biggy.spr 0 0 20 1 } + +r_part ce_boneshard +{ + model models/boneshot.mdl 0 1 1 1 + rotationspeed 425 + veladd 2 +} +r_part ce_boneshrapnel +{ + model models/boneshrd.mdl 0 1 1 1 + rotationspeed 425 + veladd 2 +} + +r_part ce_chunk_greystone +{ + model models/schunk1.mdl 0 1 0.25 1 + model models/schunk2.mdl 0 1 0.25 1 + model models/schunk3.mdl 0 1 0.25 1 + model models/schunk4.mdl 0 1 0.25 1 + randomvel 210 70 280 + spawnorg 0 + gravity 800 + rotationspeed 425 +} +r_part ce_chunk_wood +{ + model models/splnter1.mdl 0 1 0.25 1 + model models/splnter2.mdl 0 1 0.25 1 + model models/splnter3.mdl 0 1 0.25 1 + model models/splnter4.mdl 0 1 0.25 1 + randomvel 210 70 280 + spawnorg 0 + gravity 800 + rotationspeed 425 +} +r_part ce_chunk_metal +{ + model models/metlchk1.mdl 0 1 0.25 1 + model models/metlchk2.mdl 0 1 0.25 1 + model models/metlchk3.mdl 0 1 0.25 1 + model models/metlchk4.mdl 0 1 0.25 1 + randomvel 210 70 280 + spawnorg 0 + gravity 800 + rotationspeed 425 +} +r_part ce_chunk_flesh +{ + model models/flesh1.mdl 0 1 0.25 1 + model models/flesh2.mdl 0 1 0.25 1 + model models/flesh3.mdl 0 1 0.25 1 + randomvel 210 70 280 + spawnorg 0 + gravity 800 + rotationspeed 425 +} +//r_part ce_chunk_fire +//{ +//} +r_part ce_chunk_clay +{ + model models/clshard1.mdl 0 1 0.25 1 + model models/clshard2.mdl 0 1 0.25 1 + model models/clshard3.mdl 0 1 0.25 1 + model models/clshard4.mdl 0 1 0.25 1 + randomvel 210 70 280 + spawnorg 0 + gravity 800 + rotationspeed 425 +} +r_part ce_chunk_leaves +{ + model models/leafchk1.mdl 0 1 0.25 1 + model models/leafchk2.mdl 0 1 0.25 1 + model models/leafchk3.mdl 0 1 0.25 1 + randomvel 210 70 280 + spawnorg 0 + gravity 800 + rotationspeed 425 +} +r_part ce_chunk_hay +{ + model models/hay1.mdl 0 1 0.25 1 + model models/hay2.mdl 0 1 0.25 1 + model models/hay3.mdl 0 1 0.25 1 + randomvel 210 70 280 + spawnorg 0 + gravity 800 + rotationspeed 425 +} +r_part ce_chunk_brownstone +{ + model models/schunk1.mdl 1 1 0.25 1 + model models/schunk2.mdl 1 1 0.25 1 + model models/schunk3.mdl 1 1 0.25 1 + model models/schunk4.mdl 1 1 0.25 1 + randomvel 210 70 280 + spawnorg 0 + gravity 800 + rotationspeed 425 +} +r_part ce_chunk_cloth +{ + model models/clthchk1.mdl 0 1 0.25 1 + model models/clthchk2.mdl 0 1 0.25 1 + model models/clthchk3.mdl 0 1 0.25 1 + randomvel 210 70 280 + spawnorg 0 + gravity 800 + rotationspeed 425 +} +r_part ce_chunk_wood_leaf +{ + model models/splnter1.mdl 0 1 0.25 1 + model models/splnter2.mdl 0 1 0.25 1 + model models/splnter3.mdl 0 1 0.25 1 + model models/splnter4.mdl 0 1 0.25 1 + model models/leafchk1.mdl 0 1 0.25 1 + model models/leafchk2.mdl 0 1 0.25 1 + model models/leafchk3.mdl 0 1 0.25 1 + randomvel 210 70 280 + spawnorg 0 + gravity 800 + rotationspeed 425 + +} +r_part ce_chunk_wood_metal +{ + model models/splnter1.mdl 0 1 0.25 1 + model models/splnter2.mdl 0 1 0.25 1 + model models/splnter3.mdl 0 1 0.25 1 + model models/splnter4.mdl 0 1 0.25 1 + model models/metlchk1.mdl 0 1 0.25 1 + model models/metlchk2.mdl 0 1 0.25 1 + model models/metlchk3.mdl 0 1 0.25 1 + model models/metlchk4.mdl 0 1 0.25 1 + randomvel 210 70 280 + spawnorg 0 + gravity 800 + rotationspeed 425 +} +r_part ce_chunk_wood_stone +{ + model models/splnter1.mdl 0 1 0.25 1 + model models/splnter2.mdl 0 1 0.25 1 + model models/splnter3.mdl 0 1 0.25 1 + model models/splnter4.mdl 0 1 0.25 1 + model models/schunk1.mdl 0 1 0.25 1 + model models/schunk2.mdl 0 1 0.25 1 + model models/schunk3.mdl 0 1 0.25 1 + model models/schunk4.mdl 0 1 0.25 1 + randomvel 210 70 280 + spawnorg 0 + gravity 800 + rotationspeed 425 +} +r_part ce_chunk_metal_stone +{ + model models/metlchk1.mdl 0 1 0.25 1 + model models/metlchk2.mdl 0 1 0.25 1 + model models/metlchk3.mdl 0 1 0.25 1 + model models/metlchk4.mdl 0 1 0.25 1 + model models/schunk1.mdl 0 1 0.25 1 + model models/schunk2.mdl 0 1 0.25 1 + model models/schunk3.mdl 0 1 0.25 1 + model models/schunk4.mdl 0 1 0.25 1 + randomvel 210 70 280 + spawnorg 0 + gravity 800 + rotationspeed 425 +} +r_part ce_chunk_metal_cloth +{ + model models/metlchk1.mdl 0 1 0.25 1 + model models/metlchk2.mdl 0 1 0.25 1 + model models/metlchk3.mdl 0 1 0.25 1 + model models/metlchk4.mdl 0 1 0.25 1 + model models/clthchk1.mdl 0 1 0.25 1 + model models/clthchk2.mdl 0 1 0.25 1 + model models/clthchk3.mdl 0 1 0.25 1 + randomvel 210 70 280 + spawnorg 0 + gravity 800 + rotationspeed 425 +} +r_part ce_chunk_webs +{ + model models/shard1.mdl 3 1 0.25 0.5 + model models/shard2.mdl 3 1 0.25 0.5 + model models/shard3.mdl 3 1 0.25 0.5 + model models/shard4.mdl 3 1 0.25 0.5 + model models/shard5.mdl 3 1 0.25 0.5 + randomvel 210 70 280 + spawnorg 0 + gravity 500 + rotationspeed 425 +} +r_part ce_chunk_glass +{ + model models/shard1.mdl 0 1 0.25 1 + model models/shard2.mdl 0 1 0.25 1 + model models/shard3.mdl 0 1 0.25 1 + model models/shard4.mdl 0 1 0.25 1 + model models/shard5.mdl 0 1 0.25 1 + randomvel 210 70 280 + spawnorg 0 + gravity 800 + rotationspeed 425 +} +r_part ce_chunk_ice +{ + model models/shard.mdl 0 1 0.25 0.5 + model models/shard.mdl 1 1 0.25 0.5 + randomvel 210 70 280 + spawnorg 0 + gravity 800 +} +r_part ce_chunk_clearglass +{ + model models/shard1.mdl 1 1 0.25 0.5 + model models/shard2.mdl 1 1 0.25 0.5 + model models/shard3.mdl 1 1 0.25 0.5 + model models/shard4.mdl 1 1 0.25 0.5 + model models/shard5.mdl 1 1 0.25 0.5 + randomvel 210 70 280 + spawnorg 0 + gravity 800 + rotationspeed 425 +} +r_part ce_chunk_redglass +{ + model models/shard1.mdl 2 1 0.25 1 + model models/shard2.mdl 2 1 0.25 1 + model models/shard3.mdl 2 1 0.25 1 + model models/shard4.mdl 2 1 0.25 1 + model models/shard5.mdl 2 1 0.25 1 + randomvel 210 70 280 + spawnorg 0 + gravity 800 + rotationspeed 425 +} +r_part ce_chunk_acid +{ + model models/sucwp2p.mdl 0 1 0.25 1 + randomvel 210 70 280 + spawnorg 0 + gravity 800 + rotationspeed 425 +} +r_part ce_chunk_meteor +{ + model models/tempmetr.mdl 0 1 0.25 1 + randomvel 360 + spawnorg 0 + gravity 800 + rotationspeed 425 +} +r_part ce_chunk_greenflesh +{ + model models/sflesh1.mdl 0 1 0.25 1 + model models/sflesh2.mdl 0 1 0.25 1 + model models/sflesh3.mdl 0 1 0.25 1 + randomvel 210 70 280 + spawnorg 0 + gravity 800 + rotationspeed 425 +} +r_part ce_chunk_bone +{ + model models/clshard1.mdl 1 1 0.25 1 + model models/clshard2.mdl 1 1 0.25 1 + model models/clshard3.mdl 1 1 0.25 1 + model models/clshard4.mdl 1 1 0.25 1 + randomvel 210 70 280 + spawnorg 0 + gravity 800 + rotationspeed 425 +} + diff --git a/engine/qclib/execloop.h b/engine/qclib/execloop.h index 89e10d9a4..d2dfb442f 100644 --- a/engine/qclib/execloop.h +++ b/engine/qclib/execloop.h @@ -358,7 +358,7 @@ reeval: case OP_MULSTORE_F: // f *= f OPB->_float *= OPA->_float; break; - case OP_MULSTORE_V: // v *= f + case OP_MULSTORE_VF: // v *= f OPB->_vector[0] *= OPA->_float; OPB->_vector[1] *= OPA->_float; OPB->_vector[2] *= OPA->_float; @@ -372,7 +372,7 @@ reeval: ptr = QCPOINTER(OPB); OPC->_float = (ptr->_float *= OPA->_float); break; - case OP_MULSTOREP_V: // e.v *= f + case OP_MULSTOREP_VF: // e.v *= f if ((unsigned int)OPB->_int >= addressableused) { pr_xstatement = st-pr_statements; @@ -866,7 +866,7 @@ reeval: i = (int)OPB->_float; if(i < 0 || i > ((eval_t *)&glob[st->a-1])->_int) { - PR_RunError(progfuncs, "array index out of bounds: %s[%d]", PR_GlobalStringNoContents(progfuncs, st->a), i); + PR_RunError(progfuncs, "array index out of bounds: %s[%d] (max %d)", PR_GlobalStringNoContents(progfuncs, st->a), i, ((eval_t *)&glob[st->a-1])->_int); } t = (eval_t *)&pr_globals[(uofs)st->a + i]; OPC->_int = t->_int; diff --git a/engine/qclib/pr_comp.h b/engine/qclib/pr_comp.h index d6c34a96e..ab31721da 100644 --- a/engine/qclib/pr_comp.h +++ b/engine/qclib/pr_comp.h @@ -112,9 +112,9 @@ enum qcop_e { //these following ones are Hexen 2 constants. OP_MULSTORE_F, - OP_MULSTORE_V, + OP_MULSTORE_VF, OP_MULSTOREP_F, - OP_MULSTOREP_V, + OP_MULSTOREP_VF, OP_DIVSTORE_F, //70 OP_DIVSTOREP_F, @@ -350,7 +350,10 @@ enum qcop_e { OP_SUBSTORE_FI, OP_SUBSTOREP_FI, - OP_NUMOPS //246 + OP_MULSTORE_VI, + OP_MULSTOREP_VI, + + OP_NUMOPS }; #define MAX_PARMS 8 diff --git a/engine/qclib/pr_exec.c b/engine/qclib/pr_exec.c index 2d7f7a53b..323c56606 100644 --- a/engine/qclib/pr_exec.c +++ b/engine/qclib/pr_exec.c @@ -492,6 +492,8 @@ char *EvaluateDebugString(progfuncs_t *progfuncs, char *key) if (assignment) { assignment++; + while(*assignment == ' ') + assignment++; switch (type&~DEF_SAVEGLOBAL) { case ev_string: @@ -499,7 +501,10 @@ char *EvaluateDebugString(progfuncs_t *progfuncs, char *key) break; case ev_float: - *(float *)val = (float)atof (assignment); + if (assignment[0] == '0' && (assignment[1] == 'x' || assignment[1] == 'X')) + *(float*)val = strtoul(assignment, NULL, 0); + else + *(float *)val = (float)atof (assignment); break; case ev_integer: diff --git a/engine/qclib/qcc.h b/engine/qclib/qcc.h index bbd90b0c1..81517b413 100644 --- a/engine/qclib/qcc.h +++ b/engine/qclib/qcc.h @@ -373,7 +373,7 @@ typedef union QCC_eval_s const extern unsigned int type_size[]; //extern QCC_def_t *def_for_type[9]; -extern QCC_type_t *type_void, *type_string, *type_float, *type_vector, *type_entity, *type_field, *type_function, *type_pointer, *type_integer, *type_variant, *type_floatfield; +extern QCC_type_t *type_void, *type_string, *type_float, *type_vector, *type_entity, *type_field, *type_function, *type_pointer, *type_floatpointer, *type_intpointer, *type_integer, *type_variant, *type_floatfield; struct QCC_function_s { @@ -484,6 +484,7 @@ extern pbool flag_fasttrackarrays; extern pbool flag_assume_integer; extern pbool flag_msvcstyle; extern pbool flag_filetimes; +extern pbool flag_typeexplicit; extern pbool opt_overlaptemps; extern pbool opt_shortenifnots; diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index 90564783b..cd55e5643 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -78,6 +78,7 @@ pbool flag_fasttrackarrays; //Faster arrays, dynamically detected, activated onl pbool flag_msvcstyle; //MSVC style warnings, so msvc's ide works properly pbool flag_assume_integer; //5 - is that an integer or a float? qcc says float. but we support int too, so maybe we want that instead? pbool flag_filetimes; +pbool flag_typeexplicit; //no implicit type conversions, you must do the casts yourself. pbool opt_overlaptemps; //reduce numpr_globals by reuse of temps. When they are not needed they are freed for reuse. The way this is implemented is better than frikqcc's. (This is the single most important optimisation) pbool opt_assignments; //STORE_F isn't used if an operation wrote to a temp. @@ -293,9 +294,9 @@ QCC_opcode_t pr_opcodes[] = //these are hexen2 {7, "*=", "MULSTORE_F", 6, ASSOC_RIGHT_RESULT, &type_float, &type_float, &type_float}, - {7, "*=", "MULSTORE_V", 6, ASSOC_RIGHT_RESULT, &type_vector, &type_float, &type_vector}, + {7, "*=", "MULSTORE_VF", 6, ASSOC_RIGHT_RESULT, &type_vector, &type_float, &type_vector}, {7, "*=", "MULSTOREP_F", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_float, &type_float}, - {7, "*=", "MULSTOREP_V", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_float, &type_vector}, + {7, "*=", "MULSTOREP_VF", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_float, &type_vector}, {7, "/=", "DIVSTORE_F", 6, ASSOC_RIGHT_RESULT, &type_float, &type_float, &type_float}, {7, "/=", "DIVSTOREP_F", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_float, &type_float}, @@ -522,23 +523,26 @@ QCC_opcode_t pr_opcodes[] = {7, "+=", "ADDSTOREP_I", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_integer, &type_integer}, {7, "-=", "SUBSTOREP_I", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_integer, &type_integer}, - {7, "*=", "OP_MULSTORE_IF", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_float, &type_integer}, - {7, "*=", "OP_MULSTOREP_IF", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_float, &type_integer}, - {7, "/=", "OP_DIVSTORE_IF", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_float, &type_integer}, - {7, "/=", "OP_DIVSTOREP_IF", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_float, &type_integer}, - {7, "+=", "OP_ADDSTORE_IF", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_float, &type_integer}, - {7, "+=", "OP_ADDSTOREP_IF", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_float, &type_integer}, - {7, "-=", "OP_SUBSTORE_IF", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_float, &type_integer}, - {7, "-=", "OP_SUBSTOREP_IF", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_float, &type_integer}, + {7, "*=", "MULSTORE_IF", 6, ASSOC_RIGHT_RESULT, &type_integer, &type_float, &type_float}, + {7, "*=", "MULSTOREP_IF", 6, ASSOC_RIGHT_RESULT, &type_intpointer, &type_float, &type_float}, + {7, "/=", "DIVSTORE_IF", 6, ASSOC_RIGHT_RESULT, &type_integer, &type_float, &type_float}, + {7, "/=", "DIVSTOREP_IF", 6, ASSOC_RIGHT_RESULT, &type_intpointer, &type_float, &type_float}, + {7, "+=", "ADDSTORE_IF", 6, ASSOC_RIGHT_RESULT, &type_integer, &type_float, &type_float}, + {7, "+=", "ADDSTOREP_IF", 6, ASSOC_RIGHT_RESULT, &type_intpointer, &type_float, &type_float}, + {7, "-=", "SUBSTORE_IF", 6, ASSOC_RIGHT_RESULT, &type_integer, &type_float, &type_float}, + {7, "-=", "SUBSTOREP_IF", 6, ASSOC_RIGHT_RESULT, &type_intpointer, &type_float, &type_float}, - {7, "*=", "OP_MULSTORE_FI", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_integer, &type_float}, - {7, "*=", "OP_MULSTOREP_FI", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_integer, &type_float}, - {7, "/=", "OP_DIVSTORE_FI", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_integer, &type_float}, - {7, "/=", "OP_DIVSTOREP_FI", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_integer, &type_float}, - {7, "+=", "OP_ADDSTORE_FI", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_integer, &type_float}, - {7, "+=", "OP_ADDSTOREP_FI", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_integer, &type_float}, - {7, "-=", "OP_SUBSTORE_FI", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_integer, &type_float}, - {7, "-=", "OP_SUBSTOREP_FI", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_integer, &type_float}, + {7, "*=", "MULSTORE_FI", 6, ASSOC_RIGHT_RESULT, &type_float, &type_integer, &type_float}, + {7, "*=", "MULSTOREP_FI", 6, ASSOC_RIGHT_RESULT, &type_floatpointer, &type_integer, &type_float}, + {7, "/=", "DIVSTORE_FI", 6, ASSOC_RIGHT_RESULT, &type_float, &type_integer, &type_float}, + {7, "/=", "DIVSTOREP_FI", 6, ASSOC_RIGHT_RESULT, &type_floatpointer, &type_integer, &type_float}, + {7, "+=", "ADDSTORE_FI", 6, ASSOC_RIGHT_RESULT, &type_float, &type_integer, &type_float}, + {7, "+=", "ADDSTOREP_FI", 6, ASSOC_RIGHT_RESULT, &type_floatpointer, &type_integer, &type_float}, + {7, "-=", "SUBSTORE_FI", 6, ASSOC_RIGHT_RESULT, &type_float, &type_integer, &type_float}, + {7, "-=", "SUBSTOREP_FI", 6, ASSOC_RIGHT_RESULT, &type_floatpointer, &type_integer, &type_float}, + + {7, "*=", "MULSTORE_VI", 6, ASSOC_RIGHT_RESULT, &type_vector, &type_integer, &type_vector}, + {7, "*=", "MULSTOREP_VI", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_integer, &type_vector}, {0, NULL} }; @@ -656,11 +660,17 @@ QCC_opcode_t *opcodeprioritized[TOP_PRIORITY+1][128] = &pr_opcodes[OP_MUL_F], &pr_opcodes[OP_MUL_V], &pr_opcodes[OP_MUL_FV], + &pr_opcodes[OP_MUL_IV], &pr_opcodes[OP_MUL_VF], + &pr_opcodes[OP_MUL_VI], &pr_opcodes[OP_MUL_I], + &pr_opcodes[OP_MUL_FI], + &pr_opcodes[OP_MUL_IF], &pr_opcodes[OP_DIV_F], &pr_opcodes[OP_DIV_I], + &pr_opcodes[OP_DIV_FI], + &pr_opcodes[OP_DIV_IF], &pr_opcodes[OP_DIV_VF], &pr_opcodes[OP_BITAND_F], @@ -764,12 +774,14 @@ QCC_opcode_t *opcodeprioritized[TOP_PRIORITY+1][128] = &pr_opcodes[OP_DIVSTOREP_IF], &pr_opcodes[OP_DIVSTOREP_FI], &pr_opcodes[OP_MULSTORE_F], - &pr_opcodes[OP_MULSTORE_V], + &pr_opcodes[OP_MULSTORE_VF], + &pr_opcodes[OP_MULSTORE_VI], &pr_opcodes[OP_MULSTORE_I], &pr_opcodes[OP_MULSTORE_IF], &pr_opcodes[OP_MULSTORE_FI], &pr_opcodes[OP_MULSTOREP_F], - &pr_opcodes[OP_MULSTOREP_V], + &pr_opcodes[OP_MULSTOREP_VF], + &pr_opcodes[OP_MULSTOREP_VI], &pr_opcodes[OP_MULSTOREP_I], &pr_opcodes[OP_MULSTOREP_IF], &pr_opcodes[OP_MULSTOREP_FI], @@ -1010,9 +1022,9 @@ pbool QCC_OPCodeValid(QCC_opcode_t *op) return false; //DPFIXME: dp's bounds check may give false positives with expected uses. case OP_MULSTORE_F: - case OP_MULSTORE_V: + case OP_MULSTORE_VF: case OP_MULSTOREP_F: - case OP_MULSTOREP_V: // e.v *= f + case OP_MULSTOREP_VF: // e.v *= f case OP_DIVSTORE_F: case OP_DIVSTOREP_F: case OP_STORE_IF: @@ -1134,7 +1146,7 @@ QCC_def_t *QCC_SupplyConversion(QCC_def_t *var, etype_t wanted, pbool fatal) if (pr_classtype) { //load self.var into a temp QCC_def_t *self; - self = QCC_PR_GetDef(type_entity, "self", NULL, true, 1, false); + self = QCC_PR_GetDef(type_entity, "self", NULL, true, 0, false); switch(wanted) { case ev_float: @@ -1157,6 +1169,8 @@ QCC_def_t *QCC_SupplyConversion(QCC_def_t *var, etype_t wanted, pbool fatal) if (o == 0) //type already matches return var; + if (flag_typeexplicit) + QCC_PR_ParseErrorPrintDef(ERR_TYPEMISMATCH, var, "Implicit type mismatch. Needed %s, got %s.", basictypenames[wanted], var->type->name); if (o < 0) { if (fatal) @@ -1515,7 +1529,7 @@ static void QCC_fprintfLocals(FILE *f, gofs_t paramstart, gofs_t paramend) { if (var->ofs >= paramstart && var->ofs < paramend) continue; - if (var->arraysize != 1) + if (var->arraysize) fprintf(f, "local %s %s[%i];\n", TypeName(var->type), var->name, var->arraysize); else fprintf(f, "local %s %s;\n", TypeName(var->type), var->name); @@ -2097,7 +2111,7 @@ QCC_def_t *QCC_PR_Statement (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t *var_ switch(op - pr_opcodes) { case OP_IF_S: - var_c = QCC_PR_GetDef(type_string, "string_null", NULL, true, 1, false); + var_c = QCC_PR_GetDef(type_string, "string_null", NULL, true, 0, false); numstatements--; var_a = QCC_PR_Statement(&pr_opcodes[OP_NE_S], var_a, var_c, NULL); statement = &statements[numstatements]; @@ -2108,7 +2122,7 @@ QCC_def_t *QCC_PR_Statement (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t *var_ break; case OP_IFNOT_S: - var_c = QCC_PR_GetDef(type_string, "string_null", NULL, true, 1, false); + var_c = QCC_PR_GetDef(type_string, "string_null", NULL, true, 0, false); numstatements--; var_a = QCC_PR_Statement(&pr_opcodes[OP_NE_S], var_a, var_c, NULL); statement = &statements[numstatements]; @@ -2251,13 +2265,20 @@ QCC_def_t *QCC_PR_Statement (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t *var_ var_c = var_a; break; - case OP_MULSTORE_V: + case OP_MULSTORE_VF: op = &pr_opcodes[OP_MUL_VF]; var_c = var_b; var_b = var_a; var_a = var_c; var_c = var_a; break; + case OP_MULSTORE_VI: + op = &pr_opcodes[OP_MUL_VI]; + var_c = var_b; + var_b = var_a; + var_a = var_c; + var_c = var_a; + break; case OP_BITSET_I: op = &pr_opcodes[OP_BITOR_I]; @@ -2304,7 +2325,8 @@ QCC_def_t *QCC_PR_Statement (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t *var_ case OP_DIVSTOREP_FI: case OP_DIVSTOREP_IF: - case OP_MULSTOREP_V: + case OP_MULSTOREP_VF: + case OP_MULSTOREP_VI: case OP_SUBSTOREP_V: case OP_ADDSTOREP_V: @@ -2365,9 +2387,12 @@ QCC_def_t *QCC_PR_Statement (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t *var_ case OP_ADDSTOREP_V: statement->op = OP_ADD_V; break; - case OP_MULSTOREP_V: + case OP_MULSTOREP_VF: statement->op = OP_MUL_VF; break; + case OP_MULSTOREP_VI: + statement->op = OP_MUL_VI; + break; case OP_SUBSTOREP_F: statement->op = OP_SUB_F; break; @@ -2887,7 +2912,7 @@ QCC_def_t *QCC_PR_GenerateFunctionCall (QCC_def_t *func, QCC_def_t *arglist[], i //FIXME: problems could occur with hexen2 calling conventions when parm0/1 is 'self' //thiscall. copy the right ent into 'self' (if it's not the same offset) - d = QCC_PR_GetDef(type_entity, "self", NULL, true, 1, false); + d = QCC_PR_GetDef(type_entity, "self", NULL, true, 0, false); if (statements[laststatement-1].a != d->ofs) { oself = QCC_GetTemp(type_entity); @@ -3493,7 +3518,7 @@ QCC_def_t *QCC_PR_ParseFunctionCall (QCC_def_t *func) //warning, the func could { char genfunc[2048]; sprintf(genfunc, "Class*%s", rettype->name); - func = QCC_PR_GetDef(type_function, genfunc, NULL, true, 1, false); + func = QCC_PR_GetDef(type_function, genfunc, NULL, true, 0, false); func->references++; } QCC_PR_SimpleStatement(OP_CALL0, func->ofs, 0, 0, false); @@ -3641,7 +3666,7 @@ QCC_def_t *QCC_PR_ParseFunctionCall (QCC_def_t *func) //warning, the func could if (pr_classtype && e->type->type == ev_field && p->type != ev_field) { //convert. - oself = QCC_PR_GetDef(type_entity, "self", NULL, true, 1, false); + oself = QCC_PR_GetDef(type_entity, "self", NULL, true, 0, false); switch(e->type->aux_type->type) { case ev_string: @@ -3766,7 +3791,7 @@ QCC_def_t *QCC_MakeIntConst(int value) cn->constant = true; cn->initialized = 1; cn->scope = NULL; // always share immediates - cn->arraysize = 1; + cn->arraysize = 0; if (!value) G_INT(cn->ofs) = 0; @@ -3818,7 +3843,7 @@ QCC_def_t *QCC_MakeVectorConst(float a, float b, float c) cn->constant = true; cn->initialized = 1; cn->scope = NULL; // always share immediates - cn->arraysize = 1; + cn->arraysize = 0; // copy the immediate to the global area cn->ofs = QCC_GetFreeOffsetSpace (type_size[type_vector->type]); @@ -3859,7 +3884,7 @@ QCC_def_t *QCC_MakeFloatConst(float value) cn->constant = true; cn->initialized = 1; cn->scope = NULL; // always share immediates - cn->arraysize = 1; + cn->arraysize = 0; // copy the immediate to the global area cn->ofs = QCC_GetFreeOffsetSpace (type_size[type_integer->type]); @@ -3905,7 +3930,7 @@ static QCC_def_t *QCC_MakeStringConstInternal(char *value, pbool translate) cn->constant = true; cn->initialized = 1; cn->scope = NULL; // always share immediates - cn->arraysize = 1; + cn->arraysize = 0; // copy the immediate to the global area cn->ofs = QCC_GetFreeOffsetSpace (type_size[type_integer->type]); @@ -4011,7 +4036,7 @@ void QCC_PR_EmitFieldsForMembers(QCC_type_t *clas) f = QCC_MemberInParentClass(mt->name, clas->parentclass); if (f) { - if (m->arraysize>1) + if (m->arraysize) QCC_Error(ERR_INTERNAL, "FTEQCC does not support overloaded arrays of members"); a=0; for (o = 0; o < m->type->size; o++) @@ -4019,7 +4044,7 @@ void QCC_PR_EmitFieldsForMembers(QCC_type_t *clas) continue; } - for (a = 0; a < m->arraysize; a++) + for (a = 0; a < (m->arraysize?m->arraysize:1); a++) { /*if it was already set, don't go recursive and generate 500 fields for a one-member class that was intheritted from 500 times*/ if (((int *)qcc_pr_globals)[o+a*mt->size+m->ofs]) @@ -4032,7 +4057,7 @@ void QCC_PR_EmitFieldsForMembers(QCC_type_t *clas) ft->size = ft->aux_type->size; ft = QCC_PR_FindType(ft); sprintf(membername, "__f_%s_%i", ft->name, ++basictypefield[mt->type]); - f = QCC_PR_GetDef(ft, membername, NULL, true, 1, true); + f = QCC_PR_GetDef(ft, membername, NULL, true, 0, true); for (o = 0; o < m->type->size; o++) ((int *)qcc_pr_globals)[o+a*mt->size+m->ofs] = ((int *)qcc_pr_globals)[o+f->ofs]; @@ -4071,7 +4096,7 @@ void QCC_PR_EmitClassFunctionTable(QCC_type_t *clas, QCC_type_t *childclas, QCC_ if (type->type == ev_function) //FIXME: inheritance will not install all the member functions. { sprintf(membername, "%s::"MEMBERFIELDNAME, clas->name, type->name); - member = QCC_PR_GetDef(NULL, membername, NULL, false, 1, false); + member = QCC_PR_GetDef(NULL, membername, NULL, false, 0, false); if (!member) { QCC_PR_Warning(0, NULL, 0, "Member function %s was not defined", membername); @@ -4083,7 +4108,7 @@ void QCC_PR_EmitClassFunctionTable(QCC_type_t *clas, QCC_type_t *childclas, QCC_ } point = QCC_PR_Statement(&pr_opcodes[OP_ADDRESS], ed, member, NULL); sprintf(membername, "%s::%s", clas->name, type->name); - virt = QCC_PR_GetDef(type, membername, NULL, false, 1, false); + virt = QCC_PR_GetDef(type, membername, NULL, false, 0, false); QCC_PR_Statement(&pr_opcodes[OP_STOREP_FNC], virt, point, NULL); } } @@ -4131,7 +4156,7 @@ void QCC_PR_EmitClassFromFunction(QCC_def_t *scope, char *tname) G_FUNCTION(scope->ofs) = df - functions; //locals here... - ed = QCC_PR_GetDef(type_entity, "ent", pr_scope, true, 1, false); + ed = QCC_PR_GetDef(type_entity, "ent", pr_scope, true, 0, false); virt = QCC_PR_GetDef(type_function, "spawn", NULL, false, 0, false); if (!virt) @@ -4148,7 +4173,7 @@ void QCC_PR_EmitClassFromFunction(QCC_def_t *scope, char *tname) if (constructor) { //self = ent; self = QCC_PR_GetDef(type_entity, "self", NULL, false, 0, false); - oself = QCC_PR_GetDef(type_entity, "oself", scope, true, 1, false); + oself = QCC_PR_GetDef(type_entity, "oself", scope, true, 0, false); QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_ENT], self, oself, NULL)); QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_ENT], ed, self, NULL)); //return to our old self. boom boom. QCC_PR_SimpleStatement(OP_CALL0, constructor->ofs, 0, 0, false); @@ -4237,26 +4262,26 @@ QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign) (!strcmp(name, "entnum")) || (!strcmp(name, "_"))) //intrinsics, any old function with no args will do. { - d = QCC_PR_GetDef (type_function, name, NULL, true, 1, false); + d = QCC_PR_GetDef (type_function, name, NULL, true, 0, false); d->initialized = 0; } else if (keyword_class && !strcmp(name, "this")) { if (!pr_classtype) QCC_PR_ParseError(ERR_NOTANAME, "Cannot use 'this' outside of an OO function\n"); - od = QCC_PR_GetDef(NULL, "self", NULL, true, 1, false); - d = QCC_PR_DummyDef(pr_classtype, "this", pr_scope, 1, od->ofs, true, false); + od = QCC_PR_GetDef(NULL, "self", NULL, true, 0, false); + d = QCC_PR_DummyDef(pr_classtype, "this", pr_scope, 0, od->ofs, true, false); } else if (keyword_class && !strcmp(name, "super")) { if (!pr_classtype) QCC_PR_ParseError(ERR_NOTANAME, "Cannot use 'super' outside of an OO function\n"); - od = QCC_PR_GetDef(NULL, "self", NULL, true, 1, false); - d = QCC_PR_DummyDef(pr_classtype, "super", pr_scope, 1, od->ofs, true, false); + od = QCC_PR_GetDef(NULL, "self", NULL, true, 0, false); + d = QCC_PR_DummyDef(pr_classtype, "super", pr_scope, 0, od->ofs, true, false); } else { - d = QCC_PR_GetDef (type_variant, name, pr_scope, true, 1, false); + d = QCC_PR_GetDef (type_variant, name, pr_scope, true, 0, false); if (!d) QCC_PR_ParseError (ERR_UNKNOWNVALUE, "Unknown value \"%s\"", name); else @@ -4275,7 +4300,7 @@ QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign) tmp = QCC_PR_Expression (TOP_PRIORITY, 0); QCC_PR_Expect("]"); - if (!idx && t->type == ev_pointer && d->arraysize == 1) + if (!idx && t->type == ev_pointer && !d->arraysize) t = t->aux_type; if (!idx && d->type->type == ev_pointer) @@ -4284,7 +4309,7 @@ QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign) } else if (tmp->constant) { - int i; + unsigned int i; if (tmp->type->type == ev_integer) i = G_INT(tmp->ofs); else if (tmp->type->type == ev_float) @@ -4314,7 +4339,7 @@ QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign) } else if ((t->type == ev_pointer || t->type == ev_struct || t->type == ev_union) && (QCC_PR_CheckToken(".") || QCC_PR_CheckToken("->"))) { - if (!idx && t->type == ev_pointer && d->arraysize == 1) + if (!idx && t->type == ev_pointer && !d->arraysize) t = t->aux_type; for (t = t->param; t; t = t->next) @@ -4422,7 +4447,7 @@ QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign) d->references++; tmp = (void *)qccHunkAlloc (sizeof(QCC_def_t)); memcpy (tmp, d, sizeof(QCC_def_t)); - tmp->arraysize = 1; + tmp->arraysize = 0; tmp->ofs = d->ofs + (cidx * type_size[d->type->type]); d = tmp; @@ -4434,7 +4459,7 @@ QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign) QCC_def_t *args[2], *funcretr, *rhs; d->references++; - funcretr = QCC_PR_GetDef(type_function, qcva("ArraySet*%s", d->name), NULL, true, 1, false); + funcretr = QCC_PR_GetDef(type_function, qcva("ArraySet*%s", d->name), NULL, true, 0, false); rhs = QCC_PR_Expression(TOP_PRIORITY, 0); if (rhs->type->type != d->type->type) @@ -4448,28 +4473,34 @@ QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign) } else if (QCC_OPCodeValid(&pr_opcodes[OP_FETCH_GBL_F])) { + if (!d->arraysize) + QCC_PR_ParseErrorPrintDef(ERR_TYPEMISMATCH, d, "array lookup on non-array"); + + if (d->temp) + QCC_PR_ParseErrorPrintDef(ERR_TYPEMISMATCH, d, "array lookup on a temp"); + /*hexen2 format has opcodes to read arrays (but has no way to write)*/ switch(t->type) { case ev_float: d = QCC_PR_Statement(&pr_opcodes[OP_FETCH_GBL_F], d, QCC_SupplyConversion(idx, ev_float, true), &st); //get pointer to precise def. - st->a = d->ofs; +// st->a = d->ofs; break; case ev_vector: d = QCC_PR_Statement(&pr_opcodes[OP_FETCH_GBL_V], d, QCC_SupplyConversion(idx, ev_float, true), &st); //get pointer to precise def. - st->a = d->ofs; +// st->a = d->ofs; break; case ev_string: d = QCC_PR_Statement(&pr_opcodes[OP_FETCH_GBL_S], d, QCC_SupplyConversion(idx, ev_float, true), &st); //get pointer to precise def. - st->a = d->ofs; +// st->a = d->ofs; break; case ev_entity: d = QCC_PR_Statement(&pr_opcodes[OP_FETCH_GBL_E], d, QCC_SupplyConversion(idx, ev_float, true), &st); //get pointer to precise def. - st->a = d->ofs; +// st->a = d->ofs; break; case ev_function: d = QCC_PR_Statement(&pr_opcodes[OP_FETCH_GBL_FNC], d, QCC_SupplyConversion(idx, ev_float, true), &st); //get pointer to precise def. - st->a = d->ofs; +// st->a = d->ofs; break; default: QCC_PR_ParseError(ERR_NOVALIDOPCODES, "No op available. Try assembler"); @@ -4487,7 +4518,7 @@ QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign) /*make sure the function type that we're calling exists*/ def_parms[0].type = type_float; - funcretr = QCC_PR_GetDef(type_function, qcva("ArrayGet*%s", d->name), NULL, true, 1, false); + funcretr = QCC_PR_GetDef(type_function, qcva("ArrayGet*%s", d->name), NULL, true, 0, false); args[0] = QCC_SupplyConversion(idx, ev_float, true); d = QCC_PR_GenerateFunctionCall(funcretr, args, 1); @@ -4793,8 +4824,12 @@ QCC_def_t *QCC_PR_Term (void) QCC_PR_Expect (")"); e = QCC_PR_Expression (UNARY_PRIORITY, EXPR_DISALLOW_COMMA); + /*you may cast from a type to itself*/ + if (!typecmp(e->type, newtype)) + { + } /*you may cast from const 0 to any type of same size for free (from either int or float for simplicity)*/ - if (newtype->size == e->type->size && (e->type->type == ev_integer || e->type->type == ev_float) && e->constant && !G_INT(e->ofs)) + else if (newtype->size == e->type->size && (e->type->type == ev_integer || e->type->type == ev_float) && e->constant && !G_INT(e->ofs)) { } /*cast from int->float will convert*/ @@ -5007,8 +5042,8 @@ QCC_def_t *QCC_PR_Expression (int priority, int exprflags) if (pr_token_type == tt_immediate) { - if (pr_immediate_type->type == ev_float) - if (pr_immediate._float < 0) //hehehe... was a minus all along... + if ((pr_immediate_type->type == ev_float && pr_immediate._float < 0) || + (pr_immediate_type->type == ev_integer && pr_immediate._int < 0)) //hehehe... was a minus all along... { QCC_PR_IncludeChunk(pr_token, true, NULL); strcpy(pr_token, "+");//two negatives would make a positive. @@ -5137,6 +5172,7 @@ QCC_def_t *QCC_PR_Expression (int priority, int exprflags) {//assignment if (op->type_a == &type_pointer) //ent var { + /*FIXME: I don't like this code*/ if (e->type->type != ev_pointer) c = -200; //don't cast to a pointer. else if ((*op->type_c)->type == ev_void && op->type_b == &type_pointer && e2->type->type == ev_pointer) @@ -5151,6 +5187,8 @@ QCC_def_t *QCC_PR_Expression (int priority, int exprflags) c=QCC_canConv(e2, (*op->type_b)->type); if (type_a != (*op->type_a)->type) //in this case, a is the final assigned value c = -300; //don't use this op, as we must not change var b's type + else if ((*op->type_a)->type == ev_pointer && e->type->aux_type->type != (*op->type_a)->aux_type->type) + c = -300; //don't use this op if its a pointer to a different type } } else @@ -5495,7 +5533,7 @@ void QCC_PR_ParseStatement (void) { e = QCC_PR_GetDef(NULL, "__oself", pr_scope, false, 0); e2 = QCC_PR_GetDef(NULL, "self", NULL, false, 0); - QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_ENT], e, QCC_PR_DummyDef(pr_classtype, "self", pr_scope, 1, e2->ofs, false), NULL)); + QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_ENT], e, QCC_PR_DummyDef(pr_classtype, "self", pr_scope, 0, e2->ofs, false), NULL)); }*/ if (QCC_PR_CheckToken (";")) @@ -6439,7 +6477,7 @@ void QCC_PR_ParseState (void) name = QCC_PR_ParseName (); pr_scope = NULL; - def = QCC_PR_GetDef (type_function, name, NULL, true, 1, false); + def = QCC_PR_GetDef (type_function, name, NULL, true, 0, false); pr_scope = sc; QCC_PR_Expect ("]"); @@ -6998,6 +7036,7 @@ void QCC_Marshal_Locals(int first, int laststatement) { QCC_def_t *local; unsigned int newofs; + int size; // if (!opt_overlaptemps) //clear these after each function. we arn't overlapping them so why do we need to keep track of them? // { @@ -7033,9 +7072,11 @@ void QCC_Marshal_Locals(int first, int laststatement) if (local->constant) continue; - newofs += local->type->size*local->arraysize; - if (local->arraysize>1) - newofs++; + size = local->type->size*(local->arraysize?local->arraysize:1); + if (local->arraysize) + size++; + + newofs += size; } locals_start = MAX_REGS; @@ -7052,12 +7093,14 @@ void QCC_Marshal_Locals(int first, int laststatement) if (((int*)qcc_pr_globals)[local->ofs]) QCC_PR_ParseError(ERR_INTERNAL, "Marshall of a set value"); - newofs -= local->type->size*local->arraysize; - if (local->arraysize>1) - newofs--; + size = local->type->size*(local->arraysize?local->arraysize:1); + if (local->arraysize) + size++; - QCC_RemapOffsets(first, laststatement, local->ofs, local->ofs+local->type->size*local->arraysize, newofs); - QCC_FreeOffset(local->ofs, local->type->size*local->arraysize); + newofs -= size; + + QCC_RemapOffsets(first, laststatement, local->ofs, local->ofs+size, newofs); + QCC_FreeOffset(local->ofs, size); local->ofs = newofs; } @@ -7223,7 +7266,7 @@ QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_type_t *type) { if (!*pr_parm_names[i]) QCC_PR_ParseError(ERR_PARAMWITHNONAME, "Parameter is not named"); - defs[i] = QCC_PR_GetDef (parm, pr_parm_names[i], pr_scope, true, 1, false); + defs[i] = QCC_PR_GetDef (parm, pr_parm_names[i], pr_scope, true, 0, false); defs[i]->references++; if (i < MAX_PARMS) @@ -7268,9 +7311,9 @@ QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_type_t *type) /*if (pr_classtype) { QCC_def_t *e, *e2; - e = QCC_PR_GetDef(pr_classtype, "__oself", pr_scope, true, 1); - e2 = QCC_PR_GetDef(type_entity, "self", NULL, true, 1); - QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_ENT], QCC_PR_DummyDef(pr_classtype, "self", pr_scope, 1, e2->ofs, false), e, NULL)); + e = QCC_PR_GetDef(pr_classtype, "__oself", pr_scope, true, 0); + e2 = QCC_PR_GetDef(type_entity, "self", NULL, true, 0); + QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_ENT], QCC_PR_DummyDef(pr_classtype, "self", pr_scope, 0, e2->ofs, false), e, NULL)); }*/ // @@ -7293,7 +7336,7 @@ QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_type_t *type) do { name = QCC_PR_ParseName(); QCC_PR_Expect(":"); - e2 = QCC_PR_GetDef(QCC_PR_ParseType(false, false), name, pr_scope, true, 1, false); + e2 = QCC_PR_GetDef(QCC_PR_ParseType(false, false), name, pr_scope, true, 0, false); QCC_PR_Expect(";"); } while(!QCC_PR_CheckToken("{")); } @@ -7358,7 +7401,7 @@ QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_type_t *type) QCC_def_t *e, *e2; e = QCC_PR_GetDef(NULL, "__oself", pr_scope, false, 0); e2 = QCC_PR_GetDef(NULL, "self", NULL, false, 0); - QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_ENT], e, QCC_PR_DummyDef(pr_classtype, "self", pr_scope, 1, e2->ofs, false), NULL)); + QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_ENT], e, QCC_PR_DummyDef(pr_classtype, "self", pr_scope, 0, e2->ofs, false), NULL)); }*/ QCC_PR_Statement (pr_opcodes, 0,0, NULL); @@ -7476,7 +7519,7 @@ QCC_def_t *QCC_PR_EmitArrayGetVector(QCC_def_t *array) QCC_dfunction_t *df; QCC_def_t *temp, *index, *func; - func = QCC_PR_GetDef(type_function, qcva("ArrayGetVec*%s", array->name), NULL, true, 1, false); + func = QCC_PR_GetDef(type_function, qcva("ArrayGetVec*%s", array->name), NULL, true, 0, false); pr_scope = func; @@ -7492,9 +7535,9 @@ QCC_def_t *QCC_PR_EmitArrayGetVector(QCC_def_t *array) df->parm_size[0] = 1; df->numparms = 1; df->parm_start = numpr_globals; - index = QCC_PR_GetDef(type_float, "index___", func, true, 1, false); + index = QCC_PR_GetDef(type_float, "index___", func, true, 0, false); index->references++; - temp = QCC_PR_GetDef(type_float, "div3___", func, true, 1, false); + temp = QCC_PR_GetDef(type_float, "div3___", func, true, 0, false); locals_end = numpr_globals; df->locals = locals_end - df->parm_start; QCC_PR_Statement3(pr_opcodes+OP_DIV_F, index, QCC_MakeFloatConst(3), temp, false); @@ -7522,7 +7565,7 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, char *arrayname) QCC_def_t *fasttrackpossible; if (flag_fasttrackarrays) - fasttrackpossible = QCC_PR_GetDef(type_float, "__ext__fasttrackarrays", NULL, true, 1, false); + fasttrackpossible = QCC_PR_GetDef(type_float, "__ext__fasttrackarrays", NULL, true, 0, false); else fasttrackpossible = NULL; @@ -7549,7 +7592,7 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, char *arrayname) df->parm_size[0] = 1; df->numparms = 1; df->parm_start = numpr_globals; - index = QCC_PR_GetDef(type_float, "indexg___", def, true, 1, false); + index = QCC_PR_GetDef(type_float, "indexg___", def, true, 0, false); G_FUNCTION(scope->ofs) = df - functions; @@ -7578,8 +7621,8 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, char *arrayname) //we need to work out which part, x/y/z that it's stored in. //0,1,2 = i - ((int)i/3 *) 3; - div3 = QCC_PR_GetDef(type_float, "div3___", def, true, 1, false); - intdiv3 = QCC_PR_GetDef(type_float, "intdiv3___", def, true, 1, false); + div3 = QCC_PR_GetDef(type_float, "div3___", def, true, 0, false); + intdiv3 = QCC_PR_GetDef(type_float, "intdiv3___", def, true, 0, false); eq = QCC_PR_Statement(pr_opcodes+OP_GE_F, index, QCC_MakeFloatConst((float)def->arraysize), NULL); //escape clause - should call some sort of error function instead.. that'd rule! QCC_FreeTemp(QCC_PR_Statement(pr_opcodes+OP_IFNOT_I, eq, 0, &st)); @@ -7594,7 +7637,7 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, char *arrayname) QCC_PR_Statement3(pr_opcodes+OP_STORE_F, index, &def_parms[0], NULL, false); QCC_PR_Statement3(pr_opcodes+OP_CALL1, vectortrick, NULL, NULL, false); vectortrick->references++; - ret = QCC_PR_GetDef(type_vector, "vec__", pr_scope, true, 1, false); + ret = QCC_PR_GetDef(type_vector, "vec__", pr_scope, true, 0, false); ret->references+=4; QCC_PR_Statement3(pr_opcodes+OP_STORE_V, &def_ret, ret, NULL, false); QCC_FreeTemp(&def_ret); @@ -7686,7 +7729,7 @@ void QCC_PR_EmitArraySetFunction(QCC_def_t *scope, char *arrayname) QCC_def_t *fasttrackpossible; if (flag_fasttrackarrays) - fasttrackpossible = QCC_PR_GetDef(type_float, "__ext__fasttrackarrays", NULL, true, 1, false); + fasttrackpossible = QCC_PR_GetDef(type_float, "__ext__fasttrackarrays", NULL, true, 0, false); else fasttrackpossible = NULL; @@ -7706,8 +7749,8 @@ void QCC_PR_EmitArraySetFunction(QCC_def_t *scope, char *arrayname) df->parm_size[1] = def->type->size; df->numparms = 2; df->parm_start = numpr_globals; - index = QCC_PR_GetDef(type_float, "indexs___", def, true, 1, false); - value = QCC_PR_GetDef(def->type, "value___", def, true, 1, false); + index = QCC_PR_GetDef(type_float, "indexs___", def, true, 0, false); + value = QCC_PR_GetDef(def->type, "value___", def, true, 0, false); locals_end = numpr_globals; df->locals = locals_end - df->parm_start; @@ -7781,7 +7824,7 @@ QCC_def_t *QCC_PR_DummyDef(QCC_type_t *type, char *name, QCC_def_t *scope, int a KEYWORD(asm); } - for (a = 0; a < arraysize; a++) + for (a = 0; a < (arraysize?arraysize:1); a++) { if (a == 0) *array = '\0'; @@ -7797,7 +7840,7 @@ QCC_def_t *QCC_PR_DummyDef(QCC_type_t *type, char *name, QCC_def_t *scope, int a def = (void *)qccHunkAlloc (sizeof(QCC_def_t)); memset (def, 0, sizeof(*def)); def->next = NULL; - def->arraysize = arraysize; + def->arraysize = a?0:arraysize; if (name) { pr.def_tail->next = def; @@ -7841,14 +7884,14 @@ QCC_def_t *QCC_PR_DummyDef(QCC_type_t *type, char *name, QCC_def_t *scope, int a { case ev_vector: sprintf(newname, "%s%s.%s", name, array, parttype->name); - QCC_PR_DummyDef(parttype, newname, scope, 1, ofs + type->size*a + parttype->ofs, false, saved); + QCC_PR_DummyDef(parttype, newname, scope, 0, ofs + type->size*a + parttype->ofs, false, saved); sprintf(newname, "%s%s.%s_x", name, array, parttype->name); - QCC_PR_DummyDef(type_float, newname, scope, 1, ofs + type->size*a + parttype->ofs, false, false); + QCC_PR_DummyDef(type_float, newname, scope, 0, ofs + type->size*a + parttype->ofs, false, false); sprintf(newname, "%s%s.%s_y", name, array, parttype->name); - QCC_PR_DummyDef(type_float, newname, scope, 1, ofs + type->size*a + parttype->ofs+1, false, false); + QCC_PR_DummyDef(type_float, newname, scope, 0, ofs + type->size*a + parttype->ofs+1, false, false); sprintf(newname, "%s%s.%s_z", name, array, parttype->name); - QCC_PR_DummyDef(type_float, newname, scope, 1, ofs + type->size*a + parttype->ofs+2, false, false); + QCC_PR_DummyDef(type_float, newname, scope, 0, ofs + type->size*a + parttype->ofs+2, false, false); break; case ev_float: @@ -7861,12 +7904,12 @@ QCC_def_t *QCC_PR_DummyDef(QCC_type_t *type, char *name, QCC_def_t *scope, int a case ev_union: case ev_variant: //for lack of any better alternative sprintf(newname, "%s%s.%s", name, array, parttype->name); - QCC_PR_DummyDef(parttype, newname, scope, 1, ofs + type->size*a + parttype->ofs, false, saved); + QCC_PR_DummyDef(parttype, newname, scope, 0, ofs + type->size*a + parttype->ofs, false, saved); break; case ev_function: sprintf(newname, "%s%s.%s", name, array, parttype->name); - QCC_PR_DummyDef(parttype, newname, scope, 1, ofs + type->size*a +parttype->ofs, false, saved)->initialized = true; + QCC_PR_DummyDef(parttype, newname, scope, 0, ofs + type->size*a +parttype->ofs, false, saved)->initialized = true; break; case ev_void: break; @@ -7877,11 +7920,11 @@ QCC_def_t *QCC_PR_DummyDef(QCC_type_t *type, char *name, QCC_def_t *scope, int a else if (type->type == ev_vector) { //do the vector thing. sprintf(newname, "%s%s_x", name, array); - QCC_PR_DummyDef(type_float, newname, scope, 1, ofs + type->size*a+0, referable, false); + QCC_PR_DummyDef(type_float, newname, scope, 0, ofs + type->size*a+0, referable, false); sprintf(newname, "%s%s_y", name, array); - QCC_PR_DummyDef(type_float, newname, scope, 1, ofs + type->size*a+1, referable, false); + QCC_PR_DummyDef(type_float, newname, scope, 0, ofs + type->size*a+1, referable, false); sprintf(newname, "%s%s_z", name, array); - QCC_PR_DummyDef(type_float, newname, scope, 1, ofs + type->size*a+2, referable, false); + QCC_PR_DummyDef(type_float, newname, scope, 0, ofs + type->size*a+2, referable, false); } else if (type->type == ev_field) { @@ -7889,11 +7932,11 @@ QCC_def_t *QCC_PR_DummyDef(QCC_type_t *type, char *name, QCC_def_t *scope, int a { //do the vector thing. sprintf(newname, "%s%s_x", name, array); - QCC_PR_DummyDef(type_floatfield, newname, scope, 1, ofs + type->size*a+0, referable, false); + QCC_PR_DummyDef(type_floatfield, newname, scope, 0, ofs + type->size*a+0, referable, false); sprintf(newname, "%s%s_y", name, array); - QCC_PR_DummyDef(type_floatfield, newname, scope, 1, ofs + type->size*a+1, referable, false); + QCC_PR_DummyDef(type_floatfield, newname, scope, 0, ofs + type->size*a+1, referable, false); sprintf(newname, "%s%s_z", name, array); - QCC_PR_DummyDef(type_floatfield, newname, scope, 1, ofs + type->size*a+2, referable, false); + QCC_PR_DummyDef(type_floatfield, newname, scope, 0, ofs + type->size*a+2, referable, false); } } first->deftail = pr.def_tail; @@ -7903,7 +7946,7 @@ QCC_def_t *QCC_PR_DummyDef(QCC_type_t *type, char *name, QCC_def_t *scope, int a { if (!pHash_Get(&globalstable, "end_sys_fields")) first->references++; //anything above needs to be left in, and so warning about not using it is just going to pee people off. - if (arraysize <= 1 && first->type->type != ev_field) + if (!arraysize && first->type->type != ev_field) first->constant = false; if (scope) pHash_Add(&localstable, first->name, first, qccHunkAlloc(sizeof(bucket_t))); @@ -7923,6 +7966,9 @@ PR_GetDef If type is NULL, it will match any type If allocate is true, a new def will be allocated if it can't be found +If arraysize=0, its not an array and has 1 element. +If arraysize>0, its an array and requires array notation +If arraysize<0, its an array with undefined size - GetDef will fail if its not already allocated. ============ */ @@ -7934,6 +7980,9 @@ QCC_def_t *QCC_PR_GetDef (QCC_type_t *type, char *name, QCC_def_t *scope, pbool unsigned int i; QCC_def_t *foundstatic = NULL; + if (!allocate) + arraysize = -1; + if (scope) { def = Hash_Get(&localstable, name); @@ -7948,7 +7997,7 @@ QCC_def_t *QCC_PR_GetDef (QCC_type_t *type, char *name, QCC_def_t *scope, pbool if (type && typecmp(def->type, type)) QCC_PR_ParseErrorPrintDef (ERR_TYPEMISMATCHREDEC, def, "Type mismatch on redeclaration of %s. %s, should be %s",name, TypeName(type), TypeName(def->type)); - if (def->arraysize != arraysize && arraysize) + if (def->arraysize != arraysize && arraysize>=0) QCC_PR_ParseErrorPrintDef (ERR_TYPEMISMATCHARRAYSIZE, def, "Array sizes for redecleration of %s do not match",name); if (allocate && scope) { @@ -7984,7 +8033,7 @@ QCC_def_t *QCC_PR_GetDef (QCC_type_t *type, char *name, QCC_def_t *scope, pbool if (!pr_scope) QCC_PR_ParseErrorPrintDef (ERR_TYPEMISMATCHREDEC, def, "Type mismatch on redeclaration of %s. %s, should be %s",name, TypeName(type), TypeName(def->type)); } - if (def->arraysize != arraysize && arraysize) + if (def->arraysize != arraysize && arraysize>=0) QCC_PR_ParseErrorPrintDef(ERR_TYPEMISMATCHARRAYSIZE, def, "Array sizes for redecleration of %s do not match",name); if (allocate && scope) { @@ -8018,7 +8067,7 @@ QCC_def_t *QCC_PR_GetDef (QCC_type_t *type, char *name, QCC_def_t *scope, pbool if (type && typecmp(def->type, type)) QCC_PR_ParseError (ERR_TYPEMISMATCHREDEC, "Type mismatch on redeclaration of %s. %s, should be %s",name, TypeName(type), TypeName(def->type)); - if (def->arraysize != arraysize && arraysize) + if (def->arraysize != arraysize && arraysize>=0) QCC_PR_ParseError (ERR_TYPEMISMATCHARRAYSIZE, "Array sizes for redecleration of %s do not match",name); if (allocate && scope) { @@ -8054,7 +8103,7 @@ QCC_def_t *QCC_PR_GetDef (QCC_type_t *type, char *name, QCC_def_t *scope, pbool if (!pr_scope) QCC_PR_ParseError (ERR_TYPEMISMATCHREDEC, "Type mismatch on redeclaration of %s. %s, should be %s",name, TypeName(type), TypeName(def->type)); } - if (def->arraysize != arraysize && arraysize) + if (def->arraysize != arraysize && arraysize>=0) QCC_PR_ParseError (ERR_TYPEMISMATCHARRAYSIZE, "Array sizes for redecleration of %s do not match",name); if (allocate && scope) { @@ -8082,7 +8131,7 @@ QCC_def_t *QCC_PR_GetDef (QCC_type_t *type, char *name, QCC_def_t *scope, pbool if (!allocate) return NULL; - if (arraysize < 1) + if (arraysize < 0) { QCC_PR_ParseError (ERR_ARRAYNEEDSSIZE, "First declaration of array %s with no size",name); } @@ -8094,7 +8143,7 @@ QCC_def_t *QCC_PR_GetDef (QCC_type_t *type, char *name, QCC_def_t *scope, pbool } ofs = numpr_globals; - if (arraysize > 1) + if (arraysize) { //write the array size ofs = QCC_GetFreeOffsetSpace(1 + (type->size * arraysize)); @@ -8102,14 +8151,14 @@ QCC_def_t *QCC_PR_GetDef (QCC_type_t *type, char *name, QCC_def_t *scope, pbool ofs++; } else - ofs = QCC_GetFreeOffsetSpace(type->size * arraysize); + ofs = QCC_GetFreeOffsetSpace(type->size); def = QCC_PR_DummyDef(type, name, scope, arraysize, ofs, true, saved); //fix up fields. if (type->type == ev_field && allocate != 2) { - for (i = 0; i < type->size*arraysize; i++) //make arrays of fields work. + for (i = 0; i < type->size*(arraysize?arraysize:1); i++) //make arrays of fields work. *(int *)&qcc_pr_globals[def->ofs+i] = pr.size_fields+i; pr.size_fields += i; @@ -8136,7 +8185,7 @@ QCC_def_t *QCC_PR_DummyFieldDef(QCC_type_t *type, char *name, QCC_def_t *scope, startfield = *fieldofs; maxfield = startfield; - for (a = 0; a < arraysize; a++) + for (a = 0; a < (arraysize?arraysize:1); a++) { if (a == 0) *array = '\0'; @@ -8214,10 +8263,10 @@ QCC_def_t *QCC_PR_DummyFieldDef(QCC_type_t *type, char *name, QCC_def_t *scope, ftype->aux_type = parttype; if (parttype->type == ev_vector) ftype->size = parttype->size; //vector fields create a _y and _z too, so we need this still. - def = QCC_PR_GetDef(NULL, newname, scope, false, 1, saved); + def = QCC_PR_GetDef(NULL, newname, scope, false, 0, saved); if (!def) { - def = QCC_PR_GetDef(ftype, newname, scope, true, 1, saved); + def = QCC_PR_GetDef(ftype, newname, scope, true, 0, saved); } else { @@ -8233,7 +8282,7 @@ QCC_def_t *QCC_PR_DummyFieldDef(QCC_type_t *type, char *name, QCC_def_t *scope, sprintf(newname, "%s%s", parttype->name, array); ftype = QCC_PR_NewType("FIELD TYPE", ev_field); ftype->aux_type = parttype; - def = QCC_PR_GetDef(ftype, newname, scope, true, 1, saved); + def = QCC_PR_GetDef(ftype, newname, scope, true, 0, saved); def->initialized = true; ((int *)qcc_pr_globals)[def->ofs] = *fieldofs; *fieldofs += parttype->size; @@ -8270,13 +8319,13 @@ void QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *def, QCC_type_t *type QCC_def_t *tmp; int i; - if (arraysize > 1) + if (arraysize) { //arrays go recursive QCC_PR_Expect("{"); for (i = 0; i < arraysize; i++) { - QCC_PR_ParseInitializerType(1, def, type, offset + i*type->size); + QCC_PR_ParseInitializerType(0, def, type, offset + i*type->size); if (!QCC_PR_CheckToken(",")) break; } @@ -8377,12 +8426,31 @@ void QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *def, QCC_type_t *type { QCC_def_t *dt; sprintf(trname, "dotranslate_%i", ++dotranslate_count); - dt = QCC_PR_DummyDef(type_string, trname, pr_scope, 1, offset, true, true); + dt = QCC_PR_DummyDef(type_string, trname, pr_scope, 0, offset, true, true); dt->references = 1; dt->constant = 1; dt->initialized = 1; } } + else if (type->type == ev_struct || type->type == ev_union) + { + //structs go recursive + QCC_type_t *parttype; + int partnum; + int parms; + pbool isunion; + QCC_PR_Expect("{"); + + isunion = ((type)->type == ev_union); + for (partnum = 0, parttype = (type)->param, parms = (type)->num_parms; partnum < parms; partnum++, parttype = parttype->next) + { + QCC_PR_ParseInitializerType(parttype->arraysize, def, parttype, offset + parttype->ofs); + if (isunion || !QCC_PR_CheckToken(",")) + break; + } + QCC_PR_Expect("}"); + return; + } else { tmp = QCC_PR_Expression(TOP_PRIORITY, EXPR_DISALLOW_COMMA); @@ -8736,7 +8804,7 @@ void QCC_PR_ParseDefs (char *classname) if (accglobalsblock == 3) { if (!QCC_PR_GetDef(type_void, "end_sys_fields", NULL, false, 0, false)) - QCC_PR_GetDef(type_void, "end_sys_fields", NULL, true, 1, false); + QCC_PR_GetDef(type_void, "end_sys_fields", NULL, true, 0, false); } QCC_PR_ParseName(); @@ -8755,11 +8823,11 @@ void QCC_PR_ParseDefs (char *classname) if (accglobalsblock == 3) { if (!QCC_PR_GetDef(type_void, "end_sys_fields", NULL, false, 0, false)) - QCC_PR_GetDef(type_void, "end_sys_fields", NULL, true, 1, false); + QCC_PR_GetDef(type_void, "end_sys_fields", NULL, true, 0, false); } else if (!QCC_PR_GetDef(type_void, "end_sys_globals", NULL, false, 0, false)) - QCC_PR_GetDef(type_void, "end_sys_globals", NULL, true, 1, false); + QCC_PR_GetDef(type_void, "end_sys_globals", NULL, true, 0, false); accglobalsblock = 3; } } @@ -8780,12 +8848,12 @@ void QCC_PR_ParseDefs (char *classname) break; } if (QCC_PR_CheckKeyword(keyword_object, "object")) - QCC_PR_GetDef(type_entity, name, NULL, true, 1, true); + QCC_PR_GetDef(type_entity, name, NULL, true, 0, true); else if (QCC_PR_CheckKeyword(keyword_string, "string")) - QCC_PR_GetDef(type_string, name, NULL, true, 1, true); + QCC_PR_GetDef(type_string, name, NULL, true, 0, true); else if (QCC_PR_CheckKeyword(keyword_real, "real")) { - def = QCC_PR_GetDef(type_float, name, NULL, true, 1, true); + def = QCC_PR_GetDef(type_float, name, NULL, true, 0, true); if (QCC_PR_CheckToken("=")) { G_FLOAT(def->ofs) = pr_immediate._float; @@ -8794,7 +8862,7 @@ void QCC_PR_ParseDefs (char *classname) } else if (QCC_PR_CheckKeyword(keyword_vector, "vector")) { - def = QCC_PR_GetDef(type_vector, name, NULL, true, 1, true); + def = QCC_PR_GetDef(type_vector, name, NULL, true, 0, true); if (QCC_PR_CheckToken("=")) { QCC_PR_Expect("["); @@ -8808,7 +8876,7 @@ void QCC_PR_ParseDefs (char *classname) } } else if (QCC_PR_CheckKeyword(keyword_pfunc, "pfunc")) - QCC_PR_GetDef(type_function, name, NULL, true, 1, true); + QCC_PR_GetDef(type_function, name, NULL, true, 0, true); else QCC_PR_ParseError(ERR_BADNOTTYPE, "Bad type\n"); QCC_PR_Expect (";"); @@ -8835,15 +8903,15 @@ void QCC_PR_ParseDefs (char *classname) break; } if (QCC_PR_CheckKeyword(keyword_object, "object")) - QCC_PR_GetDef(QCC_PR_FieldType(type_entity), name, NULL, true, 1, true); + QCC_PR_GetDef(QCC_PR_FieldType(type_entity), name, NULL, true, 0, true); else if (QCC_PR_CheckKeyword(keyword_string, "string")) - QCC_PR_GetDef(QCC_PR_FieldType(type_string), name, NULL, true, 1, true); + QCC_PR_GetDef(QCC_PR_FieldType(type_string), name, NULL, true, 0, true); else if (QCC_PR_CheckKeyword(keyword_real, "real")) - QCC_PR_GetDef(QCC_PR_FieldType(type_float), name, NULL, true, 1, true); + QCC_PR_GetDef(QCC_PR_FieldType(type_float), name, NULL, true, 0, true); else if (QCC_PR_CheckKeyword(keyword_vector, "vector")) - QCC_PR_GetDef(QCC_PR_FieldType(type_vector), name, NULL, true, 1, true); + QCC_PR_GetDef(QCC_PR_FieldType(type_vector), name, NULL, true, 0, true); else if (QCC_PR_CheckKeyword(keyword_pfunc, "pfunc")) - QCC_PR_GetDef(QCC_PR_FieldType(type_function), name, NULL, true, 1, true); + QCC_PR_GetDef(QCC_PR_FieldType(type_function), name, NULL, true, 0, true); else QCC_PR_ParseError(ERR_BADNOTTYPE, "Bad type\n"); QCC_PR_Expect (";"); @@ -8895,7 +8963,7 @@ void QCC_PR_ParseDefs (char *classname) QCC_PR_Expect("("); type = QCC_PR_ParseFunctionTypeReacc(false, type); QCC_PR_Expect(";"); - def = QCC_PR_GetDef (type, name, NULL, true, 1, false); + def = QCC_PR_GetDef (type, name, NULL, true, 0, false); if (autoprototype) { //ignore the code and stuff @@ -9038,11 +9106,11 @@ void QCC_PR_ParseDefs (char *classname) if (arraysize < 1) { QCC_PR_ParseError (ERR_BADARRAYSIZE, "Definition of array (%s) size is not of a numerical value", name); - arraysize=0; //grrr... + arraysize=1; //grrr... } } else - arraysize = 1; + arraysize = 0; if (QCC_PR_CheckToken("(")) { diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index 2579d9e94..6017cbd50 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -74,6 +74,8 @@ QCC_type_t *type_function;// = {ev_function/*, &def_function*/,NULL,&type_void}; QCC_type_t *type_pointer;// = {ev_pointer/*, &def_pointer*/}; QCC_type_t *type_integer;// = {ev_integer/*, &def_integer*/}; QCC_type_t *type_variant;// = {ev_integer/*, &def_integer*/}; +QCC_type_t *type_floatpointer; +QCC_type_t *type_intpointer; QCC_type_t *type_floatfield;// = {ev_field/*, &def_field*/, NULL, &type_float}; @@ -1367,7 +1369,7 @@ int QCC_PR_LexInteger (void) len++; pr_file_p++; c = *pr_file_p; - } while ((c >= '0' && c<= '9') || c == '.' || (c>='a' && c <= 'f')); + } while ((c >= '0' && c<= '9') || (c == '.'&&pr_file_p[1]!='.') || (c>='a' && c <= 'f')); pr_token[len] = 0; return atoi (pr_token); } @@ -1420,7 +1422,7 @@ void QCC_PR_LexNumber (void) num*=base; num += c -'A'+10; } - else if (c == '.') + else if (c == '.' && pr_file_p[1]!='.') { pr_token[tokenlen++] = c; pr_file_p++; @@ -1447,6 +1449,15 @@ void QCC_PR_LexNumber (void) pr_immediate._float = (float)atof(pr_token); return; } + else if (c == 'f') + { + pr_token[tokenlen++] = c; + pr_token[tokenlen++] = 0; + pr_file_p++; + pr_immediate_type = type_float; + pr_immediate._float = num*sign; + return; + } else if (c == 'i') { pr_token[tokenlen++] = c; @@ -1500,6 +1511,8 @@ float QCC_PR_LexFloat (void) pr_file_p++; c = *pr_file_p; } while ((c >= '0' && c<= '9') || (c == '.'&&pr_file_p[1]!='.')); //only allow a . if the next isn't too... + if (*pr_file_p == 'f') + pr_file_p++; pr_token[len] = 0; return (float)atof (pr_token); } @@ -2561,7 +2574,7 @@ void QCC_PR_Lex (void) QCC_PR_LexNumber(); return; } - if ( (c == '.'&&pr_file_p[1] >='0' && pr_file_p[1] <= '9') || (c >= '0' && c <= '9') || ( c=='-' && pr_file_p[1]>='0' && pr_file_p[1] <='9') ) + if ( (c == '.'&&pr_file_p[1]!='.'&&pr_file_p[1] >='0' && pr_file_p[1] <= '9') || (c >= '0' && c <= '9') || ( c=='-' && pr_file_p[1]>='0' && pr_file_p[1] <='9') ) { pr_token_type = tt_immediate; QCC_PR_LexNumber (); @@ -3469,7 +3482,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) fieldtype = QCC_PR_NewType(newparm->name, ev_field); fieldtype->aux_type = newparm; fieldtype->size = newparm->size; - QCC_PR_GetDef(fieldtype, membername, pr_scope, 2, 1, false); + QCC_PR_GetDef(fieldtype, membername, pr_scope, 2, 0, false); newparm->ofs = 0;//newt->size; @@ -3523,7 +3536,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) else newparm->name = QCC_CopyString("")+strings; newparm->ofs = newt->size; - newt->size += newparm->size*newparm->arraysize; + newt->size += newparm->size*(newparm->arraysize?newparm->arraysize:1); newt->num_parms++; if (type) @@ -3546,6 +3559,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) newparm = NULL; while (!QCC_PR_CheckToken("}")) { + int arraysize; if (QCC_PR_CheckToken(",")) { if (!newparm) @@ -3568,8 +3582,11 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) QCC_PR_Expect(";"); } newparm->ofs = 0; - if (newparm->size > newt->size*newparm->arraysize) - newt->size = newparm->size*newparm->arraysize; + arraysize = newparm->arraysize; + if (!arraysize) + arraysize = 1; + if (newparm->size*arraysize > newt->size) + newt->size = newparm->size*arraysize; newt->num_parms++; if (type) diff --git a/engine/qclib/qccmain.c b/engine/qclib/qccmain.c index 6c5f2beca..abd49242c 100644 --- a/engine/qclib/qccmain.c +++ b/engine/qclib/qccmain.c @@ -247,6 +247,7 @@ compiler_flag_t compiler_flag[] = { {&flag_assume_integer, FLAG_MIDCOMPILE,"assumeint", "Assume Integers", "Numerical constants are assumed to be integers, instead of floats."}, {&pr_subscopedlocals, FLAG_MIDCOMPILE,"subscope", "Subscoped Locals", "Restrict the scope of locals to the block they are actually defined within, as in C."}, {&verbose, FLAG_MIDCOMPILE,"verbose", "Verbose", "Lots of extra compiler messages."}, + {&flag_typeexplicit, FLAG_MIDCOMPILE,"typeexplicit", "Explicit types", "All type conversions must be explicit or directly supported by instruction set."}, {NULL} }; @@ -1610,7 +1611,7 @@ QCC_type_t *QCC_PR_NewType (char *name, int basictype) qcc_typeinfo[numtypeinfos].num_parms = 0; qcc_typeinfo[numtypeinfos].param = NULL; qcc_typeinfo[numtypeinfos].size = type_size[basictype]; - qcc_typeinfo[numtypeinfos].arraysize = 1; + qcc_typeinfo[numtypeinfos].arraysize = 0; numtypeinfos++; @@ -1675,11 +1676,11 @@ void QCC_PR_BeginCompilation (void *memory, int memsize) if (output_parms) { //this tends to confuse the brains out of decompilers. :) numpr_globals = 1; - QCC_PR_GetDef(type_vector, "RETURN", NULL, true, 1, false)->references++; + QCC_PR_GetDef(type_vector, "RETURN", NULL, true, 0, false)->references++; for (i = 0; i < MAX_PARMS; i++) { sprintf(name, "PARM%i", i); - QCC_PR_GetDef(type_vector, name, NULL, true, 1, false)->references++; + QCC_PR_GetDef(type_vector, name, NULL, true, 0, false)->references++; } } else @@ -2768,6 +2769,7 @@ void QCC_SetDefaultProperties (void) qccwarningdisabled[WARN_FTE_SPECIFIC] = true; qccwarningdisabled[WARN_EXTENSION_USED] = true; qccwarningdisabled[WARN_IFSTRING_USED] = true; + qccwarningdisabled[WARN_CORRECTEDRETURNTYPE] = true; diff --git a/engine/qclib/qcdecomp.c b/engine/qclib/qcdecomp.c index 24fc433f6..e488a2fd7 100644 --- a/engine/qclib/qcdecomp.c +++ b/engine/qclib/qcdecomp.c @@ -51,6 +51,8 @@ extern QCC_type_t *type_function;// = {ev_function/*, &def_function*/,NULL,&type // type_function is a void() function used for state defs extern QCC_type_t *type_pointer;// = {ev_pointer/*, &def_pointer*/}; extern QCC_type_t *type_integer;// = {ev_integer/*, &def_integer*/}; +extern QCC_type_t *type_floatpointer; +extern QCC_type_t *type_intpointer; extern QCC_type_t *type_floatfield;// = {ev_field/*, &def_field*/, NULL, &type_float}; QCC_type_t *QCC_PR_NewType (char *name, int basictype); diff --git a/engine/server/net_preparse.c b/engine/server/net_preparse.c index b520e0989..85609ef0a 100644 --- a/engine/server/net_preparse.c +++ b/engine/server/net_preparse.c @@ -655,27 +655,38 @@ void NPP_NQFlush(void) if (cl->state == cs_spawned && ISQWCLIENT(cl)) { char *h2finale = NULL; + char *h2title = NULL; if (cl->zquake_extensions & Z_EXT_SERVERTIME) { - ClientReliableCheckBlock(cl, 6); +/* ClientReliableCheckBlock(cl, 6); ClientReliableWrite_Byte(cl, svc_updatestatlong); ClientReliableWrite_Byte(cl, STAT_TIME); ClientReliableWrite_Long(cl, (int)(sv.world.physicstime * 1000)); cl->nextservertimeupdate = sv.world.physicstime+10; - } +*/ } if (progstype == PROG_H2) { /*hexen2 does something like this in the client, but we don't support those protocols, so translate to something usable*/ - int lookup[13] = {394, 395, 356, 357, 358, 411, 386+6, 386+7, 386+8, 391, 538, 545, 561}; + char *title[13] = {"gfx/finale.lmp", "gfx/meso.lmp", "gfx/egypt.lmp", "gfx/roman.lmp", "gfx/castle.lmp", "gfx/castle.lmp", "gfx/end-1.lmp", "gfx/end-2.lmp", "gfx/end-3.lmp", "gfx/castle.lmp", "gfx/mpend.lmp", "gfx/mpmid.lmp", "gfx/end-3.lmp"}; + int lookup[13] = {394, 395, 396, 397, 358, 411, 386+6, 386+7, 386+8, 391, 538, 545, 561}; if (buffer[1] < 13) + { + h2title = title[buffer[1]]; h2finale = T_GetString(lookup[buffer[1]]); + } } if (h2finale) { - ClientReliableCheckBlock(cl, 16); + ClientReliableCheckBlock(cl, 3 + strlen(h2title) + 3 + strlen(h2finale) + 1); ClientReliableWrite_Byte(cl, svc_finale); + ClientReliableWrite_Byte(cl, '/'); + ClientReliableWrite_Byte(cl, 'I'); + ClientReliableWrite_SZ(cl, h2title, strlen(h2title)); + ClientReliableWrite_Byte(cl, ':'); + ClientReliableWrite_Byte(cl, '/'); + ClientReliableWrite_Byte(cl, 'P'); ClientReliableWrite_String(cl, h2finale); } else diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index c61281850..18584eda9 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -2905,6 +2905,7 @@ static void QCBUILTIN PF_sound (progfuncs_t *prinst, struct globalvars_s *pr_glo int volume; float attenuation; int pitchadj; + int flags; entity = G_EDICT(prinst, OFS_PARM0); channel = G_FLOAT(OFS_PARM1); @@ -2915,6 +2916,15 @@ static void QCBUILTIN PF_sound (progfuncs_t *prinst, struct globalvars_s *pr_glo pitchadj = G_FLOAT(OFS_PARM5); else pitchadj = 0; + if (*svprogfuncs->callargc > 6) + { + flags = G_FLOAT(OFS_PARM5); + if (channel < 0) + channel = 0; + channel &= 7; + } + else + flags = (channel & 8)?1:0; if (volume < 0) //erm... return; @@ -2922,6 +2932,9 @@ static void QCBUILTIN PF_sound (progfuncs_t *prinst, struct globalvars_s *pr_glo if (volume > 255) volume = 255; + if (flags & 1) + channel |= 8; + SVQ1_StartSound ((wedict_t*)entity, channel, sample, volume, attenuation, pitchadj); } @@ -3476,11 +3489,12 @@ static void QCBUILTIN PF_conprint (progfuncs_t *prinst, struct globalvars_s *pr_ Sys_Printf ("%s",PF_VarString(prinst, 0, pr_globals)); } - -static void QCBUILTIN PF_h2printf (progfuncs_t *prinst, struct globalvars_s *pr_globals) +static void QCBUILTIN PF_h2dprintf (progfuncs_t *prinst, struct globalvars_s *pr_globals) { char temp[256]; + char printable[2048]; float v; + char *pct; v = G_FLOAT(OFS_PARM1); @@ -3489,16 +3503,34 @@ static void QCBUILTIN PF_h2printf (progfuncs_t *prinst, struct globalvars_s *pr_ else sprintf (temp, "%5.1f",v); - Con_Printf (PR_GetStringOfs(prinst, OFS_PARM0),temp); + Q_strncpyz(printable, PR_GetStringOfs(prinst, OFS_PARM0), sizeof(printable)); + while(pct = strstr(printable, "%s")) + { + if ((pct-printable) + strlen(temp) + strlen(pct) > sizeof(printable)) + break; + memmove(pct + strlen(temp), pct+2, strlen(pct+2)+1); + memcpy(pct, temp, strlen(temp)); + } + Con_DPrintf ("%s", printable); } -static void QCBUILTIN PF_h2printv (progfuncs_t *prinst, struct globalvars_s *pr_globals) +static void QCBUILTIN PF_h2dprintv (progfuncs_t *prinst, struct globalvars_s *pr_globals) { char temp[256]; + char printable[2048]; + char *pct; sprintf (temp, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM1)[0], G_VECTOR(OFS_PARM1)[1], G_VECTOR(OFS_PARM1)[2]); - Con_Printf (PR_GetStringOfs(prinst, OFS_PARM0),temp); + Q_strncpyz(printable, PR_GetStringOfs(prinst, OFS_PARM0), sizeof(printable)); + while(pct = strstr(printable, "%s")) + { + if ((pct-printable) + strlen(temp) + strlen(pct) > sizeof(printable)) + break; + memmove(pct + strlen(temp), pct+2, strlen(pct+2)+1); + memcpy(pct, temp, strlen(temp)); + } + Con_DPrintf ("%s", printable); } static void QCBUILTIN PF_h2spawn_temp (progfuncs_t *prinst, struct globalvars_s *pr_globals) @@ -3625,7 +3657,7 @@ int PF_precache_model_Internal (progfuncs_t *prinst, char *s, qboolean queryonly sv.strings.model_precache[i] = PR_AddString(prinst, s, 0); s = sv.strings.model_precache[i]; if (!strcmp(s + strlen(s) - 4, ".bsp") || sv_gameplayfix_setmodelrealbox.ival) - sv.models[i] = Mod_FindName(s); + sv.models[i] = Mod_ForName(s, false); else { /*touch the file, so any packs will be referenced*/ @@ -6299,22 +6331,36 @@ void PRH2_SetPlayerClass(client_t *cl, int classnum, qboolean fromqc) { char temp[16]; if (classnum < 1) - return; //reject it (it would crash the (standard hexen2) mod) + return; //reject it (it would crash the (standard hexen2) mod) if (classnum > 5) return; - /*ignore it if they already have a class, this fixes some h2mp crashes*/ - if (cl->playerclass) - return; + if (!fromqc) + { + if (progstype != PROG_H2) + return; + /*if they already have a class, only switch to the class already set by the gamecode + this is awkward, but matches hexen2*/ + if (cl->playerclass) + { + if (cl->edict->xv->playerclass) + classnum = cl->edict->xv->playerclass; + else if (cl->playerclass) + classnum = cl->playerclass; + } + } + + if (classnum) + sprintf(temp,"%i",(int)classnum); + else + *temp = 0; + Info_SetValueForKey (cl->userinfo, "cl_playerclass", temp, sizeof(cl->userinfo)); if (cl->playerclass != classnum) { cl->edict->xv->playerclass = classnum; cl->playerclass = classnum; - sprintf(temp,"%i",(int)classnum); - Info_SetValueForKey (cl->userinfo, "cl_playerclass", temp, sizeof(cl->userinfo)); - if (!fromqc) { cl->sendinfo = true; @@ -6629,6 +6675,31 @@ enum ce_grey_smoke_15, ce_grey_smoke_100, + ce_chunk_1, + ce_chunk_2, + ce_chunk_3, + ce_chunk_4, + ce_chunk_5, + ce_chunk_6, + ce_chunk_7, + ce_chunk_8, + ce_chunk_9, + ce_chunk_10, + ce_chunk_11, + ce_chunk_12, + ce_chunk_13, + ce_chunk_14, + ce_chunk_15, + ce_chunk_16, + ce_chunk_17, + ce_chunk_18, + ce_chunk_19, + ce_chunk_20, + ce_chunk_21, + ce_chunk_22, + ce_chunk_23, + ce_chunk_24, + ce_max }; int h2customtents[ce_max]; @@ -6677,11 +6748,11 @@ void SV_RegisterH2CustomTents(void) h2customtents[ce_magic_missile_explosion] = SV_CustomTEnt_Register("ce_magic_missile_explosion", 0, NULL, 0, NULL, 0, 0, NULL); // ce_ghost h2customtents[ce_bone_explosion] = SV_CustomTEnt_Register("ce_bone_explosion", 0, NULL, 0, NULL, 0, 0, NULL); -// ce_redcloud + h2customtents[ce_redcloud] = SV_CustomTEnt_Register("ce_redcloud", CTE_CUSTOMVELOCITY, NULL, 0, NULL, 0, 0, NULL); h2customtents[ce_teleporterpuffs] = SV_CustomTEnt_Register("ce_teleporterpuffs", 0, NULL, 0, NULL, 0, 0, NULL); h2customtents[ce_teleporterbody] = SV_CustomTEnt_Register("ce_teleporterbody", CTE_CUSTOMVELOCITY, NULL, 0, NULL, 0, 0, NULL); -// ce_boneshard -// ce_boneshrapnel + h2customtents[ce_boneshard] = SV_CustomTEnt_Register("ce_boneshard", CTE_CUSTOMVELOCITY, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_boneshrapnel] = SV_CustomTEnt_Register("ce_boneshrapnel", CTE_CUSTOMVELOCITY, NULL, 0, NULL, 0, 0, NULL); h2customtents[ce_flamestream] = SV_CustomTEnt_Register("ce_flamestream", CTE_CUSTOMVELOCITY, NULL, 0, NULL, 0, 0, NULL); // ce_snow, h2customtents[ce_gravitywell] = SV_CustomTEnt_Register("ce_gravitywell", 0, NULL, 0, NULL, 0, 0, NULL); @@ -6718,6 +6789,31 @@ void SV_RegisterH2CustomTents(void) h2customtents[ce_green_smoke_20] = SV_CustomTEnt_Register("ce_green_smoke_20", CTE_CUSTOMVELOCITY, NULL, 0, NULL, 0, 0, NULL); h2customtents[ce_grey_smoke_15] = SV_CustomTEnt_Register("ce_grey_smoke_15", CTE_CUSTOMVELOCITY, NULL, 0, NULL, 0, 0, NULL); h2customtents[ce_grey_smoke_100] = SV_CustomTEnt_Register("ce_grey_smoke_100", CTE_CUSTOMVELOCITY, NULL, 0, NULL, 0, 0, NULL); + + h2customtents[ce_chunk_1] = SV_CustomTEnt_Register("ce_chunk_greystone", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_chunk_2] = SV_CustomTEnt_Register("ce_chunk_wood", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_chunk_3] = SV_CustomTEnt_Register("ce_chunk_metal", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_chunk_4] = SV_CustomTEnt_Register("ce_chunk_flesh", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_chunk_5] = SV_CustomTEnt_Register("ce_chunk_fire", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_chunk_6] = SV_CustomTEnt_Register("ce_chunk_clay", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_chunk_7] = SV_CustomTEnt_Register("ce_chunk_leaves", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_chunk_8] = SV_CustomTEnt_Register("ce_chunk_hay", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_chunk_9] = SV_CustomTEnt_Register("ce_chunk_brownstone", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_chunk_10] = SV_CustomTEnt_Register("ce_chunk_cloth", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_chunk_11] = SV_CustomTEnt_Register("ce_chunk_wood_leaf", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_chunk_12] = SV_CustomTEnt_Register("ce_chunk_wood_metal", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_chunk_13] = SV_CustomTEnt_Register("ce_chunk_wood_stone", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_chunk_14] = SV_CustomTEnt_Register("ce_chunk_metal_stone", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_chunk_15] = SV_CustomTEnt_Register("ce_chunk_metal_cloth", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_chunk_16] = SV_CustomTEnt_Register("ce_chunk_webs", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_chunk_17] = SV_CustomTEnt_Register("ce_chunk_glass", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_chunk_18] = SV_CustomTEnt_Register("ce_chunk_ice", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_chunk_19] = SV_CustomTEnt_Register("ce_chunk_clearglass", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_chunk_20] = SV_CustomTEnt_Register("ce_chunk_redglass", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_chunk_21] = SV_CustomTEnt_Register("ce_chunk_acid", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_chunk_22] = SV_CustomTEnt_Register("ce_chunk_meteor", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_chunk_23] = SV_CustomTEnt_Register("ce_chunk_greenflesh", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); + h2customtents[ce_chunk_24] = SV_CustomTEnt_Register("ce_chunk_bone", CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL); } } static void QCBUILTIN PF_h2starteffect(progfuncs_t *prinst, struct globalvars_s *pr_globals) @@ -6725,6 +6821,7 @@ static void QCBUILTIN PF_h2starteffect(progfuncs_t *prinst, struct globalvars_s // float *min, *max, *angle, *size; // float colour, wait, radius, frame, framelength, duration; // int flags, type, skin; + int type; float *org, *dir; int count; @@ -6934,17 +7031,22 @@ static void QCBUILTIN PF_h2starteffect(progfuncs_t *prinst, struct globalvars_s break; case ce_chunk: org = G_VECTOR(OFS_PARM1); - //type = G_FLOAT(OFS_PARM2); /*FIXME: discarded*/ + type = G_FLOAT(OFS_PARM2); dir = G_VECTOR(OFS_PARM3); count = G_FLOAT(OFS_PARM4); + /*convert it to the requested chunk type*/ + efnum = ce_chunk_1 + type - 1; + if (efnum < ce_chunk_1 && efnum > ce_chunk_24) + efnum = ce_chunk; + if (h2customtents[efnum] != -1) { SV_CustomTEnt_Spawn(h2customtents[efnum], org, NULL, count, dir); return; } - Con_Printf("FTE-H2 FIXME: ce_chunk not supported!\n"); + Con_Printf("FTE-H2 FIXME: ce_chunk type=%i not supported!\n", type); return; @@ -8482,7 +8584,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"lightstylestatic",PF_lightstylestatic,0, 0, 5, 5, "void(float style, float val)"}, {"break", PF_break, 6, 6, 6, 0, "void()"}, {"random", PF_random, 7, 7, 7, 0, "float()"}, - {"sound", PF_sound, 8, 8, 8, 0, "void(entity e, float chan, string samp, float vol, float atten, optional float speedpct)"}, + {"sound", PF_sound, 8, 8, 8, 0, "void(entity e, float chan, string samp, float vol, float atten, optional float speedpct, optional float flags)"}, {"normalize", PF_normalize, 9, 9, 9, 0, "vector(vector v)"}, {"error", PF_error, 10, 10, 10, 0, "void(string e)"}, {"objerror", PF_objerror, 11, 11, 11, 0, "void(string e)"}, @@ -8561,14 +8663,14 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"bwriteentity", PF_qtBroadcast_WriteEntity}, //66 - {"printfloat", PF_h2printf, 0, 0, 60}, //60 + {"printfloat", PF_h2dprintf, 0, 0, 60}, //60 {"sin", PF_Sin, 0, 0, 62, 60, "float(float angle)"}, //60 {"cos", PF_Cos, 0, 0, 61, 61, "float(float angle)"}, //61 {"sqrt", PF_Sqrt, 0, 0, 84, 62, "float(float value)"}, //62 {"AdvanceFrame", PF_h2AdvanceFrame, 0, 0, 63, 0}, - {"printvec", PF_h2printv, 0, 0, 64, 0}, //64 + {"printvec", PF_h2dprintv, 0, 0, 64, 0}, //64 {"RewindFrame", PF_h2RewindFrame, 0, 0, 65, 0}, {"particleexplosion",PF_h2particleexplosion,0, 0, 81, 0}, {"movestep", PF_h2movestep, 0, 0, 82, 0}, @@ -8761,7 +8863,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"map_builtin", PF_builtinsupported,0, 0, 0, 220, "", true}, //like #100 - takes 2 args. arg0 is builtinname, 1 is number to map to. //FTE_STRINGS - {"strstrofs", PF_strstrofs, 0, 0, 0, 221, "float(string s1, string sub)"}, + {"strstrofs", PF_strstrofs, 0, 0, 0, 221, "float(string s1, string sub, optional float startidx)"}, {"str2chr", PF_str2chr, 0, 0, 0, 222, "float(string str, float index)"}, {"chr2str", PF_chr2str, 0, 0, 0, 223, "string(float chr, ...)"}, {"strconv", PF_strconv, 0, 0, 0, 224, "string(float ccase, float redalpha, float redchars, string str, ...)"}, @@ -8930,6 +9032,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"dynamiclight_get",PF_Fixme, 0, 0, 0, 372, "__variant(float lno, float fld)"}, {"dynamiclight_set",PF_Fixme, 0, 0, 0, 373, "void(float lno, float fld, __variant value)"}, + {"particleeffectquery",PF_Fixme,0, 0, 0, 374, "string(float efnum, float body)"}, //END EXT_CSQC //end fte extras @@ -9766,7 +9869,7 @@ void PR_DumpPlatform_f(void) {"FL_WATERJUMP", "const float", QW|NQ|CS, FL_WATERJUMP}, {"FL_FINDABLE_NONSOLID","const float", QW|NQ|CS, FL_FINDABLE_NONSOLID}, // {"FL_MOVECHAIN_ANGLE", "const float", QW|NQ, FL_MOVECHAIN_ANGLE}, - {"FL_LAGGEDMOVE", "const float", QW|NQ, FL_LAGGEDMOVE}, + {"FL_LAGGEDMOVE", "const float", QW|NQ, FLQW_LAGGEDMOVE}, // {"FL_CLASS_DEPENDENT", "const float", QW|NQ, FL_CLASS_DEPENDENT}, {"MOVE_NORMAL", "const float", QW|NQ|CS, MOVE_NORMAL}, diff --git a/engine/server/savegame.c b/engine/server/savegame.c index 082a1a1cd..91f60fd3d 100644 --- a/engine/server/savegame.c +++ b/engine/server/savegame.c @@ -678,6 +678,7 @@ qboolean SV_LoadLevelCache(char *savename, char *level, char *startspot, qboolea PR_LoadGlabalStruct(); + pr_global_struct->serverflags = svs.serverflags; pr_global_struct->time = sv.time = sv.world.physicstime = time; sv.starttime = Sys_DoubleTime() - sv.time; @@ -740,8 +741,40 @@ qboolean SV_LoadLevelCache(char *savename, char *level, char *startspot, qboolea if (ent->isfree) continue; - World_LinkEdict (&sv.world, (wedict_t*)ent, false); // force retouch even for stationary + World_LinkEdict (&sv.world, (wedict_t*)ent, false); } + for (i=0 ; iisfree) + continue; + + /*hexen2 instead overwrites ents, which can theoretically be unreliable (ents with this flag are not saved in the first place, and thus are effectively reset instead of reloaded). + fte purges all ents beforehand in a desperate attempt to remain sane. + this behaviour does not match exactly, but is enough for vanilla hexen2/POP. + */ + if ((unsigned int)ent->v->flags & FL_HUBSAVERESET) + { + func_t f; + /*set some minimal fields*/ + ent->v->solid = SOLID_NOT; + ent->v->use = 0; + ent->v->touch = 0; + ent->v->think = 0; + ent->v->nextthink = 0; + /*reinvoke the spawn function*/ + pr_global_struct->time = 0.1; + pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, ent); + f = PR_FindFunction(svprogfuncs, PR_GetString(svprogfuncs, ent->v->classname), PR_ANY); + + svprogfuncs->ToggleBreak(svprogfuncs, PR_GetString(svprogfuncs, ent->v->classname), 0, 1); + svprogfuncs->ToggleBreak(svprogfuncs, "trigger_crosslevel_target_think", 0, 1); + + if (f) + PR_ExecuteProgram(svprogfuncs, f); + } + } + pr_global_struct->time = sv.world.physicstime; return true; //yay } @@ -836,6 +869,7 @@ void SV_SaveLevelCache(char *savedir, qboolean dontharmgame) // this will set the body to a dead frame, among other things pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, cl->edict); PR_ExecuteProgram (svprogfuncs, pr_global_struct->ClientDisconnect); + sv.spawned_client_slots--; } else if (SpectatorDisconnect) { @@ -866,7 +900,7 @@ void SV_SaveLevelCache(char *savedir, qboolean dontharmgame) for (i=1 ; iv->origin, viewer->v->view_ofs, start); tr.fraction = 1; - if (!sv.world.worldmodel->funcs.Trace (sv.world.worldmodel, 1, 0, NULL, start, seen->v->origin, vec3_origin, vec3_origin, &tr)) + if (!sv.world.worldmodel->funcs.NativeTrace (sv.world.worldmodel, 1, 0, NULL, start, seen->v->origin, vec3_origin, vec3_origin, FTECONTENTS_SOLID, &tr)) return false; //wasn't blocked //stage 2: check against their bbox @@ -1427,7 +1427,7 @@ qboolean Cull_Traceline(edict_t *viewer, edict_t *seen) end[2] = seen->v->origin[2] + ((i&4)?seen->v->mins[2]+0.1:seen->v->maxs[2]); tr.fraction = 1; - if (!sv.world.worldmodel->funcs.Trace (sv.world.worldmodel, 1, 0, NULL, start, end, vec3_origin, vec3_origin, &tr)) + if (!sv.world.worldmodel->funcs.NativeTrace (sv.world.worldmodel, 1, 0, NULL, start, end, vec3_origin, vec3_origin, FTECONTENTS_SOLID, &tr)) return false; //this trace went through, so don't cull } diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 136aa6eec..39eda2099 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -1477,7 +1477,8 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us SV_FilterImpulseInit(); Info_SetValueForKey (svs.info, "map", sv.name, MAX_SERVERINFO_STRING); - Con_TPrintf (STL_SERVERSPAWNED); //misc filenotfounds can be misleading. + if (sv.allocated_client_slots != 1) + Con_TPrintf (STL_SERVERSPAWNED); //misc filenotfounds can be misleading. if (!startspot) { @@ -1536,6 +1537,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us pr_global_struct->time = sv.world.physicstime; pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv_player); PR_ExecuteProgram (svprogfuncs, pr_global_struct->PutClientInServer); + sv.spawned_client_slots++; // send notification to all clients host_client->sendinfo = true; diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index ed7fb5da7..0b91f31d3 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -127,6 +127,7 @@ cvar_t allow_download_textures = CVAR("allow_download_textures", "1"); cvar_t allow_download_packages = CVAR("allow_download_packages", "1"); cvar_t allow_download_wads = CVAR("allow_download_wads", "1"); cvar_t allow_download_configs = CVAR("allow_download_configs", "0"); +cvar_t allow_download_copyrighted = CVAR("allow_download_copyrighted", "0"); cvar_t sv_public = CVAR("sv_public", "0"); cvar_t sv_listen_qw = CVARAF("sv_listen_qw", "1", "sv_listen", 0); @@ -490,6 +491,7 @@ void SV_DropClient (client_t *drop) pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, drop->edict); if (pr_global_ptrs->ClientDisconnect) PR_ExecuteProgram (svprogfuncs, pr_global_struct->ClientDisconnect); + sv.spawned_client_slots--; } else if (SpectatorDisconnect) { @@ -3475,6 +3477,7 @@ void SV_CheckTimeouts (void) { pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, cl->edict); PR_ExecuteProgram (svprogfuncs, pr_global_struct->ClientDisconnect); + sv.spawned_client_slots--; host_client->istobeloaded=false; @@ -3635,6 +3638,7 @@ void SV_Impulse_f (void) pr_global_struct->time = sv.world.physicstime; pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, svs.clients[i].edict); PR_ExecuteProgram (svprogfuncs, pr_global_struct->PutClientInServer); + sv.spawned_client_slots++; pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, svs.clients[i].edict); PR_ExecuteProgram (svprogfuncs, pr_global_struct->PlayerPreThink); @@ -3654,6 +3658,7 @@ void SV_Impulse_f (void) pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, svs.clients[i].edict); PR_ExecuteProgram (svprogfuncs, pr_global_struct->ClientDisconnect); + sv.spawned_client_slots--; svs.clients[i].state = cs_free; } @@ -3709,7 +3714,11 @@ float SV_Frame (void) sv.gamespeed = 1; #ifndef SERVERONLY - if ((sv.paused & 4) != ((!isDedicated && sv.allocated_client_slots == 1 && key_dest != key_game && cls.state == ca_active)?4:0)) + isidle = !isDedicated && sv.allocated_client_slots == 1 && key_dest != key_game && cls.state == ca_active; + /*server is effectively paused if there are no clients*/ + if (sv.spawned_client_slots == 0) + isidle = true; + if ((sv.paused & 4) != (isidle?4:0)) sv.paused ^= 4; #endif @@ -3730,15 +3739,14 @@ float SV_Frame (void) timedelta = 0; } + if (isDedicated) + realtime += sv.time - oldtime; + if (sv.paused && sv.time > 1.5) { sv.starttime += sv.time - oldtime; //move the offset sv.time = oldtime; //and keep time as it was. } - - if (isDedicated) - realtime += sv.time - oldtime; - } @@ -3797,7 +3805,7 @@ void SV_MVDStream_Poll(void); } // move autonomous things around if enough time has passed - if (!sv.paused || sv.time < 1.5) + if (!sv.paused || (sv.world.physicstime < 1 && sv.spawned_client_slots)) { #ifdef Q2SERVER //q2 is idle even if clients sent packets. @@ -4036,6 +4044,7 @@ void SV_InitLocal (void) Cvar_Register (&allow_download_packages,cvargroup_serverpermissions); Cvar_Register (&allow_download_wads, cvargroup_serverpermissions); Cvar_Register (&allow_download_root, cvargroup_serverpermissions); + Cvar_Register (&allow_download_copyrighted, cvargroup_serverpermissions); Cvar_Register (&secure, cvargroup_serverpermissions); Cvar_Register (&sv_highchars, cvargroup_servercontrol); diff --git a/engine/server/sv_move.c b/engine/server/sv_move.c index 553c94ce3..32a80c29a 100644 --- a/engine/server/sv_move.c +++ b/engine/server/sv_move.c @@ -121,13 +121,17 @@ qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, qboolean re trace_t trace; int i; wedict_t *enemy = world->edicts; + int eflags = ent->v->flags; + + if (progstype != PROG_H2) + eflags &= ~FLH2_NOZ|FLH2_HUNTFACE; // try the move VectorCopy (ent->v->origin, oldorg); VectorAdd (ent->v->origin, move, neworg); // flying monsters don't step up - if ( (int)ent->v->flags & (FL_SWIM | FL_FLY) ) + if ( eflags & (FL_SWIM | FL_FLY) && !(eflags & (FLH2_NOZ|FLH2_HUNTFACE))) { // try one move with vertical motion, then one without for (i=0 ; i<2 ; i++) @@ -139,6 +143,8 @@ qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, qboolean re if (i == 0 && enemy->entnum) { dz = ent->v->origin[2] - ((wedict_t*)PROG_TO_EDICT(world->progs, ent->v->enemy))->v->origin[2]; + if (eflags & FLH2_HUNTFACE) /*get the ent's origin_z to match its victims face*/ + dz += ((wedict_t*)PROG_TO_EDICT(world->progs, ent->v->enemy))->v->view_ofs[2]; if (dz > 40) neworg[2] -= 8; if (dz < 30) @@ -151,7 +157,7 @@ qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, qboolean re if (trace.fraction == 1) { - if ( ((int)ent->v->flags & FL_SWIM) && !(World_PointContents(world, trace.endpos) & FTECONTENTS_FLUID)) + if ( (eflags & FL_SWIM) && !(World_PointContents(world, trace.endpos) & FTECONTENTS_FLUID)) continue; // swim monster left water VectorCopy (trace.endpos, ent->v->origin); @@ -301,6 +307,8 @@ qboolean World_StepDirection (world_t *world, wedict_t *ent, float yaw, float di move[1] = sin(yaw)*dist; move[2] = 0; + //FIXME: Hexen2: ent flags & FL_SET_TRACE + VectorCopy (ent->v->origin, oldorigin); if (World_movestep (world, ent, move, false, false, NULL, NULL)) { diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index 80a7c838e..838fbffc1 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -478,7 +478,7 @@ static trace_t WPhys_PushEntity (world_t *w, wedict_t *ent, vec3_t push, unsigne VectorAdd (ent->v->origin, push, end); - if ((int)ent->v->flags&FL_LAGGEDMOVE) + if ((int)ent->v->flags&FLQW_LAGGEDMOVE) traceflags |= MOVE_LAGGED; if (ent->v->movetype == MOVETYPE_FLYMISSILE) @@ -489,6 +489,17 @@ static trace_t WPhys_PushEntity (world_t *w, wedict_t *ent, vec3_t push, unsigne else trace = World_Move (w, ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL|traceflags, (wedict_t*)ent); + /*hexen2's movetype_swim does not allow swimming entities to move out of water. this implementation is quite hacky, but matches hexen2 well enough*/ + if (ent->v->movetype == MOVETYPE_H2SWIM) + { + if (!(w->worldmodel->funcs.PointContents(w->worldmodel, NULL, trace.endpos) & (FTECONTENTS_WATER|FTECONTENTS_SLIME|FTECONTENTS_LAVA))) + { + VectorCopy(ent->v->origin, trace.endpos); + trace.fraction = 0; + trace.ent = w->edicts; + } + } + // if (trace.ent) // VectorMA(trace.endpos, sv_impactpush.value, trace.plane.normal, ent->v->origin); // else @@ -547,8 +558,6 @@ static qboolean WPhys_PushAngles (world_t *w, wedict_t *pusher, vec3_t move, vec pushed_p->ent = pusher; VectorCopy (pusher->v->origin, pushed_p->origin); VectorCopy (pusher->v->angles, pushed_p->angles); -// if (pusher->client) -// pushed_p->deltayaw = pusher->client->ps.pmove.delta_angles[YAW]; pushed_p++; // move the pusher to it's final position @@ -569,17 +578,12 @@ static qboolean WPhys_PushAngles (world_t *w, wedict_t *pusher, vec3_t move, vec || check->v->movetype == MOVETYPE_ANGLENOCLIP) continue; -#if 1 oldsolid = pusher->v->solid; pusher->v->solid = SOLID_NOT; block = World_TestEntityPosition (w, check); pusher->v->solid = oldsolid; if (block) continue; -#else - if (!check->area.prev) - continue; // not linked in anywhere -#endif // if the entity is standing on the pusher, it will definitely be moved if ( ! ( ((int)check->v->flags & FL_ONGROUND) @@ -610,10 +614,6 @@ static qboolean WPhys_PushAngles (world_t *w, wedict_t *pusher, vec3_t move, vec // try moving the contacted entity VectorAdd (check->v->origin, move, check->v->origin); -// if (check->client) -// { // FIXME: doesn't rotate monsters? -// check->client->ps.pmove.delta_angles[YAW] += amove[YAW]; -// } VectorAdd (check->v->angles, amove, check->v->angles); // figure movement due to the pusher's amove @@ -679,10 +679,6 @@ static qboolean WPhys_PushAngles (world_t *w, wedict_t *pusher, vec3_t move, vec { VectorCopy (p->origin, p->ent->v->origin); VectorCopy (p->angles, p->ent->v->angles); -// if (p->ent->client) -// { -// p->ent->client->ps.pmove.delta_angles[YAW] = p->deltayaw; -// } World_LinkEdict (w, p->ent, false); } return false; @@ -1765,7 +1761,7 @@ static void WPhys_WalkMove (world_t *w, wedict_t *ent) } #endif -static void WPhys_MoveChain(world_t *w, wedict_t *ent, wedict_t *movechain, float *initial_origin, float *initial_angle) +void WPhys_MoveChain(world_t *w, wedict_t *ent, wedict_t *movechain, float *initial_origin, float *initial_angle) { qboolean callfunc; if ((callfunc=DotProduct(ent->v->origin, initial_origin)) || DotProduct(ent->v->angles, initial_angle)) diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index def217697..b94d7fa9c 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -1646,6 +1646,8 @@ void SV_Begin_Core(client_t *split) } else { + sv.spawned_client_slots++; + if (svprogfuncs) { eval_t *eval, *eval2; @@ -2468,6 +2470,16 @@ qboolean SV_AllowDownload (const char *name) extern cvar_t allow_download_wads; extern cvar_t allow_download_root; extern cvar_t allow_download_configs; + extern cvar_t allow_download_copyrighted; + char cleanname[MAX_QPATH]; + int i=0; + if (strlen(name) >= MAX_QPATH) + return false; + do + { + cleanname[i++] = *name; + } while(*name++); + name = cleanname; //allowed at all? if (!allow_download.value) @@ -2488,8 +2500,10 @@ qboolean SV_AllowDownload (const char *name) if (!strcmp("pk4", COM_FileExtension(name)) || !strcmp("pk3", COM_FileExtension(name)) || !strcmp("pak", COM_FileExtension(name))) { /*do not permit 'id1/pak1.pak' or 'baseq3/pak0.pk3' or any similarly named packages. such packages would violate copyright, and must be obtained through other means (like buying the damn game)*/ - if (!strstr(name, "/pak")) + if (FS_GetPackageDownloadable(name+8)) return !!allow_download_packages.value; + else + return !!allow_download_copyrighted.ival; } return false; } @@ -2523,8 +2537,12 @@ qboolean SV_AllowDownload (const char *name) //pak/pk3s. if (!strcmp("pk4", COM_FileExtension(name)) || !strcmp("pk3", COM_FileExtension(name)) || !strcmp("pak", COM_FileExtension(name))) + { if (strnicmp(name, "pak", 3)) //don't give out core pak/pk3 files. This matches q3 logic. return !!allow_download_packages.value; + else + return !!allow_download_copyrighted.value; + } if (!strcmp("cfg", COM_FileExtension(name))) return !!allow_download_configs.value; @@ -2587,17 +2605,14 @@ static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementnam if (!strncmp(name, "package/", 8)) { - vfsfile_t *f; - if (FS_GetPackageDownloadable(name+8)) + vfsfile_t *f = FS_OpenVFS(name+8, "rb", FS_ROOT); + if (f) { - f = FS_OpenVFS(name+8, "rb", FS_ROOT); - if (f) - { - VFS_CLOSE(f); - return -5; //found package - } + VFS_CLOSE(f); + return -5; //found package } - return -1; //not found + else + return -1; //not found/unable to open } else found = FS_FLocateFile(name, FSLFRT_IFFOUND, loc); @@ -3892,15 +3907,21 @@ void Cmd_Give_f (void) break; } } - else if (developer.value || host_client->netchan.remote_address.type == NA_LOOPBACK) //we don't want clients doing nasty things... like setting movetype 3123 + else { - int oldself; - oldself = pr_global_struct->self; - pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv_player); - SV_ClientPrintf(host_client, PRINT_HIGH, "Result: %s\n", svprogfuncs->EvaluateDebugString(svprogfuncs, Cmd_Args())); - pr_global_struct->self = oldself; + if (developer.value < 2 && host_client->netchan.remote_address.type != NA_LOOPBACK) //we don't want clients doing nasty things... like setting movetype 3123 + { + SV_PrintToClient(host_client, PRINT_HIGH, "'give' debugging command requires developer 2 set on the server before you may use it\n"); + } + else + { + int oldself; + oldself = pr_global_struct->self; + pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv_player); + SV_ClientPrintf(host_client, PRINT_HIGH, "Result: %s\n", svprogfuncs->EvaluateDebugString(svprogfuncs, Cmd_Args())); + pr_global_struct->self = oldself; + } } - } void Cmd_Noclip_f (void) @@ -4115,6 +4136,7 @@ void Cmd_Join_f (void) pr_global_struct->time = sv.world.physicstime; pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv_player); PR_ExecuteProgram (svprogfuncs, pr_global_struct->PutClientInServer); + sv.spawned_client_slots++; // send notification to all clients host_client->old_frags = host_client->edict->v->frags; @@ -4177,6 +4199,7 @@ void Cmd_Observe_f (void) // this will set the body to a dead frame, among other things pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv_player); PR_ExecuteProgram (svprogfuncs, pr_global_struct->ClientDisconnect); + sv.spawned_client_slots--; SV_SetUpClientEdict (host_client, host_client->edict); @@ -4438,6 +4461,8 @@ void SVNQ_Begin_f (void) } else { + sv.spawned_client_slots++; + // copy spawn parms out of the client_t for (i=0 ; i< NUM_SPAWN_PARMS ; i++) { @@ -4951,6 +4976,7 @@ ucmd_t nqucmds[] = {"pext", SV_Pext_f}, {"enablecsqc", SV_EnableClientsCSQC}, {"disablecsqc", SV_DisableClientsCSQC}, + {"challengeconnect", NULL}, #ifdef VOICECHAT {"voicetarg", SV_Voice_Target_f}, @@ -5816,7 +5842,14 @@ if (sv_player->v->health > 0 && before && !after ) continue; if (ent->v->touch) + { + if (progstype != PROG_QW && VectorCompare(sv_player->v->velocity, old_vel)) + { + VectorCopy(pmove.touchvel[i], old_vel); + VectorCopy(pmove.touchvel[i], sv_player->v->velocity); + } sv.world.Event_Touch(&sv.world, (wedict_t*)ent, (wedict_t*)sv_player); + } playertouch[n/8] |= 1 << (n%8); if (sv_player->v->touch && !ent->isfree) diff --git a/engine/server/svhl_game.c b/engine/server/svhl_game.c index a01d2128e..422320d8d 100644 --- a/engine/server/svhl_game.c +++ b/engine/server/svhl_game.c @@ -1574,7 +1574,7 @@ extern vec3_t player_maxs; pe->forcecontentsmask = FTECONTENTS_SKY; break; case -16: - pe->forcecontentsmask = FTECONTENTS_LADDER; + pe->forcecontentsmask = Q2CONTENTS_LADDER; break; default: pe->forcecontentsmask = 0; diff --git a/engine/server/svq3_game.c b/engine/server/svq3_game.c index 804899890..d67ccf47e 100644 --- a/engine/server/svq3_game.c +++ b/engine/server/svq3_game.c @@ -560,10 +560,10 @@ static int SVQ3_Contact(vec3_t mins, vec3_t maxs, q3sharedEntity_t *ent) else mod = Mod_ForName(va("*%i", ent->s.modelindex), false); - if (mod->needload || !mod->funcs.Trace) + if (mod->needload || !mod->funcs.NativeTrace) return false; - mod->funcs.Trace(mod, 0, 0, NULL, vec3_origin, vec3_origin, mins, maxs, &tr); + mod->funcs.NativeTrace(mod, 0, 0, NULL, vec3_origin, vec3_origin, mins, maxs, 0xffffffff, &tr); if (tr.startsolid) return true; diff --git a/engine/server/world.c b/engine/server/world.c index 5c6521afa..9e84bb4ef 100644 --- a/engine/server/world.c +++ b/engine/server/world.c @@ -41,6 +41,7 @@ typedef struct float *start, *end; trace_t trace; int type; + int hitcontentsmask; wedict_t *passedict; #ifdef Q2SERVER q2edict_t *q2passedict; @@ -899,7 +900,7 @@ qboolean Q1BSP_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, //wrapper function. Rotates the start and end positions around the angles if needed. //qboolean TransformedHullCheck (hull_t *hull, vec3_t start, vec3_t end, trace_t *trace, vec3_t angles) -qboolean TransformedTrace (struct model_s *model, int hulloverride, int frame, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, struct trace_s *trace, vec3_t origin, vec3_t angles) +qboolean TransformedTrace (struct model_s *model, int hulloverride, int frame, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, struct trace_s *trace, vec3_t origin, vec3_t angles, unsigned int hitcontentsmask) { vec3_t start_l, end_l; vec3_t axis[3]; @@ -928,11 +929,11 @@ qboolean TransformedTrace (struct model_s *model, int hulloverride, int frame, v { AngleVectors (angles, axis[0], axis[1], axis[2]); VectorNegate(axis[1], axis[1]); - result = model->funcs.Trace (model, hulloverride, frame, axis, start_l, end_l, mins, maxs, trace); + result = model->funcs.NativeTrace (model, hulloverride, frame, axis, start_l, end_l, mins, maxs, hitcontentsmask, trace); } else { - result = model->funcs.Trace (model, hulloverride, frame, NULL, start_l, end_l, mins, maxs, trace); + result = model->funcs.NativeTrace (model, hulloverride, frame, NULL, start_l, end_l, mins, maxs, hitcontentsmask, trace); } VectorAdd (trace->endpos, origin, trace->endpos); @@ -1011,7 +1012,7 @@ Handles selection or creation of a clipping hull, and offseting (and eventually rotation) of the end points ================== */ -static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int hullnum, qboolean hitmodel) //hullnum overrides min/max for q1 style bsps +static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int hullnum, qboolean hitmodel, unsigned int hitcontentsmask) //hullnum overrides min/max for q1 style bsps { trace_t trace; model_t *model; @@ -1036,42 +1037,37 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v if (ent->v->solid != SOLID_BSP) { ent->v->angles[0]*=-1; //carmack made bsp models rotate wrongly. - TransformedTrace(model, hullnum, ent->v->frame, start, end, mins, maxs, &trace, eorg, ent->v->angles); + TransformedTrace(model, hullnum, ent->v->frame, start, end, mins, maxs, &trace, eorg, ent->v->angles, hitcontentsmask); ent->v->angles[0]*=-1; } else { - TransformedTrace(model, hullnum, ent->v->frame, start, end, mins, maxs, &trace, eorg, ent->v->angles); + TransformedTrace(model, hullnum, ent->v->frame, start, end, mins, maxs, &trace, eorg, ent->v->angles, hitcontentsmask); } -// fix trace up by the offset - if (trace.fraction != 1) +// if using hitmodel, we know it hit the bounding box, so try a proper trace now. + if (hitmodel && trace.fraction != 1 && ent->v->solid != SOLID_BSP && ent->v->modelindex != 0) { - if (!model && hitmodel && ent->v->solid != SOLID_BSP && ent->v->modelindex > 0) + //okay, we hit the bbox + + model_t *model; + model = w->Get_CModel(w, ent->v->modelindex); + + if (model && model->funcs.NativeTrace) { - //okay, we hit the bbox - - model_t *model; - if (ent->v->modelindex < 1 || ent->v->modelindex >= MAX_MODELS) - Host_Error("SV_ClipMoveToEntity: modelindex out of range\n"); - model = w->Get_CModel(w, ent->v->modelindex); - - if (model && model->funcs.Trace) - { - //do the second trace - TransformedTrace(model, hullnum, ent->v->frame, start, end, mins, maxs, &trace, eorg, ent->v->angles); - } + //do the second trace + TransformedTrace(model, hullnum, ent->v->frame, start, end, mins, maxs, &trace, eorg, ent->v->angles, hitcontentsmask); } } // did we clip the move? - if (trace.fraction < 1 || trace.startsolid ) + if (trace.fraction < 1 || trace.startsolid) trace.ent = ent; return trace; } #ifdef Q2SERVER -static trace_t WorldQ2_ClipMoveToEntity (world_t *w, q2edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end) +static trace_t WorldQ2_ClipMoveToEntity (world_t *w, q2edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, unsigned int hitcontentsmask) { trace_t trace; model_t *model; @@ -1093,7 +1089,7 @@ static trace_t WorldQ2_ClipMoveToEntity (world_t *w, q2edict_t *ent, vec3_t star } // trace a line through the apropriate clipping hull - TransformedTrace(model, 0, 0, start, end, mins, maxs, &trace, ent->s.origin, ent->s.angles); + TransformedTrace(model, 0, 0, start, end, mins, maxs, &trace, ent->s.origin, ent->s.angles, hitcontentsmask); // did we clip the move? if (trace.fraction < 1 || trace.startsolid ) @@ -1295,7 +1291,7 @@ static model_t *WorldQ2_ModelForEntity (world_t *w, q2edict_t *ent) #endif #ifdef Q2SERVER -void WorldQ2_ClipMoveToEntities (world_t *w, moveclip_t *clip, int contentsmask ) +void WorldQ2_ClipMoveToEntities (world_t *w, moveclip_t *clip ) { int i, num; q2edict_t *touchlist[MAX_EDICTS], *touch; @@ -1326,7 +1322,7 @@ void WorldQ2_ClipMoveToEntities (world_t *w, moveclip_t *clip, int contentsmask } if (touch->svflags & SVF_DEADMONSTER) - if ( !(contentsmask & Q2CONTENTS_DEADMONSTER)) + if ( !(clip->hitcontentsmask & Q2CONTENTS_DEADMONSTER)) continue; // might intersect, so do an exact clip @@ -1337,11 +1333,11 @@ void WorldQ2_ClipMoveToEntities (world_t *w, moveclip_t *clip, int contentsmask if (touch->svflags & SVF_MONSTER) trace = CM_TransformedBoxTrace (model, clip->start, clip->end, - clip->mins2, clip->maxs2, contentsmask, + clip->mins2, clip->maxs2, clip->hitcontentsmask, touch->s.origin, angles); else trace = CM_TransformedBoxTrace (model, clip->start, clip->end, - clip->mins, clip->maxs, contentsmask, + clip->mins, clip->maxs, clip->hitcontentsmask, touch->s.origin, angles); if (trace.allsolid || trace.startsolid || @@ -1434,9 +1430,9 @@ static void World_ClipToEverything (world_t *w, moveclip_t *clip) } if ((int)touch->v->flags & FL_MONSTER) - trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins2, clip->maxs2, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL); + trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins2, clip->maxs2, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->hitcontentsmask); else - trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins, clip->maxs, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL); + trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins, clip->maxs, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->hitcontentsmask); if (trace.allsolid || trace.startsolid || trace.fraction < clip->trace.fraction) { @@ -1535,9 +1531,9 @@ static void World_ClipToLinks (world_t *w, areanode_t *node, moveclip_t *clip) } if ((int)touch->v->flags & FL_MONSTER) - trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins2, clip->maxs2, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL); + trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins2, clip->maxs2, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->hitcontentsmask); else - trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins, clip->maxs, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL); + trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins, clip->maxs, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->hitcontentsmask); if (trace.allsolid || trace.startsolid || trace.fraction < clip->trace.fraction) @@ -1608,7 +1604,7 @@ static void WorldQ2_ClipToLinks (world_t *w, areanode_t *node, moveclip_t *clip) continue; // don't clip against owner } - trace = WorldQ2_ClipMoveToEntity (w, touch, clip->start, clip->mins, clip->maxs, clip->end); + trace = WorldQ2_ClipMoveToEntity (w, touch, clip->start, clip->mins, clip->maxs, clip->end, clip->hitcontentsmask); if (trace.allsolid || trace.startsolid || trace.fraction < clip->trace.fraction) @@ -1706,8 +1702,15 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e } #endif + if (type & MOVE_NOMONSTERS) + clip.hitcontentsmask = MASK_WORLDSOLID; /*solid only to world*/ + else if (maxs[0] - mins[0]) + clip.hitcontentsmask = MASK_BOXSOLID; /*impacts playerclip*/ + else + clip.hitcontentsmask = MASK_POINTSOLID; /*ignores playerclip but hits everything else*/ + // clip to world - clip.trace = World_ClipMoveToEntity (w, w->edicts, w->edicts->v->origin, start, mins, maxs, end, hullnum, false); + clip.trace = World_ClipMoveToEntity (w, w->edicts, w->edicts->v->origin, start, mins, maxs, end, hullnum, false, clip.hitcontentsmask); clip.start = start; clip.end = end; @@ -1830,7 +1833,7 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e continue; // don't clip against owner } - trace = World_ClipMoveToEntity (w, touch, lp, clip.start, clip.mins, clip.maxs, clip.end, clip.hullnum, clip.type & MOVE_HITMODEL); + trace = World_ClipMoveToEntity (w, touch, lp, clip.start, clip.mins, clip.maxs, clip.end, clip.hullnum, clip.type & MOVE_HITMODEL, clip.hitcontentsmask); if (trace.allsolid || trace.startsolid || trace.fraction < clip.trace.fraction) { @@ -1860,14 +1863,14 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e return clip.trace; } #ifdef Q2SERVER -trace_t WorldQ2_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, q2edict_t *passedict) +trace_t WorldQ2_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int hitcontentsmask, q2edict_t *passedict) { moveclip_t clip; memset ( &clip, 0, sizeof ( moveclip_t ) ); // clip to world - clip.trace = CM_BoxTrace(w->worldmodel, start, end, mins, maxs, type);//SVQ2_ClipMoveToEntity ( ge->edicts, start, mins, maxs, end ); + clip.trace = CM_BoxTrace(w->worldmodel, start, end, mins, maxs, hitcontentsmask);//SVQ2_ClipMoveToEntity ( ge->edicts, start, mins, maxs, end ); clip.trace.ent = ge->edicts; if (clip.trace.fraction == 0) @@ -1877,7 +1880,8 @@ trace_t WorldQ2_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t clip.end = end; clip.mins = mins; clip.maxs = maxs; - clip.type = type; + clip.type = MOVE_NORMAL; + clip.hitcontentsmask = hitcontentsmask; clip.passedict = NULL; clip.q2passedict = passedict; @@ -1890,7 +1894,7 @@ trace_t WorldQ2_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t // clip to entities #ifdef Q2BSPS if (w->worldmodel->fromgame == fg_quake2 || w->worldmodel->fromgame == fg_quake3) - WorldQ2_ClipMoveToEntities(w, &clip, type); + WorldQ2_ClipMoveToEntities(w, &clip); else #endif WorldQ2_ClipToLinks (w, w->areanodes, &clip ); diff --git a/engine/shaders/generatebuiltinsl.c b/engine/shaders/generatebuiltinsl.c new file mode 100644 index 000000000..7a33130db --- /dev/null +++ b/engine/shaders/generatebuiltinsl.c @@ -0,0 +1,132 @@ +#include +#include + +char shaders[][64] = +{ + "bloom_blur", + "bloom_filter", + "bloom_final", + "" +}; + +void dumpprogstring(FILE *out, FILE *src) +{ + int j; + char line[1024]; + + while(fgets(line, sizeof(line), src)) + { + j = 0; + while (line[j] == ' ' || line[j] == '\t') + j++; + if ((line[j] == '/' && line[j] == '/') || line[j] == '\r' || line[j] == '\n') + { + while (line[j]) + fputc(line[j++], out); + } + else + { + fputc('\"', out); + while (line[j] && line[j] != '\r' && line[j] != '\n') + { + if (line[j] == '\t') + fputc(' ', out); + else if (line[j] == '\"') + { + fputc('\\', out); + fputc(line[j], out); + } + else + fputc(line[j], out); + j++; + } + fputs("\\n\"\n", out); + } + } + +} + +int main(void) +{ + FILE *c, *s; + char line[1024]; + int i, j, a; + c = fopen("../gl/r_bishaders.h", "wt"); + + if (!c) + { + printf("unable to open a file\n"); + return; + } + + fprintf(c, "/*\nWARNING: THIS FILE IS GENERATED BY '"__FILE__"'.\nYOU SHOULD NOT EDIT THIS FILE BY HAND\n*/\n\n"); + + for (i = 0; *shaders[i]; i++) + { + for (a = 0; a < 3; a++) + { + if (a == 0) + sprintf(line, "glsl/%s.glsl", shaders[i]); + else if (a == 1) + sprintf(line, "gles/%s.glsl", shaders[i]); + else + sprintf(line, "hlsl/%s.hlsl", shaders[i]); + s = fopen(line, "rt"); + if (!s) + { + printf("unable to open %s\n", line); + continue; + } + if (a == 0) + { + fprintf(c, "#ifdef GLQUAKE\n"); + fprintf(c, "{QR_OPENGL, 110, \"%s\",\n", shaders[i]); + } + else if (a == 1) + { + fprintf(c, "#ifdef GLQUAKE\n"); + fprintf(c, "{QR_OPENGL, 100, \"%s\",\n", shaders[i]); + } + else + { + fprintf(c, "#ifdef D3DQUAKE\n"); + fprintf(c, "{QR_DIRECT3D, 9, \"%s\",\n", shaders[i]); + } + + while(fgets(line, sizeof(line), s)) + { + j = 0; + while (line[j] == ' ' || line[j] == '\t') + j++; + if ((line[j] == '/' && line[j] == '/') || line[j] == '\r' || line[j] == '\n') + { + while (line[j]) + fputc(line[j++], c); + } + else + { + fputc('\"', c); + while (line[j] && line[j] != '\r' && line[j] != '\n') + { + if (line[j] == '\t') + fputc(' ', c); + else if (line[j] == '\"') + { + fputc('\\', c); + fputc(line[j], c); + } + else + fputc(line[j], c); + j++; + } + fputs("\\n\"\n", c); + } + } + fputs("},\n", c); + fprintf(c, "#endif\n"); + fclose(s); + } + } + + fclose(c); +} diff --git a/engine/shaders/glsl/bloom_blur.glsl b/engine/shaders/glsl/bloom_blur.glsl new file mode 100644 index 000000000..fb9772c19 --- /dev/null +++ b/engine/shaders/glsl/bloom_blur.glsl @@ -0,0 +1,24 @@ +//apply gaussian filter + +varying vec2 tc; + +#ifdef VERTEX_SHADER +attribute vec2 v_texcoord; +void main () +{ + tc = v_texcoord; + gl_Position = ftetransform(); +} +#endif +#ifdef FRAGMENT_SHADER +/*offset should be 1.2 pixels away from the center*/ +uniform vec3 e_glowmod; +uniform sampler2D s_t0; +void main () +{ + gl_FragColor = + 0.3125 * texture2D(s_t0, tc - e_glowmod.st) + + 0.375 * texture2D(s_t0, tc) + + 0.3125 * texture2D(s_t0, tc + e_glowmod.st); +} +#endif \ No newline at end of file diff --git a/engine/shaders/glsl/bloom_filter.glsl b/engine/shaders/glsl/bloom_filter.glsl new file mode 100644 index 000000000..35f127828 --- /dev/null +++ b/engine/shaders/glsl/bloom_filter.glsl @@ -0,0 +1,20 @@ +//the bloom filter +//filter out any texels which are not to bloom + +varying vec2 tc; + +#ifdef VERTEX_SHADER +attribute vec2 v_texcoord; +void main () +{ + tc = v_texcoord; + gl_Position = ftetransform(); +} +#endif +#ifdef FRAGMENT_SHADER +uniform sampler2D s_t0; +void main () +{ + gl_FragColor = (texture2D(s_t0, tc) - vec4(0.5, 0.5, 0.5, 0.0)) * vec4(2.0,2.0,2.0,1.0); +} +#endif \ No newline at end of file diff --git a/engine/shaders/glsl/bloom_final.glsl b/engine/shaders/glsl/bloom_final.glsl new file mode 100644 index 000000000..43fad1777 --- /dev/null +++ b/engine/shaders/glsl/bloom_final.glsl @@ -0,0 +1,27 @@ +//add them together +//optionally apply tonemapping + +varying vec2 tc; + +#ifdef VERTEX_SHADER +attribute vec2 v_texcoord; +void main () +{ + tc = v_texcoord; + gl_Position = ftetransform(); +} +#endif +#ifdef FRAGMENT_SHADER +uniform sampler2D s_t0; +uniform sampler2D s_t1; +uniform sampler2D s_t2; +uniform sampler2D s_t3; +void main () +{ + gl_FragColor = + texture2D(s_t0, tc) + + texture2D(s_t1, tc) + + texture2D(s_t2, tc) + + texture2D(s_t3, tc) ; +} +#endif