/* ============= RB_SurfacePolychain ============= */ static void RB_SurfacePolychain( srfPoly_t *p ) { int i; int numv; RB_CheckVao(tess.vao); RB_CHECKOVERFLOW( p->numVerts, 3*(p->numVerts - 2) ); // fan triangles into the tess array numv = tess.numVertexes; for ( i = 0; i < p->numVerts; i++ ) { VectorCopy( p->verts[i].xyz, tess.xyz[numv] ); tess.texCoords[numv][0] = p->verts[i].st[0]; tess.texCoords[numv][1] = p->verts[i].st[1]; tess.color[numv][0] = (int)p->verts[i].modulate[0] * 257; tess.color[numv][1] = (int)p->verts[i].modulate[1] * 257; tess.color[numv][2] = (int)p->verts[i].modulate[2] * 257; tess.color[numv][3] = (int)p->verts[i].modulate[3] * 257; numv++; } // generate fan indexes into the tess array for ( i = 0; i < p->numVerts-2; i++ ) { tess.indexes[tess.numIndexes + 0] = tess.numVertexes; tess.indexes[tess.numIndexes + 1] = tess.numVertexes + i + 1; tess.indexes[tess.numIndexes + 2] = tess.numVertexes + i + 2; tess.numIndexes += 3; } tess.numVertexes = numv; }
static void DoRailCore( const vec3_t start, const vec3_t end, const vec3_t up, float len, float spanWidth ) { float spanWidth2; int vbase; float t = len / 256.0f; RB_CheckVao(tess.vao); RB_CHECKOVERFLOW( 4, 6 ); vbase = tess.numVertexes; spanWidth2 = -spanWidth; // FIXME: use quad stamp? VectorMA( start, spanWidth, up, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0] = 0; tess.texCoords[tess.numVertexes][1] = 0; tess.color[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 0.25f * 257.0f; tess.color[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 0.25f * 257.0f; tess.color[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 0.25f * 257.0f; tess.numVertexes++; VectorMA( start, spanWidth2, up, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0] = 0; tess.texCoords[tess.numVertexes][1] = 1; tess.color[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 257; tess.color[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 257; tess.color[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 257; tess.numVertexes++; VectorMA( end, spanWidth, up, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0] = t; tess.texCoords[tess.numVertexes][1] = 0; tess.color[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 257; tess.color[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 257; tess.color[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 257; tess.numVertexes++; VectorMA( end, spanWidth2, up, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0] = t; tess.texCoords[tess.numVertexes][1] = 1; tess.color[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 257; tess.color[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 257; tess.color[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 257; tess.numVertexes++; tess.indexes[tess.numIndexes++] = vbase; tess.indexes[tess.numIndexes++] = vbase + 1; tess.indexes[tess.numIndexes++] = vbase + 2; tess.indexes[tess.numIndexes++] = vbase + 2; tess.indexes[tess.numIndexes++] = vbase + 1; tess.indexes[tess.numIndexes++] = vbase + 3; }
/* ============= RB_SurfaceMesh ============= */ static void RB_SurfaceMesh(mdvSurface_t *surface) { int j; float backlerp; mdvSt_t *texCoords; int Bob, Doug; int numVerts; if ( backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame ) { backlerp = 0; } else { backlerp = backEnd.currentEntity->e.backlerp; } RB_CheckVao(tess.vao); RB_CHECKOVERFLOW( surface->numVerts, surface->numIndexes ); LerpMeshVertexes (surface, backlerp); Bob = tess.numIndexes; Doug = tess.numVertexes; for (j = 0 ; j < surface->numIndexes ; j++) { tess.indexes[Bob + j] = Doug + surface->indexes[j]; } tess.numIndexes += surface->numIndexes; texCoords = surface->st; numVerts = surface->numVerts; for ( j = 0; j < numVerts; j++ ) { tess.texCoords[Doug + j][0] = texCoords[j].st[0]; tess.texCoords[Doug + j][1] = texCoords[j].st[1]; // FIXME: fill in lightmapST for completeness? } tess.numVertexes += surface->numVerts; }
/* ============= RB_SurfaceGrid Just copy the grid of points and triangulate ============= */ static void RB_SurfaceGrid( srfBspSurface_t *srf ) { int i, j; float *xyz; float *texCoords, *lightCoords; int16_t *normal; int16_t *tangent; uint16_t *color; int16_t *lightdir; srfVert_t *dv; int rows, irows, vrows; int used; int widthTable[MAX_GRID_SIZE]; int heightTable[MAX_GRID_SIZE]; float lodError; int lodWidth, lodHeight; int numVertexes; int dlightBits; int pshadowBits; //int *vDlightBits; if (RB_SurfaceVaoCached(srf->numVerts, srf->verts, srf->numIndexes, srf->indexes, srf->dlightBits, srf->pshadowBits)) { return; } RB_CheckVao(tess.vao); dlightBits = srf->dlightBits; tess.dlightBits |= dlightBits; pshadowBits = srf->pshadowBits; tess.pshadowBits |= pshadowBits; // determine the allowable discrepance lodError = LodErrorForVolume( srf->lodOrigin, srf->lodRadius ); // determine which rows and columns of the subdivision // we are actually going to use widthTable[0] = 0; lodWidth = 1; for ( i = 1 ; i < srf->width-1 ; i++ ) { if ( srf->widthLodError[i] <= lodError ) { widthTable[lodWidth] = i; lodWidth++; } } widthTable[lodWidth] = srf->width-1; lodWidth++; heightTable[0] = 0; lodHeight = 1; for ( i = 1 ; i < srf->height-1 ; i++ ) { if ( srf->heightLodError[i] <= lodError ) { heightTable[lodHeight] = i; lodHeight++; } } heightTable[lodHeight] = srf->height-1; lodHeight++; // very large grids may have more points or indexes than can be fit // in the tess structure, so we may have to issue it in multiple passes used = 0; while ( used < lodHeight - 1 ) { // see how many rows of both verts and indexes we can add without overflowing do { vrows = ( SHADER_MAX_VERTEXES - tess.numVertexes ) / lodWidth; irows = ( SHADER_MAX_INDEXES - tess.numIndexes ) / ( lodWidth * 6 ); // if we don't have enough space for at least one strip, flush the buffer if ( vrows < 2 || irows < 1 ) { RB_EndSurface(); RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex ); } else { break; } } while ( 1 ); rows = irows; if ( vrows < irows + 1 ) { rows = vrows - 1; } if ( used + rows > lodHeight ) { rows = lodHeight - used; } numVertexes = tess.numVertexes; xyz = tess.xyz[numVertexes]; normal = tess.normal[numVertexes]; tangent = tess.tangent[numVertexes]; texCoords = tess.texCoords[numVertexes]; lightCoords = tess.lightCoords[numVertexes]; color = tess.color[numVertexes]; lightdir = tess.lightdir[numVertexes]; //vDlightBits = &tess.vertexDlightBits[numVertexes]; for ( i = 0 ; i < rows ; i++ ) { for ( j = 0 ; j < lodWidth ; j++ ) { dv = srf->verts + heightTable[ used + i ] * srf->width + widthTable[ j ]; if ( tess.shader->vertexAttribs & ATTR_POSITION ) { VectorCopy(dv->xyz, xyz); xyz += 4; } if ( tess.shader->vertexAttribs & ATTR_NORMAL ) { VectorCopy4(dv->normal, normal); normal += 4; } if ( tess.shader->vertexAttribs & ATTR_TANGENT ) { VectorCopy4(dv->tangent, tangent); tangent += 4; } if ( tess.shader->vertexAttribs & ATTR_TEXCOORD ) { VectorCopy2(dv->st, texCoords); texCoords += 2; } if ( tess.shader->vertexAttribs & ATTR_LIGHTCOORD ) { VectorCopy2(dv->lightmap, lightCoords); lightCoords += 2; } if ( tess.shader->vertexAttribs & ATTR_COLOR ) { VectorCopy4(dv->color, color); color += 4; } if ( tess.shader->vertexAttribs & ATTR_LIGHTDIRECTION ) { VectorCopy4(dv->lightdir, lightdir); lightdir += 4; } //*vDlightBits++ = dlightBits; } } // add the indexes { int numIndexes; int w, h; h = rows - 1; w = lodWidth - 1; numIndexes = tess.numIndexes; for (i = 0 ; i < h ; i++) { for (j = 0 ; j < w ; j++) { int v1, v2, v3, v4; // vertex order to be reckognized as tristrips v1 = numVertexes + i*lodWidth + j + 1; v2 = v1 - 1; v3 = v2 + lodWidth; v4 = v3 + 1; tess.indexes[numIndexes] = v2; tess.indexes[numIndexes+1] = v3; tess.indexes[numIndexes+2] = v1; tess.indexes[numIndexes+3] = v1; tess.indexes[numIndexes+4] = v3; tess.indexes[numIndexes+5] = v4; numIndexes += 6; } } tess.numIndexes = numIndexes; } tess.numVertexes += rows * lodWidth; used += rows - 1; } }
/* ============== RB_AddQuadStampExt ============== */ void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, float color[4], float s1, float t1, float s2, float t2 ) { vec3_t normal; int16_t iNormal[4]; uint16_t iColor[4]; int ndx; RB_CheckVao(tess.vao); RB_CHECKOVERFLOW( 4, 6 ); ndx = tess.numVertexes; // triangle indexes for a simple quad tess.indexes[ tess.numIndexes ] = ndx; tess.indexes[ tess.numIndexes + 1 ] = ndx + 1; tess.indexes[ tess.numIndexes + 2 ] = ndx + 3; tess.indexes[ tess.numIndexes + 3 ] = ndx + 3; tess.indexes[ tess.numIndexes + 4 ] = ndx + 1; tess.indexes[ tess.numIndexes + 5 ] = ndx + 2; tess.xyz[ndx][0] = origin[0] + left[0] + up[0]; tess.xyz[ndx][1] = origin[1] + left[1] + up[1]; tess.xyz[ndx][2] = origin[2] + left[2] + up[2]; tess.xyz[ndx+1][0] = origin[0] - left[0] + up[0]; tess.xyz[ndx+1][1] = origin[1] - left[1] + up[1]; tess.xyz[ndx+1][2] = origin[2] - left[2] + up[2]; tess.xyz[ndx+2][0] = origin[0] - left[0] - up[0]; tess.xyz[ndx+2][1] = origin[1] - left[1] - up[1]; tess.xyz[ndx+2][2] = origin[2] - left[2] - up[2]; tess.xyz[ndx+3][0] = origin[0] + left[0] - up[0]; tess.xyz[ndx+3][1] = origin[1] + left[1] - up[1]; tess.xyz[ndx+3][2] = origin[2] + left[2] - up[2]; // constant normal all the way around VectorSubtract( vec3_origin, backEnd.viewParms.or.axis[0], normal ); R_VaoPackNormal(iNormal, normal); VectorCopy4(iNormal, tess.normal[ndx]); VectorCopy4(iNormal, tess.normal[ndx + 1]); VectorCopy4(iNormal, tess.normal[ndx + 2]); VectorCopy4(iNormal, tess.normal[ndx + 3]); // standard square texture coordinates VectorSet2(tess.texCoords[ndx], s1, t1); VectorSet2(tess.lightCoords[ndx], s1, t1); VectorSet2(tess.texCoords[ndx+1], s2, t1); VectorSet2(tess.lightCoords[ndx+1], s2, t1); VectorSet2(tess.texCoords[ndx+2], s2, t2); VectorSet2(tess.lightCoords[ndx+2], s2, t2); VectorSet2(tess.texCoords[ndx+3], s1, t2); VectorSet2(tess.lightCoords[ndx+3], s1, t2); // constant color all the way around // should this be identity and let the shader specify from entity? R_VaoPackColor(iColor, color); VectorCopy4(iColor, tess.color[ndx]); VectorCopy4(iColor, tess.color[ndx + 1]); VectorCopy4(iColor, tess.color[ndx + 2]); VectorCopy4(iColor, tess.color[ndx + 3]); tess.numVertexes += 4; tess.numIndexes += 6; }
static void DoRailDiscs( int numSegs, const vec3_t start, const vec3_t dir, const vec3_t right, const vec3_t up ) { int i; vec3_t pos[4]; vec3_t v; int spanWidth = r_railWidth->integer; float c, s; float scale; if ( numSegs > 1 ) numSegs--; if ( !numSegs ) return; scale = 0.25; for ( i = 0; i < 4; i++ ) { c = cos( DEG2RAD( 45 + i * 90 ) ); s = sin( DEG2RAD( 45 + i * 90 ) ); v[0] = ( right[0] * c + up[0] * s ) * scale * spanWidth; v[1] = ( right[1] * c + up[1] * s ) * scale * spanWidth; v[2] = ( right[2] * c + up[2] * s ) * scale * spanWidth; VectorAdd( start, v, pos[i] ); if ( numSegs > 1 ) { // offset by 1 segment if we're doing a long distance shot VectorAdd( pos[i], dir, pos[i] ); } } RB_CheckVao(tess.vao); for ( i = 0; i < numSegs; i++ ) { int j; RB_CHECKOVERFLOW( 4, 6 ); for ( j = 0; j < 4; j++ ) { VectorCopy( pos[j], tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0] = (j < 2); tess.texCoords[tess.numVertexes][1] = (j && j != 3); tess.color[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 257; tess.color[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 257; tess.color[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 257; tess.numVertexes++; VectorAdd( pos[j], dir, pos[j] ); } tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 0; tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 1; tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 3; tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 3; tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 1; tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 2; } }
static void RB_SurfaceVertsAndIndexes( int numVerts, srfVert_t *verts, int numIndexes, glIndex_t *indexes, int dlightBits, int pshadowBits) { int i; glIndex_t *inIndex; srfVert_t *dv; float *xyz, *texCoords, *lightCoords; int16_t *lightdir; int16_t *normal; int16_t *tangent; glIndex_t *outIndex; uint16_t *color; RB_CheckVao(tess.vao); RB_CHECKOVERFLOW( numVerts, numIndexes ); inIndex = indexes; outIndex = &tess.indexes[ tess.numIndexes ]; for ( i = 0 ; i < numIndexes ; i++ ) { *outIndex++ = tess.numVertexes + *inIndex++; } tess.numIndexes += numIndexes; if ( tess.shader->vertexAttribs & ATTR_POSITION ) { dv = verts; xyz = tess.xyz[ tess.numVertexes ]; for ( i = 0 ; i < numVerts ; i++, dv++, xyz+=4 ) VectorCopy(dv->xyz, xyz); } if ( tess.shader->vertexAttribs & ATTR_NORMAL ) { dv = verts; normal = tess.normal[ tess.numVertexes ]; for ( i = 0 ; i < numVerts ; i++, dv++, normal+=4 ) VectorCopy4(dv->normal, normal); } if ( tess.shader->vertexAttribs & ATTR_TANGENT ) { dv = verts; tangent = tess.tangent[ tess.numVertexes ]; for ( i = 0 ; i < numVerts ; i++, dv++, tangent+=4 ) VectorCopy4(dv->tangent, tangent); } if ( tess.shader->vertexAttribs & ATTR_TEXCOORD ) { dv = verts; texCoords = tess.texCoords[tess.numVertexes]; for ( i = 0 ; i < numVerts ; i++, dv++, texCoords+=2 ) VectorCopy2(dv->st, texCoords); } if ( tess.shader->vertexAttribs & ATTR_LIGHTCOORD ) { dv = verts; lightCoords = tess.lightCoords[ tess.numVertexes ]; for ( i = 0 ; i < numVerts ; i++, dv++, lightCoords+=2 ) VectorCopy2(dv->lightmap, lightCoords); } if ( tess.shader->vertexAttribs & ATTR_COLOR ) { dv = verts; color = tess.color[ tess.numVertexes ]; for ( i = 0 ; i < numVerts ; i++, dv++, color+=4 ) VectorCopy4(dv->color, color); } if ( tess.shader->vertexAttribs & ATTR_LIGHTDIRECTION ) { dv = verts; lightdir = tess.lightdir[ tess.numVertexes ]; for ( i = 0 ; i < numVerts ; i++, dv++, lightdir+=4 ) VectorCopy4(dv->lightdir, lightdir); } #if 0 // nothing even uses vertex dlightbits for ( i = 0 ; i < numVerts ; i++ ) { tess.vertexDlightBits[ tess.numVertexes + i ] = dlightBits; } #endif tess.dlightBits |= dlightBits; tess.pshadowBits |= pshadowBits; tess.numVertexes += numVerts; }
static qboolean RB_SurfaceVao(vao_t *vao, int numVerts, int numIndexes, int firstIndex, int minIndex, int maxIndex, int dlightBits, int pshadowBits, qboolean shaderCheck) { int i, mergeForward, mergeBack; GLvoid *firstIndexOffset, *lastIndexOffset; if (!vao) { return qfalse; } if (shaderCheck && !(!ShaderRequiresCPUDeforms(tess.shader) && !tess.shader->isSky && !tess.shader->isPortal)) { return qfalse; } RB_CheckVao(vao); tess.dlightBits |= dlightBits; tess.pshadowBits |= pshadowBits; // merge this into any existing multidraw primitives mergeForward = -1; mergeBack = -1; firstIndexOffset = BUFFER_OFFSET(firstIndex * sizeof(glIndex_t)); lastIndexOffset = BUFFER_OFFSET((firstIndex + numIndexes) * sizeof(glIndex_t)); if (tess.multiDrawPrimitives && r_mergeMultidraws->integer) { i = 0; if (r_mergeMultidraws->integer == 1) { // lazy merge, only check the last primitive i = tess.multiDrawPrimitives - 1; } for (; i < tess.multiDrawPrimitives; i++) { if (firstIndexOffset == tess.multiDrawFirstIndex[i] + tess.multiDrawNumIndexes[i]) { mergeBack = i; if (mergeForward != -1) break; } if (lastIndexOffset == tess.multiDrawFirstIndex[i]) { mergeForward = i; if (mergeBack != -1) break; } } } if (mergeBack != -1 && mergeForward == -1) { tess.multiDrawNumIndexes[mergeBack] += numIndexes; tess.multiDrawMinIndex[mergeBack] = MIN(tess.multiDrawMinIndex[mergeBack], minIndex); tess.multiDrawMaxIndex[mergeBack] = MAX(tess.multiDrawMaxIndex[mergeBack], maxIndex); backEnd.pc.c_multidrawsMerged++; } else if (mergeBack == -1 && mergeForward != -1) { tess.multiDrawNumIndexes[mergeForward] += numIndexes; tess.multiDrawFirstIndex[mergeForward] = firstIndexOffset; tess.multiDrawMinIndex[mergeForward] = MIN(tess.multiDrawMinIndex[mergeForward], minIndex); tess.multiDrawMaxIndex[mergeForward] = MAX(tess.multiDrawMaxIndex[mergeForward], maxIndex); backEnd.pc.c_multidrawsMerged++; } else if (mergeBack != -1 && mergeForward != -1) { tess.multiDrawNumIndexes[mergeBack] += numIndexes + tess.multiDrawNumIndexes[mergeForward]; tess.multiDrawMinIndex[mergeBack] = MIN(tess.multiDrawMinIndex[mergeBack], MIN(tess.multiDrawMinIndex[mergeForward], minIndex)); tess.multiDrawMaxIndex[mergeBack] = MAX(tess.multiDrawMaxIndex[mergeBack], MAX(tess.multiDrawMaxIndex[mergeForward], maxIndex)); tess.multiDrawPrimitives--; if (mergeForward != tess.multiDrawPrimitives) { tess.multiDrawNumIndexes[mergeForward] = tess.multiDrawNumIndexes[tess.multiDrawPrimitives]; tess.multiDrawFirstIndex[mergeForward] = tess.multiDrawFirstIndex[tess.multiDrawPrimitives]; tess.multiDrawMinIndex[mergeForward] = tess.multiDrawMinIndex[tess.multiDrawPrimitives]; tess.multiDrawMaxIndex[mergeForward] = tess.multiDrawMaxIndex[tess.multiDrawPrimitives]; } backEnd.pc.c_multidrawsMerged += 2; } else //if (mergeBack == -1 && mergeForward == -1) { tess.multiDrawNumIndexes[tess.multiDrawPrimitives] = numIndexes; tess.multiDrawFirstIndex[tess.multiDrawPrimitives] = firstIndexOffset; tess.multiDrawMinIndex[tess.multiDrawPrimitives] = minIndex; tess.multiDrawMaxIndex[tess.multiDrawPrimitives] = maxIndex; tess.multiDrawPrimitives++; } backEnd.pc.c_multidraws++; tess.numIndexes += numIndexes; tess.numVertexes += numVerts; return qtrue; }