/* * R_DrawBSPSurf */ qboolean R_DrawBSPSurf( const entity_t *e, const shader_t *shader, const mfog_t *fog, drawSurfaceBSP_t *drawSurf ) { vboSlice_t *slice; slice = R_GetVBOSlice( drawSurf - rsh.worldBrushModel->drawSurfaces ); assert( slice != NULL ); RB_BindVBO( drawSurf->vbo->index, GL_TRIANGLES ); if( drawSurf->dlightFrame == rsc.frameCount ) { RB_SetDlightBits( drawSurf->dlightBits & rn.dlightBits ); } else { RB_SetDlightBits( 0 ); } if( drawSurf->shadowFrame == rsc.frameCount ) { RB_SetShadowBits( drawSurf->shadowBits & rn.shadowBits ); } else { RB_SetShadowBits( 0 ); } RB_SetLightstyle( drawSurf->superLightStyle ); if( drawSurf->numInstances ) { RB_DrawElementsInstanced( slice->firstVert, slice->numVerts, slice->firstElem, slice->numElems, drawSurf->numInstances, drawSurf->instances ); } else { RB_DrawElements( slice->firstVert, slice->numVerts, slice->firstElem, slice->numElems ); } return qfalse; }
/* * RB_BeginFrame */ void RB_BeginFrame( void ) { Vector4Set( rb.nullEnt.shaderRGBA, 1, 1, 1, 1 ); rb.nullEnt.scale = 1; VectorClear( rb.nullEnt.origin ); Matrix3_Identity( rb.nullEnt.axis ); memset( &rb.stats, 0, sizeof( rb.stats ) ); // start fresh each frame RB_SetShaderStateMask( ~0, 0 ); RB_BindVBO( 0, 0 ); }
/* * R_DrawBSPSurf */ bool R_DrawBSPSurf( const entity_t *e, const shader_t *shader, const mfog_t *fog, const portalSurface_t *portalSurface, drawSurfaceBSP_t *drawSurf ) { const vboSlice_t *slice; const vboSlice_t *shadowSlice; static const vboSlice_t nullSlice = { 0 }; int firstVert, firstElem; int firstShadowVert, firstShadowElem; slice = R_GetVBOSlice( drawSurf - rsh.worldBrushModel->drawSurfaces ); shadowSlice = R_GetVBOSlice( rsh.worldBrushModel->numDrawSurfaces + ( drawSurf - rsh.worldBrushModel->drawSurfaces ) ); if( !shadowSlice ) { shadowSlice = &nullSlice; } assert( slice != NULL ); RB_BindVBO( drawSurf->vbo->index, GL_TRIANGLES ); if( drawSurf->dlightFrame == rsc.frameCount ) { RB_SetDlightBits( drawSurf->dlightBits & rn.dlightBits ); } else { RB_SetDlightBits( 0 ); } if( drawSurf->shadowFrame == rsc.frameCount ) { RB_SetShadowBits( (drawSurf->shadowBits & rn.shadowBits) & rsc.renderedShadowBits ); } else { RB_SetShadowBits( 0 ); } RB_SetLightstyle( drawSurf->superLightStyle ); firstVert = drawSurf->firstVboVert + slice->firstVert; firstElem = drawSurf->firstVboElem + slice->firstElem; firstShadowVert = drawSurf->firstVboVert + shadowSlice->firstVert; firstShadowElem = drawSurf->firstVboElem + shadowSlice->firstElem; if( drawSurf->numInstances ) { RB_DrawElementsInstanced( firstVert, slice->numVerts, firstElem, slice->numElems, firstShadowVert, shadowSlice->numVerts, firstShadowElem, shadowSlice->numElems, drawSurf->numInstances, drawSurf->instances ); } else { RB_DrawElements( firstVert, slice->numVerts,firstElem, slice->numElems, firstShadowVert, shadowSlice->numVerts, firstShadowElem, shadowSlice->numElems ); } return false; }
/* * R_DrawBlackBottom * * Draw dummy skybox side to prevent the HOM effect */ static void R_DrawBlackBottom( const skydome_t *skydome, const visSkySide_t *visSides ) { int side = 5; const visSkySide_t *visSide = visSides + side; if( rn.skyMins[0][side] >= rn.skyMaxs[0][side] || rn.skyMins[1][side] >= rn.skyMaxs[1][side] ) return; RB_BindShader( rsc.worldent, rf.envShader, rn.skyFog ); RB_BindVBO( skydome->linearVbos[side]->index, GL_TRIANGLES ); RB_DrawElements( visSide->firstVert, visSide->numVerts, visSide->firstElem, visSide->numElems ); }
/* * R_DrawBlackBottom * * Draw dummy skybox side to prevent the HOM effect */ static void R_DrawBlackBottom( const skydome_t *skydome, const visSkySide_t *visSides, const mfog_t *fog, drawSurfaceSky_t *drawSurf ) { int side = 5; const visSkySide_t *visSide = visSides + side; if( drawSurf->skyMins[0][side] >= drawSurf->skyMaxs[0][side] || drawSurf->skyMins[1][side] >= drawSurf->skyMaxs[1][side] ) { return; } RB_BindShader( rsc.skyent, rsh.envShader, fog ); RB_BindVBO( skydome->linearVbos[side]->index, GL_TRIANGLES ); RB_DrawElements( visSide->firstVert, visSide->numVerts, visSide->firstElem, visSide->numElems, 0, 0, 0, 0 ); }
/* * R_DrawSkyBoxSide */ static void R_DrawSkyBoxSide( const skydome_t *skydome, const visSkySide_t *visSide, const shader_t *shader, int imageIndex ) { int side = visSide->index; if( rn.skyMins[0][side] >= rn.skyMaxs[0][side] || rn.skyMins[1][side] >= rn.skyMaxs[1][side] ) return; RB_BindShader( rsc.worldent, rf.skyShader, rn.skyFog ); RB_BindVBO( skydome->linearVbos[side]->index, GL_TRIANGLES ); RB_SetSkyboxShader( shader ); RB_SetSkyboxSide( imageIndex ); RB_DrawElements( visSide->firstVert, visSide->numVerts, visSide->firstElem, visSide->numElems ); }
/* * R_DrawSkyBoxSide */ static void R_DrawSkyBoxSide( const skydome_t *skydome, const visSkySide_t *visSide, const shader_t *skyShader, const shader_t *skyboxShader, const mfog_t *fog, int imageIndex, drawSurfaceSky_t *drawSurf ) { int side = visSide->index; if( drawSurf->skyMins[0][side] >= drawSurf->skyMaxs[0][side] || drawSurf->skyMins[1][side] >= drawSurf->skyMaxs[1][side] ) { return; } RB_BindShader( rsc.skyent, skyShader, fog ); RB_BindVBO( skydome->linearVbos[side]->index, GL_TRIANGLES ); RB_SetSkyboxShader( skyboxShader ); RB_SetSkyboxSide( imageIndex ); RB_DrawElements( visSide->firstVert, visSide->numVerts, visSide->firstElem, visSide->numElems, 0, 0, 0, 0 ); }
/* * R_RenderDebugBounds */ static void R_RenderDebugBounds( void ) { int i, j; vec3_t corner; const vec_t *mins, *maxs; mesh_t *rb_mesh; elem_t elems[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; if( !r_num_debug_bounds ) return; RB_EnableTriangleOutlines( qtrue ); RB_BindShader( rsc.worldent, rsh.whiteShader, NULL ); RB_BindVBO( RB_VBO_STREAM, GL_TRIANGLE_STRIP ); for( i = 0; i < r_num_debug_bounds; i++ ) { mins = r_debug_bounds[i].mins; maxs = r_debug_bounds[i].maxs; rb_mesh = RB_MapBatchMesh( 8, 8 ); for( j = 0; j < 8; j++ ) { corner[0] = ( ( j & 1 ) ? mins[0] : maxs[0] ); corner[1] = ( ( j & 2 ) ? mins[1] : maxs[1] ); corner[2] = ( ( j & 4 ) ? mins[2] : maxs[2] ); VectorCopy( corner, rb_mesh->xyzArray[j] ); } rb_mesh->numVerts = 8; rb_mesh->numElems = 8; rb_mesh->elems = elems; RB_UploadMesh( rb_mesh ); RB_EndBatch(); } RB_EnableTriangleOutlines( qfalse ); }
/* * RB_BeginRegistration */ void RB_BeginRegistration( void ) { int i; RB_RegisterStreamVBOs(); RB_BindVBO( 0, 0 ); // unbind all texture targets on all TMUs for( i = MAX_TEXTURE_UNITS - 1; i >= 0; i-- ) { RB_SelectTextureUnit( i ); qglBindTexture( GL_TEXTURE_CUBE_MAP_ARB, 0 ); if( glConfig.ext.texture_array ) qglBindTexture( GL_TEXTURE_2D_ARRAY_EXT, 0 ); if( glConfig.ext.texture3D ) qglBindTexture( GL_TEXTURE_3D_EXT, 0 ); qglBindTexture( GL_TEXTURE_2D, 0 ); } RB_FlushTextureCache(); }
/* * R_BeginCoronaSurf */ qboolean R_BeginCoronaSurf( const entity_t *e, const shader_t *shader, const mfog_t *fog, drawSurfaceType_t *drawSurf ) { RB_BindVBO( RB_VBO_STREAM_QUAD, GL_TRIANGLES ); return qtrue; }
/* * RB_EndRegistration */ void RB_EndRegistration( void ) { RB_BindVBO( 0, 0 ); }
/* * RB_FlushDynamicMeshes */ void RB_FlushDynamicMeshes( void ) { int i, numDraws = rb.numDynamicDraws; rbDynamicStream_t *stream; rbDynamicDraw_t *draw; int sx, sy, sw, sh; float offsetx = 0.0f, offsety = 0.0f, transx, transy; mat4_t m; if( !numDraws ) { return; } for( i = 0; i < RB_VBO_NUM_STREAMS; i++ ) { stream = &rb.dynamicStreams[i]; // R_UploadVBO* are going to rebind buffer arrays for upload // so update our local VBO state cache by calling RB_BindVBO RB_BindVBO( -i - 1, GL_TRIANGLES ); // dummy value for primitive here // because of firstVert, upload elems first if( stream->drawElements.numElems ) { mesh_t elemMesh; memset( &elemMesh, 0, sizeof( elemMesh ) ); elemMesh.elems = dynamicStreamElems[i] + stream->drawElements.firstElem; elemMesh.numElems = stream->drawElements.numElems; R_UploadVBOElemData( stream->vbo, 0, stream->drawElements.firstElem, &elemMesh ); stream->drawElements.firstElem += stream->drawElements.numElems; stream->drawElements.numElems = 0; } if( stream->drawElements.numVerts ) { R_UploadVBOVertexRawData( stream->vbo, stream->drawElements.firstVert, stream->drawElements.numVerts, stream->vertexData + stream->drawElements.firstVert * stream->vbo->vertexSize ); stream->drawElements.firstVert += stream->drawElements.numVerts; stream->drawElements.numVerts = 0; } } RB_GetScissor( &sx, &sy, &sw, &sh ); Matrix4_Copy( rb.objectMatrix, m ); transx = m[12]; transy = m[13]; for( i = 0, draw = rb.dynamicDraws; i < numDraws; i++, draw++ ) { RB_BindShader( draw->entity, draw->shader, draw->fog ); RB_BindVBO( draw->streamId, draw->primitive ); RB_SetPortalSurface( draw->portalSurface ); RB_SetShadowBits( draw->shadowBits ); RB_Scissor( draw->scissor[0], draw->scissor[1], draw->scissor[2], draw->scissor[3] ); // translate the mesh in 2D if( ( offsetx != draw->offset[0] ) || ( offsety != draw->offset[1] ) ) { offsetx = draw->offset[0]; offsety = draw->offset[1]; m[12] = transx + offsetx; m[13] = transy + offsety; RB_LoadObjectMatrix( m ); } RB_DrawElements( draw->drawElements.firstVert, draw->drawElements.numVerts, draw->drawElements.firstElem, draw->drawElements.numElems, draw->drawElements.firstVert, draw->drawElements.numVerts, draw->drawElements.firstElem, draw->drawElements.numElems ); } rb.numDynamicDraws = 0; RB_Scissor( sx, sy, sw, sh ); // restore the original translation in the object matrix if it has been changed if( offsetx || offsety ) { m[12] = transx; m[13] = transy; RB_LoadObjectMatrix( m ); } }
/* * R_DrawAliasSurf * * Interpolates between two frames and origins */ qboolean R_DrawAliasSurf( const entity_t *e, const shader_t *shader, const mfog_t *fog, drawSurfaceAlias_t *drawSurf ) { int i; int framenum, oldframenum; float backv[3], frontv[3]; vec3_t normal, oldnormal; qboolean calcVerts, calcNormals, calcSTVectors; vec3_t move; const maliasframe_t *frame, *oldframe; const maliasvertex_t *v, *ov; float backlerp = e->backlerp; const maliasmodel_t *model = ( const maliasmodel_t * )drawSurf->model->extradata; const maliasmesh_t *aliasmesh = drawSurf->mesh; vattribmask_t vattribs; // see what vertex attribs backend needs vattribs = RB_GetVertexAttribs(); framenum = bound( e->frame, 0, model->numframes ); oldframenum = bound( e->oldframe, 0, model->numframes ); frame = model->frames + framenum; oldframe = model->frames + oldframenum; for( i = 0; i < 3; i++ ) move[i] = frame->translate[i] + ( oldframe->translate[i] - frame->translate[i] ) * backlerp; // based on backend's needs calcNormals = calcSTVectors = qfalse; calcNormals = ( ( vattribs & VATTRIB_NORMAL_BIT ) != 0 ) && ( ( framenum != 0 ) || ( oldframenum != 0 ) ); calcSTVectors = ( ( vattribs & VATTRIB_SVECTOR_BIT ) != 0 ) && calcNormals; if( aliasmesh->vbo != NULL && !framenum && !oldframenum ) { RB_BindVBO( aliasmesh->vbo->index, GL_TRIANGLES ); RB_DrawElements( 0, aliasmesh->numverts, 0, aliasmesh->numtris * 3 ); } else { mesh_t *rb_mesh; vec3_t *inVertsArray; vec3_t *inNormalsArray; vec4_t *inSVectorsArray; RB_BindVBO( RB_VBO_STREAM, GL_TRIANGLES ); rb_mesh = RB_MapBatchMesh( aliasmesh->numverts, aliasmesh->numtris * 3 ); if( !rb_mesh ) { ri.Com_DPrintf( S_COLOR_YELLOW "R_DrawAliasSurf: RB_MapBatchMesh returned NULL for (%s)(%s)", drawSurf->model->name, aliasmesh->name ); return qfalse; } inVertsArray = rb_mesh->xyzArray; inNormalsArray = rb_mesh->normalsArray; inSVectorsArray = rb_mesh->sVectorsArray; if( !framenum && !oldframenum ) { calcVerts = qfalse; if( calcNormals ) { v = aliasmesh->vertexes; for( i = 0; i < aliasmesh->numverts; i++, v++ ) R_LatLongToNorm( v->latlong, inNormalsArray[i] ); } } else if( framenum == oldframenum ) { calcVerts = qtrue; for( i = 0; i < 3; i++ ) frontv[i] = frame->scale[i]; v = aliasmesh->vertexes + framenum * aliasmesh->numverts; for( i = 0; i < aliasmesh->numverts; i++, v++ ) { VectorSet( inVertsArray[i], move[0] + v->point[0]*frontv[0], move[1] + v->point[1]*frontv[1], move[2] + v->point[2]*frontv[2] ); if( calcNormals ) R_LatLongToNorm( v->latlong, inNormalsArray[i] ); } } else { calcVerts = qtrue; for( i = 0; i < 3; i++ ) { backv[i] = backlerp * oldframe->scale[i]; frontv[i] = ( 1.0f - backlerp ) * frame->scale[i]; } v = aliasmesh->vertexes + framenum * aliasmesh->numverts; ov = aliasmesh->vertexes + oldframenum * aliasmesh->numverts; for( i = 0; i < aliasmesh->numverts; i++, v++, ov++ ) { VectorSet( inVertsArray[i], move[0] + v->point[0]*frontv[0] + ov->point[0]*backv[0], move[1] + v->point[1]*frontv[1] + ov->point[1]*backv[1], move[2] + v->point[2]*frontv[2] + ov->point[2]*backv[2] ); if( calcNormals ) { R_LatLongToNorm( v->latlong, normal ); R_LatLongToNorm( ov->latlong, oldnormal ); VectorSet( inNormalsArray[i], normal[0] + ( oldnormal[0] - normal[0] ) * backlerp, normal[1] + ( oldnormal[1] - normal[1] ) * backlerp, normal[2] + ( oldnormal[2] - normal[2] ) * backlerp ); } } } if( calcSTVectors ) R_BuildTangentVectors( aliasmesh->numverts, inVertsArray, inNormalsArray, aliasmesh->stArray, aliasmesh->numtris, aliasmesh->elems, inSVectorsArray ); if( !calcVerts ) { rb_mesh->xyzArray = aliasmesh->xyzArray; } rb_mesh->elems = aliasmesh->elems; rb_mesh->numElems = aliasmesh->numtris * 3; rb_mesh->numVerts = aliasmesh->numverts; rb_mesh->stArray = aliasmesh->stArray; if( !calcNormals ) { rb_mesh->normalsArray = aliasmesh->normalsArray; } if( !calcSTVectors ) { rb_mesh->sVectorsArray = aliasmesh->sVectorsArray; } RB_UploadMesh( rb_mesh ); RB_EndBatch(); } return qfalse; }
/* * RB_BeginRegistration */ void RB_BeginRegistration( void ) { RB_RegisterStreamVBOs(); RB_BindVBO( 0, 0 ); }
/* * R_DrawSkySurf */ void R_DrawSkySurf( const entity_t *e, const shader_t *shader, const mfog_t *fog, const portalSurface_t *portalSurface, unsigned int shadowBits, drawSurfaceSky_t *drawSurf ) { int i; int numVisSides; visSkySide_t visSkySides[6]; vec3_t mins, maxs; int umin, umax, vmin, vmax; bool skyportal = portalSurface != NULL && portalSurface->skyPortal; skydome_t *skydome = rsh.worldBrushModel->skydome; if( !skydome ) { return; } if( skyportal && !fog ) { return; } numVisSides = 0; ClearBounds( mins, maxs ); memset( visSkySides, 0, sizeof( visSkySides ) ); for( i = 0; i < 6; i++ ) { if( drawSurf->skyMins[0][i] >= drawSurf->skyMaxs[0][i] || drawSurf->skyMins[1][i] >= drawSurf->skyMaxs[1][i] ) { continue; } // increase the visible sides counter numVisSides++; umin = (int)( ( drawSurf->skyMins[0][i] + 1.0f ) * 0.5f * (float)( SIDE_SIZE - 1 ) ); umax = (int)( ( drawSurf->skyMaxs[0][i] + 1.0f ) * 0.5f * (float)( SIDE_SIZE - 1 ) ) + 1; vmin = (int)( ( drawSurf->skyMins[1][i] + 1.0f ) * 0.5f * (float)( SIDE_SIZE - 1 ) ); vmax = (int)( ( drawSurf->skyMaxs[1][i] + 1.0f ) * 0.5f * (float)( SIDE_SIZE - 1 ) ) + 1; clamp( umin, 0, SIDE_SIZE - 1 ); clamp( umax, 0, SIDE_SIZE - 1 ); clamp( vmin, 0, SIDE_SIZE - 1 ); clamp( vmax, 0, SIDE_SIZE - 1 ); visSkySides[i].index = i; visSkySides[i].firstVert = vmin * SIDE_SIZE + umin; visSkySides[i].numVerts = ( vmax - vmin ) * SIDE_SIZE + ( umax - umin ) + 1; visSkySides[i].firstElem = ( vmin * ( SIDE_SIZE - 2 ) + umin ) * 6; visSkySides[i].numElems = ( ( vmax - vmin ) * ( SIDE_SIZE - 2 ) + ( umax - umin ) ) * 6; clamp( visSkySides[i].firstVert, 0, POINTS_LEN - 1 ); clamp( visSkySides[i].numVerts, 0, POINTS_LEN ); clamp( visSkySides[i].firstElem, 0, ELEM_LEN - 1 ); clamp( visSkySides[i].numElems, 0, ELEM_LEN ); skydome->meshes[i].numElems = visSkySides[i].numElems; } // no sides are truly visible, ignore if( !numVisSides ) { return; } // center skydome on camera to give the illusion of a larger space rsc.skyent->scale = shader->skyHeight; VectorCopy( rn.viewOrigin, rsc.skyent->origin ); R_TransformForEntity( rsc.skyent ); if( skyportal ) { // render fake fogged skybox R_DrawSkyBox( skydome, visSkySides, rsh.emptyFogShader, shader, fog, drawSurf ); } else { if( shader->skyboxImages[0] ) { R_DrawSkyBox( skydome, visSkySides, rsh.skyShader, shader, fog, drawSurf ); } else { R_DrawBlackBottom( skydome, visSkySides, fog, drawSurf ); } if( shader->numpasses ) { for( i = 0; i < 5; i++ ) { const visSkySide_t *visSide = visSkySides + i; if( drawSurf->skyMins[0][i] >= drawSurf->skyMaxs[0][i] || drawSurf->skyMins[1][i] >= drawSurf->skyMaxs[1][i] ) { continue; } RB_BindShader( rsc.skyent, shader, NULL ); // must be called for every side to reset backend state RB_BindVBO( skydome->sphereVbos[i]->index, GL_TRIANGLES ); RB_DrawElements( visSide->firstVert, visSide->numVerts, visSide->firstElem, visSide->numElems, 0, 0, 0, 0 ); } } } R_TransformForEntity( e ); }
/* * R_DrawBSPSurf */ void R_DrawBSPSurf( const entity_t *e, const shader_t *shader, const mfog_t *fog, const portalSurface_t *portalSurface, unsigned int entShadowBits, drawSurfaceBSP_t *drawSurf ) { const vboSlice_t *slice; const vboSlice_t *shadowSlice; static const vboSlice_t nullSlice = { 0 }; int firstVert, firstElem; int numVerts, numElems; int firstShadowVert, firstShadowElem; int numShadowVerts, numShadowElems; unsigned shadowBits, dlightBits; slice = R_GetVBOSlice( drawSurf - rsh.worldBrushModel->drawSurfaces ); shadowSlice = R_GetVBOSlice( rsh.worldBrushModel->numDrawSurfaces + ( drawSurf - rsh.worldBrushModel->drawSurfaces ) ); if( !shadowSlice ) { shadowSlice = &nullSlice; } assert( slice != NULL ); if( drawSurf->dlightFrame == rsc.frameCount ) { dlightBits = drawSurf->dlightBits & rn.dlightBits; } else { dlightBits = 0; } if( drawSurf->shadowFrame == rsc.frameCount ) { shadowBits = (drawSurf->shadowBits & rn.shadowBits) & rsc.renderedShadowBits; } else { shadowBits = 0; } // shadowBits are shared for all rendering instances (normal view, portals, etc) // if either shadow slice is empty or shadowBits is 0, then we must pass the surface unshadowed numVerts = slice->numVerts; numElems = slice->numElems; firstVert = drawSurf->firstVboVert + slice->firstVert; firstElem = drawSurf->firstVboElem + slice->firstElem; if( shadowBits && shadowSlice->numElems ) { numShadowVerts = shadowSlice->numVerts; numShadowElems = shadowSlice->numElems; firstShadowVert = drawSurf->firstVboVert + shadowSlice->firstVert; firstShadowElem = drawSurf->firstVboElem + shadowSlice->firstElem; } else { shadowBits = 0; numShadowVerts = 0; numShadowElems = 0; firstShadowVert = 0; firstShadowElem = 0; } RB_BindVBO( drawSurf->vbo->index, GL_TRIANGLES ); RB_SetDlightBits( dlightBits ); RB_SetShadowBits( shadowBits ); RB_SetLightstyle( drawSurf->superLightStyle ); if( drawSurf->numInstances ) { RB_DrawElementsInstanced( firstVert, numVerts, firstElem, numElems, firstShadowVert, numShadowVerts, firstShadowElem, numShadowElems, drawSurf->numInstances, drawSurf->instances ); } else { RB_DrawElements( firstVert, numVerts, firstElem, numElems, firstShadowVert, numShadowVerts, firstShadowElem, numShadowElems ); } }
/* * R_BeginPolySurf */ qboolean R_BeginPolySurf( const entity_t *e, const shader_t *shader, const mfog_t *fog, drawSurfacePoly_t *drawSurf ) { RB_BindVBO( RB_VBO_STREAM, GL_TRIANGLES ); return qtrue; }
/* * R_BlitTextureToScrFbo */ static void R_BlitTextureToScrFbo( const refdef_t *fd, image_t *image, int dstFbo, int program_type, const vec4_t color, int blendMask, int numShaderImages, image_t **shaderImages ) { int x, y; int w, h, fw, fh; static char s_name[] = "$builtinpostprocessing"; static shaderpass_t p; static shader_t s; int i; static tcmod_t tcmod; mat4_t m; assert( rsh.postProcessingVBO ); // blit + flip using a static mesh to avoid redundant buffer uploads // (also using custom PP effects like FXAA with the stream VBO causes // Adreno to mark the VBO as "slow" (due to some weird bug) // for the rest of the frame and drop FPS to 10-20). RB_FlushDynamicMeshes(); RB_BindFrameBufferObject( dstFbo ); if( !dstFbo ) { // default framebuffer // set the viewport to full resolution // but keep the scissoring region x = fd->x; y = fd->y; w = fw = fd->width; h = fh = fd->height; RB_Viewport( 0, 0, glConfig.width, glConfig.height ); RB_Scissor( rn.scissor[0], rn.scissor[1], rn.scissor[2], rn.scissor[3] ); } else { // aux framebuffer // set the viewport to full resolution of the framebuffer (without the NPOT padding if there's one) // draw quad on the whole framebuffer texture // set scissor to default framebuffer resolution image_t *cb = RFB_GetObjectTextureAttachment( dstFbo, false ); x = 0; y = 0; w = fw = rf.frameBufferWidth; h = fh = rf.frameBufferHeight; if( cb ) { fw = cb->upload_width; fh = cb->upload_height; } RB_Viewport( 0, 0, w, h ); RB_Scissor( 0, 0, glConfig.width, glConfig.height ); } s.vattribs = VATTRIB_POSITION_BIT|VATTRIB_TEXCOORDS_BIT; s.sort = SHADER_SORT_NEAREST; s.numpasses = 1; s.name = s_name; s.passes = &p; p.rgbgen.type = RGB_GEN_IDENTITY; p.alphagen.type = ALPHA_GEN_IDENTITY; p.tcgen = TC_GEN_NONE; p.images[0] = image; for( i = 0; i < numShaderImages; i++ ) p.images[i + 1] = shaderImages[i]; p.flags = blendMask; p.program_type = program_type; if( !dstFbo ) { tcmod.type = TC_MOD_TRANSFORM; tcmod.args[0] = ( float )( w ) / ( float )( image->upload_width ); tcmod.args[1] = ( float )( h ) / ( float )( image->upload_height ); tcmod.args[4] = ( float )( x ) / ( float )( image->upload_width ); tcmod.args[5] = ( float )( image->upload_height - h - y ) / ( float )( image->upload_height ); p.numtcmods = 1; p.tcmods = &tcmod; } else { p.numtcmods = 0; } Matrix4_Identity( m ); Matrix4_Scale2D( m, fw, fh ); Matrix4_Translate2D( m, x, y ); RB_LoadObjectMatrix( m ); RB_BindShader( NULL, &s, NULL ); RB_BindVBO( rsh.postProcessingVBO->index, GL_TRIANGLES ); RB_DrawElements( 0, 4, 0, 6, 0, 0, 0, 0 ); RB_LoadObjectMatrix( mat4x4_identity ); // restore 2D viewport and scissor RB_Viewport( 0, 0, rf.frameBufferWidth, rf.frameBufferHeight ); RB_Scissor( 0, 0, rf.frameBufferWidth, rf.frameBufferHeight ); }
/* * R_DrawSkeletalSurf */ qboolean R_DrawSkeletalSurf( const entity_t *e, const shader_t *shader, const mfog_t *fog, drawSurfaceSkeletal_t *drawSurf ) { unsigned int i, j; int framenum = e->frame; int oldframenum = e->oldframe; float backlerp = e->backlerp; float frontlerp = 1.0 - backlerp; bonepose_t tempbonepose[256]; const bonepose_t *bp, *oldbp, *bonepose, *oldbonepose, *lerpedbonepose; bonepose_t *out, tp; mskbone_t *bone; mat4_t *bonePoseRelativeMat; dualquat_t *bonePoseRelativeDQ; size_t bonePoseRelativeMatSize, bonePoseRelativeDQSize; const model_t *mod = drawSurf->model; const mskmodel_t *skmodel = ( const mskmodel_t * )mod->extradata; const mskmesh_t *skmesh = drawSurf->mesh; qboolean hardwareTransform = skmesh->vbo != NULL && glConfig.maxGLSLBones > 0 ? qtrue : qfalse; vattribmask_t vattribs; bonePoseRelativeMat = NULL; bonePoseRelativeDQ = NULL; bp = e->boneposes; oldbp = e->oldboneposes; // not sure if it's really needed if( bp == skmodel->frames[0].boneposes ) { bp = NULL; framenum = oldframenum = 0; } // choose boneposes for lerping if( bp ) { if( !oldbp ) oldbp = bp; } else { if( ( framenum >= (int)skmodel->numframes ) || ( framenum < 0 ) ) { #ifndef PUBLIC_BUILD ri.Com_DPrintf( "R_DrawBonesFrameLerp %s: no such frame %d\n", mod->name, framenum ); #endif framenum = 0; } if( ( oldframenum >= (int)skmodel->numframes ) || ( oldframenum < 0 ) ) { #ifndef PUBLIC_BUILD ri.Com_DPrintf( "R_DrawBonesFrameLerp %s: no such oldframe %d\n", mod->name, oldframenum ); #endif oldframenum = 0; } bp = skmodel->frames[framenum].boneposes; oldbp = skmodel->frames[oldframenum].boneposes; } if( bp == oldbp && !framenum && skmesh->vbo != NULL ) { // fastpath: render static frame 0 as is RB_BindVBO( skmesh->vbo->index, GL_TRIANGLES ); RB_DrawElements( 0, skmesh->numverts, 0, skmesh->numtris * 3 ); return qfalse; } // see what vertex attribs backend needs vattribs = RB_GetVertexAttribs(); // cache size bonePoseRelativeMatSize = sizeof( mat4_t ) * (skmodel->numbones + skmodel->numblends); bonePoseRelativeDQSize = sizeof( dualquat_t ) * skmodel->numbones; // fetch bones tranforms from cache (both matrices and dual quaternions) bonePoseRelativeDQ = ( dualquat_t * )R_GetSketalCache( R_ENT2NUM( e ), mod->lodnum ); if( bonePoseRelativeDQ ) { bonePoseRelativeMat = ( mat4_t * )(( qbyte * )bonePoseRelativeDQ + bonePoseRelativeDQSize); } else { // lerp boneposes and store results in cache lerpedbonepose = tempbonepose; if( bp == oldbp || frontlerp == 1 ) { if( e->boneposes ) { // assume that parent transforms have already been applied lerpedbonepose = bp; } else { for( i = 0; i < skmodel->numbones; i++ ) { j = i; out = tempbonepose + j; bonepose = bp + j; bone = skmodel->bones + j; if( bone->parent >= 0 ) { DualQuat_Multiply( tempbonepose[bone->parent].dualquat, bonepose->dualquat, out->dualquat ); } else { DualQuat_Copy( bonepose->dualquat, out->dualquat ); } } } } else { if( e->boneposes ) { // lerp, assume that parent transforms have already been applied for( i = 0, out = tempbonepose, bonepose = bp, oldbonepose = oldbp, bone = skmodel->bones; i < skmodel->numbones; i++, out++, bonepose++, oldbonepose++, bone++ ) { DualQuat_Lerp( oldbonepose->dualquat, bonepose->dualquat, frontlerp, out->dualquat ); } } else { // lerp and transform for( i = 0; i < skmodel->numbones; i++ ) { j = i; out = tempbonepose + j; bonepose = bp + j; oldbonepose = oldbp + j; bone = skmodel->bones + j; DualQuat_Lerp( oldbonepose->dualquat, bonepose->dualquat, frontlerp, out->dualquat ); if( bone->parent >= 0 ) { DualQuat_Copy( out->dualquat, tp.dualquat ); DualQuat_Multiply( tempbonepose[bone->parent].dualquat, tp.dualquat, out->dualquat ); } } } } bonePoseRelativeDQ = ( dualquat_t * )R_AllocSkeletalDataCache( R_ENT2NUM( e ), mod->lodnum, bonePoseRelativeDQSize + bonePoseRelativeMatSize ); // generate dual quaternions for all bones for( i = 0; i < skmodel->numbones; i++ ) { DualQuat_Multiply( lerpedbonepose[i].dualquat, skmodel->invbaseposes[i].dualquat, bonePoseRelativeDQ[i] ); DualQuat_Normalize( bonePoseRelativeDQ[i] ); } // CPU transforms if( !hardwareTransform ) { bonePoseRelativeMat = ( mat4_t * )(( qbyte * )bonePoseRelativeDQ + bonePoseRelativeDQSize); // generate matrices for all bones for( i = 0; i < skmodel->numbones; i++ ) { Matrix4_FromDualQuaternion( bonePoseRelativeDQ[i], bonePoseRelativeMat[i] ); } // generate matrices for all blend combinations R_SkeletalBlendPoses( skmodel->numblends, skmodel->blends, skmodel->numbones, bonePoseRelativeMat ); } } if( hardwareTransform ) { RB_BindVBO( skmesh->vbo->index, GL_TRIANGLES ); RB_SetBonesData( skmodel->numbones, bonePoseRelativeDQ, skmesh->maxWeights ); RB_DrawElements( 0, skmesh->numverts, 0, skmesh->numtris * 3 ); } else { mesh_t *rb_mesh; RB_BindVBO( RB_VBO_STREAM, GL_TRIANGLES ); rb_mesh = RB_MapBatchMesh( skmesh->numverts, skmesh->numtris * 3 ); if( !rb_mesh ) { ri.Com_DPrintf( S_COLOR_YELLOW "R_DrawAliasSurf: RB_MapBatchMesh returned NULL for (%s)(%s)", drawSurf->model->name, skmesh->name ); return qfalse; } R_SkeletalTransformVerts( skmesh->numverts, skmesh->vertexBlends, bonePoseRelativeMat, ( vec_t * )skmesh->xyzArray[0], ( vec_t * )rb_mesh->xyzArray ); if( vattribs & VATTRIB_SVECTOR_BIT ) { R_SkeletalTransformNormalsAndSVecs( skmesh->numverts, skmesh->vertexBlends, bonePoseRelativeMat, ( vec_t * )skmesh->normalsArray[0], ( vec_t * )rb_mesh->normalsArray, ( vec_t * )skmesh->sVectorsArray[0], ( vec_t * )rb_mesh->sVectorsArray ); } else if( vattribs & VATTRIB_NORMAL_BIT ) { R_SkeletalTransformNormals( skmesh->numverts, skmesh->vertexBlends, bonePoseRelativeMat, ( vec_t * )skmesh->normalsArray[0], ( vec_t * )rb_mesh->normalsArray ); } rb_mesh->elems = skmesh->elems; rb_mesh->numElems = skmesh->numtris * 3; rb_mesh->numVerts = skmesh->numverts; rb_mesh->stArray = skmesh->stArray; RB_UploadMesh( rb_mesh ); RB_EndBatch(); } return qfalse; }
/* * R_DrawSkySurf */ qboolean R_DrawSkySurf( const entity_t *e, const shader_t *shader, const mfog_t *fog, drawSurfaceBSP_t *drawSurf ) { int i; int numVisSides; visSkySide_t visSkySides[6]; vec3_t mins, maxs; int umin, umax, vmin, vmax; entity_t skyent; refdef_t *rd = &rn.refdef; skydome_t *skydome = r_worldbrushmodel->skydome; if( !skydome ) return qfalse; numVisSides = 0; ClearBounds( mins, maxs ); memset( visSkySides, 0, sizeof( visSkySides ) ); for( i = 0; i < 6; i++ ) { if( rn.skyMins[0][i] >= rn.skyMaxs[0][i] || rn.skyMins[1][i] >= rn.skyMaxs[1][i] ) continue; // increase the visible sides counter numVisSides++; umin = (int)( ( rn.skyMins[0][i]+1.0f )*0.5f*(float)( SIDE_SIZE-1 ) ); umax = (int)( ( rn.skyMaxs[0][i]+1.0f )*0.5f*(float)( SIDE_SIZE-1 ) ) + 1; vmin = (int)( ( rn.skyMins[1][i]+1.0f )*0.5f*(float)( SIDE_SIZE-1 ) ); vmax = (int)( ( rn.skyMaxs[1][i]+1.0f )*0.5f*(float)( SIDE_SIZE-1 ) ) + 1; clamp( umin, 0, SIDE_SIZE-1 ); clamp( umax, 0, SIDE_SIZE-1 ); clamp( vmin, 0, SIDE_SIZE-1 ); clamp( vmax, 0, SIDE_SIZE-1 ); visSkySides[i].index = i; visSkySides[i].firstVert = vmin * SIDE_SIZE + umin; visSkySides[i].numVerts = (vmax - vmin) * SIDE_SIZE + (umax - umin); visSkySides[i].firstElem = (vmin * (SIDE_SIZE-1) + umin) * 6; visSkySides[i].numElems = ((vmax - vmin) * (SIDE_SIZE-1) + (umax - umin)) * 6; AddPointToBounds( skydome->meshes[i].xyzArray[vmin*SIDE_SIZE+umin], mins, maxs ); AddPointToBounds( skydome->meshes[i].xyzArray[vmax*SIDE_SIZE+umax], mins, maxs ); skydome->meshes[i].numElems = visSkySides[i].numElems; } // no sides are truly visible, ignore if( !numVisSides ) return qfalse; VectorAdd( mins, rn.viewOrigin, mins ); VectorAdd( maxs, rn.viewOrigin, maxs ); if( rd->rdflags & RDF_SKYPORTALINVIEW ) { R_DrawSkyPortal( e, &rd->skyportal, mins, maxs ); return qfalse; } // center skydome on camera to give the illusion of a larger space skyent = *rsc.worldent; skyent.scale = shader->skyHeight; VectorCopy( rn.viewOrigin, skyent.origin ); R_TransformForEntity( &skyent ); if( shader->skyboxImages[0] ) R_DrawSkyBox( skydome, visSkySides, shader ); else R_DrawBlackBottom( skydome, visSkySides ); if( shader->numpasses ) { RB_BindShader( rsc.worldent, shader, rn.skyFog ); for( i = 0; i < 5; i++ ) { const visSkySide_t *visSide = visSkySides + i; if( rn.skyMins[0][i] >= rn.skyMaxs[0][i] || rn.skyMins[1][i] >= rn.skyMaxs[1][i] ) continue; RB_BindVBO( skydome->sphereVbos[i]->index, GL_TRIANGLES ); RB_DrawElements( visSide->firstVert, visSide->numVerts, visSide->firstElem, visSide->numElems ); } } R_TransformForEntity( e ); return qfalse; }