/* * Mod_AliasBuildStaticVBOForMesh * * Builds a static vertex buffer object for given alias model mesh */ static void Mod_AliasBuildStaticVBOForMesh( maliasmesh_t *mesh ) { int i; mesh_t aliasmesh; vattribmask_t vattribs; vattribs = VATTRIB_TEXCOORDS_BIT | VATTRIB_NORMAL_BIT | VATTRIB_SVECTOR_BIT; for( i = 0; i < mesh->numskins; i++ ) { vattribs |= mesh->skins[i].shader->vattribs; } mesh->vbo = R_CreateMeshVBO( ( void * )mesh, mesh->numverts, mesh->numtris * 3, 0, vattribs, VBO_TAG_MODEL ); if( !mesh->vbo ) { return; } memset( &aliasmesh, 0, sizeof( aliasmesh ) ); aliasmesh.elems = mesh->elems; aliasmesh.numElems = mesh->numtris * 3; aliasmesh.numVerts = mesh->numverts; aliasmesh.xyzArray = mesh->xyzArray; aliasmesh.stArray = mesh->stArray; aliasmesh.normalsArray = mesh->normalsArray; aliasmesh.sVectorsArray = mesh->sVectorsArray; R_UploadVBOVertexData( mesh->vbo, 0, vattribs, &aliasmesh, VBO_HINT_NONE ); R_UploadVBOElemData( mesh->vbo, 0, 0, &aliasmesh, VBO_HINT_NONE ); }
/* * Mod_SkeletalBuildStaticVBOForMesh * * Builds a static vertex buffer object for given skeletal model mesh */ static void Mod_SkeletalBuildStaticVBOForMesh( mskmesh_t *mesh ) { mesh_t skmmesh; vattribmask_t vattribs; vattribs = VATTRIB_POSITION_BIT | VATTRIB_TEXCOORDS_BIT | VATTRIB_NORMAL_BIT | VATTRIB_SVECTOR_BIT; vattribs |= VATTRIB_BONES_BITS; vattribs |= mesh->skin.shader->vattribs; mesh->vbo = R_CreateMeshVBO( ( void * )mesh, mesh->numverts, mesh->numtris * 3, 0, vattribs, VBO_TAG_MODEL, vattribs ); if( !mesh->vbo ) { return; } memset( &skmmesh, 0, sizeof( skmmesh ) ); skmmesh.elems = mesh->elems; skmmesh.numElems = mesh->numtris * 3; skmmesh.numVerts = mesh->numverts; skmmesh.xyzArray = mesh->xyzArray; skmmesh.stArray = mesh->stArray; skmmesh.normalsArray = mesh->normalsArray; skmmesh.sVectorsArray = mesh->sVectorsArray; R_UploadVBOVertexData( mesh->vbo, 0, vattribs, &skmmesh, VBO_HINT_NONE ); R_UploadVBOElemData( mesh->vbo, 0, 0, &skmmesh, VBO_HINT_NONE ); if( glConfig.maxGLSLBones > 0 ) { R_UploadVBOBonesData( mesh->vbo, 0, mesh->numverts, mesh->blendIndices, mesh->blendWeights ); } }
/* * Mod_AliasBuildStaticVBOForMesh * * Builds a static vertex buffer object for given alias model mesh */ static void Mod_AliasBuildStaticVBOForMesh( maliasmesh_t *mesh ) { mesh_t aliasmesh; mesh->vbo = R_CreateStaticMeshVBO( ( void * )mesh, mesh->numverts, mesh->numtris * 3, MF_STCOORDS | (mesh->sVectorsArray ? MF_SVECTORS : 0), VBO_TAG_MODEL ); if( !mesh->vbo ) { return; } aliasmesh.elems = mesh->elems; aliasmesh.numElems = mesh->numtris * 3; aliasmesh.numVerts = mesh->numverts; aliasmesh.xyzArray = mesh->xyzArray; aliasmesh.stArray = mesh->stArray; aliasmesh.normalsArray = mesh->normalsArray; aliasmesh.sVectorsArray = mesh->sVectorsArray; R_UploadVBOVertexData( mesh->vbo, 0, &aliasmesh ); R_UploadVBOElemData( mesh->vbo, 0, 0, &aliasmesh ); }
/* * 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; }
/* * Gen_BoxSide * * I don't know exactly what Q3A does for skybox texturing, but * this is at least fairly close. We tile the texture onto the * inside of a large sphere, and put the camera near the top of * the sphere. We place the box around the camera, and cast rays * through the box verts to the sphere to find the texture coordinates. */ static void Gen_BoxSide( skydome_t *skydome, int side, vec3_t orig, vec3_t drow, vec3_t dcol ) { vec3_t pos, w, row, norm; float *v, *n, *st = NULL, *st2; int r, c; float t, d, d2, b, b2, q[2], s; elem_t *elem; mesh_t *mesh = &( skydome->meshes[side] ); s = 1.0 / ( SIDE_SIZE - 1 ); d = EYE_RAD; // sphere center to camera distance d2 = d * d; b = SPHERE_RAD; // sphere radius b2 = b * b; q[0] = 1.0 / ( 2.0 * SCALE_S ); q[1] = 1.0 / ( 2.0 * SCALE_T ); v = mesh->xyzArray[0]; n = mesh->normalsArray[0]; if( side != 5 ) { st = skydome->sphereStCoords[side][0]; } st2 = skydome->linearStCoords[side][0]; VectorCopy( orig, row ); // CrossProduct( dcol, drow, norm ); // VectorNormalize( norm ); VectorClear( norm ); for( r = 0; r < SIDE_SIZE; r++ ) { VectorCopy( row, pos ); for( c = 0; c < SIDE_SIZE; c++ ) { // pos points from eye to vertex on box VectorCopy( pos, v ); VectorCopy( pos, w ); // Normalize pos -> w VectorNormalize( w ); // Find distance along w to sphere t = sqrt( d2 * ( w[2] * w[2] - 1.0 ) + b2 ) - d * w[2]; w[0] *= t; w[1] *= t; if( st ) { // use x and y on sphere as s and t // minus is here so skies scoll in correct (Q3A's) direction st[0] = -w[0] * q[0]; st[1] = -w[1] * q[1]; // avoid bilerp seam st[0] = ( bound( -1, st[0], 1 ) + 1.0 ) * 0.5; st[1] = ( bound( -1, st[1], 1 ) + 1.0 ) * 0.5; } st2[0] = c * s; st2[1] = 1.0 - r * s; VectorAdd( pos, dcol, pos ); VectorCopy( norm, n ); v[3] = 0; // set w-coordinate to 0 for infinite farclip n[3] = 0; v += 4; n += 4; if( st ) { st += 2; } st2 += 2; } VectorAdd( row, drow, row ); } // elements in tristrip order elem = mesh->elems; for( r = 0; r < SIDE_SIZE - 1; r++ ) { for( c = 0; c < SIDE_SIZE - 1; c++ ) { elem[0] = r * SIDE_SIZE + c; elem[1] = elem[4] = elem[0] + SIDE_SIZE; elem[2] = elem[3] = elem[0] + 1; elem[5] = elem[1] + 1; elem += 6; } } // upload two static VBO's for each side except for the bottom one // which only has 1 side for skybox if( side != 5 ) { mesh->stArray = skydome->sphereStCoords[side]; R_UploadVBOVertexData( skydome->sphereVbos[side], 0, SKYDOME_VATTRIBS, mesh ); R_UploadVBOElemData( skydome->sphereVbos[side], 0, 0, mesh ); } skydome->meshes[side].stArray = skydome->linearStCoords[side]; R_UploadVBOVertexData( skydome->linearVbos[side], 0, SKYDOME_VATTRIBS, mesh ); R_UploadVBOElemData( skydome->linearVbos[side], 0, 0, mesh ); }