void OGLMapping::Mapping(GLenum& primType, uint32_t& primCount, RenderLayout const & rl) { uint32_t const vertexCount = static_cast<uint32_t>(rl.UseIndices() ? rl.NumIndices() : rl.NumVertices()); primType = GL_POINTS; primCount = vertexCount; switch (rl.TopologyType()) { case RenderLayout::TT_PointList: primType = GL_POINTS; primCount = vertexCount; break; case RenderLayout::TT_LineList: primType = GL_LINES; primCount = vertexCount / 2; break; case RenderLayout::TT_LineStrip: primType = GL_LINE_STRIP; primCount = vertexCount - 1; break; case RenderLayout::TT_TriangleList: primType = GL_TRIANGLES; primCount = vertexCount / 3; break; case RenderLayout::TT_TriangleStrip: primType = GL_TRIANGLE_STRIP; primCount = vertexCount - 2; break; default: THR(errc::function_not_supported); } }
// 渲染 ///////////////////////////////////////////////////////////////////////////////// void OGLESRenderEngine::DoRender(RenderTechnique const & tech, RenderLayout const & rl) { uint32_t const num_instance = rl.NumInstances(); BOOST_ASSERT(num_instance != 0); OGLESShaderObjectPtr cur_shader = checked_pointer_cast<OGLESShaderObject>(tech.Pass(0)->GetShaderObject()); checked_cast<OGLESRenderLayout const *>(&rl)->Active(cur_shader); size_t const vertexCount = rl.UseIndices() ? rl.NumIndices() : rl.NumVertices(); GLenum mode; uint32_t primCount; OGLESMapping::Mapping(mode, primCount, rl); numPrimitivesJustRendered_ += num_instance * primCount; numVerticesJustRendered_ += num_instance * vertexCount; GLenum index_type = GL_UNSIGNED_SHORT; uint8_t* index_offset = nullptr; if (rl.UseIndices()) { if (EF_R16UI == rl.IndexStreamFormat()) { index_type = GL_UNSIGNED_SHORT; index_offset += rl.StartIndexLocation() * 2; } else { index_type = GL_UNSIGNED_INT; index_offset += rl.StartIndexLocation() * 4; } } uint32_t const num_passes = tech.NumPasses(); size_t const inst_format_size = rl.InstanceStreamFormat().size(); if (glloader_GLES_VERSION_3_0() && rl.InstanceStream()) { OGLESGraphicsBuffer& stream(*checked_pointer_cast<OGLESGraphicsBuffer>(rl.InstanceStream())); uint32_t const instance_size = rl.InstanceSize(); BOOST_ASSERT(num_instance * instance_size <= stream.Size()); uint8_t* elem_offset = nullptr; for (size_t i = 0; i < inst_format_size; ++ i) { vertex_element const & vs_elem = rl.InstanceStreamFormat()[i]; GLint attr = cur_shader->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; OGLESMapping::MappingVertexFormat(type, normalized, vs_elem.format); normalized = (((VEU_Diffuse == vs_elem.usage) || (VEU_Specular == vs_elem.usage)) && !IsFloatFormat(vs_elem.format)) ? GL_TRUE : normalized; GLvoid* offset = static_cast<GLvoid*>(elem_offset + rl.StartInstanceLocation() * instance_size); stream.Active(false); glVertexAttribPointer(attr, num_components, type, normalized, instance_size, offset); glEnableVertexAttribArray(attr); glVertexAttribDivisor(attr, 1); } elem_offset += vs_elem.element_size(); } if (so_rl_) { glBeginTransformFeedback(so_primitive_mode_); } if (rl.UseIndices()) { for (uint32_t i = 0; i < num_passes; ++ i) { RenderPassPtr const & pass = tech.Pass(i); pass->Bind(); if (so_rl_) { OGLESShaderObjectPtr shader = checked_pointer_cast<OGLESShaderObject>(pass->GetShaderObject()); glTransformFeedbackVaryings(shader->GLSLProgram(), static_cast<GLsizei>(so_vars_ptrs_.size()), &so_vars_ptrs_[0], GL_SEPARATE_ATTRIBS); for (uint32_t j = 0; j < so_buffs_.size(); ++ j) { glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, j, so_buffs_[j]); } } glDrawElementsInstanced(mode, static_cast<GLsizei>(rl.NumIndices()), index_type, index_offset, num_instance); pass->Unbind(); } } else { for (uint32_t i = 0; i < num_passes; ++ i) { RenderPassPtr const & pass = tech.Pass(i); pass->Bind(); if (so_rl_) { OGLESShaderObjectPtr shader = checked_pointer_cast<OGLESShaderObject>(pass->GetShaderObject()); glTransformFeedbackVaryings(shader->GLSLProgram(), static_cast<GLsizei>(so_vars_ptrs_.size()), &so_vars_ptrs_[0], GL_SEPARATE_ATTRIBS); for (uint32_t j = 0; j < so_buffs_.size(); ++ j) { glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, j, so_buffs_[j]); } } glDrawArraysInstanced(mode, rl.StartVertexLocation(), static_cast<GLsizei>(rl.NumVertices()), num_instance); pass->Unbind(); } } if (so_rl_) { glEndTransformFeedback(); } for (size_t i = 0; i < inst_format_size; ++ i) { vertex_element const & vs_elem = rl.InstanceStreamFormat()[i]; GLint attr = cur_shader->GetAttribLocation(vs_elem.usage, vs_elem.usage_index); if (attr != -1) { glDisableVertexAttribArray(attr); glVertexAttribDivisor(attr, 0); } } } else { for (uint32_t instance = rl.StartInstanceLocation(); instance < rl.StartInstanceLocation() + num_instance; ++ instance) { if (rl.InstanceStream()) { GraphicsBuffer& stream = *rl.InstanceStream(); uint32_t const instance_size = rl.InstanceSize(); BOOST_ASSERT(num_instance * instance_size <= stream.Size()); GraphicsBuffer::Mapper mapper(stream, BA_Read_Only); uint8_t const * buffer = mapper.Pointer<uint8_t>(); uint32_t elem_offset = 0; for (size_t i = 0; i < inst_format_size; ++ i) { BOOST_ASSERT(elem_offset < instance_size); vertex_element const & vs_elem = rl.InstanceStreamFormat()[i]; GLint attr = cur_shader->GetAttribLocation(vs_elem.usage, vs_elem.usage_index); if (attr != -1) { void const * addr = &buffer[instance * instance_size + elem_offset]; GLfloat const * float_addr = static_cast<GLfloat const *>(addr); GLint const num_components = static_cast<GLint>(NumComponents(vs_elem.format)); GLenum type; GLboolean normalized; OGLESMapping::MappingVertexFormat(type, normalized, vs_elem.format); normalized = (((VEU_Diffuse == vs_elem.usage) || (VEU_Specular == vs_elem.usage)) && !IsFloatFormat(vs_elem.format)) ? GL_TRUE : normalized; switch (num_components) { case 1: BOOST_ASSERT(IsFloatFormat(vs_elem.format)); glVertexAttrib1fv(attr, float_addr); break; case 2: BOOST_ASSERT(IsFloatFormat(vs_elem.format)); glVertexAttrib2fv(attr, float_addr); break; case 3: BOOST_ASSERT(IsFloatFormat(vs_elem.format)); glVertexAttrib3fv(attr, float_addr); break; case 4: if (IsFloatFormat(vs_elem.format)) { glVertexAttrib4fv(attr, float_addr); } else { GLubyte const * byte_addr = static_cast<GLubyte const *>(addr); if (normalized) { glVertexAttrib4f(attr, byte_addr[0] / 255.0f, byte_addr[1] / 255.0f, byte_addr[2] / 255.0f, byte_addr[3] / 255.0f); } else { glVertexAttrib4f(attr, byte_addr[0], byte_addr[1], byte_addr[2], byte_addr[3]); } } break; default: BOOST_ASSERT(false); break; } } elem_offset += vs_elem.element_size(); } } if (so_rl_) { glBeginTransformFeedback(so_primitive_mode_); } if (rl.UseIndices()) { for (uint32_t i = 0; i < num_passes; ++ i) { RenderPassPtr const & pass = tech.Pass(i); pass->Bind(); if (so_rl_) { OGLESShaderObjectPtr shader = checked_pointer_cast<OGLESShaderObject>(pass->GetShaderObject()); glTransformFeedbackVaryings(shader->GLSLProgram(), static_cast<GLsizei>(so_vars_ptrs_.size()), &so_vars_ptrs_[0], GL_SEPARATE_ATTRIBS); for (uint32_t j = 0; j < so_buffs_.size(); ++ j) { glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, j, so_buffs_[j]); } } glDrawElements(mode, static_cast<GLsizei>(rl.NumIndices()), index_type, index_offset); pass->Unbind(); } } else { for (uint32_t i = 0; i < num_passes; ++ i) { RenderPassPtr const & pass = tech.Pass(i); pass->Bind(); if (so_rl_) { OGLESShaderObjectPtr shader = checked_pointer_cast<OGLESShaderObject>(pass->GetShaderObject()); glTransformFeedbackVaryings(shader->GLSLProgram(), static_cast<GLsizei>(so_vars_ptrs_.size()), &so_vars_ptrs_[0], GL_SEPARATE_ATTRIBS); for (uint32_t j = 0; j < so_buffs_.size(); ++ j) { glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, j, so_buffs_[j]); } } glDrawArrays(mode, rl.StartVertexLocation(), static_cast<GLsizei>(rl.NumVertices())); pass->Unbind(); } } if (so_rl_) { glEndTransformFeedback(); } } } checked_cast<OGLESRenderLayout const *>(&rl)->Deactive(cur_shader); }