/* ============= R_DrawStretchImage ============= */ void R_DrawStretchImage (int32_t x, int32_t y, int32_t w, int32_t h, image_t *gl, float alpha) { const vec4_t color[4] = { {1.0, 1.0, 1.0, alpha}, {1.0, 1.0, 1.0, alpha}, {1.0, 1.0, 1.0, alpha}, {1.0, 1.0, 1.0, alpha} }; const vec3_t verts[4] = { {x, y, 0}, {x+w, y, 0}, {x+w, y+h, 0}, {x, y+h, 0} }; if (scrap_dirty) Scrap_Upload (); // Psychospaz's transparent console support if (gl->has_alpha || alpha < 1.0) { GL_Disable (GL_ALPHA_TEST); GL_TexEnv (GL_MODULATE); GL_Enable (GL_BLEND); GL_DepthMask (false); } GL_Bind (gl->texnum); rb_vertex = rb_index = 0; memcpy(&indexArray[rb_index], indices, sizeof(indices)); rb_index = 6; Vector2Set(texCoordArray[0][0], gl->sl, gl->tl); Vector2Set(texCoordArray[0][1], gl->sh, gl->tl); Vector2Set(texCoordArray[0][2], gl->sh, gl->th); Vector2Set(texCoordArray[0][3], gl->sl, gl->th); memcpy(vertexArray, verts, sizeof(vec3_t) * 4); memcpy(colorArray[rb_vertex], color, sizeof(vec4_t) * 4); rb_vertex = 4; RB_RenderMeshGeneric (false); // Psychospaz's transparent console support if (gl->has_alpha || alpha < 1.0) { GL_DepthMask (true); GL_TexEnv (GL_REPLACE); GL_Disable (GL_BLEND); GL_Enable (GL_ALPHA_TEST); } }
/* ============= R_DrawStretchImage ============= */ void R_DrawStretchImage (int32_t x, int32_t y, int32_t w, int32_t h, image_t *gl, float alpha) { int32_t i; vec2_t texCoord[4], verts[4]; if (scrap_dirty) Scrap_Upload (); // Psychospaz's transparent console support if (gl->has_alpha || alpha < 1.0) { GL_Disable (GL_ALPHA_TEST); GL_TexEnv (GL_MODULATE); GL_Enable (GL_BLEND); GL_DepthMask (false); } GL_Bind (gl->texnum); Vector2Set(texCoord[0], gl->sl, gl->tl); Vector2Set(texCoord[1], gl->sh, gl->tl); Vector2Set(texCoord[2], gl->sh, gl->th); Vector2Set(texCoord[3], gl->sl, gl->th); Vector2Set(verts[0], x, y); Vector2Set(verts[1], x+w, y); Vector2Set(verts[2], x+w, y+h); Vector2Set(verts[3], x, y+h); rb_vertex = rb_index = 0; indexArray[rb_index++] = rb_vertex+0; indexArray[rb_index++] = rb_vertex+1; indexArray[rb_index++] = rb_vertex+2; indexArray[rb_index++] = rb_vertex+0; indexArray[rb_index++] = rb_vertex+2; indexArray[rb_index++] = rb_vertex+3; for (i=0; i<4; i++) { VA_SetElem2(texCoordArray[0][rb_vertex], texCoord[i][0], texCoord[i][1]); VA_SetElem3(vertexArray[rb_vertex], verts[i][0], verts[i][1], 0); VA_SetElem4(colorArray[rb_vertex], 1.0, 1.0, 1.0, alpha); rb_vertex++; } RB_RenderMeshGeneric (false); // Psychospaz's transparent console support if (gl->has_alpha || alpha < 1.0) { GL_DepthMask (true); GL_TexEnv (GL_REPLACE); GL_Disable (GL_BLEND); GL_Enable (GL_ALPHA_TEST); } }
/* ====================== R_DrawFill Fills a box of pixels with a 24-bit color w/ alpha =========================== */ void R_DrawFill (int32_t x, int32_t y, int32_t w, int32_t h, int32_t red, int32_t green, int32_t blue, int32_t alpha) { const vec_t r = min(red, 255)*DIV255; const vec_t g = min(green, 255)*DIV255; const vec_t b = min(blue, 255)*DIV255; const vec_t a = max(min(alpha, 255), 1)*DIV255; const vec4_t color[4] = { {r, g, b, a}, {r, g, b, a}, {r, g, b, a}, {r, g, b, a} }; const vec3_t verts[4] = { {x, y, 0}, {x+w, y, 0}, {x+w, y+h, 0}, {x, y+h, 0} }; // GL_DisableTexture (0); GL_Disable (GL_ALPHA_TEST); GL_TexEnv (GL_MODULATE); GL_Enable (GL_BLEND); GL_DepthMask (false); GL_Bind (glMedia.whitetexture->texnum); rb_vertex = rb_index = 0; memcpy(&indexArray[rb_index], indices, sizeof(indices)); rb_index = 6; memcpy(vertexArray, verts, sizeof(vec3_t) * 4); memcpy(colorArray, color, sizeof(vec4_t) * 4); rb_vertex = 4; RB_RenderMeshGeneric (false); GL_DepthMask (true); GL_Disable (GL_BLEND); GL_TexEnv (GL_REPLACE); GL_Enable (GL_ALPHA_TEST); // GL_EnableTexture (0); }
/* ================= R_SetBlendModeOn ================= */ void R_SetBlendModeOn (image_t *skin) { GL_TexEnv( GL_MODULATE ); if (skin) GL_Bind(skin->texnum); GL_ShadeModel (GL_SMOOTH); if (currententity->flags & RF_TRANSLUCENT) { GL_DepthMask (false); if (currententity->flags & RF_TRANS_ADDITIVE) { GL_BlendFunc (GL_SRC_ALPHA, GL_ONE); glColor4ub(255, 255, 255, 255); GL_ShadeModel (GL_FLAT); } else GL_BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_Enable (GL_BLEND); } }
void Pass::finalize() { GL_SwitchTexUnit(GL_TEXTURE0_ARB); //GL_TextureEnvMode(GL_REPLACE); if(viewer) GL_PopCamera(); //GL_Disable(GL_SCISSOR_TEST); GL_DepthMask(GL_FALSE); GL_Disable(GL_DEPTH_TEST); GL_Disable(GL_FOG); GL_Disable(GL_ALPHA_TEST); if(gfx_postProcessing.integer) { target->unmakeTarget(); } else { glScreen->unmakeTarget(); } GL_Disable(GL_LIGHTING); for(lightCount-=1;lightCount>=0;lightCount--) GL_Disable(GL_LIGHT0+lightCount); Cvar_SetVarValue(&gfx_GLSLPass, 0); glPopAttrib(); //if(gfx_postProcessing.integer && gfx_GLSLQuality.integer>1) //glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboTargetBufferId); #ifdef DEBUG GLSL_catchLastError("Pass::finalize(): "); #endif }
/* ================= R_SetBlendModeOff ================= */ void R_SetBlendModeOff (void) { if ( currententity->flags & RF_TRANSLUCENT ) { GL_DepthMask (true); GL_Disable(GL_BLEND); GL_BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } }
/* ====================== R_DrawFill Fills a box of pixels with a 24-bit color w/ alpha =========================== */ void R_DrawFill (int32_t x, int32_t y, int32_t w, int32_t h, int32_t red, int32_t green, int32_t blue, int32_t alpha) { int32_t i; vec2_t verts[4]; red = min(red, 255); green = min(green, 255); blue = min(blue, 255); alpha = max(min(alpha, 255), 1); // GL_DisableTexture (0); GL_Disable (GL_ALPHA_TEST); GL_TexEnv (GL_MODULATE); GL_Enable (GL_BLEND); GL_DepthMask (false); GL_Bind (glMedia.whitetexture->texnum); Vector2Set(verts[0], x, y); Vector2Set(verts[1], x+w, y); Vector2Set(verts[2], x+w, y+h); Vector2Set(verts[3], x, y+h); rb_vertex = rb_index = 0; indexArray[rb_index++] = rb_vertex+0; indexArray[rb_index++] = rb_vertex+1; indexArray[rb_index++] = rb_vertex+2; indexArray[rb_index++] = rb_vertex+0; indexArray[rb_index++] = rb_vertex+2; indexArray[rb_index++] = rb_vertex+3; for (i=0; i<4; i++) { VA_SetElem3(vertexArray[rb_vertex], verts[i][0], verts[i][1], 0); VA_SetElem4(colorArray[rb_vertex], red*DIV255, green*DIV255, blue*DIV255, alpha*DIV255); rb_vertex++; } RB_RenderMeshGeneric (false); GL_DepthMask (true); GL_Disable (GL_BLEND); GL_TexEnv (GL_REPLACE); GL_Enable (GL_ALPHA_TEST); // GL_EnableTexture (0); }
/* ================ R_FlushChars ================ */ void R_FlushChars (void) { if (rb_vertex == 0 || rb_index == 0) // nothing to flush return; GL_Disable (GL_ALPHA_TEST); GL_TexEnv (GL_MODULATE); GL_Enable (GL_BLEND); GL_DepthMask (false); GL_Bind(draw_chars->texnum); RB_RenderMeshGeneric (false); char_count = 0; GL_DepthMask (true); GL_Disable (GL_BLEND); GL_TexEnv (GL_REPLACE); GL_Enable (GL_ALPHA_TEST); }
static void R_DrawExplosion_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) { int surfacelistindex = 0; const int numtriangles = EXPLOSIONTRIS, numverts = EXPLOSIONVERTS; GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); GL_DepthMask(false); GL_DepthRange(0, 1); GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset); GL_DepthTest(true); GL_CullFace(r_refdef.view.cullface_back); R_EntityMatrix(&identitymatrix); // R_Mesh_ResetTextureState(); R_SetupShader_Generic(explosiontexture, NULL, GL_MODULATE, 1, false, false, false); for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++) { const explosion_t *e = explosion + surfacelist[surfacelistindex]; // FIXME: this can't properly handle r_refdef.view.colorscale > 1 GL_Color(e->alpha * r_refdef.view.colorscale, e->alpha * r_refdef.view.colorscale, e->alpha * r_refdef.view.colorscale, 1); R_Mesh_PrepareVertices_Generic_Arrays(numverts, e->vert[0], NULL, explosiontexcoord2f[0]); R_Mesh_Draw(0, numverts, 0, numtriangles, NULL, NULL, 0, explosiontris[0], NULL, 0); } }
/* ================= R_DrawSpriteModel ================= */ void R_DrawSpriteModel (entity_t *e) { float alpha = 1.0f; vec2_t texCoord[4]; vec3_t point[4]; dsprite_t *psprite; dsprframe_t *frame; float *up, *right; int i; // don't even bother culling, because it's just a single // polygon without a surface cache psprite = (dsprite_t *)currentmodel->extradata; e->frame %= psprite->numframes; frame = &psprite->frames[e->frame]; if (!frame) return; c_alias_polys += 2; // normal sprite up = vup; right = vright; if (e->flags & RF_TRANSLUCENT) alpha = e->alpha; R_SetVertexRGBScale (true); // Psychospaz's additive transparency if ((currententity->flags & RF_TRANS_ADDITIVE) && (alpha != 1.0f)) { GL_Enable (GL_BLEND); GL_TexEnv (GL_MODULATE); GL_Disable (GL_ALPHA_TEST); GL_DepthMask (false); GL_BlendFunc (GL_SRC_ALPHA, GL_ONE); } else { GL_TexEnv (GL_MODULATE); if (alpha == 1.0f) { GL_Enable (GL_ALPHA_TEST); GL_DepthMask (true); } else { GL_BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_DepthMask (false); GL_Enable (GL_BLEND); GL_Disable (GL_ALPHA_TEST); } } GL_Bind(currentmodel->skins[0][e->frame]->texnum); Vector2Set(texCoord[0], 0, 1); Vector2Set(texCoord[1], 0, 0); Vector2Set(texCoord[2], 1, 0); Vector2Set(texCoord[3], 1, 1); VectorMA (e->origin, -frame->origin_y, up, point[0]); VectorMA (point[0], -frame->origin_x, right, point[0]); VectorMA (e->origin, frame->height - frame->origin_y, up, point[1]); VectorMA (point[1], -frame->origin_x, right, point[1]); VectorMA (e->origin, frame->height - frame->origin_y, up, point[2]); VectorMA (point[2], frame->width - frame->origin_x, right, point[2]); VectorMA (e->origin, -frame->origin_y, up, point[3]); VectorMA (point[3], frame->width - frame->origin_x, right, point[3]); rb_vertex = rb_index = 0; indexArray[rb_index++] = rb_vertex+0; indexArray[rb_index++] = rb_vertex+1; indexArray[rb_index++] = rb_vertex+2; indexArray[rb_index++] = rb_vertex+0; indexArray[rb_index++] = rb_vertex+2; indexArray[rb_index++] = rb_vertex+3; for (i=0; i<4; i++) { VA_SetElem2(texCoordArray[0][rb_vertex], texCoord[i][0], texCoord[i][1]); VA_SetElem3(vertexArray[rb_vertex], point[i][0], point[i][1], point[i][2]); VA_SetElem4(colorArray[rb_vertex], 1.0f, 1.0f, 1.0f, alpha); rb_vertex++; } RB_DrawArrays (); GL_BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_TexEnv (GL_REPLACE); GL_DepthMask (true); GL_Disable (GL_ALPHA_TEST); GL_Disable (GL_BLEND); R_SetVertexRGBScale (false); RB_DrawMeshTris (); rb_vertex = rb_index = 0; }
void Pass::setup(GLRenderer *) { vec4_t ambient = { sunLight.ambient[0] * 0.8, sunLight.ambient[1] * 0.8, sunLight.ambient[2] * 0.95, 1 }; GLSL_reset(); shader = NULL; lightCount = 0; glPushAttrib(attrib_bits); //GL_Enable(GL_SCISSOR_TEST); GL_SwitchTexUnit(GL_TEXTURE0_ARB); //defaults for pass GL_Enable(GL_BLEND); GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); GL_Enable(GL_CULL_FACE); GL_Enable(GL_ALPHA_TEST); //glAlphaFunc(GL_GREATER, 0.0); GL_ResetColor(); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); //enable the lights for this pass by default if(allowLighting()) { if(gfx_GLSLQuality.integer <= 1) M_MultVec3(ambient, 1.5, ambient); GL_Enable(GL_LIGHTING); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, true); glShadeModel(GL_SMOOTH); } //GL_Enable(GL_NORMALIZE); //framebuffer if(gfx_postProcessing.integer) { if(!target) target = glScreen; target->makeTarget(); } else { glScreen->makeTarget(); } //depth GL_Enable(GL_DEPTH_TEST); GL_DepthMask(depthMask); GL_DepthFunc(depthFunc); if(preclearDepth) { glClearDepth(1.0); glClear(GL_DEPTH_BUFFER_BIT); } if(viewer) { vec4_t rect; //FIXME: probably should be a data member for configurable pass "windows" SET_VEC4(rect, 0, 0, viewer->width, viewer->height); Scene_SetFrustum(viewer, rect); Scene_BuildOccluderList(viewer); if(gfx_debugCamera.integer>0) { camera_t debugcam; vec3_t back; M_MultVec3(viewer->viewaxis[AXIS_FORWARD], -gfx_debugCamera.integer, back); memcpy(&debugcam, viewer, sizeof(camera_t)); M_AddVec3(debugcam.origin, back, debugcam.origin); GL_PushCamera(&debugcam); } else { GL_PushCamera(viewer); //scene_cam = viewer; } //fog if (viewer->fog_far > 0 && gfx_fog.integer) { vec4_t fog_color = { gfx_fogr.value, gfx_fogg.value, gfx_fogb.value, 0 }; GL_Enable(GL_FOG); if(gfx_nicerFog.integer) { glFogf(GL_FOG_MODE, GL_EXP2); glFogf(GL_FOG_DENSITY, 1.5 / viewer->fog_far); // Notaus: old value was fixed at 0.00072 and not appropriate for very foggy maps } else { glFogf(GL_FOG_MODE, GL_LINEAR); } glHint(GL_FOG_HINT, GL_NICEST); if (viewer->fog_near > 0 && viewer->fog_far >= viewer->fog_near) { glFogf(GL_FOG_START, viewer->fog_near); glFogf(GL_FOG_END, viewer->fog_far); fog_near = viewer->fog_near; fog_far = viewer->fog_far; } else { glFogf(GL_FOG_START, gfx_fog_near.value); glFogf(GL_FOG_END, gfx_fog_far.value); fog_near = gfx_fog_near.value; fog_far = gfx_fog_far.value; } glFogfv(GL_FOG_COLOR, fog_color); } else if (gfx_fog.integer==0) { GL_Enable(GL_FOG); glFogf(GL_FOG_START, 90000); glFogf(GL_FOG_END, 100000); //shaders make it better just to set this ridiculously far out } else { GL_Disable(GL_FOG); } } else { GL_Disable(GL_FOG); } if(gfx_GLSL.integer) Cvar_SetVarValue(&gfx_GLSLPass, 1); else GL_TexModulate(2.0); #ifdef DEBUG GLSL_catchLastError("Pass::setup()"); #endif }
/* ================== GL_Setup3D TODO: time is messed up ================== */ void GL_Setup3D (int time){ double clipPlane[4]; QGL_LogPrintf("---------- RB_Setup3D ----------\n"); backEnd.projection2D = false; backEnd.time = time; backEnd.floatTime = MS2SEC(Sys_Milliseconds()); backEnd.viewport.x = backEnd.viewParms.viewport.x; backEnd.viewport.y = backEnd.viewParms.viewport.y; backEnd.viewport.width = backEnd.viewParms.viewport.width; backEnd.viewport.height = backEnd.viewParms.viewport.height; backEnd.scissor.x = backEnd.viewParms.scissor.x; backEnd.scissor.y = backEnd.viewParms.scissor.y; backEnd.scissor.width = backEnd.viewParms.scissor.width; backEnd.scissor.height = backEnd.viewParms.scissor.height; backEnd.coordScale[0] = 1.0f / backEnd.viewport.width; backEnd.coordScale[1] = 1.0f / backEnd.viewport.height; backEnd.coordBias[0] = -backEnd.viewport.x * backEnd.coordScale[0]; backEnd.coordBias[1] = -backEnd.viewport.y * backEnd.coordScale[1]; backEnd.depthFilling = false; backEnd.debugRendering = false; backEnd.currentColorCaptured = SORT_BAD; backEnd.currentDepthCaptured = false; // Set up the viewport GL_Viewport(backEnd.viewport); // Set up the scissor GL_Scissor(backEnd.viewport); // Set up the depth bounds if (glConfig.depthBoundsTestAvailable) GL_DepthBounds(0.0f, 1.0f); // Set the projection matrix GL_LoadMatrix(GL_PROJECTION, backEnd.viewParms.projectionMatrix); // Set the modelview matrix GL_LoadIdentity(GL_MODELVIEW); // Set the GL state GL_PolygonMode(GL_FILL); GL_Disable(GL_CULL_FACE); GL_Disable(GL_POLYGON_OFFSET_FILL); GL_Disable(GL_BLEND); GL_Disable(GL_ALPHA_TEST); GL_Disable(GL_DEPTH_TEST); GL_Disable(GL_STENCIL_TEST); GL_DepthRange(0.0f, 1.0f); GL_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); GL_DepthMask(GL_TRUE); GL_StencilMask(255); // Enable the clip plane if needed if (backEnd.viewParms.viewType != VIEW_MIRROR) qglDisable(GL_CLIP_PLANE0); else { clipPlane[0] = -DotProduct(backEnd.viewParms.axis[1], backEnd.viewParms.clipPlane.normal); clipPlane[1] = DotProduct(backEnd.viewParms.axis[2], backEnd.viewParms.clipPlane.normal); clipPlane[2] = -DotProduct(backEnd.viewParms.axis[0], backEnd.viewParms.clipPlane.normal); clipPlane[3] = DotProduct(backEnd.viewParms.origin, backEnd.viewParms.clipPlane.normal) - backEnd.viewParms.clipPlane.dist; qglEnable(GL_CLIP_PLANE0); qglClipPlane(GL_CLIP_PLANE0, clipPlane); } // Enable multisampling if available if (glConfig.multiSamples > 1) qglEnable(GL_MULTISAMPLE); // Clear the buffers qglClearColor(0.0f, 0.0f, 0.0f, 1.0f); qglClearDepth(1.0f); qglClearStencil(0); if (backEnd.viewParms.primaryView) qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); else qglClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Check for errors if (!r_ignoreGLErrors->integerValue) GL_CheckForErrors(); QGL_LogPrintf("--------------------\n"); }
/* ================== GL_Setup2D TODO: time is messed up ================== */ void GL_Setup2D (int time){ mat4_t projectionMatrix = {2.0f / backEnd.cropWidth, 0.0f, 0.0f, 0.0f, 0.0f, -2.0f / backEnd.cropHeight, 0.0f, 0.0f, 0.0f, 0.0f, -2.0f, 0.0f, -1.0f, 1.0f, -1.0f, 1.0f}; QGL_LogPrintf("---------- RB_Setup2D ----------\n"); backEnd.projection2D = true; backEnd.time = time; backEnd.floatTime = MS2SEC(Sys_Milliseconds()); backEnd.viewport.x = 0; backEnd.viewport.y = 0; backEnd.viewport.width = backEnd.cropWidth; backEnd.viewport.height = backEnd.cropHeight; backEnd.scissor.x = 0; backEnd.scissor.y = 0; backEnd.scissor.width = backEnd.cropWidth; backEnd.scissor.height = backEnd.cropHeight; backEnd.coordScale[0] = 1.0f / backEnd.viewport.width; backEnd.coordScale[1] = 1.0f / backEnd.viewport.height; backEnd.coordBias[0] = -backEnd.viewport.x * backEnd.coordScale[0]; backEnd.coordBias[1] = -backEnd.viewport.y * backEnd.coordScale[1]; backEnd.depthFilling = false; backEnd.debugRendering = false; backEnd.currentColorCaptured = SORT_BAD; backEnd.currentDepthCaptured = false; // Set up the viewport GL_Viewport(backEnd.viewport); // Set up the scissor GL_Scissor(backEnd.viewport); // Set up the depth bounds if (glConfig.depthBoundsTestAvailable) GL_DepthBounds(0.0f, 1.0f); // Set the projection matrix GL_LoadMatrix(GL_PROJECTION, projectionMatrix); // Set the modelview matrix GL_LoadIdentity(GL_MODELVIEW); // Set the GL state GL_PolygonMode(GL_FILL); GL_Disable(GL_CULL_FACE); GL_Disable(GL_POLYGON_OFFSET_FILL); GL_Disable(GL_BLEND); GL_Disable(GL_ALPHA_TEST); GL_Disable(GL_DEPTH_TEST); GL_Disable(GL_STENCIL_TEST); GL_DepthRange(0.0f, 1.0f); GL_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); GL_DepthMask(GL_FALSE); GL_StencilMask(255); // Disable the clip plane qglDisable(GL_CLIP_PLANE0); // Disable multisampling if available if (glConfig.multiSamples > 1) qglDisable(GL_MULTISAMPLE); // Check for errors if (!r_ignoreGLErrors->integerValue) GL_CheckForErrors(); QGL_LogPrintf("--------------------\n"); }
void R_DrawCameraEffect (void) { image_t *image[2]; int32_t x, y, w, h, i, j; float texparms[2][4]; vec2_t texCoord[4]; vec3_t verts[4]; renderparms_t cameraParms; image[0] = R_DrawFindPic ("/gfx/2d/screenstatic.tga"); image[1] = R_DrawFindPic ("/gfx/2d/scanlines.tga"); if (!image[0] || !image[1]) return; x = y = 0; w = vid.width; h = vid.height; GL_Disable (GL_ALPHA_TEST); GL_TexEnv (GL_MODULATE); GL_Enable (GL_BLEND); GL_BlendFunc (GL_DST_COLOR, GL_SRC_COLOR); GL_DepthMask (false); VectorSet(verts[0], x, y, 0); VectorSet(verts[1], x+w, y, 0); VectorSet(verts[2], x+w, y+h, 0); VectorSet(verts[3], x, y+h, 0); Vector4Set(texparms[0], 2, 2, -30, 10); Vector4Set(texparms[1], 1, 10, 0, 0); rb_vertex = rb_index = 0; indexArray[rb_index++] = rb_vertex+0; indexArray[rb_index++] = rb_vertex+1; indexArray[rb_index++] = rb_vertex+2; indexArray[rb_index++] = rb_vertex+0; indexArray[rb_index++] = rb_vertex+2; indexArray[rb_index++] = rb_vertex+3; rb_vertex = 4; for (i=0; i<2; i++) { GL_Bind (image[i]->texnum); Vector2Set(texCoord[0], x/image[i]->width, y/image[i]->height); Vector2Set(texCoord[1], (x+w)/image[i]->width, y/image[i]->height); Vector2Set(texCoord[2], (x+w)/image[i]->width, (y+h)/image[i]->height); Vector2Set(texCoord[3], x/image[i]->width, (y+h)/image[i]->height); Mod_SetRenderParmsDefaults (&cameraParms); cameraParms.scale_x = texparms[i][0]; cameraParms.scale_y = texparms[i][1]; cameraParms.scroll_x = texparms[i][2]; cameraParms.scroll_y = texparms[i][3]; RB_ModifyTextureCoords (&texCoord[0][0], &verts[0][0], 4, cameraParms); for (j=0; j<4; j++) { VA_SetElem2(texCoordArray[0][j], texCoord[j][0], texCoord[j][1]); VA_SetElem3(vertexArray[j], verts[j][0], verts[j][1], verts[j][2]); VA_SetElem4(colorArray[j], 1, 1, 1, 1); } RB_DrawArrays (); } rb_vertex = rb_index = 0; GL_DepthMask (true); GL_BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_Disable (GL_BLEND); GL_TexEnv (GL_REPLACE); GL_Enable (GL_ALPHA_TEST); }
/* ============= R_DrawScaledImage Psychospaz's code for drawing stretched crosshairs ============= */ void R_DrawScaledImage (int32_t x, int32_t y, float scale, float alpha, image_t *gl) { float xoff, yoff; float scale_x, scale_y; int32_t i; vec2_t texCoord[4], verts[4]; if (scrap_dirty) Scrap_Upload (); // add alpha support if (gl->has_alpha || alpha < 1.0) { GL_Disable (GL_ALPHA_TEST); GL_TexEnv (GL_MODULATE); GL_Enable (GL_BLEND); GL_DepthMask (false); } GL_Bind (gl->texnum); scale_x = scale_y = scale; scale_x *= gl->replace_scale_w; // scale down if replacing a pcx image scale_y *= gl->replace_scale_h; // scale down if replacing a pcx image Vector2Set(texCoord[0], gl->sl, gl->tl); Vector2Set(texCoord[1], gl->sh, gl->tl); Vector2Set(texCoord[2], gl->sh, gl->th); Vector2Set(texCoord[3], gl->sl, gl->th); xoff = gl->width*scale_x-gl->width; yoff = gl->height*scale_y-gl->height; Vector2Set(verts[0], x, y); Vector2Set(verts[1], x+gl->width+xoff, y); Vector2Set(verts[2], x+gl->width+xoff, y+gl->height+yoff); Vector2Set(verts[3], x, y+gl->height+yoff); rb_vertex = rb_index = 0; indexArray[rb_index++] = rb_vertex+0; indexArray[rb_index++] = rb_vertex+1; indexArray[rb_index++] = rb_vertex+2; indexArray[rb_index++] = rb_vertex+0; indexArray[rb_index++] = rb_vertex+2; indexArray[rb_index++] = rb_vertex+3; for (i=0; i<4; i++) { VA_SetElem2(texCoordArray[0][rb_vertex], texCoord[i][0], texCoord[i][1]); VA_SetElem3(vertexArray[rb_vertex], verts[i][0], verts[i][1], 0); VA_SetElem4(colorArray[rb_vertex], 1.0, 1.0, 1.0, alpha); rb_vertex++; } RB_RenderMeshGeneric (false); if (gl->has_alpha || alpha < 1.0) { GL_DepthMask (true); GL_TexEnv (GL_REPLACE); GL_Disable (GL_BLEND); GL_Enable (GL_ALPHA_TEST); // add alpha support } }
/* ============= R_DrawScaledImage Psychospaz's code for drawing stretched crosshairs ============= */ void R_DrawScaledImage (int32_t x, int32_t y, float scale, float alpha, image_t *gl) { float xoff, yoff; float scale_x, scale_y; const vec4_t color[4] = { {1.0, 1.0, 1.0, alpha}, {1.0, 1.0, 1.0, alpha}, {1.0, 1.0, 1.0, alpha}, {1.0, 1.0, 1.0, alpha} }; if (scrap_dirty) Scrap_Upload (); // add alpha support if (gl->has_alpha || alpha < 1.0) { GL_Disable (GL_ALPHA_TEST); GL_TexEnv (GL_MODULATE); GL_Enable (GL_BLEND); GL_DepthMask (false); } GL_Bind (gl->texnum); scale_x = scale_y = scale; scale_x *= gl->replace_scale_w; // scale down if replacing a pcx image scale_y *= gl->replace_scale_h; // scale down if replacing a pcx image xoff = gl->width*scale_x-gl->width; yoff = gl->height*scale_y-gl->height; rb_vertex = rb_index = 0; memcpy(indexArray, indices, sizeof(indices)); rb_index = 6; VA_SetElem2(texCoordArray[0][0], gl->sl, gl->tl); VA_SetElem2(texCoordArray[0][1], gl->sh, gl->tl); VA_SetElem2(texCoordArray[0][2], gl->sh, gl->th); VA_SetElem2(texCoordArray[0][3], gl->sl, gl->th); VA_SetElem3(vertexArray[0], x, y, 0); VA_SetElem3(vertexArray[1], x+gl->width+xoff, y, 0); VA_SetElem3(vertexArray[2], x+gl->width+xoff, y+gl->height+yoff, 0); VA_SetElem3(vertexArray[3], x, y+gl->height+yoff, 0); memcpy(colorArray, color, sizeof(vec4_t) * 4); rb_vertex = 4; RB_RenderMeshGeneric (false); if (gl->has_alpha || alpha < 1.0) { GL_DepthMask (true); GL_TexEnv (GL_REPLACE); GL_Disable (GL_BLEND); GL_Enable (GL_ALPHA_TEST); // add alpha support } }
/** * @brief This routine is responsible for setting the most commonly changed state in Q3. */ void GL_State(uint32_t stateBits) { uint32_t diff = stateBits ^ glState.glStateBits; if (!diff) { return; } // check depthFunc bits if (diff & GLS_DEPTHFUNC_BITS) { switch (stateBits & GLS_DEPTHFUNC_BITS) { default: GL_DepthFunc(GL_LEQUAL); break; case GLS_DEPTHFUNC_LESS: GL_DepthFunc(GL_LESS); break; case GLS_DEPTHFUNC_EQUAL: GL_DepthFunc(GL_EQUAL); break; } } // check blend bits if (diff & (GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS)) { GLenum srcFactor, dstFactor; if (stateBits & (GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS)) { switch (stateBits & GLS_SRCBLEND_BITS) { case GLS_SRCBLEND_ZERO: srcFactor = GL_ZERO; break; case GLS_SRCBLEND_ONE: srcFactor = GL_ONE; break; case GLS_SRCBLEND_DST_COLOR: srcFactor = GL_DST_COLOR; break; case GLS_SRCBLEND_ONE_MINUS_DST_COLOR: srcFactor = GL_ONE_MINUS_DST_COLOR; break; case GLS_SRCBLEND_SRC_ALPHA: srcFactor = GL_SRC_ALPHA; break; case GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA: srcFactor = GL_ONE_MINUS_SRC_ALPHA; break; case GLS_SRCBLEND_DST_ALPHA: srcFactor = GL_DST_ALPHA; break; case GLS_SRCBLEND_ONE_MINUS_DST_ALPHA: srcFactor = GL_ONE_MINUS_DST_ALPHA; break; case GLS_SRCBLEND_ALPHA_SATURATE: srcFactor = GL_SRC_ALPHA_SATURATE; break; default: srcFactor = GL_ONE; // to get warning to shut up Ren_Drop("GL_State: invalid src blend state bits\n"); break; } switch (stateBits & GLS_DSTBLEND_BITS) { case GLS_DSTBLEND_ZERO: dstFactor = GL_ZERO; break; case GLS_DSTBLEND_ONE: dstFactor = GL_ONE; break; case GLS_DSTBLEND_SRC_COLOR: dstFactor = GL_SRC_COLOR; break; case GLS_DSTBLEND_ONE_MINUS_SRC_COLOR: dstFactor = GL_ONE_MINUS_SRC_COLOR; break; case GLS_DSTBLEND_SRC_ALPHA: dstFactor = GL_SRC_ALPHA; break; case GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA: dstFactor = GL_ONE_MINUS_SRC_ALPHA; break; case GLS_DSTBLEND_DST_ALPHA: dstFactor = GL_DST_ALPHA; break; case GLS_DSTBLEND_ONE_MINUS_DST_ALPHA: dstFactor = GL_ONE_MINUS_DST_ALPHA; break; default: dstFactor = GL_ONE; // to get warning to shut up Ren_Drop("GL_State: invalid dst blend state bits\n"); break; } glEnable(GL_BLEND); GL_BlendFunc(srcFactor, dstFactor); } else { glDisable(GL_BLEND); } } // check colormask if (diff & GLS_COLORMASK_BITS) { if (stateBits & GLS_COLORMASK_BITS) { GL_ColorMask((stateBits & GLS_REDMASK_FALSE) ? GL_FALSE : GL_TRUE, (stateBits & GLS_GREENMASK_FALSE) ? GL_FALSE : GL_TRUE, (stateBits & GLS_BLUEMASK_FALSE) ? GL_FALSE : GL_TRUE, (stateBits & GLS_ALPHAMASK_FALSE) ? GL_FALSE : GL_TRUE); } else { GL_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } } // check depthmask if (diff & GLS_DEPTHMASK_TRUE) { if (stateBits & GLS_DEPTHMASK_TRUE) { GL_DepthMask(GL_TRUE); } else { GL_DepthMask(GL_FALSE); } } // fill/line mode if (diff & GLS_POLYMODE_LINE) { if (stateBits & GLS_POLYMODE_LINE) { GL_PolygonMode(GL_FRONT_AND_BACK, GL_LINE); } else { GL_PolygonMode(GL_FRONT_AND_BACK, GL_FILL); } } // depthtest if (diff & GLS_DEPTHTEST_DISABLE) { if (stateBits & GLS_DEPTHTEST_DISABLE) { glDisable(GL_DEPTH_TEST); } else { glEnable(GL_DEPTH_TEST); } } // alpha test - deprecated in OpenGL 3.0 #if 0 if (diff & GLS_ATEST_BITS) { switch (stateBits & GLS_ATEST_BITS) { case GLS_ATEST_GT_0: case GLS_ATEST_LT_128: case GLS_ATEST_GE_128: //case GLS_ATEST_GT_CUSTOM: glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE); break; default: case 0: glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); break; } } #endif /* if(diff & GLS_ATEST_BITS) { switch (stateBits & GLS_ATEST_BITS) { case 0: glDisable(GL_ALPHA_TEST); break; case GLS_ATEST_GT_0: glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.0f); break; case GLS_ATEST_LT_80: glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_LESS, 0.5f); break; case GLS_ATEST_GE_80: glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GEQUAL, 0.5f); break; case GLS_ATEST_GT_CUSTOM: // FIXME glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.5f); break; default: assert(0); break; } } */ // stenciltest if (diff & GLS_STENCILTEST_ENABLE) { if (stateBits & GLS_STENCILTEST_ENABLE) { glEnable(GL_STENCIL_TEST); } else { glDisable(GL_STENCIL_TEST); } } glState.glStateBits = stateBits; }
/* ============= R_DrawAliasVolumeShadow based on code from BeefQuake R6 ============= */ void R_DrawAliasVolumeShadow (maliasmodel_t *paliashdr, vec3_t bbox[8]) { vec3_t light, temp, vecAdd; float dist, highest, lowest, projected_distance; float angle, cosp, sinp, cosy, siny, cosr, sinr, ix, iy, iz; int i, lnum; dlight_t *dl; dl = r_newrefdef.dlights; VectorSet(vecAdd, 680,0,1024); // set base vector, was 576,0,1024 // compute average light vector from dlights for (i=0, lnum=0; i<r_newrefdef.num_dlights; i++, dl++) { if (VectorCompare(dl->origin, currententity->origin)) continue; VectorSubtract(dl->origin, currententity->origin, temp); dist = dl->intensity - VectorLength(temp); if (dist <= 0) continue; lnum++; // Factor in the intensity of a dlight VectorScale (temp, dist*0.25, temp); VectorAdd (vecAdd, temp, vecAdd); } VectorNormalize(vecAdd); VectorScale(vecAdd, 1024, vecAdd); // get projection distance from lightspot height highest = lowest = bbox[0][2]; for (i=0; i<8; i++) { if (bbox[i][2] > highest) highest = bbox[i][2]; if (bbox[i][2] < lowest) lowest = bbox[i][2]; } projected_distance = (fabs(highest - lightspot[2]) + (highest-lowest)) / vecAdd[2]; VectorCopy(vecAdd, light); /*cosy = cos(-currententity->angles[YAW] / 180 * M_PI); siny = sin(-currententity->angles[YAW] / 180 * M_PI); ix = light[0], iy = light[1]; light[0] = (cosy * (ix - 0) + siny * (0 - iy) + 0); light[1] = (cosy * (iy - 0) + siny * (ix - 0) + 0); light[2] += 8;*/ // reverse-rotate light vector based on angles angle = -currententity->angles[PITCH] / 180 * M_PI; cosp = cos(angle), sinp = sin(angle); angle = -currententity->angles[YAW] / 180 * M_PI; cosy = cos(angle), siny = sin(angle); angle = currententity->angles[ROLL] / 180 * M_PI; // roll is backwards cosr = cos(angle), sinr = sin(angle); // rotate for yaw (z axis) ix = light[0], iy = light[1]; light[0] = cosy * ix - siny * iy + 0; light[1] = siny * ix + cosy * iy + 0; // rotate for pitch (y axis) ix = light[0], iz = light[2]; light[0] = cosp * ix + 0 + sinp * iz; light[2] = -sinp * ix + 0 + cosp * iz; // rotate for roll (x axis) iy = light[1], iz = light[2]; light[1] = 0 + cosr * iy - sinr * iz; light[2] = 0 + sinr * iy + cosr * iz; // set up stenciling if (!r_shadowvolumes->value) { qglPushAttrib(GL_STENCIL_BUFFER_BIT); // save stencil buffer qglClear(GL_STENCIL_BUFFER_BIT); qglColorMask(0,0,0,0); GL_DepthMask(0); GL_DepthFunc(GL_LESS); GL_Enable(GL_STENCIL_TEST); qglStencilFunc(GL_ALWAYS, 0, 255); // qglStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); // qglStencilMask (255); } // build shadow volumes and render each to stencil buffer for (i=0; i<paliashdr->num_meshes; i++) { if (paliashdr->meshes[i].skins[currententity->skinnum].renderparms.nodraw || paliashdr->meshes[i].skins[currententity->skinnum].renderparms.alphatest || paliashdr->meshes[i].skins[currententity->skinnum].renderparms.noshadow) continue; R_BuildShadowVolume (paliashdr, i, light, projected_distance, r_shadowvolumes->value); GL_LockArrays (shadow_va); if (!r_shadowvolumes->value) { if (gl_config.atiSeparateStencil && gl_config.extStencilWrap) // Barnes ATI stenciling { GL_Disable(GL_CULL_FACE); qglStencilOpSeparateATI (GL_BACK, GL_KEEP, GL_INCR_WRAP_EXT, GL_KEEP); qglStencilOpSeparateATI (GL_FRONT, GL_KEEP, GL_DECR_WRAP_EXT, GL_KEEP); R_DrawShadowVolume (); GL_Enable(GL_CULL_FACE); } else if (gl_config.extStencilTwoSide && gl_config.extStencilWrap) // Echon's two-sided stenciling { GL_Disable(GL_CULL_FACE); qglEnable (GL_STENCIL_TEST_TWO_SIDE_EXT); qglActiveStencilFaceEXT (GL_BACK); qglStencilOp (GL_KEEP, GL_INCR_WRAP_EXT, GL_KEEP); qglActiveStencilFaceEXT (GL_FRONT); qglStencilOp (GL_KEEP, GL_DECR_WRAP_EXT, GL_KEEP); R_DrawShadowVolume (); qglDisable (GL_STENCIL_TEST_TWO_SIDE_EXT); GL_Enable(GL_CULL_FACE); } else { // increment stencil if backface is behind depthbuffer GL_CullFace(GL_BACK); // quake is backwards, this culls front faces qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP); R_DrawShadowVolume (); // decrement stencil if frontface is behind depthbuffer GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP); R_DrawShadowVolume (); } } else R_DrawShadowVolume (); GL_UnlockArrays (); } // end stenciling and draw stenciled volume if (!r_shadowvolumes->value) { GL_CullFace(GL_FRONT); GL_Disable(GL_STENCIL_TEST); GL_DepthFunc(GL_LEQUAL); GL_DepthMask(1); qglColorMask(1,1,1,1); // draw shadows for this model now R_ShadowBlend (aliasShadowAlpha * currententity->alpha); // was r_shadowalpha->value qglPopAttrib(); // restore stencil buffer } }