void RMesh_MakeVertexBuffers (model_t *mod) { // because the buffers may have been used by a previous model if (mod->meshvbo) glDeleteBuffers (1, &mod->meshvbo); if (mod->texcoordvbo) glDeleteBuffers (1, &mod->texcoordvbo); if (mod->indexbuffer) glDeleteBuffers (1, &mod->indexbuffer); if (mod->meshvao) glDeleteVertexArrays (1, &mod->meshvao); RMesh_CreateFrames (mod, (dmdl_t *) mod->extradata); RMesh_CreateTexCoords (mod, (dmdl_t *) mod->extradata); RMesh_CreateIndexes (mod, (dmdl_t *) mod->extradata); glGenVertexArrays (1, &mod->meshvao); glEnableVertexArrayAttribEXT (mod->meshvao, 0); glVertexArrayVertexAttribOffsetEXT (mod->meshvao, mod->meshvbo, 0, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof (posevert_t), 0); glEnableVertexArrayAttribEXT (mod->meshvao, 1); glVertexArrayVertexAttribOffsetEXT (mod->meshvao, mod->meshvbo, 1, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof (posevert_t), 0); glEnableVertexArrayAttribEXT (mod->meshvao, 2); glVertexArrayVertexAttribOffsetEXT (mod->meshvao, mod->texcoordvbo, 2, 2, GL_FLOAT, GL_FALSE, 0, 0); mod->lastcurrframe = 0; mod->lastlastframe = 0; GL_BindVertexArray (mod->meshvao); glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, mod->indexbuffer); }
bool initVertexArray() { glGenVertexArrays(1, &VertexArrayName); glVertexArrayVertexAttribOffsetEXT(VertexArrayName, BufferName[buffer::VERTEX], glf::semantic::attr::POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(glf::vertex_v2fv2f), 0); glVertexArrayVertexAttribOffsetEXT(VertexArrayName, BufferName[buffer::VERTEX], glf::semantic::attr::TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(glf::vertex_v2fv2f), sizeof(glm::vec2)); glEnableVertexArrayAttribEXT(VertexArrayName, glf::semantic::attr::POSITION); glEnableVertexArrayAttribEXT(VertexArrayName, glf::semantic::attr::TEXCOORD); return glf::checkError("initVertexArray"); }
void OGLRenderLayout::BindVertexStreams(ShaderObjectPtr const & so, GLuint vao) const { OGLShaderObjectPtr const & ogl_so = checked_pointer_cast<OGLShaderObject>(so); RenderEngine& re = Context::Instance().RenderFactoryInstance().RenderEngineInstance(); uint32_t max_vertex_streams = re.DeviceCaps().max_vertex_streams; std::vector<char> used_streams(max_vertex_streams, 0); for (uint32_t i = 0; i < this->NumVertexStreams(); ++ i) { OGLGraphicsBuffer& stream(*checked_pointer_cast<OGLGraphicsBuffer>(this->GetVertexStream(i))); uint32_t const size = this->VertexSize(i); auto const & vertex_stream_fmt = this->VertexStreamFormat(i); if (glloader_GL_VERSION_4_5() || glloader_GL_ARB_direct_state_access()) { glVertexArrayVertexBuffer(vao, i, stream.GLvbo(), this->StartVertexLocation() * size, size); } uint32_t elem_offset = 0; for (auto const & vs_elem : vertex_stream_fmt) { GLint attr = ogl_so->GetAttribLocation(vs_elem.usage, vs_elem.usage_index); if (attr != -1) { GLintptr offset = elem_offset + this->StartVertexLocation() * size; GLint const num_components = static_cast<GLint>(NumComponents(vs_elem.format)); GLenum type; GLboolean normalized; OGLMapping::MappingVertexFormat(type, normalized, vs_elem.format); normalized = (((VEU_Diffuse == vs_elem.usage) || (VEU_Specular == vs_elem.usage)) && !IsFloatFormat(vs_elem.format)) ? GL_TRUE : normalized; BOOST_ASSERT(GL_ARRAY_BUFFER == stream.GLType()); stream.Active(true); if (glloader_GL_VERSION_4_5() || glloader_GL_ARB_direct_state_access()) { glVertexArrayAttribFormat(vao, attr, num_components, type, normalized, elem_offset); glVertexArrayAttribBinding(vao, attr, i); glEnableVertexArrayAttrib(vao, attr); } else if (glloader_GL_EXT_direct_state_access()) { glVertexArrayVertexAttribOffsetEXT(vao, stream.GLvbo(), attr, num_components, type, normalized, size, offset); glEnableVertexArrayAttribEXT(vao, attr); } else { glVertexAttribPointer(attr, num_components, type, normalized, size, reinterpret_cast<GLvoid*>(offset)); glEnableVertexAttribArray(attr); } used_streams[attr] = 1; } elem_offset += vs_elem.element_size(); } } if (this->InstanceStream()) { OGLGraphicsBuffer& stream(*checked_pointer_cast<OGLGraphicsBuffer>(this->InstanceStream())); uint32_t const instance_size = this->InstanceSize(); BOOST_ASSERT(this->NumInstances() * instance_size <= stream.Size()); if (glloader_GL_VERSION_4_5() || glloader_GL_ARB_direct_state_access()) { glVertexArrayVertexBuffer(vao, this->NumVertexStreams(), stream.GLvbo(), this->StartInstanceLocation() * instance_size, instance_size); glVertexArrayBindingDivisor(vao, this->NumVertexStreams(), 1); } size_t const inst_format_size = this->InstanceStreamFormat().size(); uint32_t elem_offset = 0; for (size_t i = 0; i < inst_format_size; ++ i) { VertexElement const & vs_elem = this->InstanceStreamFormat()[i]; GLint attr = ogl_so->GetAttribLocation(vs_elem.usage, vs_elem.usage_index); if (attr != -1) { GLint const num_components = static_cast<GLint>(NumComponents(vs_elem.format)); GLenum type; GLboolean normalized; OGLMapping::MappingVertexFormat(type, normalized, vs_elem.format); normalized = (((VEU_Diffuse == vs_elem.usage) || (VEU_Specular == vs_elem.usage)) && !IsFloatFormat(vs_elem.format)) ? GL_TRUE : normalized; GLintptr offset = elem_offset + this->StartInstanceLocation() * instance_size; BOOST_ASSERT(GL_ARRAY_BUFFER == stream.GLType()); stream.Active(true); if (glloader_GL_VERSION_4_5() || glloader_GL_ARB_direct_state_access()) { glVertexArrayAttribFormat(vao, attr, num_components, type, normalized, elem_offset); glVertexArrayAttribBinding(vao, attr, this->NumVertexStreams()); glEnableVertexArrayAttrib(vao, attr); } else if (glloader_GL_EXT_direct_state_access()) { glVertexArrayVertexAttribOffsetEXT(vao, stream.GLvbo(), attr, num_components, type, normalized, instance_size, offset); glEnableVertexArrayAttribEXT(vao, attr); glVertexAttribDivisor(attr, 1); } else { glVertexAttribPointer(attr, num_components, type, normalized, instance_size, reinterpret_cast<GLvoid*>(offset)); glEnableVertexAttribArray(attr); glVertexAttribDivisor(attr, 1); } used_streams[attr] = 1; } elem_offset += vs_elem.element_size(); } } for (GLuint i = 0; i < max_vertex_streams; ++ i) { if (!used_streams[i]) { if (glloader_GL_VERSION_4_5() || glloader_GL_ARB_direct_state_access()) { glDisableVertexArrayAttrib(vao, i); } else if (glloader_GL_EXT_direct_state_access()) { glDisableVertexArrayAttribEXT(vao, i); } else { glDisableVertexAttribArray(i); } } } }
//[-------------------------------------------------------] //[ Public methods ] //[-------------------------------------------------------] VertexArrayVaoDsa::VertexArrayVaoDsa(OpenGLRenderer &openGLRenderer, const Renderer::VertexAttributes& vertexAttributes, uint32_t numberOfVertexBuffers, const Renderer::VertexArrayVertexBuffer *vertexBuffers, IndexBuffer *indexBuffer) : VertexArrayVao(openGLRenderer, numberOfVertexBuffers, vertexBuffers, indexBuffer) { // Vertex buffer reference handling is done within the base class "VertexArrayVao" const bool isARB_DSA = openGLRenderer.getExtensions().isGL_ARB_direct_state_access(); if (isARB_DSA) { // Create the OpenGL vertex array glCreateVertexArrays(1, &mOpenGLVertexArray); } else { // Create the OpenGL vertex array glGenVertexArrays(1, &mOpenGLVertexArray); } // Loop through all attributes // -> We're using "glBindAttribLocationARB()" when linking the program so we have known attribute locations (the vertex array can't know about the program) GLuint attributeLocation = 0; const Renderer::VertexAttribute *attributeEnd = vertexAttributes.attributes + vertexAttributes.numberOfAttributes; for (const Renderer::VertexAttribute *attribute = vertexAttributes.attributes; attribute < attributeEnd; ++attribute, ++attributeLocation) { // Set the OpenGL vertex attribute pointer // TODO(co) Add security check: Is the given resource one of the currently used renderer? const Renderer::VertexArrayVertexBuffer& vertexArrayVertexBuffer = vertexBuffers[attribute->inputSlot]; if (isARB_DSA) { // Enable attribute glEnableVertexArrayAttrib(mOpenGLVertexArray, attributeLocation); // Set up the format for my attribute glVertexArrayAttribFormat(mOpenGLVertexArray, attributeLocation, Mapping::getOpenGLSize(attribute->vertexAttributeFormat), Mapping::getOpenGLType(attribute->vertexAttributeFormat), static_cast<GLboolean>(Mapping::isOpenGLVertexAttributeFormatNormalized(attribute->vertexAttributeFormat)), static_cast<GLuint>(attribute->alignedByteOffset)); // Bind vertex buffer to buffer point glVertexArrayVertexBuffer(mOpenGLVertexArray, attributeLocation, static_cast<VertexBuffer*>(vertexArrayVertexBuffer.vertexBuffer)->getOpenGLArrayBuffer(), 0, // No offset to the first element of the buffer static_cast<GLsizei>(vertexArrayVertexBuffer.strideInBytes)); // Per-instance instead of per-vertex requires "GL_ARB_instanced_arrays" if (attribute->instancesPerElement > 0 && openGLRenderer.getExtensions().isGL_ARB_instanced_arrays()) { glVertexArrayBindingDivisor(mOpenGLVertexArray, attributeLocation, attribute->instancesPerElement); } } else { glVertexArrayVertexAttribOffsetEXT(mOpenGLVertexArray, static_cast<VertexBuffer*>(vertexArrayVertexBuffer.vertexBuffer)->getOpenGLArrayBuffer(), attributeLocation, Mapping::getOpenGLSize(attribute->vertexAttributeFormat), Mapping::getOpenGLType(attribute->vertexAttributeFormat), static_cast<GLboolean>(Mapping::isOpenGLVertexAttributeFormatNormalized(attribute->vertexAttributeFormat)), static_cast<GLsizei>(vertexArrayVertexBuffer.strideInBytes), static_cast<GLintptr>(attribute->alignedByteOffset)); // Per-instance instead of per-vertex requires "GL_ARB_instanced_arrays" if (attribute->instancesPerElement > 0 && openGLRenderer.getExtensions().isGL_ARB_instanced_arrays()) { // Sadly, DSA has no support for "GL_ARB_instanced_arrays", so, we have to use the bind way // -> Keep the bind-horror as local as possible #ifndef OPENGLRENDERER_NO_STATE_CLEANUP // Backup the currently bound OpenGL vertex array GLint openGLVertexArrayBackup = 0; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &openGLVertexArrayBackup); #endif // Bind this OpenGL vertex array glBindVertexArray(mOpenGLVertexArray); // Set divisor glVertexAttribDivisorARB(attributeLocation, attribute->instancesPerElement); #ifndef OPENGLRENDERER_NO_STATE_CLEANUP // Be polite and restore the previous bound OpenGL vertex array glBindVertexArray(static_cast<GLuint>(openGLVertexArrayBackup)); #endif } // Enable OpenGL vertex attribute array glEnableVertexArrayAttribEXT(mOpenGLVertexArray, attributeLocation); } } // Check the used index buffer // -> In case of no index buffer we don't bind buffer 0, there's not really a point in it if (nullptr != indexBuffer) { if (isARB_DSA) { // Bind the index buffer glVertexArrayElementBuffer(mOpenGLVertexArray, indexBuffer->getOpenGLElementArrayBuffer()); } else { // Sadly, EXT DSA has no support for element array buffer, so, we have to use the bind way // -> Keep the bind-horror as local as possible #ifndef OPENGLRENDERER_NO_STATE_CLEANUP // Backup the currently bound OpenGL vertex array GLint openGLVertexArrayBackup = 0; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &openGLVertexArrayBackup); // Backup the currently bound OpenGL element array buffer GLint openGLElementArrayBufferBackup = 0; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &openGLElementArrayBufferBackup); #endif // Bind this OpenGL vertex array glBindVertexArray(mOpenGLVertexArray); // Bind OpenGL element array buffer glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexBuffer->getOpenGLElementArrayBuffer()); #ifndef OPENGLRENDERER_NO_STATE_CLEANUP // Be polite and restore the previous bound OpenGL vertex array glBindVertexArray(static_cast<GLuint>(openGLVertexArrayBackup)); // Be polite and restore the previous bound OpenGL element array buffer glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, static_cast<GLuint>(openGLElementArrayBufferBackup)); #endif } } }
/* ============= GL_DrawAliasFrameLerp interpolates between two frames and origins FIXME: batch lerp all vertexes ============= */ void GL_DrawAliasFrameLerp (entity_t *e, dmdl_t *hdr, float backlerp) { int i; float frontlerp; float alpha; vec3_t delta, vectors[3]; daliasframe_t *currframe = (daliasframe_t *) ((byte *) hdr + hdr->ofs_frames + e->currframe * hdr->framesize); daliasframe_t *lastframe = (daliasframe_t *) ((byte *) hdr + hdr->ofs_frames + e->lastframe * hdr->framesize); meshubo_t *meshubo = NULL; GLbitfield access; if (e->flags & RF_TRANSLUCENT) alpha = e->alpha; else alpha = 1.0; frontlerp = 1.0 - backlerp; // move should be the delta back to the previous frame * backlerp VectorSubtract (e->lastorigin, e->currorigin, delta); AngleVectors (e->angles, vectors[0], vectors[1], vectors[2]); gl_meshuboupdate.move[0] = lastframe->translate[0] + DotProduct (delta, vectors[0]); // forward gl_meshuboupdate.move[1] = lastframe->translate[1] - DotProduct (delta, vectors[1]); // left gl_meshuboupdate.move[2] = lastframe->translate[2] + DotProduct (delta, vectors[2]); // up for (i = 0; i < 3; i++) { gl_meshuboupdate.move[i] = backlerp * gl_meshuboupdate.move[i] + frontlerp * currframe->translate[i]; gl_meshuboupdate.frontv[i] = frontlerp * currframe->scale[i]; gl_meshuboupdate.backv[i] = backlerp * lastframe->scale[i]; } if (!(e->flags & (RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE))) { if (gl_monolightmap->value) { float ntsc[] = {0.3f, 0.59f, 0.11f}; float gs = DotProduct (gl_meshuboupdate.shadelight, ntsc); gl_meshuboupdate.shadelight[0] = gl_meshuboupdate.shadelight[1] = gl_meshuboupdate.shadelight[2] = gs; } gl_meshuboupdate.shadelight[0] *= r_lightscale->value * 2.0f; gl_meshuboupdate.shadelight[1] *= r_lightscale->value * 2.0f; gl_meshuboupdate.shadelight[2] *= r_lightscale->value * 2.0f; gl_meshuboupdate.powersuitscale = 0.0f; gl_meshuboupdate.shellmix = 0.0f; } else { float scale = (e->flags & RF_WEAPONMODEL) ? WEAPONSHELL_SCALE : POWERSUIT_SCALE; gl_meshuboupdate.powersuitscale = scale; gl_meshuboupdate.shellmix = 1.0f; } gl_meshuboupdate.shadelight[3] = alpha; gl_meshuboupdate.lerpfrac = backlerp; if (e->model->lastcurrframe != e->currframe) { glVertexArrayVertexAttribOffsetEXT (e->model->meshvao, e->model->meshvbo, 0, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof (posevert_t), VERTOFFSET (e->currframe)); e->model->lastcurrframe = e->currframe; } if (e->model->lastlastframe != e->lastframe) { glVertexArrayVertexAttribOffsetEXT (e->model->meshvao, e->model->meshvbo, 1, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof (posevert_t), VERTOFFSET (e->lastframe)); e->model->lastlastframe = e->lastframe; } GL_BindVertexArray (e->model->meshvao); GL_Enable (DEPTHTEST_BIT | ((e->flags & RF_TRANSLUCENT) ? BLEND_BIT : DEPTHWRITE_BIT) | (gl_cull->value ? CULLFACE_BIT : 0)); GL_UseProgram (gl_meshprog); if (gl_meshubonumblocks + 1 >= MESH_UBO_MAX_BLOCKS) { access = BUFFER_DISCARD; gl_meshubonumblocks = 0; } else access = BUFFER_NO_OVERWRITE; if ((meshubo = glMapNamedBufferRangeEXT (gl_meshubo, gl_meshubonumblocks * gl_meshuboblocksize, sizeof (meshubo_t), access)) != NULL) { memcpy (meshubo, &gl_meshuboupdate, sizeof (meshubo_t)); glUnmapNamedBufferEXT (gl_meshubo); glBindBufferRange (GL_UNIFORM_BUFFER, gl_meshubobinding, gl_meshubo, gl_meshubonumblocks * gl_meshuboblocksize, sizeof (meshubo_t)); glDrawElements (GL_TRIANGLES, e->model->numindexes, GL_UNSIGNED_SHORT, NULL); gl_meshubonumblocks++; } }