From e3a25c6274fa1bed2a3b862eaa412f938cf4ee3e Mon Sep 17 00:00:00 2001 From: BZLZHH Date: Fri, 16 May 2025 23:40:32 +0800 Subject: [PATCH] [Feat] (ShittilyDrawing): Implement more Drawing functions. Make uniform correct. --- .../Implementations/GL/Drawing/GL_Drawing.cpp | 180 +++++++++++------- .../Implementations/GL/Drawing/GL_Drawing.h | 3 + .../GLFuncsDefinitions/GLFuncsDefinitions.cpp | 6 +- 3 files changed, 116 insertions(+), 73 deletions(-) diff --git a/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.cpp b/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.cpp index 40934450..4dc8096a 100644 --- a/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.cpp +++ b/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.cpp @@ -583,8 +583,7 @@ namespace MG_GL::GL { } } - - + void SyncAllVAOsToGLES(VertexArrayState* vaState) { for (auto& [mgid, vao] : vaState->vaos_) { if (!vao.generated) @@ -740,25 +739,20 @@ namespace MG_GL::GL { } } - - void DrawArraysSHITTILY(GLenum mode, GLint first, GLsizei count) { - - } - - void DrawElementsSHITTILY(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) { + void SyncAllToGLES() { CommonState* commonState = MG_State_T::commonState; TextureState* textureState = MG_State_T::textureState; BufferState* bufferState = MG_State_T::bufferState; VertexArrayState* vaState = MG_State_T::vertexArrayState; ProgramState* programState = MG_State_T::programState; FramebufferState* fbState = MG_State_T::framebufferState; - + // Common const GLint* viewport = commonState->viewport; - if (viewport[2] > 0 && viewport[3] > 0) { + if (viewport[2] > 0 && viewport[3] > 0) { CallAndCheck(::GLES::glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);) } - + if (commonState->capabilities[GL_BLEND]) { CallAndCheck(::GLES::glEnable(GL_BLEND);) CallAndCheck(::GLES::glBlendFuncSeparate( @@ -768,7 +762,7 @@ namespace MG_GL::GL { } else { CallAndCheck(::GLES::glDisable(GL_BLEND);) } - + if (commonState->capabilities[GL_DEPTH_TEST]) { CallAndCheck(::GLES::glEnable(GL_DEPTH_TEST);) CallAndCheck(::GLES::glDepthMask(commonState->depthMask);) @@ -776,24 +770,24 @@ namespace MG_GL::GL { } else { CallAndCheck(::GLES::glDisable(GL_DEPTH_TEST);) } - + if (commonState->capabilities[GL_CULL_FACE]) { CallAndCheck(::GLES::glEnable(GL_CULL_FACE);) } else { CallAndCheck(::GLES::glDisable(GL_CULL_FACE);) } - + CallAndCheck(::GLES::glColorMask( commonState->colorMask[0], commonState->colorMask[1], commonState->colorMask[2], commonState->colorMask[3] );) - + // Texture SyncAllTexturesToGLES(textureState); for (size_t unitIdx = 0; unitIdx < textureState->textureUnits_.size(); ++unitIdx) { TextureUnitState& mgUnit = textureState->textureUnits_[unitIdx]; GLenum glUnit = GL_TEXTURE0 + unitIdx; - + if (lastBoundTextures[unitIdx] != mgUnit.boundTextures[GL_TEXTURE_2D]) { CallAndCheck(::GLES::glActiveTexture(glUnit);) for (auto& [target, texId] : mgUnit.boundTextures) { @@ -802,12 +796,12 @@ namespace MG_GL::GL { lastBoundTextures[unitIdx] = 0; continue; } - + if (s_textureMap.find(texId) == s_textureMap.end()) { GLuint glTexId; CallAndCheck(::GLES::glGenTextures(1, &glTexId);) s_textureMap[texId] = glTexId; - + CallAndCheck(::GLES::glBindTexture(target, glTexId);) TextureObject& mgTex = textureState->textures[texId]; TexParamCache& entry = cache[&mgTex]; @@ -818,7 +812,7 @@ namespace MG_GL::GL { entry.lastInt[pname] = param; } } - + for (auto& [pname, param] : mgTex.params.texPropertiesFloat) { auto it = entry.lastFloat.find(pname); if (it == entry.lastFloat.end() || it->second != param) { @@ -826,13 +820,13 @@ namespace MG_GL::GL { entry.lastFloat[pname] = param; } } - + for (auto& [level, mip] : mgTex.params.mipmapData) { CallAndCheck(::GLES::glTexImage2D( target, level, mip.internalFormat, mip.width, mip.height, 0, mip.format, mip.type, mip.pixelData.data() - );) + );) } } CallAndCheck(::GLES::glBindTexture(target, s_textureMap[texId]);) @@ -856,11 +850,11 @@ namespace MG_GL::GL { MG_Util::Debug::LogD("binding vbo MG %d -> ES %d", vbo, s_bufferMap[vbo]); SyncCurrentVAOToGLES(vaState); - + // EBO GLuint curVaoId = vaState->currentVao_; VertexArrayObject* curvao = &vaState->vaos_[curVaoId]; - + // Program GLuint currentProgram = programState->GetCurrentProgram(); if (currentProgram != lastBoundProgram) { @@ -893,7 +887,7 @@ namespace MG_GL::GL { const char* s[] = { source.c_str() }; CallAndCheck(::GLES::glShaderSource(glShader, 1, s, nullptr);) CallAndCheck(::GLES::glCompileShader(glShader);) - + GLint success; CallAndCheck(::GLES::glGetShaderiv(glShader, GL_COMPILE_STATUS, &success);) if (!success) { @@ -903,7 +897,7 @@ namespace MG_GL::GL { } CallAndCheck(::GLES::glAttachShader(glProgram, glShader);) } - + CallAndCheck(::GLES::glLinkProgram(glProgram);) GLint linkStatus; CallAndCheck(::GLES::glGetProgramiv(glProgram, GL_LINK_STATUS, &linkStatus);) @@ -916,12 +910,12 @@ namespace MG_GL::GL { } CallAndCheck(::GLES::glUseProgram(s_programMap[currentProgram]);) lastBoundProgram = currentProgram; - + // Uniform ProgramObject& mgProgram = programState->programs_[currentProgram]; for (auto& [name, uniform] : mgProgram.uniformValues) { GLint location = ::GLES::glGetUniformLocation(s_programMap[currentProgram], name.c_str()); - if (location == -1) { + if (location == -1) { MG_Util::Debug::LogE("Uniform location not found: %s", name.c_str()); continue; } @@ -929,23 +923,19 @@ namespace MG_GL::GL { switch (uniform.type) { case GL_FLOAT: { - GLsizei num = static_cast(uniform.count / 1); - CallAndCheck(::GLES::glUniform1fv(location, num, uniform.floatData.data());) + CallAndCheck(::GLES::glUniform1fv(location, uniform.count, uniform.floatData.data());) break; } case GL_FLOAT_VEC2: { - GLsizei num = static_cast(uniform.count / 2); - CallAndCheck(::GLES::glUniform2fv(location, num, uniform.floatData.data());) + CallAndCheck(::GLES::glUniform2fv(location, uniform.count, uniform.floatData.data());) break; } case GL_FLOAT_VEC3: { - GLsizei num = static_cast(uniform.count / 3); - CallAndCheck(::GLES::glUniform3fv(location, num, uniform.floatData.data());) + CallAndCheck(::GLES::glUniform3fv(location, uniform.count, uniform.floatData.data());) break; } case GL_FLOAT_VEC4: { - GLsizei num = static_cast(uniform.count / 4); - CallAndCheck(::GLES::glUniform4fv(location, num, uniform.floatData.data());) + CallAndCheck(::GLES::glUniform4fv(location, uniform.count, uniform.floatData.data());) break; } @@ -957,103 +947,98 @@ namespace MG_GL::GL { case GL_SAMPLER_CUBE: case GL_SAMPLER_1D_SHADOW: case GL_SAMPLER_2D_SHADOW: { - GLsizei num = static_cast(uniform.count / 1); - CallAndCheck(::GLES::glUniform1iv(location, num, uniform.intData.data());) + CallAndCheck(::GLES::glUniform1iv(location, uniform.count, uniform.intData.data());) break; } case GL_INT_VEC2: case GL_BOOL_VEC2: { - GLsizei num = static_cast(uniform.count / 2); - CallAndCheck(::GLES::glUniform2iv(location, num, uniform.intData.data());) + CallAndCheck(::GLES::glUniform2iv(location, uniform.count, uniform.intData.data());) break; } case GL_INT_VEC3: case GL_BOOL_VEC3: { - GLsizei num = static_cast(uniform.count / 3); - CallAndCheck(::GLES::glUniform3iv(location, num, uniform.intData.data());) + CallAndCheck(::GLES::glUniform3iv(location, uniform.count, uniform.intData.data());) break; } case GL_INT_VEC4: case GL_BOOL_VEC4: { - GLsizei num = static_cast(uniform.count / 4); - CallAndCheck(::GLES::glUniform4iv(location, num, uniform.intData.data());) + CallAndCheck(::GLES::glUniform4iv(location, uniform.count, uniform.intData.data());) break; } case GL_UNSIGNED_INT: { - GLsizei num = static_cast(uniform.count / 1); - CallAndCheck(::GLES::glUniform1uiv(location, num, uniform.uintData.data());) + CallAndCheck(::GLES::glUniform1uiv(location, uniform.count, uniform.uintData.data());) break; } case GL_UNSIGNED_INT_VEC2: { - GLsizei num = static_cast(uniform.count / 2); - CallAndCheck(::GLES::glUniform2uiv(location, num, uniform.uintData.data());) + CallAndCheck(::GLES::glUniform2uiv(location, uniform.count, uniform.uintData.data());) break; } case GL_UNSIGNED_INT_VEC3: { - GLsizei num = static_cast(uniform.count / 3); - CallAndCheck(::GLES::glUniform3uiv(location, num, uniform.uintData.data());) + CallAndCheck(::GLES::glUniform3uiv(location, uniform.count, uniform.uintData.data());) break; } case GL_UNSIGNED_INT_VEC4: { - GLsizei num = static_cast(uniform.count / 4); - CallAndCheck(::GLES::glUniform4uiv(location, num, uniform.uintData.data());) + CallAndCheck(::GLES::glUniform4uiv(location, uniform.count, uniform.uintData.data());) break; } case GL_FLOAT_MAT2: { - GLsizei num = static_cast(uniform.count / 4); - CallAndCheck(::GLES::glUniformMatrix2fv(location, num, GL_FALSE, uniform.floatData.data());) + CallAndCheck(::GLES::glUniformMatrix2fv(location, uniform.count, GL_FALSE, uniform.floatData.data());) break; } case GL_FLOAT_MAT3: { - GLsizei num = static_cast(uniform.count / 9); - CallAndCheck(::GLES::glUniformMatrix3fv(location, num, GL_FALSE, uniform.floatData.data());) + CallAndCheck(::GLES::glUniformMatrix3fv(location, uniform.count, GL_FALSE, uniform.floatData.data());) break; } case GL_FLOAT_MAT4: { - GLsizei num = static_cast(uniform.count / 16); - CallAndCheck(::GLES::glUniformMatrix4fv(location, num, GL_FALSE, uniform.floatData.data());) + CallAndCheck(::GLES::glUniformMatrix4fv(location, uniform.count, GL_FALSE, uniform.floatData.data());) break; } case GL_FLOAT_MAT2x3: { - GLsizei num = static_cast(uniform.count / 6); - CallAndCheck(::GLES::glUniformMatrix2x3fv(location, num, GL_FALSE, uniform.floatData.data());) + CallAndCheck(::GLES::glUniformMatrix2x3fv(location, uniform.count, GL_FALSE, uniform.floatData.data());) break; } case GL_FLOAT_MAT2x4: { - GLsizei num = static_cast(uniform.count / 8); - CallAndCheck(::GLES::glUniformMatrix2x4fv(location, num, GL_FALSE, uniform.floatData.data());) + CallAndCheck(::GLES::glUniformMatrix2x4fv(location, uniform.count, GL_FALSE, uniform.floatData.data());) break; } case GL_FLOAT_MAT3x2: { - GLsizei num = static_cast(uniform.count / 6); - CallAndCheck(::GLES::glUniformMatrix3x2fv(location, num, GL_FALSE, uniform.floatData.data());) + CallAndCheck(::GLES::glUniformMatrix3x2fv(location, uniform.count, GL_FALSE, uniform.floatData.data());) break; } case GL_FLOAT_MAT3x4: { - GLsizei num = static_cast(uniform.count / 12); - CallAndCheck(::GLES::glUniformMatrix3x4fv(location, num, GL_FALSE, uniform.floatData.data());) + CallAndCheck(::GLES::glUniformMatrix3x4fv(location, uniform.count, GL_FALSE, uniform.floatData.data());) break; } case GL_FLOAT_MAT4x2: { - GLsizei num = static_cast(uniform.count / 8); - CallAndCheck(::GLES::glUniformMatrix4x2fv(location, num, GL_FALSE, uniform.floatData.data());) + CallAndCheck(::GLES::glUniformMatrix4x2fv(location, uniform.count, GL_FALSE, uniform.floatData.data());) break; } case GL_FLOAT_MAT4x3: { - GLsizei num = static_cast(uniform.count / 12); - CallAndCheck(::GLES::glUniformMatrix4x3fv(location, num, GL_FALSE, uniform.floatData.data());) + CallAndCheck(::GLES::glUniformMatrix4x3fv(location, uniform.count, GL_FALSE, uniform.floatData.data());) break; } } } } - + // Framebuffer RealizeFBOState(GL_DRAW_FRAMEBUFFER); + } + void DrawArraysSHITTILY(GLenum mode, GLint first, GLsizei count) { + + } + + void DrawElementsSHITTILY(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) { + SyncAllToGLES(); + + VertexArrayState* vaState = MG_State_T::vertexArrayState; + GLuint curVaoId = vaState->currentVao_; + VertexArrayObject* curvao = &vaState->vaos_[curVaoId]; + if (curvao->elementBuffer != 0 || indices != nullptr) { CallAndCheck(::GLES::glDrawElements( mode, @@ -1064,6 +1049,24 @@ namespace MG_GL::GL { } } + void DrawElementsBaseVertexSHITTILY(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLint basevertex) { + SyncAllToGLES(); + + VertexArrayState* vaState = MG_State_T::vertexArrayState; + GLuint curVaoId = vaState->currentVao_; + VertexArrayObject* curvao = &vaState->vaos_[curVaoId]; + + if (curvao->elementBuffer != 0 || indices != nullptr) { + CallAndCheck(::GLES::glDrawElementsBaseVertex( + mode, + count, + type, + indices, + basevertex + );) + } + } + void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, @@ -1187,4 +1190,41 @@ namespace MG_GL::GL { void DrawArrays(GLenum mode, GLint first, GLsizei count) { DrawArraysSHITTILY(mode, first, count); } + + void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex) { + DrawElementsBaseVertexSHITTILY(mode, count, type, indices, basevertex); + } + + void MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const *indices, GLsizei drawcount) { + SyncAllToGLES(); + + VertexArrayState* vaState = MG_State_T::vertexArrayState; + GLuint curVaoId = vaState->currentVao_; + VertexArrayObject* curvao = &vaState->vaos_[curVaoId]; + + if (curvao->elementBuffer != 0 || indices != nullptr) { + for (GLsizei i = 0; i < drawcount; ++i) { + CallAndCheck(::GLES::glDrawElements( + mode, + count[i], + type, + indices[i] + );) + } + } + } + + void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const *indices, GLsizei drawcount, const GLint *basevertex) { + SyncAllToGLES(); + + VertexArrayState* vaState = MG_State_T::vertexArrayState; + GLuint curVaoId = vaState->currentVao_; + VertexArrayObject* curvao = &vaState->vaos_[curVaoId]; + + if (curvao->elementBuffer != 0 || indices != nullptr) { + for (GLsizei i = 0; i < drawcount; ++i) { + CallAndCheck(::GLES::glDrawElementsBaseVertex(mode, count[i], type, indices[i], basevertex[i]);) + } + } + } } \ No newline at end of file diff --git a/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.h b/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.h index fe06ce5d..ac6f5528 100644 --- a/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.h +++ b/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.h @@ -8,6 +8,9 @@ namespace MG_GL::GL { void DrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices); void DrawArrays(GLenum mode, GLint first, GLsizei count); + void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); + void MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const *indices, GLsizei drawcount); + void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const *indices, GLsizei drawcount, const GLint *basevertex); } #endif //MOBILEGL_GL_DRAWING_H diff --git a/MG/MG_GL/Implementations/GL/GLFuncsDefinitions/GLFuncsDefinitions.cpp b/MG/MG_GL/Implementations/GL/GLFuncsDefinitions/GLFuncsDefinitions.cpp index 156da322..a00683f9 100644 --- a/MG/MG_GL/Implementations/GL/GLFuncsDefinitions/GLFuncsDefinitions.cpp +++ b/MG/MG_GL/Implementations/GL/GLFuncsDefinitions/GLFuncsDefinitions.cpp @@ -366,7 +366,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendFunci, GLuint buf, GLenum src, GLenum d DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendFuncSeparatei, GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendFuncSeparatei, buf,srcRGB,dstRGB,srcAlpha,dstAlpha) DECLARE_GL_FUNCTION_STUB_HEAD(void, ColorMaski, GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ColorMaski, index,r,g,b,a) DECLARE_GL_FUNCTION_STUB_HEAD(GLboolean, IsEnabledi, GLenum target, GLuint index) DECLARE_GL_FUNCTION_STUB_END(GLboolean, IsEnabledi, target,index) -DECLARE_GL_FUNCTION_STUB_HEAD(void, DrawElementsBaseVertex, GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DrawElementsBaseVertex, mode,count,type,indices,basevertex) +DECLARE_GL_FUNCTION_HEAD(void, DrawElementsBaseVertex, GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElementsBaseVertex, mode,count,type,indices,basevertex) DECLARE_GL_FUNCTION_STUB_HEAD(void, DrawRangeElementsBaseVertex, GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DrawRangeElementsBaseVertex, mode,start,end,count,type,indices,basevertex) DECLARE_GL_FUNCTION_STUB_HEAD(void, DrawElementsInstancedBaseVertex, GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DrawElementsInstancedBaseVertex, mode,count,type,indices,instancecount,basevertex) DECLARE_GL_FUNCTION_STUB_HEAD(void, FramebufferTexture, GLenum target, GLenum attachment, GLuint texture, GLint level) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, FramebufferTexture, target,attachment,texture,level) @@ -739,7 +739,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, LoadTransposeMatrixd,const GLdouble* m) DECL DECLARE_GL_FUNCTION_STUB_HEAD(void, MultTransposeMatrixf,const GLfloat* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultTransposeMatrixf,m) DECLARE_GL_FUNCTION_STUB_HEAD(void, MultTransposeMatrixd,const GLdouble* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultTransposeMatrixd,m) DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawArrays, GLenum mode, const GLint* first, const GLsizei* count, GLsizei drawcount) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawArrays,mode,first,count,drawcount) -DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawElements, GLenum mode, const GLsizei* count, GLenum type, const void* const*indices, GLsizei drawcount) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawElements,mode,count,type,indices,drawcount) +DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElements, GLenum mode, const GLsizei* count, GLenum type, const void* const*indices, GLsizei drawcount) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElements,mode,count,type,indices,drawcount) DECLARE_GL_FUNCTION_STUB_HEAD(void, PointParameterf, GLenum pname, GLfloat param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PointParameterf,pname,param) DECLARE_GL_FUNCTION_STUB_HEAD(void, PointParameterfv, GLenum pname, const GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PointParameterfv,pname,params) DECLARE_GL_FUNCTION_STUB_HEAD(void, PointParameteri, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PointParameteri,pname,param) @@ -815,7 +815,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4uiv, GLuint index, const GLuint DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4usv, GLuint index, const GLushort* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib4usv,index,v) DECLARE_GL_FUNCTION_STUB_HEAD(void, PrimitiveRestartIndex, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PrimitiveRestartIndex,index) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetActiveUniformName, GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformName) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetActiveUniformName,program,uniformIndex,bufSize,length,uniformName) -DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawElementsBaseVertex, GLenum mode, const GLsizei* count, GLenum type, const void* const*indices, GLsizei drawcount, const GLint* basevertex) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawElementsBaseVertex,mode,count,type,indices,drawcount,basevertex) +DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElementsBaseVertex, GLenum mode, const GLsizei* count, GLenum type, const void* const*indices, GLsizei drawcount, const GLint* basevertex) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElementsBaseVertex,mode,count,type,indices,drawcount,basevertex) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProvokingVertex, GLenum mode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProvokingVertex,mode) DECLARE_GL_FUNCTION_STUB_HEAD(void, TexImage2DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexImage2DMultisample,target,samples,internalformat,width,height,fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_HEAD(void, TexImage3DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexImage3DMultisample,target,samples,internalformat,width,height,depth,fixedsamplelocations)