From 6e825e42dd0e1c846c80b0e284c1553a4de871f8 Mon Sep 17 00:00:00 2001 From: Spoike Date: Tue, 13 Dec 2016 11:50:15 +0000 Subject: [PATCH] merge gl+vk win32 code. include egl support on windows (useful for ANGLE). fix misc bugs. rewrote skeletal code to use gpu-friendly skeletal data for all skeletal formats. add modelframecount builtin, to easily get the number of frames in a model. integrate hlmdl a little better. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5031 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/Makefile | 4 +- engine/client/cl_cam.c | 1 + engine/client/cl_screen.c | 2 +- engine/client/m_download.c | 21 +- engine/client/m_options.c | 44 +- engine/client/merged.h | 3 +- engine/client/pr_csqc.c | 3 + engine/client/pr_skelobj.c | 11 + engine/client/vid.h | 6 - engine/common/bothdefs.h | 3 + engine/common/com_mesh.c | 1360 ++++++++++----------- engine/common/com_mesh.h | 18 +- engine/common/fs.c | 2 +- engine/common/gl_q2bsp.c | 4 +- engine/common/mathlib.c | 2 +- engine/common/mathlib.h | 2 +- engine/common/pr_bgcmd.c | 5 +- engine/common/pr_common.h | 1 + engine/d3d/vid_d3d11.c | 2 +- engine/dotnet2005/ftequake.vcproj | 8 +- engine/gl/gl_hlmdl.c | 35 +- engine/gl/gl_model.c | 30 +- engine/gl/gl_model.h | 5 +- engine/gl/gl_shader.c | 2 +- engine/gl/gl_vidcommon.c | 8 + engine/gl/gl_videgl.c | 60 +- engine/gl/gl_videgl.h | 4 +- engine/gl/gl_vidlinuxglx.c | 47 +- engine/gl/gl_vidnt.c | 827 +++++++++---- engine/gl/glmod_doom.c | 3 +- engine/gl/glquake.h | 12 - engine/gl/model_hl.h | 2 + engine/gl/r_bishaders.h | 6 +- engine/nacl/gl_vidppapi.c | 2 - engine/server/pr_cmds.c | 2 +- engine/server/svhl_game.c | 3 +- engine/shaders/glsl/defaultwall.glsl | 6 +- engine/sw/sw_vidwin.c | 4 +- engine/vk/vk_win32.c | 1686 -------------------------- 39 files changed, 1469 insertions(+), 2777 deletions(-) delete mode 100644 engine/vk/vk_win32.c diff --git a/engine/Makefile b/engine/Makefile index 93ccfbde1..89fea4683 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -1081,7 +1081,7 @@ ifeq (win,$(findstring win,$(FTE_TARGET))$(findstring _SDL,$(FTE_TARGET))) NPFTE_CFLAGS=$(NPFTECFLAGS) $(W32_CFLAGS) -DMULTITHREAD NPFTEB_DIR=npfte_mgw$(BITS) - MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) $(D3DQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) gl_vidnt.o vk_win32.o $(WINDOWS_OBJS) + MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) $(D3DQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) gl_vidnt.o gl_videgl.o $(WINDOWS_OBJS) M_EXE_NAME=../fteqw$(BITS)$(EXEPOSTFIX) MCL_EXE_NAME=../fteqwcl$(BITS)$(EXEPOSTFIX) M_LDFLAGS=$(GLLDFLAGS) $(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 -Wl,--subsystem,windows @@ -1097,7 +1097,7 @@ ifeq (win,$(findstring win,$(FTE_TARGET))$(findstring _SDL,$(FTE_TARGET))) D3DB_DIR=d3d_mgw$(BITS) D3DCL_DIR=d3dcl_mgw$(BITS) - VKCL_OBJS=$(GLQUAKE_OBJS) $(D3DGL_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) $(WINDOWS_OBJS) vk_win32.o + VKCL_OBJS=$(GLQUAKE_OBJS) $(D3DGL_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) $(WINDOWS_OBJS) gl_vidnt.o VK_EXE_NAME=../ftevkqw$(BITS)$(EXEPOSTFIX) VKCL_EXE_NAME=../ftevkclqw$(BITS)$(EXEPOSTFIX) VK_LDFLAGS=$(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 -Wl,--subsystem,windows diff --git a/engine/client/cl_cam.c b/engine/client/cl_cam.c index 5da616993..9cf170d0b 100644 --- a/engine/client/cl_cam.c +++ b/engine/client/cl_cam.c @@ -1112,6 +1112,7 @@ void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd) end = (pv->cam_spec_track + 1) % MAX_CLIENTS; else end = pv->cam_spec_track; + end = max(0, end) % cl.allocated_client_slots; i = end; do { diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index 94f6f7488..07ae36d59 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -1462,7 +1462,7 @@ void SCR_DrawFPS (void) double t; extern int fps_count; static float lastfps; - static float deviationtimes[64]; + static double deviationtimes[64]; static int deviationframe; char str[80]; int sfps, frame; diff --git a/engine/client/m_download.c b/engine/client/m_download.c index a620e8553..b7a1cb082 100644 --- a/engine/client/m_download.c +++ b/engine/client/m_download.c @@ -1399,13 +1399,6 @@ static void PM_UpdatePackageList(qboolean autoupdate, int retry) -typedef struct { - menucustom_t *list; - char intermediatefilename[MAX_QPATH]; - char pathprefix[MAX_QPATH]; - int downloadablessequence; - qboolean populated; -} dlmenu_t; static void COM_QuotedConcat(const char *cat, char *buf, size_t bufsize) { @@ -2294,9 +2287,6 @@ void PM_Command_f (void) { Con_Printf("Package Manager is not implemented in this build\n"); } -void Menu_Download_Update(void) -{ -} void PM_LoadPackages(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, int minpri, int maxpri) { } @@ -2309,6 +2299,14 @@ void PM_Shutdown(void) #endif #ifdef DOWNLOADMENU +typedef struct { + menucustom_t *list; + char intermediatefilename[MAX_QPATH]; + char pathprefix[MAX_QPATH]; + int downloadablessequence; + qboolean populated; +} dlmenu_t; + static int autoupdatesetting = UPD_UNSUPPORTED; static void MD_Draw (int x, int y, struct menucustom_s *c, struct menu_s *m) { @@ -2735,6 +2733,9 @@ void Menu_Download_Update(void) PM_UpdatePackageList(true, 2); } #else +void Menu_Download_Update(void) +{ +} void Menu_DownloadStuff_f (void) { Con_Printf("Download menu not implemented in this build\n"); diff --git a/engine/client/m_options.c b/engine/client/m_options.c index 010fc77b6..c283a1aa5 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -2805,21 +2805,25 @@ static unsigned int genhsv(float h_, float s, float v) #include "com_mesh.h" #ifdef SKELETALMODELS -static void M_BoneDisplay(entity_t *e, galiasbone_t *b, int *y, int depth, int parent, int first, int last) +static void M_BoneDisplayLame(entity_t *e, int *y, int depth, int parent, int first, int last) { int i; for (i = first; i < last; i++) { - if (b[i].parent == parent) + int p = Mod_GetBoneParent(e->model, i+1); + if (p == parent) { + const char *bname = Mod_GetBoneName(e->model, i+1); float result[12]; + if (!bname) + bname = "NULL"; memset(result, 0, sizeof(result)); if (Mod_GetTag(e->model, i+1, &e->framestate, result)) - Draw_FunString(depth*16, *y, va("%i: %s (%g %g %g)", i, b[i].name, result[3], result[7], result[11])); + Draw_FunString(depth*16, *y, va("%i: %s (%g %g %g)", i, bname, result[3], result[7], result[11])); else - Draw_FunString(depth*16, *y, va("%i: %s", i, b[i].name)); + Draw_FunString(depth*16, *y, va("%i: %s", i, bname)); *y += 8; - M_BoneDisplay(e, b, y, depth+1, i, i+1, last); + M_BoneDisplayLame(e, y, depth+1, i+1, i+1, last); } } } @@ -2832,7 +2836,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_ const char *fname; shader_t *shader; vec2_t fs = {8,8}; - float bones[12*MAX_BONES]; +// float bones[12*MAX_BONES]; modelview_t *mods = c->dptr; @@ -2892,15 +2896,30 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_ ent.customskin = Mod_RegisterSkinFile(va("%s_0.skin", mods->modelname)); // ent.framestate.bonecount = Mod_GetNumBones(ent.model, false); - ent.framestate.bonestate = bones; - ent.framestate.bonecount = Mod_GetBoneRelations(ent.model, 0, MAX_BONES, &ent.framestate, ent.framestate.bonestate); - ent.framestate.skeltype = SKEL_RELATIVE; +// ent.framestate.bonestate = bones; +// ent.framestate.bonecount = Mod_GetBoneRelations(ent.model, 0, MAX_BONES, &ent.framestate, ent.framestate.bonestate); +// ent.framestate.skeltype = SKEL_RELATIVE; ent.light_avg[0] = ent.light_avg[1] = ent.light_avg[2] = 0.66; ent.light_range[0] = ent.light_range[1] = ent.light_range[2] = 0.33; ent.light_dir[0] = 0; ent.light_dir[1] = 1; ent.light_dir[2] = 0; ent.light_known = 2; + switch(ent.model->loadstate) + { + case MLS_LOADED: + break; + case MLS_NOTLOADED: + Draw_FunString(0, 0, va("%s not loaded", ent.model->name)); + return; + case MLS_LOADING: + Draw_FunString(0, 0, va("%s still loading", ent.model->name)); + return; + case MLS_FAILED: + Draw_FunString(0, 0, va("Unable to load %s", ent.model->name)); + return; + } + V_AddEntity(&ent); V_ApplyRefdef(); @@ -2950,13 +2969,12 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_ case MV_BONES: #ifdef SKELETALMODELS { - int bonecount; - galiasbone_t *b = Mod_GetBoneInfo(ent.model, &bonecount); - if (b && bonecount) + int bonecount = Mod_GetNumBones(ent.model, false); + if (bonecount) { Draw_FunString(0, y, va("Bones: ")); y+=8; - M_BoneDisplay(&ent, b, &y, 0, -1, 0, bonecount); + M_BoneDisplayLame(&ent, &y, 0, 0, 0, bonecount); } else R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+y, r_refdef.grect.width, r_refdef.grect.height-y, "No bones in model", CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, fs); diff --git a/engine/client/merged.h b/engine/client/merged.h index 85ab56543..468d3ffe8 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -176,6 +176,7 @@ extern void Mod_Think (void); extern int Mod_SkinNumForName (struct model_s *model, int surfaceidx, const char *name); extern int Mod_FrameNumForName (struct model_s *model, int surfaceidx, const char *name); extern float Mod_GetFrameDuration (struct model_s *model, int surfaceidx, int framenum); +extern int Mod_GetFrameCount (struct model_s *model); #undef FNC @@ -186,7 +187,7 @@ int Mod_GetNumBones(struct model_s *model, qboolean allowtags); int Mod_GetBoneRelations(struct model_s *model, int firstbone, int lastbone, framestate_t *fstate, float *result); int Mod_GetBoneParent(struct model_s *model, int bonenum); struct galiasbone_s *Mod_GetBoneInfo(struct model_s *model, int *numbones); -char *Mod_GetBoneName(struct model_s *model, int bonenum); +const char *Mod_GetBoneName(struct model_s *model, int bonenum); void Draw_FunString(float x, float y, const void *str); void Draw_AltFunString(float x, float y, const void *str); diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 71ec5915a..4e7726542 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -5736,6 +5736,9 @@ static struct { {"hash_getcb", PF_hash_getcb, 293}, {"checkcommand", PF_checkcommand, 294}, {"argescape", PF_argescape, 295}, + + {"modelframecount", PF_modelframecount, 0}, + //300 {"clearscene", PF_R_ClearScene, 300}, // #300 void() clearscene (EXT_CSQC) {"addentities", PF_R_AddEntityMask, 301}, // #301 void(float mask) addentities (EXT_CSQC) diff --git a/engine/client/pr_skelobj.c b/engine/client/pr_skelobj.c index b88bc52c1..a85bb7d64 100644 --- a/engine/client/pr_skelobj.c +++ b/engine/client/pr_skelobj.c @@ -2332,6 +2332,17 @@ void QCBUILTIN PF_frameduration (pubprogfuncs_t *prinst, struct globalvars_s *pr else G_FLOAT(OFS_RETURN) = 0; } +void QCBUILTIN PF_modelframecount (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + world_t *w = prinst->parms->user; + unsigned int modelindex = G_FLOAT(OFS_PARM0); + model_t *mod = w->Get_CModel(w, modelindex); + + if (mod) + G_FLOAT(OFS_RETURN) = Mod_GetFrameCount(mod); + else + G_FLOAT(OFS_RETURN) = 0; +} //string(float modidx, float skinnum) skintoname void QCBUILTIN PF_skintoname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) diff --git a/engine/client/vid.h b/engine/client/vid.h index f0d19dec9..36bc40d74 100644 --- a/engine/client/vid.h +++ b/engine/client/vid.h @@ -119,12 +119,6 @@ void GLVID_Crashed(void); void GLVID_Update (vrect_t *rects); // flushes the given rectangles from the view buffer to the screen -int GLVID_SetMode (rendererstate_t *info, unsigned char *palette); -// sets the mode; only used by the Quake engine for resetting to mode 0 (the -// base mode) on memory allocation failures - -qboolean GLVID_Is8bit(void); - void GLVID_SwapBuffers(void); enum uploadfmt; char *GLVID_GetRGBInfo(int *truewidth, int *trueheight, enum uploadfmt *fmt); diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index e9db106d5..accd83078 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -131,6 +131,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #if (defined(D3D9QUAKE) || defined(D3D11QUAKE)) && !defined(D3DQUAKE) #define D3DQUAKE #endif +#if defined(_WIN32) && defined(GLQUAKE) +#define USE_EGL +#endif #if defined(_MSC_VER) && !defined(BOTLIB_STATIC) //too lazy to fix up the makefile #define BOTLIB_STATIC diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index 2ee5b2c8c..98c58c4d4 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -121,11 +121,11 @@ clampedmodel_t clampedmodel[] = { -void Mod_AccumulateTextureVectors(vecV_t *vc, vec2_t *tc, vec3_t *nv, vec3_t *sv, vec3_t *tv, index_t *idx, int numidx) +void Mod_AccumulateTextureVectors(vecV_t *const vc, vec2_t *const tc, vec3_t *nv, vec3_t *sv, vec3_t *tv, const index_t *idx, int numidx, qboolean calcnorms) { int i; - float *v0, *v1, *v2; - float *tc0, *tc1, *tc2; + const float *v0, *v1, *v2; + const float *tc0, *tc1, *tc2; vec3_t d1, d2; float td1, td2; @@ -174,6 +174,13 @@ void Mod_AccumulateTextureVectors(vecV_t *vc, vec2_t *tc, vec3_t *nv, vec3_t *sv } //and we're done, accumulate the result + if (calcnorms) + { + VectorAdd(nv[idx[i+0]], norm, nv[idx[i+0]]); + VectorAdd(nv[idx[i+1]], norm, nv[idx[i+1]]); + VectorAdd(nv[idx[i+2]], norm, nv[idx[i+2]]); + } + VectorAdd(sv[idx[i+0]], s, sv[idx[i+0]]); VectorAdd(sv[idx[i+1]], s, sv[idx[i+1]]); VectorAdd(sv[idx[i+2]], s, sv[idx[i+2]]); @@ -186,10 +193,10 @@ void Mod_AccumulateTextureVectors(vecV_t *vc, vec2_t *tc, vec3_t *nv, vec3_t *sv void Mod_AccumulateMeshTextureVectors(mesh_t *m) { - Mod_AccumulateTextureVectors(m->xyz_array, m->st_array, m->normals_array, m->snormals_array, m->tnormals_array, m->indexes, m->numindexes); + Mod_AccumulateTextureVectors(m->xyz_array, m->st_array, m->normals_array, m->snormals_array, m->tnormals_array, m->indexes, m->numindexes, false); } -void Mod_NormaliseTextureVectors(vec3_t *n, vec3_t *s, vec3_t *t, int v) +void Mod_NormaliseTextureVectors(vec3_t *n, vec3_t *s, vec3_t *t, int v, qboolean calcnorms) { int i; float f; @@ -197,6 +204,9 @@ void Mod_NormaliseTextureVectors(vec3_t *n, vec3_t *s, vec3_t *t, int v) for (i = 0; i < v; i++) { + if (calcnorms) + VectorNormalize(n[i]); + //strip away any variance against the normal to keep it perpendicular, then normalize f = -DotProduct(s[i], n[i]); VectorMA(s[i], f, n[i], tmp); @@ -463,49 +473,6 @@ static void Alias_TransformVerticies_VNST(const float *bonepose, int vertcount, } } -static void Alias_TransformVerticies_SW(const float *bonepose, galisskeletaltransforms_t *weights, int numweights, vecV_t *xyzout, vec3_t *normout) -{ - int i; - float *out; - const float *matrix; - galisskeletaltransforms_t *v = weights; -#ifndef SERVERONLY - float *normo; - if (normout) - { - for (i = 0;i < numweights;i++, v++) - { - out = xyzout[v->vertexindex]; - normo = normout[v->vertexindex]; - matrix = bonepose+v->boneindex*12; - // FIXME: this can very easily be optimized with SSE or 3DNow - out[0] += v->org[0] * matrix[0] + v->org[1] * matrix[1] + v->org[2] * matrix[ 2] + v->org[3] * matrix[ 3]; - out[1] += v->org[0] * matrix[4] + v->org[1] * matrix[5] + v->org[2] * matrix[ 6] + v->org[3] * matrix[ 7]; - out[2] += v->org[0] * matrix[8] + v->org[1] * matrix[9] + v->org[2] * matrix[10] + v->org[3] * matrix[11]; - - normo[0] += v->normal[0] * matrix[0] + v->normal[1] * matrix[1] + v->normal[2] * matrix[ 2]; - normo[1] += v->normal[0] * matrix[4] + v->normal[1] * matrix[5] + v->normal[2] * matrix[ 6]; - normo[2] += v->normal[0] * matrix[8] + v->normal[1] * matrix[9] + v->normal[2] * matrix[10]; - } - } - else -#elif defined(_DEBUG) - if (normout) - Sys_Error("norms error"); -#endif - { - for (i = 0;i < numweights;i++, v++) - { - out = xyzout[v->vertexindex]; - matrix = bonepose+v->boneindex*12; - // FIXME: this can very easily be optimized with SSE or 3DNow - out[0] += v->org[0] * matrix[0] + v->org[1] * matrix[1] + v->org[2] * matrix[ 2] + v->org[3] * matrix[ 3]; - out[1] += v->org[0] * matrix[4] + v->org[1] * matrix[5] + v->org[2] * matrix[ 6] + v->org[3] * matrix[ 7]; - out[2] += v->org[0] * matrix[8] + v->org[1] * matrix[9] + v->org[2] * matrix[10] + v->org[3] * matrix[11]; - } - } -} - //converts one entire frame to another skeleton type //only writes to destbuffer if absolutely needed const float *Alias_ConvertBoneData(skeltype_t sourcetype, const float *sourcedata, size_t bonecount, galiasbone_t *bones, skeltype_t desttype, float *destbuffer, float *destbufferalt, size_t destbonecount) @@ -663,194 +630,6 @@ void QDECL Alias_ForceConvertBoneData(skeltype_t sourcetype, const float *source } } -#ifndef NOLEGACY -static float Alias_CalculateSkeletalNormals(galiasinfo_t *model) -{ -#ifndef SERVERONLY - //servers don't need normals. except maybe for tracing... but hey. The normal is calculated on a per-triangle basis. - -#define TriangleNormal(a,b,c,n) ( \ - (n)[0] = ((a)[1] - (b)[1]) * ((c)[2] - (b)[2]) - ((a)[2] - (b)[2]) * ((c)[1] - (b)[1]), \ - (n)[1] = ((a)[2] - (b)[2]) * ((c)[0] - (b)[0]) - ((a)[0] - (b)[0]) * ((c)[2] - (b)[2]), \ - (n)[2] = ((a)[0] - (b)[0]) * ((c)[1] - (b)[1]) - ((a)[1] - (b)[1]) * ((c)[0] - (b)[0]) \ - ) - int i, j; - vecV_t *xyz; - vec3_t *normals; - int *mvert; - float *inversepose; - galiasinfo_t *next; - vec3_t tn; - vec3_t d1, d2; - index_t *idx; - const float *bonepose = NULL; - float angle; - float maxvdist = 0, d, maxbdist = 0; - float absmatrix[MAX_BONES*12]; - float absmatrixalt[MAX_BONES*12]; - float bonedist[MAX_BONES]; - int modnum = 0; - int bcmodnum = -1; - int vcmodnum = -1; - - while (model) - { - int numbones = model->numbones; - galisskeletaltransforms_t *v = model->ofsswtransforms; - int numweights = model->numswtransforms; - int numverts = model->numverts; - - next = model->nextsurf; - - xyz = Z_Malloc(numverts*sizeof(vecV_t)); - normals = Z_Malloc(numverts*sizeof(vec3_t)); - inversepose = Z_Malloc(numbones*sizeof(float)*9); - mvert = Z_Malloc(numverts*sizeof(*mvert)); - - if (bcmodnum != model->shares_bones) - { - galiasanimation_t *g; - galiasbone_t *bones = model->ofsbones; - bcmodnum = model->shares_bones; - if (model->baseframeofs) - bonepose = model->baseframeofs; - else - { - //figure out the pose from frame0pose0 - if (!model->numanimations) - return 0; - g = model->ofsanimations; - if (g->numposes < 1) - return 0; - bonepose = Alias_ConvertBoneData(g->skeltype, g->boneofs, numbones, bones, SKEL_ABSOLUTE, absmatrix, absmatrixalt, MAX_BONES); - } - /*calculate the bone sizes (assuming the bones are strung up and hanging or such)*/ - for (i = 0; i < model->numbones; i++) - { - vec3_t d; - const float *b; - b = bonepose + i*12; - d[0] = b[3]; - d[1] = b[7]; - d[2] = b[11]; - if (bones[i].parent >= 0) - { - b = bonepose + bones[i].parent*12; - d[0] -= b[3]; - d[1] -= b[7]; - d[2] -= b[11]; - } - bonedist[i] = Length(d); - if (bones[i].parent >= 0) - bonedist[i] += bonedist[bones[i].parent]; - if (maxbdist < bonedist[i]) - maxbdist = bonedist[i]; - } - for (i = 0; i < numbones; i++) - Matrix3x4_InvertTo3x3(bonepose+i*12, inversepose+i*9); - } - - for (i = 0; i < numweights; i++) - { - d = Length(v[i].org); - if (maxvdist < d) - maxvdist = d; - } - - //build the actual base pose positions - Alias_TransformVerticies_SW(bonepose, v, numweights, xyz, NULL); - - //work out which verticies are identical - //this is needed as two verts can have same origin but different tex coords - //without this, we end up with a seam that splits the normals each side on arms, etc - for (i = 0; i < numverts; i++) - { - mvert[i] = i; - for (j = 0; j < i; j++) - { - if ( xyz[i][0] == xyz[j][0] - && xyz[i][1] == xyz[j][1] - && xyz[i][2] == xyz[j][2]) - { - mvert[i] = j; - break; - } - } - } - - //use that base pose to calculate the normals - memset(normals, 0, numverts*sizeof(vec3_t)); - vcmodnum = modnum; - idx = model->ofs_indexes; - - //calculate the triangle normal and accumulate them - for (i = 0; i < model->numindexes; i+=3, idx+=3) - { - TriangleNormal(xyz[idx[0]], xyz[idx[1]], xyz[idx[2]], tn); - //note that tn is relative to the size of the triangle - - //Imagine a cube, each side made of two triangles - - VectorSubtract(xyz[idx[1]], xyz[idx[0]], d1); - VectorSubtract(xyz[idx[2]], xyz[idx[0]], d2); - angle = acos(DotProduct(d1, d2)/(Length(d1)*Length(d2))); - VectorMA(normals[mvert[idx[0]]], angle, tn, normals[mvert[idx[0]]]); - - VectorSubtract(xyz[idx[0]], xyz[idx[1]], d1); - VectorSubtract(xyz[idx[2]], xyz[idx[1]], d2); - angle = acos(DotProduct(d1, d2)/(Length(d1)*Length(d2))); - VectorMA(normals[mvert[idx[1]]], angle, tn, normals[mvert[idx[1]]]); - - VectorSubtract(xyz[idx[0]], xyz[idx[2]], d1); - VectorSubtract(xyz[idx[1]], xyz[idx[2]], d2); - angle = acos(DotProduct(d1, d2)/(Length(d1)*Length(d2))); - VectorMA(normals[mvert[idx[2]]], angle, tn, normals[mvert[idx[2]]]); - } - - /*skip over each additional surface that shares the same verts*/ - for(;;) - { - if (next && next->shares_verts == vcmodnum) - { - modnum++; - model = next; - next = model->nextsurf; - } - else - break; - } - - //the normals are not normalized yet. - for (i = 0; i < numverts; i++) - { - VectorNormalize(normals[i]); - } - - for (i = 0; i < numweights; i++, v++) - { - v->normal[0] = DotProduct(normals[mvert[v->vertexindex]], inversepose+9*v->boneindex+0) * v->org[3]; - v->normal[1] = DotProduct(normals[mvert[v->vertexindex]], inversepose+9*v->boneindex+3) * v->org[3]; - v->normal[2] = DotProduct(normals[mvert[v->vertexindex]], inversepose+9*v->boneindex+6) * v->org[3]; - } - - if (model->ofs_skel_norm) - memcpy(model->ofs_skel_norm, normals, numverts*sizeof(vec3_t)); - - //FIXME: save off the xyz+normals for this base pose as an optimisation for world objects. - Z_Free(inversepose); - Z_Free(normals); - Z_Free(xyz); - Z_Free(mvert); - - model = next; - modnum++; - } - return maxvdist+maxbdist; -#else - return 0; -#endif -} -#endif #endif @@ -1415,61 +1194,150 @@ const float *Alias_GetBoneInformation(galiasinfo_t *inf, framestate_t *framestat static void Alias_BuildSkeletalMesh(mesh_t *mesh, framestate_t *framestate, galiasinfo_t *inf) { - if (inf->ofs_skel_idx) - { - qbyte *fte_restrict bidx = inf->ofs_skel_idx[0]; - float *fte_restrict weight = inf->ofs_skel_weight[0]; + qbyte *fte_restrict bidx = inf->ofs_skel_idx[0]; + float *fte_restrict weight = inf->ofs_skel_weight[0]; - if (meshcache.bonecachetype != SKEL_INVERSE_ABSOLUTE) - meshcache.usebonepose = Alias_GetBoneInformation(inf, framestate, meshcache.bonecachetype=SKEL_INVERSE_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, MAX_BONES); + if (meshcache.bonecachetype != SKEL_INVERSE_ABSOLUTE) + meshcache.usebonepose = Alias_GetBoneInformation(inf, framestate, meshcache.bonecachetype=SKEL_INVERSE_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, MAX_BONES); - if (1) - Alias_TransformVerticies_VNST(meshcache.usebonepose, inf->numverts, bidx, weight, - inf->ofs_skel_xyz[0], mesh->xyz_array[0], - inf->ofs_skel_norm[0], mesh->normals_array[0], - inf->ofs_skel_svect[0], mesh->snormals_array[0], - inf->ofs_skel_tvect[0], mesh->tnormals_array[0] - ); - else - Alias_TransformVerticies_VN(meshcache.usebonepose, inf->numverts, bidx, weight, - inf->ofs_skel_xyz[0], mesh->xyz_array[0], - inf->ofs_skel_norm[0], mesh->normals_array[0] - ); - } + if (1) + Alias_TransformVerticies_VNST(meshcache.usebonepose, inf->numverts, bidx, weight, + inf->ofs_skel_xyz[0], mesh->xyz_array[0], + inf->ofs_skel_norm[0], mesh->normals_array[0], + inf->ofs_skel_svect[0], mesh->snormals_array[0], + inf->ofs_skel_tvect[0], mesh->tnormals_array[0] + ); else - { - galisskeletaltransforms_t *weights = inf->ofsswtransforms; - int numweights = inf->numswtransforms; - if (meshcache.bonecachetype != SKEL_ABSOLUTE) - meshcache.usebonepose = Alias_GetBoneInformation(inf, framestate, meshcache.bonecachetype=SKEL_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, MAX_BONES); - memset(mesh->xyz_array, 0, mesh->numvertexes*sizeof(vecV_t)); - memset(mesh->normals_array, 0, mesh->numvertexes*sizeof(vec3_t)); - Alias_TransformVerticies_SW(meshcache.usebonepose, weights, numweights, mesh->xyz_array, mesh->normals_array); - } + Alias_TransformVerticies_VN(meshcache.usebonepose, inf->numverts, bidx, weight, + inf->ofs_skel_xyz[0], mesh->xyz_array[0], + inf->ofs_skel_norm[0], mesh->normals_array[0] + ); } static void Alias_BuildSkeletalVPositionsPose(float *xyzout, skeltype_t bonetype, const float *bonepose, galiasinfo_t *inf) { float buffer[MAX_BONES*12]; float bufferalt[MAX_BONES*12]; - if (inf->ofs_skel_idx) - { - qbyte *fte_restrict bidx = inf->ofs_skel_idx[0]; - float *fte_restrict xyzin = inf->ofs_skel_xyz[0]; - float *fte_restrict weight = inf->ofs_skel_weight[0]; - bonepose = Alias_ConvertBoneData(bonetype, bonepose, inf->numbones, inf->ofsbones, SKEL_INVERSE_ABSOLUTE, buffer, bufferalt, MAX_BONES); + qbyte *fte_restrict bidx = inf->ofs_skel_idx[0]; + float *fte_restrict xyzin = inf->ofs_skel_xyz[0]; + float *fte_restrict weight = inf->ofs_skel_weight[0]; + bonepose = Alias_ConvertBoneData(bonetype, bonepose, inf->numbones, inf->ofsbones, SKEL_INVERSE_ABSOLUTE, buffer, bufferalt, MAX_BONES); - Alias_TransformVerticies_V(bonepose, inf->numverts, bidx, weight, xyzin, xyzout); - } - else - { - galisskeletaltransforms_t *weights = inf->ofsswtransforms; - int numweights = inf->numswtransforms; - bonepose = Alias_ConvertBoneData(bonetype, bonepose, inf->numbones, inf->ofsbones, SKEL_ABSOLUTE, buffer, bufferalt, MAX_BONES); - Alias_TransformVerticies_SW(bonepose, weights, numweights, (vecV_t*)xyzout, NULL); - } + Alias_TransformVerticies_V(bonepose, inf->numverts, bidx, weight, xyzin, xyzout); } +#if defined(MD5MODELS) || defined(ZYMOTICMODELS) || defined(DPMMODELS) +static int QDECL sortweights(const void *v1, const void *v2) //helper for Alias_BuildGPUWeights +{ + const galisskeletaltransforms_t *w1=v1, *w2=v2; + if (w1->vertexindex - w2->vertexindex) + return w1->vertexindex - w2->vertexindex; + if (w1->org[3] > w2->org[3]) + return -1; + if (w1->org[3] < w2->org[3]) + return 1; + return 0; +} +//takes old-style vertex transforms and tries to generate something more friendly for GPUs, limited to only 4 influences per vertex +static void Alias_BuildGPUWeights(model_t *mod, galiasinfo_t *inf, size_t num_trans, galisskeletaltransforms_t *trans, qboolean calcnorms) +{ + size_t i, j, v; + double strength; + const float *matrix, *basepose; + const galisskeletaltransforms_t *t; + + float buffer[MAX_BONES*12]; + float bufferalt[MAX_BONES*12]; + + //first sort the weights by the verticies, then by strength. this is probably already done, but whatever. + qsort(trans, num_trans, sizeof(*trans), sortweights); + + inf->ofs_skel_xyz = ZG_Malloc(&mod->memgroup, sizeof(*inf->ofs_skel_xyz) * inf->numverts); + inf->ofs_skel_norm = ZG_Malloc(&mod->memgroup, sizeof(*inf->ofs_skel_norm) * inf->numverts); + inf->ofs_skel_svect = ZG_Malloc(&mod->memgroup, sizeof(*inf->ofs_skel_svect) * inf->numverts); + inf->ofs_skel_tvect = ZG_Malloc(&mod->memgroup, sizeof(*inf->ofs_skel_tvect) * inf->numverts); + inf->ofs_skel_idx = ZG_Malloc(&mod->memgroup, sizeof(*inf->ofs_skel_idx) * inf->numverts); + inf->ofs_skel_weight = ZG_Malloc(&mod->memgroup, sizeof(*inf->ofs_skel_weight) * inf->numverts); + + //make sure we have a base pose for all animations to be relative to. first animation's first pose if there isn't an explicit one + basepose = inf->baseframeofs; + if (!basepose) + { + if (!inf->numanimations || !inf->ofsanimations[0].boneofs) + { + Con_DPrintf("Alias_BuildGPUWeights: no base pose\n"); + return; //its fucked jim + } + basepose = Alias_ConvertBoneData(inf->ofsanimations[0].skeltype, inf->ofsanimations[0].boneofs, inf->numbones, inf->ofsbones, SKEL_ABSOLUTE, buffer, bufferalt, MAX_BONES); + } + + //make sure we have bone inversions + for (i = 0; i < inf->numbones; i++) + { + Matrix3x4_Invert_Simple(basepose+i*12, inf->ofsbones[i].inverse); + } + + //validate the indicies, because we can. + for (i = 0; i < inf->numindexes; i++) + { + if (inf->ofs_indexes[i] >= inf->numverts) + Con_DPrintf("Alias_BuildGPUWeights: bad index\n"); + } + + //walk the (sorted) transforms and calculate the proper position for each vert, and the strongest influences too. + for (i = 0; i < num_trans; i++) + { + t = &trans[i]; + v = t->vertexindex; + if (v >= inf->numverts || t->boneindex >= inf->numbones) + { + Con_DPrintf("Alias_BuildGPUWeights: bad vertex\n"); + continue; + } + matrix = basepose + t->boneindex*12; + + //calculate the correct position in the base pose + inf->ofs_skel_xyz[v][0] += t->org[0] * matrix[0] + t->org[1] * matrix[1] + t->org[2] * matrix[ 2] + t->org[3] * matrix[ 3]; + inf->ofs_skel_xyz[v][1] += t->org[0] * matrix[4] + t->org[1] * matrix[5] + t->org[2] * matrix[ 6] + t->org[3] * matrix[ 7]; + inf->ofs_skel_xyz[v][2] += t->org[0] * matrix[8] + t->org[1] * matrix[9] + t->org[2] * matrix[10] + t->org[3] * matrix[11]; + if (!calcnorms) + { + inf->ofs_skel_norm[v][0] += t->org[0] * matrix[0] + t->org[1] * matrix[1] + t->org[2] * matrix[ 2]; + inf->ofs_skel_norm[v][1] += t->org[0] * matrix[4] + t->org[1] * matrix[5] + t->org[2] * matrix[ 6]; + inf->ofs_skel_norm[v][2] += t->org[0] * matrix[8] + t->org[1] * matrix[9] + t->org[2] * matrix[10]; + } + + //we sorted them so we're guarenteed to see the highest influences first. + for (j = 0; j < 4; j++) + { + if (!inf->ofs_skel_weight[v][j]) + { + inf->ofs_skel_weight[v][j] = t->org[3]; + for (; j < 4; j++) //be nicer on cache, if necessary + inf->ofs_skel_idx[v][j] = t->boneindex; + break; + } + } + } + + //weights should add up to 1, but might not if we had too many influences. make sure they don't move, at least in their base pose. + for (v = 0; v < inf->numverts; v++) + { + strength = inf->ofs_skel_weight[v][0] + inf->ofs_skel_weight[v][1] + inf->ofs_skel_weight[v][2] + inf->ofs_skel_weight[v][3]; + if (strength && strength != 1) + { + strength = 1/strength; + Vector4Scale(inf->ofs_skel_weight[v], strength, inf->ofs_skel_weight[v]); + } + } + +#ifndef SERVERONLY + Mod_AccumulateTextureVectors(inf->ofs_skel_xyz, inf->ofs_st_array, inf->ofs_skel_norm, inf->ofs_skel_svect, inf->ofs_skel_tvect, inf->ofs_indexes, inf->numindexes, calcnorms); + Mod_NormaliseTextureVectors(inf->ofs_skel_norm, inf->ofs_skel_svect, inf->ofs_skel_tvect, inf->numverts, calcnorms); +#endif +} +#endif + #ifndef SERVERONLY static void Alias_DrawSkeletalBones(galiasbone_t *bones, float *bonepose, int bonecount, int basebone) { @@ -1664,7 +1532,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in usebones = false; else if (inf->ofs_skel_xyz && !inf->ofs_skel_weight) usebones = false; - else if (e->fatness || !inf->ofs_skel_idx || inf->numswtransforms || inf->numbones > MAX_GPU_BONES) + else if (e->fatness || !inf->ofs_skel_idx || inf->numbones > MAX_GPU_BONES) #endif usebones = false; @@ -2602,8 +2470,8 @@ void Mod_BuildTextureVectors(galiasinfo_t *galias) sv = pose->ofssvector; tv = pose->ofstvector; - Mod_AccumulateTextureVectors(vc, tc, nv, sv, tv, idx, galias->numindexes); - Mod_NormaliseTextureVectors(nv, sv, tv, galias->numverts); + Mod_AccumulateTextureVectors(vc, tc, nv, sv, tv, idx, galias->numindexes, false); + Mod_NormaliseTextureVectors(nv, sv, tv, galias->numverts, false); } } } @@ -3634,6 +3502,7 @@ qboolean QDECL Mod_LoadQ1Model (model_t *mod, void *buffer, size_t fsize) Mesh_HandleFramegroupsFile(mod, galias); + mod->numframes = galias->numanimations; mod->meshinfo = galias; mod->funcs.NativeTrace = Mod_Trace; @@ -3972,6 +3841,7 @@ qboolean QDECL Mod_LoadQ2Model (model_t *mod, void *buffer, size_t fsize) Mod_ClampModelSize(mod); mod->meshinfo = galias; + mod->numframes = galias->numanimations; mod->type = mod_alias; mod->funcs.NativeTrace = Mod_Trace; @@ -4000,8 +3870,10 @@ int Mod_GetNumBones(model_t *model, qboolean allowtags) return inf->numbones; else #endif +#ifdef MD3MODELS if (allowtags) return inf->numtags; +#endif return 0; } #ifdef HALFLIFEMODELS @@ -4048,217 +3920,273 @@ galiasbone_t *Mod_GetBoneInfo(model_t *model, int *numbones) int Mod_GetBoneParent(model_t *model, int bonenum) { #ifdef SKELETALMODELS - galiasbone_t *bone; - galiasinfo_t *inf; + if (model && model->type == mod_alias) + { + galiasbone_t *bone; + galiasinfo_t *inf; + inf = Mod_Extradata(model); - if (!model || model->type != mod_alias) - return 0; - - inf = Mod_Extradata(model); - - - bonenum--; - if ((unsigned int)bonenum >= inf->numbones) - return 0; //no parent - bone = inf->ofsbones; - return bone[bonenum].parent+1; + bonenum--; + if ((unsigned int)bonenum >= inf->numbones) + return 0; //no parent + bone = inf->ofsbones; + return bone[bonenum].parent+1; + } +#endif +#ifdef HALFLIFEMODELS + if (model && model->type == mod_halflife) + return HLMDL_GetBoneParent(model, bonenum-1)+1; #endif return 0; } -char *Mod_GetBoneName(model_t *model, int bonenum) +const char *Mod_GetBoneName(model_t *model, int bonenum) { #ifdef SKELETALMODELS - galiasbone_t *bone; - galiasinfo_t *inf; + if (model && model->type == mod_alias) + { + galiasbone_t *bone; + galiasinfo_t *inf; + inf = Mod_Extradata(model); - if (!model || model->type != mod_alias) - return 0; - - inf = Mod_Extradata(model); - - - bonenum--; - if ((unsigned int)bonenum >= inf->numbones) - return 0; //no parent - bone = inf->ofsbones; - return bone[bonenum].name; + bonenum--; + if ((unsigned int)bonenum >= inf->numbones) + return 0; //no parent + bone = inf->ofsbones; + return bone[bonenum].name; + } +#endif +#ifdef HALFLIFEMODELS + if (model && model->type == mod_halflife) + return HLMDL_GetBoneName(model, bonenum-1); #endif return 0; } qboolean Mod_GetTag(model_t *model, int tagnum, framestate_t *fstate, float *result) { - galiasinfo_t *inf; - - - if (!model || model->type != mod_alias) - return false; - - inf = Mod_Extradata(model); -#ifdef SKELETALMODELS - if (inf->numbones) +#ifdef HALFLIFEMODELS + if (model && model->type == mod_halflife) { - galiasbone_t *bone = inf->ofsbones; - - float tempmatrix[12]; //flipped between this and bonematrix - float *matrix; //the matrix for a single bone in a single pose. - float m[12]; //combined interpolated version of 'matrix'. - int b, k; //counters - - int numbonegroups = 0; - skellerps_t lerps[FS_COUNT], *lerp; - - if (tagnum <= 0 || tagnum > inf->numbones) - return false; - tagnum--; //tagnum 0 is 'use my angles/org' - - //data comes from skeletal object, if possible - if (!numbonegroups && fstate->bonestate) + int numbones = Mod_GetNumBones(model, false); + if (tagnum > 0 && tagnum <= numbones) { - if (tagnum >= fstate->bonecount) + float relatives[MAX_BONES*12]; + float tempmatrix[12]; //flipped between this and bonematrix + float *matrix; //the matrix for a single bone in a single pose. + float *lerps = relatives; + + if (tagnum <= 0 || tagnum > numbones) return false; + tagnum--; //tagnum 0 is 'use my angles/org' - if (fstate->skeltype == SKEL_ABSOLUTE) - { //can just directly read it, woo. - memcpy(result, fstate->bonestate + 12 * tagnum, 12*sizeof(*result)); - return true; - } - - lerps[0].pose[0] = fstate->bonestate; - lerps[0].frac[0] = 1; - lerps[0].lerpcount = 1; - lerps[0].firstbone = 0; - lerps[0].endbone = fstate->bonecount; - numbonegroups = 1; - } - - //try getting the data from the frame state - if (!numbonegroups) - numbonegroups = Alias_FindRawSkelData(inf, fstate, lerps, 0, inf->numbones); - - //try base pose? - if (!numbonegroups && inf->baseframeofs) - { - lerps[0].pose[0] = inf->baseframeofs; - lerps[0].frac[0] = 1; - lerps[0].lerpcount = 1; - lerps[0].firstbone = 0; - lerps[0].endbone = inf->numbones; - numbonegroups = 1; - } - - //make sure it was all okay. - if (!numbonegroups || tagnum >= lerps[numbonegroups-1].endbone) - return false; - - //set up the identity matrix - for (k = 0;k < 12;k++) - result[k] = 0; - result[0] = 1; - result[5] = 1; - result[10] = 1; - while(tagnum >= 0) - { - for (lerp = lerps; tagnum < lerp->firstbone; lerp++) - ; - //set up the per-bone transform matrix - matrix = lerp->pose[0] + tagnum*12; - for (k = 0;k < 12;k++) - m[k] = matrix[k] * lerp->frac[0]; - for (b = 1;b < lerp->lerpcount;b++) + //data comes from skeletal object, if possible + if (fstate->bonestate) { - matrix = lerp->pose[b] + tagnum*12; - for (k = 0;k < 12;k++) - m[k] += matrix[k] * lerp->frac[b]; - } + if (tagnum >= fstate->bonecount) + return false; - if (lerp->skeltype == SKEL_ABSOLUTE) + if (fstate->skeltype == SKEL_ABSOLUTE) + { //can just directly read it, woo. + memcpy(result, fstate->bonestate + 12 * tagnum, 12*sizeof(*result)); + return true; + } + + lerps = fstate->bonestate; + } + else //try getting the data from the frame state { - memcpy(result, m, sizeof(tempmatrix)); - return true; + numbones = Mod_GetBoneRelations(model, 0, tagnum+1, fstate, relatives); + lerps = relatives; + + //make sure it was all okay. + if (tagnum >= numbones) + return false; } - memcpy(tempmatrix, result, sizeof(tempmatrix)); - R_ConcatTransforms((void*)m, (void*)tempmatrix, (void*)result); + while(tagnum >= 0) + { + //set up the per-bone transform matrix + matrix = lerps + tagnum*12; + memcpy(tempmatrix, result, sizeof(tempmatrix)); + R_ConcatTransforms((void*)matrix, (void*)tempmatrix, (void*)result); + tagnum = Mod_GetBoneParent(model, tagnum+1)-1; + } - tagnum = bone[tagnum].parent; + return true; } - - return true; } #endif - if (inf->numtags) + + if (model && model->type == mod_alias) { - md3tag_t *t1, *t2; - - int frame1, frame2; - //float f1time, f2time; //tags/md3s don't support framegroups. - float f2ness; - - frame1 = fstate->g[FS_REG].frame[0]; - frame2 = fstate->g[FS_REG].frame[1]; - //f1time = fstate->g[FS_REG].frametime[0]; - //f2time = fstate->g[FS_REG].frametime[1]; - f2ness = fstate->g[FS_REG].lerpweight[1]; - - if (tagnum <= 0 || tagnum > inf->numtags) - return false; - if (frame1 < 0) - return false; - if (frame1 >= inf->numtagframes) - frame1 = inf->numtagframes - 1; - if (frame2 < 0 || frame2 >= inf->numtagframes) - frame2 = frame1; - tagnum--; //tagnum 0 is 'use my angles/org' - - t1 = inf->ofstags; - t1 += tagnum; - t1 += inf->numtags*frame1; - - t2 = inf->ofstags; - t2 += tagnum; - t2 += inf->numtags*frame2; - - if (t1 == t2) + galiasinfo_t *inf = Mod_Extradata(model); +#ifdef SKELETALMODELS + if (inf->numbones) { - result[0] = t1->ang[0][0]; - result[1] = t1->ang[0][1]; - result[2] = t1->ang[0][2]; - result[3] = t1->org[0]; - result[4] = t1->ang[1][0]; - result[5] = t1->ang[1][1]; - result[6] = t1->ang[1][2]; - result[7] = t1->org[1]; - result[8] = t1->ang[2][0]; - result[9] = t1->ang[2][1]; - result[10] = t1->ang[2][2]; - result[11] = t1->org[2]; + galiasbone_t *bone = inf->ofsbones; + + float tempmatrix[12]; //flipped between this and bonematrix + float *matrix; //the matrix for a single bone in a single pose. + float m[12]; //combined interpolated version of 'matrix'. + int b, k; //counters + + int numbonegroups = 0; + skellerps_t lerps[FS_COUNT], *lerp; + + if (tagnum <= 0 || tagnum > inf->numbones) + return false; + tagnum--; //tagnum 0 is 'use my angles/org' + + //data comes from skeletal object, if possible + if (!numbonegroups && fstate->bonestate) + { + if (tagnum >= fstate->bonecount) + return false; + + if (fstate->skeltype == SKEL_ABSOLUTE) + { //can just directly read it, woo. + memcpy(result, fstate->bonestate + 12 * tagnum, 12*sizeof(*result)); + return true; + } + + lerps[0].pose[0] = fstate->bonestate; + lerps[0].frac[0] = 1; + lerps[0].lerpcount = 1; + lerps[0].firstbone = 0; + lerps[0].endbone = fstate->bonecount; + numbonegroups = 1; + } + + //try getting the data from the frame state + if (!numbonegroups) + numbonegroups = Alias_FindRawSkelData(inf, fstate, lerps, 0, inf->numbones); + + //try base pose? + if (!numbonegroups && inf->baseframeofs) + { + lerps[0].pose[0] = inf->baseframeofs; + lerps[0].frac[0] = 1; + lerps[0].lerpcount = 1; + lerps[0].firstbone = 0; + lerps[0].endbone = inf->numbones; + numbonegroups = 1; + } + + //make sure it was all okay. + if (!numbonegroups || tagnum >= lerps[numbonegroups-1].endbone) + return false; + + //set up the identity matrix + for (k = 0;k < 12;k++) + result[k] = 0; + result[0] = 1; + result[5] = 1; + result[10] = 1; + while(tagnum >= 0) + { + for (lerp = lerps; tagnum < lerp->firstbone; lerp++) + ; + //set up the per-bone transform matrix + matrix = lerp->pose[0] + tagnum*12; + for (k = 0;k < 12;k++) + m[k] = matrix[k] * lerp->frac[0]; + for (b = 1;b < lerp->lerpcount;b++) + { + matrix = lerp->pose[b] + tagnum*12; + for (k = 0;k < 12;k++) + m[k] += matrix[k] * lerp->frac[b]; + } + + if (lerp->skeltype == SKEL_ABSOLUTE) + { + memcpy(result, m, sizeof(tempmatrix)); + return true; + } + + memcpy(tempmatrix, result, sizeof(tempmatrix)); + R_ConcatTransforms((void*)m, (void*)tempmatrix, (void*)result); + + tagnum = bone[tagnum].parent; + } + + return true; } - else +#endif +#ifdef MD3MODELS + if (inf->numtags) { - float f1ness = 1-f2ness; - result[0] = t1->ang[0][0]*f1ness + t2->ang[0][0]*f2ness; - result[1] = t1->ang[0][1]*f1ness + t2->ang[0][1]*f2ness; - result[2] = t1->ang[0][2]*f1ness + t2->ang[0][2]*f2ness; - result[3] = t1->org[0]*f1ness + t2->org[0]*f2ness; - result[4] = t1->ang[1][0]*f1ness + t2->ang[1][0]*f2ness; - result[5] = t1->ang[1][1]*f1ness + t2->ang[1][1]*f2ness; - result[6] = t1->ang[1][2]*f1ness + t2->ang[1][2]*f2ness; - result[7] = t1->org[1]*f1ness + t2->org[1]*f2ness; - result[8] = t1->ang[2][0]*f1ness + t2->ang[2][0]*f2ness; - result[9] = t1->ang[2][1]*f1ness + t2->ang[2][1]*f2ness; - result[10] = t1->ang[2][2]*f1ness + t2->ang[2][2]*f2ness; - result[11] = t1->org[2]*f1ness + t2->org[2]*f2ness; + md3tag_t *t1, *t2; + + int frame1, frame2; + //float f1time, f2time; //tags/md3s don't support framegroups. + float f2ness; + + frame1 = fstate->g[FS_REG].frame[0]; + frame2 = fstate->g[FS_REG].frame[1]; + //f1time = fstate->g[FS_REG].frametime[0]; + //f2time = fstate->g[FS_REG].frametime[1]; + f2ness = fstate->g[FS_REG].lerpweight[1]; + + if (tagnum <= 0 || tagnum > inf->numtags) + return false; + if (frame1 < 0) + return false; + if (frame1 >= inf->numtagframes) + frame1 = inf->numtagframes - 1; + if (frame2 < 0 || frame2 >= inf->numtagframes) + frame2 = frame1; + tagnum--; //tagnum 0 is 'use my angles/org' + + t1 = inf->ofstags; + t1 += tagnum; + t1 += inf->numtags*frame1; + + t2 = inf->ofstags; + t2 += tagnum; + t2 += inf->numtags*frame2; + + if (t1 == t2) + { + result[0] = t1->ang[0][0]; + result[1] = t1->ang[0][1]; + result[2] = t1->ang[0][2]; + result[3] = t1->org[0]; + result[4] = t1->ang[1][0]; + result[5] = t1->ang[1][1]; + result[6] = t1->ang[1][2]; + result[7] = t1->org[1]; + result[8] = t1->ang[2][0]; + result[9] = t1->ang[2][1]; + result[10] = t1->ang[2][2]; + result[11] = t1->org[2]; + } + else + { + float f1ness = 1-f2ness; + result[0] = t1->ang[0][0]*f1ness + t2->ang[0][0]*f2ness; + result[1] = t1->ang[0][1]*f1ness + t2->ang[0][1]*f2ness; + result[2] = t1->ang[0][2]*f1ness + t2->ang[0][2]*f2ness; + result[3] = t1->org[0]*f1ness + t2->org[0]*f2ness; + result[4] = t1->ang[1][0]*f1ness + t2->ang[1][0]*f2ness; + result[5] = t1->ang[1][1]*f1ness + t2->ang[1][1]*f2ness; + result[6] = t1->ang[1][2]*f1ness + t2->ang[1][2]*f2ness; + result[7] = t1->org[1]*f1ness + t2->org[1]*f2ness; + result[8] = t1->ang[2][0]*f1ness + t2->ang[2][0]*f2ness; + result[9] = t1->ang[2][1]*f1ness + t2->ang[2][1]*f2ness; + result[10] = t1->ang[2][2]*f1ness + t2->ang[2][2]*f2ness; + result[11] = t1->org[2]*f1ness + t2->org[2]*f2ness; + } + + VectorNormalize(result); + VectorNormalize(result+4); + VectorNormalize(result+8); + + return true; } - - VectorNormalize(result); - VectorNormalize(result+4); - VectorNormalize(result+8); - - return true; +#endif } return false; } @@ -4267,7 +4195,6 @@ int Mod_TagNumForName(model_t *model, const char *name) { int i; galiasinfo_t *inf; - md3tag_t *t; if (!model) return 0; @@ -4277,29 +4204,35 @@ int Mod_TagNumForName(model_t *model, const char *name) if (model->type == mod_halflife) return HLMDL_BoneForName(model, name); #endif - if (model->type != mod_alias) - return 0; - inf = Mod_Extradata(model); + if (model->type == mod_alias) + { + inf = Mod_Extradata(model); #ifdef SKELETALMODELS - if (inf->numbones) - { - galiasbone_t *b; - b = inf->ofsbones; - for (i = 0; i < inf->numbones; i++) + if (inf->numbones) { - if (!strcmp(b[i].name, name)) - return i+1; + galiasbone_t *b; + b = inf->ofsbones; + for (i = 0; i < inf->numbones; i++) + { + if (!strcmp(b[i].name, name)) + return i+1; + } } - } #endif - t = inf->ofstags; - for (i = 0; i < inf->numtags; i++) - { - if (!strcmp(t[i].name, name)) - return i+1; +#ifdef MD3MODELS + if (inf->numtags) + { + md3tag_t *t = inf->ofstags; + for (i = 0; i < inf->numtags; i++) + { + if (!strcmp(t[i].name, name)) + return i+1; + } + } +#endif + return 0; } - return 0; } @@ -4516,6 +4449,13 @@ float Mod_GetFrameDuration(model_t *model, int surfaceidx, int frameno) return 0; } +int Mod_GetFrameCount(struct model_s *model) +{ + if (!model) + return 0; + return model->numframes; +} + #ifdef MD3MODELS @@ -4830,6 +4770,7 @@ qboolean QDECL Mod_LoadQ3Model(model_t *mod, void *buffer, size_t fsize) Mod_ClampModelSize(mod); mod->type = mod_alias; + mod->numframes = root->numanimations; mod->meshinfo = root; mod->funcs.NativeTrace = Mod_Trace; @@ -4913,6 +4854,7 @@ qboolean QDECL Mod_LoadZymoticModel(model_t *mod, void *buffer, size_t fsize) zymtype1header_t *header; galiasinfo_t *root; + size_t numtransforms; galisskeletaltransforms_t *transforms; zymvertex_t *intrans; @@ -4969,16 +4911,15 @@ qboolean QDECL Mod_LoadZymoticModel(model_t *mod, void *buffer, size_t fsize) root = ZG_Malloc(&mod->memgroup, sizeof(galiasinfo_t)*header->numsurfaces); - root->numswtransforms = header->lump_verts.length/sizeof(zymvertex_t); - transforms = ZG_Malloc(&mod->memgroup, root->numswtransforms*sizeof(*transforms)); - root->ofsswtransforms = transforms; + numtransforms = header->lump_verts.length/sizeof(zymvertex_t); + transforms = Z_Malloc(numtransforms*sizeof(*transforms)); vertbonecounts = (int *)((char*)header + header->lump_vertbonecounts.start); intrans = (zymvertex_t *)((char*)header + header->lump_verts.start); vertbonecounts[0] = BigLong(vertbonecounts[0]); multiplier = 1.0f / vertbonecounts[0]; - for (i = 0, v=0; i < root->numswtransforms; i++) + for (i = 0, v=0; i < numtransforms; i++) { while(!vertbonecounts[v]) { @@ -5013,7 +4954,7 @@ qboolean QDECL Mod_LoadZymoticModel(model_t *mod, void *buffer, size_t fsize) root->numverts = v+1; root->numbones = header->numbones; - bone = ZG_Malloc(&mod->memgroup, root->numswtransforms*sizeof(*transforms)); + bone = ZG_Malloc(&mod->memgroup, numtransforms*sizeof(*transforms)); inbone = (zymbone_t*)((char*)header + header->lump_bones.start); for (i = 0; i < root->numbones; i++) { @@ -5063,6 +5004,11 @@ qboolean QDECL Mod_LoadZymoticModel(model_t *mod, void *buffer, size_t fsize) #ifndef SERVERONLY skinfiles = Mod_CountSkinFiles(mod->name); + if (skinfiles < 1) + skinfiles = 1; + + skin = ZG_Malloc(&mod->memgroup, (sizeof(galiasskin_t)+sizeof(skinframe_t))*skinfiles*header->numsurfaces); + skinframe = (skinframe_t*)(skin+skinfiles*header->numsurfaces); #endif for (i = 0; i < header->numsurfaces; i++, surfname+=32) @@ -5077,18 +5023,20 @@ qboolean QDECL Mod_LoadZymoticModel(model_t *mod, void *buffer, size_t fsize) #else root[i].ofs_st_array = stcoords; root[i].numskins = skinfiles; - - skin = ZG_Malloc(&mod->memgroup, (sizeof(galiasskin_t)+sizeof(skinframe_t*))*skinfiles); - skinframe = (skinframe_t*)(skin+skinfiles); - for (j = 0; j < skinfiles; j++, skinframe++) - { - skin[j].numframes = 1; //non-sequenced skins. - skin[j].frame = skinframe; - -// shaders[0] = Mod_LoadSkinFile(NULL, &root[i], j, NULL, 0, 0, NULL, skin->name); - } - root[i].ofsskins = skin; + + for (j = 0; j < skinfiles; j++) + { + skin->skinwidth = 1; + skin->skinheight = 1; + skin->skinspeed = 10; /*something to avoid div-by-0*/ + skin->numframes = 1; //non-sequenced skins. + skin->frame = skinframe; + skin++; + + Q_strncpyz(skinframe->shadername, surfname, sizeof(skinframe->shadername)); + skinframe++; + } #endif } @@ -5121,7 +5069,8 @@ qboolean QDECL Mod_LoadZymoticModel(model_t *mod, void *buffer, size_t fsize) root[i].ofsbones = root[0].ofsbones; } - Alias_CalculateSkeletalNormals(root); + Alias_BuildGPUWeights(mod, root, numtransforms, transforms, true); + Z_Free(transforms); mod->flags = Mod_ReadFlagsFromMD1(mod->name, 0); //file replacement - inherit flags from any defunc mdl files. @@ -5129,6 +5078,7 @@ qboolean QDECL Mod_LoadZymoticModel(model_t *mod, void *buffer, size_t fsize) mod->meshinfo = root; + mod->numframes = root->numanimations; mod->type = mod_alias; mod->funcs.NativeTrace = Mod_Trace; @@ -5264,7 +5214,6 @@ qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize) galiasanimation_t *group; float *animmatrix, *basematrix; index_t *indexes; - float vrad; int bonemap[MAX_BONES]; char *e; size_t psasize; @@ -5282,16 +5231,10 @@ qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize) pskanimkeys_t *animkeys = NULL; unsigned int num_animinfo=0, num_animkeys=0; -//#define PSK_GPU -#ifndef PSK_GPU - unsigned int num_trans; - galisskeletaltransforms_t *trans; -#else vecV_t *skel_xyz; - vec3_t *skel_norm; + vec3_t *skel_norm, *skel_svect, *skel_tvect; byte_vec4_t *skel_idx; vec4_t *skel_weights; -#endif /*load the psk*/ while (pos < fsize && !fail) @@ -5569,44 +5512,12 @@ qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize) Matrix3x4_Invert_Simple(basematrix+i*12, bones[i].inverse); } - -#ifndef PSK_GPU - /*expand the translations*/ - num_trans = 0; - for (i = 0; i < num_vtxw; i++) - { - for (j = 0; j < num_rawweights; j++) - { - if (rawweights[j].pntsindex == vtxw[i].pntsindex) - { - num_trans++; - } - } - } - trans = ZG_Malloc(&mod->memgroup, sizeof(*trans)*num_trans); - num_trans = 0; - for (i = 0; i < num_vtxw; i++) - { -// first_trans = num_trans; - for (j = 0; j < num_rawweights; j++) - { - if (rawweights[j].pntsindex == vtxw[i].pntsindex) - { - vec3_t tmp; - trans[num_trans].vertexindex = i; - trans[num_trans].boneindex = rawweights[j].boneindex; - VectorTransform(pnts[rawweights[j].pntsindex].origin, (void*)bones[rawweights[j].boneindex].inverse, tmp); - VectorScale(tmp, rawweights[j].weight, trans[num_trans].org); - trans[num_trans].org[3] = rawweights[j].weight; - num_trans++; - } - } - } -#else - skel_xyz = Hunk_Alloc(sizeof(*skel_xyz) * num_vtxw); - skel_norm = Hunk_Alloc(sizeof(*skel_norm) * num_vtxw); - skel_idx = Hunk_Alloc(sizeof(*skel_idx) * num_vtxw); - skel_weights = Hunk_Alloc(sizeof(*skel_weights) * num_vtxw); + skel_xyz = ZG_Malloc(&mod->memgroup, sizeof(*skel_xyz) * num_vtxw); + skel_norm = ZG_Malloc(&mod->memgroup, sizeof(*skel_norm) * num_vtxw); + skel_svect = ZG_Malloc(&mod->memgroup, sizeof(*skel_svect) * num_vtxw); + skel_tvect = ZG_Malloc(&mod->memgroup, sizeof(*skel_tvect) * num_vtxw); + skel_idx = ZG_Malloc(&mod->memgroup, sizeof(*skel_idx) * num_vtxw); + skel_weights = ZG_Malloc(&mod->memgroup, sizeof(*skel_weights) * num_vtxw); for (i = 0; i < num_vtxw; i++) { float t; @@ -5641,12 +5552,10 @@ qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize) for (j = 0; j < 4; j++) skel_weights[i][j] *= 1/t; - skel_xyz[i][0] = pnts[vtxw[i].pntsindex].origin[0]; skel_xyz[i][1] = pnts[vtxw[i].pntsindex].origin[1]; skel_xyz[i][2] = pnts[vtxw[i].pntsindex].origin[2]; } -#endif #ifndef SERVERONLY /*st coords, all share the same list*/ @@ -5760,7 +5669,9 @@ qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize) group->skeltype = SKEL_ABSOLUTE; } + #ifndef SERVERONLY + //client builds need skin info skin = ZG_Malloc(&mod->memgroup, num_matt * (sizeof(galiasskin_t) + sizeof(skinframe_t))); sframes = (skinframe_t*)(skin + num_matt); for (i = 0; i < num_matt; i++, skin++) @@ -5778,13 +5689,14 @@ qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize) gmdl[i].ofs_st_array = stcoord; gmdl[i].numverts = num_vtxw; #else + //server-only builds for (i = 0; i < num_matt; i++) { #endif + //common to all builds gmdl[i].ofsanimations = group; gmdl[i].numanimations = num_animinfo; - gmdl[i].baseframeofs = basematrix; gmdl[i].numindexes = 0; for (j = 0; j < num_face; j++) @@ -5800,24 +5712,29 @@ qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize) gmdl[i].ofs_indexes = indexes; indexes += gmdl[i].numindexes; + //all surfaces share bones + gmdl[i].baseframeofs = basematrix; gmdl[i].ofsbones = bones; gmdl[i].numbones = num_boneinfo; + gmdl[i].shares_bones = 0; -#ifndef PSK_GPU - gmdl[i].ofsswtransforms = trans; - gmdl[i].numswtransforms = num_trans; -#else + //all surfaces share verts, but not indexes. gmdl[i].ofs_skel_idx = skel_idx; gmdl[i].ofs_skel_weight = skel_weights; gmdl[i].ofs_skel_xyz = skel_xyz; gmdl[i].ofs_skel_norm = skel_norm; -#endif - + gmdl[i].ofs_skel_svect = skel_svect; + gmdl[i].ofs_skel_tvect = skel_tvect; gmdl[i].shares_verts = 0; - gmdl[i].shares_bones = 0; + gmdl[i].nextsurf = (i != num_matt-1)?&gmdl[i+1]:NULL; } +#ifndef SERVERONLY + Mod_AccumulateTextureVectors(skel_xyz, stcoord, skel_norm, skel_svect, skel_tvect, gmdl[0].ofs_indexes, indexes-gmdl[0].ofs_indexes, true); + Mod_NormaliseTextureVectors(skel_norm, skel_svect, skel_tvect, num_vtxw, true); +#endif + BZ_Free(psabuffer); if (fail) { @@ -5825,11 +5742,10 @@ qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize) } - vrad = Alias_CalculateSkeletalNormals(gmdl); +// mod->radius = Alias_CalculateSkeletalNormals(gmdl); - mod->mins[0] = mod->mins[1] = mod->mins[2] = -vrad; - mod->maxs[0] = mod->maxs[1] = mod->maxs[2] = vrad; - mod->radius = vrad; + mod->mins[0] = mod->mins[1] = mod->mins[2] = -mod->radius; + mod->maxs[0] = mod->maxs[1] = mod->maxs[2] = mod->radius; mod->flags = Mod_ReadFlagsFromMD1(mod->name, 0); //file replacement - inherit flags from any defunc mdl files. @@ -5837,6 +5753,7 @@ qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize) mod->meshinfo = gmdl; + mod->numframes = gmdl->numanimations; mod->type = mod_alias; mod->funcs.NativeTrace = Mod_Trace; return true; @@ -5949,7 +5866,7 @@ qboolean QDECL Mod_LoadDarkPlacesModel(model_t *mod, void *buffer, size_t fsize) dpmvertex_t *vert; dpmbonevert_t *bonevert; - galisskeletaltransforms_t *transforms; + galisskeletaltransforms_t *transforms, *firsttransform; galiasbone_t *outbone; dpmbone_t *inbone; @@ -6002,86 +5919,6 @@ qboolean QDECL Mod_LoadDarkPlacesModel(model_t *mod, void *buffer, size_t fsize) root = ZG_Malloc(&mod->memgroup, sizeof(galiasinfo_t)*header->num_meshs); - mesh = (dpmmesh_t*)((char*)buffer + header->ofs_meshs); - for (i = 0; i < header->num_meshs; i++, mesh++) - { - //work out how much memory we need to allocate - - mesh->num_verts = BigLong(mesh->num_verts); - mesh->num_tris = BigLong(mesh->num_tris); - mesh->ofs_verts = BigLong(mesh->ofs_verts); - mesh->ofs_texcoords = BigLong(mesh->ofs_texcoords); - mesh->ofs_indices = BigLong(mesh->ofs_indices); - mesh->ofs_groupids = BigLong(mesh->ofs_groupids); - - - numtransforms = 0; - //count and byteswap the transformations - vert = (dpmvertex_t*)((char *)buffer+mesh->ofs_verts); - for (j = 0; j < mesh->num_verts; j++) - { - vert->numbones = BigLong(vert->numbones); - numtransforms += vert->numbones; - bonevert = (dpmbonevert_t*)(vert+1); - vert = (dpmvertex_t*)(bonevert+vert->numbones); - } - - m = &root[i]; - m->shares_verts = i; - m->shares_bones = 0; -#ifdef SERVERONLY - transforms = ZG_Malloc(&mod->memgroup, numtransforms*sizeof(galisskeletaltransforms_t) + mesh->num_tris*3*sizeof(index_t)); -#else - outst = ZG_Malloc(&mod->memgroup, mesh->num_verts*sizeof(vec2_t) + numtransforms*sizeof(galisskeletaltransforms_t) + mesh->num_tris*3*sizeof(index_t)); - m->ofs_st_array = (vec2_t*)outst; - m->numverts = mesh->num_verts; - inst = (float*)((char*)buffer + mesh->ofs_texcoords); - for (j = 0; j < mesh->num_verts; j++, outst+=2, inst+=2) - { - outst[0] = BigFloat(inst[0]); - outst[1] = BigFloat(inst[1]); - } - - transforms = (galisskeletaltransforms_t*)outst; -#endif - - //build the transform list. - m->ofsswtransforms = transforms; - m->numswtransforms = numtransforms; - vert = (dpmvertex_t*)((char *)buffer+mesh->ofs_verts); - for (j = 0; j < mesh->num_verts; j++) - { - bonevert = (dpmbonevert_t*)(vert+1); - for (k = 0; k < vert->numbones; k++, bonevert++, transforms++) - { - transforms->boneindex = BigLong(bonevert->bonenum); - transforms->vertexindex = j; - transforms->org[0] = BigFloat(bonevert->origin[0]); - transforms->org[1] = BigFloat(bonevert->origin[1]); - transforms->org[2] = BigFloat(bonevert->origin[2]); - transforms->org[3] = BigFloat(bonevert->influence); -#ifndef SERVERONLY - transforms->normal[0] = BigFloat(bonevert->normal[0]); - transforms->normal[1] = BigFloat(bonevert->normal[1]); - transforms->normal[2] = BigFloat(bonevert->normal[2]); -#endif - } - //FIXME: transform these verts into the base pose, prioritise the weights, clamp to 4 weights, and then generate per-vertex arrays that are simple enough for the gpu to be happy. - vert = (dpmvertex_t*)bonevert; - } - - index = (unsigned int*)((char*)buffer + mesh->ofs_indices); - outdex = (index_t *)transforms; - m->ofs_indexes = outdex; - m->numindexes = mesh->num_tris*3; - for (j = 0; j < mesh->num_tris; j++, index += 3, outdex += 3) - { - outdex[0] = BigLong(index[2]); - outdex[1] = BigLong(index[1]); - outdex[2] = BigLong(index[0]); - } - } - outbone = ZG_Malloc(&mod->memgroup, sizeof(galiasbone_t)*header->num_bones); inbone = (dpmbone_t*)((char*)buffer + header->ofs_bones); for (i = 0; i < header->num_bones; i++) @@ -6178,16 +6015,86 @@ qboolean QDECL Mod_LoadDarkPlacesModel(model_t *mod, void *buffer, size_t fsize) m->ofsskins = skin; #endif + + + mesh->num_verts = BigLong(mesh->num_verts); + mesh->num_tris = BigLong(mesh->num_tris); + mesh->ofs_verts = BigLong(mesh->ofs_verts); + mesh->ofs_texcoords = BigLong(mesh->ofs_texcoords); + mesh->ofs_indices = BigLong(mesh->ofs_indices); + mesh->ofs_groupids = BigLong(mesh->ofs_groupids); + + index = (unsigned int*)((char*)buffer + mesh->ofs_indices); + outdex = ZG_Malloc(&mod->memgroup, mesh->num_tris*3*sizeof(index_t)); + m->ofs_indexes = outdex; + m->numindexes = mesh->num_tris*3; + for (j = 0; j < mesh->num_tris; j++, index += 3, outdex += 3) + { + outdex[0] = BigLong(index[2]); + outdex[1] = BigLong(index[1]); + outdex[2] = BigLong(index[0]); + } + + + numtransforms = 0; + //count and byteswap the transformations + vert = (dpmvertex_t*)((char *)buffer+mesh->ofs_verts); + for (j = 0; j < mesh->num_verts; j++) + { + vert->numbones = BigLong(vert->numbones); + numtransforms += vert->numbones; + bonevert = (dpmbonevert_t*)(vert+1); + vert = (dpmvertex_t*)(bonevert+vert->numbones); + } + + m = &root[i]; + m->shares_verts = i; + m->shares_bones = 0; +#ifndef SERVERONLY + outst = ZG_Malloc(&mod->memgroup, mesh->num_verts*sizeof(vec2_t)); + m->ofs_st_array = (vec2_t*)outst; + m->numverts = mesh->num_verts; + inst = (float*)((char*)buffer + mesh->ofs_texcoords); + for (j = 0; j < mesh->num_verts; j++, outst+=2, inst+=2) + { + outst[0] = BigFloat(inst[0]); + outst[1] = BigFloat(inst[1]); + } +#endif + + + firsttransform = transforms = Z_Malloc(numtransforms*sizeof(galisskeletaltransforms_t)); + //build the transform list. + vert = (dpmvertex_t*)((char *)buffer+mesh->ofs_verts); + for (j = 0; j < mesh->num_verts; j++) + { + bonevert = (dpmbonevert_t*)(vert+1); + for (k = 0; k < vert->numbones; k++, bonevert++, transforms++) + { + transforms->boneindex = BigLong(bonevert->bonenum); + transforms->vertexindex = j; + transforms->org[0] = BigFloat(bonevert->origin[0]); + transforms->org[1] = BigFloat(bonevert->origin[1]); + transforms->org[2] = BigFloat(bonevert->origin[2]); + transforms->org[3] = BigFloat(bonevert->influence); +#ifndef SERVERONLY + transforms->normal[0] = BigFloat(bonevert->normal[0]); + transforms->normal[1] = BigFloat(bonevert->normal[1]); + transforms->normal[2] = BigFloat(bonevert->normal[2]); +#endif + } + vert = (dpmvertex_t*)bonevert; + } + Alias_BuildGPUWeights(mod, root, numtransforms, firsttransform, false); + Z_Free(firsttransform); } - - Alias_CalculateSkeletalNormals(root); - mod->flags = Mod_ReadFlagsFromMD1(mod->name, 0); //file replacement - inherit flags from any defunc mdl files. Mod_ClampModelSize(mod); mod->meshinfo = root; + mod->numframes = root->numanimations; mod->type = mod_alias; mod->funcs.NativeTrace = Mod_Trace; @@ -6989,11 +6896,11 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer, size_t fsize) { //make something up for (i = 0; i < h->num_meshes; i++) { - Mod_AccumulateTextureVectors(gai[i].ofs_skel_xyz, gai[i].ofs_st_array, gai[i].ofs_skel_norm, gai[i].ofs_skel_svect, gai[i].ofs_skel_tvect, gai[i].ofs_indexes, gai[i].numindexes); + Mod_AccumulateTextureVectors(gai[i].ofs_skel_xyz, gai[i].ofs_st_array, gai[i].ofs_skel_norm, gai[i].ofs_skel_svect, gai[i].ofs_skel_tvect, gai[i].ofs_indexes, gai[i].numindexes, false); } for (i = 0; i < h->num_meshes; i++) { - Mod_NormaliseTextureVectors(gai[i].ofs_skel_norm, gai[i].ofs_skel_svect, gai[i].ofs_skel_tvect, gai[i].numverts); + Mod_NormaliseTextureVectors(gai[i].ofs_skel_norm, gai[i].ofs_skel_svect, gai[i].ofs_skel_tvect, gai[i].numverts, false); } } #endif @@ -7027,6 +6934,7 @@ qboolean QDECL Mod_LoadInterQuakeModel(model_t *mod, void *buffer, size_t fsize) Mod_ClampModelSize(mod); + mod->numframes = root->numanimations; mod->meshinfo = root; mod->type = mod_alias; @@ -7254,7 +7162,7 @@ galiasinfo_t *Mod_ParseMD5MeshModel(model_t *mod, char *buffer, char *modname) { #define MD5ERROR0PARAM(x) { Con_Printf(CON_ERROR x "\n"); return NULL; } #define MD5ERROR1PARAM(x, y) { Con_Printf(CON_ERROR x "\n", y); return NULL; } -#define EXPECT(x) buffer = COM_Parse(buffer); if (strcmp(com_token, x)) Sys_Error("MD5MESH: expected %s", x); +#define EXPECT(x) buffer = COM_ParseOut(buffer, token, sizeof(token)); if (strcmp(token, x)) Sys_Error("MD5MESH: expected %s", x); int numjoints = 0; int nummeshes = 0; qboolean foundjoints = false; @@ -7269,15 +7177,17 @@ galiasinfo_t *Mod_ParseMD5MeshModel(model_t *mod, char *buffer, char *modname) skinframe_t *frames; #endif char *filestart = buffer; + const int com_token = 4; + char token[1024]; float x, y, z, qx, qy, qz; - buffer = COM_Parse(buffer); - if (strcmp(com_token, "MD5Version")) + buffer = COM_ParseOut(buffer, token, sizeof(token)); + if (strcmp(token, "MD5Version")) MD5ERROR0PARAM("MD5 model without MD5Version identifier first"); - buffer = COM_Parse(buffer); - if (atoi(com_token) != 10) + buffer = COM_ParseOut(buffer, token, sizeof(token)); + if (atoi(token) != 10) MD5ERROR0PARAM("MD5 model with unsupported MD5Version"); @@ -7286,11 +7196,11 @@ galiasinfo_t *Mod_ParseMD5MeshModel(model_t *mod, char *buffer, char *modname) for(;;) { - buffer = COM_Parse(buffer); + buffer = COM_ParseOut(buffer, token, sizeof(token)); if (!buffer) break; - if (!strcmp(com_token, "numFrames")) + if (!strcmp(token, "numFrames")) { void *poseofs; galiasanimation_t *grp = ZG_Malloc(&mod->memgroup, sizeof(galiasanimation_t)); @@ -7300,31 +7210,31 @@ galiasinfo_t *Mod_ParseMD5MeshModel(model_t *mod, char *buffer, char *modname) grp->poseofs = poseofs; return root; } - else if (!strcmp(com_token, "commandline")) + else if (!strcmp(token, "commandline")) { //we don't need this buffer = strchr(buffer, '\"'); buffer = strchr((char*)buffer+1, '\"')+1; // buffer = COM_Parse(buffer); } - else if (!strcmp(com_token, "numJoints")) + else if (!strcmp(token, "numJoints")) { if (numjoints) MD5ERROR0PARAM("MD5MESH: numMeshes was already declared"); - buffer = COM_Parse(buffer); - numjoints = atoi(com_token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + numjoints = atoi(token); if (numjoints <= 0) MD5ERROR0PARAM("MD5MESH: Needs some joints"); } - else if (!strcmp(com_token, "numMeshes")) + else if (!strcmp(token, "numMeshes")) { if (nummeshes) MD5ERROR0PARAM("MD5MESH: numMeshes was already declared"); - buffer = COM_Parse(buffer); - nummeshes = atoi(com_token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + nummeshes = atoi(token); if (nummeshes <= 0) MD5ERROR0PARAM("MD5MESH: Needs some meshes"); } - else if (!strcmp(com_token, "joints")) + else if (!strcmp(token, "joints")) { if (foundjoints) MD5ERROR0PARAM("MD5MESH: Duplicate joints section"); @@ -7348,36 +7258,36 @@ galiasinfo_t *Mod_ParseMD5MeshModel(model_t *mod, char *buffer, char *modname) for (i = 0; i < numjoints; i++) { - buffer = COM_Parse(buffer); - Q_strncpyz(bones[i].name, com_token, sizeof(bones[i].name)); - buffer = COM_Parse(buffer); - bones[i].parent = atoi(com_token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + Q_strncpyz(bones[i].name, token, sizeof(bones[i].name)); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + bones[i].parent = atoi(token); if (bones[i].parent >= i) MD5ERROR0PARAM("MD5MESH: joints parent's must be lower"); if ((bones[i].parent < 0 && i) || (!i && bones[i].parent!=-1)) MD5ERROR0PARAM("MD5MESH: Only the root joint may have a negative parent"); EXPECT("("); - buffer = COM_Parse(buffer); - x = atof(com_token); - buffer = COM_Parse(buffer); - y = atof(com_token); - buffer = COM_Parse(buffer); - z = atof(com_token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + x = atof(token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + y = atof(token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + z = atof(token); EXPECT(")"); EXPECT("("); - buffer = COM_Parse(buffer); - qx = atof(com_token); - buffer = COM_Parse(buffer); - qy = atof(com_token); - buffer = COM_Parse(buffer); - qz = atof(com_token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + qx = atof(token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + qy = atof(token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + qz = atof(token); EXPECT(")"); GenMatrix(x, y, z, qx, qy, qz, posedata+i*12); } EXPECT("}"); } - else if (!strcmp(com_token, "mesh")) + else if (!strcmp(token, "mesh")) { int numverts = 0; int numweights = 0; @@ -7414,6 +7324,7 @@ galiasinfo_t *Mod_ParseMD5MeshModel(model_t *mod, char *buffer, char *modname) else { inf = ZG_Malloc(&mod->memgroup, sizeof(*inf)); + inf->shares_verts = lastsurf->shares_verts+1; lastsurf->nextsurf = inf; lastsurf = inf; } @@ -7436,24 +7347,24 @@ galiasinfo_t *Mod_ParseMD5MeshModel(model_t *mod, char *buffer, char *modname) EXPECT("{"); for(;;) { - buffer = COM_Parse(buffer); + buffer = COM_ParseOut(buffer, token, sizeof(token)); if (!buffer) MD5ERROR0PARAM("MD5MESH: unexpected eof"); - if (!strcmp(com_token, "shader")) + if (!strcmp(token, "shader")) { - buffer = COM_Parse(buffer); + buffer = COM_ParseOut(buffer, token, sizeof(token)); #ifndef SERVERONLY //FIXME: we probably want to support multiple skins some time - Q_strncpyz(frames[0].shadername, com_token, sizeof(frames[0].shadername)); + Q_strncpyz(frames[0].shadername, token, sizeof(frames[0].shadername)); #endif } - else if (!strcmp(com_token, "numverts")) + else if (!strcmp(token, "numverts")) { if (numverts) MD5ERROR0PARAM("MD5MESH: numverts was already specified"); - buffer = COM_Parse(buffer); - numverts = atoi(com_token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + numverts = atoi(token); if (numverts < 0) MD5ERROR0PARAM("MD5MESH: numverts cannot be negative"); @@ -7465,39 +7376,39 @@ galiasinfo_t *Mod_ParseMD5MeshModel(model_t *mod, char *buffer, char *modname) inf->numverts = numverts; #endif } - else if (!strcmp(com_token, "vert")) + else if (!strcmp(token, "vert")) { //vert num ( s t ) firstweight numweights - buffer = COM_Parse(buffer); - num = atoi(com_token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + num = atoi(token); if (num < 0 || num >= numverts) MD5ERROR0PARAM("MD5MESH: vertex out of range"); EXPECT("("); - buffer = COM_Parse(buffer); + buffer = COM_ParseOut(buffer, token, sizeof(token)); #ifndef SERVERONLY if (!stcoord) MD5ERROR0PARAM("MD5MESH: vertex out of range"); - stcoord[num*2+0] = atof(com_token); + stcoord[num*2+0] = atof(token); #endif - buffer = COM_Parse(buffer); + buffer = COM_ParseOut(buffer, token, sizeof(token)); #ifndef SERVERONLY - stcoord[num*2+1] = atof(com_token); + stcoord[num*2+1] = atof(token); #endif EXPECT(")"); - buffer = COM_Parse(buffer); - firstweightlist[num] = atoi(com_token); - buffer = COM_Parse(buffer); - numweightslist[num] = atoi(com_token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + firstweightlist[num] = atoi(token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + numweightslist[num] = atoi(token); numusableweights += numweightslist[num]; } - else if (!strcmp(com_token, "numtris")) + else if (!strcmp(token, "numtris")) { if (numtris) MD5ERROR0PARAM("MD5MESH: numtris was already specified"); - buffer = COM_Parse(buffer); - numtris = atoi(com_token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + numtris = atoi(token); if (numtris < 0) MD5ERROR0PARAM("MD5MESH: numverts cannot be negative"); @@ -7505,64 +7416,63 @@ galiasinfo_t *Mod_ParseMD5MeshModel(model_t *mod, char *buffer, char *modname) inf->ofs_indexes = indexes; inf->numindexes = numtris*3; } - else if (!strcmp(com_token, "tri")) + else if (!strcmp(token, "tri")) { - buffer = COM_Parse(buffer); - num = atoi(com_token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + num = atoi(token); if (num < 0 || num >= numtris) MD5ERROR0PARAM("MD5MESH: vertex out of range"); - buffer = COM_Parse(buffer); - indexes[num*3+0] = atoi(com_token); - buffer = COM_Parse(buffer); - indexes[num*3+1] = atoi(com_token); - buffer = COM_Parse(buffer); - indexes[num*3+2] = atoi(com_token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + indexes[num*3+0] = atoi(token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + indexes[num*3+1] = atoi(token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + indexes[num*3+2] = atoi(token); } - else if (!strcmp(com_token, "numweights")) + else if (!strcmp(token, "numweights")) { if (numweights) MD5ERROR0PARAM("MD5MESH: numweights was already specified"); - buffer = COM_Parse(buffer); - numweights = atoi(com_token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + numweights = atoi(token); rawweight = Z_Malloc(sizeof(*rawweight)*numweights); rawweightbone = Z_Malloc(sizeof(*rawweightbone)*numweights); } - else if (!strcmp(com_token, "weight")) + else if (!strcmp(token, "weight")) { //weight num bone scale ( x y z ) - buffer = COM_Parse(buffer); - num = atoi(com_token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + num = atoi(token); if (num < 0 || num >= numweights) MD5ERROR0PARAM("MD5MESH: weight out of range"); - buffer = COM_Parse(buffer); - rawweightbone[num] = atoi(com_token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + rawweightbone[num] = atoi(token); if (rawweightbone[num] < 0 || rawweightbone[num] >= numjoints) MD5ERROR0PARAM("MD5MESH: weight specifies bad bone"); - buffer = COM_Parse(buffer); - w = atof(com_token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + w = atof(token); EXPECT("("); - buffer = COM_Parse(buffer); - rawweight[num][0] = w*atof(com_token); - buffer = COM_Parse(buffer); - rawweight[num][1] = w*atof(com_token); - buffer = COM_Parse(buffer); - rawweight[num][2] = w*atof(com_token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + rawweight[num][0] = w*atof(token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + rawweight[num][1] = w*atof(token); + buffer = COM_ParseOut(buffer, token, sizeof(token)); + rawweight[num][2] = w*atof(token); EXPECT(")"); rawweight[num][3] = w; } - else if (!strcmp(com_token, "}")) + else if (!strcmp(token, "}")) break; else MD5ERROR1PARAM("MD5MESH: Unrecognised token inside mesh (%s)", com_token); } - trans = ZG_Malloc(&mod->memgroup, sizeof(*trans)*numusableweights); - inf->ofsswtransforms = trans; + trans = Z_Malloc(sizeof(*trans)*numusableweights); for (num = 0, vnum = 0; num < numverts; num++) { @@ -7581,7 +7491,9 @@ galiasinfo_t *Mod_ParseMD5MeshModel(model_t *mod, char *buffer, char *modname) numweightslist[num]--; } } - inf->numswtransforms = vnum; + + Alias_BuildGPUWeights(mod, inf, vnum, trans, true); + Z_Free(trans); if (firstweightlist) Z_Free(firstweightlist); @@ -7599,7 +7511,7 @@ galiasinfo_t *Mod_ParseMD5MeshModel(model_t *mod, char *buffer, char *modname) if (!lastsurf) MD5ERROR0PARAM("MD5MESH: No meshes"); - Alias_CalculateSkeletalNormals(root); +// Alias_CalculateSkeletalNormals(root); return root; #undef MD5ERROR0PARAM @@ -7624,6 +7536,7 @@ qboolean QDECL Mod_LoadMD5MeshModel(model_t *mod, void *buffer, size_t fsize) mod->type = mod_alias; + mod->numframes = root->numanimations; mod->meshinfo = root; mod->funcs.NativeTrace = Mod_Trace; @@ -7801,6 +7714,7 @@ qboolean QDECL Mod_LoadCompositeAnim(model_t *mod, void *buffer, size_t fsize) Mod_ClampModelSize(mod); mod->type = mod_alias; + mod->numframes = root->numanimations; mod->meshinfo = root; mod->funcs.NativeTrace = Mod_Trace; diff --git a/engine/common/com_mesh.h b/engine/common/com_mesh.h index c554f8fb5..1b90331cc 100644 --- a/engine/common/com_mesh.h +++ b/engine/common/com_mesh.h @@ -56,9 +56,9 @@ struct galiasbone_s float inverse[12]; }; -typedef struct FTE_DEPRECATED +typedef struct { - //DEPRECATED + //should be load-time only //use of this prevents the use of glsl acceleration. the framerate loss is of the order of 90% //skeletal poses refer to this. int vertexindex; @@ -148,8 +148,8 @@ typedef struct galiasinfo_s float *baseframeofs; /*non-heirachical*/ int numbones; galiasbone_t *ofsbones; - int numswtransforms; - galisskeletaltransforms_t *ofsswtransforms; +//FTE_DEPRECATED int numswtransforms; +//FTE_DEPRECATED galisskeletaltransforms_t *ofsswtransforms; vecV_t *ofs_skel_xyz; vec3_t *ofs_skel_norm; @@ -172,9 +172,15 @@ typedef struct galiasinfo_s void *ebomem; //these exist only in the root mesh. +#ifdef MD3MODELS int numtagframes; int numtags; md3tag_t *ofstags; +#else + FTE_DEPRECATED int numtagframes; + FTE_DEPRECATED int numtags; + FTE_DEPRECATED md3tag_t *ofstags; +#endif unsigned int warned; //passed around at load time, so we don't spam warnings } galiasinfo_t; @@ -224,9 +230,9 @@ qboolean Mod_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **nam void Mod_DoCRC(model_t *mod, char *buffer, int buffersize); -void Mod_AccumulateTextureVectors(vecV_t *vc, vec2_t *tc, vec3_t *nv, vec3_t *sv, vec3_t *tv, index_t *idx, int numidx); +void Mod_AccumulateTextureVectors(vecV_t *const vc, vec2_t *const tc, vec3_t *nv, vec3_t *sv, vec3_t *tv, const index_t *idx, int numidx, qboolean calcnorms); void Mod_AccumulateMeshTextureVectors(mesh_t *mesh); -void Mod_NormaliseTextureVectors(vec3_t *n, vec3_t *s, vec3_t *t, int v); +void Mod_NormaliseTextureVectors(vec3_t *n, vec3_t *s, vec3_t *t, int v, qboolean calcnorms); void R_Generate_Mesh_ST_Vectors(mesh_t *mesh); #ifdef __cplusplus diff --git a/engine/common/fs.c b/engine/common/fs.c index c9300493a..d22b005ba 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -758,7 +758,7 @@ static int QDECL COM_Dir_List(const char *name, qofs_t size, time_t mtime, void Q_snprintfz(link, sizeof(link), "\\map\\%s", name); colour = "^4"; //disconnects } - else if (!Q_strcasecmp(link, "bsp") || !Q_strcasecmp(link, "spr") || !Q_strcasecmp(link, "mdl") || !Q_strcasecmp(link, "md3") || !Q_strcasecmp(link, "iqm") || !Q_strcasecmp(link, "psk") || !Q_strcasecmp(link, "dpm") || !Q_strcasecmp(link, "zym")) + else if (!Q_strcasecmp(link, "bsp") || !Q_strcasecmp(link, "spr") || !Q_strcasecmp(link, "mdl") || !Q_strcasecmp(link, "md3") || !Q_strcasecmp(link, "iqm") || !Q_strcasecmp(link, "psk") || !Q_strcasecmp(link, "dpm") || !Q_strcasecmp(link, "zym") || !Q_strcasecmp(link, "md5mesh") || !Q_strcasecmp(link, "md5anim")) Q_snprintfz(link, sizeof(link), "\\modelviewer\\%s", name); else if (!Q_strcasecmp(link, "qc") || !Q_strcasecmp(link, "src") || !Q_strcasecmp(link, "qh") || !Q_strcasecmp(link, "h") || !Q_strcasecmp(link, "c") || !Q_strcasecmp(link, "cfg") || !Q_strcasecmp(link, "rc") diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index aa28132fd..c2969b3e1 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -2776,7 +2776,7 @@ void CModRBSP_BuildSurfMesh(model_t *mod, msurface_t *out, builddata_t *bd) } Mod_AccumulateMeshTextureVectors(out->mesh); - Mod_NormaliseTextureVectors(out->mesh->normals_array, out->mesh->snormals_array, out->mesh->tnormals_array, out->mesh->numvertexes); + Mod_NormaliseTextureVectors(out->mesh->normals_array, out->mesh->snormals_array, out->mesh->tnormals_array, out->mesh->numvertexes, false); } void CModQ3_BuildSurfMesh(model_t *mod, msurface_t *out, builddata_t *bd) @@ -2845,7 +2845,7 @@ void CModQ3_BuildSurfMesh(model_t *mod, msurface_t *out, builddata_t *bd) } Mod_AccumulateMeshTextureVectors(out->mesh); - Mod_NormaliseTextureVectors(out->mesh->normals_array, out->mesh->snormals_array, out->mesh->tnormals_array, out->mesh->numvertexes); + Mod_NormaliseTextureVectors(out->mesh->normals_array, out->mesh->snormals_array, out->mesh->tnormals_array, out->mesh->numvertexes, false); } qboolean CModQ3_LoadRFaces (model_t *mod, qbyte *mod_base, lump_t *l) diff --git a/engine/common/mathlib.c b/engine/common/mathlib.c index 49cc0b881..16aeeaeb0 100644 --- a/engine/common/mathlib.c +++ b/engine/common/mathlib.c @@ -448,7 +448,7 @@ void CrossProduct (const vec3_t v1, const vec3_t v2, vec3_t cross) cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; } -vec_t Length(vec3_t v) +vec_t Length(const vec3_t v) { int i; float length; diff --git a/engine/common/mathlib.h b/engine/common/mathlib.h index 51b5a2d38..91af269db 100644 --- a/engine/common/mathlib.h +++ b/engine/common/mathlib.h @@ -132,7 +132,7 @@ void CrossProduct (const vec3_t v1, const vec3_t v2, vec3_t cross); void FloorDivMod (double numer, double denom, int *quotient, int *rem); int GreatestCommonDivisor (int i1, int i2); fixed16_t Invert24To16 (fixed16_t val); -vec_t Length (vec3_t v); +vec_t Length (const vec3_t v); void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up); float Q_rsqrt(float number); diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 8ba81806a..718886cec 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -6083,6 +6083,7 @@ lh_extension_t QSG_Extensions[] = { {"DP_CON_SETA", 0, NULL, {NULL}, "The 'seta' console command exists, like the 'set' command, but also marks the cvar for archiving, allowing it to be written into the user's config. Use this command in your default.cfg file."}, #endif {"DP_EF_ADDITIVE"}, +//--{"DP_ENT_ALPHA"}, //listed above {"DP_EF_BLUE"}, //hah!! This is QuakeWorld!!! {"DP_EF_FULLBRIGHT"}, //Rerouted to hexen2 support. {"DP_EF_NODEPTHTEST"}, //for cheats @@ -6090,10 +6091,10 @@ lh_extension_t QSG_Extensions[] = { {"DP_EF_NOGUNBOB"}, //nogunbob. sane people should use csqc instead. {"DP_EF_NOSHADOW"}, {"DP_EF_RED"}, -// {"DP_ENT_COLORMOD"}, +//--{"DP_ENT_COLORMOD"}, //listed above {"DP_ENT_CUSTOMCOLORMAP"}, {"DP_ENT_EXTERIORMODELTOCLIENT"}, - {"DP_ENT_SCALE"}, +//--{"DP_ENT_SCALE"}, //listed above {"DP_ENT_TRAILEFFECTNUM", 1, NULL, {"particleeffectnum"}, "self.traileffectnum=particleeffectnum(\"myeffectname\"); can be used to attach a particle trail to the given server entity. This is equivelent to calling trailparticles each frame."}, //only in dp6 currently {"DP_ENT_GLOW"}, {"DP_ENT_VIEWMODEL"}, diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index fdb0b844d..a95294871 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -257,6 +257,7 @@ void QCBUILTIN PF_setattachment(pubprogfuncs_t *prinst, struct globalvars_s *pr_ void QCBUILTIN PF_skintoname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_frameforname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_frameduration (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); + void QCBUILTIN PF_modelframecount (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_skinforname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_gettaginfo (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_gettagindex (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); diff --git a/engine/d3d/vid_d3d11.c b/engine/d3d/vid_d3d11.c index cfa32a0f5..6b1b155af 100644 --- a/engine/d3d/vid_d3d11.c +++ b/engine/d3d/vid_d3d11.c @@ -375,7 +375,7 @@ static LRESULT WINAPI D3D11_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR SetWindowPos(hWnd, NULL, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, SWP_SHOWWINDOW|SWP_FRAMECHANGED); modestate = MS_FULLSCREEN; } - + if (!d3dscreen && modestate == MS_FULLSCREEN) IDXGISwapChain_GetContainingOutput(d3dswapchain, &d3dscreen); IDXGISwapChain_SetFullscreenState(d3dswapchain, modestate == MS_FULLSCREEN, (modestate == MS_FULLSCREEN)?d3dscreen:NULL); diff --git a/engine/dotnet2005/ftequake.vcproj b/engine/dotnet2005/ftequake.vcproj index 4c9345b29..5b9a0bb61 100644 --- a/engine/dotnet2005/ftequake.vcproj +++ b/engine/dotnet2005/ftequake.vcproj @@ -29423,6 +29423,10 @@ /> + + @@ -29949,10 +29953,6 @@ RelativePath="..\vk\vk_init.c" > - - diff --git a/engine/gl/gl_hlmdl.c b/engine/gl/gl_hlmdl.c index a276875c6..2b927c8c9 100644 --- a/engine/gl/gl_hlmdl.c +++ b/engine/gl/gl_hlmdl.c @@ -322,6 +322,7 @@ qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize) Z_Free(texmem); mod->type = mod_halflife; + mod->numframes = model->header->numseq; mod->meshinfo = model; model->numgeomsets = model->header->numbodyparts; @@ -396,6 +397,8 @@ int HLMDL_BoneForName(model_t *mod, const char *name) if (!strcmp(bones[i].name, name)) return i+1; } + + //FIXME: hlmdl has tags as well as bones. return 0; } @@ -616,8 +619,10 @@ void HL_SetupBones(hlmodel_t *model, int seqnum, int firstbone, int lastbone, fl FIXME: we don't handle frame2. */ - if (sequence->hasblendseq>1) + if (sequence->hasblendseq>1 && sequence->hasblendseq<9) { + //I have no idea how to deal with > 1. + //some CS models seem to have 9 here, but some look like they're fucked. if (subblendfrac < 0) subblendfrac = 0; if (subblendfrac > 1) @@ -652,12 +657,16 @@ void HL_SetupBones(hlmodel_t *model, int seqnum, int firstbone, int lastbone, fl QuaternionSlerp(quatb, quat1, subblendfrac, quat1); QuaternionGLMatrix(quat1[0], quat1[1], quat1[2], quat1[3], (vec4_t*)matrix); FloatInterpolate(organgb[0][0], subblendfrac, organg1[0][0], matrix[0*4+3]); - FloatInterpolate(organgb[0][0], subblendfrac, organg1[0][1], matrix[1*4+3]); - FloatInterpolate(organgb[0][0], subblendfrac, organg1[0][2], matrix[2*4+3]); + FloatInterpolate(organgb[0][1], subblendfrac, organg1[0][1], matrix[1*4+3]); + FloatInterpolate(organgb[0][2], subblendfrac, organg1[0][2], matrix[2*4+3]); } } else { + //FIXME: disgusting hack to get CS player models not looking like total idiots. but merely regular ones instead. + if (sequence->hasblendseq == 9) + animation += 4*model->header->numbones; + for(i = firstbone; i < lastbone; i++, matrix+=12) { HL_CalculateBones(frame1, model->adjust, model->bones + i, animation + i, organg1[0]); @@ -692,6 +701,24 @@ int HLMDL_GetNumBones(model_t *mod) return mc->header->numbones; } +int HLMDL_GetBoneParent(model_t *mod, int bonenum) +{ + hlmodel_t *model = Mod_Extradata(mod); + + if (bonenum >= 0 && bonenum < model->header->numbones) + return model->bones[bonenum].parent; + return -1; +} + +const char *HLMDL_GetBoneName(model_t *mod, int bonenum) +{ + hlmodel_t *model = Mod_Extradata(mod); + + if (bonenum >= 0 && bonenum < model->header->numbones) + return model->bones[bonenum].name; + return NULL; +} + int HLMDL_GetBoneData(model_t *mod, int firstbone, int lastbone, framestate_t *fstate, float *result) { int b, cbone, bgroup; @@ -854,7 +881,7 @@ void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches) static mesh_t bmesh, *mptr = &bmesh; skinfile_t *sk = NULL; - unsigned int entity_body = rent->bottomcolour; + unsigned int entity_body = 0; if (rent->customskin) sk = Mod_LookupSkin(rent->customskin); diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 7b57eb767..93621d6ca 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -2652,6 +2652,8 @@ qboolean Mod_LoadTexinfo (model_t *loadmodel, qbyte *mod_base, lump_t *l) out->texture = r_notexture_mip; // texture not found out->flags = 0; } + if (!strncmp(out->texture->name, "scroll", 6) || ((*out->texture->name == '*' || *out->texture->name == '{' || *out->texture->name == '!') && !strncmp(out->texture->name+1, "scroll", 6))) + out->flags |= TI_FLOWING; } return true; @@ -2846,7 +2848,7 @@ qboolean Mod_LoadFaces (model_t *loadmodel, qbyte *mod_base, lump_t *l, lump_t * continue; } - if (!Q_strncmp(out->texinfo->texture->name,"*",1)) // turbulent + if (*out->texinfo->texture->name == '*' || (*out->texinfo->texture->name == '!' && loadmodel->fromgame == fg_halflife)) // turbulent { out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED); for (i=0 ; i<2 ; i++) @@ -3194,7 +3196,14 @@ static int Mod_Batches_Generate(model_t *mod) surf = mod->surfaces + mod->firstmodelsurface + i; shader = surf->texinfo->texture->shader; - if (shader) + if (surf->flags & SURF_NODRAW) + { + shader = R_RegisterShader("nodraw", SUF_NONE, "{\nsurfaceparm nodraw\n}"); + sortid = shader->sort; + VectorClear(plane); + plane[3] = 0; + } + else if (shader) { sortid = shader->sort; @@ -3227,6 +3236,7 @@ static int Mod_Batches_Generate(model_t *mod) if (lbatch && ( lbatch->texture == surf->texinfo->texture && + lbatch->shader == shader && lbatch->lightmap[0] == lmmerge(surf->lightmaptexturenums[0]) && Vector4Compare(plane, lbatch->plane) && lbatch->firstmesh + surf->mesh->numvertexes <= MAX_INDICIES) && @@ -3243,6 +3253,7 @@ static int Mod_Batches_Generate(model_t *mod) { if ( batch->texture == surf->texinfo->texture && + lbatch->shader == shader && batch->lightmap[0] == lmmerge(surf->lightmaptexturenums[0]) && Vector4Compare(plane, batch->plane) && batch->firstmesh + surf->mesh->numvertexes <= MAX_INDICIES && @@ -3265,7 +3276,7 @@ static int Mod_Batches_Generate(model_t *mod) batch->lightmap[3] = lmmerge(surf->lightmaptexturenums[3]); #endif batch->texture = surf->texinfo->texture; - batch->shader = surf->texinfo->texture->shader; + batch->shader = shader; if (surf->texinfo->texture->alternate_anims || surf->texinfo->texture->anim_total) { if (mod->fromgame == fg_quake2) @@ -5024,6 +5035,19 @@ TRACE(("LoadBrushModel %i\n", __LINE__)); if (submod->hulls[j].available) Q1BSP_CheckHullNodes(&submod->hulls[j]); } + + if (mod->fromgame == fg_halflife && i) + { + for (j=bm->firstface ; jfirstface+bm->numfaces ; j++) + { + if (mod->surfaces[j].flags & SURF_DRAWTURB) + { + if (mod->surfaces[j].plane->type == PLANE_Z && mod->surfaces[j].plane->dist == bm->maxs[2]-1) + continue; + mod->surfaces[j].flags |= SURF_NODRAW; + } + } + } submod->firstmodelsurface = bm->firstface; submod->nummodelsurfaces = bm->numfaces; diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index dcbfc35c6..88986285a 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -327,14 +327,15 @@ typedef struct #define SURF_PLANEBACK 0x00002 #define SURF_DRAWSKY 0x00004 #define SURF_DRAWSPRITE 0x00008 -#define SURF_DRAWTURB 0x00010 -#define SURF_DRAWTILED 0x00020 +#define SURF_DRAWTURB 0x00010 //water warp effect +#define SURF_DRAWTILED 0x00020 //no need for a sw surface cache... (read: no lightmap) #define SURF_DRAWBACKGROUND 0x00040 #define SURF_UNDERWATER 0x00080 #define SURF_DONTWARP 0x00100 //#define SURF_BULLETEN 0x00200 #define SURF_NOFLAT 0x08000 #define SURF_DRAWALPHA 0x10000 +#define SURF_NODRAW 0x20000 //set on non-vertical halflife water submodel surfaces // !!! if this is changed, it must be changed in asm_draw.h too !!! typedef struct diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 819f0a349..1075aa6dc 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -5686,7 +5686,7 @@ void Shader_DefaultBSPQ1(const char *shortname, shader_t *s, const void *args) } - if (!builtin && (*shortname == '*')) + if (!builtin && (*shortname == '*' || *shortname == '!')) { builtin = Shader_DefaultBSPWater(s, shortname); } diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index defd1dbba..e57873366 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -1053,6 +1053,7 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) gl_config.arb_depth_texture = GL_CheckExtension("GL_OES_depth_texture"); //gles2 gl_config.arb_depth_texture |= GL_CheckExtension("GL_CHROMIUM_depth_texture"); //nacl gl_config.arb_depth_texture |= GL_CheckExtension("GL_WEBGL_depth_texture"); //webgl. duh. + gl_config.arb_depth_texture |= GL_CheckExtension("GL_ANGLE_depth_texture"); //gah. should just use wildcards huh (no uploads) } else { @@ -2770,6 +2771,13 @@ void GL_Init(void *(*getglfunction) (char *name)) sh_config.texfmt[PTI_S3RGBA3] = true; sh_config.texfmt[PTI_S3RGBA5] = true; } + else if (gl_config.gles) + { + sh_config.texfmt[PTI_S3RGB1] = + sh_config.texfmt[PTI_S3RGBA1] = GL_CheckExtension("GL_EXT_texture_compression_dxt1"); + sh_config.texfmt[PTI_S3RGBA3] = GL_CheckExtension("GL_ANGLE_texture_compression_dxt3"); + sh_config.texfmt[PTI_S3RGBA5] = GL_CheckExtension("GL_ANGLE_texture_compression_dxt5"); + } if (gl_config.gles) { diff --git a/engine/gl/gl_videgl.c b/engine/gl/gl_videgl.c index cbd622d71..03751e85c 100644 --- a/engine/gl/gl_videgl.c +++ b/engine/gl/gl_videgl.c @@ -1,32 +1,36 @@ -#include "bothdefs.h" +#include "quakedef.h" #if defined(GLQUAKE) && defined(USE_EGL) #include "gl_videgl.h" +extern cvar_t vid_vsync; + EGLContext eglctx = EGL_NO_CONTEXT; EGLDisplay egldpy = EGL_NO_DISPLAY; EGLSurface eglsurf = EGL_NO_SURFACE; -static dllhandle_t egllibrary; -static dllhandle_t eslibrary; +static dllhandle_t *egllibrary; +static dllhandle_t *eslibrary; -static EGLint (*qeglGetError)(void); +static EGLint (EGLAPIENTRY *qeglGetError)(void); -static EGLDisplay (*qeglGetDisplay)(EGLNativeDisplayType display_id); -static EGLBoolean (*qeglInitialize)(EGLDisplay dpy, EGLint *major, EGLint *minor); -static EGLBoolean (*qeglTerminate)(EGLDisplay dpy); +static EGLDisplay (EGLAPIENTRY *qeglGetDisplay)(EGLNativeDisplayType display_id); +static EGLBoolean (EGLAPIENTRY *qeglInitialize)(EGLDisplay dpy, EGLint *major, EGLint *minor); +static EGLBoolean (EGLAPIENTRY *qeglTerminate)(EGLDisplay dpy); -static EGLBoolean (*qeglGetConfigs)(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config); -static EGLBoolean (*qeglChooseConfig)(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config); +static EGLBoolean (EGLAPIENTRY *qeglGetConfigs)(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config); +static EGLBoolean (EGLAPIENTRY *qeglChooseConfig)(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config); -static EGLSurface (*qeglCreateWindowSurface)(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list); -static EGLBoolean (*qeglDestroySurface)(EGLDisplay dpy, EGLSurface surface); -static EGLBoolean (*qeglQuerySurface)(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value); +static EGLSurface (EGLAPIENTRY *qeglCreateWindowSurface)(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list); +static EGLBoolean (EGLAPIENTRY *qeglDestroySurface)(EGLDisplay dpy, EGLSurface surface); +static EGLBoolean (EGLAPIENTRY *qeglQuerySurface)(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value); -static EGLBoolean (*qeglSwapBuffers)(EGLDisplay dpy, EGLSurface surface); -static EGLBoolean (*qeglMakeCurrent)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); -static EGLContext (*qeglCreateContext)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list); -static EGLBoolean (*qeglDestroyContext)(EGLDisplay dpy, EGLContext ctx); -static void *(*qeglGetProcAddress) (char *name); +static EGLBoolean (EGLAPIENTRY *qeglSwapBuffers)(EGLDisplay dpy, EGLSurface surface); +static EGLBoolean (EGLAPIENTRY *qeglMakeCurrent)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); +static EGLContext (EGLAPIENTRY *qeglCreateContext)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list); +static EGLBoolean (EGLAPIENTRY *qeglDestroyContext)(EGLDisplay dpy, EGLContext ctx); +static void * (EGLAPIENTRY *qeglGetProcAddress) (char *name); + +static EGLBoolean (EGLAPIENTRY *qeglSwapInterval) (EGLDisplay display, EGLint interval); static dllfunction_t qeglfuncs[] = { @@ -50,6 +54,9 @@ static dllfunction_t qeglfuncs[] = {(void*)&qeglGetProcAddress, "eglGetProcAddress"}, + //EGL 1.1 + {(void*)&qeglSwapInterval, "eglSwapInterval"}, + {NULL} }; @@ -99,6 +106,7 @@ qboolean EGL_LoadLibrary(char *driver) } else Sys_Printf("success\n"); +#ifndef _WIN32 if (!eslibrary) { eslibrary = dlopen("libGL", RTLD_NOW|RTLD_GLOBAL); @@ -114,6 +122,7 @@ qboolean EGL_LoadLibrary(char *driver) eslibrary = dlopen("libGL.so.1", RTLD_NOW|RTLD_GLOBAL); if (eslibrary) Sys_Printf("Loaded libGL.so.1\n"); } +#endif if (!eslibrary) Sys_Printf("unable to load some libGL\n"); @@ -152,6 +161,18 @@ void EGL_Shutdown(void) void EGL_SwapBuffers (void) { + if (vid_vsync.modified) + { + int interval; + vid_vsync.modified = false; + if (*vid_vsync.string) + interval = vid_vsync.ival; + else + interval = 1; //default is to always vsync, according to EGL docs, so lets just do that. + if (qeglSwapInterval) + qeglSwapInterval(egldpy, interval); + } + TRACE(("EGL_SwapBuffers\n")); TRACE(("swapping buffers\n")); qeglSwapBuffers(egldpy, eglsurf); @@ -180,7 +201,7 @@ qboolean EGL_Init (rendererstate_t *info, unsigned char *palette, EGLNativeWindo }; EGLint contextattr[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_CONTEXT_CLIENT_VERSION, 2, //requires EGL 1.3 EGL_NONE, EGL_NONE }; @@ -246,6 +267,9 @@ qboolean EGL_Init (rendererstate_t *info, unsigned char *palette, EGLNativeWindo return false; } + + vid_vsync.modified = true; + return true; } #endif diff --git a/engine/gl/gl_videgl.h b/engine/gl/gl_videgl.h index c57afc09d..8c67cba03 100644 --- a/engine/gl/gl_videgl.h +++ b/engine/gl/gl_videgl.h @@ -4,7 +4,9 @@ #include "quakedef.h" #define NativeWindowType EGLNativeWindowType #include -#include +#ifndef _WIN32 + #include +#endif void *EGL_Proc(char *f); void EGL_UnloadLibrary(void); diff --git a/engine/gl/gl_vidlinuxglx.c b/engine/gl/gl_vidlinuxglx.c index fb72242dc..1c964b6da 100644 --- a/engine/gl/gl_vidlinuxglx.c +++ b/engine/gl/gl_vidlinuxglx.c @@ -1446,22 +1446,45 @@ void GLVID_SwapBuffers (void) void X_StoreIcon(Window wnd) { int i; - unsigned long data[64*64+2]; - unsigned int *indata = (unsigned int*)icon.pixel_data; - unsigned int inwidth = icon.width; - unsigned int inheight = icon.height; - - //FIXME: support loading an icon from the filesystem. - Atom propname = x11.pXInternAtom(vid_dpy, "_NET_WM_ICON", false); Atom proptype = x11.pXInternAtom(vid_dpy, "CARDINAL", false); - data[0] = inwidth; - data[1] = inheight; - for (i = 0; i < data[0]*data[1]; i++) - data[i+2] = indata[i]; + size_t filesize; + qbyte *filedata = FS_LoadMallocFile("icon.png", &filesize); + if (!filedata) + FS_LoadMallocFile("icon.tga", &filesize); + if (!filedata) + FS_LoadMallocFile("icon.jpg", &filesize); + if (filedata) + { + int imagewidth, imageheight; + int *iconblob; + qboolean hasalpha; + qbyte *imagedata = Read32BitImageFile(filedata, filesize, &imagewidth, &imageheight, &hasalpha, "icon.png"); + Z_Free(filedata); - x11.pXChangeProperty(vid_dpy, wnd, propname, proptype, 32, PropModeReplace, (void*)data, data[0]*data[1]+2); + iconblob = BZ_Malloc(sizeof(int)*(2+imagewidth*imageheight)); + iconblob[0] = imagewidth; + iconblob[1] = imageheight; + //needs to be 0xARGB, rather than RGBA bytes + for (i = 0; i < imagewidth*imageheight; i++) + iconblob[i+2] = (imagedata[i*4+3]<<24) | (imagedata[i*4+0]<<16) | (imagedata[i*4+1]<<8) | (imagedata[i*4+2]<<0); + Z_Free(imagedata); + + x11.pXChangeProperty(vid_dpy, wnd, propname, proptype, 32, PropModeReplace, (void*)iconblob, 2+imagewidth*imageheight); + BZ_Free(iconblob); + } + else + { + //fall back to the embedded icon. + unsigned long data[64*64+2]; + data[0] = icon.width; + data[1] = icon.height; + for (i = 0; i < data[0]*data[1]; i++) + data[i+2] = ((unsigned int*)icon.pixel_data)[i]; + + x11.pXChangeProperty(vid_dpy, wnd, propname, proptype, 32, PropModeReplace, (void*)data, data[0]*data[1]+2); + } } void X_GoFullscreen(void) diff --git a/engine/gl/gl_vidnt.c b/engine/gl/gl_vidnt.c index 0f998fb8c..b2c7066d9 100644 --- a/engine/gl/gl_vidnt.c +++ b/engine/gl/gl_vidnt.c @@ -18,15 +18,45 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // gl_vidnt.c -- NT GL vid component +// note that this file also handles win32 vulkan window things +// and can also use either EGL or WGL. #include "quakedef.h" -#ifdef GLQUAKE +#if defined(_WIN32) && (defined(GLQUAKE) || defined(VKQUAKE)) #include "glquake.h" #include "winquake.h" #include "resource.h" #include "shader.h" #include +#ifdef USE_EGL + #ifdef GLQUAKE + #include "gl_videgl.h" + #else + #undef USE_EGL + #endif +#endif +#ifdef GLQUAKE + #define USE_WGL +#endif +#ifdef VKQUAKE + #include "../vk/vkrenderer.h" +#endif + +static enum +{ +#ifdef USE_WGL + MODE_WGL, +#endif +#ifdef USE_EGL + MODE_EGL, +#endif +#ifdef VKQUAKE + MODE_VULKAN, +#endif +} platform_rendermode; + + void STT_Event(void); #ifndef SetWindowLongPtr //yes its a define, for unicode support @@ -82,33 +112,18 @@ extern cvar_t vid_conwidth, vid_conautoscale; #define WINDOW_CLASS_NAME_W L"FTEGLQuake" #define WINDOW_CLASS_NAME_A "FTEGLQuake" -#define MAX_MODE_LIST 128 -#define VID_ROW_SIZE 3 -#define WARP_WIDTH 320 -#define WARP_HEIGHT 200 -#define MAXWIDTH 10000 -#define MAXHEIGHT 10000 -#define BASEWIDTH 320 -#define BASEHEIGHT 200 - extern cvar_t vid_width; extern cvar_t vid_height; extern cvar_t vid_wndalpha; -const char *wgl_extensions; - typedef enum {MS_WINDOWED, MS_FULLDIB, MS_FULLWINDOW, MS_UNINIT} modestate_t; -BOOL bSetupPixelFormat(HDC hDC, rendererstate_t *info); - -//qboolean VID_SetWindowedMode (int modenum); -//qboolean VID_SetFullDIBMode (int modenum); static qboolean VID_SetWindowedMode (rendererstate_t *info); //-1 on bpp or hz for default. static qboolean VID_SetFullDIBMode (rendererstate_t *info); //-1 on bpp or hz for default. -qboolean scr_skipupdate; - -//#define WTHREAD //While the user is resizing a window, the entire thread that owns said window becomes frozen. in order to cope with window resizing, its easiest to just create a separate thread to be microsoft's plaything. our main game thread can then just keep rendering. hopefully that won't bug out on the present. +#ifdef MULTITHREADED +#define WTHREAD //While the user is resizing a window, the entire thread that owns said window becomes frozen. in order to cope with window resizing, its easiest to just create a separate thread to be microsoft's plaything. our main game thread can then just keep rendering. hopefully that won't bug out on the present. +#endif #ifdef WTHREAD static HANDLE windowthread; static void *windowmutex; @@ -122,21 +137,18 @@ extern qboolean mouseactive; // from in_win.c static HICON hIcon; extern qboolean vid_isfullscreen; -unsigned short originalgammaramps[3][256]; +static unsigned short originalgammaramps[3][256]; qboolean vid_initializing; -qboolean VID_AttachGL (rendererstate_t *info); +static int DIBWidth, DIBHeight; +static RECT WindowRect; +static DWORD WindowStyle, ExWindowStyle; -int DIBWidth, DIBHeight; -RECT WindowRect; -DWORD WindowStyle, ExWindowStyle; - -HWND mainwindow, dibwindow; - -HGLRC baseRC; -HDC maindc; +HWND mainwindow; +static HWND dibwindow; +static HDC maindc; HWND WINAPI InitializeWindow (HINSTANCE hInstance, int nCmdShow); @@ -147,22 +159,11 @@ viddef_t vid; // global video state //unsigned short d_8to16bgrtable[256]; //unsigned d_8to24bgrtable[256]; -modestate_t modestate = MS_UNINIT; +static modestate_t modestate = MS_UNINIT; extern float gammapending; -LONG WINAPI GLMainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); -qboolean GLAppActivate(BOOL fActive, BOOL minimize); -void ClearAllStates (void); -void VID_UpdateWindowStatus (HWND hWnd); -void GL_Init(void *(*getglfunction) (char *name)); - -typedef void (APIENTRY *lp3DFXFUNC) (int, int, int, int, int, const void*); -lp3DFXFUNC qglColorTableEXT; -qboolean is8bit = false; -qboolean isPermedia = false; - //==================================== // Note that 0 is MODE_WINDOWED extern cvar_t vid_mode; @@ -174,6 +175,28 @@ extern cvar_t vid_desktopgamma; extern cvar_t gl_lateswap; extern cvar_t vid_preservegamma; +int window_x, window_y; +static int window_width, window_height; +int window_center_x, window_center_y; +RECT window_rect; + + +static LONG WINAPI GLMainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +static qboolean GLAppActivate(BOOL fActive, BOOL minimize); +static void ClearAllStates (void); +static void VID_UpdateWindowStatus (HWND hWnd); + +static BOOL (WINAPI *qGetDeviceGammaRamp)(HDC hDC, void *ramp); +static BOOL (WINAPI *qSetDeviceGammaRamp)(HDC hDC, void *ramp); + +//========================================================== +#ifdef USE_WGL +static HGLRC baseRC; +static const char *wgl_extensions; + +static qboolean VID_AttachGL (rendererstate_t *info); +static BOOL bSetupPixelFormat(HDC hDC, rendererstate_t *info); + extern cvar_t vid_gl_context_version; extern cvar_t vid_gl_context_debug; extern cvar_t vid_gl_context_es; @@ -182,15 +205,63 @@ extern cvar_t vid_gl_context_compatibility; extern cvar_t vid_gl_context_robustness; extern cvar_t vid_gl_context_selfreset; -int window_center_x, window_center_y, window_x, window_y, window_width, window_height; -RECT window_rect; - -dllhandle_t *hInstGL = NULL; -dllhandle_t *hInstwgl = NULL; +static dllhandle_t *hInstGL = NULL; +static dllhandle_t *hInstwgl = NULL; static qboolean usingminidriver; static char reqminidriver[MAX_OSPATH]; static char opengldllname[MAX_OSPATH]; + +static HGLRC (WINAPI *qwglCreateContext)(HDC); +static BOOL (WINAPI *qwglDeleteContext)(HGLRC); +static HGLRC (WINAPI *qwglGetCurrentContext)(VOID); +static HDC (WINAPI *qwglGetCurrentDC)(VOID); +static PROC (WINAPI *qwglGetProcAddress)(LPCSTR); +static BOOL (WINAPI *qwglMakeCurrent)(HDC, HGLRC); +static BOOL (WINAPI *qSwapBuffers)(HDC); +static BOOL (WINAPI *qwglSwapLayerBuffers)(HDC, UINT); +static int (WINAPI *qChoosePixelFormat)(HDC, CONST PIXELFORMATDESCRIPTOR *); +static BOOL (WINAPI *qSetPixelFormat)(HDC, int, CONST PIXELFORMATDESCRIPTOR *); +static int (WINAPI *qDescribePixelFormat)(HDC, int, UINT, LPPIXELFORMATDESCRIPTOR); + +static BOOL (WINAPI *qwglSwapIntervalEXT) (int); + +static BOOL (APIENTRY *qwglChoosePixelFormatARB)(HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats); + +static HGLRC (APIENTRY *qwglCreateContextAttribsARB)(HDC hDC, HGLRC hShareContext, const int *attribList); +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 +#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x0004 /*WGL_ARB_create_context_robustness*/ +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 /*WGL_ARB_create_context_profile*/ +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 /*WGL_CONTEXT_ES2_PROFILE_BIT_EXT*/ +#define ERROR_INVALID_VERSION_ARB 0x2095 +#define ERROR_INVALID_PROFILE_ARB 0x2096 +#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 /*WGL_ARB_create_context_robustness*/ +#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261 +#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 + + +//pixel format stuff +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_STEREO_ARB 0x2012 +#define WGL_COLOR_BITS_ARB 0x2014 +#define WGL_ALPHA_BITS_ARB 0x201B +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_FULL_ACCELERATION_ARB 0x2027 + + + #ifdef _DEBUG //this is a list of the functions that exist in opengles2, as well as wglCreateContextAttribsARB. //functions not in this list *should* be stubs that just return errors, but we can't always depend on drivers for that... they shouldn't get called. @@ -506,7 +577,7 @@ static char *gles1funcs[] = #endif //just GetProcAddress with a safty net. -void *getglfunc(char *name) +static void *getglfunc(char *name) { FARPROC proc; proc = qwglGetProcAddress?qwglGetProcAddress(name):NULL; @@ -544,7 +615,7 @@ void *getglfunc(char *name) #endif return proc; } -void *getwglfunc(char *name) +static void *getwglfunc(char *name) { FARPROC proc; TRACE(("dbg: getwglfunc: %s: getting\n", name)); @@ -567,61 +638,11 @@ void *getwglfunc(char *name) return proc; } -HGLRC (WINAPI *qwglCreateContext)(HDC); -BOOL (WINAPI *qwglDeleteContext)(HGLRC); -HGLRC (WINAPI *qwglGetCurrentContext)(VOID); -HDC (WINAPI *qwglGetCurrentDC)(VOID); -PROC (WINAPI *qwglGetProcAddress)(LPCSTR); -BOOL (WINAPI *qwglMakeCurrent)(HDC, HGLRC); -BOOL (WINAPI *qSwapBuffers)(HDC); -BOOL (WINAPI *qwglSwapLayerBuffers)(HDC, UINT); -int (WINAPI *qChoosePixelFormat)(HDC, CONST PIXELFORMATDESCRIPTOR *); -BOOL (WINAPI *qSetPixelFormat)(HDC, int, CONST PIXELFORMATDESCRIPTOR *); -int (WINAPI *qDescribePixelFormat)(HDC, int, UINT, LPPIXELFORMATDESCRIPTOR); +static qboolean shouldforcepixelformat; +static int forcepixelformat; +static int currentpixelformat; -BOOL (WINAPI *qwglSwapIntervalEXT) (int); - -BOOL (APIENTRY *qGetDeviceGammaRamp)(HDC hDC, GLvoid *ramp); -BOOL (APIENTRY *qSetDeviceGammaRamp)(HDC hDC, GLvoid *ramp); - -BOOL (APIENTRY *qwglChoosePixelFormatARB)(HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats); - -HGLRC (APIENTRY *qwglCreateContextAttribsARB)(HDC hDC, HGLRC hShareContext, const int *attribList); -#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 -#define WGL_CONTEXT_FLAGS_ARB 0x2094 -#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 -#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 -#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x0004 /*WGL_ARB_create_context_robustness*/ -#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 /*WGL_ARB_create_context_profile*/ -#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 -#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 -#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 /*WGL_CONTEXT_ES2_PROFILE_BIT_EXT*/ -#define ERROR_INVALID_VERSION_ARB 0x2095 -#define ERROR_INVALID_PROFILE_ARB 0x2096 -#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 /*WGL_ARB_create_context_robustness*/ -#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261 -#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 - - -//pixel format stuff -#define WGL_DRAW_TO_WINDOW_ARB 0x2001 -#define WGL_ACCELERATION_ARB 0x2003 -#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 -#define WGL_SUPPORT_OPENGL_ARB 0x2010 -#define WGL_DOUBLE_BUFFER_ARB 0x2011 -#define WGL_STEREO_ARB 0x2012 -#define WGL_COLOR_BITS_ARB 0x2014 -#define WGL_ALPHA_BITS_ARB 0x201B -#define WGL_DEPTH_BITS_ARB 0x2022 -#define WGL_STENCIL_BITS_ARB 0x2023 -#define WGL_FULL_ACCELERATION_ARB 0x2027 -qboolean shouldforcepixelformat; -int forcepixelformat; -int currentpixelformat; - -qboolean GLInitialise (char *renderer) +static qboolean GLInitialise (char *renderer) { if (!hInstGL || strcmp(reqminidriver, renderer)) { @@ -736,8 +757,84 @@ qboolean GLInitialise (char *renderer) return true; } +static void ReleaseGL(void) +{ + HGLRC hRC; + HDC hDC = NULL; + + if (qwglGetCurrentContext) + { + hRC = qwglGetCurrentContext(); + hDC = qwglGetCurrentDC(); + + qwglMakeCurrent(NULL, NULL); + + if (hRC) + qwglDeleteContext(hRC); + } + qwglGetCurrentContext=NULL; + + if (hDC && dibwindow) + ReleaseDC(dibwindow, hDC); +} +#endif //USE_WGL + +#ifdef VKQUAKE +static dllhandle_t *hInstVulkan = NULL; +static qboolean Win32VK_CreateSurface(void) +{ + VkResult err; + VkWin32SurfaceCreateInfoKHR createInfo = {VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR}; + createInfo.flags = 0; + createInfo.hinstance = GetModuleHandle(NULL); + createInfo.hwnd = mainwindow; + + err = vkCreateWin32SurfaceKHR(vk.instance, &createInfo, NULL, &vk.surface); + switch(err) + { + default: + Con_Printf("Unknown vulkan device creation error: %x\n", err); + return false; + case VK_SUCCESS: + break; + } + return true; +} + +#ifdef WTHREAD +static void Win32VK_Present(struct vkframe *theframe) +{ +// if (theframe) +// PostMessage(mainwindow, WM_USER+7, 0, (LPARAM)theframe); +// else + SendMessage(mainwindow, WM_USER+7, 0, (LPARAM)theframe); +} +#else +#define Win32VK_Present NULL +#endif + +static qboolean Win32VK_AttachVulkan (rendererstate_t *info) +{ //make sure we can get a valid renderer. +#ifdef VK_NO_PROTOTYPES + hInstVulkan = NULL; + if (!hInstVulkan) + hInstVulkan = *info->subrenderer?LoadLibrary(info->subrenderer):NULL; + if (!hInstVulkan) + hInstVulkan = LoadLibrary("vulkan-1.dll"); + if (!hInstVulkan) + { + Con_Printf("Unable to load vulkan-1.dll\nNo Vulkan drivers are installed\n"); + return false; + } + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) GetProcAddress(hInstVulkan, "vkGetInstanceProcAddr"); +#endif + + return VK_Init(info, VK_KHR_WIN32_SURFACE_EXTENSION_NAME, Win32VK_CreateSurface, Win32VK_Present); +} +#endif + /*doesn't consider parent offsets*/ -RECT centerrect(unsigned int parentleft, unsigned int parenttop, unsigned int parentwidth, unsigned int parentheight, unsigned int cwidth, unsigned int cheight) +static RECT centerrect(unsigned int parentleft, unsigned int parenttop, unsigned int parentwidth, unsigned int parentheight, unsigned int cwidth, unsigned int cheight) { RECT r; if (modestate!=MS_WINDOWED) @@ -1115,11 +1212,57 @@ static qboolean VID_SetFullDIBMode (rendererstate_t *info) } extern qboolean gammaworks; -static void ReleaseGL(void); static void Win_Touch_Init(HWND wnd); -static qboolean CreateMainWindow(rendererstate_t *info) + +#ifdef WTHREAD +static rendererstate_t *rs; +static qboolean CreateMainWindow(rendererstate_t *info, qboolean withthread); +static int GLVID_WindowThread(void *cond) +{ + extern qboolean mouseshowtoggle; + int cursor = 1; + MSG msg; + HWND wnd; + CreateMainWindow(rs, false); + wnd = mainwindow; + Sys_ConditionSignal(cond); + + while (GetMessageW(&msg, NULL, 0, 0)) + { +// TranslateMessageW (&msg); + DispatchMessageW (&msg); + + //ShowCursor is thread-local. + if (cursor != mouseshowtoggle) + { + cursor = mouseshowtoggle; + ShowCursor(cursor); + } + } + DestroyWindow(wnd); + return 0; +} +#endif +static qboolean CreateMainWindow(rendererstate_t *info, qboolean withthread) { qboolean stat; + +#ifdef WTHREAD + if (withthread) + { + void *cond = Sys_CreateConditional(); + Sys_LockConditional(cond); + rs = info; + windowthread = Sys_CreateThread("windowthread", GLVID_WindowThread, cond, 0, 0); + if (!Sys_ConditionWait(cond)) + Con_SafePrintf ("Looks like the window thread isn't starting up\n"); + Sys_UnlockConditional(cond); + Sys_DestroyConditional(cond); + + return !!mainwindow; + } +#endif + if (WinNT) { WNDCLASSW wc; @@ -1174,46 +1317,14 @@ static qboolean CreateMainWindow(rendererstate_t *info) return stat; } -#ifdef WTHREAD -rendererstate_t *rs; -int GLVID_WindowThread(void *cond) -{ - extern qboolean mouseshowtoggle; - int cursor = 1; - MSG msg; - HWND wnd; - CreateMainWindow(rs); - wnd = mainwindow; - Sys_ConditionSignal(cond); - - while (GetMessageW(&msg, NULL, 0, 0)) - { - TranslateMessageW (&msg); - DispatchMessageW (&msg); - - //ShowCursor is thread-local. - if (cursor != mouseshowtoggle) - { - cursor = mouseshowtoggle; - ShowCursor(cursor); - } - } - DestroyWindow(wnd); - return 0; -} -#endif - -BOOL CheckForcePixelFormat(rendererstate_t *info); -void VID_UnSetMode (void); -int GLVID_SetMode (rendererstate_t *info, unsigned char *palette) +static BOOL CheckForcePixelFormat(rendererstate_t *info); +static void VID_UnSetMode (void); +static int GLVID_SetMode (rendererstate_t *info, unsigned char *palette) { int temp; qboolean stat; -#ifdef WTHREAD - void *cond; -#endif #ifndef NPFTE - MSG msg; + MSG msg; #endif // HDC hdc; @@ -1225,59 +1336,82 @@ int GLVID_SetMode (rendererstate_t *info, unsigned char *palette) CDAudio_Pause (); - // Set either the fullscreen or windowed mode - qwglChoosePixelFormatARB = NULL; - qwglCreateContextAttribsARB = NULL; + qGetDeviceGammaRamp = (void*)GetDeviceGammaRamp; + qSetDeviceGammaRamp = (void*)SetDeviceGammaRamp; -#ifdef WTHREAD - cond = Sys_CreateConditional(); - Sys_LockConditional(cond); - rs = info; - windowthread = Sys_CreateThread("windowthread", GLVID_WindowThread, cond, 0, 0); - if (!Sys_ConditionWait(cond)) - Con_SafePrintf ("Looks like the window thread isn't starting up\n"); - Sys_UnlockConditional(cond); - Sys_DestroyConditional(cond); - - stat = !!mainwindow; -#else - stat = CreateMainWindow(info); -#endif - - if (stat) + switch(platform_rendermode) { - stat = VID_AttachGL(info); +#ifdef USE_WGL + case MODE_WGL: + // Set either the fullscreen or windowed mode + qwglChoosePixelFormatARB = NULL; + qwglCreateContextAttribsARB = NULL; + stat = CreateMainWindow(info, true); + if (stat) { - TRACE(("dbg: GLVID_SetMode: attaching gl okay\n")); - if (CheckForcePixelFormat(info)) + stat = VID_AttachGL(info); + if (stat) { - HMODULE oldgl = hInstGL; - hInstGL = NULL; //don't close the gl library, just in case - VID_UnSetMode(); - hInstGL = oldgl; + TRACE(("dbg: GLVID_SetMode: attaching gl okay\n")); + if (CheckForcePixelFormat(info)) + { + HMODULE oldgl = hInstGL; + hInstGL = NULL; //don't close the gl library, just in case + VID_UnSetMode(); + hInstGL = oldgl; - if (CreateMainWindow(info) && VID_AttachGL(info)) - { - //we have our multisample window - } - else - { - //multisample failed - //try the origional way - if (!CreateMainWindow(info) || !VID_AttachGL(info)) + if (CreateMainWindow(info, true) && VID_AttachGL(info)) { - Con_Printf("Failed to undo antialising. Giving up.\n"); - return false; //eek + //we have our multisample window + } + else + { + //multisample failed + //try the origional way + if (!CreateMainWindow(info, true) || !VID_AttachGL(info)) + { + Con_Printf("Failed to undo antialising. Giving up.\n"); + return false; //eek + } } } } + else + { + TRACE(("dbg: GLVID_SetMode: attaching gl failed\n")); + return false; + } } - else + break; +#endif +#ifdef USE_EGL + case MODE_EGL: + stat = CreateMainWindow(info, true); + if (stat) { - TRACE(("dbg: GLVID_SetMode: attaching gl failed\n")); - return false; + maindc = GetDC(mainwindow); + stat = EGL_Init (info, palette, mainwindow, maindc); + + if (stat) + GL_Init(&EGL_Proc); } + break; +#endif +#ifdef VKQUAKE + case MODE_VULKAN: + stat = CreateMainWindow(info, true); + + if (stat) + { + maindc = GetDC(mainwindow); + stat = Win32VK_AttachVulkan(info); + } + break; +#endif + default: + stat = false; + break; } if (!stat) @@ -1286,6 +1420,10 @@ int GLVID_SetMode (rendererstate_t *info, unsigned char *palette) return false; } + if (!qGetDeviceGammaRamp) qGetDeviceGammaRamp = (void*)GetDeviceGammaRamp; + if (!qSetDeviceGammaRamp) qSetDeviceGammaRamp = (void*)SetDeviceGammaRamp; + + window_width = DIBWidth; window_height = DIBHeight; VID_UpdateWindowStatus (mainwindow); @@ -1306,8 +1444,8 @@ int GLVID_SetMode (rendererstate_t *info, unsigned char *palette) /*I don't like this, but if we */ while (PeekMessage (&msg, mainwindow, 0, 0, PM_REMOVE)) { - TranslateMessage (&msg); - DispatchMessage (&msg); + TranslateMessage (&msg); + DispatchMessage (&msg); } Sleep (100); #endif @@ -1342,27 +1480,6 @@ int GLVID_SetMode (rendererstate_t *info, unsigned char *palette) return true; } -static void ReleaseGL(void) -{ - HGLRC hRC; - HDC hDC = NULL; - - if (qwglGetCurrentContext) - { - hRC = qwglGetCurrentContext(); - hDC = qwglGetCurrentDC(); - - qwglMakeCurrent(NULL, NULL); - - if (hRC) - qwglDeleteContext(hRC); - } - qwglGetCurrentContext=NULL; - - if (hDC && dibwindow) - ReleaseDC(dibwindow, hDC); -} - void VID_UnSetMode (void) { if (mainwindow && vid_initialized) @@ -1370,13 +1487,32 @@ void VID_UnSetMode (void) GLAppActivate(false, false); vid_canalttab = false; - ReleaseGL(); + + switch(platform_rendermode) + { +#ifdef USE_WGL + case MODE_WGL: + ReleaseGL(); + break; +#endif +#ifdef USE_EGL + case MODE_EGL: + EGL_Shutdown(); + break; +#endif +#ifdef VKQUAKE + case MODE_VULKAN: + VK_Shutdown(); + break; +#endif + } if (modestate == MS_FULLDIB) ChangeDisplaySettings (NULL, 0); if (maindc && dibwindow) ReleaseDC (dibwindow, maindc); + maindc = NULL; } if (mainwindow) @@ -1389,7 +1525,7 @@ void VID_UnSetMode (void) if (windowthread) { SendMessage(mainwindow, WM_USER+4, 0, 0); - CloseHandle((HANDLE)windowthread); + Sys_WaitOnThread(windowthread); windowthread = NULL; } else @@ -1427,7 +1563,7 @@ void VID_UnSetMode (void) VID_UpdateWindowStatus ================ */ -void VID_UpdateWindowStatus (HWND hWnd) +static void VID_UpdateWindowStatus (HWND hWnd) { POINT p; RECT nr; @@ -1447,8 +1583,6 @@ void VID_UpdateWindowStatus (HWND hWnd) window_y = p.y; window_width = WindowRect.right - WindowRect.left; window_height = WindowRect.bottom - WindowRect.top; - vid.pixelwidth = window_width; - vid.pixelheight = window_height; window_rect.left = window_x; window_rect.top = window_y; @@ -1458,9 +1592,24 @@ void VID_UpdateWindowStatus (HWND hWnd) window_center_y = (window_rect.top + window_rect.bottom) / 2; INS_UpdateClipCursor (); + + switch(platform_rendermode) + { +#ifdef VKQUAKE + case MODE_VULKAN: + if (vid.pixelwidth != window_width || vid.pixelheight != window_height) + vk.neednewswapchain = true; + break; +#endif + default: + vid.pixelwidth = window_width; + vid.pixelheight = window_height; + break; + } } -qboolean WGL_CheckExtension(char *extname) +#ifdef USE_WGL +static qboolean WGL_CheckExtension(char *extname) { // int i; int len; @@ -1543,14 +1692,14 @@ qboolean VID_AttachGL (rendererstate_t *info) TRACE(("dbg: VID_AttachGL: qwglCreateContext\n")); - baseRC = qwglCreateContext(maindc); + baseRC = qwglCreateContext(maindc); if (!baseRC) { Con_SafePrintf(CON_ERROR "Could not initialize GL (wglCreateContext failed).\n\nMake sure you in are 65535 color mode, and try running -window.\n"); //green to make it show. return false; } TRACE(("dbg: VID_AttachGL: qwglMakeCurrent\n")); - if (!qwglMakeCurrent(maindc, baseRC)) + if (!qwglMakeCurrent(maindc, baseRC)) { Con_SafePrintf(CON_ERROR "wglMakeCurrent failed\n"); //green to make it show. return false; @@ -1707,19 +1856,26 @@ qboolean VID_AttachGL (rendererstate_t *info) qglClear(GL_COLOR_BUFFER_BIT); qSwapBuffers(maindc); - if (!qGetDeviceGammaRamp) qGetDeviceGammaRamp = (void*)GetDeviceGammaRamp; - if (!qSetDeviceGammaRamp) qSetDeviceGammaRamp = (void*)SetDeviceGammaRamp; - return true; } +#endif static void QDECL VID_Wait_Override_Callback(struct cvar_s *var, char *oldvalue) { - if (qwglSwapIntervalEXT && *vid_vsync.string) - qwglSwapIntervalEXT(vid_vsync.value); + switch(platform_rendermode) + { +#ifdef USE_WGL + case MODE_WGL: + if (qwglSwapIntervalEXT && *vid_vsync.string) + qwglSwapIntervalEXT(vid_vsync.value); + break; +#endif + default: + break; + } } -void GLVID_Recenter_f(void) +static void GLVID_Recenter_f(void) { // 4 unused variables //int nw = vid_width.value; @@ -1817,20 +1973,37 @@ static void QDECL VID_WndAlpha_Override_Callback(struct cvar_s *var, char *oldva void GLVID_SwapBuffers (void) { - if (qwglSwapLayerBuffers) + switch(platform_rendermode) { - if (!qwglSwapLayerBuffers(maindc, WGL_SWAP_MAIN_PLANE)) - qwglSwapLayerBuffers = NULL; +#ifdef USE_WGL + case MODE_WGL: + if (qwglSwapLayerBuffers) + { + if (!qwglSwapLayerBuffers(maindc, WGL_SWAP_MAIN_PLANE)) + qwglSwapLayerBuffers = NULL; + } + else + qSwapBuffers(maindc); + break; +#endif +#ifdef USE_EGL + case MODE_EGL: + EGL_SwapBuffers(); + break; +#endif +#ifdef VKQUAKE + case MODE_VULKAN: + //FIXME: force a buffer swap now (might be called while loading (eg: q3), where we won't get a chance to redraw for a bit) + break; +#endif } - else - qSwapBuffers(maindc); // handle the mouse state when windowed if that's changed INS_UpdateGrabs(modestate != MS_WINDOWED, vid.activeapp); } -void OblitterateOldGamma(void) +static void OblitterateOldGamma(void) { int i; if (vid_preservegamma.value) @@ -1926,15 +2099,16 @@ void GLVID_Shutdown (void) gammaworks = false; - GLBE_Shutdown(); - Image_Shutdown(); +// GLBE_Shutdown(); +// Image_Shutdown(); VID_UnSetMode(); } //========================================================================== -BOOL CheckForcePixelFormat(rendererstate_t *info) +#ifdef USE_WGL +static BOOL CheckForcePixelFormat(rendererstate_t *info) { if (qwglChoosePixelFormatARB && (info->multisample || info->srgb)) { @@ -1988,7 +2162,7 @@ BOOL CheckForcePixelFormat(rendererstate_t *info) return false; } -BYTE IntensityFromShifted(unsigned int index, unsigned int shift, unsigned int bits) +static BYTE IntensityFromShifted(unsigned int index, unsigned int shift, unsigned int bits) { unsigned int val; @@ -2023,7 +2197,7 @@ BYTE IntensityFromShifted(unsigned int index, unsigned int shift, unsigned int b return val; } -void FixPaletteInDescriptor(HDC hDC, PIXELFORMATDESCRIPTOR *pfd) +static void FixPaletteInDescriptor(HDC hDC, PIXELFORMATDESCRIPTOR *pfd) { LOGPALETTE *ppal; HPALETTE hpal; @@ -2053,9 +2227,9 @@ void FixPaletteInDescriptor(HDC hDC, PIXELFORMATDESCRIPTOR *pfd) } } -BOOL bSetupPixelFormat(HDC hDC, rendererstate_t *info) +static BOOL bSetupPixelFormat(HDC hDC, rendererstate_t *info) { - PIXELFORMATDESCRIPTOR pfd = { + PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd 1, // version number PFD_DRAW_TO_WINDOW // support window @@ -2079,7 +2253,7 @@ BOOL bSetupPixelFormat(HDC hDC, rendererstate_t *info) PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0 // layer masks ignored - }; + }; TRACE(("dbg: bSetupPixelFormat: ChoosePixelFormat\n")); @@ -2127,11 +2301,11 @@ BOOL bSetupPixelFormat(HDC hDC, rendererstate_t *info) qDescribePixelFormat(hDC, currentpixelformat, sizeof(pfd), &pfd); - if (qSetPixelFormat(hDC, currentpixelformat, &pfd) == FALSE) - { - Con_Printf("bSetupPixelFormat: SetPixelFormat failed (%i)\n", (int)GetLastError()); - return FALSE; - } + if (qSetPixelFormat(hDC, currentpixelformat, &pfd) == FALSE) + { + Con_Printf("bSetupPixelFormat: SetPixelFormat failed (%i)\n", (int)GetLastError()); + return FALSE; + } if ((pfd.dwFlags & PFD_GENERIC_FORMAT) && !(pfd.dwFlags & PFD_GENERIC_ACCELERATED)) { @@ -2141,8 +2315,9 @@ BOOL bSetupPixelFormat(HDC hDC, rendererstate_t *info) Con_Printf(CON_WARNING "WARNING: buffer swaps will use copy operations\n"); FixPaletteInDescriptor(hDC, &pfd); - return TRUE; + return TRUE; } +#endif /* =================================================================== @@ -2157,7 +2332,7 @@ MAIN WINDOW ClearAllStates ================ */ -void ClearAllStates (void) +static void ClearAllStates (void) { int i; @@ -2171,7 +2346,7 @@ void ClearAllStates (void) INS_ClearStates (); } -qboolean GLAppActivate(BOOL fActive, BOOL minimize) +static qboolean GLAppActivate(BOOL fActive, BOOL minimize) /**************************************************************************** * * Function: AppActivate @@ -2317,6 +2492,8 @@ static void Win_Touch_Event(int points, HTOUCHINPUT ti) } #ifdef WTHREAD +//runs on the main/render thread, forwarded from the worker thread. +//these events are the ones that would cause race conditions, but need to be able to cope with a little bit of a delay (and shouldn't need to trigger other window messages, as that would cause other races). void MainThreadWndProc(void *ctx, void *data, size_t msg, size_t ex) { switch(msg) @@ -2353,7 +2530,7 @@ however, we have to tread carefully. the main/render thread will be running the this means that the main and window thread cannot be allowed to contest any mutexes where anything but memory is touched before its unlocked. (or in other words, we can't have the main thread near-perma-lock any mutexes that can be locked-to-sync here) */ -LONG WINAPI GLMainWndProc ( +static LONG WINAPI GLMainWndProc ( HWND hWnd, UINT uMsg, WPARAM wParam, @@ -2521,6 +2698,11 @@ LONG WINAPI GLMainWndProc ( } break; +#ifdef VKQUAKE + case WM_USER+7: + VK_DoPresent((struct vkframe*)lParam); + break; +#endif case WM_USER+4: PostQuitMessage(0); break; @@ -2646,12 +2828,7 @@ LONG WINAPI GLMainWndProc ( return lRet; } - -qboolean GLVID_Is8bit(void) { - return is8bit; -} - - +/* void VID_Init8bitPalette(void) { #ifdef GL_USE8BITTEX @@ -2685,6 +2862,7 @@ void VID_Init8bitPalette(void) #endif #endif } +*/ void GLVID_DeInit (void) { @@ -2701,12 +2879,14 @@ void GLVID_DeInit (void) VID_Init =================== */ -qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) +qboolean Win32VID_Init (rendererstate_t *info, unsigned char *palette, int mode) { extern int isPlugin; // qbyte *ptmp; DEVMODE devmode; + platform_rendermode = mode; + memset(&devmode, 0, sizeof(devmode)); hIcon = LoadIcon (global_hInstance, MAKEINTRESOURCE (IDI_ICON1)); @@ -2726,7 +2906,7 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) } // Check for 3DFX Extensions and initialize them. - VID_Init8bitPalette(); + //VID_Init8bitPalette(); vid_canalttab = true; @@ -2746,4 +2926,153 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) return true; } + +#ifdef USE_WGL +qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) +{ + return Win32VID_Init(info, palette, MODE_WGL); +} +#endif //USE_WGL + + + + + +#ifdef USE_EGL + +static qboolean EGLVID_Init (rendererstate_t *info, unsigned char *palette) +{ + if (!EGL_LoadLibrary(info->subrenderer)) + return false; + return Win32VID_Init(info, palette, MODE_EGL); +} + + + +#include "shader.h" +#include "gl_draw.h" +rendererinfo_t eglrendererinfo = +{ + "EGL(win32)", + { + "egl" + }, + QR_OPENGL, + + GLDraw_Init, + GLDraw_DeInit, + + GL_UpdateFiltering, + GL_LoadTextureMips, + GL_DestroyTexture, + + GLR_Init, + GLR_DeInit, + GLR_RenderView, + + EGLVID_Init, + GLVID_DeInit, + GLVID_SwapBuffers, + GLVID_ApplyGammaRamps, + + NULL, + NULL, + NULL, + GLVID_SetCaption, //setcaption + GLVID_GetRGBInfo, + + + GLSCR_UpdateScreen, + + GLBE_SelectMode, + GLBE_DrawMesh_List, + GLBE_DrawMesh_Single, + GLBE_SubmitBatch, + GLBE_GetTempBatch, + GLBE_DrawWorld, + GLBE_Init, + GLBE_GenBrushModelVBO, + GLBE_ClearVBO, + GLBE_UploadAllLightmaps, + GLBE_SelectEntity, + GLBE_SelectDLight, + GLBE_Scissor, + GLBE_LightCullModel, + + GLBE_VBO_Begin, + GLBE_VBO_Data, + GLBE_VBO_Finish, + GLBE_VBO_Destroy, + + GLBE_RenderToTextureUpdate2d, + + "" +}; +#endif //USE_EGL + + +#ifdef VKQUAKE +static qboolean VKVID_Init (rendererstate_t *info, unsigned char *palette) +{ + return Win32VID_Init(info, palette, MODE_VULKAN); +} + +rendererinfo_t vkrendererinfo = +{ + "Vulkan", + { + "vk", + "Vulkan" + }, + QR_VULKAN, + + VK_Draw_Init, + VK_Draw_Shutdown, + + VK_UpdateFiltering, + VK_LoadTextureMips, + VK_DestroyTexture, + + VK_R_Init, + VK_R_DeInit, + VK_R_RenderView, + + VKVID_Init, + GLVID_DeInit, + GLVID_SwapBuffers, + GLVID_ApplyGammaRamps, + WIN_CreateCursor, + WIN_SetCursor, + WIN_DestroyCursor, + GLVID_SetCaption, + VKVID_GetRGBInfo, + + VK_SCR_UpdateScreen, + + VKBE_SelectMode, + VKBE_DrawMesh_List, + VKBE_DrawMesh_Single, + VKBE_SubmitBatch, + VKBE_GetTempBatch, + VKBE_DrawWorld, + VKBE_Init, + VKBE_GenBrushModelVBO, + VKBE_ClearVBO, + VKBE_UploadAllLightmaps, + VKBE_SelectEntity, + VKBE_SelectDLight, + VKBE_Scissor, + VKBE_LightCullModel, + + VKBE_VBO_Begin, + VKBE_VBO_Data, + VKBE_VBO_Finish, + VKBE_VBO_Destroy, + + VKBE_RenderToTextureUpdate2d, + + "no more" +}; +#endif + #endif diff --git a/engine/gl/glmod_doom.c b/engine/gl/glmod_doom.c index 2fd9dccc2..5ec7cd43f 100644 --- a/engine/gl/glmod_doom.c +++ b/engine/gl/glmod_doom.c @@ -1902,8 +1902,7 @@ void QuakifyThings(model_t *mod, dthing_t *thingsl) ptr += strlen(ptr); } - mod->entities = BZ_Malloc(ptr-newlump+1); - memcpy(mod->entities, newlump, ptr-newlump+1); + Mod_SetEntitiesStringLen(mod, newlump, ptr-newlump); } void Doom_GeneratePlanes(ddoomnode_t *nodel) diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index 8568aea53..1fcf58c5e 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -1005,18 +1005,6 @@ extern void (APIENTRY *qglTranslatef) (GLfloat x, GLfloat y, GLfloat z); extern FTEPFNGLUNIFORMMATRIXPROC qglUniformMatrix4x3fv; extern FTEPFNGLUNIFORMMATRIXPROC qglUniformMatrix3x4fv; -#ifdef _WIN32 -extern BOOL (WINAPI *qwglCopyContext)(HGLRC, HGLRC, UINT); -extern HGLRC (WINAPI *qwglCreateContext)(HDC); -extern HGLRC (WINAPI *qwglCreateLayerContext)(HDC, int); -extern BOOL (WINAPI *qwglDeleteContext)(HGLRC); -extern HGLRC (WINAPI *qwglGetCurrentContext)(VOID); -extern HDC (WINAPI *qwglGetCurrentDC)(VOID); -extern PROC (WINAPI *qwglGetProcAddress)(LPCSTR); -extern BOOL (WINAPI *qwglMakeCurrent)(HDC, HGLRC); -extern BOOL (WINAPI *qSwapBuffers)(HDC); -#endif - extern const GLubyte * (APIENTRY * qglGetStringi) (GLenum name, GLuint index); /* diff --git a/engine/gl/model_hl.h b/engine/gl/model_hl.h index 75c561cf5..04025624a 100644 --- a/engine/gl/model_hl.h +++ b/engine/gl/model_hl.h @@ -272,4 +272,6 @@ int HLMDL_FrameForName(model_t *mod, const char *name); const char *HLMDL_FrameNameForNum(model_t *model, int surfaceidx, int num); qboolean HLMDL_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **name, int *numframes, float *duration, qboolean *loop); int HLMDL_GetNumBones(model_t *mod); +int HLMDL_GetBoneParent(model_t *mod, int bonenum); +const char *HLMDL_GetBoneName(model_t *mod, int bonenum); int HLMDL_GetBoneData(model_t *model, int firstbone, int lastbone, framestate_t *fstate, float *result); diff --git a/engine/gl/r_bishaders.h b/engine/gl/r_bishaders.h index 4bbb5cd64..3a9d4a546 100644 --- a/engine/gl/r_bishaders.h +++ b/engine/gl/r_bishaders.h @@ -4483,7 +4483,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #endif #ifdef GLQUAKE {QR_OPENGL, 110, "defaultwall", -"!!ver 110 // 130\n" +"!!ver 100 120 // 130\n" "!!permu DELUXE\n" "!!permu FULLBRIGHT\n" "!!permu FOG\n" @@ -4496,7 +4496,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#include \"sys/defs.h\"\n" -"#if GL_VERSION >= 130\n" +"#if __VERSION__ >= 130\n" "#define texture2D texture\n" "#define textureCube texture\n" "#define gl_FragColor gl_FragData[0]\n" @@ -4586,7 +4586,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND //optional: round the lightmap coords to ensure all pixels within a texel have different lighting values either. it just looks wrong otherwise. //don't bother if its lightstyled, such cases will have unpredictable correlations anyway. //FIXME: this rounding is likely not correct with respect to software rendering. oh well. -"#if GL_VERSION >= 130\n" +"#if __VERSION__ >= 130\n" "vec2 lmsize = vec2(textureSize(s_lightmap0, 0));\n" "#else\n" "#define lmsize vec2(128.0,2048.0)\n" diff --git a/engine/nacl/gl_vidppapi.c b/engine/nacl/gl_vidppapi.c index cdefa1605..5fad50634 100644 --- a/engine/nacl/gl_vidppapi.c +++ b/engine/nacl/gl_vidppapi.c @@ -292,8 +292,6 @@ void GLVID_Crashed(void); void GLVID_Update (vrect_t *rects); -int GLVID_SetMode (rendererstate_t *info, unsigned char *palette); - void GLVID_SetCaption(const char *caption) { } diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 0500eea74..efb402958 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -10295,7 +10295,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs // {"cvar_setlatch", PF_cvar_setlatch, 0, 0, 0, ???, "void(string cvarname, optional string value)"}, {"clusterevent", PF_clusterevent, 0, 0, 0, 0, D("void(string dest, string from, string cmd, string info)", "Only functions in mapcluster mode. Sends an event to whichever server the named player is on. The destination server can then dispatch the event to the client or handle it itself via the SV_ParseClusterEvent entrypoint. If dest is empty, the event is broadcast to ALL servers. If the named player can't be found, the event will be returned to this server with the cmd prefixed with 'error:'.")}, {"clustertransfer", PF_clustertransfer, 0, 0, 0, 0, D("string(entity player, optional string newnode)", "Only functions in mapcluster mode. Initiate transfer of the player to a different node. Can take some time. If dest is specified, returns null on error. Otherwise returns the current/new target node (or null if not transferring).")}, - + {"modelframecount", PF_modelframecount, 0, 0, 0, 0, D("float(float mdlidx)", "Retrieves the number of frames in the specified model.")}, {"clearscene", PF_Fixme, 0, 0, 0, 300, D("void()", "Forgets all rentities, polygons, and temporary dlights. Resets all view properties to their default values.")},// (EXT_CSQC) {"addentities", PF_Fixme, 0, 0, 0, 301, D("void(float mask)", "Walks through all entities effectively doing this:\n if (ent.drawmask&mask){ if (!ent.predaw()) addentity(ent); }\nIf mask&MASK_DELTA, non-csqc entities, particles, and related effects will also be added to the rentity list.\n If mask&MASK_STDVIEWMODEL then the default view model will also be added.")},// (EXT_CSQC) diff --git a/engine/server/svhl_game.c b/engine/server/svhl_game.c index 7b1365ea0..4ab5ec67c 100644 --- a/engine/server/svhl_game.c +++ b/engine/server/svhl_game.c @@ -174,8 +174,7 @@ int QDECL GHL_ModelFrames(int midx) { bi_trace(); //returns the number of frames(sequences I assume) this model has - ignore("ModelFrames"); - return 1; + return Mod_GetFrameCount(sv.models[mdlidx], surfaceidx); } void QDECL GHL_SetSize(hledict_t *ed, float *mins, float *maxs) { diff --git a/engine/shaders/glsl/defaultwall.glsl b/engine/shaders/glsl/defaultwall.glsl index cb3ef694a..f35ff30cd 100644 --- a/engine/shaders/glsl/defaultwall.glsl +++ b/engine/shaders/glsl/defaultwall.glsl @@ -1,4 +1,4 @@ -!!ver 110 // 130 +!!ver 100 120 // 130 !!permu DELUXE !!permu FULLBRIGHT !!permu FOG @@ -11,7 +11,7 @@ #include "sys/defs.h" -#if GL_VERSION >= 130 +#if __VERSION__ >= 130 #define texture2D texture #define textureCube texture #define gl_FragColor gl_FragData[0] @@ -101,7 +101,7 @@ void main () //optional: round the lightmap coords to ensure all pixels within a texel have different lighting values either. it just looks wrong otherwise. //don't bother if its lightstyled, such cases will have unpredictable correlations anyway. //FIXME: this rounding is likely not correct with respect to software rendering. oh well. -#if GL_VERSION >= 130 +#if __VERSION__ >= 130 vec2 lmsize = vec2(textureSize(s_lightmap0, 0)); #else #define lmsize vec2(128.0,2048.0) diff --git a/engine/sw/sw_vidwin.c b/engine/sw/sw_vidwin.c index ac9d5f210..b34cb72c1 100644 --- a/engine/sw/sw_vidwin.c +++ b/engine/sw/sw_vidwin.c @@ -209,8 +209,8 @@ void DIB_SwapBuffers(void) */ } -extern int window_width; -extern int window_height; +static int window_width; +static int window_height; void SWV_UpdateWindowStatus(void) { POINT p; diff --git a/engine/vk/vk_win32.c b/engine/vk/vk_win32.c deleted file mode 100644 index 0c687b6cb..000000000 --- a/engine/vk/vk_win32.c +++ /dev/null @@ -1,1686 +0,0 @@ -/* -Copyright (C) 1996-1997 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ -// vk_win32.c -- win32-specific window handling for vulkan. -//I should probably merge this with gl_vidnt.c somehow... might get messy though - -#include "quakedef.h" -#ifdef VKQUAKE -#include "glquake.h" -#include "vkrenderer.h" -#include "winquake.h" -#include "resource.h" -#include "shader.h" -#include - -void STT_Event(void); - -#ifndef SetWindowLongPtr //yes its a define, for unicode support -#define SetWindowLongPtr SetWindowLong -#endif - -#ifndef CDS_FULLSCREEN - #define CDS_FULLSCREEN 4 -#endif - -#ifndef WM_XBUTTONDOWN - #define WM_XBUTTONDOWN 0x020B - #define WM_XBUTTONUP 0x020C -#endif -#ifndef MK_XBUTTON1 - #define MK_XBUTTON1 0x0020 -#endif -#ifndef MK_XBUTTON2 - #define MK_XBUTTON2 0x0040 -#endif -// copied from DarkPlaces in an attempt to grab more buttons -#ifndef MK_XBUTTON3 - #define MK_XBUTTON3 0x0080 -#endif -#ifndef MK_XBUTTON4 - #define MK_XBUTTON4 0x0100 -#endif -#ifndef MK_XBUTTON5 - #define MK_XBUTTON5 0x0200 -#endif -#ifndef MK_XBUTTON6 - #define MK_XBUTTON6 0x0400 -#endif -#ifndef MK_XBUTTON7 - #define MK_XBUTTON7 0x0800 -#endif - -#ifndef WM_INPUT - #define WM_INPUT 255 -#endif - -#ifndef WS_EX_LAYERED - #define WS_EX_LAYERED 0x00080000 -#endif -#ifndef LWA_ALPHA - #define LWA_ALPHA 0x00000002 -#endif -typedef BOOL (WINAPI *lpfnSetLayeredWindowAttributes)(HWND hwnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags); - -extern cvar_t vid_conwidth, vid_conautoscale; - -#define WINDOW_CLASS_NAME_W L"FTEVkQuake" -#define WINDOW_CLASS_NAME_A "FTEVkQuake" - -extern cvar_t vid_width; -extern cvar_t vid_height; -extern cvar_t vid_wndalpha; -extern qboolean gammaworks; - -typedef enum {MS_WINDOWED, MS_FULLDIB, MS_FULLWINDOW, MS_UNINIT} modestate_t; - -//qboolean VID_SetWindowedMode (int modenum); -//qboolean VID_SetFullDIBMode (int modenum); -static qboolean VID_SetWindowedMode (rendererstate_t *info); //-1 on bpp or hz for default. -static qboolean VID_SetFullDIBMode (rendererstate_t *info); //-1 on bpp or hz for default. - -qboolean scr_skipupdate; - -#ifdef MULTITHREAD -#define WTHREAD //While the user is resizing a window, the entire thread that owns said window becomes frozen. in order to cope with window resizing, its easiest to just create a separate thread to be microsoft's plaything. our main game thread can then just keep rendering. hopefully that won't bug out on the present. -#endif -#ifdef WTHREAD -static HANDLE windowthread; -#endif - -static DEVMODE gdevmode; -static qboolean vid_initialized = false; -static qboolean vid_canalttab = false; -static qboolean vid_wassuspended = false; -extern qboolean mouseactive; // from in_win.c -static HICON hIcon; -extern qboolean vid_isfullscreen; - -unsigned short originalgammaramps[3][256]; - -qboolean vid_initializing; - -int DIBWidth, DIBHeight; -RECT WindowRect; -DWORD WindowStyle, ExWindowStyle; - -HWND mainwindow; - -HWND WINAPI InitializeWindow (HINSTANCE hInstance, int nCmdShow); - -viddef_t vid; // global video state - -//unsigned short d_8to16rgbtable[256]; -//unsigned d_8to24rgbtable[256]; -//unsigned short d_8to16bgrtable[256]; -//unsigned d_8to24bgrtable[256]; - -static modestate_t modestate = MS_UNINIT; - -extern float gammapending; - - -static LONG WINAPI VKMainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); -static qboolean VKAppActivate(BOOL fActive, BOOL minimize); -static void ClearAllStates (void); -static void VID_UpdateWindowStatus (HWND hWnd); - -//==================================== -// Note that 0 is MODE_WINDOWED -extern cvar_t vid_mode; -// Note that 3 is MODE_FULLSCREEN_DEFAULT -extern cvar_t vid_vsync; -extern cvar_t _windowed_mouse; -extern cvar_t vid_hardwaregamma; -extern cvar_t vid_desktopgamma; -extern cvar_t vid_preservegamma; - -int window_center_x, window_center_y, window_x, window_y, window_width, window_height; -RECT window_rect; - -static dllhandle_t *hInstVulkan = NULL; - -/*doesn't consider parent offsets*/ -static RECT centerrect(unsigned int parentleft, unsigned int parenttop, unsigned int parentwidth, unsigned int parentheight, unsigned int cwidth, unsigned int cheight) -{ - RECT r; - if (modestate!=MS_WINDOWED) - { - if (!vid_width.ival) - cwidth = parentwidth; - if (!vid_height.ival) - cheight = parentwidth; - } - - if (parentwidth < cwidth) - { - r.left = parentleft; - r.right = r.left+parentwidth; - } - else - { - r.left = parentleft + (parentwidth - cwidth) / 2; - r.right = r.left + cwidth; - } - - if (parentheight < cheight) - { - r.top = parenttop; - r.bottom = r.top + parentheight; - } - else - { - r.top = parenttop + (parentheight - cheight) / 2; - r.bottom = r.top + cheight; - } - - return r; -} - -static qboolean VID_SetWindowedMode (rendererstate_t *info) -{ - int i; - HDC hdc; - int wwidth, wheight, pleft, ptop, pwidth, pheight; - RECT rect; - - modestate = MS_WINDOWED; - - hdc = GetDC(NULL); - if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) - { - ReleaseDC(NULL, hdc); - Con_Printf("Can't run GL in non-RGB mode\n"); - return false; - } - ReleaseDC(NULL, hdc); - - WindowRect.top = WindowRect.left = 0; - - WindowRect.right = info->width; - WindowRect.bottom = info->height; - - -#ifndef FTE_SDL - if (sys_parentwindow) - { - SetWindowLong(sys_parentwindow, GWL_STYLE, GetWindowLong(sys_parentwindow, GWL_STYLE)|WS_OVERLAPPED); - WindowStyle = WS_CHILDWINDOW|WS_OVERLAPPED; - ExWindowStyle = 0; - - pleft = sys_parentleft; - ptop = sys_parenttop; - pwidth = sys_parentwidth; - pheight = sys_parentheight; - - WindowRect.right = sys_parentwidth; - WindowRect.bottom = sys_parentheight; - } - else -#endif - { - WindowStyle = WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_SYSMENU | - WS_MINIMIZEBOX; - ExWindowStyle = 0; - - WindowStyle |= WS_SIZEBOX | WS_MAXIMIZEBOX; - - pleft = 0; - ptop = 0; - pwidth = GetSystemMetrics(SM_CXSCREEN); - pheight = GetSystemMetrics(SM_CYSCREEN); - - /*Assume dual monitors, and chop the width to try to put it on only one screen*/ - if (pwidth >= pheight*2) - pwidth /= 2; - } - - DIBWidth = WindowRect.right - WindowRect.left; - DIBHeight = WindowRect.bottom - WindowRect.top; - - rect = WindowRect; - AdjustWindowRectEx(&rect, WindowStyle, FALSE, 0); - - wwidth = rect.right - rect.left; - wheight = rect.bottom - rect.top; - - WindowRect = centerrect(pleft, ptop, pwidth, pheight, wwidth, wheight); - - // Create the DIB window - if (WinNT) - { - mainwindow = CreateWindowExW ( - ExWindowStyle, - WINDOW_CLASS_NAME_W, - _L(FULLENGINENAME), - WindowStyle, - WindowRect.left, WindowRect.top, - WindowRect.right - WindowRect.left, - WindowRect.bottom - WindowRect.top, - sys_parentwindow, - NULL, - global_hInstance, - NULL); - } - else - { - mainwindow = CreateWindowExA ( - ExWindowStyle, - WINDOW_CLASS_NAME_A, - FULLENGINENAME, - WindowStyle, - WindowRect.left, WindowRect.top, - WindowRect.right - WindowRect.left, - WindowRect.bottom - WindowRect.top, - sys_parentwindow, - NULL, - global_hInstance, - NULL); - } - - if (!mainwindow) - { - Con_Printf ("Couldn't create DIB window"); - return false; - } - - SendMessage (mainwindow, WM_SETICON, (WPARAM)TRUE, (LPARAM)hIcon); - SendMessage (mainwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon); - - if (!sys_parentwindow) - { -#ifdef WS_EX_LAYERED - int av; - av = 255*vid_wndalpha.value; - if (av < 70) - av = 70; - if (av < 255) - { - HMODULE hm = GetModuleHandleA("user32.dll"); - lpfnSetLayeredWindowAttributes pSetLayeredWindowAttributes; - pSetLayeredWindowAttributes = (void*)GetProcAddress(hm, "SetLayeredWindowAttributes"); - - if (pSetLayeredWindowAttributes) - { - // Set WS_EX_LAYERED on this window - SetWindowLong(mainwindow, GWL_EXSTYLE, GetWindowLong(mainwindow, GWL_EXSTYLE) | WS_EX_LAYERED); - - // Make this window 70% alpha - pSetLayeredWindowAttributes(mainwindow, 0, (BYTE)av, LWA_ALPHA); - } - } -#endif - } - - ShowWindow (mainwindow, SW_SHOWDEFAULT); - SetFocus(mainwindow); - -// ShowWindow (mainwindow, SW_SHOWDEFAULT); -// UpdateWindow (mainwindow); - -// because we have set the background brush for the window to NULL -// (to avoid flickering when re-sizing the window on the desktop), -// we clear the window to black when created, otherwise it will be -// empty while Quake starts up. - hdc = GetDC(mainwindow); - PatBlt(hdc,0,0,WindowRect.right,WindowRect.bottom,BLACKNESS); - ReleaseDC(mainwindow, hdc); - - if ((i = COM_CheckParm("-conwidth")) != 0) - vid.width = Q_atoi(com_argv[i+1]); - else - { - vid.width = 640; - } - - vid.width &= 0xfff8; // make it a multiple of eight - - if (vid.width < 320) - vid.width = 320; - - // pick a conheight that matches with correct aspect - vid.height = vid.width*3 / 4; - - if ((i = COM_CheckParm("-conheight")) != 0) - vid.height = Q_atoi(com_argv[i+1]); - if (vid.height < 200) - vid.height = 200; - - if (vid.height > info->height) - vid.height = info->height; - if (vid.width > info->width) - vid.width = info->width; - - vid.numpages = 2; - - vid_isfullscreen=false; - - CL_UpdateWindowTitle(); - - return true; -} - -static void VKVID_SetWindowCaption(const char *text) -{ - wchar_t wide[2048]; - widen(wide, sizeof(wide), text); - SetWindowTextW(mainwindow, wide); -} - - -static qboolean VID_SetFullDIBMode (rendererstate_t *info) -{ - int i; - HDC hdc; - int wwidth, wheight; - RECT rect; - - if (info->fullscreen != 2) - { //make windows change res. - - modestate = MS_FULLDIB; - - gdevmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; - if (info->bpp) - gdevmode.dmFields |= DM_BITSPERPEL; - if (info->rate) - gdevmode.dmFields |= DM_DISPLAYFREQUENCY; - if (info->bpp && (info->bpp < 15)) - { //low values get you a warning. otherwise only 16 and 32bit are allowed. - Con_Printf("Forcing at least 15bpp\n"); - gdevmode.dmBitsPerPel = 16; - } - else if (info->bpp == 16) - gdevmode.dmBitsPerPel = 16; - else - gdevmode.dmBitsPerPel = 32; - gdevmode.dmDisplayFrequency = info->rate; - gdevmode.dmPelsWidth = info->width; - gdevmode.dmPelsHeight = info->height; - gdevmode.dmSize = sizeof (gdevmode); - - if (ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) - { - Con_SafePrintf((gdevmode.dmFields&DM_DISPLAYFREQUENCY)?"Windows rejected mode %i*%i*%ibpp@%ihz\n":"Windows rejected mode %i*%i*%ibpp\n", (int)gdevmode.dmPelsWidth, (int)gdevmode.dmPelsHeight, (int)gdevmode.dmBitsPerPel, (int)gdevmode.dmDisplayFrequency); - return false; - } - } - else - { - modestate = MS_FULLWINDOW; - - } - - WindowRect.top = WindowRect.left = 0; - - WindowRect.right = info->width; - WindowRect.bottom = info->height; - - DIBWidth = info->width; - DIBHeight = info->height; - - WindowStyle = WS_POPUP; - ExWindowStyle = 0; - - rect = WindowRect; - AdjustWindowRectEx(&rect, WindowStyle, FALSE, 0); - - wwidth = rect.right - rect.left; - wheight = rect.bottom - rect.top; - - // Create the DIB window - if(WinNT) - { - mainwindow = CreateWindowExW ( - ExWindowStyle, - WINDOW_CLASS_NAME_W, - _L(FULLENGINENAME), - WindowStyle, - rect.left, rect.top, - wwidth, - wheight, - NULL, - NULL, - global_hInstance, - NULL); - } - else - { - mainwindow = CreateWindowExA ( - ExWindowStyle, - WINDOW_CLASS_NAME_A, - FULLENGINENAME, - WindowStyle, - rect.left, rect.top, - wwidth, - wheight, - NULL, - NULL, - global_hInstance, - NULL); - } - - if (!mainwindow) - Sys_Error ("Couldn't create DIB window"); - - SendMessage (mainwindow, WM_SETICON, (WPARAM)TRUE, (LPARAM)hIcon); - SendMessage (mainwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon); - - if (modestate == MS_FULLWINDOW) - ShowWindow (mainwindow, SW_SHOWMAXIMIZED); - else - ShowWindow (mainwindow, SW_SHOWDEFAULT); - UpdateWindow (mainwindow); - - // Because we have set the background brush for the window to NULL - // (to avoid flickering when re-sizing the window on the desktop), we - // clear the window to black when created, otherwise it will be - // empty while Quake starts up. - hdc = GetDC(mainwindow); - PatBlt(hdc,0,0,WindowRect.right,WindowRect.bottom,BLACKNESS); - ReleaseDC(mainwindow, hdc); - - - if ((i = COM_CheckParm("-conwidth")) != 0) - vid.width = Q_atoi(com_argv[i+1]); - else - vid.width = 640; - - vid.width &= 0xfff8; // make it a multiple of eight - - if (vid.width < 320) - vid.width = 320; - - // pick a conheight that matches with correct aspect - vid.height = vid.width*3 / 4; - - if ((i = COM_CheckParm("-conheight")) != 0) - vid.height = Q_atoi(com_argv[i+1]); - if (vid.height < 200) - vid.height = 200; - - if (vid.height > info->height) - vid.height = info->height; - if (vid.width > info->width) - vid.width = info->width; - - vid.numpages = 2; - -// needed because we're not getting WM_MOVE messages fullscreen on NT - window_x = 0; - window_y = 0; - vid_isfullscreen=true; - - return true; -} - -static void Win_Touch_Init(HWND wnd); -static qboolean CreateMainWindow(rendererstate_t *info) -{ - qboolean stat; - if (WinNT) - { - WNDCLASSW wc; - /* Register the frame class */ - wc.style = CS_OWNDC; - wc.lpfnWndProc = (WNDPROC)VKMainWndProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = global_hInstance; - wc.hIcon = hIcon; - wc.hCursor = hArrowCursor; - wc.hbrBackground = NULL; - wc.lpszMenuName = 0; - wc.lpszClassName = WINDOW_CLASS_NAME_W; - if (!RegisterClassW (&wc)) //this isn't really fatal, we'll let the CreateWindow fail instead. - Con_Printf("RegisterClass failed\n"); - } - else - { - WNDCLASSA wc; - /* Register the frame class */ - wc.style = CS_OWNDC; - wc.lpfnWndProc = (WNDPROC)VKMainWndProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = global_hInstance; - wc.hIcon = hIcon; - wc.hCursor = hArrowCursor; - wc.hbrBackground = NULL; - wc.lpszMenuName = 0; - wc.lpszClassName = WINDOW_CLASS_NAME_A; - if (!RegisterClassA (&wc)) //this isn't really fatal, we'll let the CreateWindow fail instead. - Con_Printf("RegisterClass failed\n"); - } - - if (!info->fullscreen) - { - stat = VID_SetWindowedMode(info); - } - else - { - stat = VID_SetFullDIBMode(info); - } - VID_UpdateWindowStatus(mainwindow); - - Win_Touch_Init(mainwindow); - - INS_UpdateGrabs(info->fullscreen, vid.activeapp); - - return stat; -} - -#ifdef WTHREAD -static rendererstate_t *rs; -static int VKVID_WindowThread(void *cond) -{ - extern qboolean mouseshowtoggle; - int cursor = 1; - MSG msg; - HWND wnd; - CreateMainWindow(rs); - wnd = mainwindow; - Sys_ConditionSignal(cond); - - while (GetMessageW(&msg, NULL, 0, 0)) - { -// TranslateMessageW (&msg); - DispatchMessageW (&msg); - - //ShowCursor is thread-local. - if (cursor != mouseshowtoggle) - { - cursor = mouseshowtoggle; - ShowCursor(cursor); - } - } - DestroyWindow(wnd); - return 0; -} -#endif - -static qboolean VK_CreateSurface(void) -{ - VkResult err; - VkWin32SurfaceCreateInfoKHR createInfo = {VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR}; - createInfo.flags = 0; - createInfo.hinstance = GetModuleHandle(NULL); - createInfo.hwnd = mainwindow; - - err = vkCreateWin32SurfaceKHR(vk.instance, &createInfo, NULL, &vk.surface); - switch(err) - { - default: - Con_Printf("Unknown vulkan device creation error: %x\n", err); - return false; - case VK_SUCCESS: - break; - } - return true; -} - -#ifdef WTHREAD -static void VK_Win32_Present(struct vkframe *theframe) -{ -// if (theframe) -// PostMessage(mainwindow, WM_USER+7, 0, (LPARAM)theframe); -// else - SendMessage(mainwindow, WM_USER+7, 0, (LPARAM)theframe); -} -#else -#define VK_Present NULL -#endif - -static qboolean VID_AttachVulkan (rendererstate_t *info) -{ //make sure we can get a valid renderer. -#ifdef VK_NO_PROTOTYPES - hInstVulkan = NULL; - if (!hInstVulkan) - hInstVulkan = *info->subrenderer?LoadLibrary(info->subrenderer):NULL; - if (!hInstVulkan) - hInstVulkan = LoadLibrary("vulkan-1.dll"); - if (!hInstVulkan) - { - Con_Printf("Unable to load vulkan-1.dll\nNo Vulkan drivers are installed\n"); - return false; - } - vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) GetProcAddress(hInstVulkan, "vkGetInstanceProcAddr"); -#endif - - return VK_Init(info, VK_KHR_WIN32_SURFACE_EXTENSION_NAME, VK_CreateSurface, VK_Win32_Present); -} - - -static void VID_UnSetMode (void); -static int VKVID_SetMode (rendererstate_t *info, unsigned char *palette) -{ - int temp; - qboolean stat; -#ifdef WTHREAD - void *cond; -#endif -#ifndef NPFTE - MSG msg; -#endif -// HDC hdc; - -// so Con_Printfs don't mess us up by forcing vid and snd updates - temp = scr_disabled_for_loading; - scr_disabled_for_loading = true; - - CDAudio_Pause (); - -#ifdef WTHREAD - cond = Sys_CreateConditional(); - Sys_LockConditional(cond); - rs = info; - windowthread = Sys_CreateThread("windowthread", VKVID_WindowThread, cond, 0, 0); - if (!Sys_ConditionWait(cond)) - Con_SafePrintf ("Looks like the window thread isn't starting up\n"); - Sys_UnlockConditional(cond); - Sys_DestroyConditional(cond); - - stat = !!mainwindow; -#else - stat = CreateMainWindow(info); -#endif - - if (stat) - { - stat = VID_AttachVulkan(info); - if (!stat) - return false; - } - - if (!stat) - return false; - - window_width = DIBWidth; - window_height = DIBHeight; - VID_UpdateWindowStatus (mainwindow); - - CDAudio_Resume (); - scr_disabled_for_loading = temp; - -// now we try to make sure we get the focus on the mode switch, because -// sometimes in some systems we don't. We grab the foreground, then -// finish setting up, pump all our messages, and sleep for a little while -// to let messages finish bouncing around the system, then we put -// ourselves at the top of the z order, then grab the foreground again, -// Who knows if it helps, but it probably doesn't hurt - SetForegroundWindow (mainwindow); - -#ifndef NPFTE - /*I don't like this, but if we */ - while (PeekMessage (&msg, mainwindow, 0, 0, PM_REMOVE)) - { - TranslateMessage (&msg); - DispatchMessage (&msg); - } - Sleep (100); -#endif - - SetWindowPos (mainwindow, HWND_TOP, 0, 0, 0, 0, - SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | - SWP_NOCOPYBITS); - - SetForegroundWindow (mainwindow); - -// fix the leftover Alt from any Alt-Tab or the like that switched us away - ClearAllStates (); - - if (vid_desktopgamma.value) - { - HDC hDC = GetDC(GetDesktopWindow()); - gammaworks = GetDeviceGammaRamp(hDC, originalgammaramps); - ReleaseDC(GetDesktopWindow(), hDC); - } - else - { - HDC hDC = GetDC(mainwindow); - gammaworks = GetDeviceGammaRamp(hDC, originalgammaramps); - ReleaseDC(mainwindow, hDC); - } - - return true; -} - -static void VID_UnSetMode (void) -{ - if (mainwindow && vid_initialized) - { - VKAppActivate(false, false); - - vid_canalttab = false; - VK_Shutdown(); - - if (modestate == MS_FULLDIB) - ChangeDisplaySettings (NULL, 0); - } - - if (mainwindow) - { - // ShowWindow(mainwindow, SW_HIDE); - // SetWindowLongPtr(mainwindow, GWL_WNDPROC, DefWindowProc); - // PostMessage(mainwindow, WM_CLOSE, 0, 0); -#ifdef WTHREAD - if (windowthread) - { - SendMessage(mainwindow, WM_USER+4, 0, 0); - Sys_WaitOnThread(windowthread); - windowthread = NULL; - } - else -#endif - DestroyWindow(mainwindow); - mainwindow = NULL; - } - - if (hInstVulkan) - FreeLibrary(hInstVulkan); - hInstVulkan = NULL; -} - - -/* -================ -VID_UpdateWindowStatus -================ -*/ -static void VID_UpdateWindowStatus (HWND hWnd) -{ - POINT p; - RECT nr; - GetClientRect(hWnd, &nr); - - //if its bad then we're probably minimised - if (nr.right <= nr.left) - return; - if (nr.bottom <= nr.top) - return; - - WindowRect = nr; - p.x = 0; - p.y = 0; - ClientToScreen(hWnd, &p); - window_x = p.x; - window_y = p.y; - window_width = WindowRect.right - WindowRect.left; - window_height = WindowRect.bottom - WindowRect.top; - if (vid.pixelwidth != window_width || vid.pixelheight != window_height) - vk.neednewswapchain = true; - - window_rect.left = window_x; - window_rect.top = window_y; - window_rect.right = window_x + window_width; - window_rect.bottom = window_y + window_height; - window_center_x = (window_rect.left + window_rect.right) / 2; - window_center_y = (window_rect.top + window_rect.bottom) / 2; - - INS_UpdateClipCursor (); -} - -//==================================== - -static void QDECL VID_Wait_Override_Callback(struct cvar_s *var, char *oldvalue) -{ - qboolean want = !!atoi(oldvalue); - if (vk.vsync != want) - { - vk.vsync = want; - vk.neednewswapchain = true; - } -} - -static void VKVID_Recenter_f(void) -{ - // 4 unused variables - //int nw = vid_width.value; - //int nh = vid_height.value; - //int nx = 0; - //int ny = 0; - - if (Cmd_Argc() > 1) - sys_parentleft = atoi(Cmd_Argv(1)); - if (Cmd_Argc() > 2) - sys_parenttop = atoi(Cmd_Argv(2)); - if (Cmd_Argc() > 3) - sys_parentwidth = atoi(Cmd_Argv(3)); - if (Cmd_Argc() > 4) - sys_parentheight = atoi(Cmd_Argv(4)); - if (Cmd_Argc() > 5) - { - HWND newparent = (HWND)(DWORD_PTR)strtoull(Cmd_Argv(5), NULL, 16); - if (newparent != sys_parentwindow && mainwindow && modestate==MS_WINDOWED) - SetParent(mainwindow, sys_parentwindow); - sys_parentwindow = newparent; - } - - if (sys_parentwindow && modestate==MS_WINDOWED) - { - WindowRect = centerrect(sys_parentleft, sys_parenttop, sys_parentwidth, sys_parentheight, sys_parentwidth, sys_parentheight); - MoveWindow(mainwindow, WindowRect.left, WindowRect.top, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top, FALSE); - - VID_UpdateWindowStatus (mainwindow); - } -} - -static void QDECL VID_WndAlpha_Override_Callback(struct cvar_s *var, char *oldvalue) -{ - //this code tells windows to use the alpha channel of the screen, but does really nasty things with the mouse such that its unplayable. - //its not useful. -/* if (modestate==MS_WINDOWED) - { - struct qDWM_BLURBEHIND - { - DWORD dwFlags; - BOOL fEnable; - HRGN hRgnBlur; - BOOL fTransitionOnMaximized; - } bb = {1, true, NULL, true}; - HRESULT (WINAPI *pDwmEnableBlurBehindWindow)(HWND hWnd,const struct qDWM_BLURBEHIND *pBlurBehind); - dllfunction_t dwm[] = - { - {(void*)&pDwmEnableBlurBehindWindow, "DwmEnableBlurBehindWindow"}, - {NULL,NULL} - }; - if (Sys_LoadLibrary("dwmapi.dll", dwm)) - pDwmEnableBlurBehindWindow(mainwindow, &bb); - } -*/ - -#ifdef WS_EX_LAYERED - //enable whole-window fixed transparency. should work in win2k+ - //note that this can destroy framerates, and they won't reset when the setting is reverted to 1. - //be prepared to do a vid_restart. - if (modestate==MS_WINDOWED) - { - int av; - HMODULE hm = GetModuleHandleA("user32.dll"); - lpfnSetLayeredWindowAttributes pSetLayeredWindowAttributes; - pSetLayeredWindowAttributes = (void*)GetProcAddress(hm, "SetLayeredWindowAttributes"); - - av = 255 * var->value; - if (av < 70) - av = 70; - if (av > 255) - av = 255; - - if (pSetLayeredWindowAttributes) - { - // Set WS_EX_LAYERED on this window - - if (av < 255) - { - SetWindowLong(mainwindow, GWL_EXSTYLE, GetWindowLong(mainwindow, GWL_EXSTYLE) | WS_EX_LAYERED); - - // Make this window 70% alpha - pSetLayeredWindowAttributes(mainwindow, 0, (BYTE)av, LWA_ALPHA); - } - else - { - SetWindowLong(mainwindow, GWL_EXSTYLE, GetWindowLong(mainwindow, GWL_EXSTYLE) & ~WS_EX_LAYERED); - pSetLayeredWindowAttributes(mainwindow, 0, (BYTE)255, LWA_ALPHA); - } - } - } -#endif -} - -static void VKVID_SwapBuffers (void) -{ -// handle the mouse state when windowed if that's changed - - INS_UpdateGrabs(modestate != MS_WINDOWED, vid.activeapp); -} - -static void OblitterateOldGamma(void) -{ - int i; - if (vid_preservegamma.value) - return; - - for (i = 0; i < 256; i++) - { - originalgammaramps[0][i] = (i<<8) + i; - originalgammaramps[1][i] = (i<<8) + i; - originalgammaramps[2][i] = (i<<8) + i; - } -} - -static qboolean VKVID_ApplyGammaRamps (unsigned int gammarampsize, unsigned short *ramps) -{ - if (ramps) - { - if (!gammaworks || gammarampsize != 256) - return false; - - if (vid_hardwaregamma.value == 1 && modestate == MS_WINDOWED) - return false; //don't do hardware gamma in windowed mode - - if (vid.activeapp && vid_hardwaregamma.value) //this is needed because ATI drivers don't work properly (or when task-switched out). - { - if (gammaworks) - { //we have hardware gamma applied - if we're doing a BF, we don't want to reset to the default gamma (yuck) - if (vid_desktopgamma.value) - { - HDC hDC = GetDC(GetDesktopWindow()); - SetDeviceGammaRamp (hDC, ramps); - ReleaseDC(GetDesktopWindow(), hDC); - } - else - { - HDC hDC = GetDC(mainwindow); - SetDeviceGammaRamp (hDC, ramps); - ReleaseDC(mainwindow, hDC); - } - } - return true; - } - return false; - } - else - { - if (vid_initialized) - { - //revert to default - OblitterateOldGamma(); - - if (vid_desktopgamma.value) - { - HDC hDC = GetDC(GetDesktopWindow()); - SetDeviceGammaRamp (hDC, originalgammaramps); - ReleaseDC(GetDesktopWindow(), hDC); - } - else - { - HDC hDC = GetDC(mainwindow); - SetDeviceGammaRamp (hDC, originalgammaramps); - ReleaseDC(mainwindow, hDC); - } - } - return true; - } -} - -void VKVID_Crashed(void) -{ - if (vid_initialized && gammaworks) - { - OblitterateOldGamma(); - - if (vid_desktopgamma.value) - { - HDC hDC = GetDC(GetDesktopWindow()); - SetDeviceGammaRamp (hDC, originalgammaramps); - ReleaseDC(GetDesktopWindow(), hDC); - } - else - { - HDC hDC = GetDC(mainwindow); - SetDeviceGammaRamp (hDC, originalgammaramps); - ReleaseDC(mainwindow, hDC); - } - } -} - -static void VKVID_Shutdown (void) -{ - if (vid_initialized) - { - OblitterateOldGamma(); - - if (vid_desktopgamma.value) - { - HDC hDC = GetDC(GetDesktopWindow()); - SetDeviceGammaRamp(hDC, originalgammaramps); - ReleaseDC(GetDesktopWindow(), hDC); - } - else - { - HDC hDC = GetDC(mainwindow); - SetDeviceGammaRamp(hDC, originalgammaramps); - ReleaseDC(mainwindow, hDC); - } - } - - gammaworks = false; - - VID_UnSetMode(); -} - -/* -=================================================================== - -MAIN WINDOW - -=================================================================== -*/ - -/* -================ -ClearAllStates -================ -*/ -static void ClearAllStates (void) -{ - int i; - -// send an up event for each key, to make sure the server clears them all - for (i=0 ; i<256 ; i++) - { - Key_Event (0, i, 0, false); - } - - Key_ClearStates (); - INS_ClearStates (); -} - -static qboolean VKAppActivate(BOOL fActive, BOOL minimize) -/**************************************************************************** -* -* Function: AppActivate -* Parameters: fActive - True if app is activating -* -* Description: If the application is activating, then swap the system -* into SYSPAL_NOSTATIC mode so that our palettes will display -* correctly. -* -****************************************************************************/ -{ - static BOOL sound_active; - - if (vid.activeapp == fActive && Minimized == minimize) - return false; //so windows doesn't crash us over and over again. - - vid.activeapp = fActive;// && (foregroundwindow==mainwindow); - Minimized = minimize; - -// enable/disable sound on focus gain/loss - if (!vid.activeapp && sound_active) - { - S_BlockSound (); - sound_active = false; - } - else if (vid.activeapp && !sound_active) - { - S_UnblockSound (); - sound_active = true; - } - - INS_UpdateGrabs(modestate != MS_WINDOWED, vid.activeapp); - - if (fActive) - { - if (modestate == MS_FULLDIB) - { - if (vid_canalttab && vid_wassuspended) - { - vid_wassuspended = false; - ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN); - ShowWindow(mainwindow, SW_SHOWNORMAL); - - // Fix for alt-tab bug in NVidia drivers - MoveWindow (mainwindow, 0, 0, gdevmode.dmPelsWidth, gdevmode.dmPelsHeight, false); - } - } - else if (modestate == MS_FULLWINDOW) - { - ShowWindow (mainwindow, SW_SHOWMAXIMIZED); - UpdateWindow (mainwindow); - } - - gammapending = 0.5; //delayed gamma force - Cvar_ForceCallback(&v_gamma); //so the delay isn't so blatent when you have decent graphics drivers that don't break things. - } - - if (!fActive) - { - if (modestate == MS_FULLDIB) - { - if (vid_canalttab) - { - ChangeDisplaySettings (NULL, 0); - vid_wassuspended = true; - } - } - - Cvar_ForceCallback(&v_gamma); //wham bam thanks. - } - - return true; -} - -#ifndef TWF_WANTPALM -typedef struct _TOUCHINPUT { - LONG x; - LONG y; - HANDLE hSource; - DWORD dwID; - DWORD dwFlags; - DWORD dwMask; - DWORD dwTime; - ULONG_PTR dwExtraInfo; - DWORD cxContact; - DWORD cyContact; -} TOUCHINPUT, *PTOUCHINPUT; -DECLARE_HANDLE(HTOUCHINPUT); - -#define WM_TOUCH 0x0240 -#define TOUCHINPUTMASKF_CONTACTAREA 0x0004 -#define TOUCHEVENTF_DOWN 0x0002 -#define TOUCHEVENTF_UP 0x0004 -#define TWF_WANTPALM 0x00000002 -#endif - -static BOOL (WINAPI *pRegisterTouchWindow)(HWND hWnd, ULONG ulFlags); -static BOOL (WINAPI *pGetTouchInputInfo)(HTOUCHINPUT hTouchInput, UINT cInputs, PTOUCHINPUT pInputs, int cbSize); -static BOOL (WINAPI *pCloseTouchInputHandle)(HTOUCHINPUT hTouchInput); -static void Win_Touch_Init(HWND wnd) -{ - HMODULE lib; - lib = LoadLibraryA("user32.dll"); - pRegisterTouchWindow = (void*)GetProcAddress(lib, "RegisterTouchWindow"); - pGetTouchInputInfo = (void*)GetProcAddress(lib, "GetTouchInputInfo"); - pCloseTouchInputHandle = (void*)GetProcAddress(lib, "CloseTouchInputHandle"); - - if (pRegisterTouchWindow && pGetTouchInputInfo && pCloseTouchInputHandle) - pRegisterTouchWindow(wnd, TWF_WANTPALM); -} -static void Win_Touch_Event(int points, HTOUCHINPUT ti) -{ - float sz; - int i; - TOUCHINPUT *inputs = malloc(points * sizeof(*inputs)), *input; - if (inputs) - { - if (pGetTouchInputInfo(ti, points, inputs, sizeof(*inputs))) - { - for (i = 0, input = inputs; i < points; i++, input++) - { - int id = input->dwID+1; //googling implies the id is generally a low 0-based index. I can't test this. the +1 ensures that mouselook is not broken by someone trying to use a touchscreen at the same time. - if (input->dwMask & TOUCHINPUTMASKF_CONTACTAREA) - sz = sqrt((input->cxContact*input->cxContact + input->cyContact*input->cyContact) / 10000.0); - else - sz = 0; - - //the web seems to imply that the ids should be low values, <16 or so. hurrah. - - //movement *then* buttons. this should ensure that the cursor is positioned correctly. - IN_MouseMove(id, true, input->x/100.0f, input->y/100.0f, 0, sz); - - if (input->dwFlags & TOUCHEVENTF_DOWN) - IN_KeyEvent(id, true, K_MOUSE1, 0); - if (input->dwFlags & TOUCHEVENTF_UP) - IN_KeyEvent(id, false, K_MOUSE1, 0); - } - } - free(inputs); - } - - pCloseTouchInputHandle(ti); -} - -#ifdef WTHREAD -static void MainThreadWndProc(void *ctx, void *data, size_t msg, size_t ex) -{ - switch(msg) - { - case WM_COPYDATA: - Host_RunFile(data, ex, NULL); - Z_Free(data); - break; - case WM_CLOSE: - Cbuf_AddText("\nquit\n", RESTRICT_LOCAL); - break; - case WM_SIZE: - case WM_MOVE: - VID_UpdateWindowStatus(mainwindow); - break; - case WM_KILLFOCUS: - VKAppActivate(FALSE, Minimized); - if (modestate == MS_FULLDIB) - ShowWindow(mainwindow, SW_SHOWMINNOACTIVE); - ClearAllStates (); - break; - case WM_SETFOCUS: - if (!VKAppActivate(TRUE, Minimized)) - break; - ClearAllStates (); - break; - } -} -#endif - -/* main window procedure -due to moving the main window over to a different thread, we gain access to input timestamps (as well as video refreshes when dragging etc) -however, we have to tread carefully. the main/render thread will be running the whole time, and may trigger messages that we need to respond to _now_. -this means that the main and window thread cannot be allowed to contest any mutexes where anything but memory is touched before its unlocked. -(or in other words, we can't have the main thread near-perma-lock any mutexes that can be locked-to-sync here) -*/ -static LONG WINAPI VKMainWndProc ( - HWND hWnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) -{ - LONG lRet = 1; -// int fActive, fMinimized; - int temp; - extern unsigned int uiWheelMessage; - - if ( uMsg == uiWheelMessage ) - uMsg = WM_MOUSEWHEEL; - - switch (uMsg) - { - case WM_COPYDATA: - { - COPYDATASTRUCT *cds = (COPYDATASTRUCT*)lParam; -#ifdef WTHREAD - COM_AddWork(WG_MAIN, MainThreadWndProc, NULL, memcpy(Z_Malloc(cds->cbData), cds->lpData, cds->cbData), uMsg, cds->cbData); -#else - Host_RunFile(cds->lpData, cds->cbData, NULL); -#endif - lRet = 1; - } - break; - case WM_KILLFOCUS: -#ifdef WTHREAD - COM_AddWork(WG_MAIN, MainThreadWndProc, NULL, NULL, uMsg, 0); -#else - VKAppActivate(FALSE, Minimized);//FIXME: thread - if (modestate == MS_FULLDIB) - ShowWindow(mainwindow, SW_SHOWMINNOACTIVE); - ClearAllStates (); //FIXME: thread -#endif - break; - case WM_SETFOCUS: -#ifdef WTHREAD - COM_AddWork(WG_MAIN, MainThreadWndProc, NULL, NULL, uMsg, 0); -#else - if (!VKAppActivate(TRUE, Minimized))//FIXME: thread - break; - ClearAllStates (); //FIXME: thread -#endif - break; - - case WM_TOUCH: - Win_Touch_Event(LOWORD(wParam), (HTOUCHINPUT)lParam); - return 0; //return 0 if we handled it. - - case WM_CREATE: - break; - - case WM_MOVE: -#ifdef WTHREAD - COM_AddWork(WG_MAIN, MainThreadWndProc, NULL, NULL, uMsg, 0); -#else - VID_UpdateWindowStatus (hWnd); -#endif - break; - - case WM_KEYDOWN: - case WM_SYSKEYDOWN: - if (!vid_initializing) - INS_TranslateKeyEvent(wParam, lParam, true, 0, false); - break; - -// case WM_UNICHAR: - case WM_DEADCHAR: - case WM_SYSDEADCHAR: - case WM_CHAR: - case WM_SYSCHAR: -// if (!vid_initializing) -// INS_TranslateKeyEvent(wParam, lParam, true); - break; - - case WM_KEYUP: - case WM_SYSKEYUP: - if (!vid_initializing) - INS_TranslateKeyEvent(wParam, lParam, false, 0, false); - break; - - case WM_MOUSEACTIVATE: - lRet = MA_ACTIVATEANDEAT; - break; - - // this is complicated because Win32 seems to pack multiple mouse events into - // one update sometimes, so we always check all states and look for events - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - case WM_RBUTTONDOWN: - case WM_RBUTTONUP: - case WM_MBUTTONDOWN: - case WM_MBUTTONUP: - case WM_MOUSEMOVE: - case WM_XBUTTONDOWN: - case WM_XBUTTONUP: - temp = 0; - - if (wParam & MK_LBUTTON) - { - temp |= 1; - if (sys_parentwindow && modestate == MS_WINDOWED) - SetFocus(hWnd); - } - - if (wParam & MK_RBUTTON) - temp |= 2; - - if (wParam & MK_MBUTTON) - temp |= 4; - - if (wParam & MK_XBUTTON1) - temp |= 8; - - if (wParam & MK_XBUTTON2) - temp |= 16; - - if (wParam & MK_XBUTTON3) - temp |= 32; - - if (wParam & MK_XBUTTON4) - temp |= 64; - - if (wParam & MK_XBUTTON5) - temp |= 128; - - if (wParam & MK_XBUTTON6) - temp |= 256; - - if (wParam & MK_XBUTTON7) - temp |= 512; - - if (!vid_initializing) - INS_MouseEvent (temp); //FIXME: thread (halflife) - - break; - - // JACK: This is the mouse wheel with the Intellimouse - // Its delta is either positive or neg, and we generate the proper - // Event. - case WM_MOUSEWHEEL: - if (!vid_initializing) - { - if ((short) HIWORD(wParam&0xffffffff) > 0) - { - IN_KeyEvent(0, true, K_MWHEELUP, 0); - IN_KeyEvent(0, false, K_MWHEELUP, 0); - } - else - { - IN_KeyEvent(0, true, K_MWHEELDOWN, 0); - IN_KeyEvent(0, false, K_MWHEELDOWN, 0); - } - } - break; - - case WM_INPUT: - // raw input handling - if (!vid_initializing) - { - INS_RawInput_Read((HANDLE)lParam); - lRet = 0; - } - break; - - case WM_USER+4: - PostQuitMessage(0); - break; - case WM_USER: -#ifndef NOMEDIA - STT_Event(); -#endif - break; - case WM_USER+7: - VK_DoPresent((struct vkframe*)lParam); - break; - - case WM_GETMINMAXINFO: - { - RECT windowrect; - RECT clientrect; - MINMAXINFO *mmi = (MINMAXINFO *) lParam; - - GetWindowRect (hWnd, &windowrect); - GetClientRect (hWnd, &clientrect); - - mmi->ptMinTrackSize.x = 320 + ((windowrect.right - windowrect.left) - (clientrect.right - clientrect.left)); - mmi->ptMinTrackSize.y = 200 + ((windowrect.bottom - windowrect.top) - (clientrect.bottom - clientrect.top)); - } - return 0; - case WM_SIZE: - vid.isminimized = (wParam==SIZE_MINIMIZED); - if (!vid_initializing) - { -#ifdef WTHREAD - COM_AddWork(WG_MAIN, MainThreadWndProc, NULL, NULL, uMsg, 0); -#else - VID_UpdateWindowStatus(hWnd); -#endif - } - break; - - case WM_CLOSE: - if (!vid_initializing) - { - if (wantquit) - { - //urr, this would be the second time that they've told us to quit. - //assume the main thread has deadlocked - if (MessageBoxW (hWnd, L"Terminate process?", L"Confirm Exit", - MB_YESNO | MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_DEFBUTTON2) == IDYES) - { - //abrupt process termination is never nice, but sometimes drivers suck. - //or qc code runs away, or ... - exit(1); - } - } - - else if (MessageBoxW (hWnd, L"Are you sure you want to quit?", L"Confirm Exit", - MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION|MB_DEFBUTTON2) == IDYES) - { -#ifdef WTHREAD - COM_AddWork(WG_MAIN, MainThreadWndProc, NULL, NULL, uMsg, 0); -#else - Cbuf_AddText("\nquit\n", RESTRICT_LOCAL); -#endif - wantquit = true; - } - } - break; - - case WM_ERASEBKGND: - lRet = TRUE; - break; -/* - case WM_ACTIVATE: -// fActive = LOWORD(wParam); -// fMinimized = (BOOL) HIWORD(wParam); -// if (!GLAppActivate(!(fActive == WA_INACTIVE), fMinimized)) - break;//so, urm, tell me microsoft, what changed? - if (modestate == MS_FULLDIB) - ShowWindow(hWnd, SW_SHOWNORMAL); - -#ifdef WTHREAD -#else - // fix the leftover Alt from any Alt-Tab or the like that switched us away - ClearAllStates (); //FIXME: thread - - Cvar_ForceCallback(&vid_conautoscale); //FIXME: thread -#endif - break; -*/ - case WM_DESTROY: - break; - case WM_SETCURSOR: - //only use a custom cursor if the cursor is inside the client area - switch(lParam&0xffff) - { - case 0: - break; - case HTCLIENT: - if (hCustomCursor) //custom cursor enabled - SetCursor(hCustomCursor); - else //fallback on an arrow cursor, just so we have something visible at startup or so - SetCursor(hArrowCursor); - lRet = TRUE; - break; - default: - lRet = DefWindowProcW (hWnd, uMsg, wParam, lParam); - break; - } - break; - -#ifndef WTHREAD - case MM_MCINOTIFY: - lRet = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam); //FIXME: thread - break; -#endif - - default: - /* pass all unhandled messages to DefWindowProc */ - if (WinNT) - lRet = DefWindowProcW (hWnd, uMsg, wParam, lParam); - else - lRet = DefWindowProcA (hWnd, uMsg, wParam, lParam); - break; - } - - /* return 1 if handled message, 0 if not */ - return lRet; -} - -void VKVID_DeInit (void) -{ - VKVID_Shutdown(); - vid.activeapp = false; - - Cvar_Unhook(&vid_vsync); - Cvar_Unhook(&vid_wndalpha); - Cmd_RemoveCommand("vid_recenter"); - - if (WinNT) - UnregisterClassW(WINDOW_CLASS_NAME_W, global_hInstance); - else - UnregisterClassA(WINDOW_CLASS_NAME_A, global_hInstance); -} - -/* -=================== -VID_Init -=================== -*/ -qboolean VKVID_Init (rendererstate_t *info, unsigned char *palette) -{ - extern int isPlugin; -// qbyte *ptmp; - DEVMODE devmode; - - memset(&devmode, 0, sizeof(devmode)); - - hIcon = LoadIcon (global_hInstance, MAKEINTRESOURCE (IDI_ICON1)); - hArrowCursor = LoadCursor (NULL,IDC_ARROW); - - vid_initialized = false; - vid_initializing = true; - - if (!VKVID_SetMode (info, palette)) - { - VID_UnSetMode(); - return false; - } - - vid_canalttab = true; - - Cvar_Hook(&vid_vsync, VID_Wait_Override_Callback); - Cvar_Hook(&vid_wndalpha, VID_WndAlpha_Override_Callback); - - Cmd_AddCommand("vid_recenter", VKVID_Recenter_f); - - if (isPlugin >= 2) - { - fprintf(stdout, "refocuswindow %"PRIxPTR"\n", (quintptr_t)mainwindow); - fflush(stdout); - } - - vid_initialized = true; - vid_initializing = false; - - return true; -} - -rendererinfo_t vkrendererinfo = -{ - "Vulkan", - { - "vk", - "Vulkan" - }, - QR_VULKAN, - - VK_Draw_Init, - VK_Draw_Shutdown, - - VK_UpdateFiltering, - VK_LoadTextureMips, - VK_DestroyTexture, - - VK_R_Init, - VK_R_DeInit, - VK_R_RenderView, - - VKVID_Init, - VKVID_DeInit, - VKVID_SwapBuffers, - VKVID_ApplyGammaRamps, - WIN_CreateCursor, - WIN_SetCursor, - WIN_DestroyCursor, - VKVID_SetWindowCaption, - VKVID_GetRGBInfo, - - VK_SCR_UpdateScreen, - - VKBE_SelectMode, - VKBE_DrawMesh_List, - VKBE_DrawMesh_Single, - VKBE_SubmitBatch, - VKBE_GetTempBatch, - VKBE_DrawWorld, - VKBE_Init, - VKBE_GenBrushModelVBO, - VKBE_ClearVBO, - VKBE_UploadAllLightmaps, - VKBE_SelectEntity, - VKBE_SelectDLight, - VKBE_Scissor, - VKBE_LightCullModel, - - VKBE_VBO_Begin, - VKBE_VBO_Data, - VKBE_VBO_Finish, - VKBE_VBO_Destroy, - - VKBE_RenderToTextureUpdate2d, - - "no more" -}; -#endif