/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "GLEScmContext.h" #include "GLEScmUtils.h" #include #include #include #include #include #include #include "aemu/base/synchronization/Lock.h" #include "aemu/base/files/StreamSerializing.h" #include "host-common/crash_reporter.h" #include "GLEScmValidate.h" #include #include #include #include static GLESVersion s_maxGlesVersion = GLES_1_1; void GLEScmContext::setMaxGlesVersion(GLESVersion version) { s_maxGlesVersion = version; } void GLEScmContext::init(bool nativeTextureDecompressionEnabled) { android::base::AutoLock mutex(s_lock); if(!m_initialized) { GLEScontext::init(nativeTextureDecompressionEnabled); addVertexArrayObject(0); setVertexArrayObject(0); m_currVaoState[GL_COLOR_ARRAY] = new GLESpointer(); m_currVaoState[GL_NORMAL_ARRAY] = new GLESpointer(); m_currVaoState[GL_VERTEX_ARRAY] = new GLESpointer(); m_currVaoState[GL_POINT_SIZE_ARRAY_OES] = new GLESpointer(); m_texCoords = new GLESpointer[kMaxTextureUnits]; m_currVaoState[GL_TEXTURE_COORD_ARRAY] = &m_texCoords[m_clientActiveTexture]; if (isCoreProfile()) { m_coreProfileEngine = new CoreProfileEngine(this); } else if (isGles2Gles()) { m_coreProfileEngine = new CoreProfileEngine(this, true /* gles2gles */); } mColor.type = GL_UNSIGNED_BYTE; mColor.val.ubyteVal[0] = 255; mColor.val.ubyteVal[1] = 255; mColor.val.ubyteVal[2] = 255; mColor.val.ubyteVal[3] = 255; mNormal.type = GL_FLOAT; mNormal.val.floatVal[0] = 0.0f; mNormal.val.floatVal[1] = 0.0f; mNormal.val.floatVal[2] = 1.0f; } m_initialized = true; } void GLEScmContext::initGlobal(EGLiface* eglIface) { s_glDispatch.dispatchFuncs(s_maxGlesVersion, eglIface->eglGetGlLibrary(), eglIface->getProcAddress); GLEScontext::initGlobal(eglIface); buildStrings( 1, 1, (const char*)dispatcher().glGetString(GL_VENDOR), (const char*)dispatcher().glGetString(GL_RENDERER), (const char*)dispatcher().glGetString(GL_VERSION), "OpenGL ES-CM 1.1"); } void GLEScmContext::initDefaultFBO( GLint width, GLint height, GLint colorFormat, GLint depthstencilFormat, GLint multisamples, GLuint* eglSurfaceRBColorId, GLuint* eglSurfaceRBDepthId, GLuint readWidth, GLint readHeight, GLint readColorFormat, GLint readDepthstencilFormat, GLint readMultisamples, GLuint* eglReadSurfaceRBColorId, GLuint* eglReadSurfaceRBDepthId) { GLEScontext::initDefaultFBO( width, height, colorFormat, depthstencilFormat, multisamples, eglSurfaceRBColorId, eglSurfaceRBDepthId, readWidth, readHeight, readColorFormat, readDepthstencilFormat, readMultisamples, eglReadSurfaceRBColorId, eglReadSurfaceRBDepthId ); } GLEScmContext::GLEScmContext(int maj, int min, GlobalNameSpace* globalNameSpace, android::base::Stream* stream) : GLEScontext(globalNameSpace, stream, nullptr) { if (stream) { assert(maj == m_glesMajorVersion); assert(min == m_glesMinorVersion); android::base::loadBuffer(stream, &mProjMatrices); android::base::loadBuffer(stream, &mModelviewMatrices); android::base::loadBuffer(stream, &mTextureMatrices, [](android::base::Stream* stream) { MatrixStack matrices; android::base::loadBuffer(stream, &matrices); return matrices; }); android::base::loadBuffer(stream, &mTexUnitEnvs, [](android::base::Stream* stream) { TexEnv texEnv; android::base::loadCollection(stream, &texEnv, [] (android::base::Stream* stream) { GLenum idx = stream->getBe32(); GLValTyped val; stream->read(&val, sizeof(GLValTyped)); return std::make_pair(idx, val); }); return texEnv; }); android::base::loadBuffer(stream, &mTexGens, [](android::base::Stream* stream) { TexEnv texEnv; android::base::loadCollection(stream, &texEnv, [] (android::base::Stream* stream) { GLenum idx = stream->getBe32(); GLValTyped val; stream->read(&val, sizeof(GLValTyped)); return std::make_pair(idx, val); }); return texEnv; }); m_clientActiveTexture = stream->getBe32(); if (m_initialized) { mShadeModel = stream->getBe32(); stream->read((void*)&mColor, sizeof(mColor)); stream->read((void*)&mNormal, sizeof(mNormal)); uint32_t size = stream->getBe32(); m_texCoords = new GLESpointer[size]; for (uint32_t i = 0; i < size; i++) { m_texCoords[i].onLoad(stream); } m_currVaoState[GL_TEXTURE_COORD_ARRAY] = &m_texCoords[m_clientActiveTexture]; } android::base::loadBufferPtr(stream, mMultiTexCoord); android::base::loadBufferPtr(stream, &mMaterial); android::base::loadBufferPtr(stream, &mLightModel); android::base::loadBufferPtr(stream, mLights); android::base::loadBufferPtr(stream, &mFog); } else { m_glesMajorVersion = maj; m_glesMinorVersion = min; mProjMatrices.resize(1, glm::mat4()); mModelviewMatrices.resize(1, glm::mat4()); mTextureMatrices.resize(kMaxTextureUnits, { glm::mat4() }); mTexUnitEnvs.resize(kMaxTextureUnits, TexEnv()); mTexGens.resize(kMaxTextureUnits, TexEnv()); for (int i = 0; i < kMaxTextureUnits; i++) { mTexUnitEnvs[i][GL_TEXTURE_ENV_MODE].val.intVal[0] = GL_MODULATE; mTexUnitEnvs[i][GL_TEXTURE_ENV_MODE].type = GL_INT; mTexUnitEnvs[i][GL_TEXTURE_ENV_COLOR].val.floatVal[0] = 0.2f; mTexUnitEnvs[i][GL_TEXTURE_ENV_COLOR].val.floatVal[1] = 0.4f; mTexUnitEnvs[i][GL_TEXTURE_ENV_COLOR].val.floatVal[2] = 0.8f; mTexUnitEnvs[i][GL_TEXTURE_ENV_COLOR].val.floatVal[3] = 0.7f; mTexUnitEnvs[i][GL_TEXTURE_ENV_COLOR].type = GL_FLOAT; mTexUnitEnvs[i][GL_COMBINE_RGB].val.intVal[0] = GL_REPLACE; mTexUnitEnvs[i][GL_COMBINE_RGB].type = GL_INT; mTexUnitEnvs[i][GL_COMBINE_ALPHA].val.intVal[0] = GL_REPLACE; mTexUnitEnvs[i][GL_COMBINE_ALPHA].type = GL_INT; } // GL_LIGHT0 starts off as white mLights[0].diffuse[0] = 1.0f; mLights[0].diffuse[1] = 1.0f; mLights[0].diffuse[2] = 1.0f; mLights[0].diffuse[3] = 1.0f; mLights[0].specular[0] = 1.0f; mLights[0].specular[1] = 1.0f; mLights[0].specular[2] = 1.0f; mLights[0].specular[3] = 1.0f; } } void GLEScmContext::setActiveTexture(GLenum tex) { m_activeTexture = tex - GL_TEXTURE0; } void GLEScmContext::setClientActiveTexture(GLenum tex) { m_clientActiveTexture = tex - GL_TEXTURE0; m_currVaoState[GL_TEXTURE_COORD_ARRAY] = &m_texCoords[m_clientActiveTexture]; } void GLEScmContext::setBindedTexture(GLenum target, unsigned int texture, unsigned int globalTexName) { GLEScontext::setBindedTexture(target, texture); } GLEScmContext::~GLEScmContext(){ if(m_texCoords){ delete[] m_texCoords; m_texCoords = NULL; } if (m_vaoStateMap.size()) { m_currVaoState[GL_TEXTURE_COORD_ARRAY] = NULL; } if (m_coreProfileEngine) { delete m_coreProfileEngine; m_coreProfileEngine = NULL; } } const GLEScmContext::Material& GLEScmContext::getMaterialInfo() { return mMaterial; } const GLEScmContext::LightModel& GLEScmContext::getLightModelInfo() { return mLightModel; } const GLEScmContext::Light& GLEScmContext::getLightInfo(uint32_t lightIndex) { return mLights[lightIndex]; } const GLEScmContext::Fog& GLEScmContext::getFogInfo() { return mFog; } void GLEScmContext::onSave(android::base::Stream* stream) const { GLEScontext::onSave(stream); android::base::saveBuffer(stream, mProjMatrices); android::base::saveBuffer(stream, mModelviewMatrices); android::base::saveBuffer(stream, mTextureMatrices, [](android::base::Stream* stream, const MatrixStack& matrices) { android::base::saveBuffer(stream, matrices); }); android::base::saveBuffer(stream, mTexUnitEnvs, [](android::base::Stream* stream, const TexEnv& texEnv) { android::base::saveCollection(stream, texEnv, [] (android::base::Stream* stream, const std::pair& it) { stream->putBe32(it.first); stream->write(&it.second, sizeof(GLValTyped)); }); }); android::base::saveBuffer(stream, mTexGens, [](android::base::Stream* stream, const TexEnv& texEnv) { android::base::saveCollection(stream, texEnv, [] (android::base::Stream* stream, const std::pair& it) { stream->putBe32(it.first); stream->write(&it.second, sizeof(GLValTyped)); }); }); stream->putBe32(m_clientActiveTexture); if (m_initialized) { stream->putBe32(mShadeModel); stream->write((void*)&mColor, sizeof(mColor)); stream->write((void*)&mNormal, sizeof(mNormal)); stream->putBe32(kMaxTextureUnits); for (uint32_t i = 0; i < kMaxTextureUnits; i++) { m_texCoords[i].onSave(stream); } } android::base::saveBuffer(stream, mMultiTexCoord, kMaxTextureUnits); android::base::saveBuffer(stream, &mMaterial, 1); android::base::saveBuffer(stream, &mLightModel, 1); android::base::saveBuffer(stream, mLights, kMaxLights); android::base::saveBuffer(stream, &mFog, 1); } void GLEScmContext::restoreMatrixStack(const MatrixStack& matrices) { for (size_t i = 0; i < matrices.size(); i++) { if (i > 0) { dispatcher().glPushMatrix(); } dispatcher().glLoadMatrixf(&matrices[i][0][0]); } } void GLEScmContext::postLoadRestoreCtx() { if (isInitialized()) { initExtensionString(); if (isCoreProfile()) { m_coreProfileEngine = new CoreProfileEngine(this); } else if (isGles2Gles()) { m_coreProfileEngine = new CoreProfileEngine(this, true); } if (!m_coreProfileEngine) { GLDispatch& dispatcher = GLEScontext::dispatcher(); dispatcher.glMatrixMode(GL_PROJECTION); restoreMatrixStack(mProjMatrices); dispatcher.glMatrixMode(GL_MODELVIEW); restoreMatrixStack(mModelviewMatrices); dispatcher.glMatrixMode(GL_TEXTURE); for (size_t i = 0; i < mTextureMatrices.size(); i++) { if (mTextureMatrices[i].size() == 0) { continue; } dispatcher.glActiveTexture(GL_TEXTURE0 + i); restoreMatrixStack(mTextureMatrices[i]); } for (const auto& array : m_currVaoState) { if (array.first == GL_TEXTURE_COORD_ARRAY) continue; array.second->restoreBufferObj(getBufferObj); } for (uint32_t i = 0; i < kMaxTextureUnits; i++) { m_texCoords[i].restoreBufferObj(getBufferObj); } dispatcher.glMatrixMode(mCurrMatrixMode); dispatcher.glActiveTexture(GL_TEXTURE0 + m_activeTexture); for (const auto& it : *m_currVaoState.it->second.arraysMap) { if (GLEScmValidate::supportedArrays(it.first) && it.first != GL_TEXTURE_COORD_ARRAY) { if (it.second->isEnable()) { dispatcher.glEnableClientState(it.first); } else { dispatcher.glDisableClientState(it.first); } } } for (int i = 0; i < kMaxTextureUnits; i++) { GLESpointer* texcoord = m_texCoords + i; dispatcher.glClientActiveTexture(i + GL_TEXTURE0); if (texcoord->isEnable()) { dispatcher.glEnableClientState(GL_TEXTURE_COORD_ARRAY); } else { dispatcher.glDisableClientState(GL_TEXTURE_COORD_ARRAY); } dispatcher.glActiveTexture(i + GL_TEXTURE0); for (const auto& texEnv : mTexUnitEnvs[i]) { GLenum target = texEnv.first == GL_POINT_SPRITE_OES ? GL_COORD_REPLACE_OES : GL_TEXTURE_ENV; if (texEnv.second.type == GL_INT) { dispatcher.glTexEnviv(target, texEnv.first, texEnv.second.val.intVal); } else { assert(texEnv.second.type == GL_FLOAT); dispatcher.glTexEnvfv(target, texEnv.first, texEnv.second.val.floatVal); } } } dispatcher.glClientActiveTexture( m_clientActiveTexture + GL_TEXTURE0); dispatcher.glActiveTexture(m_activeTexture + GL_TEXTURE0); dispatcher.glShadeModel(mShadeModel); switch (mColor.type) { case GL_FLOAT: dispatcher.glColor4f(mColor.val.floatVal[0], mColor.val.floatVal[1], mColor.val.floatVal[2], mColor.val.floatVal[3]); break; case GL_UNSIGNED_BYTE: dispatcher.glColor4ub(mColor.val.ubyteVal[0], mColor.val.ubyteVal[1], mColor.val.ubyteVal[2], mColor.val.ubyteVal[3]); break; default: fprintf(stderr, "WARNING: glColor with unknown type 0x%x\n", mColor.type); break; } switch (mNormal.type) { case GL_FLOAT: dispatcher.glNormal3f(mNormal.val.floatVal[0], mNormal.val.floatVal[1], mNormal.val.floatVal[2]); break; default: fprintf(stderr, "WARNING: glNormal with unknown type 0x%x\n", mNormal.type); break; } dispatcher.glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mMaterial.ambient); dispatcher.glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mMaterial.diffuse); dispatcher.glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mMaterial.specular); dispatcher.glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mMaterial.emissive); dispatcher.glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, mMaterial.specularExponent); dispatcher.glLightModelfv(GL_LIGHT_MODEL_AMBIENT, mLightModel.color); dispatcher.glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, mLightModel.twoSided); for (int i = 0; i < kMaxLights; i++) { dispatcher.glLightfv(GL_LIGHT0 + i, GL_AMBIENT, mLights[i].ambient); dispatcher.glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, mLights[i].diffuse); dispatcher.glLightfv(GL_LIGHT0 + i, GL_SPECULAR, mLights[i].specular); dispatcher.glLightfv(GL_LIGHT0 + i, GL_POSITION, mLights[i].position); dispatcher.glLightfv(GL_LIGHT0 + i, GL_SPOT_DIRECTION, mLights[i].direction); dispatcher.glLightf(GL_LIGHT0 + i, GL_SPOT_EXPONENT, mLights[i].spotlightExponent); dispatcher.glLightf(GL_LIGHT0 + i, GL_SPOT_CUTOFF, mLights[i].spotlightCutoffAngle); dispatcher.glLightf(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, mLights[i].attenuationConst); dispatcher.glLightf(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, mLights[i].attenuationLinear); dispatcher.glLightf(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, mLights[i].attenuationQuadratic); } dispatcher.glFogf(GL_FOG_MODE, (GLfloat)mFog.mode); dispatcher.glFogf(GL_FOG_DENSITY, mFog.density); dispatcher.glFogf(GL_FOG_START, mFog.start); dispatcher.glFogf(GL_FOG_END, mFog.end); dispatcher.glFogfv(GL_FOG_COLOR, mFog.color); } } GLEScontext::postLoadRestoreCtx(); } //setting client side arr void GLEScmContext::setupArr(const GLvoid* arr,GLenum arrayType,GLenum dataType,GLint size,GLsizei stride,GLboolean normalized, int index, bool isInt){ if( arr == NULL) return; switch(arrayType) { case GL_VERTEX_ARRAY: s_glDispatch.glVertexPointer(size,dataType,stride,arr); break; case GL_NORMAL_ARRAY: s_glDispatch.glNormalPointer(dataType,stride,arr); break; case GL_TEXTURE_COORD_ARRAY: s_glDispatch.glTexCoordPointer(size,dataType,stride,arr); break; case GL_COLOR_ARRAY: s_glDispatch.glColorPointer(size,dataType,stride,arr); break; case GL_POINT_SIZE_ARRAY_OES: m_pointsIndex = index; break; } } void GLEScmContext::setupArrayPointerHelper(GLESConversionArrays& cArrs,GLint first,GLsizei count,GLenum type,const GLvoid* indices,bool direct,GLenum array_id,GLESpointer* p){ unsigned int size = p->getSize(); GLenum dataType = p->getType(); if(needConvert(cArrs,first,count,type,indices,direct,p,array_id)){ //conversion has occured ArrayData currentArr = cArrs.getCurrentArray(); setupArr(currentArr.data,array_id,currentArr.type,size,currentArr.stride,GL_FALSE, cArrs.getCurrentIndex()); ++cArrs; } else { setupArr(p->getData(),array_id,dataType,size,p->getStride(), GL_FALSE); } } void GLEScmContext::setupArraysPointers(GLESConversionArrays& cArrs,GLint first,GLsizei count,GLenum type,const GLvoid* indices,bool direct, bool* needEnablingPostDraw) { (void)needEnablingPostDraw; ArraysMap::iterator it; m_pointsIndex = -1; //going over all clients arrays Pointers for ( it=m_currVaoState.begin() ; it != m_currVaoState.end(); ++it) { GLenum array_id = (*it).first; GLESpointer* p = (*it).second; if(!p->isEnable()) continue; if(array_id == GL_TEXTURE_COORD_ARRAY) continue; //handling textures later setupArrayPointerHelper(cArrs,first,count,type,indices,direct,array_id,p); } unsigned int activeTexture = m_clientActiveTexture + GL_TEXTURE0; //converting all texture coords arrays for(int i=0; i< kMaxTextureUnits;i++) { unsigned int tex = GL_TEXTURE0+i; setClientActiveTexture(tex); s_glDispatch.glClientActiveTexture(tex); GLenum array_id = GL_TEXTURE_COORD_ARRAY; GLESpointer* p = m_currVaoState[array_id]; if(!p->isEnable()) continue; setupArrayPointerHelper(cArrs,first,count,type,indices,direct,array_id,p); } setClientActiveTexture(activeTexture); s_glDispatch.glClientActiveTexture(activeTexture); } void GLEScmContext::drawPointsData(GLESConversionArrays& cArrs,GLint first,GLsizei count,GLenum type,const GLvoid* indices_in,bool isElemsDraw) { const char *pointsArr = NULL; int stride = 0; GLESpointer* p = m_currVaoState[GL_POINT_SIZE_ARRAY_OES]; //choosing the right points sizes array source if(m_pointsIndex >= 0) { //point size array was converted pointsArr = (const char*)(cArrs[m_pointsIndex].data); stride = cArrs[m_pointsIndex].stride; } else { pointsArr = static_cast(p->getData()); stride = p->getStride(); } if(stride == 0){ stride = sizeof(GLfloat); } if(isElemsDraw) { int tSize = 0; switch (type) { case GL_UNSIGNED_BYTE: tSize = 1; break; case GL_UNSIGNED_SHORT: tSize = 2; break; case GL_UNSIGNED_INT: tSize = 4; break; }; int i = 0; while(i(indices_in)[i]: \ type == GL_UNSIGNED_SHORT ? \ static_cast(indices_in)[i]: \ static_cast(indices_in)[i]) GLfloat pSize = *((GLfloat*)(pointsArr+(INDEX*stride))); i++; while(i < count && pSize == *((GLfloat*)(pointsArr+(INDEX*stride)))) { sCount++; i++; } s_glDispatch.glPointSize(pSize); s_glDispatch.glDrawElements(GL_POINTS, sCount, type, (char*)indices_in+sStart*tSize); } } else { int i = 0; while(i& out) const { std::vector vec(4); switch (mColor.type) { case GL_UNSIGNED_BYTE: vec = { mColor.val.ubyteVal[0] / 255.0f, mColor.val.ubyteVal[1] / 255.0f, mColor.val.ubyteVal[2] / 255.0f, mColor.val.ubyteVal[3] / 255.0f, }; default: vec = { mColor.val.floatVal[0], mColor.val.floatVal[1], mColor.val.floatVal[2], mColor.val.floatVal[3], }; } appendRepeatedVector(count, vec, out); } void GLEScmContext::getNormal(uint32_t count, std::vector& out) const { std::vector vec = { mNormal.val.floatVal[0], mNormal.val.floatVal[1], mNormal.val.floatVal[2] }; appendRepeatedVector(count, vec, out); } void GLEScmContext::getMultiTexCoord(uint32_t count, uint32_t index, std::vector& out) const { // s, t, r, qcomponents std::vector vec = { mMultiTexCoord[index].floatVal[0], mMultiTexCoord[index].floatVal[1], mMultiTexCoord[index].floatVal[2], mMultiTexCoord[index].floatVal[3] }; appendRepeatedVector(count, vec, out); } void GLEScmContext::appendRepeatedVector(uint32_t count, std::vector& in, std::vector& out) const { size_t previousOutSize = out.size(); out.resize(previousOutSize + (count * in.size())); auto it = out.begin() + previousOutSize; for (int i = 0; i < count; i++) { std::copy(in.begin(), in.end(), it); it += in.size(); } } GLenum GLEScmContext::getTextureEnvMode() { return mTexUnitEnvs[m_activeTexture][GL_TEXTURE_ENV_MODE].val.intVal[0]; } GLenum GLEScmContext::getTextureGenMode() { return mTexGens[m_activeTexture][GL_TEXTURE_GEN_MODE_OES].val.intVal[0]; } glm::mat4 GLEScmContext::getProjMatrix() { return mProjMatrices.back(); } glm::mat4 GLEScmContext::getModelviewMatrix() { return mModelviewMatrices.back(); } glm::mat4 GLEScmContext::getTextureMatrix() { return mTextureMatrices[m_activeTexture].back(); } glm::mat4& GLEScmContext::currMatrix() { return currMatrixStack().back(); } GLEScmContext::MatrixStack& GLEScmContext::currMatrixStack() { switch (mCurrMatrixMode) { case GL_TEXTURE: return mTextureMatrices[m_activeTexture]; case GL_PROJECTION: return mProjMatrices; case GL_MODELVIEW: return mModelviewMatrices; default: break; // emugl_crash_reporter("error: matrix mode set to 0x%x!", mCurrMatrixMode); } // Make compiler happy return mModelviewMatrices; } bool GLEScmContext::needConvert(GLESConversionArrays& cArrs,GLint first,GLsizei count,GLenum type,const GLvoid* indices,bool direct,GLESpointer* p,GLenum array_id) { bool usingVBO = p->getAttribType() == GLESpointer::BUFFER; GLenum arrType = p->getType(); /* conversion is not necessary in the following cases: (*) array type is byte but it is not vertex or texture array (*) array type is not fixed */ if((arrType != GL_FIXED) && (arrType != GL_BYTE)) return false; if((arrType == GL_BYTE && (array_id != GL_VERTEX_ARRAY)) && (arrType == GL_BYTE && (array_id != GL_TEXTURE_COORD_ARRAY)) ) return false; bool byteVBO = (arrType == GL_BYTE) && usingVBO; if(byteVBO){ p->redirectPointerData(); } if(!usingVBO || byteVBO) { if (direct) { convertDirect(cArrs,first,count,array_id,p); } else { convertIndirect(cArrs,count,type,indices,array_id,p); } } else { if (direct) { convertDirectVBO(cArrs,first,count,array_id,p) ; } else { convertIndirectVBO(cArrs,count,type,indices,array_id,p); } } return true; } const GLESpointer* GLEScmContext::getPointer(GLenum arrType) { GLenum type = arrType == GL_VERTEX_ARRAY_POINTER ? GL_VERTEX_ARRAY : arrType == GL_NORMAL_ARRAY_POINTER ? GL_NORMAL_ARRAY : arrType == GL_TEXTURE_COORD_ARRAY_POINTER ? GL_TEXTURE_COORD_ARRAY : arrType == GL_COLOR_ARRAY_POINTER ? GL_COLOR_ARRAY : arrType == GL_POINT_SIZE_ARRAY_POINTER_OES ? GL_POINT_SIZE_ARRAY_OES : 0; if(type != 0) { return GLEScontext::getPointer(type); } return NULL; } void GLEScmContext::initExtensionString() { if (s_glExtensionsGles1Initialized) return; initCapsLocked((const GLubyte*)getHostExtensionsString(&s_glDispatch).c_str(), m_nativeTextureDecompressionEnabled, s_glSupportGles1); *s_glExtensionsGles1 = "GL_OES_blend_func_separate GL_OES_blend_equation_separate GL_OES_blend_subtract " "GL_OES_byte_coordinates GL_OES_compressed_paletted_texture GL_OES_point_size_array " "GL_OES_point_sprite GL_OES_single_precision GL_OES_stencil_wrap GL_OES_texture_env_crossbar " "GL_OES_texture_mirored_repeat GL_OES_EGL_image GL_OES_element_index_uint GL_OES_draw_texture " "GL_OES_texture_cube_map GL_OES_draw_texture "; if (s_glSupportGles1.GL_OES_READ_FORMAT) *s_glExtensionsGles1+="GL_OES_read_format "; if (s_glSupportGles1.GL_EXT_FRAMEBUFFER_OBJECT) { *s_glExtensionsGles1+="GL_OES_framebuffer_object GL_OES_depth24 GL_OES_depth32 GL_OES_fbo_render_mipmap " "GL_OES_rgb8_rgba8 GL_OES_stencil1 GL_OES_stencil4 GL_OES_stencil8 "; } if (s_glSupportGles1.GL_EXT_PACKED_DEPTH_STENCIL) *s_glExtensionsGles1+="GL_OES_packed_depth_stencil "; if (s_glSupportGles1.GL_EXT_TEXTURE_FORMAT_BGRA8888) *s_glExtensionsGles1+="GL_EXT_texture_format_BGRA8888 GL_APPLE_texture_format_BGRA8888 "; if (s_glSupportGles1.GL_ARB_MATRIX_PALETTE && s_glSupportGles1.GL_ARB_VERTEX_BLEND) { *s_glExtensionsGles1+="GL_OES_matrix_palette "; GLint max_palette_matrices=0; GLint max_vertex_units=0; dispatcher().glGetIntegerv(GL_MAX_PALETTE_MATRICES_OES,&max_palette_matrices); dispatcher().glGetIntegerv(GL_MAX_VERTEX_UNITS_OES,&max_vertex_units); if (max_palette_matrices>=32 && max_vertex_units>=4) *s_glExtensionsGles1+="GL_OES_extended_matrix_palette "; } *s_glExtensionsGles1+="GL_OES_compressed_ETC1_RGB8_texture "; s_glExtensionsGles1Initialized = true; } int GLEScmContext::getMaxTexUnits() { return kMaxTextureUnits; } bool GLEScmContext::glGetBooleanv(GLenum pname, GLboolean *params) { GLint iParam; if(glGetIntegerv(pname, &iParam)) { *params = (iParam != 0); return true; } return false; } bool GLEScmContext::glGetFixedv(GLenum pname, GLfixed *params) { GLint iParam; if(glGetIntegerv(pname, &iParam)) { *params = I2X(iParam); return true; } return false; } bool GLEScmContext::glGetFloatv(GLenum pname, GLfloat *params) { GLint iParam; if(glGetIntegerv(pname, &iParam)) { *params = (GLfloat)iParam; return true; } return false; } bool GLEScmContext::glGetIntegerv(GLenum pname, GLint *params) { if(GLEScontext::glGetIntegerv(pname, params)) return true; const GLESpointer* ptr = NULL; switch(pname){ case GL_VERTEX_ARRAY_BUFFER_BINDING: case GL_VERTEX_ARRAY_SIZE: case GL_VERTEX_ARRAY_STRIDE: case GL_VERTEX_ARRAY_TYPE: ptr = getPointer(GL_VERTEX_ARRAY_POINTER); break; case GL_NORMAL_ARRAY_BUFFER_BINDING: case GL_NORMAL_ARRAY_STRIDE: case GL_NORMAL_ARRAY_TYPE: ptr = getPointer(GL_NORMAL_ARRAY_POINTER); break; case GL_COLOR_ARRAY_BUFFER_BINDING: case GL_COLOR_ARRAY_SIZE: case GL_COLOR_ARRAY_STRIDE: case GL_COLOR_ARRAY_TYPE: ptr = getPointer(GL_COLOR_ARRAY_POINTER); break; case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING: case GL_TEXTURE_COORD_ARRAY_SIZE: case GL_TEXTURE_COORD_ARRAY_STRIDE: case GL_TEXTURE_COORD_ARRAY_TYPE: ptr = getPointer(GL_TEXTURE_COORD_ARRAY_POINTER); break; case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES: case GL_POINT_SIZE_ARRAY_STRIDE_OES: case GL_POINT_SIZE_ARRAY_TYPE_OES: ptr = getPointer(GL_POINT_SIZE_ARRAY_POINTER_OES); break; default: return false; } switch(pname) { case GL_VERTEX_ARRAY_BUFFER_BINDING: case GL_NORMAL_ARRAY_BUFFER_BINDING: case GL_COLOR_ARRAY_BUFFER_BINDING: case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING: case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES: *params = ptr ? ptr->getBufferName() : 0; break; case GL_VERTEX_ARRAY_STRIDE: case GL_NORMAL_ARRAY_STRIDE: case GL_COLOR_ARRAY_STRIDE: case GL_TEXTURE_COORD_ARRAY_STRIDE: case GL_POINT_SIZE_ARRAY_STRIDE_OES: *params = ptr ? ptr->getStride() : 0; break; case GL_VERTEX_ARRAY_SIZE: case GL_COLOR_ARRAY_SIZE: case GL_TEXTURE_COORD_ARRAY_SIZE: *params = ptr ? ptr->getSize() : 0; break; case GL_VERTEX_ARRAY_TYPE: case GL_NORMAL_ARRAY_TYPE: case GL_COLOR_ARRAY_TYPE: case GL_TEXTURE_COORD_ARRAY_TYPE: case GL_POINT_SIZE_ARRAY_TYPE_OES: *params = ptr ? ptr->getType() : 0; break; } return true; } GLint GLEScmContext::getErrorCoreProfile() { return core().getAndClearLastError(); } void GLEScmContext::enable(GLenum cap) { setEnable(cap, true); if (m_coreProfileEngine) { core().enable(cap); } else { if (cap==GL_TEXTURE_GEN_STR_OES) { dispatcher().glEnable(GL_TEXTURE_GEN_S); dispatcher().glEnable(GL_TEXTURE_GEN_T); dispatcher().glEnable(GL_TEXTURE_GEN_R); } else { dispatcher().glEnable(cap); } } } void GLEScmContext::disable(GLenum cap) { setEnable(cap, false); if (m_coreProfileEngine) { core().disable(cap); } else { if (cap==GL_TEXTURE_GEN_STR_OES) { dispatcher().glDisable(GL_TEXTURE_GEN_S); dispatcher().glDisable(GL_TEXTURE_GEN_T); dispatcher().glDisable(GL_TEXTURE_GEN_R); } else { dispatcher().glDisable(cap); } } } void GLEScmContext::shadeModel(GLenum mode) { mShadeModel = mode; if (m_coreProfileEngine) { core().shadeModel(mode); } else { dispatcher().glShadeModel(mode); } } void GLEScmContext::matrixMode(GLenum mode) { mCurrMatrixMode = mode; if (m_coreProfileEngine) { core().matrixMode(mode); } else { dispatcher().glMatrixMode(mode); } } void GLEScmContext::loadIdentity() { currMatrix() = glm::mat4(); if (m_coreProfileEngine) { core().loadIdentity(); } else { dispatcher().glLoadIdentity(); } } void GLEScmContext::loadMatrixf(const GLfloat* m) { currMatrix() = glm::make_mat4(m); if (m_coreProfileEngine) { core().loadMatrixf(m); } else { dispatcher().glLoadMatrixf(m); } } void GLEScmContext::pushMatrix() { if (currMatrixStack().size() >= kMaxMatrixStackSize) { setGLerror(GL_STACK_OVERFLOW); return; } currMatrixStack().emplace_back(currMatrixStack().back()); if (m_coreProfileEngine) { core().pushMatrix(); } else { dispatcher().glPushMatrix(); } } void GLEScmContext::popMatrix() { if (currMatrixStack().size() == 1) { setGLerror(GL_STACK_UNDERFLOW); return; } currMatrixStack().pop_back(); if (m_coreProfileEngine) { core().popMatrix(); } else { dispatcher().glPopMatrix(); } } void GLEScmContext::multMatrixf(const GLfloat* m) { currMatrix() *= glm::make_mat4(m); if (m_coreProfileEngine) { core().multMatrixf(m); } else { dispatcher().glMultMatrixf(m); } } void GLEScmContext::orthof(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) { currMatrix() *= glm::ortho(left, right, bottom, top, zNear, zFar); if (m_coreProfileEngine) { core().orthof(left, right, bottom, top, zNear, zFar); } else { dispatcher().glOrthof(left,right,bottom,top,zNear,zFar); } } void GLEScmContext::frustumf(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) { currMatrix() *= glm::frustum(left, right, bottom, top, zNear, zFar); if (m_coreProfileEngine) { core().frustumf(left, right, bottom, top, zNear, zFar); } else { dispatcher().glFrustumf(left,right,bottom,top,zNear,zFar); } } void GLEScmContext::texEnvf(GLenum target, GLenum pname, GLfloat param) { // Assume |target| is GL_TEXTURE_ENV if (pname == GL_TEXTURE_ENV_MODE) { texEnvi(target, pname, (GLint)param); } else { mTexUnitEnvs[m_activeTexture][pname].val.floatVal[0] = param; mTexUnitEnvs[m_activeTexture][pname].type = GL_FLOAT; } if (m_coreProfileEngine) { core().texEnvf(target, pname, param); } else { dispatcher().glTexEnvf(target, pname, param); } } void GLEScmContext::texEnvfv(GLenum target, GLenum pname, const GLfloat* params) { if (pname == GL_TEXTURE_ENV_COLOR) { for (int i = 0; i < 4; i++) { mTexUnitEnvs[m_activeTexture][pname].val.floatVal[i] = params[i]; mTexUnitEnvs[m_activeTexture][pname].type = GL_FLOAT; } } else { texEnvf(target, pname, params[0]); } if (m_coreProfileEngine) { core().texEnvfv(target, pname, params); } else { dispatcher().glTexEnvfv(target, pname, params); } } void GLEScmContext::texEnvi(GLenum target, GLenum pname, GLint param) { mTexUnitEnvs[m_activeTexture][pname].val.intVal[0] = param; mTexUnitEnvs[m_activeTexture][pname].type = GL_INT; if (m_coreProfileEngine) { core().texEnvi(target, pname, param); } else { dispatcher().glTexEnvi(target, pname, param); } } void GLEScmContext::texEnviv(GLenum target, GLenum pname, const GLint* params) { mTexUnitEnvs[m_activeTexture][pname].val.intVal[0] = params[0]; mTexUnitEnvs[m_activeTexture][pname].type = GL_INT; if (m_coreProfileEngine) { core().texEnviv(target, pname, params); } else { dispatcher().glTexEnviv(target, pname, params); } } void GLEScmContext::getTexEnvfv(GLenum env, GLenum pname, GLfloat* params) { *params = mTexUnitEnvs[m_activeTexture][pname].val.floatVal[0]; if (m_coreProfileEngine) { core().getTexEnvfv(env, pname, params); } else { dispatcher().glGetTexEnvfv(env, pname, params); } } void GLEScmContext::getTexEnviv(GLenum env, GLenum pname, GLint* params) { *params = mTexUnitEnvs[m_activeTexture][pname].val.intVal[0]; if (m_coreProfileEngine) { core().getTexEnviv(env, pname, params); } else { dispatcher().glGetTexEnviv(env, pname, params); } } void GLEScmContext::texGenf(GLenum coord, GLenum pname, GLfloat param) { mTexGens[m_activeTexture][pname].val.floatVal[0] = param; mTexGens[m_activeTexture][pname].type = GL_FLOAT; if (m_coreProfileEngine) { core().texGenf(coord, pname, param); } else { if (coord == GL_TEXTURE_GEN_STR_OES) { dispatcher().glTexGenf(GL_S,pname,param); dispatcher().glTexGenf(GL_T,pname,param); dispatcher().glTexGenf(GL_R,pname,param); } else { dispatcher().glTexGenf(coord,pname,param); } } } void GLEScmContext::texGenfv(GLenum coord, GLenum pname, const GLfloat* params) { mTexGens[m_activeTexture][pname].val.floatVal[0] = params[0]; mTexGens[m_activeTexture][pname].type = GL_FLOAT; if (m_coreProfileEngine) { core().texGenfv(coord, pname, params); } else { if (coord == GL_TEXTURE_GEN_STR_OES) { dispatcher().glTexGenfv(GL_S,pname,params); dispatcher().glTexGenfv(GL_T,pname,params); dispatcher().glTexGenfv(GL_R,pname,params); } else { dispatcher().glTexGenfv(coord,pname,params); } } } void GLEScmContext::texGeni(GLenum coord, GLenum pname, GLint param) { mTexGens[m_activeTexture][pname].val.intVal[0] = param; mTexGens[m_activeTexture][pname].type = GL_INT; if (m_coreProfileEngine) { core().texGeni(coord, pname, param); } else { if (coord == GL_TEXTURE_GEN_STR_OES) { dispatcher().glTexGeni(GL_S,pname,param); dispatcher().glTexGeni(GL_T,pname,param); dispatcher().glTexGeni(GL_R,pname,param); } else { dispatcher().glTexGeni(coord,pname,param); } } } void GLEScmContext::texGeniv(GLenum coord, GLenum pname, const GLint* params) { mTexGens[m_activeTexture][pname].val.intVal[0] = params[0]; mTexGens[m_activeTexture][pname].type = GL_INT; if (m_coreProfileEngine) { core().texGeniv(coord, pname, params); } else { if (coord == GL_TEXTURE_GEN_STR_OES) { dispatcher().glTexGeniv(GL_S,pname,params); dispatcher().glTexGeniv(GL_T,pname,params); dispatcher().glTexGeniv(GL_R,pname,params); } else { dispatcher().glTexGeniv(coord,pname,params); } } } void GLEScmContext::getTexGeniv(GLenum coord, GLenum pname, GLint* params) { *params = mTexGens[m_activeTexture][pname].val.intVal[0]; if (m_coreProfileEngine) { core().getTexGeniv(coord, pname, params); } else { if (coord == GL_TEXTURE_GEN_STR_OES) { GLint state_s = GL_FALSE; GLint state_t = GL_FALSE; GLint state_r = GL_FALSE; dispatcher().glGetTexGeniv(GL_S,pname,&state_s); dispatcher().glGetTexGeniv(GL_T,pname,&state_t); dispatcher().glGetTexGeniv(GL_R,pname,&state_r); *params = state_s && state_t && state_r ? GL_TRUE: GL_FALSE; } else { dispatcher().glGetTexGeniv(coord,pname,params); } } } void GLEScmContext::getTexGenfv(GLenum coord, GLenum pname, GLfloat* params) { params[0] = mTexGens[m_activeTexture][pname].val.floatVal[0]; params[1] = mTexGens[m_activeTexture][pname].val.floatVal[1]; params[2] = mTexGens[m_activeTexture][pname].val.floatVal[2]; params[3] = mTexGens[m_activeTexture][pname].val.floatVal[3]; if (m_coreProfileEngine) { core().getTexGenfv(coord, pname, params); } else { if (coord == GL_TEXTURE_GEN_STR_OES) { GLfloat state_s = GL_FALSE; GLfloat state_t = GL_FALSE; GLfloat state_r = GL_FALSE; dispatcher().glGetTexGenfv(GL_S,pname,&state_s); dispatcher().glGetTexGenfv(GL_T,pname,&state_t); dispatcher().glGetTexGenfv(GL_R,pname,&state_r); *params = state_s && state_t && state_r ? GL_TRUE: GL_FALSE; } else { dispatcher().glGetTexGenfv(coord,pname,params); } } } void GLEScmContext::materialf(GLenum face, GLenum pname, GLfloat param) { if (face != GL_FRONT_AND_BACK) { fprintf(stderr, "GL_INVALID_ENUM: GLES1's glMaterial(f/x) " "only supports GL_FRONT_AND_BACK for materials.\n"); setGLerror(GL_INVALID_ENUM); return; } switch (pname) { case GL_AMBIENT: case GL_DIFFUSE: case GL_AMBIENT_AND_DIFFUSE: case GL_SPECULAR: case GL_EMISSION: fprintf(stderr, "GL_INVALID_ENUM: glMaterial(f/x) only supports " "GL_SHININESS for single parameter setting.\n"); setGLerror(GL_INVALID_ENUM); return; case GL_SHININESS: if (param < 0.0f || param > 128.0f) { fprintf(stderr, "GL_INVALID_VALUE: Invalid specular exponent value %f. " "Only range [0.0, 128.0] supported.\n", param); setGLerror(GL_INVALID_VALUE); return; } mMaterial.specularExponent = param; break; default: fprintf(stderr, "Unknown parameter name 0x%x for glMaterial(f/x)\n", pname); setGLerror(GL_INVALID_ENUM); return; } if (!m_coreProfileEngine) { dispatcher().glMaterialf(face, pname, param); } } void GLEScmContext::materialfv(GLenum face, GLenum pname, const GLfloat* params) { if (face != GL_FRONT_AND_BACK) { fprintf(stderr, "GL_INVALID_ENUM: GLES1's glMaterial(f/x)v " "only supports GL_FRONT_AND_BACK for materials.\n"); setGLerror(GL_INVALID_ENUM); return; } switch (pname) { case GL_AMBIENT: memcpy(&mMaterial.ambient, params, 4 * sizeof(GLfloat)); break; case GL_DIFFUSE: memcpy(&mMaterial.diffuse, params, 4 * sizeof(GLfloat)); break; case GL_AMBIENT_AND_DIFFUSE: memcpy(&mMaterial.ambient, params, 4 * sizeof(GLfloat)); memcpy(&mMaterial.diffuse, params, 4 * sizeof(GLfloat)); break; case GL_SPECULAR: memcpy(&mMaterial.specular, params, 4 * sizeof(GLfloat)); break; case GL_EMISSION: memcpy(&mMaterial.emissive, params, 4 * sizeof(GLfloat)); break; case GL_SHININESS: if (*params < 0.0f || *params > 128.0f) { fprintf(stderr, "GL_INVALID_VALUE: Invalid specular exponent value %f. " "Only range [0.0, 128.0] supported.\n", *params); setGLerror(GL_INVALID_VALUE); return; } mMaterial.specularExponent = *params; break; default: fprintf(stderr, "Unknown parameter name 0x%x for glMaterial(f/x)v.\n", pname); setGLerror(GL_INVALID_ENUM); return; } if (!m_coreProfileEngine) { dispatcher().glMaterialfv(face, pname, params); } } void GLEScmContext::getMaterialfv(GLenum face, GLenum pname, GLfloat* params) { if (face != GL_FRONT && face != GL_BACK) { fprintf(stderr, "GL_INVALID_ENUM: glGetMaterial(f/x)v " "must take GL_FRONT or GL_BACK as face argument\n"); setGLerror(GL_INVALID_ENUM); return; } switch (pname) { case GL_AMBIENT: memcpy(params, &mMaterial.ambient, 4 * sizeof(GLfloat)); break; case GL_DIFFUSE: memcpy(params, &mMaterial.diffuse, 4 * sizeof(GLfloat)); break; case GL_SPECULAR: memcpy(params, &mMaterial.specular, 4 * sizeof(GLfloat)); break; case GL_EMISSION: memcpy(params, &mMaterial.emissive, 4 * sizeof(GLfloat)); break; case GL_SHININESS: *params = mMaterial.specularExponent; break; default: fprintf(stderr, "GL_INVALID_ENUM: Unknown parameter name 0x%x for glGetMaterial(f/x)v.\n", pname); setGLerror(GL_INVALID_ENUM); return; } if (!m_coreProfileEngine) { dispatcher().glGetMaterialfv(face, pname, params); } } void GLEScmContext::lightModelf(GLenum pname, GLfloat param) { switch (pname) { case GL_LIGHT_MODEL_AMBIENT: fprintf(stderr, "GL_INVALID_ENUM: glLightModelf only supports GL_LIGHT_MODEL_TWO_SIDE.\n"); setGLerror(GL_INVALID_ENUM); return; case GL_LIGHT_MODEL_TWO_SIDE: if (param != 1.0f && param != 0.0f) { fprintf(stderr, "GL_INVALID_VALUE: glLightModelf only takes 0 or 1 " "for GL_LIGHT_MODEL_TWO_SIDE, but got %f\n", param); setGLerror(GL_INVALID_VALUE); } mLightModel.twoSided = param == 1.0f ? true : false; break; default: fprintf(stderr, "GL_INVALID_ENUM: Unknown parameter name 0x%x for glLightModel(f/x)v.\n", pname); setGLerror(GL_INVALID_ENUM); return; } if (!m_coreProfileEngine) { dispatcher().glLightModelf(pname, param); } } void GLEScmContext::lightModelfv(GLenum pname, const GLfloat* params) { switch (pname) { case GL_LIGHT_MODEL_AMBIENT: memcpy(&mLightModel.color, params, 4 * sizeof(GLfloat)); break; case GL_LIGHT_MODEL_TWO_SIDE: if (*params != 1.0f && *params != 0.0f) { fprintf(stderr, "GL_INVALID_VALUE: glLightModelf only takes 0 or 1 " "for GL_LIGHT_MODEL_TWO_SIDE, but got %f\n", *params); setGLerror(GL_INVALID_VALUE); } mLightModel.twoSided = *params == 1.0f ? true : false; break; default: fprintf(stderr, "GL_INVALID_ENUM: Unknown parameter name 0x%x for glLightModel(f/x)v.\n", pname); setGLerror(GL_INVALID_ENUM); return; } if (!m_coreProfileEngine) { dispatcher().glLightModelfv(pname, params); } } void GLEScmContext::lightf(GLenum light, GLenum pname, GLfloat param) { uint32_t lightIndex = light - GL_LIGHT0; if (lightIndex >= kMaxLights) { fprintf(stderr, "GL_INVALID_ENUM: Exceeded max lights for glLight(f/x) (wanted %u)\n", lightIndex); setGLerror(GL_INVALID_ENUM); return; } switch (pname) { case GL_AMBIENT: case GL_DIFFUSE: case GL_SPECULAR: case GL_POSITION: case GL_SPOT_DIRECTION: fprintf(stderr, "GL_INVALID_ENUM: Invalid parameter name 0x%x " "for glLight(f/x). Needs glLight(f/x)v.\n", pname); setGLerror(GL_INVALID_ENUM); return; case GL_SPOT_EXPONENT: mLights[lightIndex].spotlightExponent = param; break; case GL_SPOT_CUTOFF: mLights[lightIndex].spotlightCutoffAngle = param; break; case GL_CONSTANT_ATTENUATION: mLights[lightIndex].attenuationConst = param; break; case GL_LINEAR_ATTENUATION: mLights[lightIndex].attenuationLinear = param; break; case GL_QUADRATIC_ATTENUATION: mLights[lightIndex].attenuationQuadratic = param; break; default: fprintf(stderr, "GL_INVALID_ENUM: Unknown parameter name 0x%x " "for glLight(f/x).\n", pname); setGLerror(GL_INVALID_ENUM); return; } if (!m_coreProfileEngine) { dispatcher().glLightf(light, pname, param); } } void GLEScmContext::lightfv(GLenum light, GLenum pname, const GLfloat* params) { uint32_t lightIndex = light - GL_LIGHT0; if (lightIndex >= kMaxLights) { fprintf(stderr, "GL_INVALID_ENUM: Exceeded max lights for " "glLight(f/x)v (wanted %u)\n", lightIndex); setGLerror(GL_INVALID_ENUM); return; } switch (pname) { case GL_AMBIENT: memcpy(&mLights[lightIndex].ambient, params, 4 * sizeof(GLfloat)); break; case GL_DIFFUSE: memcpy(&mLights[lightIndex].diffuse, params, 4 * sizeof(GLfloat)); break; case GL_SPECULAR: memcpy(&mLights[lightIndex].specular, params, 4 * sizeof(GLfloat)); break; case GL_POSITION: memcpy(&mLights[lightIndex].position, params, 4 * sizeof(GLfloat)); break; case GL_SPOT_DIRECTION: memcpy(&mLights[lightIndex].direction, params, 3 * sizeof(GLfloat)); break; case GL_SPOT_EXPONENT: mLights[lightIndex].spotlightExponent = *params; break; case GL_SPOT_CUTOFF: mLights[lightIndex].spotlightCutoffAngle = *params; break; case GL_CONSTANT_ATTENUATION: mLights[lightIndex].attenuationConst = *params; break; case GL_LINEAR_ATTENUATION: mLights[lightIndex].attenuationLinear = *params; break; case GL_QUADRATIC_ATTENUATION: mLights[lightIndex].attenuationQuadratic = *params; break; default: fprintf(stderr, "GL_INVALID_ENUM: Unknown parameter name 0x%x " "for glLight(f/x).\n", pname); setGLerror(GL_INVALID_ENUM); return; } if (!m_coreProfileEngine) { dispatcher().glLightfv(light, pname, params); } } void GLEScmContext::getLightfv(GLenum light, GLenum pname, GLfloat* params) { uint32_t lightIndex = light - GL_LIGHT0; if (lightIndex >= kMaxLights) { fprintf(stderr, "GL_INVALID_ENUM: Exceeded max lights for " "glGetLight(f/x)v (wanted %u)\n", lightIndex); setGLerror(GL_INVALID_ENUM); return; } switch (pname) { case GL_AMBIENT: memcpy(params, &mLights[lightIndex].ambient, 4 * sizeof(GLfloat)); break; case GL_DIFFUSE: memcpy(params, &mLights[lightIndex].diffuse, 4 * sizeof(GLfloat)); break; case GL_SPECULAR: memcpy(params, &mLights[lightIndex].specular, 4 * sizeof(GLfloat)); break; case GL_POSITION: memcpy(params, &mLights[lightIndex].position, 4 * sizeof(GLfloat)); break; case GL_SPOT_DIRECTION: memcpy(params, &mLights[lightIndex].direction, 3 * sizeof(GLfloat)); break; case GL_SPOT_EXPONENT: *params = mLights[lightIndex].spotlightExponent; break; case GL_SPOT_CUTOFF: *params = mLights[lightIndex].spotlightCutoffAngle; break; case GL_CONSTANT_ATTENUATION: *params = mLights[lightIndex].attenuationConst; break; case GL_LINEAR_ATTENUATION: *params = mLights[lightIndex].attenuationLinear; break; case GL_QUADRATIC_ATTENUATION: *params = mLights[lightIndex].attenuationQuadratic; break; default: fprintf(stderr, "GL_INVALID_ENUM: Unknown parameter name 0x%x " "for glGetLight(f/x).\n", pname); setGLerror(GL_INVALID_ENUM); return; } if (!m_coreProfileEngine) { dispatcher().glGetLightfv(light, pname, params); } } void GLEScmContext::multiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) { mMultiTexCoord[target - GL_TEXTURE0].floatVal[0] = s; mMultiTexCoord[target - GL_TEXTURE0].floatVal[1] = t; mMultiTexCoord[target - GL_TEXTURE0].floatVal[2] = q; mMultiTexCoord[target - GL_TEXTURE0].floatVal[3] = r; if (!m_coreProfileEngine) { dispatcher().glMultiTexCoord4f(target, s, t, r, q); } } void GLEScmContext::normal3f(GLfloat nx, GLfloat ny, GLfloat nz) { mNormal.type = GL_FLOAT; mNormal.val.floatVal[0] = nx; mNormal.val.floatVal[1] = ny; mNormal.val.floatVal[2] = nz; if (!m_coreProfileEngine) { dispatcher().glNormal3f(nx, ny, nz); } } void GLEScmContext::fogf(GLenum pname, GLfloat param) { switch (pname) { case GL_FOG_MODE: { GLenum mode = (GLenum)param; switch (mode) { case GL_EXP: case GL_EXP2: case GL_LINEAR: mFog.mode = mode; break; default: fprintf(stderr, "GL_INVALID_ENUM: Unknown GL_FOG_MODE 0x%x " "for glFog(f/x).\n", mode); setGLerror(GL_INVALID_ENUM); break; } break; } case GL_FOG_DENSITY: if (param < 0.0f) { fprintf(stderr, "GL_INVALID_VALUE: glFog(f/x): GL_FOG_DENSITY " "needs to be nonnegative, but got %f\n", param); setGLerror(GL_INVALID_VALUE); return; } mFog.density = param; break; case GL_FOG_START: mFog.start = param; break; case GL_FOG_END: mFog.end = param; break; case GL_FOG_COLOR: fprintf(stderr, "GL_INVALID_ENUM: GL_FOG_COLOR not allowed for glFog(f/x).\n"); setGLerror(GL_INVALID_ENUM); break; default: fprintf(stderr, "GL_INVALID_ENUM: Unknown parameter name 0x%x " "for glFog(f/x).\n", pname); setGLerror(GL_INVALID_ENUM); return; } if (!m_coreProfileEngine) { dispatcher().glFogf(pname, param); } } void GLEScmContext::fogfv(GLenum pname, const GLfloat* params) { switch (pname) { case GL_FOG_MODE: { GLenum mode = (GLenum)params[0]; switch (mode) { case GL_EXP: case GL_EXP2: case GL_LINEAR: mFog.mode = mode; break; default: fprintf(stderr, "GL_INVALID_ENUM: Unknown GL_FOG_MODE 0x%x " "for glFog(f/x)v.\n", mode); setGLerror(GL_INVALID_ENUM); break; } break; } case GL_FOG_DENSITY: if (params[0] < 0.0f) { fprintf(stderr, "GL_INVALID_VALUE: glFog(f/x)v: GL_FOG_DENSITY " "needs to be nonnegative, but got %f\n", params[0]); setGLerror(GL_INVALID_VALUE); return; } mFog.density = params[0]; break; case GL_FOG_START: mFog.start = params[0]; break; case GL_FOG_END: mFog.end = params[0]; break; case GL_FOG_COLOR: memcpy(&mFog.color, params, 4 * sizeof(GLfloat)); break; default: fprintf(stderr, "GL_INVALID_ENUM: Unknown parameter name 0x%x " "for glFog(f/x)v.\n", pname); setGLerror(GL_INVALID_ENUM); return; } if (!m_coreProfileEngine) { dispatcher().glFogfv(pname, params); } } void GLEScmContext::enableClientState(GLenum clientState) { if (m_coreProfileEngine) { core().enableClientState(clientState); } else { dispatcher().glEnableClientState(clientState); } } void GLEScmContext::disableClientState(GLenum clientState) { if (m_coreProfileEngine) { core().disableClientState(clientState); } else { dispatcher().glDisableClientState(clientState); } } void GLEScmContext::drawTexOES(float x, float y, float z, float width, float height) { if (m_coreProfileEngine) { core().drawTexOES(x, y, z, width, height); } else { auto& gl = dispatcher(); int numClipPlanes; GLint viewport[4] = {}; z = (z>1 ? 1 : (z<0 ? 0 : z)); float vertices[4*3] = { x , y, z, x , static_cast(y+height), z, static_cast(x+width), static_cast(y+height), z, static_cast(x+width), y, z }; GLfloat texels[getMaxTexUnits()][4*2]; memset((void*)texels, 0, getMaxTexUnits()*4*2*sizeof(GLfloat)); gl.glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); gl.glPushAttrib(GL_TRANSFORM_BIT); //setup projection matrix to draw in viewport aligned coordinates gl.glMatrixMode(GL_PROJECTION); gl.glPushMatrix(); gl.glLoadIdentity(); gl.glGetIntegerv(GL_VIEWPORT,viewport); gl.glOrtho(viewport[0],viewport[0] + viewport[2],viewport[1],viewport[1]+viewport[3],0,-1); //setup texture matrix gl.glMatrixMode(GL_TEXTURE); gl.glPushMatrix(); gl.glLoadIdentity(); //setup modelview matrix gl.glMatrixMode(GL_MODELVIEW); gl.glPushMatrix(); gl.glLoadIdentity(); //backup vbo's int array_buffer,element_array_buffer; gl.glGetIntegerv(GL_ARRAY_BUFFER_BINDING,&array_buffer); gl.glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING,&element_array_buffer); gl.glBindBuffer(GL_ARRAY_BUFFER,0); gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); //disable clip planes gl.glGetIntegerv(GL_MAX_CLIP_PLANES,&numClipPlanes); for (int i=0;igetObjectData( NamedObjectType::TEXTURE, tex); if (objData) { texData = (TextureData*)objData; //calculate texels texels[i][0] = (float)(texData->crop_rect[0])/(float)(texData->width); texels[i][1] = (float)(texData->crop_rect[1])/(float)(texData->height); texels[i][2] = (float)(texData->crop_rect[0])/(float)(texData->width); texels[i][3] = (float)(texData->crop_rect[3]+texData->crop_rect[1])/(float)(texData->height); texels[i][4] = (float)(texData->crop_rect[2]+texData->crop_rect[0])/(float)(texData->width); texels[i][5] = (float)(texData->crop_rect[3]+texData->crop_rect[1])/(float)(texData->height); texels[i][6] = (float)(texData->crop_rect[2]+texData->crop_rect[0])/(float)(texData->width); texels[i][7] = (float)(texData->crop_rect[1])/(float)(texData->height); gl.glTexCoordPointer(2,GL_FLOAT,0,texels[i]); nTexPtrs++; } } } if (nTexPtrs>0) { //draw rectangle - only if we have some textures enabled & ready gl.glEnableClientState(GL_VERTEX_ARRAY); gl.glVertexPointer(3,GL_FLOAT,0,vertices); gl.glEnableClientState(GL_TEXTURE_COORD_ARRAY); gl.glDrawArrays(GL_TRIANGLE_FAN,0,4); } //restore vbo's gl.glBindBuffer(GL_ARRAY_BUFFER,array_buffer); gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,element_array_buffer); //restore matrix state gl.glMatrixMode(GL_MODELVIEW); gl.glPopMatrix(); gl.glMatrixMode(GL_TEXTURE); gl.glPopMatrix(); gl.glMatrixMode(GL_PROJECTION); gl.glPopMatrix(); gl.glPopAttrib(); gl.glPopClientAttrib(); } } void GLEScmContext::rotatef(float angle, float x, float y, float z) { glm::mat4 rot = glm::rotate(glm::mat4(), 3.14159265358979f / 180.0f * angle, glm::vec3(x, y, z)); currMatrix() *= rot; if (m_coreProfileEngine) { core().rotatef(angle, x, y, z); } else { dispatcher().glRotatef(angle, x, y, z); } } void GLEScmContext::scalef(float x, float y, float z) { glm::mat4 scale = glm::scale(glm::mat4(), glm::vec3(x, y, z)); currMatrix() *= scale; if (m_coreProfileEngine) { core().scalef(x, y, z); } else { dispatcher().glScalef(x, y, z); } } void GLEScmContext::translatef(float x, float y, float z) { glm::mat4 tr = glm::translate(glm::mat4(), glm::vec3(x, y, z)); currMatrix() *= tr; if (m_coreProfileEngine) { core().translatef(x, y, z); } else { dispatcher().glTranslatef(x, y, z); } } void GLEScmContext::color4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { mColor.type = GL_FLOAT; mColor.val.floatVal[0] = red; mColor.val.floatVal[1] = green; mColor.val.floatVal[2] = blue; mColor.val.floatVal[3] = alpha; if (m_coreProfileEngine) { core().color4f(red,green,blue,alpha); } else{ dispatcher().glColor4f(red,green,blue,alpha); } } void GLEScmContext::color4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) { mColor.type = GL_UNSIGNED_BYTE; mColor.val.ubyteVal[0] = red; mColor.val.ubyteVal[1] = green; mColor.val.ubyteVal[2] = blue; mColor.val.ubyteVal[3] = alpha; if (m_coreProfileEngine) { core().color4ub(red,green,blue,alpha); } else{ dispatcher().glColor4ub(red,green,blue,alpha); } } void GLEScmContext::drawArrays(GLenum mode, GLint first, GLsizei count) { if (!isArrEnabled(GL_VERTEX_ARRAY)) return; drawValidate(); GLuint prev_vbo; GLuint prev_ibo; dispatcher().glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&prev_vbo); dispatcher().glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, (GLint*)&prev_ibo); dispatcher().glBindBuffer(GL_ARRAY_BUFFER, 0); dispatcher().glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); if (m_coreProfileEngine) { ArraysMap::iterator it; m_pointsIndex = -1; // going over all clients arrays Pointers for (it = m_currVaoState.begin(); it != m_currVaoState.end(); ++it) { GLenum array_id = (*it).first; GLESpointer* p = (*it).second; if (array_id == GL_VERTEX_ARRAY || array_id == GL_NORMAL_ARRAY || array_id == GL_COLOR_ARRAY || array_id == GL_POINT_SIZE_ARRAY_OES || array_id == GL_TEXTURE_COORD_ARRAY) { core().setupArrayForDraw(array_id, p, first, count, false, 0, nullptr); } } GLenum activeTexture = m_clientActiveTexture + GL_TEXTURE0; setClientActiveTexture(activeTexture); core().clientActiveTexture(activeTexture); core().drawArrays(mode, first, count); } else { GLESConversionArrays tmpArrs; setupArraysPointers(tmpArrs,first,count,0,NULL,true,nullptr); if (mode == GL_POINTS && isArrEnabled(GL_POINT_SIZE_ARRAY_OES)){ drawPointsArrs(tmpArrs,first,count); } else { dispatcher().glDrawArrays(mode,first,count); } } dispatcher().glBindBuffer(GL_ARRAY_BUFFER, prev_vbo); dispatcher().glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prev_ibo); } void GLEScmContext::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) { if (!isArrEnabled(GL_VERTEX_ARRAY)) return; drawValidate(); if(isBindedBuffer(GL_ELEMENT_ARRAY_BUFFER)) { // if vbo is binded take the indices from the vbo const unsigned char* buf = static_cast(getBindedBuffer(GL_ELEMENT_ARRAY_BUFFER)); indices = buf + SafeUIntFromPointer(indices); } GLuint prev_vbo; GLuint prev_ibo; dispatcher().glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&prev_vbo); dispatcher().glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, (GLint*)&prev_ibo); dispatcher().glBindBuffer(GL_ARRAY_BUFFER, 0); dispatcher().glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); if (m_coreProfileEngine) { ArraysMap::iterator it; m_pointsIndex = -1; // going over all clients arrays Pointers for (it = m_currVaoState.begin(); it != m_currVaoState.end(); ++it) { GLenum array_id = (*it).first; GLESpointer* p = (*it).second; if (array_id == GL_VERTEX_ARRAY || array_id == GL_NORMAL_ARRAY || array_id == GL_COLOR_ARRAY || array_id == GL_POINT_SIZE_ARRAY_OES || array_id == GL_TEXTURE_COORD_ARRAY) { core().setupArrayForDraw(array_id, p, 0, count, true, type, indices); } } GLenum activeTexture = m_clientActiveTexture + GL_TEXTURE0; setClientActiveTexture(activeTexture); core().clientActiveTexture(activeTexture); core().drawElements(mode, count, type, indices); } else { GLESConversionArrays tmpArrs; setupArraysPointers(tmpArrs,0,count,type,indices,false,nullptr); if(mode == GL_POINTS && isArrEnabled(GL_POINT_SIZE_ARRAY_OES)){ drawPointsElems(tmpArrs,count,type,indices); } else{ dispatcher().glDrawElements(mode,count,type,indices); } } dispatcher().glBindBuffer(GL_ARRAY_BUFFER, prev_vbo); dispatcher().glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prev_ibo); } void GLEScmContext::clientActiveTexture(GLenum texture) { setClientActiveTexture(texture); if (m_coreProfileEngine) { core().clientActiveTexture(texture); } else { dispatcher().glClientActiveTexture(texture); } }