void Gui_FillCrosshairBuffer() { GLfloat x = (GLfloat)screen_info.w / 2.0f; GLfloat y = (GLfloat)screen_info.h / 2.0f; GLfloat *v, crosshairArray[32]; const GLfloat size = 8.0f; const GLfloat color[4] = {1.0f, 0.0f, 0.0f, 1.0f}; v = crosshairArray; *v++ = x; *v++ = y - size; vec4_copy(v, color); v += 4; *v++ = 0.0; *v++ = 0.0; *v++ = x; *v++ = y + size; vec4_copy(v, color); v += 4; *v++ = 0.0; *v++ = 0.0; *v++ = x - size; *v++ = y; vec4_copy(v, color); v += 4; *v++ = 0.0; *v++ = 0.0; *v++ = x + size; *v++ = y; vec4_copy(v, color); v += 4; *v++ = 0.0; *v++ = 0.0; // copy vertices into GL buffer qglBindBufferARB(GL_ARRAY_BUFFER, crosshairBuffer); qglBufferDataARB(GL_ARRAY_BUFFER, sizeof(GLfloat[32]), crosshairArray, GL_STATIC_DRAW); }
/* ======================== idJointBuffer::AllocBufferObject ======================== */ bool idJointBuffer::AllocBufferObject( const float * joints, int numAllocJoints ) { assert( apiObject == NULL ); assert_16_byte_aligned( joints ); if ( numAllocJoints <= 0 ) { idLib::Error( "idJointBuffer::AllocBufferObject: joints = %i", numAllocJoints ); } numJoints = numAllocJoints; bool allocationFailed = false; const int numBytes = GetAllocedSize(); GLuint buffer = 0; qglGenBuffersARB( 1, &buffer ); qglBindBufferARB( GL_UNIFORM_BUFFER, buffer ); qglBufferDataARB( GL_UNIFORM_BUFFER, numBytes, NULL, GL_STREAM_DRAW_ARB ); qglBindBufferARB( GL_UNIFORM_BUFFER, 0); apiObject = reinterpret_cast< void * >( buffer ); if ( r_showBuffers.GetBool() ) { idLib::Printf( "joint buffer alloc %p, api %p (%i joints)\n", this, GetAPIObject(), GetNumJoints() ); } // copy the data if ( joints != NULL ) { Update( joints, numAllocJoints ); } return !allocationFailed; }
void Gui_FillBackgroundBuffer() { GLfloat x0 = 0.0f; GLfloat y0 = 0.0f; GLfloat x1 = screen_info.w; GLfloat y1 = screen_info.h; GLfloat *v, backgroundArray[32]; GLfloat color[4] = {0.0f, 0.0f, 0.0f, 0.5f}; v = backgroundArray; *v++ = x0; *v++ = y0; vec4_copy(v, color); v += 4; *v++ = 0.0f; *v++ = 0.0f; *v++ = x1; *v++ = y0; vec4_copy(v, color); v += 4; *v++ = 1.0f; *v++ = 0.0f; *v++ = x1; *v++ = y1; vec4_copy(v, color); v += 4; *v++ = 1.0f; *v++ = 1.0f; *v++ = x0; *v++ = y1; vec4_copy(v, color); v += 4; *v++ = 0.0f; *v++ = 1.0f; qglBindBufferARB(GL_ARRAY_BUFFER, backgroundBuffer); qglBufferDataARB(GL_ARRAY_BUFFER, sizeof(GLfloat[32]), backgroundArray, GL_STATIC_DRAW); }
/* * R_DiscardVBOElemData */ void R_DiscardVBOElemData( mesh_vbo_t *vbo ) { GLenum elem_usage = VBO_ELEM_USAGE_FOR_TAG(vbo->tag); if( vbo->elemId ) { RB_BindElementArrayBuffer( vbo->elemId ); qglBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, vbo->elemBufferSize, NULL, elem_usage ); } }
/* * R_DiscardVBOVertexData */ void R_DiscardVBOVertexData( mesh_vbo_t *vbo ) { GLenum array_usage = VBO_ARRAY_USAGE_FOR_TAG(vbo->tag); if( vbo->vertexId ) { RB_BindArrayBuffer( vbo->vertexId ); qglBufferDataARB( GL_ARRAY_BUFFER_ARB, vbo->arrayBufferSize, NULL, array_usage ); } }
/* ============ R_CreateVBO ============ */ VBO_t *R_CreateVBO(const char *name, byte * vertexes, int vertexesSize, vboUsage_t usage) { VBO_t *vbo; int glUsage; switch (usage) { case VBO_USAGE_STATIC: glUsage = GL_STATIC_DRAW_ARB; break; case VBO_USAGE_DYNAMIC: glUsage = GL_DYNAMIC_DRAW_ARB; break; default: Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage); return NULL; } if(strlen(name) >= MAX_QPATH) { ri.Error(ERR_DROP, "R_CreateVBO: \"%s\" is too long\n", name); } if ( tr.numVBOs == MAX_VBOS ) { ri.Error( ERR_DROP, "R_CreateVBO: MAX_VBOS hit\n"); } // make sure the render thread is stopped R_SyncRenderThread(); vbo = tr.vbos[tr.numVBOs] = ri.Hunk_Alloc(sizeof(*vbo), h_low); tr.numVBOs++; memset(vbo, 0, sizeof(*vbo)); Q_strncpyz(vbo->name, name, sizeof(vbo->name)); vbo->vertexesSize = vertexesSize; qglGenBuffersARB(1, &vbo->vertexesVBO); qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO); qglBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexesSize, vertexes, glUsage); qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); glState.currentVBO = NULL; GL_CheckErrors(); return vbo; }
/* ============ R_CreateIBO ============ */ IBO_t *R_CreateIBO(const char *name, byte * indexes, int indexesSize, vboUsage_t usage) { IBO_t *ibo; int glUsage; switch (usage) { case VBO_USAGE_STATIC: glUsage = GL_STATIC_DRAW_ARB; break; case VBO_USAGE_DYNAMIC: glUsage = GL_DYNAMIC_DRAW_ARB; break; default: Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage); return NULL; } if(strlen(name) >= MAX_QPATH) { ri.Error(ERR_DROP, "R_CreateIBO: \"%s\" is too long", name); } if ( tr.numIBOs == MAX_IBOS ) { ri.Error( ERR_DROP, "R_CreateIBO: MAX_IBOS hit"); } R_IssuePendingRenderCommands(); ibo = tr.ibos[tr.numIBOs] = ri.Hunk_Alloc(sizeof(*ibo), h_low); tr.numIBOs++; Q_strncpyz(ibo->name, name, sizeof(ibo->name)); ibo->indexesSize = indexesSize; qglGenBuffersARB(1, &ibo->indexesVBO); qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo->indexesVBO); qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexesSize, indexes, glUsage); qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); glState.currentIBO = NULL; GL_CheckErrors(); return ibo; }
/* ============== idVertexCache::ActuallyFree ============== */ void idVertexCache::ActuallyFree(vertCache_t *block) { if (!block) { common->Error("idVertexCache Free: NULL pointer"); } if (block->user) { // let the owner know we have purged it *block->user = NULL; block->user = NULL; } // temp blocks are in a shared space that won't be freed if (block->tag != TAG_TEMP) { staticAllocTotal -= block->size; staticCountTotal--; if (block->vbo) { #if 0 // this isn't really necessary, it will be reused soon enough // filling with zero length data is the equivalent of freeing qglBindBufferARB(GL_ARRAY_BUFFER_ARB, block->vbo); qglBufferDataARB(GL_ARRAY_BUFFER_ARB, 0, 0, GL_DYNAMIC_DRAW_ARB); #endif } else if (block->virtMem) { Mem_Free(block->virtMem); block->virtMem = NULL; } } block->tag = TAG_FREE; // mark as free // unlink stick it back on the free list block->next->prev = block->prev; block->prev->next = block->next; #if 1 // stick it on the front of the free list so it will be reused immediately block->next = freeStaticHeaders.next; block->prev = &freeStaticHeaders; #else // stick it on the back of the free list so it won't be reused soon (just for debugging) block->next = &freeStaticHeaders; block->prev = freeStaticHeaders.prev; #endif block->next->prev = block; block->prev->next = block; }
/* ======================== idIndexBuffer::AllocBufferObject ======================== */ bool idIndexBuffer::AllocBufferObject( const void * data, int allocSize ) { assert( apiObject == NULL ); assert_16_byte_aligned( data ); if ( allocSize <= 0 ) { idLib::Error( "idIndexBuffer::AllocBufferObject: allocSize = %i", allocSize ); } size = allocSize; bool allocationFailed = false; int numBytes = GetAllocedSize(); // clear out any previous error qglGetError(); GLuint bufferObject = 0xFFFF; qglGenBuffersARB( 1, & bufferObject ); if ( bufferObject == 0xFFFF ) { GLenum error = qglGetError(); idLib::FatalError( "idIndexBuffer::AllocBufferObject: failed - GL_Error %d", error ); } qglBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, bufferObject ); // these are rewritten every frame qglBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, numBytes, NULL, bufferUsage ); apiObject = reinterpret_cast< void * >( bufferObject ); GLenum err = qglGetError(); if ( err == GL_OUT_OF_MEMORY ) { idLib::Warning( "idIndexBuffer:AllocBufferObject: allocation failed" ); allocationFailed = true; } if ( r_showBuffers.GetBool() ) { idLib::Printf( "index buffer alloc %p, api %p (%i bytes)\n", this, GetAPIObject(), GetSize() ); } // copy the data if ( data != NULL ) { Update( data, allocSize ); } return !allocationFailed; }
/* ============ R_CreateVBO2 ============ */ VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * verts, unsigned int stateBits, vboUsage_t usage) { VBO_t *vbo; int i; byte *data; int dataSize; int dataOfs; int glUsage; switch (usage) { case VBO_USAGE_STATIC: glUsage = GL_STATIC_DRAW_ARB; break; case VBO_USAGE_DYNAMIC: glUsage = GL_DYNAMIC_DRAW_ARB; break; default: Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage); return NULL; } if(!numVertexes) return NULL; if(strlen(name) >= MAX_QPATH) { ri.Error(ERR_DROP, "R_CreateVBO2: \"%s\" is too long", name); } if ( tr.numVBOs == MAX_VBOS ) { ri.Error( ERR_DROP, "R_CreateVBO2: MAX_VBOS hit"); } R_IssuePendingRenderCommands(); vbo = tr.vbos[tr.numVBOs] = ri.Hunk_Alloc(sizeof(*vbo), h_low); tr.numVBOs++; memset(vbo, 0, sizeof(*vbo)); Q_strncpyz(vbo->name, name, sizeof(vbo->name)); if (usage == VBO_USAGE_STATIC) { // since these vertex attributes are never altered, interleave them vbo->ofs_xyz = 0; dataSize = sizeof(verts[0].xyz); if(stateBits & ATTR_NORMAL) { vbo->ofs_normal = dataSize; dataSize += sizeof(uint8_t) * 4; } #ifdef USE_VERT_TANGENT_SPACE if(stateBits & ATTR_TANGENT) { vbo->ofs_tangent = dataSize; dataSize += sizeof(uint8_t) * 4; } #endif if(stateBits & ATTR_TEXCOORD) { vbo->ofs_st = dataSize; dataSize += sizeof(verts[0].st); } if(stateBits & ATTR_LIGHTCOORD) { vbo->ofs_lightmap = dataSize; dataSize += sizeof(verts[0].lightmap); } if(stateBits & ATTR_COLOR) { vbo->ofs_vertexcolor = dataSize; dataSize += sizeof(verts[0].vertexColors); } if(stateBits & ATTR_LIGHTDIRECTION) { vbo->ofs_lightdir = dataSize; dataSize += sizeof(verts[0].lightdir); } vbo->stride_xyz = dataSize; vbo->stride_normal = dataSize; #ifdef USE_VERT_TANGENT_SPACE vbo->stride_tangent = dataSize; #endif vbo->stride_st = dataSize; vbo->stride_lightmap = dataSize; vbo->stride_vertexcolor = dataSize; vbo->stride_lightdir = dataSize; // create VBO dataSize *= numVertexes; data = ri.Hunk_AllocateTempMemory(dataSize); dataOfs = 0; //ri.Printf(PRINT_ALL, "CreateVBO: %d, %d %d %d %d %d, %d %d %d %d %d\n", dataSize, vbo->ofs_xyz, vbo->ofs_normal, vbo->ofs_st, vbo->ofs_lightmap, vbo->ofs_vertexcolor, //vbo->stride_xyz, vbo->stride_normal, vbo->stride_st, vbo->stride_lightmap, vbo->stride_vertexcolor); for (i = 0; i < numVertexes; i++) { // xyz memcpy(data + dataOfs, &verts[i].xyz, sizeof(verts[i].xyz)); dataOfs += sizeof(verts[i].xyz); // normal if(stateBits & ATTR_NORMAL) { uint8_t *p = data + dataOfs; p[0] = (uint8_t)(verts[i].normal[0] * 127.5f + 128.0f); p[1] = (uint8_t)(verts[i].normal[1] * 127.5f + 128.0f); p[2] = (uint8_t)(verts[i].normal[2] * 127.5f + 128.0f); p[3] = 0; dataOfs += sizeof(uint8_t) * 4; } #ifdef USE_VERT_TANGENT_SPACE // tangent if(stateBits & ATTR_TANGENT) { vec3_t nxt; uint8_t *p = data + dataOfs; CrossProduct(verts[i].normal, verts[i].tangent, nxt); p[0] = (uint8_t)(verts[i].tangent[0] * 127.5f + 128.0f); p[1] = (uint8_t)(verts[i].tangent[1] * 127.5f + 128.0f); p[2] = (uint8_t)(verts[i].tangent[2] * 127.5f + 128.0f); p[3] = (uint8_t)(verts[i].tangent[3] * 127.5f + 128.0f); dataOfs += sizeof(uint8_t) * 4; } #endif // vertex texcoords if(stateBits & ATTR_TEXCOORD) { memcpy(data + dataOfs, &verts[i].st, sizeof(verts[i].st)); dataOfs += sizeof(verts[i].st); } // feed vertex lightmap texcoords if(stateBits & ATTR_LIGHTCOORD) { memcpy(data + dataOfs, &verts[i].lightmap, sizeof(verts[i].lightmap)); dataOfs += sizeof(verts[i].lightmap); } // feed vertex colors if(stateBits & ATTR_COLOR) { memcpy(data + dataOfs, &verts[i].vertexColors, sizeof(verts[i].vertexColors)); dataOfs += sizeof(verts[i].vertexColors); } // feed vertex light directions if(stateBits & ATTR_LIGHTDIRECTION) { memcpy(data + dataOfs, &verts[i].lightdir, sizeof(verts[i].lightdir)); dataOfs += sizeof(verts[i].lightdir); } } } else { // since these vertex attributes may be changed, put them in flat arrays dataSize = sizeof(verts[0].xyz); if(stateBits & ATTR_NORMAL) { dataSize += sizeof(uint8_t) * 4; } #ifdef USE_VERT_TANGENT_SPACE if(stateBits & ATTR_TANGENT) { dataSize += sizeof(uint8_t) * 4; } #endif if(stateBits & ATTR_TEXCOORD) { dataSize += sizeof(verts[0].st); } if(stateBits & ATTR_LIGHTCOORD) { dataSize += sizeof(verts[0].lightmap); } if(stateBits & ATTR_COLOR) { dataSize += sizeof(verts[0].vertexColors); } if(stateBits & ATTR_LIGHTDIRECTION) { dataSize += sizeof(verts[0].lightdir); } // create VBO dataSize *= numVertexes; data = ri.Hunk_AllocateTempMemory(dataSize); dataOfs = 0; vbo->ofs_xyz = 0; vbo->ofs_normal = 0; #ifdef USE_VERT_TANGENT_SPACE vbo->ofs_tangent = 0; #endif vbo->ofs_st = 0; vbo->ofs_lightmap = 0; vbo->ofs_vertexcolor = 0; vbo->ofs_lightdir = 0; vbo->stride_xyz = sizeof(verts[0].xyz); vbo->stride_normal = sizeof(uint8_t) * 4; #ifdef USE_VERT_TANGENT_SPACE vbo->stride_tangent = sizeof(uint8_t) * 4; #endif vbo->stride_vertexcolor = sizeof(verts[0].vertexColors); vbo->stride_st = sizeof(verts[0].st); vbo->stride_lightmap = sizeof(verts[0].lightmap); vbo->stride_lightdir = sizeof(verts[0].lightdir); //ri.Printf(PRINT_ALL, "2CreateVBO: %d, %d %d %d %d %d, %d %d %d %d %d\n", dataSize, vbo->ofs_xyz, vbo->ofs_normal, vbo->ofs_st, vbo->ofs_lightmap, vbo->ofs_vertexcolor, //vbo->stride_xyz, vbo->stride_normal, vbo->stride_st, vbo->stride_lightmap, vbo->stride_vertexcolor); // xyz for (i = 0; i < numVertexes; i++) { memcpy(data + dataOfs, &verts[i].xyz, sizeof(verts[i].xyz)); dataOfs += sizeof(verts[i].xyz); } // normal if(stateBits & ATTR_NORMAL) { vbo->ofs_normal = dataOfs; for (i = 0; i < numVertexes; i++) { uint8_t *p = data + dataOfs; p[0] = (uint8_t)(verts[i].normal[0] * 127.5f + 128.0f); p[1] = (uint8_t)(verts[i].normal[1] * 127.5f + 128.0f); p[2] = (uint8_t)(verts[i].normal[2] * 127.5f + 128.0f); p[3] = 0; dataOfs += sizeof(uint8_t) * 4; } } #ifdef USE_VERT_TANGENT_SPACE // tangent if(stateBits & ATTR_TANGENT) { vbo->ofs_tangent = dataOfs; for (i = 0; i < numVertexes; i++) { vec3_t nxt; uint8_t *p = data + dataOfs; CrossProduct(verts[i].normal, verts[i].tangent, nxt); p[0] = (uint8_t)(verts[i].tangent[0] * 127.5f + 128.0f); p[1] = (uint8_t)(verts[i].tangent[1] * 127.5f + 128.0f); p[2] = (uint8_t)(verts[i].tangent[2] * 127.5f + 128.0f); p[3] = (uint8_t)(verts[i].tangent[3] * 127.5f + 128.0f); dataOfs += sizeof(uint8_t) * 4; } } #endif // vertex texcoords if(stateBits & ATTR_TEXCOORD) { vbo->ofs_st = dataOfs; for (i = 0; i < numVertexes; i++) { memcpy(data + dataOfs, &verts[i].st, sizeof(verts[i].st)); dataOfs += sizeof(verts[i].st); } } // feed vertex lightmap texcoords if(stateBits & ATTR_LIGHTCOORD) { vbo->ofs_lightmap = dataOfs; for (i = 0; i < numVertexes; i++) { memcpy(data + dataOfs, &verts[i].lightmap, sizeof(verts[i].lightmap)); dataOfs += sizeof(verts[i].lightmap); } } // feed vertex colors if(stateBits & ATTR_COLOR) { vbo->ofs_vertexcolor = dataOfs; for (i = 0; i < numVertexes; i++) { memcpy(data + dataOfs, &verts[i].vertexColors, sizeof(verts[i].vertexColors)); dataOfs += sizeof(verts[i].vertexColors); } } // feed vertex lightdirs if(stateBits & ATTR_LIGHTDIRECTION) { vbo->ofs_lightdir = dataOfs; for (i = 0; i < numVertexes; i++) { memcpy(data + dataOfs, &verts[i].lightdir, sizeof(verts[i].lightdir)); dataOfs += sizeof(verts[i].lightdir); } } } vbo->vertexesSize = dataSize; qglGenBuffersARB(1, &vbo->vertexesVBO); qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO); qglBufferDataARB(GL_ARRAY_BUFFER_ARB, dataSize, data, glUsage); qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); glState.currentVBO = NULL; GL_CheckErrors(); ri.Hunk_FreeTempMemory(data); return vbo; }
/* ============== RB_UpdateVBOs Adapted from Tess_UpdateVBOs from xreal Update the default VBO to replace the client side vertex arrays ============== */ void RB_UpdateVBOs(unsigned int attribBits) { GLimp_LogComment("--- RB_UpdateVBOs ---\n"); backEnd.pc.c_dynamicVboDraws++; // update the default VBO if(tess.numVertexes > 0 && tess.numVertexes <= SHADER_MAX_VERTEXES) { R_BindVBO(tess.vbo); // orphan old buffer so we don't stall on it qglBufferDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->vertexesSize, NULL, GL_DYNAMIC_DRAW_ARB); if(attribBits & ATTR_BITS) { if(attribBits & ATTR_POSITION) { //ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_xyz, tess.numVertexes * sizeof(tess.xyz[0])); qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_xyz, tess.numVertexes * sizeof(tess.xyz[0]), tess.xyz); } if(attribBits & ATTR_TEXCOORD || attribBits & ATTR_LIGHTCOORD) { // these are interleaved, so we update both if either need it //ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_st, tess.numVertexes * sizeof(tess.texCoords[0][0]) * 2); qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_st, tess.numVertexes * sizeof(tess.texCoords[0][0]) * 2, tess.texCoords); } if(attribBits & ATTR_NORMAL) { //ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_normal, tess.numVertexes * sizeof(tess.normal[0])); qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_normal, tess.numVertexes * sizeof(tess.normal[0]), tess.normal); } #ifdef USE_VERT_TANGENT_SPACE if(attribBits & ATTR_TANGENT) { //ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_tangent, tess.numVertexes * sizeof(tess.tangent[0])); qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_tangent, tess.numVertexes * sizeof(tess.tangent[0]), tess.tangent); } #endif if(attribBits & ATTR_COLOR) { //ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_vertexcolor, tess.numVertexes * sizeof(tess.vertexColors[0])); qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_vertexcolor, tess.numVertexes * sizeof(tess.vertexColors[0]), tess.vertexColors); } if(attribBits & ATTR_LIGHTDIRECTION) { //ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_lightdir, tess.numVertexes * sizeof(tess.lightdir[0])); qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_lightdir, tess.numVertexes * sizeof(tess.lightdir[0]), tess.lightdir); } } else { qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_xyz, tess.numVertexes * sizeof(tess.xyz[0]), tess.xyz); qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_st, tess.numVertexes * sizeof(tess.texCoords[0][0]) * 2, tess.texCoords); qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_normal, tess.numVertexes * sizeof(tess.normal[0]), tess.normal); #ifdef USE_VERT_TANGENT_SPACE qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_tangent, tess.numVertexes * sizeof(tess.tangent[0]), tess.tangent); #endif qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_vertexcolor, tess.numVertexes * sizeof(tess.vertexColors[0]), tess.vertexColors); qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_lightdir, tess.numVertexes * sizeof(tess.lightdir[0]), tess.lightdir); } } // update the default IBO if(tess.numIndexes > 0 && tess.numIndexes <= SHADER_MAX_INDEXES) { R_BindIBO(tess.ibo); // orphan old buffer so we don't stall on it qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, tess.ibo->indexesSize, NULL, GL_DYNAMIC_DRAW_ARB); qglBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, tess.numIndexes * sizeof(tess.indexes[0]), tess.indexes); } }
/* * R_CreateMeshVBO * * Create two static buffer objects: vertex buffer and elements buffer, the real * data is uploaded by calling R_UploadVBOVertexData and R_UploadVBOElemData. * * Tag allows vertex buffer objects to be grouped and released simultaneously. */ mesh_vbo_t *R_CreateMeshVBO( void *owner, int numVerts, int numElems, int numInstances, vattribmask_t vattribs, vbo_tag_t tag, vattribmask_t halfFloatVattribs ) { int i; size_t size; GLuint vbo_id; vbohandle_t *vboh = NULL; mesh_vbo_t *vbo = NULL; GLenum array_usage = VBO_ARRAY_USAGE_FOR_TAG(tag); GLenum elem_usage = VBO_ELEM_USAGE_FOR_TAG(tag); size_t vertexSize; vattribbit_t lmattrbit; if( !glConfig.ext.vertex_buffer_object ) return NULL; if( !r_free_vbohandles ) return NULL; if( !glConfig.ext.half_float_vertex ) { halfFloatVattribs = 0; } else { if( !(halfFloatVattribs & VATTRIB_POSITION_BIT) ) { halfFloatVattribs &= ~(VATTRIB_AUTOSPRITE_BIT); } halfFloatVattribs &= ~VATTRIB_COLORS_BITS; halfFloatVattribs &= ~VATTRIB_BONES_BITS; // TODO: convert quaternion component of instance_t to half-float // when uploading instances data halfFloatVattribs &= ~VATTRIB_INSTANCES_BITS; } vboh = r_free_vbohandles; vbo = &r_mesh_vbo[vboh->index]; memset( vbo, 0, sizeof( *vbo ) ); // vertex data vertexSize = 0; vertexSize += FLOAT_VATTRIB_SIZE(VATTRIB_POSITION_BIT, halfFloatVattribs) * 4; // normals data if( vattribs & VATTRIB_NORMAL_BIT ) { assert( !(vertexSize & 3) ); vbo->normalsOffset = vertexSize; vertexSize += FLOAT_VATTRIB_SIZE(VATTRIB_NORMAL_BIT, halfFloatVattribs) * 4; } // s-vectors (tangent vectors) if( vattribs & VATTRIB_SVECTOR_BIT ) { assert( !(vertexSize & 3) ); vbo->sVectorsOffset = vertexSize; vertexSize += FLOAT_VATTRIB_SIZE(VATTRIB_SVECTOR_BIT, halfFloatVattribs) * 4; } // texture coordinates if( vattribs & VATTRIB_TEXCOORDS_BIT ) { assert( !(vertexSize & 3) ); vbo->stOffset = vertexSize; vertexSize += FLOAT_VATTRIB_SIZE(VATTRIB_TEXCOORDS_BIT, halfFloatVattribs) * 2; } // lightmap texture coordinates lmattrbit = VATTRIB_LMCOORDS0_BIT; for( i = 0; i < MAX_LIGHTMAPS/2; i++ ) { if( !(vattribs & lmattrbit) ) { break; } assert( !(vertexSize & 3) ); vbo->lmstOffset[i] = vertexSize; vbo->lmstSize[i] = vattribs & VATTRIB_LMCOORDS0_BIT<<1 ? 4 : 2; vertexSize += FLOAT_VATTRIB_SIZE(VATTRIB_LMCOORDS0_BIT, halfFloatVattribs) * vbo->lmstSize[i]; lmattrbit = ( vattribbit_t )( ( vattribmask_t )lmattrbit << 2 ); } // vertex colors if( vattribs & VATTRIB_COLOR0_BIT ) { assert( !(vertexSize & 3) ); vbo->colorsOffset[0] = vertexSize; vertexSize += sizeof( int ); } // bones data for skeletal animation if( (vattribs & VATTRIB_BONES_BITS) == VATTRIB_BONES_BITS ) { assert( SKM_MAX_WEIGHTS == 4 ); assert( !(vertexSize & 3) ); vbo->bonesIndicesOffset = vertexSize; vertexSize += sizeof( int ); assert( !(vertexSize & 3) ); vbo->bonesWeightsOffset = vertexSize; vertexSize += sizeof( int ); } // autosprites // FIXME: autosprite2 requires waaaay too much data for such a trivial // transformation.. if( (vattribs & VATTRIB_AUTOSPRITE_BIT) == VATTRIB_AUTOSPRITE_BIT ) { assert( !(vertexSize & 3) ); vbo->spritePointsOffset = vertexSize; vertexSize += FLOAT_VATTRIB_SIZE(VATTRIB_AUTOSPRITE_BIT, halfFloatVattribs) * 4; } size = vertexSize * numVerts; // instances data if( ( (vattribs & VATTRIB_INSTANCES_BITS) == VATTRIB_INSTANCES_BITS ) && numInstances && glConfig.ext.instanced_arrays ) { assert( !(vertexSize & 3) ); vbo->instancesOffset = size; size += numInstances * sizeof( GLfloat ) * 8; } // pre-allocate vertex buffer vbo_id = 0; qglGenBuffersARB( 1, &vbo_id ); if( !vbo_id ) goto error; vbo->vertexId = vbo_id; RB_BindArrayBuffer( vbo->vertexId ); qglBufferDataARB( GL_ARRAY_BUFFER_ARB, size, NULL, array_usage ); if( qglGetError () == GL_OUT_OF_MEMORY ) goto error; vbo->arrayBufferSize = size; // pre-allocate elements buffer vbo_id = 0; qglGenBuffersARB( 1, &vbo_id ); if( !vbo_id ) goto error; vbo->elemId = vbo_id; size = numElems * sizeof( elem_t ); RB_BindElementArrayBuffer( vbo->elemId ); qglBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, size, NULL, elem_usage ); if( qglGetError () == GL_OUT_OF_MEMORY ) goto error; vbo->elemBufferSize = size; r_free_vbohandles = vboh->next; // link to the list of active vbo handles vboh->prev = &r_vbohandles_headnode; vboh->next = r_vbohandles_headnode.next; vboh->next->prev = vboh; vboh->prev->next = vboh; r_num_active_vbos++; vbo->registrationSequence = rsh.registrationSequence; vbo->vertexSize = vertexSize; vbo->numVerts = numVerts; vbo->numElems = numElems; vbo->owner = owner; vbo->index = vboh->index + 1; vbo->tag = tag; vbo->halfFloatAttribs = halfFloatVattribs; return vbo; error: if( vbo ) R_ReleaseMeshVBO( vbo ); RB_BindArrayBuffer( 0 ); RB_BindElementArrayBuffer( 0 ); return NULL; }
/** * Draws simple colored rectangle with given parameters. */ void Gui_DrawRect(const GLfloat &x, const GLfloat &y, const GLfloat &width, const GLfloat &height, const float colorUpperLeft[], const float colorUpperRight[], const float colorLowerLeft[], const float colorLowerRight[], const int &blendMode, const GLuint texture) { switch(blendMode) { case BM_HIDE: return; case BM_MULTIPLY: qglBlendFunc(GL_SRC_ALPHA, GL_ONE); break; case BM_SIMPLE_SHADE: qglBlendFunc(GL_ONE_MINUS_SRC_COLOR, GL_ONE_MINUS_SRC_ALPHA); break; case BM_SCREEN: qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break; default: case BM_OPAQUE: qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break; }; GLfloat x0 = x; GLfloat y0 = y + height; GLfloat x1 = x + width; GLfloat y1 = y; GLfloat *v, rectArray[32]; v = rectArray; *v++ = x0; *v++ = y0; *v++ = 0.0f; *v++ = 0.0f; vec4_copy(v, colorUpperLeft); v += 4; *v++ = x1; *v++ = y0; *v++ = 1.0f; *v++ = 0.0f; vec4_copy(v, colorUpperRight); v += 4; *v++ = x1; *v++ = y1; *v++ = 1.0f; *v++ = 1.0f; vec4_copy(v, colorLowerRight); v += 4; *v++ = x0; *v++ = y1; *v++ = 0.0f; *v++ = 1.0f; vec4_copy(v, colorLowerLeft); if(qglIsTexture(texture)) { qglBindTexture(GL_TEXTURE_2D, texture); } else { BindWhiteTexture(); } qglBindBufferARB(GL_ARRAY_BUFFER, rectBuffer); qglBufferDataARB(GL_ARRAY_BUFFER, sizeof(GLfloat[32]), rectArray, GL_DYNAMIC_DRAW); qglVertexPointer(2, GL_FLOAT, 8 * sizeof(GLfloat), (void *)0); qglTexCoordPointer(2, GL_FLOAT, 8 * sizeof(GLfloat), (void *)sizeof(GLfloat[2])); qglColorPointer(4, GL_FLOAT, 8 * sizeof(GLfloat), (void *)sizeof(GLfloat[4])); qglDrawArrays(GL_TRIANGLE_FAN, 0, 4); }
/* =========== idVertexCache::Alloc =========== */ void idVertexCache::Alloc(void *data, int size, vertCache_t **buffer, bool indexBuffer) { vertCache_t *block; if (size <= 0) { common->Error("idVertexCache::Alloc: size = %i\n", size); } // if we can't find anything, it will be NULL *buffer = NULL; // if we don't have any remaining unused headers, allocate some more if (freeStaticHeaders.next == &freeStaticHeaders) { for (int i = 0; i < EXPAND_HEADERS; i++) { block = headerAllocator.Alloc(); block->next = freeStaticHeaders.next; block->prev = &freeStaticHeaders; block->next->prev = block; block->prev->next = block; if (!virtualMemory) { qglGenBuffersARB(1, & block->vbo); } } } // move it from the freeStaticHeaders list to the staticHeaders list block = freeStaticHeaders.next; block->next->prev = block->prev; block->prev->next = block->next; block->next = staticHeaders.next; block->prev = &staticHeaders; block->next->prev = block; block->prev->next = block; block->size = size; block->offset = 0; block->tag = TAG_USED; // save data for debugging staticAllocThisFrame += block->size; staticCountThisFrame++; staticCountTotal++; staticAllocTotal += block->size; // this will be set to zero when it is purged block->user = buffer; *buffer = block; // allocation doesn't imply used-for-drawing, because at level // load time lots of things may be created, but they aren't // referenced by the GPU yet, and can be purged if needed. block->frameUsed = currentFrame - NUM_VERTEX_FRAMES; block->indexBuffer = indexBuffer; // copy the data if (block->vbo) { if (indexBuffer) { qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, block->vbo); qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, (GLsizeiptrARB)size, data, GL_STATIC_DRAW_ARB); } else { qglBindBufferARB(GL_ARRAY_BUFFER_ARB, block->vbo); if (allocatingTempBuffer) { qglBufferDataARB(GL_ARRAY_BUFFER_ARB, (GLsizeiptrARB)size, data, GL_STREAM_DRAW_ARB); } else { qglBufferDataARB(GL_ARRAY_BUFFER_ARB, (GLsizeiptrARB)size, data, GL_STATIC_DRAW_ARB); } } } else { block->virtMem = Mem_Alloc(size); SIMDProcessor->Memcpy(block->virtMem, data, size); } }
/* ============ R_CreateIBO2 ============ */ IBO_t *R_CreateIBO2(const char *name, int numTriangles, srfTriangle_t * triangles, vboUsage_t usage) { IBO_t *ibo; int i, j; byte *indexes; int indexesSize; int indexesOfs; srfTriangle_t *tri; glIndex_t index; int glUsage; switch (usage) { case VBO_USAGE_STATIC: glUsage = GL_STATIC_DRAW_ARB; break; case VBO_USAGE_DYNAMIC: glUsage = GL_DYNAMIC_DRAW_ARB; break; default: Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage); return NULL; } if(!numTriangles) return NULL; if(strlen(name) >= MAX_QPATH) { ri.Error(ERR_DROP, "R_CreateIBO2: \"%s\" is too long\n", name); } if ( tr.numIBOs == MAX_IBOS ) { ri.Error( ERR_DROP, "R_CreateIBO2: MAX_IBOS hit\n"); } // make sure the render thread is stopped R_SyncRenderThread(); ibo = tr.ibos[tr.numIBOs] = ri.Hunk_Alloc(sizeof(*ibo), h_low); tr.numIBOs++; Q_strncpyz(ibo->name, name, sizeof(ibo->name)); indexesSize = numTriangles * 3 * sizeof(int); indexes = ri.Hunk_AllocateTempMemory(indexesSize); indexesOfs = 0; for(i = 0, tri = triangles; i < numTriangles; i++, tri++) { for(j = 0; j < 3; j++) { index = tri->indexes[j]; memcpy(indexes + indexesOfs, &index, sizeof(glIndex_t)); indexesOfs += sizeof(glIndex_t); } } ibo->indexesSize = indexesSize; qglGenBuffersARB(1, &ibo->indexesVBO); qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo->indexesVBO); qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexesSize, indexes, glUsage); qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); glState.currentIBO = NULL; GL_CheckErrors(); ri.Hunk_FreeTempMemory(indexes); return ibo; }