/* ================= R_DrawAliasModel ================= */ void R_DrawAliasModel (entity_t *e) { int i, j; int lnum; vec3_t dist; float add; model_t *clmodel; vec3_t mins, maxs; aliashdr_t *paliashdr; trivertx_t *verts, *v; int index; float s, t, an; int anim; clmodel = currententity->model; VectorAdd (currententity->origin, clmodel->mins, mins); VectorAdd (currententity->origin, clmodel->maxs, maxs); if (R_CullBox (mins, maxs)) return; VectorCopy (currententity->origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); // // get lighting information // ambientlight = shadelight = R_LightPoint (currententity->origin); // allways give the gun some light if (e == &cl.viewent && ambientlight < 24) ambientlight = shadelight = 24; for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++) { if (cl_dlights[lnum].die >= cl.time) { VectorSubtract (currententity->origin, cl_dlights[lnum].origin, dist); add = cl_dlights[lnum].radius - Length(dist); if (add > 0) { ambientlight += add; //ZOID models should be affected by dlights as well shadelight += add; } } } // clamp lighting so it doesn't overbright as much if (ambientlight > 128) ambientlight = 128; if (ambientlight + shadelight > 192) shadelight = 192 - ambientlight; // ZOID: never allow players to go totally black i = currententity - cl_entities; if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */) if (ambientlight < 8) ambientlight = shadelight = 8; // HACK HACK HACK -- no fullbright colors, so make torches full light if (!strcmp (clmodel->name, "progs/flame2.mdl") || !strcmp (clmodel->name, "progs/flame.mdl") ) ambientlight = shadelight = 256; shadedots = r_avertexnormal_dots[((int)(e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; shadelight = shadelight / 200.0; an = e->angles[1]/180*M_PI; shadevector[0] = cos(-an); shadevector[1] = sin(-an); shadevector[2] = 1; VectorNormalize (shadevector); // // locate the proper data // paliashdr = (aliashdr_t *)Mod_Extradata (currententity->model); c_alias_polys += paliashdr->numtris; // // draw all the triangles // GL_DisableMultitexture(); glPushMatrix (); R_RotateForEntity (e); if (!strcmp (clmodel->name, "progs/eyes.mdl") && gl_doubleeyes.value) { glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2] - (22 + 8)); // double size of eyes, since they are really hard to see in gl glScalef (paliashdr->scale[0]*2, paliashdr->scale[1]*2, paliashdr->scale[2]*2); } else { glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]); glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]); } anim = (int)(cl.time*10) & 3; GL_Bind(paliashdr->gl_texturenum[currententity->skinnum][anim]); // we can't dynamically colormap textures, so they are cached // seperately for the players. Heads are just uncolored. if (currententity->colormap != vid.colormap && !gl_nocolors.value) { i = currententity - cl_entities; if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */) GL_Bind(playertextures - 1 + i); } if (gl_smoothmodels.value) glShadeModel (GL_SMOOTH); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); if (gl_affinemodels.value) glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); R_SetupAliasFrame (currententity->frame, paliashdr); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glShadeModel (GL_FLAT); if (gl_affinemodels.value) glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glPopMatrix (); if (r_shadows.value) { glPushMatrix (); R_RotateForEntity (e); glDisable (GL_TEXTURE_2D); glEnable (GL_BLEND); glColor4f (0,0,0,0.5); GL_DrawAliasShadow (paliashdr, lastposenum); glEnable (GL_TEXTURE_2D); glDisable (GL_BLEND); glColor4f (1,1,1,1); glPopMatrix (); } }
/* ================= R_DrawSpriteModel -- johnfitz -- rewritten: now supports all orientations ================= */ void R_DrawSpriteModel (entity_t *e) { vec3_t point, v_forward, v_right, v_up; msprite_t *psprite; mspriteframe_t *frame; float *s_up, *s_right; float angle, sr, cr; //TODO: frustum cull it? frame = R_GetSpriteFrame (e); psprite = (msprite_t *) currententity->model->cache.data; switch(psprite->type) { case SPR_VP_PARALLEL_UPRIGHT: //faces view plane, up is towards the heavens v_up[0] = 0; v_up[1] = 0; v_up[2] = 1; s_up = v_up; s_right = vright; break; case SPR_FACING_UPRIGHT: //faces camera origin, up is towards the heavens VectorSubtract(currententity->origin, r_origin, v_forward); v_forward[2] = 0; VectorNormalizeFast(v_forward); v_right[0] = v_forward[1]; v_right[1] = -v_forward[0]; v_right[2] = 0; v_up[0] = 0; v_up[1] = 0; v_up[2] = 1; s_up = v_up; s_right = v_right; break; case SPR_VP_PARALLEL: //faces view plane, up is towards the top of the screen s_up = vup; s_right = vright; break; case SPR_ORIENTED: //pitch yaw roll are independent of camera AngleVectors (currententity->angles, v_forward, v_right, v_up); s_up = v_up; s_right = v_right; break; case SPR_VP_PARALLEL_ORIENTED: //faces view plane, but obeys roll value angle = currententity->angles[ROLL] * M_PI_DIV_180; sr = sin(angle); cr = cos(angle); v_right[0] = vright[0] * cr + vup[0] * sr; v_right[1] = vright[1] * cr + vup[1] * sr; v_right[2] = vright[2] * cr + vup[2] * sr; v_up[0] = vright[0] * -sr + vup[0] * cr; v_up[1] = vright[1] * -sr + vup[1] * cr; v_up[2] = vright[2] * -sr + vup[2] * cr; s_up = v_up; s_right = v_right; break; default: return; } //johnfitz: offset decals if (psprite->type == SPR_ORIENTED) GL_PolygonOffset (OFFSET_DECAL); glColor3f (1,1,1); GL_DisableMultitexture(); GL_Bind(frame->gltexture); glEnable (GL_ALPHA_TEST); glBegin (GL_TRIANGLE_FAN); //was GL_QUADS, but changed to support r_showtris glTexCoord2f (0, frame->tmax); VectorMA (e->origin, frame->down, s_up, point); VectorMA (point, frame->left, s_right, point); glVertex3fv (point); glTexCoord2f (0, 0); VectorMA (e->origin, frame->up, s_up, point); VectorMA (point, frame->left, s_right, point); glVertex3fv (point); glTexCoord2f (frame->smax, 0); VectorMA (e->origin, frame->up, s_up, point); VectorMA (point, frame->right, s_right, point); glVertex3fv (point); glTexCoord2f (frame->smax, frame->tmax); VectorMA (e->origin, frame->down, s_up, point); VectorMA (point, frame->right, s_right, point); glVertex3fv (point); glEnd (); glDisable (GL_ALPHA_TEST); //johnfitz: offset decals if (psprite->type == SPR_ORIENTED) GL_PolygonOffset (OFFSET_NONE); }
//void GL_DrawQ3AliasFrame (md3header_mem_t *header, int lastpose, int pose, float blend, qboolean mtex) void GL_DrawQ3AliasFrame (const md3header_t *header, const entity_t *e, int pose, float blend, qboolean mtex) /*******JDH*******/ { int i, j, k, index; int frame; int lastframe; int vertframeoffset; int lastvertframeoffset; float /*alpha, */iblend; md3surface_t *surf; md3st_t *tc, *xycoord; md3tri_t *tris; md3vert_t *verts, *vertslast, *currvert, *lastvert; md3shader_t *shaders; // vec3_t currnorm, lastnorm; r_modelalpha = GL_GetAliasAlpha (e); if (r_modelalpha < 1.0) glEnable (GL_BLEND); blend = bound(0, blend, 1); iblend = 1.0 - blend; surf = (md3surface_t *)((byte *)header + header->surface_offs); for (i = 0; i < header->num_surfaces; i++) { if (surf->num_surf_frames == 0) { surf = (md3surface_t *)((byte *)surf + surf->end_offs); continue; //shouldn't ever do this, each surface should have at least one frame } //get pointer to shaders (ie. textures) shaders = (md3shader_t *)((byte *)surf + surf->shader_offs); index = shaders[e->skinnum % surf->num_surf_shaders].index; GL_Bind (index); frame = pose % surf->num_surf_frames; //cap the frame inside the list of frames in the model vertframeoffset = frame * surf->num_surf_verts * sizeof(md3vert_t); /*******JDH*******/ //lastframe = lastpose%surf->num_surf_frames; lastframe = e->lastpose % surf->num_surf_frames; /*******JDH*******/ lastvertframeoffset = lastframe*surf->num_surf_verts * sizeof(md3vert_t); tc = (md3st_t *)((byte *)surf + surf->tc_offs); tris = (md3tri_t *)((byte *)surf + surf->tris_offs); verts = (md3vert_t *)((byte *)surf + surf->vert_offs + vertframeoffset); vertslast = (md3vert_t *)((byte *)surf + surf->vert_offs + lastvertframeoffset); /*if (blend >=1) { //glNormalPointer(GL_FLOAT, 6 * sizeof(float), (float *)verts->normal); //glEnableClientState(GL_NORMAL_ARRAY); glVertexPointer(3, GL_SHORT, sizeof( md3vert_t ), verts->vec); glEnableClientState(GL_VERTEX_ARRAY); glTexCoordPointer(2, GL_FLOAT, 0, (float *)tc); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glDrawElements(GL_TRIANGLES, surf->num_surf_tris*3, GL_UNSIGNED_INT, tris); //glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } else*/ { //interpolated glBegin(GL_TRIANGLES); //for each triangle for (j = 0; j < surf->num_surf_tris; j++) { //draw the poly for (k=0; k < 3; k++) { index = tris[j].tri[k]; xycoord = &tc[index]; if (mtex) { qglMultiTexCoord2f (GL_TEXTURE0_ARB, xycoord->s, xycoord->t); qglMultiTexCoord2f (GL_TEXTURE1_ARB, xycoord->s, xycoord->t); } else { glTexCoord2f (xycoord->s, xycoord->t); } currvert = &verts[index]; lastvert = &vertslast[index]; GL_SetupMD3Light (currvert, lastvert, r_modelalpha); glVertex3f ((currvert->vec[0] * blend + lastvert->vec[0] * iblend) / 64.0, (currvert->vec[1] * blend + lastvert->vec[1] * iblend) / 64.0, (currvert->vec[2] * blend + lastvert->vec[2] * iblend) / 64.0); /*MD3_ConvertNormal (currvert->normal, currnorm); MD3_ConvertNormal (lastvert->normal, lastnorm); glNormal3f (currnorm[0] * blend + lastnorm[0] * iblend, currnorm[1] * blend + lastnorm[1] * iblend, currnorm[2] * blend + lastnorm[2] * iblend);*/ } } glEnd(); } surf = (md3surface_t *)((byte *)surf + surf->end_offs); } if (r_modelalpha < 1.0) glDisable (GL_BLEND); glColor3f (1, 1, 1); }
static void ProjectDlightTexture_scalar( void ) { int i, l; vec3_t origin; float *texCoords; byte *colors; int *intColors; byte clipBits[SHADER_MAX_VERTEXES]; float texCoordsArray[SHADER_MAX_VERTEXES][2]; byte colorArray[SHADER_MAX_VERTEXES][4]; glIndex_t hitIndexes[SHADER_MAX_INDEXES]; int numIndexes; float scale; float radius; float radiusInverseCubed; float intensity, remainder; vec3_t floatColor; float modulate = 0.0f; qboolean vertexLight; if ( !backEnd.refdef.num_dlights ) { return; } for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { dlight_t *dl; if ( !( tess.dlightBits & ( 1 << l ) ) ) { continue; // this surface definately doesn't have any of this light } // clear colors Com_Memset( colorArray, 0, sizeof( colorArray ) ); texCoords = texCoordsArray[0]; colors = colorArray[0]; dl = &backEnd.refdef.dlights[l]; VectorCopy( dl->transformed, origin ); radius = dl->radius; scale = 1.0f / radius; radiusInverseCubed = dl->radiusInverseCubed; intensity = dl->intensity; vertexLight = ( ( dl->flags & REF_DIRECTED_DLIGHT ) || ( dl->flags & REF_VERTEX_DLIGHT ) ); // directional lights have max intensity and washout remainder intensity if ( dl->flags & REF_DIRECTED_DLIGHT ) { remainder = intensity * 0.125; } else { remainder = 0.0f; } if(r_greyscale->integer) { float luminance; luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; floatColor[0] = floatColor[1] = floatColor[2] = luminance; } else if(r_greyscale->value) { float luminance; luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; floatColor[0] = LERP(dl->color[0] * 255.0f, luminance, r_greyscale->value); floatColor[1] = LERP(dl->color[1] * 255.0f, luminance, r_greyscale->value); floatColor[2] = LERP(dl->color[2] * 255.0f, luminance, r_greyscale->value); } else { floatColor[0] = dl->color[0] * 255.0f; floatColor[1] = dl->color[1] * 255.0f; floatColor[2] = dl->color[2] * 255.0f; } for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) { int clip = 0; vec3_t dist; VectorSubtract( origin, tess.xyz[i], dist ); backEnd.pc.c_dlightVertexes++; // directional dlight, origin is a directional normal if ( dl->flags & REF_DIRECTED_DLIGHT ) { // twosided surfaces use absolute value of the calculated lighting modulate = intensity * DotProduct( dl->origin, tess.normal[ i ] ); if ( tess.shader->cullType == CT_TWO_SIDED ) { modulate = fabs( modulate ); } modulate += remainder; } // spherical vertex lit dlight else if ( dl->flags & REF_VERTEX_DLIGHT ) { vec3_t dir; dir[ 0 ] = radius - fabs( dist[ 0 ] ); if ( dir[ 0 ] <= 0.0f ) { continue; } dir[ 1 ] = radius - fabs( dist[ 1 ] ); if ( dir[ 1 ] <= 0.0f ) { continue; } dir[ 2 ] = radius - fabs( dist[ 2 ] ); if ( dir[ 2 ] <= 0.0f ) { continue; } modulate = intensity * dir[ 0 ] * dir[ 1 ] * dir[ 2 ] * radiusInverseCubed; } // vertical cylinder dlight else { texCoords[0] = 0.5f + dist[0] * scale; texCoords[1] = 0.5f + dist[1] * scale; if( !r_dlightBacks->integer && // dist . tess.normal[i] ( dist[0] * tess.normal[i][0] + dist[1] * tess.normal[i][1] + dist[2] * tess.normal[i][2] ) < 0.0f ) { clip = 63; } else { if ( texCoords[0] < 0.0f ) { clip |= 1; } else if ( texCoords[0] > 1.0f ) { clip |= 2; } if ( texCoords[1] < 0.0f ) { clip |= 4; } else if ( texCoords[1] > 1.0f ) { clip |= 8; } texCoords[0] = texCoords[0]; texCoords[1] = texCoords[1]; // modulate the strength based on the height and color if ( dist[2] > radius ) { clip |= 16; modulate = 0.0f; } else if ( dist[2] < -radius ) { clip |= 32; modulate = 0.0f; } else { dist[2] = Q_fabs(dist[2]); if ( dist[2] < radius * 0.5f ) { modulate = intensity; } else { modulate = intensity * 2.0f * (radius - dist[2]) * scale; } } } } // optimizations if ( vertexLight && modulate < ( 1.0f / 128.0f ) ) { continue; } else if ( modulate > 1.0f ) { modulate = 1.0f; } clipBits[i] = clip; colors[0] = Com_Clamp( 0, 255, ri.ftol(floatColor[0] * modulate) ); colors[1] = Com_Clamp( 0, 255, ri.ftol(floatColor[1] * modulate) ); colors[2] = Com_Clamp( 0, 255, ri.ftol(floatColor[2] * modulate) ); colors[3] = 255; } // build a list of triangles that need light intColors = (int*) colorArray; numIndexes = 0; for ( i = 0 ; i < tess.numIndexes ; i += 3 ) { int a, b, c; a = tess.indexes[i]; b = tess.indexes[i+1]; c = tess.indexes[i+2]; if ( vertexLight ) { if ( !( intColors[ a ] | intColors[ b ] | intColors[ c ] ) ) { continue; } } else { if ( clipBits[a] & clipBits[b] & clipBits[c] ) { continue; // not lighted } } hitIndexes[numIndexes] = a; hitIndexes[numIndexes+1] = b; hitIndexes[numIndexes+2] = c; numIndexes += 3; } if ( !numIndexes ) { continue; } if ( !vertexLight ) { qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); } else { qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); } qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); if ( dl->dlshader ) { shader_t *dls = dl->dlshader; for ( i = 0; i < dls->numUnfoggedPasses; i++ ) { shaderStage_t *stage = dls->stages[i]; R_BindAnimatedImage( &dls->stages[i]->bundle[0] ); GL_State( stage->stateBits | GLS_DEPTHFUNC_EQUAL ); R_DrawElements( numIndexes, hitIndexes ); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; } } else { R_FogOff(); if ( !vertexLight ) { GL_Bind( tr.dlightImage ); } else { GL_Bind( tr.whiteImage ); } // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // where they aren't rendered if ( dl->flags & REF_ADDITIVE_DLIGHT ) { GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); } else { GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); } R_DrawElements( numIndexes, hitIndexes ); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; RB_FogOn(); } } }
void StencilShadow::RenderShadow() { #ifndef DISABLE_STENCILSHADOW DWORD lighting, fog, srcblend, destblend, alphablend, zwrite, zfunc, cullmode; GL_State(GLS_DEFAULT); glw_state->device->GetRenderState( D3DRS_LIGHTING, &lighting ); glw_state->device->GetRenderState( D3DRS_FOGENABLE, &fog ); glw_state->device->GetRenderState( D3DRS_SRCBLEND, &srcblend ); glw_state->device->GetRenderState( D3DRS_DESTBLEND, &destblend ); glw_state->device->GetRenderState( D3DRS_ALPHABLENDENABLE, &alphablend ); glw_state->device->GetRenderState( D3DRS_ZWRITEENABLE, &zwrite ); glw_state->device->GetRenderState( D3DRS_ZFUNC, &zfunc ); glw_state->device->GetRenderState( D3DRS_CULLMODE, &cullmode ); pVerts = NULL; pExtrusions = NULL; GL_Bind( tr.whiteImage ); glw_state->device->SetRenderState( D3DRS_LIGHTING, FALSE ); glw_state->device->SetRenderState( D3DRS_FOGENABLE, FALSE ); glw_state->device->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE ); glw_state->device->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ZERO ); // Disable z-buffer writes (note: z-testing still occurs), and enable the // stencil-buffer glw_state->device->SetRenderState( D3DRS_ZWRITEENABLE, FALSE ); glw_state->device->SetRenderState( D3DRS_STENCILENABLE, TRUE ); // Don't bother with interpolating color glw_state->device->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_FLAT ); glw_state->device->SetRenderState( D3DRS_ZFUNC, D3DCMP_LESS ); // Set up stencil compare function, reference value, and masks. // Stencil test passes if ((ref & mask) cmpfn (stencil & mask)) is true. // Note: since we set up the stencil-test to always pass, the STENCILFAIL // renderstate is really not needed. glw_state->device->SetRenderState( D3DRS_STENCILFUNC, D3DCMP_ALWAYS ); #ifdef _STENCIL_REVERSE glw_state->device->SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_INCR ); glw_state->device->SetRenderState( D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP ); glw_state->device->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_KEEP ); #else glw_state->device->SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP ); glw_state->device->SetRenderState( D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP ); glw_state->device->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_INCR ); #endif // If ztest passes, inc/decrement stencil buffer value glw_state->device->SetRenderState( D3DRS_STENCILREF, 0x1 ); glw_state->device->SetRenderState( D3DRS_STENCILMASK, 0x7f ); //0xffffffff ); glw_state->device->SetRenderState( D3DRS_STENCILWRITEMASK, 0x7f ); //0xffffffff ); // Make sure that no pixels get drawn to the frame buffer glw_state->device->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); glw_state->device->SetRenderState( D3DRS_COLORWRITEENABLE, 0 ); glw_state->device->SetTexture(0, NULL); glw_state->device->SetTexture(1, NULL); // Compute the matrix set XGMATRIX matComposite, matProjectionViewport, matWorld; glw_state->device->GetProjectionViewportMatrix( &matProjectionViewport ); XGMatrixMultiply( &matComposite, (XGMATRIX*)glw_state->matrixStack[glwstate_t::MatrixMode_Model]->GetTop(), &matProjectionViewport ); // Transpose and set the composite matrix. XGMatrixTranspose( &matComposite, &matComposite ); glw_state->device->SetVertexShaderConstant( CV_WORLDVIEWPROJ_0, &matComposite, 4 ); // Set viewport offsets. float fViewportOffsets[4] = { 0.53125f, 0.53125f, 0.0f, 0.0f }; glw_state->device->SetVertexShaderConstant( CV_VIEWPORT_OFFSETS, &fViewportOffsets, 1 ); glw_state->device->SetVertexShader(m_dwVertexShaderShadow); #ifdef _STENCIL_REVERSE qglCullFace( GL_FRONT ); #else qglCullFace( GL_BACK ); #endif BuildEdges(); // Draw front-side of shadow volume in stencil/z only if(m_nIndexes) renderObject_Shadow( D3DPT_QUADLIST, m_nIndexes, m_shadowIndexes ); #ifdef _STENCIL_REVERSE if(m_nIndexesCap) renderObject_Shadow( D3DPT_TRIANGLELIST, m_nIndexesCap, m_shadowIndexesCap ); #endif // Now reverse cull order so back sides of shadow volume are written. #ifdef _STENCIL_REVERSE qglCullFace( GL_BACK ); #else qglCullFace( GL_FRONT ); #endif // Decrement stencil buffer value #ifdef _STENCIL_REVERSE glw_state->device->SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_DECR ); #else glw_state->device->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_DECR ); #endif // Draw back-side of shadow volume in stencil/z only if(m_nIndexes) renderObject_Shadow( D3DPT_QUADLIST, m_nIndexes, m_shadowIndexes ); #ifdef _STENCIL_REVERSE if(m_nIndexesCap) renderObject_Shadow( D3DPT_TRIANGLELIST, m_nIndexesCap, m_shadowIndexesCap ); #endif // Restore render states glw_state->device->SetRenderState( D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALL ); glw_state->device->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD ); glw_state->device->SetRenderState( D3DRS_STENCILENABLE, FALSE ); glw_state->device->SetRenderState( D3DRS_LIGHTING, lighting ); glw_state->device->SetRenderState( D3DRS_FOGENABLE, fog ); glw_state->device->SetRenderState( D3DRS_SRCBLEND, srcblend ); glw_state->device->SetRenderState( D3DRS_DESTBLEND, destblend ); glw_state->device->SetRenderState( D3DRS_ALPHABLENDENABLE, alphablend ); glw_state->device->SetRenderState( D3DRS_ZWRITEENABLE, zwrite ); glw_state->device->SetRenderState( D3DRS_ZFUNC, zfunc ); glw_state->device->SetRenderState( D3DRS_CULLMODE, cullmode ); #endif }
/* ================= R_Bloom_GeneratexCross - alternative bluring method ================= */ void R_Bloom_GeneratexCross( void ) { int i; static int BLOOM_BLUR_RADIUS = 8; //static float BLOOM_BLUR_INTENSITY = 2.5f; float BLOOM_BLUR_INTENSITY; static float intensity; static float range; //set up sample size workspace qglViewport( 0, 0, sample_width, sample_height ); qglMatrixMode( GL_PROJECTION ); qglLoadIdentity (); qglOrtho(0, sample_width, sample_height, 0, -10, 100); qglMatrixMode( GL_MODELVIEW ); qglLoadIdentity (); //copy small scene into r_bloomeffecttexture GL_Bind(0, r_bloomeffecttexture); qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height); //start modifying the small scene corner qglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); GL_Enable(GL_BLEND); //darkening passes if( r_bloom_darken->value ) { GL_BlendFunc(GL_DST_COLOR, GL_ZERO); GL_TexEnv(GL_MODULATE); for(i=0; i<r_bloom_darken->value ; i++) { R_Bloom_SamplePass( 0, 0 ); } qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height); } //bluring passes if( BLOOM_BLUR_RADIUS ) { GL_BlendFunc(GL_ONE, GL_ONE); range = (float)BLOOM_BLUR_RADIUS; BLOOM_BLUR_INTENSITY = r_bloom_intensity->value; //diagonal-cross draw 4 passes to add initial smooth qglColor4f( 0.5f, 0.5f, 0.5f, 1.0); R_Bloom_SamplePass( 1, 1 ); R_Bloom_SamplePass( -1, 1 ); R_Bloom_SamplePass( -1, -1 ); R_Bloom_SamplePass( 1, -1 ); qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height); for(i=-(BLOOM_BLUR_RADIUS+1); i<BLOOM_BLUR_RADIUS; i++) { intensity = BLOOM_BLUR_INTENSITY/(range*2+1)*(1 - fabs(i*i)/(float)(range*range)); if( intensity < 0.05f ) continue; qglColor4f( intensity, intensity, intensity, 1.0f); R_Bloom_SamplePass( i, 0 ); //R_Bloom_SamplePass( -i, 0 ); } qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height); //for(i=0;i<BLOOM_BLUR_RADIUS;i++) { for(i=-(BLOOM_BLUR_RADIUS+1); i<BLOOM_BLUR_RADIUS; i++) { intensity = BLOOM_BLUR_INTENSITY/(range*2+1)*(1 - fabs(i*i)/(float)(range*range)); if( intensity < 0.05f ) continue; qglColor4f( intensity, intensity, intensity, 1.0f); R_Bloom_SamplePass( 0, i ); //R_Bloom_SamplePass( 0, -i ); } qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height); } //restore full screen workspace qglViewport( 0, 0, glState.width, glState.height ); qglMatrixMode( GL_PROJECTION ); qglLoadIdentity (); qglOrtho(0, glState.width, glState.height, 0, -10, 100); qglMatrixMode( GL_MODELVIEW ); qglLoadIdentity (); }
void R_BloomBlend ( refdef_t *fd ) { if( !(fd->rdflags & RDF_BLOOM) || !r_bloom->value || r_showtris->value ) return; if( !BLOOM_SIZE ) R_Bloom_InitTextures(); if( screen_texture_width < BLOOM_SIZE || screen_texture_height < BLOOM_SIZE ) return; //set up full screen workspace qglViewport ( 0, 0, vid.width, vid.height ); GL_TexEnv (GL_REPLACE); // Knightmare added GL_Disable (GL_DEPTH_TEST); qglMatrixMode (GL_PROJECTION); qglLoadIdentity (); qglOrtho(0, vid.width, vid.height, 0, -10, 100); qglMatrixMode (GL_MODELVIEW); qglLoadIdentity (); GL_Disable (GL_CULL_FACE); GL_Disable (GL_BLEND); qglEnable (GL_TEXTURE_2D); qglColor4f (1, 1, 1, 1); //set up current sizes curView_x = fd->x; curView_y = fd->y; curView_width = fd->width; curView_height = fd->height; screenText_tcw = ((float)fd->width / (float)screen_texture_width); screenText_tch = ((float)fd->height / (float)screen_texture_height); if( fd->height > fd->width ) { sampleText_tcw = ((float)fd->width / (float)fd->height); sampleText_tch = 1.0f; } else { sampleText_tcw = 1.0f; sampleText_tch = ((float)fd->height / (float)fd->width); } sample_width = BLOOM_SIZE * sampleText_tcw; sample_height = BLOOM_SIZE * sampleText_tch; //copy the screen space we'll use to work into the backup texture GL_Bind(r_bloombackuptexture->texnum); qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, r_screenbackuptexture_size * sampleText_tcw, r_screenbackuptexture_size * sampleText_tch); //create the bloom image R_Bloom_DownsampleView(); R_Bloom_GeneratexDiamonds( fd ); //R_Bloom_GeneratexCross(); //restore the screen-backup to the screen GL_Disable(GL_BLEND); GL_Bind(r_bloombackuptexture->texnum); qglColor4f( 1, 1, 1, 1 ); R_Bloom_Quad( 0, vid.height - (r_screenbackuptexture_size * sampleText_tch), r_screenbackuptexture_size * sampleText_tcw, r_screenbackuptexture_size * sampleText_tch, sampleText_tcw, sampleText_tch ); R_Bloom_DrawEffect( fd ); // Knightmare added R_SetupGL (); GL_BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); qglEnable (GL_TEXTURE_2D); qglColor4f(1,1,1,1); }
static void ProjectDlightTexture_altivec( void ) { int i, l; vec_t origin0, origin1, origin2; float texCoords0, texCoords1; vector float floatColorVec0, floatColorVec1; vector float modulateVec, colorVec, zero; vector short colorShort; vector signed int colorInt; vector unsigned char floatColorVecPerm, modulatePerm, colorChar; vector unsigned char vSel = VECCONST_UINT8(0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff); float *texCoords; byte *colors; byte clipBits[SHADER_MAX_VERTEXES]; float texCoordsArray[SHADER_MAX_VERTEXES][2]; byte colorArray[SHADER_MAX_VERTEXES][4]; unsigned hitIndexes[SHADER_MAX_INDEXES]; int numIndexes; float scale; float radius; vec3_t floatColor; float modulate = 0.0f; if ( !backEnd.refdef.num_dlights ) { return; } // There has to be a better way to do this so that floatColor // and/or modulate are already 16-byte aligned. floatColorVecPerm = vec_lvsl(0,(float *)floatColor); modulatePerm = vec_lvsl(0,(float *)&modulate); modulatePerm = (vector unsigned char)vec_splat((vector unsigned int)modulatePerm,0); zero = (vector float)vec_splat_s8(0); for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { dlight_t *dl; if ( !( tess.dlightBits & ( 1 << l ) ) ) { continue; // this surface definately doesn't have any of this light } texCoords = texCoordsArray[0]; colors = colorArray[0]; dl = &backEnd.refdef.dlights[l]; origin0 = dl->transformed[0]; origin1 = dl->transformed[1]; origin2 = dl->transformed[2]; radius = dl->radius; scale = 1.0f / radius; if(r_greyscale->integer) { float luminance; luminance = (dl->color[0] * 255.0f + dl->color[1] * 255.0f + dl->color[2] * 255.0f) / 3; floatColor[0] = floatColor[1] = floatColor[2] = luminance; } else { floatColor[0] = dl->color[0] * 255.0f; floatColor[1] = dl->color[1] * 255.0f; floatColor[2] = dl->color[2] * 255.0f; } floatColorVec0 = vec_ld(0, floatColor); floatColorVec1 = vec_ld(11, floatColor); floatColorVec0 = vec_perm(floatColorVec0,floatColorVec0,floatColorVecPerm); for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) { int clip = 0; vec_t dist0, dist1, dist2; dist0 = origin0 - tess.xyz[i][0]; dist1 = origin1 - tess.xyz[i][1]; dist2 = origin2 - tess.xyz[i][2]; backEnd.pc.c_dlightVertexes++; texCoords0 = 0.5f + dist0 * scale; texCoords1 = 0.5f + dist1 * scale; if( !r_dlightBacks->integer && // dist . tess.normal[i] ( dist0 * tess.normal[i][0] + dist1 * tess.normal[i][1] + dist2 * tess.normal[i][2] ) < 0.0f ) { clip = 63; } else { if ( texCoords0 < 0.0f ) { clip |= 1; } else if ( texCoords0 > 1.0f ) { clip |= 2; } if ( texCoords1 < 0.0f ) { clip |= 4; } else if ( texCoords1 > 1.0f ) { clip |= 8; } texCoords[0] = texCoords0; texCoords[1] = texCoords1; // modulate the strength based on the height and color if ( dist2 > radius ) { clip |= 16; modulate = 0.0f; } else if ( dist2 < -radius ) { clip |= 32; modulate = 0.0f; } else { dist2 = Q_fabs(dist2); if ( dist2 < radius * 0.5f ) { modulate = 1.0f; } else { modulate = 2.0f * (radius - dist2) * scale; } } } clipBits[i] = clip; modulateVec = vec_ld(0,(float *)&modulate); modulateVec = vec_perm(modulateVec,modulateVec,modulatePerm); colorVec = vec_madd(floatColorVec0,modulateVec,zero); colorInt = vec_cts(colorVec,0); // RGBx colorShort = vec_pack(colorInt,colorInt); // RGBxRGBx colorChar = vec_packsu(colorShort,colorShort); // RGBxRGBxRGBxRGBx colorChar = vec_sel(colorChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255 vec_ste((vector unsigned int)colorChar,0,(unsigned int *)colors); // store color } // build a list of triangles that need light numIndexes = 0; for ( i = 0 ; i < tess.numIndexes ; i += 3 ) { int a, b, c; a = tess.indexes[i]; b = tess.indexes[i+1]; c = tess.indexes[i+2]; if ( clipBits[a] & clipBits[b] & clipBits[c] ) { continue; // not lighted } hitIndexes[numIndexes] = a; hitIndexes[numIndexes+1] = b; hitIndexes[numIndexes+2] = c; numIndexes += 3; } if ( !numIndexes ) { continue; } qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); GL_Bind( tr.dlightImage ); // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // where they aren't rendered if ( dl->additive ) { GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); } else { GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); } R_DrawElements( numIndexes, hitIndexes ); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; } }
static void ProjectDlightTexture_scalar( void ) { int i, l; vec3_t origin; float *texCoords; byte *colors; byte clipBits[SHADER_MAX_VERTEXES]; float texCoordsArray[SHADER_MAX_VERTEXES][2]; byte colorArray[SHADER_MAX_VERTEXES][4]; unsigned hitIndexes[SHADER_MAX_INDEXES]; int numIndexes; float scale; float radius; vec3_t floatColor; float modulate = 0.0f; if ( !backEnd.refdef.num_dlights ) { return; } for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { dlight_t *dl; if ( !( tess.dlightBits & ( 1 << l ) ) ) { continue; // this surface definately doesn't have any of this light } texCoords = texCoordsArray[0]; colors = colorArray[0]; dl = &backEnd.refdef.dlights[l]; VectorCopy( dl->transformed, origin ); radius = dl->radius; scale = 1.0f / radius; if(r_greyscale->integer) { float luminance; luminance = (dl->color[0] * 255.0f + dl->color[1] * 255.0f + dl->color[2] * 255.0f) / 3; floatColor[0] = floatColor[1] = floatColor[2] = luminance; } else { floatColor[0] = dl->color[0] * 255.0f; floatColor[1] = dl->color[1] * 255.0f; floatColor[2] = dl->color[2] * 255.0f; } for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) { int clip = 0; vec3_t dist; VectorSubtract( origin, tess.xyz[i], dist ); backEnd.pc.c_dlightVertexes++; texCoords[0] = 0.5f + dist[0] * scale; texCoords[1] = 0.5f + dist[1] * scale; if( !r_dlightBacks->integer && // dist . tess.normal[i] ( dist[0] * tess.normal[i][0] + dist[1] * tess.normal[i][1] + dist[2] * tess.normal[i][2] ) < 0.0f ) { clip = 63; } else { if ( texCoords[0] < 0.0f ) { clip |= 1; } else if ( texCoords[0] > 1.0f ) { clip |= 2; } if ( texCoords[1] < 0.0f ) { clip |= 4; } else if ( texCoords[1] > 1.0f ) { clip |= 8; } texCoords[0] = texCoords[0]; texCoords[1] = texCoords[1]; // modulate the strength based on the height and color if ( dist[2] > radius ) { clip |= 16; modulate = 0.0f; } else if ( dist[2] < -radius ) { clip |= 32; modulate = 0.0f; } else { dist[2] = Q_fabs(dist[2]); if ( dist[2] < radius * 0.5f ) { modulate = 1.0f; } else { modulate = 2.0f * (radius - dist[2]) * scale; } } } clipBits[i] = clip; colors[0] = myftol(floatColor[0] * modulate); colors[1] = myftol(floatColor[1] * modulate); colors[2] = myftol(floatColor[2] * modulate); colors[3] = 255; } // build a list of triangles that need light numIndexes = 0; for ( i = 0 ; i < tess.numIndexes ; i += 3 ) { int a, b, c; a = tess.indexes[i]; b = tess.indexes[i+1]; c = tess.indexes[i+2]; if ( clipBits[a] & clipBits[b] & clipBits[c] ) { continue; // not lighted } hitIndexes[numIndexes] = a; hitIndexes[numIndexes+1] = b; hitIndexes[numIndexes+2] = c; numIndexes += 3; } if ( !numIndexes ) { continue; } qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); GL_Bind( tr.dlightImage ); // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // where they aren't rendered if ( dl->additive ) { GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); } else { GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); } R_DrawElements( numIndexes, hitIndexes ); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; } }
static void ForwardDlight( void ) { int l; //vec3_t origin; //float scale; float radius; int deformGen; vec5_t deformParams; vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0}; float eyeT = 0; shaderCommands_t *input = &tess; shaderStage_t *pStage = tess.xstages[0]; if ( !backEnd.refdef.num_dlights ) { return; } ComputeDeformValues(&deformGen, deformParams); ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT); for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { dlight_t *dl; shaderProgram_t *sp; vec4_t vector; vec4_t texMatrix; vec4_t texOffTurb; if ( !( tess.dlightBits & ( 1 << l ) ) ) { continue; // this surface definately doesn't have any of this light } dl = &backEnd.refdef.dlights[l]; //VectorCopy( dl->transformed, origin ); radius = dl->radius; //scale = 1.0f / radius; //if (pStage->glslShaderGroup == tr.lightallShader) { int index = pStage->glslShaderIndex; index &= ~LIGHTDEF_LIGHTTYPE_MASK; index |= LIGHTDEF_USE_LIGHT_VECTOR; sp = &tr.lightallShader[index]; } backEnd.pc.c_lightallDraws++; GLSL_BindProgram(sp); GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); GLSL_SetUniformVec3(sp, UNIFORM_VIEWORIGIN, backEnd.viewParms.or.origin); GLSL_SetUniformVec3(sp, UNIFORM_LOCALVIEWORIGIN, backEnd.or.viewOrigin); GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen); if (deformGen != DGEN_NONE) { GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams); GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime); } if ( input->fogNum ) { vec4_t fogColorMask; GLSL_SetUniformVec4(sp, UNIFORM_FOGDISTANCE, fogDistanceVector); GLSL_SetUniformVec4(sp, UNIFORM_FOGDEPTH, fogDepthVector); GLSL_SetUniformFloat(sp, UNIFORM_FOGEYET, eyeT); ComputeFogColorMask(pStage, fogColorMask); GLSL_SetUniformVec4(sp, UNIFORM_FOGCOLORMASK, fogColorMask); } { vec4_t baseColor; vec4_t vertColor; ComputeShaderColors(pStage, baseColor, vertColor, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE); GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, baseColor); GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, vertColor); } if (pStage->alphaGen == AGEN_PORTAL) { GLSL_SetUniformFloat(sp, UNIFORM_PORTALRANGE, tess.shader->portalRange); } GLSL_SetUniformInt(sp, UNIFORM_COLORGEN, pStage->rgbGen); GLSL_SetUniformInt(sp, UNIFORM_ALPHAGEN, pStage->alphaGen); GLSL_SetUniformVec3(sp, UNIFORM_DIRECTEDLIGHT, dl->color); VectorSet(vector, 0, 0, 0); GLSL_SetUniformVec3(sp, UNIFORM_AMBIENTLIGHT, vector); VectorCopy(dl->origin, vector); vector[3] = 1.0f; GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vector); GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, radius); GLSL_SetUniformVec4(sp, UNIFORM_NORMALSCALE, pStage->normalScale); GLSL_SetUniformVec4(sp, UNIFORM_SPECULARSCALE, pStage->specularScale); // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // where they aren't rendered GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); GLSL_SetUniformMat4(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); if (pStage->bundle[TB_DIFFUSEMAP].image[0]) R_BindAnimatedImageToTMU( &pStage->bundle[TB_DIFFUSEMAP], TB_DIFFUSEMAP); // bind textures that are sampled and used in the glsl shader, and // bind whiteImage to textures that are sampled but zeroed in the glsl shader // // alternatives: // - use the last bound texture // -> costs more to sample a higher res texture then throw out the result // - disable texture sampling in glsl shader with #ifdefs, as before // -> increases the number of shaders that must be compiled // if (pStage->bundle[TB_NORMALMAP].image[0]) { R_BindAnimatedImageToTMU( &pStage->bundle[TB_NORMALMAP], TB_NORMALMAP); } else if (r_normalMapping->integer) GL_BindToTMU( tr.whiteImage, TB_NORMALMAP ); if (pStage->bundle[TB_SPECULARMAP].image[0]) { R_BindAnimatedImageToTMU( &pStage->bundle[TB_SPECULARMAP], TB_SPECULARMAP); } else if (r_specularMapping->integer) GL_BindToTMU( tr.whiteImage, TB_SPECULARMAP ); { vec4_t enableTextures; VectorSet4(enableTextures, 0.0f, 0.0f, 0.0f, 0.0f); GLSL_SetUniformVec4(sp, UNIFORM_ENABLETEXTURES, enableTextures); } if (r_dlightMode->integer >= 2) { GL_SelectTexture(TB_SHADOWMAP); GL_Bind(tr.shadowCubemaps[l]); GL_SelectTexture(0); } ComputeTexMods( pStage, TB_DIFFUSEMAP, texMatrix, texOffTurb ); GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, texMatrix); GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, texOffTurb); GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, pStage->bundle[0].tcGen); // // draw // if (input->multiDrawPrimitives) { R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); } else { R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); } backEnd.pc.c_totalIndexes += tess.numIndexes; backEnd.pc.c_dlightIndexes += tess.numIndexes; backEnd.pc.c_dlightVertexes += tess.numVertexes; } }
/* * RB_GLSL_IterateStagesGeneric * Iterate over each stage of a shader */ static void RB_GLSL_IterateStagesGeneric(shaderCommands_t *input) { int stage; for(stage = 0; stage < MAX_SHADER_STAGES; stage++) { shaderStage_t *pStage = tess.xstages[stage]; glslProgram_t *program; if (!pStage || pStage->program == tr.skipProgram) break; /* set state */ GL_State(pStage->stateBits); /* * this is an ugly hack to work around a GeForce driver * bug with multitexture and clip planes */ if (backEnd.viewParms.isPortal) qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); if (pStage->program) /* use specified program */ R_GLSL_UseProgram(pStage->program); else /* use default program */ R_GLSL_UseProgram(tr.defaultProgram); program = tr.programs[glState.currentProgram]; /* alphaGen */ if (program->u_AlphaGen > -1) R_GLSL_SetUniform_AlphaGen(program, pStage->alphaGen); /* ambient light */ if (program->u_AmbientLight > -1) R_GLSL_SetUniform_AmbientLight(program, backEnd.currentEntity->ambientLight); /* dynamic light */ if (program->u_DynamicLight > -1) R_GLSL_SetUniform_DynamicLight(program, backEnd.currentEntity->dynamicLight); /* light distance */ if (program->u_LightDistance > -1) R_GLSL_SetUniform_LightDistance(program, backEnd.currentEntity->lightDistance); /* rgbGen */ if (program->u_ColorGen > -1) R_GLSL_SetUniform_ColorGen(program, pStage->rgbGen); /* constant color */ if (program->u_ConstantColor > -1) R_GLSL_SetUniform_ConstantColor(program, pStage->constantColor); /* directed light */ if (program->u_DirectedLight > -1) R_GLSL_SetUniform_DirectedLight(program, backEnd.currentEntity->directedLight); /* entity color */ if (program->u_EntityColor > -1) R_GLSL_SetUniform_EntityColor(program, backEnd.currentEntity->e.shaderRGBA); /* fog color */ if (program->u_FogColor > -1 && tess.fogNum) R_GLSL_SetUniform_FogColor(program, (tr.world->fogs + tess.fogNum)->colorInt); /* greyscale */ if (program->u_Greyscale > -1) R_GLSL_SetUniform_Greyscale(program, r_greyscale->integer); /* identity light */ if (program->u_IdentityLight > -1) R_GLSL_SetUniform_IdentityLight(program, tr.identityLight); /* light direction */ if (program->u_LightDirection > -1) R_GLSL_SetUniform_LightDirection(program, backEnd.currentEntity->lightDir); /* model view matrix */ if (program->u_ModelViewMatrix > -1) R_GLSL_SetUniform_ModelViewMatrix(program, glState.currentModelViewMatrix); /* model view projection matrix */ if (program->u_ModelViewProjectionMatrix > -1) R_GLSL_SetUniform_ModelViewProjectionMatrix(program, glState.currentModelViewProjectionMatrix); /* projection matrix */ if (program->u_ProjectionMatrix > -1) R_GLSL_SetUniform_ProjectionMatrix(program, glState.currentProjectionMatrix); /* texture coordinates 0 */ if (program->u_TCGen0 > -1) R_GLSL_SetUniform_TCGen0(program, pStage->bundle[0].tcGen); /* texture coordinates 1 */ if (program->u_TCGen1 > -1) R_GLSL_SetUniform_TCGen1(program, pStage->bundle[1].tcGen); /* tex env */ if (program->u_TexEnv > -1) { if (r_lightmap->integer) R_GLSL_SetUniform_TexEnv(program, GL_REPLACE); else R_GLSL_SetUniform_TexEnv(program, input->shader->multitextureEnv); } /* texture unit 0 */ if (program->u_Texture0 > -1 && pStage->bundle[0].image[0]) { GL_SelectTexture(0); if (pStage->bundle[0].vertexLightmap && ((r_vertexLight->integer && !r_uiFullScreen->integer) || glConfig.hardwareType == GLHW_PERMEDIA2) && r_lightmap->integer) GL_Bind(tr.whiteImage); else R_BindAnimatedImage(&pStage->bundle[0]); } /* texture unit 1 */ if (program->u_Texture1 > -1 && pStage->bundle[1].image[0]) { GL_SelectTexture(1); qglEnable(GL_TEXTURE_2D); R_BindAnimatedImage(&pStage->bundle[1]); } /* texture unit 2 */ if (program->u_Texture2 > -1 && pStage->bundle[2].image[0]) { GL_SelectTexture(2); qglEnable(GL_TEXTURE_2D); R_BindAnimatedImage(&pStage->bundle[2]); } /* texture unit 3 */ if (program->u_Texture3 > -1 && pStage->bundle[3].image[0]) { GL_SelectTexture(3); qglEnable(GL_TEXTURE_2D); R_BindAnimatedImage(&pStage->bundle[3]); } /* texture unit 4 */ if (program->u_Texture4 > -1 && pStage->bundle[4].image[0]) { GL_SelectTexture(4); qglEnable(GL_TEXTURE_2D); R_BindAnimatedImage(&pStage->bundle[4]); } /* texture unit 5 */ if (program->u_Texture5 > -1 && pStage->bundle[5].image[0]) { GL_SelectTexture(5); qglEnable(GL_TEXTURE_2D); R_BindAnimatedImage(&pStage->bundle[5]); } /* texture unit 6 */ if (program->u_Texture6 > -1 && pStage->bundle[6].image[0]) { GL_SelectTexture(6); qglEnable(GL_TEXTURE_2D); R_BindAnimatedImage(&pStage->bundle[6]); } /* texture unit 7 */ if (program->u_Texture7 > -1 && pStage->bundle[7].image[0]) { GL_SelectTexture(7); qglEnable(GL_TEXTURE_2D); R_BindAnimatedImage(&pStage->bundle[7]); } /* time */ if (program->u_Time > -1) R_GLSL_SetUniform_Time(program, input->shaderTime); /* view origin */ if (program->u_ViewOrigin > -1) R_GLSL_SetUniform_ViewOrigin(program, backEnd.or.viewOrigin); /* draw */ R_DrawElements(input->numIndexes, input->indexes); /* disable texture unit 7 */ if (program->u_Texture7 > -1) qglDisable(GL_TEXTURE_2D); /* disable texture unit 6 */ if (program->u_Texture6 > -1) { GL_SelectTexture(6); qglDisable(GL_TEXTURE_2D); } /* disable texture unit 5 */ if (program->u_Texture5 > -1) { GL_SelectTexture(5); qglDisable(GL_TEXTURE_2D); } /* disable texture unit 4 */ if (program->u_Texture4 > -1) { GL_SelectTexture(4); qglDisable(GL_TEXTURE_2D); } /* disable texture unit 3 */ if (program->u_Texture3 > -1) { GL_SelectTexture(3); qglDisable(GL_TEXTURE_2D); } /* disable texture unit 2 */ if (program->u_Texture2 > -1) { GL_SelectTexture(2); qglDisable(GL_TEXTURE_2D); } /* disable texture unit 1 */ if (program->u_Texture1 > -1) { GL_SelectTexture(1); qglDisable(GL_TEXTURE_2D); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); } /* switch to texture unit 0 */ GL_SelectTexture(0); /* allow skipping out to show just lightmaps during development */ if (r_lightmap->integer && (pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap || pStage->bundle[0].vertexLightmap)) break; } /* switch to standard rendering pipeline */ R_GLSL_UseProgram(0); }
void R_DrawParticles (void) { particle_t *p, *kill; float grav; int i; float time2, time3; float time1; float dvel, blend, blend1; float frametime; vec3_t up, right, neworg; float scale, sscale; ParticleEmitter_t *ekill, *emt; if (gl_wireframe.value) return; glFogfv(GL_FOG_COLOR, color_black); //Done in actual function now (stops "triangle effect") - Eradicator glEnable (GL_BLEND); glBlendFunc (GL_ONE, GL_ONE); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER,0.01); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glDepthMask(0); VectorScale (vup, 1, up); VectorScale (vright, 1, right); glMatrixMode(GL_TEXTURE); frametime = cl.time - cl.oldtime; time3 = frametime * 15; time2 = frametime * 10; // 15; time1 = frametime * 5; grav = frametime * sv_gravity.value * 0.05; dvel = 4*frametime; //remove expired emitters for ( ;; ) { ekill = active_emitters; if (ekill && ekill->die < cl.time) { active_emitters = ekill->next; ekill->next = free_emitters; free_emitters = ekill; continue; } break; } //Do the particle logic/drawing for (emt=active_emitters ; emt ; emt=emt->next) { for ( ;; ) { ekill = emt->next; //XYZ if (ekill && (ekill->die < cl.time)) { emt->next = ekill->next; ekill->next = free_emitters; free_emitters = ekill; continue; } break; } if (emt->nexttick < cl.time) { vec3_t length; VectorSubtract(emt->origin, r_refdef.vieworg, length); //dont emit if we are to far away to see it if (Length(length) < 600.0f) { for (i=0; i<emt->count; i++) { InitParticleFromEffect(emt->effect,emt->origin); } } emt->nexttick = cl.time + emt->tick; } } //remove expired particles for ( ;; ) { kill = active_particles; if (kill && kill->die < cl.time) { active_particles = kill->next; kill->next = free_particles; free_particles = kill; continue; } break; } //Do the particle logic/drawing for (p=active_particles ; p ; p=p->next) { for ( ;; ) { kill = p->next; //XYZ if (kill && ((kill->die < cl.time) || (kill->numbounces <= 0))) { p->next = kill->next; kill->next = free_particles; free_particles = kill; continue; } break; } scale = p->size; p->size += p->growspeed*frametime; //calculate color based on life ... blend = (p->die-cl.time)/p->lifetime; blend1 = 1-blend; for (i=0; i<3; i++) { p->color[i] = p->startcolor[i] * blend + p->endcolor[i] * blend1; } if ((p->die - cl.time) < 0.5) { float fade = 2*(p->die - cl.time); glColor4f(p->color[0]*fade, p->color[1]*fade, p->color[2]*fade, fade); } else { glColor3fv(&p->color[0]); } GL_Bind(p->texture); glBlendFunc (p->srcblend, p->dstblend); //Align with velocity if (p->velaligned){ float lscale; VectorCopy (p->vel, up); VectorNormalize(up); CrossProduct(vpn,up,right); VectorNormalize(right); lscale = (Length(p->vel)*p->velscale); VectorScale(up,lscale,up); } else { VectorCopy (vup, up); VectorCopy (vright, right); } glLoadIdentity(); glTranslatef(0.5,0.5,0); glRotatef(p->rot,0,0,1); glTranslatef(-0.5,-0.5,0); sscale = -scale/4; VectorMA(p->org,sscale,up,neworg); VectorMA(neworg,sscale,right,neworg); // draw the particle as two triangles scale /= 2; glBegin(GL_TRIANGLE_FAN); glTexCoord2f (0,0); glVertex3fv (neworg); glTexCoord2f (0,1); glVertex3f (neworg[0] + up[0]*scale, neworg[1] + up[1]*scale, neworg[2] + up[2]*scale); glTexCoord2f (1,1); glVertex3f (neworg[0] + up[0]*scale + right[0]*scale, neworg[1] + up[1]*scale + right[1]*scale, neworg[2] + up[2]*scale + right[2]*scale); glTexCoord2f (1,0); glVertex3f (neworg[0] + right[0]*scale, neworg[1] + right[1]*scale, neworg[2] + right[2]*scale); glEnd(); scale *= 2; //calculate new position/rotation neworg[0] = p->org[0]+p->vel[0]*frametime; neworg[1] = p->org[1]+p->vel[1]*frametime; neworg[2] = p->org[2]+p->vel[2]*frametime; p->rot = p->rot+p->rspeed*frametime; //do collision detection { trace_t trace; float d; memset (&trace, 0, sizeof(trace)); trace.fraction = 1; SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, p->org, neworg, &trace); if (trace.fraction < 1) { vec3_t tangent; //calc reflection vector d = DotProduct (p->vel, trace.plane.normal); VectorMA (p->vel, -2*d, trace.plane.normal, p->vel); VectorScale(p->vel,0.33,p->vel); VectorCopy(trace.endpos,p->org); //XYZ p->numbounces--; if (p->spawn) { CrossProduct(trace.plane.normal,p->vel,tangent); if (p->spawn->align == align_surf) { R_SpawnDecal(p->org, trace.plane.normal, tangent, p->spawn); } else { InitParticleFromEffect(p->spawn, p->org); } } } else { VectorCopy(neworg,p->org); } } for (i=0; i<3; i++) { p->vel[i] += p->gravity[i]*frametime; } for (i=0; i<3; i++) { p->vel[i] *= p->drag[i]; } } glDepthMask(1); glDisable (GL_BLEND); glDisable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER,0.666); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //XYZ glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glFogfv(GL_FOG_COLOR, fog_color); //Done in actual function now (stops "triangle effect") - Eradicator }
void CRainSystem::Render(void) { int i; SParticle *item; vec4_t forward, down, left; vec3_t pos; // float percent; float radius; CWorldEffectsSystem::Render(); if (mFadeAlpha <= 0.0) { return; } VectorScale(backEnd.viewParms.or.axis[0], 1, forward); // forward VectorScale(backEnd.viewParms.or.axis[1], 0.2f, left); // left down[0] = 0 - mWindDirection[0] * mRainHeight * mWindAngle; down[1] = 0 - mWindDirection[1] * mRainHeight * mWindAngle; down[2] = -mRainHeight; GL_Bind(mImage); GL_State(GLS_ALPHA); qglEnable(GL_TEXTURE_2D); qglDisable(GL_CULL_FACE); qglMatrixMode(GL_MODELVIEW); qglPushMatrix(); qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); item = mRainList; qglBegin(GL_TRIANGLES ); for(i=mMaxRain;i;i--) { /* percent = (item->pos[1] -(-20.0)) / (20.0 - (-20.0)); percent *= forward[2]; if (percent < 0.0) { radius = 10 * (percent + 1.0); } else { radius = 10 * (1.0 - percent); }*/ radius = item->pos[1]; if (item->pos[2] < 0.0) { // radius *= 1.0 - (item->pos[2] / 40.0); float alpha = mAlpha * (item->pos[1] / -item->pos[2]); if (alpha > mAlpha) { alpha = mAlpha; } qglColor4f(1.0, 1.0, 1.0, alpha * mFadeAlpha); } else { qglColor4f(1.0, 1.0, 1.0, mAlpha * mFadeAlpha); // radius *= 1.0 + (item->pos[2] / 20.0); } pos[0] = sin(item->pos[0]) * radius + (item->pos[2] * mWindDirection[0] * mWindAngle); pos[1] = cos(item->pos[0]) * radius + (item->pos[2] * mWindDirection[1] * mWindAngle); pos[2] = item->pos[2]; qglTexCoord2f(1.0, 0.0); qglVertex3f(pos[0], pos[1], pos[2]); qglTexCoord2f(0.0, 0.0); qglVertex3f(pos[0] + left[0], pos[1] + left[1], pos[2] + left[2]); qglTexCoord2f(0.0, 1.0); qglVertex3f(pos[0] + down[0] + left[0], pos[1] + down[1] + left[1], pos[2] + down[2] + left[2]); item++; } qglEnd(); qglEnable(GL_CULL_FACE); qglPopMatrix(); }
CRainSystem::CRainSystem(int maxRain) : mMaxRain(maxRain), mNextWindGust(0), mRainHeight(5), mAlpha(0.15f), mWindAngle(1.0f), mFadeAlpha(0.0f), mIsRaining(false) { char name[256]; unsigned char *data, *pos; int width, height; int x, y; mSpread[0] = (float)(M_PI*2.0); // angle spread mSpread[1] = 20.0f; // radius spread mSpread[2] = 20.0f; // z spread mMinVelocity[0] = 0.1f; mMaxVelocity[0] = -0.1f; mMinVelocity[1] = 0.1f; mMaxVelocity[1] = -0.1f; mMinVelocity[2] = -60.0; mMaxVelocity[2] = -50.0; mWindDuration = 15; mWindLow = 50; mWindMin = 0.01f; mWindMax = 0.05f; mWindChange = 0; mWindDirection[0] = mWindDirection[1] = mWindDirection[2] = 0.0; mRainList = new SParticle[mMaxRain]; sprintf(name, "gfx/world/rain.tga"); R_LoadImage( name, &data, &width, &height ); if (!data) { ri.Error (ERR_DROP, "Could not load %s", name); } pos = data; for(y=0;y<height;y++) { for(x=0;x<width;x++) { pos[3] = pos[0]; pos += 4; } } mImage = R_CreateImage(name, data, width, height, false, false, false, GL_CLAMP); GL_Bind(mImage); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); Init(); }
/* ================ Tess_StageIteratorSky All of the visible sky triangles are in tess Other things could be stuck in here, like birds in the sky, etc ================ */ void Tess_StageIteratorSky( void ) { // log this call if ( r_logFile->integer ) { // don't just call LogComment, or we will get // a call to va() every frame! GLimp_LogComment( va ( "--- Tess_StageIteratorSky( %s, %i vertices, %i triangles ) ---\n", tess.surfaceShader->name, tess.numVertexes, tess.numIndexes / 3 ) ); } if ( r_fastsky->integer ) { return; } // trebor: HACK why does this happen with cg_draw2D 0 ? if ( tess.stageIteratorFunc2 == NULL ) { //tess.stageIteratorFunc2 = Tess_StageIteratorGeneric; ri.Error( ERR_FATAL, "tess.stageIteratorFunc == NULL" ); } GL_Cull(CT_TWO_SIDED); if ( tess.stageIteratorFunc2 == &Tess_StageIteratorDepthFill ) { // go through all the polygons and project them onto // the sky box to see which blocks on each side need // to be drawn Tess_ClipSkyPolygons(); // generate the vertexes for all the clouds, which will be drawn // by the generic shader routine BuildCloudData(); if ( tess.numVertexes || tess.multiDrawPrimitives ) { tess.stageIteratorFunc2(); } } else { if ( tess.stageIteratorFunc2 == &Tess_StageIteratorGBuffer ) { R_BindFBO( tr.geometricRenderFBO ); } // go through all the polygons and project them onto // the sky box to see which blocks on each side need // to be drawn Tess_ClipSkyPolygons(); // r_showSky will let all the sky blocks be drawn in // front of everything to allow developers to see how // much sky is getting sucked in if ( r_showSky->integer ) { glDepthRange( 0.0, 0.0 ); } else { glDepthRange( 1.0, 1.0 ); } // draw the outer skybox if ( tess.surfaceShader->sky.outerbox && tess.surfaceShader->sky.outerbox != tr.blackCubeImage ) { #if 1 R_BindVBO( tess.vbo ); R_BindIBO( tess.ibo ); gl_skyboxShader->BindProgram(); gl_skyboxShader->SetUniform_ViewOrigin( backEnd.viewParms.orientation.origin ); // in world space gl_skyboxShader->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); gl_skyboxShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); gl_skyboxShader->SetRequiredVertexPointers(); // bind u_ColorMap GL_SelectTexture( 0 ); GL_Bind( tess.surfaceShader->sky.outerbox ); DrawSkyBox( tess.surfaceShader ); #endif } // generate the vertexes for all the clouds, which will be drawn // by the generic shader routine BuildCloudData(); if ( tess.numVertexes || tess.multiDrawPrimitives ) { tess.stageIteratorFunc2(); } // Tr3B: TODO draw the inner skybox? if ( tess.stageIteratorFunc2 == Tess_StageIteratorGBuffer ) { R_BindNullFBO(); } if ( tess.stageIteratorFunc2 != Tess_StageIteratorDepthFill ) { // back to standard depth range glDepthRange( 0.0, 1.0 ); // note that sky was drawn so we will draw a sun later backEnd.skyRenderedThisView = qtrue; } } }
void R_DrawSkyBox (void) { #ifdef ENABLE_HYG_STARS R_DrawStars(); // jitstarviewer #else int i; if (fogenabled) // jitfog qgl.Disable(GL_FOG); if (skyrotate) { // check for no sky at all for (i = 0; i < 6; ++i) { if (skymins[0][i] < skymaxs[0][i] && skymins[1][i] < skymaxs[1][i]) break; } if (i == 6) return; // nothing visible } qgl.PushMatrix(); qgl.Translatef(r_origin[0], r_origin[1], r_origin[2]); qgl.Rotatef(r_newrefdef.time * skyrotate, skyaxis[0], skyaxis[1], skyaxis[2]); if (fogenabled && sky_images[0] == r_whitetexture) // jitfog { qgl.Color3fv(fogcolor); GLSTATE_ENABLE_BLEND GL_TexEnv(GL_MODULATE); } for (i = 0; i < 6; ++i) { if (skyrotate) { // hack, forces full sky to draw when rotating skymins[0][i] = -1; skymins[1][i] = -1; skymaxs[0][i] = 1; skymaxs[1][i] = 1; } if (skymins[0][i] >= skymaxs[0][i] || skymins[1][i] >= skymaxs[1][i]) continue; GL_Bind(sky_images[skytexorder[i]]->texnum); qgl.Begin(GL_QUADS); MakeSkyVec(skymins[0][i], skymins[1][i], i); MakeSkyVec(skymins[0][i], skymaxs[1][i], i); MakeSkyVec(skymaxs[0][i], skymaxs[1][i], i); MakeSkyVec(skymaxs[0][i], skymins[1][i], i); qgl.End(); } qgl.PopMatrix(); if (fogenabled) // jitfog { qgl.Color3f(1, 1, 1); GLSTATE_DISABLE_BLEND qgl.Enable(GL_FOG); } #endif }
/* ================= RB_ShadowTessEnd triangleFromEdge[ v1 ][ v2 ] set triangle from edge( v1, v2, tri ) if ( facing[ triangleFromEdge[ v1 ][ v2 ] ] && !facing[ triangleFromEdge[ v2 ][ v1 ] ) { } ================= */ void RB_ShadowTessEnd( void ) { int i; int numTris; vec3_t lightDir; GLboolean rgba[4]; // we can only do this if we have enough space in the vertex buffers if ( tess.numVertexes >= SHADER_MAX_VERTEXES / 2 ) { return; } if ( glConfig.stencilBits < 4 ) { return; } VectorCopy( backEnd.currentEntity->lightDir, lightDir ); // project vertexes away from light direction for ( i = 0 ; i < tess.numVertexes ; i++ ) { VectorMA( tess.xyz[i], -512, lightDir, tess.xyz[i+tess.numVertexes] ); } // decide which triangles face the light Com_Memset( numEdgeDefs, 0, 4 * tess.numVertexes ); numTris = tess.numIndexes / 3; for ( i = 0 ; i < numTris ; i++ ) { int i1, i2, i3; vec3_t d1, d2, normal; float *v1, *v2, *v3; float d; i1 = tess.indexes[ i*3 + 0 ]; i2 = tess.indexes[ i*3 + 1 ]; i3 = tess.indexes[ i*3 + 2 ]; v1 = tess.xyz[ i1 ]; v2 = tess.xyz[ i2 ]; v3 = tess.xyz[ i3 ]; VectorSubtract( v2, v1, d1 ); VectorSubtract( v3, v1, d2 ); CrossProduct( d1, d2, normal ); d = DotProduct( normal, lightDir ); if ( d > 0 ) { facing[ i ] = 1; } else { facing[ i ] = 0; } // create the edges R_AddEdgeDef( i1, i2, facing[ i ] ); R_AddEdgeDef( i2, i3, facing[ i ] ); R_AddEdgeDef( i3, i1, facing[ i ] ); } // draw the silhouette edges GL_Bind( tr.whiteImage ); qglEnable( GL_CULL_FACE ); GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); qglColor3f( 0.2f, 0.2f, 0.2f ); // don't write to the color buffer qglGetBooleanv(GL_COLOR_WRITEMASK, rgba); qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); qglEnable( GL_STENCIL_TEST ); qglStencilFunc( GL_ALWAYS, 1, 255 ); // mirrors have the culling order reversed if ( backEnd.viewParms.isMirror ) { qglCullFace( GL_FRONT ); qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); R_RenderShadowEdges(); qglCullFace( GL_BACK ); qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); R_RenderShadowEdges(); } else { qglCullFace( GL_BACK ); qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); R_RenderShadowEdges(); qglCullFace( GL_FRONT ); qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); R_RenderShadowEdges(); } // reenable writing to the color buffer qglColorMask(rgba[0], rgba[1], rgba[2], rgba[3]); }
void Draw_ScaledPic(int x, int y, float scale, float alpha, char *pic, float red, float green, float blue, qboolean fixcoords, qboolean repscale) { float xoff, yoff; image_t *gl; gl = Draw_FindPic(pic); if (!gl) { ri.Con_Printf(PRINT_ALL, "Can't find pic: %s\n", pic); return; } if (scrap_dirty) Scrap_Upload(); if (((gl_config.renderer == GL_RENDERER_MCD) || (gl_config.renderer & GL_RENDERER_RENDITION)) && !gl->has_alpha) qglDisable(GL_ALPHA_TEST); /* add alpha support */ { qglDisable(GL_ALPHA_TEST); qglBindTexture(GL_TEXTURE_2D, gl->texnum); GL_TexEnv(GL_MODULATE); qglColor4f(red, green, blue, alpha); qglEnable(GL_BLEND); qglDepthMask(false); } /* NOTE: replace this with shaders as soon as they are supported */ if (repscale) scale *= gl->replace_scale; /* scale down if replacing a pcx image */ if (fixcoords) { /* Knightmare- whether to adjust coordinates for scaling */ xoff = (gl->width * scale - gl->width) / 2; yoff = (gl->height * scale - gl->height) / 2; GL_Bind(gl->texnum); qglBegin(GL_QUADS); qglTexCoord2f(gl->sl, gl->tl); qglVertex2f(x - xoff, y - yoff); qglTexCoord2f(gl->sh, gl->tl); qglVertex2f(x + gl->width + xoff, y - yoff); qglTexCoord2f(gl->sh, gl->th); qglVertex2f(x + gl->width + xoff, y + gl->height + yoff); qglTexCoord2f(gl->sl, gl->th); qglVertex2f(x - xoff, y + gl->height + yoff); qglEnd(); } else { xoff = gl->width * scale - gl->width; yoff = gl->height * scale - gl->height; GL_Bind(gl->texnum); qglBegin(GL_QUADS); qglTexCoord2f(gl->sl, gl->tl); qglVertex2f(x, y); qglTexCoord2f(gl->sh, gl->tl); qglVertex2f(x + gl->width + xoff, y); qglTexCoord2f(gl->sh, gl->th); qglVertex2f(x + gl->width + xoff, y + gl->height + yoff); qglTexCoord2f(gl->sl, gl->th); qglVertex2f(x, y + gl->height + yoff); qglEnd(); } /* add alpha support */ { qglDepthMask(true); GL_TexEnv(GL_REPLACE); qglDisable(GL_BLEND); qglColor4f(1, 1, 1, 1); qglEnable(GL_ALPHA_TEST); } if (((gl_config.renderer == GL_RENDERER_MCD) || (gl_config.renderer & GL_RENDERER_RENDITION)) && !gl->has_alpha) qglEnable(GL_ALPHA_TEST); }
/* ================= R_Bloom_GeneratexDiamonds ================= */ void R_Bloom_GeneratexDiamonds( refdef_t *fd ) { int i, j; static float intensity; //set up sample size workspace qglViewport( 0, 0, sample_width, sample_height ); qglMatrixMode( GL_PROJECTION ); qglLoadIdentity (); qglOrtho(0, sample_width, sample_height, 0, -10, 100); qglMatrixMode( GL_MODELVIEW ); qglLoadIdentity (); //copy small scene into r_bloomeffecttexture GL_Bind(r_bloomeffecttexture->texnum); qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height); //start modifying the small scene corner qglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); GL_Enable(GL_BLEND); //Com_Printf("%d %d\n", r_bloom_darken->value, fd->bloomdarken); //darkening passes if( r_bloom_darken->value ) { GL_BlendFunc(GL_DST_COLOR, GL_ZERO); GL_TexEnv(GL_MODULATE); for(i=0; i< r_bloom_darken->value ; i++) { R_Bloom_SamplePass( 0, 0 ); } qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height); } //bluring passes //GL_BlendFunc(GL_ONE, GL_ONE); GL_BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); if( r_bloom_diamond_size->value > 7 || r_bloom_diamond_size->value <= 3) { if( (int)r_bloom_diamond_size->value != 8 ) Cvar_SetValue( "r_bloom_diamond_size", 8 ); for(i=0; i<r_bloom_diamond_size->value; i++) { for(j=0; j<r_bloom_diamond_size->value; j++) { intensity = /*bc mod*/(fd->bloomintensity + r_bloom_intensity->value) * 0.3 * Diamond8x[i][j]; if( intensity < r_bloom_threshold->value ) continue; qglColor4f( intensity, intensity, intensity, 1.0); R_Bloom_SamplePass( i-4, j-4 ); } } } else if( r_bloom_diamond_size->value > 5 ) { if( r_bloom_diamond_size->value != 6 ) Cvar_SetValue( "r_bloom_diamond_size", 6 ); for(i=0; i<r_bloom_diamond_size->value; i++) { for(j=0; j<r_bloom_diamond_size->value; j++) { intensity = /*bc mod*/(fd->bloomintensity + r_bloom_intensity->value) * 0.5 * Diamond6x[i][j]; if( intensity < r_bloom_threshold->value ) continue; qglColor4f( intensity, intensity, intensity, 1.0); R_Bloom_SamplePass( i-3, j-3 ); } } } else if( r_bloom_diamond_size->value > 3 ) { if( (int)r_bloom_diamond_size->value != 4 ) Cvar_SetValue( "r_bloom_diamond_size", 4 ); for(i=0; i<r_bloom_diamond_size->value; i++) { for(j=0; j<r_bloom_diamond_size->value; j++) { intensity = /*bc mod*/(fd->bloomintensity + r_bloom_intensity->value) * 0.8f * Diamond4x[i][j]; if( intensity < r_bloom_threshold->value ) continue; qglColor4f( intensity, intensity, intensity, 1.0); R_Bloom_SamplePass( i-2, j-2 ); } } } qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height); //restore full screen workspace qglViewport( 0, 0, vid.width, vid.height ); qglMatrixMode( GL_PROJECTION ); qglLoadIdentity (); qglOrtho(0, vid.width, vid.height, 0, -10, 100); qglMatrixMode( GL_MODELVIEW ); qglLoadIdentity (); }
static void ProjectDlightTexture( void ) { int l; vec3_t origin; float scale; float radius; int deformGen; vec5_t deformParams; if ( !backEnd.refdef.num_dlights ) { return; } ComputeDeformValues(&deformGen, deformParams); for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { dlight_t *dl; shaderProgram_t *sp; vec4_t vector; if ( !( tess.dlightBits & ( 1 << l ) ) ) { continue; // this surface definately doesn't have any of this light } dl = &backEnd.refdef.dlights[l]; VectorCopy( dl->transformed, origin ); radius = dl->radius; scale = 1.0f / radius; sp = &tr.dlightShader[deformGen == DGEN_NONE ? 0 : 1]; backEnd.pc.c_dlightDraws++; GLSL_BindProgram(sp); GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen); if (deformGen != DGEN_NONE) { GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams); GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime); } vector[0] = dl->color[0]; vector[1] = dl->color[1]; vector[2] = dl->color[2]; vector[3] = 1.0f; GLSL_SetUniformVec4(sp, UNIFORM_COLOR, vector); vector[0] = origin[0]; vector[1] = origin[1]; vector[2] = origin[2]; vector[3] = scale; GLSL_SetUniformVec4(sp, UNIFORM_DLIGHTINFO, vector); GL_Bind( tr.dlightImage ); // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // where they aren't rendered if ( dl->additive ) { GL_State( GLS_ATEST_GT_0 | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); } else { GL_State( GLS_ATEST_GT_0 | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); } if (tess.multiDrawPrimitives) { shaderCommands_t *input = &tess; R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); } else { R_DrawElementsVBO(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex); } backEnd.pc.c_totalIndexes += tess.numIndexes; backEnd.pc.c_dlightIndexes += tess.numIndexes; backEnd.pc.c_dlightVertexes += tess.numVertexes; } }
static void ProjectDlightTexture_altivec( void ) { int i, l; vec_t origin0, origin1, origin2; float texCoords0, texCoords1; vector float floatColorVec0, floatColorVec1; vector float modulateVec, colorVec, zero; vector short colorShort; vector signed int colorInt; vector unsigned char floatColorVecPerm, modulatePerm, colorChar; vector unsigned char vSel = VECCONST_UINT8(0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff); float *texCoords; byte *colors; int *intColors; byte clipBits[SHADER_MAX_VERTEXES]; float texCoordsArray[SHADER_MAX_VERTEXES][2]; byte colorArray[SHADER_MAX_VERTEXES][4]; glIndex_t hitIndexes[SHADER_MAX_INDEXES]; int numIndexes; float scale; float radius; float radiusInverseCubed; float intensity, remainder; vec3_t floatColor; float modulate = 0.0f; qboolean vertexLight; if ( !backEnd.refdef.num_dlights ) { return; } // There has to be a better way to do this so that floatColor // and/or modulate are already 16-byte aligned. floatColorVecPerm = vec_lvsl(0,(float *)floatColor); modulatePerm = vec_lvsl(0,(float *)&modulate); modulatePerm = (vector unsigned char)vec_splat((vector unsigned int)modulatePerm,0); zero = (vector float)vec_splat_s8(0); for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { dlight_t *dl; if ( !( tess.dlightBits & ( 1 << l ) ) ) { continue; // this surface definately doesn't have any of this light } // clear colors Com_Memset( colorArray, 0, sizeof( colorArray ) ); texCoords = texCoordsArray[0]; colors = colorArray[0]; dl = &backEnd.refdef.dlights[l]; origin0 = dl->transformed[0]; origin1 = dl->transformed[1]; origin2 = dl->transformed[2]; radius = dl->radius; scale = 1.0f / radius; radiusInverseCubed = dl->radiusInverseCubed; intensity = dl->intensity; vertexLight = ( ( dl->flags & REF_DIRECTED_DLIGHT ) || ( dl->flags & REF_VERTEX_DLIGHT ) ); // directional lights have max intensity and washout remainder intensity if ( dl->flags & REF_DIRECTED_DLIGHT ) { remainder = intensity * 0.125; } else { remainder = 0.0f; } if(r_greyscale->integer) { float luminance; luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; floatColor[0] = floatColor[1] = floatColor[2] = luminance; } else if(r_greyscale->value) { float luminance; luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; floatColor[0] = LERP(dl->color[0] * 255.0f, luminance, r_greyscale->value); floatColor[1] = LERP(dl->color[1] * 255.0f, luminance, r_greyscale->value); floatColor[2] = LERP(dl->color[2] * 255.0f, luminance, r_greyscale->value); } else { floatColor[0] = dl->color[0] * 255.0f; floatColor[1] = dl->color[1] * 255.0f; floatColor[2] = dl->color[2] * 255.0f; } floatColorVec0 = vec_ld(0, floatColor); floatColorVec1 = vec_ld(11, floatColor); floatColorVec0 = vec_perm(floatColorVec0,floatColorVec0,floatColorVecPerm); for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) { int clip = 0; vec_t dist0, dist1, dist2; dist0 = origin0 - tess.xyz[i][0]; dist1 = origin1 - tess.xyz[i][1]; dist2 = origin2 - tess.xyz[i][2]; backEnd.pc.c_dlightVertexes++; // directional dlight, origin is a directional normal if ( dl->flags & REF_DIRECTED_DLIGHT ) { // twosided surfaces use absolute value of the calculated lighting modulate = intensity * DotProduct( dl->origin, tess.normal[ i ] ); if ( tess.shader->cullType == CT_TWO_SIDED ) { modulate = fabs( modulate ); } modulate += remainder; } // spherical vertex lit dlight else if ( dl->flags & REF_VERTEX_DLIGHT ) { vec3_t dir; dir[ 0 ] = radius - fabs( dist0 ); if ( dir[ 0 ] <= 0.0f ) { continue; } dir[ 1 ] = radius - fabs( dist1 ); if ( dir[ 1 ] <= 0.0f ) { continue; } dir[ 2 ] = radius - fabs( dist2 ); if ( dir[ 2 ] <= 0.0f ) { continue; } modulate = intensity * dir[ 0 ] * dir[ 1 ] * dir[ 2 ] * radiusInverseCubed; } // vertical cylinder dlight else { texCoords0 = 0.5f + dist0 * scale; texCoords1 = 0.5f + dist1 * scale; if( !r_dlightBacks->integer && // dist . tess.normal[i] ( dist0 * tess.normal[i][0] + dist1 * tess.normal[i][1] + dist2 * tess.normal[i][2] ) < 0.0f ) { clip = 63; } else { if ( texCoords0 < 0.0f ) { clip |= 1; } else if ( texCoords0 > 1.0f ) { clip |= 2; } if ( texCoords1 < 0.0f ) { clip |= 4; } else if ( texCoords1 > 1.0f ) { clip |= 8; } texCoords[0] = texCoords0; texCoords[1] = texCoords1; // modulate the strength based on the height and color if ( dist2 > radius ) { clip |= 16; modulate = 0.0f; } else if ( dist2 < -radius ) { clip |= 32; modulate = 0.0f; } else { dist2 = Q_fabs(dist2); if ( dist2 < radius * 0.5f ) { modulate = intensity; } else { modulate = intensity * 2.0f * (radius - dist2) * scale; } } } } clipBits[i] = clip; // optimizations if ( vertexLight && modulate < ( 1.0f / 128.0f ) ) { continue; } else if ( modulate > 1.0f ) { modulate = 1.0f; } // ZTM: FIXME: should probably clamp to 0-255 range before converting to char, // but I don't know how to do altvec stuff or if it's even used anymore modulateVec = vec_ld(0,(float *)&modulate); modulateVec = vec_perm(modulateVec,modulateVec,modulatePerm); colorVec = vec_madd(floatColorVec0,modulateVec,zero); colorInt = vec_cts(colorVec,0); // RGBx colorShort = vec_pack(colorInt,colorInt); // RGBxRGBx colorChar = vec_packsu(colorShort,colorShort); // RGBxRGBxRGBxRGBx colorChar = vec_sel(colorChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255 vec_ste((vector unsigned int)colorChar,0,(unsigned int *)colors); // store color } // build a list of triangles that need light intColors = (int*) colorArray; numIndexes = 0; for ( i = 0 ; i < tess.numIndexes ; i += 3 ) { int a, b, c; a = tess.indexes[i]; b = tess.indexes[i+1]; c = tess.indexes[i+2]; if ( vertexLight ) { if ( !( intColors[ a ] | intColors[ b ] | intColors[ c ] ) ) { continue; } } else { if ( clipBits[a] & clipBits[b] & clipBits[c] ) { continue; // not lighted } } hitIndexes[numIndexes] = a; hitIndexes[numIndexes+1] = b; hitIndexes[numIndexes+2] = c; numIndexes += 3; } if ( !numIndexes ) { continue; } if ( !vertexLight ) { qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); } else { qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); } qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); if ( dl->dlshader ) { shader_t *dls = dl->dlshader; for ( i = 0; i < dls->numUnfoggedPasses; i++ ) { shaderStage_t *stage = dls->stages[i]; R_BindAnimatedImage( &dls->stages[i]->bundle[0] ); GL_State( stage->stateBits | GLS_DEPTHFUNC_EQUAL ); R_DrawElements( numIndexes, hitIndexes ); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; } } else { R_FogOff(); if ( !vertexLight ) { GL_Bind( tr.dlightImage ); } else { GL_Bind( tr.whiteImage ); } // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // where they aren't rendered if ( dl->flags & REF_ADDITIVE_DLIGHT ) { GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); } else { GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); } R_DrawElements( numIndexes, hitIndexes ); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; RB_FogOn(); } } }
void CQuickSpriteSystem::Flush(void) { if (mNextVert==0) { return; } /* if (mUseFog && r_drawfog->integer == 2 && mFogIndex == tr.world->globalFog) { //enable hardware fog when we draw this thing if applicable -rww fog_t *fog = tr.world->fogs + mFogIndex; #ifdef _XBOX qglFogi(GL_FOG_MODE, GL_EXP2); #else qglFogf(GL_FOG_MODE, GL_EXP2); #endif qglFogf(GL_FOG_DENSITY, logtestExp2 / fog->parms.depthForOpaque); qglFogfv(GL_FOG_COLOR, fog->parms.color); qglEnable(GL_FOG); } */ //this should not be needed, since I just wait to disable fog for the surface til after surface sprites are done // // render the main pass // R_BindAnimatedImage( mTexBundle ); GL_State(mGLStateBits); // // set arrays and lock // qglEnableClientState( GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer( 2, GL_FLOAT, 0, mTextureCoords ); qglEnableClientState( GL_COLOR_ARRAY); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, mColors ); qglVertexPointer (3, GL_FLOAT, 16, mVerts); if ( qglLockArraysEXT ) { qglLockArraysEXT(0, mNextVert); GLimp_LogComment( "glLockArraysEXT\n" ); } qglDrawArrays(GL_QUADS, 0, mNextVert); backEnd.pc.c_vertexes += mNextVert; backEnd.pc.c_indexes += mNextVert; backEnd.pc.c_totalIndexes += mNextVert; //only for software fog pass (global soft/volumetric) -rww if (mUseFog && (r_drawfog->integer != 2 || mFogIndex != tr.world->globalFog)) { fog_t *fog = tr.world->fogs + mFogIndex; // // render the fog pass // GL_Bind( tr.fogImage ); GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL ); // // set arrays and lock // qglTexCoordPointer( 2, GL_FLOAT, 0, mFogTextureCoords); // qglEnableClientState( GL_TEXTURE_COORD_ARRAY); // Done above qglDisableClientState( GL_COLOR_ARRAY ); qglColor4ubv((GLubyte *)&fog->colorInt); // qglVertexPointer (3, GL_FLOAT, 16, mVerts); // Done above qglDrawArrays(GL_QUADS, 0, mNextVert); // Second pass from fog backEnd.pc.c_totalIndexes += mNextVert; } // // unlock arrays // if (qglUnlockArraysEXT) { qglUnlockArraysEXT(); GLimp_LogComment( "glUnlockArraysEXT\n" ); } mNextVert=0; }
/* =================== RB_FogPass Blends a fog texture on top of everything else =================== */ static void RB_FogPass( void ) { fog_t *fog; unsigned colorInt; fogType_t fogType; int i; // no world, no fogging if ( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) { return; } if ( r_useGlFog->integer ) { return; } if ( tess.shader->isSky ) { fogType = tr.skyFogType; colorInt = tr.skyFogColorInt; } else { fog = tr.world->fogs + tess.fogNum; // Global fog if ( fog->originalBrushNumber < 0 ) { fogType = backEnd.refdef.fogType; colorInt = backEnd.refdef.fogColorInt; } else { fogType = fog->shader->fogParms.fogType; colorInt = fog->colorInt; } } if ( fogType == FT_NONE ) { return; } // check if any stage is fogged if ( tess.shader->noFog ) { int i; for ( i = 0 ; i < MAX_SHADER_STAGES; i++ ) { shaderStage_t *pStage = tess.xstages[i]; if ( !pStage ) { return; } if ( pStage->isFogged ) { break; } } } qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors ); qglEnableClientState( GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] ); for ( i = 0; i < tess.numVertexes; i++ ) { * ( int * )&tess.svars.colors[i] = colorInt; } RB_CalcFogTexCoords( ( float * ) tess.svars.texcoords[0] ); if ( fogType == FT_LINEAR ) { GL_Bind( tr.linearFogImage ); } else { GL_Bind( tr.fogImage ); } if ( tess.shader->fogPass == FP_EQUAL ) { GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL ); } else { GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); } R_DrawElements( tess.numIndexes, tess.indexes ); }
/* ============= RE_StretchRaw FIXME: not exactly backend Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle. Used for cinematics. ============= */ void RE_StretchRaw( int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty ) { int i, j; int start, end; if ( !tr.registered ) { return; } R_IssuePendingRenderCommands(); if ( tess.numIndexes ) { RB_EndSurface(); } // we definately want to sync every frame for the cinematics qglFinish(); start = 0; if ( r_speeds->integer ) { start = ri.Milliseconds(); } // make sure rows and cols are powers of 2 for ( i = 0 ; ( 1 << i ) < cols ; i++ ) { } for ( j = 0 ; ( 1 << j ) < rows ; j++ ) { } if ( ( 1 << i ) != cols || ( 1 << j ) != rows ) { ri.Error( ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows ); } GL_Bind( tr.scratchImage[client] ); // if the scratchImage isn't in the format we want, specify it as a new texture if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) { tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols; tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows; #ifdef USE_OPENGLES qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); #else qglTexImage2D( GL_TEXTURE_2D, 0, 3, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); #endif qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); } else { if ( dirty ) { // otherwise, just subimage upload it so that drivers can tell we are going to be changing // it and don't try and do a texture compression qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data ); } } if ( r_speeds->integer ) { end = ri.Milliseconds(); ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start ); } RB_SetGL2D(); qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); #ifdef USE_OPENGLES GLfloat tex[] = { 0.5f / cols, 0.5f / rows, ( cols - 0.5f ) / cols , 0.5f / rows, ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows, 0.5f / cols, ( rows - 0.5f ) / rows }; GLfloat vtx[] = { x, y, x+w, y, x+w, y+h, x, y+h }; GLboolean text = qglIsEnabled(GL_TEXTURE_COORD_ARRAY); GLboolean glcol = qglIsEnabled(GL_COLOR_ARRAY); if (glcol) qglDisableClientState(GL_COLOR_ARRAY); if (!text) qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, tex ); qglVertexPointer ( 2, GL_FLOAT, 0, vtx ); qglDrawArrays( GL_TRIANGLE_FAN, 0, 4 ); if (!text) qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); if (glcol) qglEnableClientState(GL_COLOR_ARRAY); #else qglBegin( GL_QUADS ); qglTexCoord2f( 0.5f / cols, 0.5f / rows ); qglVertex2f( x, y ); qglTexCoord2f( ( cols - 0.5f ) / cols, 0.5f / rows ); qglVertex2f( x + w, y ); qglTexCoord2f( ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows ); qglVertex2f( x + w, y + h ); qglTexCoord2f( 0.5f / cols, ( rows - 0.5f ) / rows ); qglVertex2f( x, y + h ); qglEnd(); #endif }
/* ============== R_CalcBones The list of bones[] should only be built and modified from within here ============== */ void R_CalcBones(mdsHeader_t *header, const refEntity_t *refent, int *boneList, int numBones) { int i; int *boneRefs; float torsoWeight; // if the entity has changed since the last time the bones were built, reset them if (memcmp(&lastBoneEntity, refent, sizeof(refEntity_t))) { // different, cached bones are not valid memset(validBones, 0, header->numBones); lastBoneEntity = *refent; // (SA) also reset these counter statics //----(SA) print stats for the complete model (not per-surface) if (r_bonesDebug->integer == 4 && totalrt) { Ren_Print("Lod %.2f verts %4d/%4d tris %4d/%4d (%.2f%%)\n", lodScale, totalrv, totalv, totalrt, totalt, ( float )(100.0 * totalrt) / (float) totalt); } totalrv = totalrt = totalv = totalt = 0; } memset(newBones, 0, header->numBones); if (refent->oldframe == refent->frame) { backlerp = 0; frontlerp = 1; } else { backlerp = refent->backlerp; frontlerp = 1.0f - backlerp; } if (refent->oldTorsoFrame == refent->torsoFrame) { torsoBacklerp = 0; torsoFrontlerp = 1; } else { torsoBacklerp = refent->torsoBacklerp; torsoFrontlerp = 1.0f - torsoBacklerp; } frameSize = (int) (sizeof(mdsFrame_t) + (header->numBones - 1) * sizeof(mdsBoneFrameCompressed_t)); frame = ( mdsFrame_t * )((byte *)header + header->ofsFrames + refent->frame * frameSize); torsoFrame = ( mdsFrame_t * )((byte *)header + header->ofsFrames + refent->torsoFrame * frameSize); oldFrame = ( mdsFrame_t * )((byte *)header + header->ofsFrames + refent->oldframe * frameSize); oldTorsoFrame = ( mdsFrame_t * )((byte *)header + header->ofsFrames + refent->oldTorsoFrame * frameSize); // lerp all the needed bones (torsoParent is always the first bone in the list) cBoneList = frame->bones; cBoneListTorso = torsoFrame->bones; boneInfo = ( mdsBoneInfo_t * )((byte *)header + header->ofsBones); boneRefs = boneList; // Matrix3Transpose(refent->torsoAxis, torsoAxis); #ifdef HIGH_PRECISION_BONES if (qtrue) { #else if (!backlerp && !torsoBacklerp) { #endif for (i = 0; i < numBones; i++, boneRefs++) { if (validBones[*boneRefs]) { // this bone is still in the cache bones[*boneRefs] = rawBones[*boneRefs]; continue; } // find our parent, and make sure it has been calculated if ((boneInfo[*boneRefs].parent >= 0) && (!validBones[boneInfo[*boneRefs].parent] && !newBones[boneInfo[*boneRefs].parent])) { R_CalcBone(header, refent, boneInfo[*boneRefs].parent); } R_CalcBone(header, refent, *boneRefs); } } else // interpolated { cOldBoneList = oldFrame->bones; cOldBoneListTorso = oldTorsoFrame->bones; for (i = 0; i < numBones; i++, boneRefs++) { if (validBones[*boneRefs]) { // this bone is still in the cache bones[*boneRefs] = rawBones[*boneRefs]; continue; } // find our parent, and make sure it has been calculated if ((boneInfo[*boneRefs].parent >= 0) && (!validBones[boneInfo[*boneRefs].parent] && !newBones[boneInfo[*boneRefs].parent])) { R_CalcBoneLerp(header, refent, boneInfo[*boneRefs].parent); } R_CalcBoneLerp(header, refent, *boneRefs); } } // adjust for torso rotations torsoWeight = 0; boneRefs = boneList; for (i = 0; i < numBones; i++, boneRefs++) { thisBoneInfo = &boneInfo[*boneRefs]; bonePtr = &bones[*boneRefs]; // add torso rotation if (thisBoneInfo->torsoWeight > 0) { if (!newBones[*boneRefs]) { // just copy it back from the previous calc bones[*boneRefs] = oldBones[*boneRefs]; continue; } if (!(thisBoneInfo->flags & BONEFLAG_TAG)) { // 1st multiply with the bone->matrix // 2nd translation for rotation relative to bone around torso parent offset VectorSubtract(bonePtr->translation, torsoParentOffset, t); Matrix4FromAxisPlusTranslation(bonePtr->matrix, t, m1); // 3rd scaled rotation // 4th translate back to torso parent offset // use previously created matrix if available for the same weight if (torsoWeight != thisBoneInfo->torsoWeight) { Matrix4FromScaledAxisPlusTranslation(torsoAxis, thisBoneInfo->torsoWeight, torsoParentOffset, m2); torsoWeight = thisBoneInfo->torsoWeight; } // multiply matrices to create one matrix to do all calculations Matrix4MultiplyInto3x3AndTranslation(m2, m1, bonePtr->matrix, bonePtr->translation); } else // tag's require special handling { // rotate each of the axis by the torsoAngles LocalScaledMatrixTransformVector(bonePtr->matrix[0], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[0]); LocalScaledMatrixTransformVector(bonePtr->matrix[1], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[1]); LocalScaledMatrixTransformVector(bonePtr->matrix[2], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[2]); memcpy(bonePtr->matrix, tmpAxis, sizeof(tmpAxis)); // rotate the translation around the torsoParent VectorSubtract(bonePtr->translation, torsoParentOffset, t); LocalScaledMatrixTransformVector(t, thisBoneInfo->torsoWeight, torsoAxis, bonePtr->translation); VectorAdd(bonePtr->translation, torsoParentOffset, bonePtr->translation); } } } // backup the final bones memcpy(oldBones, bones, sizeof(bones[0]) * header->numBones); } #ifdef DBG_PROFILE_BONES #define DBG_SHOWTIME Ren_Print("%i: %i, ", di++, (dt = ri.Milliseconds()) - ldt); ldt = dt; #else #define DBG_SHOWTIME ; #endif /* ============== RB_SurfaceAnim ============== */ void RB_SurfaceAnim(mdsSurface_t *surface) { int j, k; refEntity_t *refent; int *boneList; mdsHeader_t *header; #ifdef DBG_PROFILE_BONES int di = 0, dt, ldt; dt = ri.Milliseconds(); ldt = dt; #endif refent = &backEnd.currentEntity->e; boneList = ( int * )((byte *)surface + surface->ofsBoneReferences); header = ( mdsHeader_t * )((byte *)surface + surface->ofsHeader); R_CalcBones(header, (const refEntity_t *)refent, boneList, surface->numBoneReferences); DBG_SHOWTIME // calculate LOD // TODO: lerp the radius and origin VectorAdd(refent->origin, frame->localOrigin, vec); lodRadius = frame->radius; lodScale = RB_CalcMDSLod(refent, vec, lodRadius, header->lodBias, header->lodScale); //DBG_SHOWTIME // modification to allow dead skeletal bodies to go below minlod (experiment) if (refent->reFlags & REFLAG_DEAD_LOD) { if (lodScale < 0.35) // allow dead to lod down to 35% (even if below surf->minLod) (%35 is arbitrary and probably not good generally. worked for the blackguard/infantry as a test though) { lodScale = 0.35; } render_count = ROUND_INT((float) surface->numVerts * lodScale); } else { render_count = ROUND_INT((float) surface->numVerts * lodScale); if (render_count < surface->minLod) { if (!(refent->reFlags & REFLAG_DEAD_LOD)) { render_count = surface->minLod; } } } if (render_count > surface->numVerts) { render_count = surface->numVerts; } RB_CheckOverflow(render_count, surface->numTriangles * 3); //DBG_SHOWTIME // setup triangle list //DBG_SHOWTIME collapse_map = ( int * )(( byte * )surface + surface->ofsCollapseMap); triangles = ( int * )((byte *)surface + surface->ofsTriangles); indexes = surface->numTriangles * 3; baseIndex = tess.numIndexes; baseVertex = tess.numVertexes; oldIndexes = baseIndex; tess.numVertexes += render_count; pIndexes = &tess.indexes[baseIndex]; //DBG_SHOWTIME if (render_count == surface->numVerts) { for (j = 0; j < indexes; j++) { pIndexes[j] = triangles[j] + baseVertex; } tess.numIndexes += indexes; } else { int *collapseEnd; pCollapse = collapse; for (j = 0; j < render_count; pCollapse++, j++) { *pCollapse = j; } pCollapseMap = &collapse_map[render_count]; for (collapseEnd = collapse + surface->numVerts ; pCollapse < collapseEnd; pCollapse++, pCollapseMap++) { *pCollapse = collapse[*pCollapseMap]; } for (j = 0 ; j < indexes ; j += 3) { p0 = collapse[*(triangles++)]; p1 = collapse[*(triangles++)]; p2 = collapse[*(triangles++)]; // FIXME // note: serious optimization opportunity here, // by sorting the triangles the following "continue" // could have been made into a "break" statement. if (p0 == p1 || p1 == p2 || p2 == p0) { continue; } *(pIndexes++) = baseVertex + p0; *(pIndexes++) = baseVertex + p1; *(pIndexes++) = baseVertex + p2; tess.numIndexes += 3; } baseIndex = tess.numIndexes; } //DBG_SHOWTIME // deform the vertexes by the lerped bones numVerts = surface->numVerts; v = ( mdsVertex_t * )((byte *)surface + surface->ofsVerts); tempVert = ( float * )(tess.xyz + baseVertex); tempNormal = ( float * )(tess.normal + baseVertex); for (j = 0; j < render_count; j++, tempVert += 4, tempNormal += 4) { mdsWeight_t *w; VectorClear(tempVert); w = v->weights; for (k = 0 ; k < v->numWeights ; k++, w++) { bone = &bones[w->boneIndex]; LocalAddScaledMatrixTransformVectorTranslate(w->offset, w->boneWeight, bone->matrix, bone->translation, tempVert); } LocalMatrixTransformVector(v->normal, bones[v->weights[0].boneIndex].matrix, tempNormal); tess.texCoords0[baseVertex + j].v[0] = v->texCoords[0]; tess.texCoords0[baseVertex + j].v[1] = v->texCoords[1]; v = (mdsVertex_t *)&v->weights[v->numWeights]; } DBG_SHOWTIME if (r_bonesDebug->integer) { if (r_bonesDebug->integer < 3) { int i; // DEBUG: show the bones as a stick figure with axis at each bone boneRefs = ( int * )((byte *)surface + surface->ofsBoneReferences); for (i = 0; i < surface->numBoneReferences; i++, boneRefs++) { bonePtr = &bones[*boneRefs]; GL_Bind(tr.whiteImage); qglLineWidth(1); #if 0 // TODO: OpenGL ES renderer qglBegin(GL_LINES); for (j = 0; j < 3; j++) { VectorClear(vec); vec[j] = 1; qglColor3fv(vec); qglVertex3fv(bonePtr->translation); VectorMA(bonePtr->translation, 5, bonePtr->matrix[j], vec); qglVertex3fv(vec); } qglEnd(); #endif // 0 // connect to our parent if it's valid if (validBones[boneInfo[*boneRefs].parent]) { qglLineWidth(2); #if 0 // TODO: OpenGL ES renderer qglBegin(GL_LINES); qglColor3f(.6, .6, .6); qglVertex3fv(bonePtr->translation); qglVertex3fv(bones[boneInfo[*boneRefs].parent].translation); qglEnd(); #endif } qglLineWidth(1); } } if (r_bonesDebug->integer == 3 || r_bonesDebug->integer == 4) { int render_indexes = (tess.numIndexes - oldIndexes); // show mesh edges tempVert = ( float * )(tess.xyz + baseVertex); tempNormal = ( float * )(tess.normal + baseVertex); GL_Bind(tr.whiteImage); qglLineWidth(1); #if 0 // TODO: OpenGL ES renderer qglBegin(GL_LINES); qglColor3f(.0, .0, .8); pIndexes = &tess.indexes[oldIndexes]; for (j = 0; j < render_indexes / 3; j++, pIndexes += 3) { qglVertex3fv(tempVert + 4 * pIndexes[0]); qglVertex3fv(tempVert + 4 * pIndexes[1]); qglVertex3fv(tempVert + 4 * pIndexes[1]); qglVertex3fv(tempVert + 4 * pIndexes[2]); qglVertex3fv(tempVert + 4 * pIndexes[2]); qglVertex3fv(tempVert + 4 * pIndexes[0]); } qglEnd(); #endif // 0 // track debug stats if (r_bonesDebug->integer == 4) { totalrv += render_count; totalrt += render_indexes / 3; totalv += surface->numVerts; totalt += surface->numTriangles; } if (r_bonesDebug->integer == 3) { Ren_Print("Lod %.2f verts %4d/%4d tris %4d/%4d (%.2f%%)\n", lodScale, render_count, surface->numVerts, render_indexes / 3, surface->numTriangles, ( float )(100.0 * render_indexes / 3) / (float) surface->numTriangles); } } } if (r_bonesDebug->integer > 1) { // dont draw the actual surface tess.numIndexes = oldIndexes; tess.numVertexes = baseVertex; return; } #ifdef DBG_PROFILE_BONES Ren_Print("\n"); #endif }
/* =============== RB_ShowImages Draw all the images to the screen, on top of whatever was there. This is used to test for texture thrashing. Also called by RE_EndRegistration =============== */ void RB_ShowImages( void ) { int i; image_t *image; float x, y, w, h; int start, end; if ( !backEnd.projection2D ) { RB_SetGL2D(); } qglClear( GL_COLOR_BUFFER_BIT ); qglFinish(); start = ri.Milliseconds(); for ( i = 0 ; i < tr.numImages ; i++ ) { image = tr.images[i]; w = glConfig.vidWidth / 40; h = glConfig.vidHeight / 30; x = i % 40 * w; y = i / 30 * h; // show in proportional size in mode 2 if ( r_showImages->integer == 2 ) { w *= image->uploadWidth / 512.0f; h *= image->uploadHeight / 512.0f; } #ifdef USE_OPENGLES GLfloat tex[] = { 0, 0, 1, 0, 1, 1, 0, 1 }; GLfloat vtx[] = { x, y, x + w, y, x + w, y + h, x, y + h }; GLboolean text = qglIsEnabled(GL_TEXTURE_COORD_ARRAY); GLboolean glcol = qglIsEnabled(GL_COLOR_ARRAY); if (glcol) qglDisableClientState(GL_COLOR_ARRAY); if (!text) qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, tex ); qglVertexPointer ( 2, GL_FLOAT, 0, vtx ); qglDrawArrays( GL_TRIANGLE_FAN, 0, 4 ); if (glcol) qglEnableClientState(GL_COLOR_ARRAY); if (!text) qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); #else GL_Bind( image ); qglBegin( GL_QUADS ); qglTexCoord2f( 0, 0 ); qglVertex2f( x, y ); qglTexCoord2f( 1, 0 ); qglVertex2f( x + w, y ); qglTexCoord2f( 1, 1 ); qglVertex2f( x + w, y + h ); qglTexCoord2f( 0, 1 ); qglVertex2f( x, y + h ); qglEnd(); #endif } qglFinish(); end = ri.Milliseconds(); ri.Printf( PRINT_ALL, "%i msec to draw all images\n", end - start ); }
/* ============= RE_StretchRaw FIXME: not exactly backend Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle. Used for cinematics. ============= */ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) { int i, j; int start, end; if ( !tr.registered ) { return; } R_SyncRenderThread(); // we definately want to sync every frame for the cinematics qglFinish(); start = 0; if ( r_speeds->integer ) { start = ri.Milliseconds(); } // make sure rows and cols are powers of 2 for ( i = 0 ; ( 1 << i ) < cols ; i++ ) { } for ( j = 0 ; ( 1 << j ) < rows ; j++ ) { } if ( ( 1 << i ) != cols || ( 1 << j ) != rows) { ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows); } GL_Bind( tr.scratchImage[client] ); // if the scratchImage isn't in the format we want, specify it as a new texture if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) { tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols; tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows; qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); } else { if (dirty) { // otherwise, just subimage upload it so that drivers can tell we are going to be changing // it and don't try and do a texture compression qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data ); } } if ( r_speeds->integer ) { end = ri.Milliseconds(); ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start ); } RB_SetGL2D(); qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); qglBegin (GL_QUADS); qglTexCoord2f ( 0.5f / cols, 0.5f / rows ); qglVertex2f (x, y); qglTexCoord2f ( ( cols - 0.5f ) / cols , 0.5f / rows ); qglVertex2f (x+w, y); qglTexCoord2f ( ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows ); qglVertex2f (x+w, y+h); qglTexCoord2f ( 0.5f / cols, ( rows - 0.5f ) / rows ); qglVertex2f (x, y+h); qglEnd (); }
void R_Bloom_Process(void) { int p; GLint loc; if(!bloom_initialized) return; if(!gl_bloom.value) return; // pass filter into pass0[0] glUseProgram(passProg); loc = glGetUniformLocation(passProg, "source"); glUniform1i(loc, 0); glEnable(GL_TEXTURE_2D); GL_Bind(scenebase.texture); phBindSurface(pass0, false); glBegin(GL_QUADS); glTexCoord2i(0, 0); glVertex2i(-1, -1); glTexCoord2i(0, 1); glVertex2i(-1, 1); glTexCoord2i(1, 1); glVertex2i(1, 1); glTexCoord2i(1, 0); glVertex2i(1, -1); glEnd(); glUseProgram(0); // downsample the scene into the source surfaces glEnable(GL_TEXTURE_2D); GL_Bind(pass0[0].texture); for (p = 1; p < BLOOM_FILTER_COUNT; p++) { phBindSurface(pass0 + p, false); glBegin(GL_QUADS); glTexCoord2i(0, 0); glVertex2i(-1, -1); glTexCoord2i(0, 1); glVertex2i(-1, 1); glTexCoord2i(1, 1); glVertex2i(1, 1); glTexCoord2i(1, 0); glVertex2i(1, -1); glEnd(); } // perform the horizontal blurring pass. blur(pass0, pass1, BLOOM_FILTER_COUNT, 1.0f, HORIZONTAL); // perform the vertical blurring pass. blur(pass1, pass0, BLOOM_FILTER_COUNT, 1.0f, VERTICAL); glUseProgram(combineProg); for (p = 0; p < BLOOM_FILTER_COUNT; p++) { char name[] = "Pass#"; glActiveTexture(GL_TEXTURE0 + p); glEnable(GL_TEXTURE_2D); GL_Bind(pass0[p].texture); sprintf(name, "Pass%d", p); loc = glGetUniformLocation(combineProg, name); glUniform1i(loc, p); } // combine original scene glActiveTexture(GL_TEXTURE0 + BLOOM_FILTER_COUNT); if(cl.worldmodel && r_viewleaf->contents <= CONTENTS_WATER) GL_Bind(scenepass0.texture); else GL_Bind(scenebase.texture); glEnable(GL_TEXTURE_2D); loc = glGetUniformLocation(combineProg, "Scene"); glUniform1i(loc, BLOOM_FILTER_COUNT); }
void RB_DoShadowTessEnd( vec3_t lightPos ) { int i; int numTris; vec3_t lightDir; // we can only do this if we have enough space in the vertex buffers if ( tess.numVertexes >= SHADER_MAX_VERTEXES / 2 ) { return; } if ( glConfig.stencilBits < 4 ) { return; } #if 1 //controlled method - try to keep shadows in range so they don't show through so much -rww vec3_t worldxyz; vec3_t entLight; float groundDist; VectorCopy( backEnd.currentEntity->lightDir, entLight ); entLight[2] = 0.0f; VectorNormalize(entLight); //Oh well, just cast them straight down no matter what onto the ground plane. //This presets no chance of screwups and still looks better than a stupid //shader blob. VectorSet(lightDir, entLight[0]*0.3f, entLight[1]*0.3f, 1.0f); // project vertexes away from light direction for ( i = 0 ; i < tess.numVertexes ; i++ ) { //add or.origin to vert xyz to end up with world oriented coord, then figure //out the ground pos for the vert to project the shadow volume to VectorAdd(tess.xyz[i], backEnd.ori.origin, worldxyz); groundDist = worldxyz[2] - backEnd.currentEntity->e.shadowPlane; groundDist += 16.0f; //fudge factor VectorMA( tess.xyz[i], -groundDist, lightDir, tess.xyz[i+tess.numVertexes] ); } #else if (lightPos) { for ( i = 0 ; i < tess.numVertexes ; i++ ) { tess.xyz[i+tess.numVertexes][0] = tess.xyz[i][0]+(( tess.xyz[i][0]-lightPos[0] )*128.0f); tess.xyz[i+tess.numVertexes][1] = tess.xyz[i][1]+(( tess.xyz[i][1]-lightPos[1] )*128.0f); tess.xyz[i+tess.numVertexes][2] = tess.xyz[i][2]+(( tess.xyz[i][2]-lightPos[2] )*128.0f); } } else { VectorCopy( backEnd.currentEntity->lightDir, lightDir ); // project vertexes away from light direction for ( i = 0 ; i < tess.numVertexes ; i++ ) { VectorMA( tess.xyz[i], -512, lightDir, tess.xyz[i+tess.numVertexes] ); } } #endif // decide which triangles face the light memset( numEdgeDefs, 0, 4 * tess.numVertexes ); numTris = tess.numIndexes / 3; for ( i = 0 ; i < numTris ; i++ ) { int i1, i2, i3; vec3_t d1, d2, normal; float *v1, *v2, *v3; float d; i1 = tess.indexes[ i*3 + 0 ]; i2 = tess.indexes[ i*3 + 1 ]; i3 = tess.indexes[ i*3 + 2 ]; v1 = tess.xyz[ i1 ]; v2 = tess.xyz[ i2 ]; v3 = tess.xyz[ i3 ]; if (!lightPos) { VectorSubtract( v2, v1, d1 ); VectorSubtract( v3, v1, d2 ); CrossProduct( d1, d2, normal ); d = DotProduct( normal, lightDir ); } else { float planeEq[4]; planeEq[0] = v1[1]*(v2[2]-v3[2]) + v2[1]*(v3[2]-v1[2]) + v3[1]*(v1[2]-v2[2]); planeEq[1] = v1[2]*(v2[0]-v3[0]) + v2[2]*(v3[0]-v1[0]) + v3[2]*(v1[0]-v2[0]); planeEq[2] = v1[0]*(v2[1]-v3[1]) + v2[0]*(v3[1]-v1[1]) + v3[0]*(v1[1]-v2[1]); planeEq[3] = -( v1[0]*( v2[1]*v3[2] - v3[1]*v2[2] ) + v2[0]*(v3[1]*v1[2] - v1[1]*v3[2]) + v3[0]*(v1[1]*v2[2] - v2[1]*v1[2]) ); d = planeEq[0]*lightPos[0]+ planeEq[1]*lightPos[1]+ planeEq[2]*lightPos[2]+ planeEq[3]; } if ( d > 0 ) { facing[ i ] = 1; } else { facing[ i ] = 0; } // create the edges R_AddEdgeDef( i1, i2, facing[ i ] ); R_AddEdgeDef( i2, i3, facing[ i ] ); R_AddEdgeDef( i3, i1, facing[ i ] ); } GL_Bind( tr.whiteImage ); //qglEnable( GL_CULL_FACE ); GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); #ifndef _DEBUG_STENCIL_SHADOWS qglColor3f( 0.2f, 0.2f, 0.2f ); // don't write to the color buffer qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); qglEnable( GL_STENCIL_TEST ); qglStencilFunc( GL_ALWAYS, 1, 255 ); #else qglColor3f( 1.0f, 0.0f, 0.0f ); qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE); //qglDisable(GL_DEPTH_TEST); #endif #ifdef _STENCIL_REVERSE qglDepthFunc(GL_LESS); //now using the Carmack Reverse<tm> -rww if ( backEnd.viewParms.isMirror ) { //qglCullFace( GL_BACK ); GL_Cull(CT_BACK_SIDED); qglStencilOp( GL_KEEP, GL_INCR, GL_KEEP ); R_RenderShadowEdges(); //qglCullFace( GL_FRONT ); GL_Cull(CT_FRONT_SIDED); qglStencilOp( GL_KEEP, GL_DECR, GL_KEEP ); R_RenderShadowEdges(); } else { //qglCullFace( GL_FRONT ); GL_Cull(CT_FRONT_SIDED); qglStencilOp( GL_KEEP, GL_INCR, GL_KEEP ); R_RenderShadowEdges(); //qglCullFace( GL_BACK ); GL_Cull(CT_BACK_SIDED); qglStencilOp( GL_KEEP, GL_DECR, GL_KEEP ); R_RenderShadowEdges(); } qglDepthFunc(GL_LEQUAL); #else // mirrors have the culling order reversed if ( backEnd.viewParms.isMirror ) { qglCullFace( GL_FRONT ); qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); R_RenderShadowEdges(); qglCullFace( GL_BACK ); qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); R_RenderShadowEdges(); } else { qglCullFace( GL_BACK ); qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); R_RenderShadowEdges(); qglCullFace( GL_FRONT ); qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); R_RenderShadowEdges(); } #endif // reenable writing to the color buffer qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); #ifdef _DEBUG_STENCIL_SHADOWS qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); #endif }
/* ================= R_DrawSpriteModel ================= */ void R_DrawSpriteModel (entity_t *e) { vec3_t point; mspriteframe_t *frame; float *up, *right; vec3_t v_forward, v_right, v_up; msprite_t *psprite; // don't even bother culling, because it's just a single // polygon without a surface cache frame = R_GetSpriteFrame (e); psprite = (msprite_t*) currententity->model->cache.data; if (psprite->type == SPR_ORIENTED) { // bullet marks on walls AngleVectors (currententity->angles, v_forward, v_right, v_up); up = v_up; right = v_right; } else { // normal sprite up = vup; right = vright; } glColor3f (1,1,1); GL_DisableMultitexture(); GL_Bind(frame->gl_texturenum); glEnable (GL_ALPHA_TEST); #ifdef USE_OPENGLES { float* pPoint = gVertexBuffer; float texCoords[] = { 0, 1, 0, 0, 1, 0, 1, 1 }; VectorMA (e->origin, frame->down, up, point); VectorMA (point, frame->left, right, pPoint); pPoint += 3; VectorMA (e->origin, frame->up, up, point); VectorMA (point, frame->left, right, pPoint); pPoint += 3; VectorMA (e->origin, frame->up, up, point); VectorMA (point, frame->right, right, pPoint); pPoint += 3; VectorMA (e->origin, frame->down, up, point); VectorMA (point, frame->right, right, pPoint); glVertexPointer(3, GL_FLOAT, 0, gVertexBuffer); glTexCoordPointer(2, GL_FLOAT, 0, texCoords); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } #else glBegin (GL_QUADS); glTexCoord2f (0, 1); VectorMA (e->origin, frame->down, up, point); VectorMA (point, frame->left, right, point); glVertex3fv (point); glTexCoord2f (0, 0); VectorMA (e->origin, frame->up, up, point); VectorMA (point, frame->left, right, point); glVertex3fv (point); glTexCoord2f (1, 0); VectorMA (e->origin, frame->up, up, point); VectorMA (point, frame->right, right, point); glVertex3fv (point); glTexCoord2f (1, 1); VectorMA (e->origin, frame->down, up, point); VectorMA (point, frame->right, right, point); glVertex3fv (point); glEnd (); #endif glDisable (GL_ALPHA_TEST); }