From 57fd192cdadb6e0395e022be05a52fcd27381163 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Mon, 30 Jan 2017 20:31:32 +0100 Subject: [PATCH] GL3: levels are rendered a bit the code is still very much WIP and kinda crappy, especially the static GLuint vao = 0, vbo = 0; part in GL3_DrawGLPoly() --- src/client/refresh/gl3/gl3_image.c | 17 +- src/client/refresh/gl3/gl3_light.c | 2 +- src/client/refresh/gl3/gl3_main.c | 284 +++++++++++++++++++++++--- src/client/refresh/gl3/gl3_mesh.c | 18 +- src/client/refresh/gl3/gl3_model.c | 37 ++++ src/client/refresh/gl3/gl3_shaders.c | 129 +++++++++++- src/client/refresh/gl3/gl3_surf.c | 64 +++++- src/client/refresh/gl3/gl3_warp.c | 24 +-- src/client/refresh/gl3/header/local.h | 8 +- src/common/header/shared.h | 2 +- 10 files changed, 507 insertions(+), 78 deletions(-) diff --git a/src/client/refresh/gl3/gl3_image.c b/src/client/refresh/gl3/gl3_image.c index 506ecb0b..ccb0bbf1 100644 --- a/src/client/refresh/gl3/gl3_image.c +++ b/src/client/refresh/gl3/gl3_image.c @@ -88,8 +88,6 @@ GL3_TextureMode(char *string) ri.Cvar_SetValue("gl_anisotropic", 0.0); } - STUB_ONCE("TODO: fix existing textures' modes!"); -#if 0 // TODO! gl3image_t *glt; /* change all the existing mipmap texture objects */ @@ -97,18 +95,17 @@ GL3_TextureMode(char *string) { if ((glt->type != it_pic) && (glt->type != it_sky)) { - R_Bind(glt->texnum); + GL3_Bind(glt->texnum); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); /* Set anisotropic filter if supported and enabled */ - if (gl_config.anisotropic && gl_anisotropic->value) + if (gl3config.anisotropic && gl_anisotropic->value) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_anisotropic->value); } } } -#endif // 0 } void @@ -158,17 +155,14 @@ GL3_Upload32(unsigned *data, int width, int height, qboolean mipmap) } } - // TODO: some hardware may require mipmapping disabled for NPOT textures! - - //glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, mipmap); glTexImage2D(GL_TEXTURE_2D, 0, comp, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - //glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, false); res = (samples == gl3_alpha_format); if (mipmap) { + // TODO: some hardware may require mipmapping disabled for NPOT textures! glGenerateMipmap(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); @@ -789,8 +783,11 @@ GL3_ImageList_f(void) case it_pic: R_Printf(PRINT_ALL, "P"); break; + case it_sky: + R_Printf(PRINT_ALL, "Y"); + break; default: - R_Printf(PRINT_ALL, " "); + R_Printf(PRINT_ALL, "?"); break; } diff --git a/src/client/refresh/gl3/gl3_light.c b/src/client/refresh/gl3/gl3_light.c index 7ba55d1e..4f23c85f 100644 --- a/src/client/refresh/gl3/gl3_light.c +++ b/src/client/refresh/gl3/gl3_light.c @@ -345,7 +345,7 @@ GL3_LightPoint(vec3_t p, vec3_t color) vec3_t dist; float add; - if (!gl3_worldmodel->lightdata) + if (!gl3_worldmodel->lightdata || !currententity) // FIXME: the currententity check is new { color[0] = color[1] = color[2] = 1.0; return; diff --git a/src/client/refresh/gl3/gl3_main.c b/src/client/refresh/gl3/gl3_main.c index 763c4d39..fbfcab70 100644 --- a/src/client/refresh/gl3/gl3_main.c +++ b/src/client/refresh/gl3/gl3_main.c @@ -59,11 +59,18 @@ vec3_t vpn; vec3_t vright; vec3_t gl3_origin; +hmm_mat4 gl3_projectionMatrix; // eye cord -> clip coord +hmm_mat4 gl3_world_matrix; // the view matrix: world coord -> eye coord +// TODO: I don't know yet if we'll also need a model matrix (model coord -> world coord) here. + + int gl3_visframecount; /* bumped when going to a new PVS */ int gl3_framecount; /* used for dlight push checking */ int c_brush_polys, c_alias_polys; +static float v_blend[4]; /* final blending color */ + int gl3_viewcluster, gl3_viewcluster2, gl3_oldviewcluster, gl3_oldviewcluster2; cvar_t *gl_msaa_samples; @@ -91,6 +98,8 @@ cvar_t *gl_nolerp_list; cvar_t *gl_nobind; cvar_t *gl_lockpvs; cvar_t *gl_novis; +cvar_t *gl_speeds; +cvar_t *gl_finish; cvar_t *gl_cull; cvar_t *gl_zfix; @@ -101,6 +110,8 @@ cvar_t *gl_lightmap; cvar_t *gl_shadows; // TODO: do we really need 2 cvars for shadows here? cvar_t *gl_stencilshadow; +cvar_t *gl_dynamic; + cvar_t *gl3_debugcontext; void @@ -179,6 +190,10 @@ GL3_Register(void) gl_cull = ri.Cvar_Get("gl_cull", "1", 0); gl_lockpvs = ri.Cvar_Get("gl_lockpvs", "0", 0); gl_novis = ri.Cvar_Get("gl_novis", "0", 0); + gl_speeds = ri.Cvar_Get("gl_speeds", "0", 0); + gl_finish = ri.Cvar_Get("gl_finish", "0", CVAR_ARCHIVE); + + gl_dynamic = ri.Cvar_Get("gl_dynamic", "1", 0); #if 0 // TODO! @@ -190,7 +205,7 @@ GL3_Register(void) gl_drawworld = ri.Cvar_Get("gl_drawworld", "1", 0); //gl_novis = ri.Cvar_Get("gl_novis", "0", 0); //gl_lerpmodels = ri.Cvar_Get("gl_lerpmodels", "1", 0); NOTE: screw this, it looks horrible without - gl_speeds = ri.Cvar_Get("gl_speeds", "0", 0); + //gl_speeds = ri.Cvar_Get("gl_speeds", "0", 0); gl_lightlevel = ri.Cvar_Get("gl_lightlevel", "0", 0); gl_overbrightbits = ri.Cvar_Get("gl_overbrightbits", "0", CVAR_ARCHIVE); @@ -207,14 +222,14 @@ GL3_Register(void) //gl_lightmap = ri.Cvar_Get("gl_lightmap", "0", 0); //gl_shadows = ri.Cvar_Get("gl_shadows", "0", CVAR_ARCHIVE); //gl_stencilshadow = ri.Cvar_Get("gl_stencilshadow", "0", CVAR_ARCHIVE); - gl_dynamic = ri.Cvar_Get("gl_dynamic", "1", 0); + //gl_dynamic = ri.Cvar_Get("gl_dynamic", "1", 0); //gl_nobind = ri.Cvar_Get("gl_nobind", "0", 0); gl_round_down = ri.Cvar_Get("gl_round_down", "1", 0); gl_picmip = ri.Cvar_Get("gl_picmip", "0", 0); gl_showtris = ri.Cvar_Get("gl_showtris", "0", 0); //gl_ztrick = ri.Cvar_Get("gl_ztrick", "0", 0); NOTE: dump this. //gl_zfix = ri.Cvar_Get("gl_zfix", "0", 0); - gl_finish = ri.Cvar_Get("gl_finish", "0", CVAR_ARCHIVE); + //gl_finish = ri.Cvar_Get("gl_finish", "0", CVAR_ARCHIVE); gl_clear = ri.Cvar_Get("gl_clear", "0", 0); // gl_cull = ri.Cvar_Get("gl_cull", "1", 0); gl_polyblend = ri.Cvar_Get("gl_polyblend", "1", 0); @@ -606,6 +621,127 @@ GL3_DrawEntitiesOnList(void) #endif // 0 } +static int +SignbitsForPlane(cplane_t *out) +{ + int bits, j; + + /* for fast box on planeside test */ + bits = 0; + + for (j = 0; j < 3; j++) + { + if (out->normal[j] < 0) + { + bits |= 1 << j; + } + } + + return bits; +} + +static void +SetFrustum(void) +{ + int i; + + /* rotate VPN right by FOV_X/2 degrees */ + RotatePointAroundVector(frustum[0].normal, vup, vpn, + -(90 - gl3_newrefdef.fov_x / 2)); + /* rotate VPN left by FOV_X/2 degrees */ + RotatePointAroundVector(frustum[1].normal, + vup, vpn, 90 - gl3_newrefdef.fov_x / 2); + /* rotate VPN up by FOV_X/2 degrees */ + RotatePointAroundVector(frustum[2].normal, + vright, vpn, 90 - gl3_newrefdef.fov_y / 2); + /* rotate VPN down by FOV_X/2 degrees */ + RotatePointAroundVector(frustum[3].normal, vright, vpn, + -(90 - gl3_newrefdef.fov_y / 2)); + + for (i = 0; i < 4; i++) + { + frustum[i].type = PLANE_ANYZ; + frustum[i].dist = DotProduct(gl3_origin, frustum[i].normal); + frustum[i].signbits = SignbitsForPlane(&frustum[i]); + } +} + +static void +SetupFrame(void) +{ + int i; + mleaf_t *leaf; + + gl3_framecount++; + + /* build the transformation matrix for the given view angles */ + VectorCopy(gl3_newrefdef.vieworg, gl3_origin); + + AngleVectors(gl3_newrefdef.viewangles, vpn, vright, vup); + + /* current viewcluster */ + if (!(gl3_newrefdef.rdflags & RDF_NOWORLDMODEL)) + { + gl3_oldviewcluster = gl3_viewcluster; + gl3_oldviewcluster2 = gl3_viewcluster2; + leaf = GL3_Mod_PointInLeaf(gl3_origin, gl3_worldmodel); + gl3_viewcluster = gl3_viewcluster2 = leaf->cluster; + + /* check above and below so crossing solid water doesn't draw wrong */ + if (!leaf->contents) + { + /* look down a bit */ + vec3_t temp; + + VectorCopy(gl3_origin, temp); + temp[2] -= 16; + leaf = GL3_Mod_PointInLeaf(temp, gl3_worldmodel); + + if (!(leaf->contents & CONTENTS_SOLID) && + (leaf->cluster != gl3_viewcluster2)) + { + gl3_viewcluster2 = leaf->cluster; + } + } + else + { + /* look up a bit */ + vec3_t temp; + + VectorCopy(gl3_origin, temp); + temp[2] += 16; + leaf = GL3_Mod_PointInLeaf(temp, gl3_worldmodel); + + if (!(leaf->contents & CONTENTS_SOLID) && + (leaf->cluster != gl3_viewcluster2)) + { + gl3_viewcluster2 = leaf->cluster; + } + } + } + + for (i = 0; i < 4; i++) + { + v_blend[i] = gl3_newrefdef.blend[i]; + } + + c_brush_polys = 0; + c_alias_polys = 0; + + /* clear out the portion of the screen that the NOWORLDMODEL defines */ + if (gl3_newrefdef.rdflags & RDF_NOWORLDMODEL) + { + glEnable(GL_SCISSOR_TEST); + glClearColor(0.3, 0.3, 0.3, 1); + glScissor(gl3_newrefdef.x, + vid.height - gl3_newrefdef.height - gl3_newrefdef.y, + gl3_newrefdef.width, gl3_newrefdef.height); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClearColor(1, 0, 0.5, 0.5); + glDisable(GL_SCISSOR_TEST); + } +} + static void GL3_SetGL2D(void) { @@ -636,9 +772,9 @@ GL3_SetGL2D(void) hmm_mat4 transMatr = HMM_Orthographic(0, vid.width, vid.height, 0, -99999, 99999); glUseProgram(gl3state.si2Dcolor.shaderProgram); - glUniformMatrix4fv(gl3state.si2Dcolor.uniTransMatrix , 1, GL_FALSE, transMatr.Elements[0]); + glUniformMatrix4fv(gl3state.si2Dcolor.uniProjMatrix , 1, GL_FALSE, transMatr.Elements[0]); glUseProgram(gl3state.si2D.shaderProgram); - glUniformMatrix4fv(gl3state.si2D.uniTransMatrix , 1, GL_FALSE, transMatr.Elements[0]); + glUniformMatrix4fv(gl3state.si2D.uniProjMatrix , 1, GL_FALSE, transMatr.Elements[0]); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); @@ -646,6 +782,107 @@ GL3_SetGL2D(void) // glColor4f(1, 1, 1, 1); // FIXME: change to GL3 code! } +static void +SetupGL(void) +{ + int x, x2, y2, y, w, h; + + /* set up viewport */ + x = floor(gl3_newrefdef.x * vid.width / vid.width); + x2 = ceil((gl3_newrefdef.x + gl3_newrefdef.width) * vid.width / vid.width); + y = floor(vid.height - gl3_newrefdef.y * vid.height / vid.height); + y2 = ceil(vid.height - (gl3_newrefdef.y + gl3_newrefdef.height) * vid.height / vid.height); + + w = x2 - x; + h = y - y2; + +#if 0 // TODO: stereo stuff + qboolean drawing_left_eye = gl_state.camera_separation < 0; + qboolean stereo_split_tb = ((gl_state.stereo_mode == STEREO_SPLIT_VERTICAL) && gl_state.camera_separation); + qboolean stereo_split_lr = ((gl_state.stereo_mode == STEREO_SPLIT_HORIZONTAL) && gl_state.camera_separation); + + if(stereo_split_lr) { + w = w / 2; + x = drawing_left_eye ? (x / 2) : (x + vid.width) / 2; + } + + if(stereo_split_tb) { + h = h / 2; + y2 = drawing_left_eye ? (y2 + vid.height) / 2 : (y2 / 2); + } +#endif // 0 + + glViewport(x, y2, w, h); + + /* set up projection matrix (eye coordinates -> clip coordinates) */ + { + float screenaspect = (float)gl3_newrefdef.width / gl3_newrefdef.height; + float dist = (gl_farsee->value == 0) ? 4096.0f : 8192.0f; + gl3_projectionMatrix = HMM_Perspective(gl3_newrefdef.fov_y, screenaspect, 4, dist); + } + +#if 0 + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + R_MYgluPerspective(gl3_newrefdef.fov_y, screenaspect, 4, dist); +#endif // 0 + + glCullFace(GL_FRONT); + + /* set up view matrix (world coordinates -> eye coordinates) */ + { + hmm_vec3 trans = HMM_Vec3(-gl3_newrefdef.vieworg[0], -gl3_newrefdef.vieworg[1], -gl3_newrefdef.vieworg[2]); + // first put Z axis going up + hmm_mat4 viewMat = HMM_MultiplyMat4( HMM_Rotate(-90, HMM_Vec3(1, 0, 0)), HMM_Rotate(90, HMM_Vec3(0, 0, 1)) ); + // now rotate by view angles + viewMat = HMM_MultiplyMat4( viewMat, HMM_Rotate(-gl3_newrefdef.viewangles[2], HMM_Vec3(1, 0, 0)) ); + viewMat = HMM_MultiplyMat4( viewMat, HMM_Rotate(-gl3_newrefdef.viewangles[0], HMM_Vec3(0, 1, 0)) ); + viewMat = HMM_MultiplyMat4( viewMat, HMM_Rotate(-gl3_newrefdef.viewangles[1], HMM_Vec3(0, 0, 1)) ); + // .. and apply translation for current position + viewMat = HMM_MultiplyMat4( viewMat, HMM_Translate(trans) ); + + // TODO: maybe there is a better way to do this, maybe similar to HMM_LookAt() ? + + gl3_world_matrix = viewMat; + } + + // TODO: set matrices as uniforms in relevant shaders + glUseProgram(gl3state.si3D.shaderProgram); + glUniformMatrix4fv(gl3state.si3D.uniProjMatrix, 1, GL_FALSE, gl3_projectionMatrix.Elements[0]); + glUniformMatrix4fv(gl3state.si3D.uniModelViewMatrix, 1, GL_FALSE, gl3_world_matrix.Elements[0]); + +#if 0 + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glRotatef(-90, 1, 0, 0); /* put Z going up */ + glRotatef(90, 0, 0, 1); /* put Z going up */ + glRotatef(-gl3_newrefdef.viewangles[2], 1, 0, 0); + glRotatef(-gl3_newrefdef.viewangles[0], 0, 1, 0); + glRotatef(-gl3_newrefdef.viewangles[1], 0, 0, 1); + glTranslatef(-gl3_newrefdef.vieworg[0], -gl3_newrefdef.vieworg[1], + -gl3_newrefdef.vieworg[2]); + + glGetFloatv(GL_MODELVIEW_MATRIX, r_world_matrix); +#endif // 0 + + /* set drawing parms */ + if (gl_cull->value) + { + glEnable(GL_CULL_FACE); + } + else + { + glDisable(GL_CULL_FACE); + } + + STUB_ONCE("Should I do anything about disabling GL_BLEND and GL_ALPHA_TEST?"); + //glDisable(GL_BLEND); + //glDisable(GL_ALPHA_TEST); + glEnable(GL_DEPTH_TEST); +} + /* * gl3_newrefdef must be set before the first call */ @@ -771,35 +1008,36 @@ GL3_RenderView(refdef_t *fd) STUB_ONCE("TODO: Implement!"); -#if 0 // TODO !! - if (!r_worldmodel && !(gl3_newrefdef.rdflags & RDF_NOWORLDMODEL)) + + if (!gl3_worldmodel && !(gl3_newrefdef.rdflags & RDF_NOWORLDMODEL)) { ri.Sys_Error(ERR_DROP, "R_RenderView: NULL worldmodel"); } + if (gl_speeds->value) { c_brush_polys = 0; c_alias_polys = 0; } - R_PushDlights(); + GL3_PushDlights(); if (gl_finish->value) { glFinish(); } - R_SetupFrame(); + SetupFrame(); - R_SetFrustum(); + SetFrustum(); - R_SetupGL(); + SetupGL(); - R_MarkLeaves(); /* done here so we know if we're in water */ - - R_DrawWorld(); + GL3_MarkLeaves(); /* done here so we know if we're in water */ + GL3_DrawWorld(); +#if 0 // TODO !! R_DrawEntitiesOnList(); GL3_RenderDlights(); @@ -867,11 +1105,8 @@ GL3_SetLightLevel(void) return; } - STUB_ONCE("TODO: IMPLEMENT!"); - -#if 0 // TODO! /* save off light value for server to look at */ - R_LightPoint(gl3_newrefdef.vieworg, shadelight); + GL3_LightPoint(gl3_newrefdef.vieworg, shadelight); /* pick the greatest component, which should be the * same as the mono value returned by software */ @@ -897,7 +1132,6 @@ GL3_SetLightLevel(void) gl_lightlevel->value = 150 * shadelight[2]; } } -#endif // 0 } @@ -909,6 +1143,7 @@ GL3_RenderFrame(refdef_t *fd) GL3_SetGL2D(); } + static void GL3_Clear(void) { @@ -957,21 +1192,12 @@ GL3_Clear(void) } glClear(GL_COLOR_BUFFER_BIT); // TODO: I added this and the next line - keep? - glClearColor(0.5, 0.5, 1, 0.5); + glClearColor(0.5, 0.5, 1, 0.5); // FIXME: this would prolly look better with black. } void GL3_BeginFrame(float camera_separation) { - STUB_ONCE("TODO: Implement!"); - /* - glClearColor(0, 0, 0, 0); // FIXME: not sure this should stay - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(1, 0, 0.5, 0.5); - - GL3_SetGL2D(); - */ - /* change modes if necessary */ if (gl_mode->modified) { diff --git a/src/client/refresh/gl3/gl3_mesh.c b/src/client/refresh/gl3/gl3_mesh.c index a4a10de5..15d39aea 100644 --- a/src/client/refresh/gl3/gl3_mesh.c +++ b/src/client/refresh/gl3/gl3_mesh.c @@ -636,15 +636,15 @@ GL3_DrawAliasModel(entity_t *e) } - // Apply gl_overbrightbits to the mesh. If we don't do this they will appear slightly dimmer relative to walls. - if (gl_overbrightbits->value) - { - for (i = 0; i < 3; ++i) - { - shadelight[i] *= gl_overbrightbits->value; - } - } - + // Apply gl_overbrightbits to the mesh. If we don't do this they will appear slightly dimmer relative to walls. + if (gl_overbrightbits->value) + { + for (i = 0; i < 3; ++i) + { + shadelight[i] *= gl_overbrightbits->value; + } + } + /* ir goggles color override */ diff --git a/src/client/refresh/gl3/gl3_model.c b/src/client/refresh/gl3/gl3_model.c index d8191dcf..bac51282 100644 --- a/src/client/refresh/gl3/gl3_model.c +++ b/src/client/refresh/gl3/gl3_model.c @@ -39,6 +39,43 @@ static byte *mod_base; /* the inline * models from the current map are kept seperate */ gl3model_t mod_inline[MAX_MOD_KNOWN]; +mleaf_t * +GL3_Mod_PointInLeaf(vec3_t p, gl3model_t *model) +{ + mnode_t *node; + float d; + cplane_t *plane; + + if (!model || !model->nodes) + { + ri.Sys_Error(ERR_DROP, "Mod_PointInLeaf: bad model"); + } + + node = model->nodes; + + while (1) + { + if (node->contents != -1) + { + return (mleaf_t *)node; + } + + plane = node->plane; + d = DotProduct(p, plane->normal) - plane->dist; + + if (d > 0) + { + node = node->children[0]; + } + else + { + node = node->children[1]; + } + } + + return NULL; /* never reached */ +} + static byte * Mod_DecompressVis(byte *in, gl3model_t *model) { diff --git a/src/client/refresh/gl3/gl3_shaders.c b/src/client/refresh/gl3/gl3_shaders.c index 47dc4e0e..8575325f 100644 --- a/src/client/refresh/gl3/gl3_shaders.c +++ b/src/client/refresh/gl3/gl3_shaders.c @@ -220,6 +220,44 @@ static const char* fragmentSrc2Dcolor = MULTILINE_STRING(#version 150\n } ); +static const char* vertexSrc3D = MULTILINE_STRING(#version 150\n + in vec2 texCoord; + in vec3 position; + + uniform mat4 transProj; + uniform mat4 transModelView; + + out vec2 passTexCoord; + + void main() + { + gl_Position = transProj * transModelView * vec4(position, 1.0); + passTexCoord = texCoord; + } +); + +static const char* fragmentSrc3D = MULTILINE_STRING(#version 150\n + in vec2 passTexCoord; + + uniform sampler2D tex; + uniform float gamma; // this is 1.0/vid_gamma + uniform float intensity; + + out vec4 outColor; + + void main() + { + vec4 texel = texture(tex, passTexCoord); + + // TODO: something about GL_BLEND vs GL_ALPHATEST etc + + // apply gamma correction and intensity + texel.rgb *= intensity; + outColor.rgb = pow(texel.rgb, vec3(gamma)); + outColor.a = texel.a; // I think alpha shouldn't be modified by gamma and intensity + } +); + #undef MULTILINE_STRING static qboolean @@ -236,7 +274,7 @@ initShader2D(gl3ShaderInfo_t* shaderInfo, const char* vertSrc, const char* fragS } shaderInfo->attribColor = shaderInfo->attribPosition = shaderInfo->attribTexCoord = -1; - shaderInfo->uniTransMatrix = -1; + shaderInfo->uniProjMatrix = shaderInfo->uniModelViewMatrix = -1; shaderInfo->shaderProgram = 0; shaders2D[0] = CompileShader(GL_VERTEX_SHADER, vertSrc); @@ -282,7 +320,79 @@ initShader2D(gl3ShaderInfo_t* shaderInfo, const char* vertSrc, const char* fragS R_Printf(PRINT_ALL, "WARNING: Couldn't get 'trans' uniform in shader\n"); return false; } - shaderInfo->uniTransMatrix = i; + shaderInfo->uniProjMatrix = i; + + return true; +} + +static qboolean +initShader3D(gl3ShaderInfo_t* shaderInfo, const char* vertSrc, const char* fragSrc) +{ + GLuint shaders3D[2] = {0}; + GLint i = -1; + GLuint prog = 0; + + if(shaderInfo->shaderProgram != 0) + { + R_Printf(PRINT_ALL, "WARNING: calling initShader3D for gl3ShaderInfo_t that already has a shaderProgram!\n"); + glDeleteProgram(shaderInfo->shaderProgram); + } + + shaderInfo->attribColor = shaderInfo->attribPosition = shaderInfo->attribTexCoord = -1; + shaderInfo->uniProjMatrix = shaderInfo->uniModelViewMatrix = -1; + shaderInfo->shaderProgram = 0; + + shaders3D[0] = CompileShader(GL_VERTEX_SHADER, vertSrc); + if(shaders3D[0] == 0) return false; + + shaders3D[1] = CompileShader(GL_FRAGMENT_SHADER, fragSrc); + if(shaders3D[1] == 0) + { + glDeleteShader(shaders3D[0]); + return false; + } + + prog = CreateShaderProgram(2, shaders3D); + + // I think the shaders aren't needed anymore once they're linked into the program + glDeleteShader(shaders3D[0]); + glDeleteShader(shaders3D[1]); + + if(prog == 0) + { + return false; + } + + shaderInfo->shaderProgram = prog; + glUseProgram(prog); + + i = glGetAttribLocation(prog, "position"); + if( i == -1) + { + R_Printf(PRINT_ALL, "WARNING: Couldn't get 'position' attribute in shader\n"); + return false; + } + shaderInfo->attribPosition = i; + + // the following line will set it to -1 for the textured case, that's ok. + shaderInfo->attribColor = glGetAttribLocation(prog, "color"); + // the following line will set it to -1 for the color-only case, that's ok. + shaderInfo->attribTexCoord = glGetAttribLocation(prog, "texCoord"); + + i = glGetUniformLocation(prog, "transProj"); + if( i == -1) + { + R_Printf(PRINT_ALL, "WARNING: Couldn't get 'trans' uniform in shader\n"); + return false; + } + shaderInfo->uniProjMatrix = i; + i = glGetUniformLocation(prog, "transModelView"); + if( i == -1) + { + R_Printf(PRINT_ALL, "WARNING: Couldn't get 'trans' uniform in shader\n"); + return false; + } + shaderInfo->uniModelViewMatrix = i; return true; } @@ -299,6 +409,12 @@ qboolean GL3_InitShaders(void) R_Printf(PRINT_ALL, "WARNING: Failed to create shader program for color-only 2D rendering!\n"); return false; } + if(!initShader3D(&gl3state.si3D, vertexSrc3D, fragmentSrc3D)) + { + R_Printf(PRINT_ALL, "WARNING: Failed to create shader program for textured 3D rendering!\n"); + return false; + } + GL3_SetGammaAndIntensity(); @@ -314,6 +430,10 @@ void GL3_ShutdownShaders(void) if(gl3state.si2Dcolor.shaderProgram != 0) glDeleteProgram(gl3state.si2Dcolor.shaderProgram); memset(&gl3state.si2Dcolor, 0, sizeof(gl3ShaderInfo_t)); + + if(gl3state.si3D.shaderProgram != 0) + glDeleteProgram(gl3state.si3D.shaderProgram); + memset(&gl3state.si3D, 0, sizeof(gl3ShaderInfo_t)); } void GL3_SetGammaAndIntensity(void) @@ -321,9 +441,10 @@ void GL3_SetGammaAndIntensity(void) float gamma = 1.0f/vid_gamma->value; float intens = intensity->value; int i=0; - GLint progs[2] = { gl3state.si2D.shaderProgram, gl3state.si2Dcolor.shaderProgram }; + GLint progs[] = { gl3state.si2D.shaderProgram, gl3state.si2Dcolor.shaderProgram, + gl3state.si3D.shaderProgram }; - for(i=0; i<2; ++i) + for(i=0; iverts[0]; + // v: blocks of 7 floats: (X, Y, Z) (S1, T1), (S2, T2) + // apparently (S2, T2) is not used here? + STUB_ONCE("TODO: Implement!"); + + glUseProgram(gl3state.si3D.shaderProgram); // TODO: needed each time?! + + static GLuint vao = 0, vbo = 0; // TODO!! + if(vao == 0) // FIXME: DON'T DO THIS! + { + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); // TODO ?? + + glEnableVertexAttribArray(gl3state.si3D.attribPosition); + qglVertexAttribPointer(gl3state.si3D.attribPosition, 3, GL_FLOAT, GL_FALSE, VERTEXSIZE*sizeof(GLfloat), 0); + + glEnableVertexAttribArray(gl3state.si3D.attribTexCoord); + qglVertexAttribPointer(gl3state.si3D.attribTexCoord, 2, GL_FLOAT, GL_FALSE, VERTEXSIZE*sizeof(GLfloat), 3*sizeof(float)); + + } + + glUseProgram(gl3state.si3D.shaderProgram); + + glBindVertexArray(vao); + + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, VERTEXSIZE*sizeof(GLfloat)*p->numverts, v, GL_STREAM_DRAW); +/* + glEnableVertexAttribArray(gl3state.si3D.attribPosition); + qglVertexAttribPointer(gl3state.si3D.attribPosition, 3, GL_FLOAT, GL_FALSE, VERTEXSIZE*sizeof(GLfloat), 0); + + glEnableVertexAttribArray(gl3state.si3D.attribTexCoord); + qglVertexAttribPointer(gl3state.si3D.attribTexCoord, 2, GL_FLOAT, GL_FALSE, VERTEXSIZE*sizeof(GLfloat), 3*sizeof(GLfloat)); +*/ + + glDrawArrays(GL_TRIANGLE_FAN, 0, p->numverts); + #if 0 glEnableClientState( GL_VERTEX_ARRAY ); glEnableClientState( GL_TEXTURE_COORD_ARRAY ); @@ -475,12 +514,14 @@ RenderBrushPoly(msurface_t *fa) image = TextureAnimation(fa->texinfo); - STUB("TODO: implement!"); -#if 0 + + if (fa->flags & SURF_DRAWTURB) { GL3_Bind(image->texnum); + STUB("TODO: do something about R_TexEnv()!"); +#if 0 // TODO /* This is a hack ontop of a hack. Warping surfaces like those generated by R_EmitWaterPolys() don't have a lightmap. Original Quake II therefore negated the global intensity on those surfaces, because otherwise they @@ -505,9 +546,11 @@ RenderBrushPoly(msurface_t *fa) glColor4f(gl_state.inverse_intensity, gl_state.inverse_intensity, gl_state.inverse_intensity, 1.0f); } +#endif // 0 GL3_EmitWaterPolys(fa); - R_TexEnv(GL_REPLACE); + + //R_TexEnv(GL_REPLACE); TODO return; } @@ -515,16 +558,16 @@ RenderBrushPoly(msurface_t *fa) { GL3_Bind(image->texnum); - R_TexEnv(GL_REPLACE); + // R_TexEnv(GL_REPLACE); TODO! } if (fa->texinfo->flags & SURF_FLOWING) { - R_DrawGLFlowingPoly(fa); + GL3_DrawGLFlowingPoly(fa); } else { - R_DrawGLPoly(fa->polys); + GL3_DrawGLPoly(fa->polys); } /* check for lightmap modification */ @@ -553,6 +596,8 @@ RenderBrushPoly(msurface_t *fa) } } + STUB_ONCE("TODO: lightmap support (=> esp. LM textures)") +#if 0 if (is_dynamic) { if (((fa->styles[maps] >= 32) || @@ -568,7 +613,7 @@ RenderBrushPoly(msurface_t *fa) GL3_BuildLightMap(fa, (void *)temp, smax * 4); GL3_SetCacheState(fa); - GL3_Bind(gl_state.lightmap_textures + fa->lightmaptexturenum); + GL3_Bind(gl3state.lightmap_textures + fa->lightmaptexturenum); glTexSubImage2D(GL_TEXTURE_2D, 0, fa->light_s, fa->light_t, smax, tmax, GL_LIGHTMAP_FORMAT, GL_UNSIGNED_BYTE, temp); @@ -583,11 +628,12 @@ RenderBrushPoly(msurface_t *fa) } } else +#endif // 0 { fa->lightmapchain = gl3_lms.lightmap_surfaces[fa->lightmaptexturenum]; gl3_lms.lightmap_surfaces[fa->lightmaptexturenum] = fa; } -#endif // 0 + } /* @@ -686,7 +732,7 @@ DrawTextureChains(void) image->texturechain = NULL; } - STUB("TODO: do something about R_TexEnv()!"); + STUB_ONCE("TODO: do something about R_TexEnv()!"); // R_TexEnv(GL_REPLACE); } diff --git a/src/client/refresh/gl3/gl3_warp.c b/src/client/refresh/gl3/gl3_warp.c index b18e97b7..9d02d6f4 100644 --- a/src/client/refresh/gl3/gl3_warp.c +++ b/src/client/refresh/gl3/gl3_warp.c @@ -246,14 +246,17 @@ GL3_EmitWaterPolys(msurface_t *fa) scroll = 0; } + // TODO: do the scrolling/warping in shader + for (bp = fa->polys; bp; bp = bp->next) { p = bp; + int numverts = p->numverts; - GLfloat tex[2*p->numverts]; + GLfloat tex[2*numverts]; unsigned int index_tex = 0; - for ( i = 0, v = p->verts [ 0 ]; i < p->numverts; i++, v += VERTEXSIZE ) + for ( i = 0, v = p->verts [ 0 ]; i < numverts; i++, v += VERTEXSIZE ) { os = v [ 3 ]; ot = v [ 4 ]; @@ -634,18 +637,11 @@ MakeSkyVec(float s, float t, int axis) vec3_t v, b; int j, k; - if (gl_farsee->value == 0) - { - b[0] = s * 2300; - b[1] = t * 2300; - b[2] = 2300; - } - else - { - b[0] = s * 4096; - b[1] = t * 4096; - b[2] = 4096; - } + float dist = (gl_farsee->value == 0) ? 2300.0f : 4096.0f; // TODO: really dist? + + b[0] = s * dist; + b[1] = t * dist; + b[2] = dist; for (j = 0; j < 3; j++) { diff --git a/src/client/refresh/gl3/header/local.h b/src/client/refresh/gl3/header/local.h index 5ba8e4f3..1d55cd9b 100644 --- a/src/client/refresh/gl3/header/local.h +++ b/src/client/refresh/gl3/header/local.h @@ -100,7 +100,8 @@ typedef struct GLint attribTexCoord; GLint attribColor; - GLint uniTransMatrix; // TODO: could use 2 or 3 matrices? + GLint uniProjMatrix; // for 2D shaders this is the only one used + GLint uniModelViewMatrix; // TODO: or even pass as 2 matrices? // TODO: probably more uniforms, at least gamma and intensity @@ -133,6 +134,8 @@ typedef struct GLuint vbo2D; // this vbo is reused for all 2D drawing (HUD, movies, menu, console, ..) GLuint vao2D; // same for this vao + gl3ShaderInfo_t si3D; + } gl3state_t; extern gl3config_t gl3config; @@ -238,6 +241,7 @@ extern struct model_s * GL3_RegisterModel(char *name); extern void GL3_EndRegistration(void); extern void GL3_Mod_Modellist_f(void); extern byte* GL3_Mod_ClusterPVS(int cluster, gl3model_t *model); +extern mleaf_t* GL3_Mod_PointInLeaf(vec3_t p, gl3model_t *model); // gl3_draw.c extern void GL3_Draw_InitLocal(void); @@ -344,6 +348,8 @@ extern cvar_t *gl_modulate; extern cvar_t *gl_stencilshadow; +extern cvar_t *gl_dynamic; + extern cvar_t *gl3_debugcontext; #endif /* SRC_CLIENT_REFRESH_GL3_HEADER_LOCAL_H_ */ diff --git a/src/common/header/shared.h b/src/common/header/shared.h index 4f729672..b6813c0a 100644 --- a/src/common/header/shared.h +++ b/src/common/header/shared.h @@ -433,7 +433,7 @@ typedef struct cplane_s vec3_t normal; float dist; byte type; /* for fast side tests */ - byte signbits; /* signx + (signy<<1) + (signz<<1) */ + byte signbits; /* signx + (signy<<1) + (signz<<2) */ byte pad[2]; } cplane_t;