/* * RB_EndBatch */ void RB_EndBatch( void ) { int stream; vboSlice_t *batch; vboSlice_t *offset; if( rb.currentVBOId >= RB_VBO_NONE ) { return; } stream = -rb.currentVBOId - 1; offset = &rb.streamOffset[stream]; batch = &rb.batches[stream]; if( batch->numVerts ) { RB_UploadBatchMesh( batch ); } if( !offset->numVerts || !offset->numElems ) { return; } RB_DrawElements( offset->firstVert, offset->numVerts, offset->firstElem, offset->numElems ); offset->firstVert += offset->numVerts; offset->firstElem += offset->numElems; offset->numVerts = offset->numElems = 0; }
/* * 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; }
/* * 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, 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_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_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_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 ); }
/* * RB_UploadMesh */ void RB_UploadMesh( const mesh_t *mesh ) { int stream; mesh_vbo_t *vbo; vboSlice_t *offset; vbo_hint_t vbo_hint = VBO_HINT_NONE; int numVerts = mesh->numVerts, numElems = mesh->numElems; assert( rb.currentVBOId < RB_VBO_NONE ); if( rb.currentVBOId >= RB_VBO_NONE ) { return; } if( rb.currentVBOId == RB_VBO_STREAM_QUAD ) { numElems = numVerts/4*6; } else if( !numElems && rb.currentVBOId == RB_VBO_STREAM ) { numElems = (max(numVerts, 2) - 2) * 3; } if( !numVerts || !numElems ) { return; } vbo = rb.currentVBO; stream = -rb.currentVBOId - 1; offset = &rb.streamOffset[stream]; if( offset->firstVert+offset->numVerts+numVerts > MAX_STREAM_VBO_VERTS || offset->firstElem+offset->numVerts+numElems > MAX_STREAM_VBO_ELEMENTS ) { RB_DrawElements( offset->firstVert, offset->numVerts, offset->firstElem, offset->numElems ); R_DiscardVBOVertexData( vbo ); if( rb.currentVBOId != RB_VBO_STREAM_QUAD ) { R_DiscardVBOElemData( vbo ); } offset->firstVert = 0; offset->firstElem = 0; offset->numVerts = 0; offset->numElems = 0; } if( numVerts > MAX_STREAM_VBO_VERTS || numElems > MAX_STREAM_VBO_ELEMENTS ) { // FIXME: do something about this? return; } if( rb.currentVBOId == RB_VBO_STREAM_QUAD ) { vbo_hint = VBO_HINT_ELEMS_QUAD; // quad indices are stored in a static vbo, don't call R_UploadVBOElemData } else { if( mesh->elems ) { vbo_hint = VBO_HINT_NONE; } else if( rb.currentVBOId == RB_VBO_STREAM ) { vbo_hint = VBO_HINT_ELEMS_TRIFAN; } else { assert( 0 ); } R_UploadVBOElemData( vbo, offset->firstVert + offset->numVerts, offset->firstElem + offset->numElems, mesh, vbo_hint ); } R_UploadVBOVertexData( vbo, offset->firstVert + offset->numVerts, rb.currentVAttribs, mesh, vbo_hint ); offset->numElems += numElems; offset->numVerts += numVerts; }
/* * 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 ); }
void RB_DrawSkyDome(int tiles, float rows, int height, int radius, float offset, float topoffs, unsigned int c1, unsigned int c2) { fixed_t x, y, z; fixed_t lx, ly; int i; angle_t an; float tu1, tu2; int r; vtx_t *vtx; int count; lx = ly = count = 0; #define NUM_SKY_DOME_FACES 32 // // front faces are drawn here, so cull the back faces // RB_SetState(GLSTATE_CULL, true); RB_SetCull(GLCULL_BACK); RB_SetState(GLSTATE_DEPTHTEST, true); RB_SetState(GLSTATE_BLEND, true); RB_SetState(GLSTATE_ALPHATEST, false); r = radius / (NUM_SKY_DOME_FACES / 4); // // set pointer for the main vertex list // RB_BindDrawPointers(drawVertex); vtx = drawVertex; // excuse the mess...... #define SKYDOME_VERTEX() vtx->x = FIXED2FLOAT(x); vtx->y = FIXED2FLOAT(y); vtx->z = FIXED2FLOAT(z) #define SKYDOME_UV(u, v) vtx->tu = u; vtx->tv = v #define SKYDOME_LEFT(v, h) \ x = lx; \ y = ly; \ z = (h<<FRACBITS); \ SKYDOME_UV(tu1, v); \ SKYDOME_VERTEX(); \ vtx++ #define SKYDOME_RIGHT(v, h) \ x = lx + FixedMul((r<<FRACBITS), finecosine[angle >> ANGLETOFINESHIFT]); \ y = ly + FixedMul((r<<FRACBITS), finesine[angle >> ANGLETOFINESHIFT]); \ z = (h<<FRACBITS); \ SKYDOME_UV((tu2 * (i + 1)), v); \ SKYDOME_VERTEX(); \ vtx++ tu1 = 0; tu2 = ((float)tiles / (float)NUM_SKY_DOME_FACES) * 0.5f; an = (ANG_MAX / NUM_SKY_DOME_FACES); // // setup vertex data // for(i = 0; i < NUM_SKY_DOME_FACES; ++i) { angle_t angle = an * i; *(unsigned int*)&vtx[0].r = c2; *(unsigned int*)&vtx[1].r = c1; *(unsigned int*)&vtx[2].r = c1; *(unsigned int*)&vtx[3].r = c2; SKYDOME_LEFT(rows, -height); SKYDOME_LEFT(topoffs, height); SKYDOME_RIGHT(topoffs, height); SKYDOME_RIGHT(rows, -height); lx = x; ly = y; RB_AddTriangle(0+count, 1+count, 2+count); RB_AddTriangle(3+count, 0+count, 2+count); count += 4; tu1 += tu2; } for(i = 0; i < NUM_SKY_DOME_FACES * 4; i++) { drawVertex[i].x += -((float)radius / ((float)NUM_SKY_DOME_FACES / 2.0f)); drawVertex[i].y += -((float)radius / (M_PI / 2)); drawVertex[i].z += -offset; } // // draw sky dome // RB_DrawElements(); RB_ResetElements(); RB_SetCull(GLCULL_FRONT); #undef SKYDOME_RIGHT #undef SKYDOME_LEFT #undef SKYDOME_UV #undef SKYDOME_VERTEX #undef NUM_SKY_DOME_FACES }
/* * 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; }
/* * 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; }
/* * 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 ); } }
/* * 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_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 ); }
void RB_DrawClouds(const int lump) { vtx_t *v; int i; rbTexture_t *texture; RB_SetCull(GLCULL_BACK); texture = RB_GetTexture(RDT_PATCH, lump, 0); RB_BindTexture(texture); RB_ChangeTexParameters(texture, TC_REPEAT, TEXFILTER); RB_BindDrawPointers(drawVertex); v = drawVertex; /* -------------------------- |\ / | | \ / | | \ / | | \ _______ / | | | | | | | | | | | | | | |_______| | | / \ | | / \ | | / \ | |/ \ | -------------------------- */ v[0].x = -CLOUD_OUTER_SIZE; v[0].y = CLOUD_OUTER_SIZE; v[0].z = CLOUD_HEIGHT; v[1].x = CLOUD_OUTER_SIZE; v[1].y = CLOUD_OUTER_SIZE; v[1].z = CLOUD_HEIGHT; v[2].x = CLOUD_OUTER_SIZE; v[2].y = -CLOUD_OUTER_SIZE; v[2].z = CLOUD_HEIGHT; v[3].x = -CLOUD_SIZE; v[3].y = -CLOUD_SIZE; v[3].z = CLOUD_HEIGHT; v[4].x = -CLOUD_SIZE; v[4].y = CLOUD_SIZE; v[4].z = CLOUD_HEIGHT; v[5].x = CLOUD_SIZE; v[5].y = -CLOUD_SIZE; v[5].z = CLOUD_HEIGHT; v[6].x = -CLOUD_OUTER_SIZE; v[6].y = -CLOUD_OUTER_SIZE; v[6].z = CLOUD_HEIGHT; v[7].x = CLOUD_SIZE; v[7].y = CLOUD_SIZE; v[7].z = CLOUD_HEIGHT; v[0].tu = CLOUD_TILE_INNER; v[0].tv = CLOUD_TILE_OUTER; v[1].tu = CLOUD_TILE_INNER; v[1].tv = CLOUD_TILE_INNER; v[2].tu = CLOUD_TILE_OUTER; v[2].tv = CLOUD_TILE_INNER; v[3].tu = CLOUD_TILE; v[3].tv = CLOUD_TILE; v[4].tu = 0.0f; v[4].tv = CLOUD_TILE; v[5].tu = CLOUD_TILE; v[5].tv = 0.0f; v[6].tu = CLOUD_TILE_OUTER; v[6].tv = CLOUD_TILE_OUTER; v[7].tu = 0.0f; v[7].tv = 0.0f; for(i = 0; i < 8; ++i) { v[i].r = 255; v[i].g = 255; v[i].b = 255; v[i].a = 100; v[i].tu += sky_cloudpan1; v[i].tv += sky_cloudpan2; } // zero out the outer portion of the geometry so it blends into the sky dome v[3].a = v[4].a = v[5].a = v[7].a = 0; v[3].r = v[4].r = v[5].r = v[7].r = 0; v[3].g = v[4].g = v[5].g = v[7].g = 0; v[3].b = v[4].b = v[5].b = v[7].b = 0; RB_SetBlend(GLSRC_ONE, GLDST_ONE_MINUS_SRC_ALPHA); RB_AddTriangle(0, 1, 2); RB_AddTriangle(4, 0, 3); RB_AddTriangle(5, 3, 6); RB_AddTriangle(7, 5, 2); RB_AddTriangle(4, 7, 1); RB_AddTriangle(6, 0, 2); RB_AddTriangle(3, 0, 6); RB_AddTriangle(2, 5, 6); RB_AddTriangle(1, 7, 2); RB_AddTriangle(0, 4, 1); RB_DrawElements(); RB_ResetElements(); }