diff --git a/ogles-readme.txt b/ogles-readme.txt new file mode 100644 index 00000000..75630f44 --- /dev/null +++ b/ogles-readme.txt @@ -0,0 +1,6 @@ +This branch is used for development of the OpenGL-ES drivers for Irrlicht. +There will be drivers for ogl-es 1.x and 2.x at some time, but we'll start +with 1.x first. Both drivers will be separate drivers, loosely based on the +OpenGL driver. +The branch is based on SVN/trunk and will be updated only very slowly. It's +not intended for regular use besides when working with ogl-es development. diff --git a/source/Irrlicht/COGLESDriver.cpp b/source/Irrlicht/COGLESDriver.cpp new file mode 100644 index 00000000..3bae7072 --- /dev/null +++ b/source/Irrlicht/COGLESDriver.cpp @@ -0,0 +1,2676 @@ +// Copyright (C) 2002-2008 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "COGLESDriver.h" +// needed here also because of the create methods' parameters +#include "CNullDriver.h" + +#ifdef _IRR_COMPILE_WITH_OGLES1_ + +#include "COpenGLTexture.h" +#include "COpenGLMaterialRenderer.h" +#include "COpenGLShaderMaterialRenderer.h" +#include "COpenGLSLMaterialRenderer.h" +#include "COpenGLNormalMapRenderer.h" +#include "COpenGLParallaxMapRenderer.h" +#include "CImage.h" +#include "os.h" + +#ifdef _IRR_USE_SDL_DEVICE_ +#include +#endif + +namespace irr +{ +namespace video +{ + + +//! constructor and init code +COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters& params, + const SExposedVideoData& data, + io::IFileSystem* io) +: CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), + CurrentRenderMode(ERM_NONE), ResetRenderStates(true), + Transformation3DChanged(true), AntiAlias(params.AntiAlias), + RenderTargetTexture(0), LastSetLight(-1), CurrentRendertargetSize(0,0), ColorFormat(ECF_R8G8B8) +{ + #ifdef _DEBUG + setDebugName("COGLESDriver"); + #endif + ExposedData=data; + EglDisplay = eglGetDisplay((NativeDisplayType)ExposedData.OpenGLLinux.X11Display); + eglInitialize(EglDisplay, NULL, NULL); + + EGLint num_configs; + EGLConfig config; + EGLint attribs[] = + { + EGL_BUFFER_SIZE, 32, + EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER, + EGL_DEPTH_SIZE, 16, + EGL_NONE, 0 + }; + eglChooseConfig(EglDisplay, attribs, &config, 1, &num_configs); + EglSurface = eglCreateWindowSurface(EglDisplay, config, (NativeWindowType)ExposedData.OpenGLLinux.X11Window, NULL); + eglBindAPI(EGL_OPENGL_ES_API); + EglContext = eglCreateContext(EglDisplay, config, EGL_NO_CONTEXT, NULL); + eglMakeCurrent(EglDisplay, EglSurface, EglSurface, EglContext); + + genericDriverInit(params.WindowSize, params.Stencilbuffer); + + // set vsync + if (params.Vsync) + eglSwapInterval(EglDisplay, 30); +} + + +//! destructor +COpenGLDriver::~COpenGLDriver() +{ + deleteMaterialRenders(); + + // I get a blue screen on my laptop, when I do not delete the + // textures manually before releasing the dc. Oh how I love this. + + deleteAllTextures(); + + eglMakeCurrent(EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroyContext(EglDisplay, EglContext); + eglDestroySurface(EglDisplay, EglSurface); + eglTerminate(EglDisplay); +} + +// ----------------------------------------------------------------------- +// METHODS +// ----------------------------------------------------------------------- + +bool COpenGLDriver::genericDriverInit(const core::dimension2d& screenSize, bool stencilBuffer) +{ + Name=L"OpenGL ES "; + Name.append(eglQueryString(EglDisplay, EGL_VERSION)); + printVersion(); + + os::Printer::log(eglQueryString(EglDisplay, EGLENSIONS)); + os::Printer::log(eglQueryString(EglDisplay, EGL_CLIENT_APIS)); + + // print renderer information + vendorName = eglQueryString(EglDisplay, EGL_VENDOR); + os::Printer::log(vendorName, ELL_INFORMATION); + + u32 i; + for (i=0; i101) || FeatureAvailable[IRR_rescale_normal]) +// glEnable(GL_RESCALE_NORMAL); + + glClearDepth(1.0); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + glDepthFunc(GL_LEQUAL); + glFrontFace( GL_CW ); + + if (AntiAlias) + { + if (MultiSamplingExtension) + glEnable(GL_MULTISAMPLE); + + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); + glEnable(GL_LINE_SMOOTH); + } +// currently disabled, because often in software, and thus very slow +// glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST); +// glEnable(GL_POINT_SMOOTH); + + UserClipPlane.reallocate(MaxUserClipPlanes); + UserClipPlaneEnabled.reallocate(MaxUserClipPlanes); + for (i=0; idrop(); + + // add remaining material renderer + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_DETAIL_MAP(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_SPHERE_MAP(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_REFLECTION_2_LAYER(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ADD_COLOR(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_VERTEX_ALPHA(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER(this)); + + // add normal map renderers + s32 tmp = 0; + video::IMaterialRenderer* renderer = 0; + renderer = new COpenGLNormalMapRenderer(this, tmp, MaterialRenderers[EMT_SOLID].Renderer); + renderer->drop(); + renderer = new COpenGLNormalMapRenderer(this, tmp, MaterialRenderers[EMT_TRANSPARENT_ADD_COLOR].Renderer); + renderer->drop(); + renderer = new COpenGLNormalMapRenderer(this, tmp, MaterialRenderers[EMT_TRANSPARENT_VERTEX_ALPHA].Renderer); + renderer->drop(); + + // add parallax map renderers + renderer = new COpenGLParallaxMapRenderer(this, tmp, MaterialRenderers[EMT_SOLID].Renderer); + renderer->drop(); + renderer = new COpenGLParallaxMapRenderer(this, tmp, MaterialRenderers[EMT_TRANSPARENT_ADD_COLOR].Renderer); + renderer->drop(); + renderer = new COpenGLParallaxMapRenderer(this, tmp, MaterialRenderers[EMT_TRANSPARENT_VERTEX_ALPHA].Renderer); + renderer->drop(); + + // add basic 1 texture blending + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_ONETEXTURE_BLEND(this)); +} + + +//! presents the rendered scene on the screen, returns false if failed +bool COpenGLDriver::endScene() +{ + CNullDriver::endScene(); + + eglSwapBuffers(EglDisplay, EglSurface); + return true; +} + + +//! clears the zbuffer +bool COpenGLDriver::beginScene(bool backBuffer, bool zBuffer, SColor color, + void* windowId, core::rect* sourceRect) +{ + CNullDriver::beginScene(backBuffer, zBuffer, color, windowId, sourceRect); + + GLbitfield mask = 0; + + if (backBuffer) + { + const f32 inv = 1.0f / 255.0f; + glClearColor(color.getRed() * inv, color.getGreen() * inv, + color.getBlue() * inv, color.getAlpha() * inv); + + mask |= GL_COLOR_BUFFER_BIT; + } + + if (zBuffer) + { + glDepthMask(GL_TRUE); + LastMaterial.ZWriteEnable=true; + mask |= GL_DEPTH_BUFFER_BIT; + } + + glClear(mask); + return true; +} + + +//! Returns the transformation set by setTransform +const core::matrix4& COpenGLDriver::getTransform(E_TRANSFORMATION_STATE state) const +{ + return Matrices[state]; +} + + +//! sets transformation +void COpenGLDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) +{ + Matrices[state] = mat; + Transformation3DChanged = true; + + switch(state) + { + case ETS_VIEW: + case ETS_WORLD: + { + // OpenGL only has a model matrix, view and world is not existent. so lets fake these two. + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf((Matrices[ETS_VIEW] * Matrices[ETS_WORLD]).pointer()); + // we have to update the clip planes to the latest view matrix + for (u32 i=0; iisRenderTarget(); + + if (MultiTextureExtension) + extGlActiveTexture(GL_TEXTURE0 + i); + + glMatrixMode(GL_TEXTURE); + if (mat.isIdentity() && !isRTT) + glLoadIdentity(); + else + { + GLfloat glmat[16]; + if (isRTT) + createGLTextureMatrix(glmat, mat * TextureFlipMatrix); + else + createGLTextureMatrix(glmat, mat); + + glLoadMatrixf(glmat); + } + break; + } + default: + break; + } +} + +bool COpenGLDriver::updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer) +{ + if (!HWBuffer) + return false; + + if (!FeatureAvailable[IRR_vertex_buffer_object]) + return false; + +#if defined(GL_vertex_buffer_object) + const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; + const void* vertices=mb->getVertices(); + const u32 vertexCount=mb->getVertexCount(); + const E_VERTEX_TYPE vType=mb->getVertexType(); + const u32 vertexSize = getVertexPitchFromType(vType); + + //buffer vertex data, and convert colours... + core::array buffer(vertexSize * vertexCount); + memcpy(buffer.pointer(), vertices, vertexSize * vertexCount); + + // in order to convert the colors into opengl format (RGBA) + switch (vType) + { + case EVT_STANDARD: + { + S3DVertex* pb = reinterpret_cast(buffer.pointer()); + const S3DVertex* po = static_cast(vertices); + for (u32 i=0; i(buffer.pointer()); + const S3DVertex2TCoords* po = static_cast(vertices); + for (u32 i=0; i(buffer.pointer()); + const S3DVertexTangents* po = static_cast(vertices); + for (u32 i=0; ivbo_verticesID) + { + extGlGenBuffers(1, &HWBuffer->vbo_verticesID); + if (!HWBuffer->vbo_verticesID) return false; + newBuffer=true; + } + else if (HWBuffer->vbo_verticesSize < vertexCount*vertexSize) + { + newBuffer=true; + } + + extGlBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID ); + + //copy data to graphics card + glGetError(); // clear error storage + if (!newBuffer) + extGlBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * vertexSize, buffer.const_pointer()); + else + { + HWBuffer->vbo_verticesSize = vertexCount*vertexSize; + + if (HWBuffer->Mapped_Vertex==scene::EHM_STATIC) + extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, buffer.const_pointer(), GL_STATIC_DRAW); + else if (HWBuffer->Mapped_Vertex==scene::EHM_DYNAMIC) + extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, buffer.const_pointer(), GL_DYNAMIC_DRAW); + else //scene::EHM_STREAM + extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, buffer.const_pointer(), GL_STREAM_DRAW); + } + + extGlBindBuffer(GL_ARRAY_BUFFER, 0); + + return (glGetError() == GL_NO_ERROR); +#else + return false; +#endif +} + + +bool COpenGLDriver::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer) +{ + if (!HWBuffer) + return false; + + if(!FeatureAvailable[IRR_vertex_buffer_object]) + return false; + +#if defined(GL_vertex_buffer_object) + const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; + + const void* indices=mb->getIndices(); + u32 indexCount= mb->getIndexCount(); + + GLenum indexSize; + switch (mb->getIndexType()) + { + case (EIT_16BIT): + { + indexSize=sizeof(u16); + break; + } + case (EIT_32BIT): + { + indexSize=sizeof(u32); + break; + } + default: + { + return false; + } + } + + + //get or create buffer + bool newBuffer=false; + if (!HWBuffer->vbo_indicesID) + { + extGlGenBuffers(1, &HWBuffer->vbo_indicesID); + if (!HWBuffer->vbo_indicesID) return false; + newBuffer=true; + } + else if (HWBuffer->vbo_indicesSize < indexCount*indexSize) + { + newBuffer=true; + } + + extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID); + + //copy data to graphics card + glGetError(); // clear error storage + if (!newBuffer) + extGlBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indexCount * indexSize, indices); + else + { + HWBuffer->vbo_indicesSize = indexCount*indexSize; + + if (HWBuffer->Mapped_Index==scene::EHM_STATIC) + extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_STATIC_DRAW); + else if (HWBuffer->Mapped_Index==scene::EHM_DYNAMIC) + extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_DYNAMIC_DRAW); + else //scene::EHM_STREAM + extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_STREAM_DRAW); + } + + extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + return (glGetError() == GL_NO_ERROR); +#else + return false; +#endif +} + + +//! updates hardware buffer if needed +bool COpenGLDriver::updateHardwareBuffer(SHWBufferLink *HWBuffer) +{ + if (!HWBuffer) + return false; + + if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER) + { + if (HWBuffer->ChangedID_Vertex != HWBuffer->MeshBuffer->getChangedID_Vertex() + || !((SHWBufferLink_opengl*)HWBuffer)->vbo_verticesID) + { + + HWBuffer->ChangedID_Vertex = HWBuffer->MeshBuffer->getChangedID_Vertex(); + + if (!updateVertexHardwareBuffer((SHWBufferLink_opengl*)HWBuffer)) + return false; + } + } + + if (HWBuffer->Mapped_Index!=scene::EHM_NEVER) + { + if (HWBuffer->ChangedID_Index != HWBuffer->MeshBuffer->getChangedID_Index() + || !((SHWBufferLink_opengl*)HWBuffer)->vbo_indicesID) + { + + HWBuffer->ChangedID_Index = HWBuffer->MeshBuffer->getChangedID_Index(); + + if (!updateIndexHardwareBuffer((SHWBufferLink_opengl*)HWBuffer)) + return false; + } + } + + return true; +} + + +//! Create hardware buffer from meshbuffer +COpenGLDriver::SHWBufferLink *COpenGLDriver::createHardwareBuffer(const scene::IMeshBuffer* mb) +{ +#if defined(GL_vertex_buffer_object) + if (!mb || (mb->getHardwareMappingHint_Index()==scene::EHM_NEVER && mb->getHardwareMappingHint_Vertex()==scene::EHM_NEVER)) + return 0; + + SHWBufferLink_opengl *HWBuffer=new SHWBufferLink_opengl(mb); + + //add to map + HWBufferMap.insert(HWBuffer->MeshBuffer, HWBuffer); + + HWBuffer->ChangedID_Vertex=HWBuffer->MeshBuffer->getChangedID_Vertex(); + HWBuffer->ChangedID_Index=HWBuffer->MeshBuffer->getChangedID_Index(); + HWBuffer->Mapped_Vertex=mb->getHardwareMappingHint_Vertex(); + HWBuffer->Mapped_Index=mb->getHardwareMappingHint_Index(); + HWBuffer->LastUsed=0; + HWBuffer->vbo_verticesID=0; + HWBuffer->vbo_indicesID=0; + HWBuffer->vbo_verticesSize=0; + HWBuffer->vbo_indicesSize=0; + + if (!updateHardwareBuffer(HWBuffer)) + { + deleteHardwareBuffer(HWBuffer); + return 0; + } + + return HWBuffer; +#else + return 0; +#endif +} + + +void COpenGLDriver::deleteHardwareBuffer(SHWBufferLink *_HWBuffer) +{ + if (!_HWBuffer) return; + + +#if defined(GL_vertex_buffer_object) + SHWBufferLink_opengl *HWBuffer=(SHWBufferLink_opengl*)_HWBuffer; + if (HWBuffer->vbo_verticesID) + { + extGlDeleteBuffers(1, &HWBuffer->vbo_verticesID); + HWBuffer->vbo_verticesID=0; + } + if (HWBuffer->vbo_indicesID) + { + extGlDeleteBuffers(1, &HWBuffer->vbo_indicesID); + HWBuffer->vbo_indicesID=0; + } +#endif + + CNullDriver::deleteHardwareBuffer(_HWBuffer); + +} + + +//! Draw hardware buffer +void COpenGLDriver::drawHardwareBuffer(SHWBufferLink *_HWBuffer) +{ + if (!_HWBuffer) + return; + + SHWBufferLink_opengl *HWBuffer=(SHWBufferLink_opengl*)_HWBuffer; + + updateHardwareBuffer(HWBuffer); //check if update is needed + + HWBuffer->LastUsed=0;//reset count + +#if defined(GL_vertex_buffer_object) + const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; + + + const void *vertices=mb->getVertices(); + const void *indexList=mb->getIndices(); + + if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER) + { + extGlBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID); + vertices=0; + } + + if (HWBuffer->Mapped_Index!=scene::EHM_NEVER) + { + extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID); + indexList=0; + } + + + drawVertexPrimitiveList(vertices, mb->getVertexCount(), indexList, mb->getIndexCount()/3, mb->getVertexType(), scene::EPT_TRIANGLES, mb->getIndexType()); + + if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER) + extGlBindBuffer(GL_ARRAY_BUFFER, 0); + + if (HWBuffer->Mapped_Index!=scene::EHM_NEVER) + extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + + +#endif +} + + +// small helper function to create vertex buffer object adress offsets +static inline u8* buffer_offset(const long offset) +{ + return ((u8*)0 + offset); +} + + +//! draws a vertex primitive list +void COpenGLDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) +{ + if (!checkPrimitiveCount(primitiveCount)) + return; + + setRenderStates3DMode(); + + drawVertexPrimitiveList2d3d(vertices, vertexCount, indexList, primitiveCount, vType, pType, true); +} + + +void COpenGLDriver::drawVertexPrimitiveList2d3d(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType, bool threed) +{ + if (!primitiveCount || !vertexCount) + return; + + if (!threed && !checkPrimitiveCount(primitiveCount)) + return; + + CNullDriver::drawVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType); + + if (vertices) + { + // convert colors to gl color format. + vertexCount *= 4; //reused as color component count + ColorBuffer.set_used(vertexCount); + u32 i; + + switch (vType) + { + case EVT_STANDARD: + { + const S3DVertex* p = static_cast(vertices); + for ( i=0; iColor.toOpenGLColor(&ColorBuffer[i]); + ++p; + } + } + break; + case EVT_2TCOORDS: + { + const S3DVertex2TCoords* p = static_cast(vertices); + for ( i=0; iColor.toOpenGLColor(&ColorBuffer[i]); + ++p; + } + } + break; + case EVT_TANGENTS: + { + const S3DVertexTangents* p = static_cast(vertices); + for ( i=0; iColor.toOpenGLColor(&ColorBuffer[i]); + ++p; + } + } + break; + } + } + + // draw everything + + if (MultiTextureExtension) + extGlClientActiveTexture(GL_TEXTURE0); + + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + if ((pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES)) + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (threed && (pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES)) + glEnableClientState(GL_NORMAL_ARRAY); + + if (vertices) + glColorPointer(4, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); + + switch (vType) + { + case EVT_STANDARD: + if (vertices) + { + if (threed) + glNormalPointer(GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].Normal); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].TCoords); + glVertexPointer((threed?3:2), GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].Pos); + } + // TODO ogles + else + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertex), buffer_offset(12)); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(S3DVertex), buffer_offset(24)); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28)); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), 0); + } + + if (MultiTextureExtension && CurrentTexture[1]) + { + extGlClientActiveTexture(GL_TEXTURE1); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (vertices) + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].TCoords); + else + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28)); + } + break; + case EVT_2TCOORDS: + if (vertices) + { + if (threed) + glNormalPointer(GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Normal); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].TCoords); + glVertexPointer((threed?3:2), GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Pos); + } + else + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(12)); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), buffer_offset(24)); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(28)); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(0)); + } + + + if (MultiTextureExtension) + { + extGlClientActiveTexture(GL_TEXTURE1); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (vertices) + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].TCoords2); + else + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(36)); + } + break; + case EVT_TANGENTS: + if (vertices) + { + if (threed) + glNormalPointer(GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Normal); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].TCoords); + glVertexPointer((threed?3:2), GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Pos); + } + else + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(12)); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), buffer_offset(24)); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(28)); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(0)); + } + + if (MultiTextureExtension) + { + extGlClientActiveTexture(GL_TEXTURE1); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (vertices) + glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Tangent); + else + glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(36)); + + extGlClientActiveTexture(GL_TEXTURE2); + glEnableClientState ( GL_TEXTURE_COORD_ARRAY ); + if (vertices) + glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Binormal); + else + glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(48)); + } + break; + } + + GLenum indexSize=0; + + switch (iType) + { + case (EIT_16BIT): + { + indexSize=GL_UNSIGNED_SHORT; + break; + } + case (EIT_32BIT): + { + indexSize=GL_UNSIGNED_INT; + break; + } + } + + switch (pType) + { + case scene::EPT_POINTS: + case scene::EPT_POINT_SPRITES: + { +#ifdef GL_point_sprite + if (pType==scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_point_sprite]) + glEnable(GL_POINT_SPRITE); +#endif + float quadratic[] = {0.0f, 0.0f, 10.01f}; + extGlPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, quadratic); + float maxParticleSize=1.0f; + glGetFloatv(GL_POINT_SIZE_MAX, &maxParticleSize); +// maxParticleSize=maxParticleSize& pos, + const core::rect& sourceRect, + const core::rect* clipRect, SColor color, + bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + if (!sourceRect.isValid()) + return; + + core::position2d targetPos(pos); + core::position2d sourcePos(sourceRect.UpperLeftCorner); + core::dimension2d sourceSize(sourceRect.getSize()); + if (clipRect) + { + if (targetPos.X < clipRect->UpperLeftCorner.X) + { + sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X; + if (sourceSize.Width <= 0) + return; + + sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X; + targetPos.X = clipRect->UpperLeftCorner.X; + } + + if (targetPos.X + sourceSize.Width > clipRect->LowerRightCorner.X) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X; + if (sourceSize.Width <= 0) + return; + } + + if (targetPos.Y < clipRect->UpperLeftCorner.Y) + { + sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y; + if (sourceSize.Height <= 0) + return; + + sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y; + targetPos.Y = clipRect->UpperLeftCorner.Y; + } + + if (targetPos.Y + sourceSize.Height > clipRect->LowerRightCorner.Y) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y; + if (sourceSize.Height <= 0) + return; + } + } + + // clip these coordinates + + if (targetPos.X<0) + { + sourceSize.Width += targetPos.X; + if (sourceSize.Width <= 0) + return; + + sourcePos.X -= targetPos.X; + targetPos.X = 0; + } + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + if (targetPos.X + sourceSize.Width > renderTargetSize.Width) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width; + if (sourceSize.Width <= 0) + return; + } + + if (targetPos.Y<0) + { + sourceSize.Height += targetPos.Y; + if (sourceSize.Height <= 0) + return; + + sourcePos.Y -= targetPos.Y; + targetPos.Y = 0; + } + + if (targetPos.Y + sourceSize.Height > renderTargetSize.Height) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height; + if (sourceSize.Height <= 0) + return; + } + + // ok, we've clipped everything. + // now draw it. + + // texcoords need to be flipped horizontally for RTTs + const bool isRTT = texture->isRenderTarget(); + const core::dimension2d& ss = texture->getOriginalSize(); + const f32 invW = 1.f / static_cast(ss.Width); + const f32 invH = 1.f / static_cast(ss.Height); + const core::rect tcoords( + sourcePos.X * invW, + (isRTT?(sourcePos.Y + sourceSize.Height):sourcePos.Y) * invH, + (sourcePos.X + sourceSize.Width) * invW, + (isRTT?sourcePos.Y:(sourcePos.Y + sourceSize.Height)) * invH); + + const core::rect poss(targetPos, sourceSize); + + disableTextures(1); + if (!setTexture(0, texture)) + return; + setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); + + u16 indices[] = {0,1,2,3}; + S3DVertex vertices[4]; + vertices[0] = S3DVertex(poss.UpperLeftCorner.X, poss.UpperLeftCorner.Y, 0, 0,0,1, color, tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); + vertices[1] = S3DVertex(poss.LowerRightCorner.X, poss.UpperLeftCorner.Y, 0, 0,0,1, color, tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); + vertices[2] = S3DVertex(poss.LowerRightCorner.X, poss.LowerRightCorner.Y, 0, 0,0,1, color, tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); + vertices[3] = S3DVertex(poss.UpperLeftCorner.X, poss.LowerRightCorner.Y, 0, 0,0,1, color, tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); + drawVertexPrimitiveList2d3d(vertices, 4, indices, 2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN, false); +} + + +//! The same, but with a four element array of colors, one for each vertex +void COpenGLDriver::draw2DImage(const video::ITexture* texture, const core::rect& destRect, + const core::rect& sourceRect, const core::rect* clipRect, + const video::SColor* const colors, bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + // texcoords need to be flipped horizontally for RTTs + const bool isRTT = texture->isRenderTarget(); + const core::dimension2d& ss = texture->getOriginalSize(); + const f32 invW = 1.f / static_cast(ss.Width); + const f32 invH = 1.f / static_cast(ss.Height); + const core::rect tcoords( + sourceRect.UpperLeftCorner.X * invW, + (isRTT?sourceRect.LowerRightCorner.Y:sourceRect.UpperLeftCorner.Y) * invH, + sourceRect.LowerRightCorner.X * invW, + (isRTT?sourceRect.UpperLeftCorner.Y:sourceRect.LowerRightCorner.Y) *invH); + + const video::SColor temp[4] = + { + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF + }; + + const video::SColor* const useColor = colors ? colors : temp; + + disableTextures(1); + setTexture(0, texture); + setRenderStates2DMode(useColor[0].getAlpha()<255 || useColor[1].getAlpha()<255 || + useColor[2].getAlpha()<255 || useColor[3].getAlpha()<255, + true, useAlphaChannelOfTexture); + + if (clipRect) + { + if (!clipRect->isValid()) + return; + + glEnable(GL_SCISSOR_TEST); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height-clipRect->LowerRightCorner.Y, + clipRect->getWidth(), clipRect->getHeight()); + } + + u16 indices[] = {0,1,2,3}; + S3DVertex vertices[4]; + vertices[0] = S3DVertex(destRect.UpperLeftCorner.X, destRect.UpperLeftCorner.Y, 0, 0,0,1, useColor[0], tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); + vertices[1] = S3DVertex(destRect.LowerRightCorner.X, destRect.UpperLeftCorner.Y, 0, 0,0,1, useColor[3], tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); + vertices[2] = S3DVertex(destRect.LowerRightCorner.X, destRect.LowerRightCorner.Y, 0, 0,0,1, useColor[2], tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); + vertices[3] = S3DVertex(destRect.UpperLeftCorner.X, destRect.LowerRightCorner.Y, 0, 0,0,1, useColor[1], tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); + drawVertexPrimitiveList2d3d(vertices, 4, indices, 2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN, false); + + if (clipRect) + glDisable(GL_SCISSOR_TEST); +} + + +//! draws a set of 2d images, using a color and the alpha channel of the +//! texture if desired. The images are drawn beginning at pos and concatenated +//! in one line. All drawings are clipped against clipRect (if != 0). +//! The subtextures are defined by the array of sourceRects and are chosen +//! by the indices given. +void COpenGLDriver::draw2DImage(const video::ITexture* texture, + const core::position2d& pos, + const core::array >& sourceRects, + const core::array& indices, + const core::rect* clipRect, SColor color, + bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + disableTextures(1); + if (!setTexture(0, texture)) + return; + setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); + + if (clipRect) + { + if (!clipRect->isValid()) + return; + + glEnable(GL_SCISSOR_TEST); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height-clipRect->LowerRightCorner.Y, + clipRect->getWidth(),clipRect->getHeight()); + } + + const core::dimension2d& ss = texture->getOriginalSize(); + core::position2d targetPos(pos); + // texcoords need to be flipped horizontally for RTTs + const bool isRTT = texture->isRenderTarget(); + const f32 invW = 1.f / static_cast(ss.Width); + const f32 invH = 1.f / static_cast(ss.Height); + + core::array vertices; + core::array quadIndices; + vertices.reallocate(indices.size()*4); + quadIndices.reallocate(indices.size()*3); + for (u32 i=0; i tcoords( + sourceRects[currentIndex].UpperLeftCorner.X * invW, + (isRTT?sourceRects[currentIndex].LowerRightCorner.Y:sourceRects[currentIndex].UpperLeftCorner.Y) * invH, + sourceRects[currentIndex].LowerRightCorner.X * invW, + (isRTT?sourceRects[currentIndex].UpperLeftCorner.Y:sourceRects[currentIndex].LowerRightCorner.Y) * invH); + + const core::rect poss(targetPos, sourceRects[currentIndex].getSize()); + + vertices.push_back(S3DVertex(poss.UpperLeftCorner.X, poss.UpperLeftCorner.Y, 0, 0,0,1, color, tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y)); + vertices.push_back(S3DVertex(poss.LowerRightCorner.X, poss.UpperLeftCorner.Y, 0, 0,0,1, color, tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y)); + vertices.push_back(S3DVertex(poss.LowerRightCorner.X, poss.LowerRightCorner.Y, 0, 0,0,1, color, tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y)); + vertices.push_back(S3DVertex(poss.UpperLeftCorner.X, poss.LowerRightCorner.Y, 0, 0,0,1, color, tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y)); + + targetPos.X += sourceRects[currentIndex].getWidth(); + } + drawVertexPrimitiveList2d3d(vertices.pointer(), 4, quadIndices.pointer(), 2*indices.size(), video::EVT_STANDARD, scene::EPT_TRIANGLES, false); + if (clipRect) + glDisable(GL_SCISSOR_TEST); +} + + +//! draw a 2d rectangle +void COpenGLDriver::draw2DRectangle(SColor color, const core::rect& position, + const core::rect* clip) +{ + disableTextures(); + setRenderStates2DMode(color.getAlpha() < 255, false, false); + + core::rect pos = position; + + if (clip) + pos.clipAgainst(*clip); + + if (!pos.isValid()) + return; + + u16 indices[] = {0,1,2,3}; + S3DVertex vertices[4]; + vertices[0] = S3DVertex(pos.UpperLeftCorner.X, pos.UpperLeftCorner.Y, 0, 0,0,1, color, 0,0); + vertices[1] = S3DVertex(pos.LowerRightCorner.X, pos.UpperLeftCorner.Y, 0, 0,0,1, color, 0,0); + vertices[2] = S3DVertex(pos.LowerRightCorner.X, pos.LowerRightCorner.Y, 0, 0,0,1, color, 0,0); + vertices[3] = S3DVertex(pos.UpperLeftCorner.X, pos.LowerRightCorner.Y, 0, 0,0,1, color, 0,0); + drawVertexPrimitiveList2d3d(vertices, 4, indices, 2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN, false); +} + + +//! draw an 2d rectangle +void COpenGLDriver::draw2DRectangle(const core::rect& position, + SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown, + const core::rect* clip) +{ + core::rect pos = position; + + if (clip) + pos.clipAgainst(*clip); + + if (!pos.isValid()) + return; + + disableTextures(); + + setRenderStates2DMode(colorLeftUp.getAlpha() < 255 || + colorRightUp.getAlpha() < 255 || + colorLeftDown.getAlpha() < 255 || + colorRightDown.getAlpha() < 255, false, false); + + u16 indices[] = {0,1,2,3}; + S3DVertex vertices[4]; + vertices[0] = S3DVertex(pos.UpperLeftCorner.X, pos.UpperLeftCorner.Y, 0, 0,0,1, colorLeftUp, 0,0); + vertices[1] = S3DVertex(pos.LowerRightCorner.X, pos.UpperLeftCorner.Y, 0, 0,0,1, colorRightUp, 0,0); + vertices[2] = S3DVertex(pos.LowerRightCorner.X, pos.LowerRightCorner.Y, 0, 0,0,1, colorRightDown, 0,0); + vertices[3] = S3DVertex(pos.UpperLeftCorner.X, pos.LowerRightCorner.Y, 0, 0,0,1, colorLeftDown, 0,0); + drawVertexPrimitiveList2d3d(vertices, 4, indices, 2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN, false); +} + + +//! Draws a 2d line. +void COpenGLDriver::draw2DLine(const core::position2d& start, + const core::position2d& end, + SColor color) +{ + disableTextures(); + setRenderStates2DMode(color.getAlpha() < 255, false, false); + + u16 indices[] = {0,1}; + S3DVertex vertices[2]; + vertices[0] = S3DVertex(start.X, start.Y, 0, 0,0,1, color, 0,0); + vertices[1] = S3DVertex(end.X, end.Y, 0, 0,0,1, color, 0,0); + drawVertexPrimitiveList2d3d(vertices, 2, indices, 1, video::EVT_STANDARD, scene::EPT_LINES, false); +} + + + +bool COpenGLDriver::setTexture(u32 stage, const video::ITexture* texture) +{ + if (stage >= MaxTextureUnits) + return false; + + if (CurrentTexture[stage]==texture) + return true; + + if (MultiTextureExtension) + extGlActiveTexture(GL_TEXTURE0 + stage); + + CurrentTexture[stage]=texture; + + if (!texture) + { + glDisable(GL_TEXTURE_2D); + return true; + } + else + { + if (texture->getDriverType() != EDT_OGLES1) + { + glDisable(GL_TEXTURE_2D); + os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR); + return false; + } + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, + static_cast(texture)->getOpenGLTextureName()); + } + return true; +} + + +//! disables all textures beginning with the optional fromStage parameter. Otherwise all texture stages are disabled. +//! Returns whether disabling was successful or not. +bool COpenGLDriver::disableTextures(u32 fromStage) +{ + bool result=true; + for (u32 i=fromStage; i= 0; --i) + { + setTransform ((E_TRANSFORMATION_STATE) ( ETS_TEXTURE_0 + i ), + material.getTextureMatrix(i)); + } +} + + +//! prints error if an error happened. +bool COpenGLDriver::testGLError() +{ +#ifdef _DEBUG + GLenum g = glGetError(); + switch(g) + { + case GL_NO_ERROR: + return false; + case GL_INVALID_ENUM: + os::Printer::log("GL_INVALID_ENUM", ELL_ERROR); break; + case GL_INVALID_VALUE: + os::Printer::log("GL_INVALID_VALUE", ELL_ERROR); break; + case GL_INVALID_OPERATION: + os::Printer::log("GL_INVALID_OPERATION", ELL_ERROR); break; + case GL_STACK_OVERFLOW: + os::Printer::log("GL_STACK_OVERFLOW", ELL_ERROR); break; + case GL_STACK_UNDERFLOW: + os::Printer::log("GL_STACK_UNDERFLOW", ELL_ERROR); break; + case GL_OUT_OF_MEMORY: + os::Printer::log("GL_OUT_OF_MEMORY", ELL_ERROR); break; +#if defined(GL_framebuffer_object) + case GL_INVALID_FRAMEBUFFER_OPERATION: + os::Printer::log("GL_INVALID_FRAMEBUFFER_OPERATION", ELL_ERROR); break; +#endif + }; + return true; +#else + return false; +#endif +} + + +bool COpenGLDriver::testEGLError() +{ +#ifdef _DEBUG + EGLint g = eglGetError(); + switch (g) + { + case EGL_SUCCESS: return false; + case EGL_NOT_INITIALIZED : + os::Printer::log("Not Initialized", ELL_ERROR); break; + case EGL_BAD_ACCESS: + os::Printer::log("Bad Access", ELL_ERROR); break; + case EGL_BAD_ALLOC: + os::Printer::log("Bad Alloc", ELL_ERROR); break; + case EGL_BAD_ATTRIBUTE: + os::Printer::log("Bad Attribute", ELL_ERROR); break; + case EGL_BAD_CONTEXT: + os::Printer::log("Bad Context", ELL_ERROR); break; + case EGL_BAD_CONFIG: + os::Printer::log("Bad Config", ELL_ERROR); break; + case EGL_BAD_CURRENT_SURFACE: + os::Printer::log("Bad Current Surface", ELL_ERROR); break; + case EGL_BAD_DISPLAY: + os::Printer::log("Bad Display", ELL_ERROR); break; + case EGL_BAD_SURFACE: + os::Printer::log("Bad Surface", ELL_ERROR); break; + case EGL_BAD_MATCH: + os::Printer::log("Bad Match", ELL_ERROR); break; + case EGL_BAD_PARAMETER: + os::Printer::log("Bad Parameter", ELL_ERROR); break; + case EGL_BAD_NATIVE_PIXMAP: + os::Printer::log("Bad Native Pixmap", ELL_ERROR); break; + case EGL_BAD_NATIVE_WINDOW: + os::Printer::log("Bad Native Window", ELL_ERROR); break; + case EGL_CONTEXT_LOST: + os::Printer::log("Context Lost", ELL_ERROR); break; + }; + return true; +#else + return false; +#endif +} + + +//! sets the needed renderstates +void COpenGLDriver::setRenderStates3DMode() +{ + if (CurrentRenderMode != ERM_3D) + { + // Reset Texture Stages + glDisable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); + + // switch back the matrices + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf((Matrices[ETS_VIEW] * Matrices[ETS_WORLD]).pointer()); + + GLfloat glmat[16]; + createGLMatrix(glmat, Matrices[ETS_PROJECTION]); + glmat[12] *= -1.0f; + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(glmat); + + ResetRenderStates = true; + } + + if ( ResetRenderStates || LastMaterial != Material) + { + // unset old material + + if (LastMaterial.MaterialType != Material.MaterialType && + static_cast(LastMaterial.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial(); + + // set new material. + if (static_cast(Material.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[Material.MaterialType].Renderer->OnSetMaterial( + Material, LastMaterial, ResetRenderStates, this); + + LastMaterial = Material; + ResetRenderStates = false; + } + + if (static_cast(Material.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[Material.MaterialType].Renderer->OnRender(this, video::EVT_STANDARD); + + CurrentRenderMode = ERM_3D; +} + + +void COpenGLDriver::setWrapMode(const SMaterial& material) +{ + // texture address mode + // Has to be checked always because it depends on the textures + for (u32 u=0; u0) + break; // stop loop + + GLint mode=GL_REPEAT; + switch (material.TextureLayer[u].TextureWrap) + { + case ETC_REPEAT: + mode=GL_REPEAT; + break; + case ETC_CLAMP: + mode=GL_CLAMP; + break; + case ETC_CLAMP_TO_EDGE: +#ifdef GL_VERSION_1_2 + if (Version>101) + mode=GL_CLAMP_TO_EDGE; + else +#endif +#ifdef GL_SGIS_texture_edge_clamp + if (FeatureAvailable[IRR_SGIS_texture_edge_clamp]) + mode=GL_CLAMP_TO_EDGE_SGIS; + else +#endif + // fallback + mode=GL_CLAMP; + break; + case ETC_CLAMP_TO_BORDER: +#ifdef GL_VERSION_1_3 + if (Version>102) + mode=GL_CLAMP_TO_BORDER; + else +#endif +#ifdef GL_texture_border_clamp + if (FeatureAvailable[IRR_texture_border_clamp]) + mode=GL_CLAMP_TO_BORDER; + else +#endif +#ifdef GL_SGIS_texture_border_clamp + if (FeatureAvailable[IRR_SGIS_texture_border_clamp]) + mode=GL_CLAMP_TO_BORDER_SGIS; + else +#endif + // fallback + mode=GL_CLAMP; + break; + case ETC_MIRROR: +#ifdef GL_VERSION_1_4 + if (Version>103) + mode=GL_MIRRORED_REPEAT; + else +#endif +#ifdef GL_texture_border_clamp + if (FeatureAvailable[IRR_texture_mirrored_repeat]) + mode=GL_MIRRORED_REPEAT; + else +#endif +#ifdef GL_IBM_texture_mirrored_repeat + if (FeatureAvailable[IRR_IBM_texture_mirrored_repeat]) + mode=GL_MIRRORED_REPEAT_IBM; + else +#endif + mode=GL_REPEAT; + break; + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mode); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mode); + } +} + + +//! Can be called by an IMaterialRenderer to make its work easier. +void COpenGLDriver::setBasicRenderStates(const SMaterial& material, const SMaterial& lastmaterial, + bool resetAllRenderStates) +{ + if (resetAllRenderStates || + lastmaterial.AmbientColor != material.AmbientColor || + lastmaterial.DiffuseColor != material.DiffuseColor || + lastmaterial.SpecularColor != material.SpecularColor || + lastmaterial.EmissiveColor != material.EmissiveColor || + lastmaterial.Shininess != material.Shininess) + { + GLfloat color[4]; + + const f32 inv = 1.0f / 255.0f; + + color[0] = material.AmbientColor.getRed() * inv; + color[1] = material.AmbientColor.getGreen() * inv; + color[2] = material.AmbientColor.getBlue() * inv; + color[3] = material.AmbientColor.getAlpha() * inv; + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color); + + color[0] = material.DiffuseColor.getRed() * inv; + color[1] = material.DiffuseColor.getGreen() * inv; + color[2] = material.DiffuseColor.getBlue() * inv; + color[3] = material.DiffuseColor.getAlpha() * inv; + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color); + + // disable Specular colors if no shininess is set + if (material.Shininess != 0.0f) + { +#ifdef GL_separate_specular_color + if (FeatureAvailable[IRR_separate_specular_color]) + glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); +#endif + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material.Shininess); + color[0] = material.SpecularColor.getRed() * inv; + color[1] = material.SpecularColor.getGreen() * inv; + color[2] = material.SpecularColor.getBlue() * inv; + color[3] = material.SpecularColor.getAlpha() * inv; + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color); + } +#ifdef GL_separate_specular_color + else + if (FeatureAvailable[IRR_separate_specular_color]) + glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR); +#endif + + color[0] = material.EmissiveColor.getRed() * inv; + color[1] = material.EmissiveColor.getGreen() * inv; + color[2] = material.EmissiveColor.getBlue() * inv; + color[3] = material.EmissiveColor.getAlpha() * inv; + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, color); + } + + // Texture filter + // Has to be checked always because it depends on the textures + // Filtering has to be set for each texture layer + for (u32 i=0; i0) + break; + + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST); + + if (material.getTexture(i) && material.getTexture(i)->hasMipMaps()) + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + material.TextureLayer[i].TrilinearFilter ? GL_LINEAR_MIPMAP_LINEAR : + material.TextureLayer[i].BilinearFilter ? GL_LINEAR_MIPMAP_NEAREST : + GL_NEAREST_MIPMAP_NEAREST ); + else + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST); + +#ifdef GL_texture_filter_anisotropic + if (AnisotropyExtension) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, + material.TextureLayer[i].AnisotropicFilter ? MaxAnisotropy : 1.0f ); +#endif + } + + // TODO ogles + // fillmode +// if (resetAllRenderStates || (lastmaterial.Wireframe != material.Wireframe) || (lastmaterial.PointCloud != material.PointCloud)) +// glPolygonMode(GL_FRONT_AND_BACK, material.Wireframe ? GL_LINE : material.PointCloud? GL_POINT : GL_FILL); + + // shademode + if (resetAllRenderStates || (lastmaterial.GouraudShading != material.GouraudShading)) + { + if (material.GouraudShading) + glShadeModel(GL_SMOOTH); + else + glShadeModel(GL_FLAT); + } + + // lighting + if (resetAllRenderStates || (lastmaterial.Lighting != material.Lighting)) + { + if (material.Lighting) + glEnable(GL_LIGHTING); + else + glDisable(GL_LIGHTING); + } + + // zbuffer + if (resetAllRenderStates || lastmaterial.ZBuffer != material.ZBuffer) + { + switch (material.ZBuffer) + { + case 0: + glDisable(GL_DEPTH_TEST); + break; + case 1: + glEnable(GL_DEPTH_TEST); + glDepthFunc ( GL_LEQUAL ); + break; + case 2: + glEnable(GL_DEPTH_TEST); + glDepthFunc ( GL_EQUAL ); + break; + } + } + + // zwrite +// if (resetAllRenderStates || lastmaterial.ZWriteEnable != material.ZWriteEnable) + { + if (material.ZWriteEnable && (AllowZWriteOnTransparent || !material.isTransparent())) + { + glDepthMask(GL_TRUE); + } + else + glDepthMask(GL_FALSE); + } + + // back face culling + if (resetAllRenderStates || (lastmaterial.FrontfaceCulling != material.FrontfaceCulling) || (lastmaterial.BackfaceCulling != material.BackfaceCulling)) + { + if ((material.FrontfaceCulling) && (material.BackfaceCulling)) + { + glCullFace(GL_FRONT_AND_BACK); + glEnable(GL_CULL_FACE); + } + else + if (material.BackfaceCulling) + { + glCullFace(GL_BACK); + glEnable(GL_CULL_FACE); + } + else + if (material.FrontfaceCulling) + { + glCullFace(GL_FRONT); + glEnable(GL_CULL_FACE); + } + else + glDisable(GL_CULL_FACE); + } + + // fog + if (resetAllRenderStates || lastmaterial.FogEnable != material.FogEnable) + { + if (material.FogEnable) + glEnable(GL_FOG); + else + glDisable(GL_FOG); + } + + // normalization + if (resetAllRenderStates || lastmaterial.NormalizeNormals != material.NormalizeNormals) + { + if (material.NormalizeNormals) + glEnable(GL_NORMALIZE); + else + glDisable(GL_NORMALIZE); + } + + // thickness + if (resetAllRenderStates || lastmaterial.Thickness != material.Thickness) + { + glPointSize(material.Thickness); + glLineWidth(material.Thickness); + } + + setWrapMode(material); + + // be sure to leave in texture stage 0 + if (MultiTextureExtension) + extGlActiveTexture(GL_TEXTURE0); +} + + +//! sets the needed renderstates +void COpenGLDriver::setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel) +{ + if (CurrentRenderMode != ERM_2D || Transformation3DChanged) + { + // unset last 3d material + if (CurrentRenderMode == ERM_3D) + { + if (static_cast(LastMaterial.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial(); + SMaterial mat; + mat.ZBuffer=0; + mat.Lighting=false; + mat.TextureLayer[0].BilinearFilter=false; + setBasicRenderStates(mat, mat, true); + LastMaterial = mat; + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + glMatrixMode(GL_PROJECTION); + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + core::matrix4 m; + m.buildProjectionMatrixOrthoLH(f32(renderTargetSize.Width), f32(-renderTargetSize.Height), -1.0, 1.0); + m.setTranslation(core::vector3df(-1,1,0)); + glLoadMatrixf(m.pointer()); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0.375, 0.375, 0.0); + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + + Transformation3DChanged = false; + } + + if (alphaChannel || alpha) + { + glEnable(GL_BLEND); + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GREATER, 0.f); + } + else + { + glDisable(GL_BLEND); + glDisable(GL_ALPHA_TEST); + } + + if (texture) + { + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + if (alphaChannel) + { + // if alpha and alpha texture just modulate, otherwise use only the alpha channel + if (alpha) + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + else + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE); + // rgb always modulates + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR); + } + } + else + { + if (alpha) + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PRIMARY_COLOR); + // rgb always modulates + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR); + } + else + { + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + } + } + + CurrentRenderMode = ERM_2D; +} + + +//! \return Returns the name of the video driver. +const wchar_t* COpenGLDriver::getName() const +{ + return Name.c_str(); +} + + +//! deletes all dynamic lights there are +void COpenGLDriver::deleteAllDynamicLights() +{ + for (s32 i=0; i& area) +{ + core::rect vp = area; + core::rect rendert(0,0, getCurrentRenderTargetSize().Width, getCurrentRenderTargetSize().Height); + vp.clipAgainst(rendert); + + if (vp.getHeight()>0 && vp.getWidth()>0) + glViewport(vp.UpperLeftCorner.X, + getCurrentRenderTargetSize().Height - vp.UpperLeftCorner.Y - vp.getHeight(), + vp.getWidth(), vp.getHeight()); + + ViewPort = vp; +} + + +//! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do +//! this: First, draw all geometry. Then use this method, to draw the shadow +//! volume. Next use IVideoDriver::drawStencilShadow() to visualize the shadow. +void COpenGLDriver::drawStencilShadowVolume(const core::vector3df* triangles, s32 count, bool zfail) +{ + if (!StencilBuffer || !count) + return; + + // unset last 3d material + if (CurrentRenderMode == ERM_3D && + static_cast(Material.MaterialType) < MaterialRenderers.size()) + { + MaterialRenderers[Material.MaterialType].Renderer->OnUnsetMaterial(); + ResetRenderStates = true; + } + + // store current OpenGL state + const bool lightingEnabled = glIsEnabled(GL_LIGHTING); + const bool fogEnabled = glIsEnabled(GL_FOG); + const bool cullFaceEnabled = glIsEnabled(GL_CULL_FACE); + GLint cullFaceMode; + glGetIntegerv(GL_CULL_FACE_MODE, &cullFaceMode); + GLint depthFunc; + glGetIntegerv(GL_DEPTH_FUNC, &depthFunc); + GLboolean depthMask; + glGetBooleanv(GL_DEPTH_WRITEMASK, &depthMask); + + glDisable(GL_LIGHTING); + glDisable(GL_FOG); + glDepthFunc(GL_LEQUAL); + glDepthMask(GL_FALSE); // no depth buffer writing + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); // no color buffer drawing + glEnable(GL_STENCIL_TEST); + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(0.0f, 1.0f); + + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3,GL_FLOAT,sizeof(core::vector3df),&triangles[0]); + glStencilMask(~0); + glStencilFunc(GL_ALWAYS, 0, ~0); + + // The first parts are not correctly working, yet. +#if 0 +#ifdef GL_stencil_two_side + if (FeatureAvailable[IRR_stencil_two_side]) + { + glEnable(GL_STENCIL_TEST_TWO_SIDE); +#ifdef GL_NV_depth_clamp + if (FeatureAvailable[IRR_NV_depth_clamp]) + glEnable(GL_DEPTH_CLAMP_NV); +#endif + glDisable(GL_CULL_FACE); + if (!zfail) + { + // ZPASS Method + + extGlActiveStencilFace(GL_BACK); + if (FeatureAvailable[IRR_stencil_wrap]) + glStencilOp(GL_KEEP, GL_KEEP, GL_DECR_WRAP); + else + glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); + glStencilMask(~0); + glStencilFunc(GL_ALWAYS, 0, ~0); + + extGlActiveStencilFace(GL_FRONT); + if (FeatureAvailable[IRR_stencil_wrap]) + glStencilOp(GL_KEEP, GL_KEEP, GL_INCR_WRAP); + else + glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); + glStencilMask(~0); + glStencilFunc(GL_ALWAYS, 0, ~0); + + glDrawArrays(GL_TRIANGLES,0,count); + } + else + { + // ZFAIL Method + + extGlActiveStencilFace(GL_BACK); + if (FeatureAvailable[IRR_stencil_wrap]) + glStencilOp(GL_KEEP, GL_INCR_WRAP, GL_KEEP); + else + glStencilOp(GL_KEEP, GL_INCR, GL_KEEP); + glStencilMask(~0); + glStencilFunc(GL_ALWAYS, 0, ~0); + + extGlActiveStencilFace(GL_FRONT); + if (FeatureAvailable[IRR_stencil_wrap]) + glStencilOp(GL_KEEP, GL_DECR_WRAP, GL_KEEP); + else + glStencilOp(GL_KEEP, GL_DECR, GL_KEEP); + glStencilMask(~0); + glStencilFunc(GL_ALWAYS, 0, ~0); + + glDrawArrays(GL_TRIANGLES,0,count); + } + glDisable(GL_STENCIL_TEST_TWO_SIDE); + } + else +#endif + if (FeatureAvailable[IRR_ATI_separate_stencil]) + { + glDisable(GL_CULL_FACE); + if (!zfail) + { + // ZPASS Method + + extGlStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR); + extGlStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR); + extGlStencilFuncSeparate(GL_FRONT_AND_BACK, GL_ALWAYS, 0, ~0); + glStencilMask(~0); + + glDrawArrays(GL_TRIANGLES,0,count); + } + else + { + // ZFAIL Method + + extGlStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR, GL_KEEP); + extGlStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR, GL_KEEP); + extGlStencilFuncSeparate(GL_FRONT_AND_BACK, GL_ALWAYS, 0, ~0); + + glDrawArrays(GL_TRIANGLES,0,count); + } + } + else +#endif + { + glEnable(GL_CULL_FACE); + if (!zfail) + { + // ZPASS Method + + glCullFace(GL_BACK); + glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); + glDrawArrays(GL_TRIANGLES,0,count); + + glCullFace(GL_FRONT); + glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); + glDrawArrays(GL_TRIANGLES,0,count); + } + else + { + // ZFAIL Method + + glStencilOp(GL_KEEP, GL_INCR, GL_KEEP); + glCullFace(GL_FRONT); + glDrawArrays(GL_TRIANGLES,0,count); + + glStencilOp(GL_KEEP, GL_DECR, GL_KEEP); + glCullFace(GL_BACK); + glDrawArrays(GL_TRIANGLES,0,count); + } + } + + glDisableClientState(GL_VERTEX_ARRAY); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glDisable(GL_STENCIL_TEST); + if (lightingEnabled) + glEnable(GL_LIGHTING); + if (fogEnabled) + glEnable(GL_FOG); + if (cullFaceEnabled) + glEnable(GL_CULL_FACE); + else + glDisable(GL_CULL_FACE); + glCullFace(cullFaceMode); + glDepthFunc(depthFunc); + glDepthMask(depthMask); +} + + +void COpenGLDriver::drawStencilShadow(bool clearStencilBuffer, video::SColor leftUpEdge, + video::SColor rightUpEdge, video::SColor leftDownEdge, video::SColor rightDownEdge) +{ + if (!StencilBuffer) + return; + + disableTextures(); + + // store attributes + const bool lightingEnabled = glIsEnabled(GL_LIGHTING); + const bool fogEnabled = glIsEnabled(GL_FOG); + GLboolean depthMask; + glGetBooleanv(GL_DEPTH_WRITEMASK, &depthMask); + GLint shadeModel; + glGetIntegerv(GL_SHADE_MODEL, &shadeModel); + const bool blendEnabled = glIsEnabled(GL_BLEND); + GLint blendSrc, blendDst; + glGetIntegerv(GL_BLEND_SRC, &blendSrc); + glGetIntegerv(GL_BLEND_DST, &blendDst); + + glDisable( GL_LIGHTING ); + glDisable(GL_FOG); + glDepthMask(GL_FALSE); + + glShadeModel( GL_FLAT ); + glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnable( GL_STENCIL_TEST ); + glStencilFunc(GL_NOTEQUAL, 0, ~0); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + + // draw a shadow rectangle covering the entire screen using stencil buffer + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + u16 indices[] = {0,1,2,3}; + S3DVertex vertices[4]; + vertices[0] = S3DVertex(-1.1f,-1.1f,0.9f, 0,0,1, leftDownEdge, 0,0); + vertices[1] = S3DVertex(-1.1f, 1.1f,0.9f, 0,0,1, leftUpEdge, 0,0); + vertices[2] = S3DVertex( 1.1f, 1.1f,0.9f, 0,0,1, rightUpEdge, 0,0); + vertices[3] = S3DVertex( 1.1f,-1.1f,0.9f, 0,0,1, rightDownEdge, 0,0); + drawVertexPrimitiveList2d3d(vertices, 4, indices, 2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN, false); + + if (clearStencilBuffer) + glClear(GL_STENCIL_BUFFER_BIT); + + // restore settings + glPopMatrix(); + glDisable(GL_STENCIL_TEST); + if (lightingEnabled) + glEnable(GL_LIGHTING); + if (fogEnabled) + glEnable(GL_FOG); + glDepthMask(depthMask); + glShadeModel(shadeModel); + if (!blendEnabled) + glDisable(GL_BLEND); + glBlendFunc(blendSrc, blendDst); +} + + +//! Sets the fog mode. +void COpenGLDriver::setFog(SColor c, bool linearFog, f32 start, + f32 end, f32 density, bool pixelFog, bool rangeFog) +{ + CNullDriver::setFog(c, linearFog, start, end, density, pixelFog, rangeFog); + + glFogf(GL_FOG_MODE, GLfloat(linearFog ? GL_LINEAR : GL_EXP)); +#ifdef GL_fog_coord + if (FeatureAvailable[IRR_fog_coord]) + glFogi(GL_FOG_COORDINATE_SOURCE, GL_FRAGMENT_DEPTH); +#endif + + if(linearFog) + { + glFogf(GL_FOG_START, start); + glFogf(GL_FOG_END, end); + } + else + glFogf(GL_FOG_DENSITY, density); + + if (pixelFog) + glHint(GL_FOG_HINT, GL_NICEST); + else + glHint(GL_FOG_HINT, GL_FASTEST); + + SColorf color(c); + GLfloat data[4] = {color.r, color.g, color.b, color.a}; + glFogfv(GL_FOG_COLOR, data); +} + + + +//! Draws a 3d line. +void COpenGLDriver::draw3DLine(const core::vector3df& start, + const core::vector3df& end, SColor color) +{ + setRenderStates3DMode(); + + u16 indices[] = {0,1}; + S3DVertex vertices[2]; + vertices[0] = S3DVertex(start.X,start.Y,start.Z, 0,0,1, color, 0,0); + vertices[1] = S3DVertex(end.X,end.Y,end.Z, 0,0,1, color, 0,0); + drawVertexPrimitiveList2d3d(vertices, 2, indices, 1, video::EVT_STANDARD, scene::EPT_LINES, false); +} + + + +//! Only used by the internal engine. Used to notify the driver that +//! the window was resized. +void COpenGLDriver::OnResize(const core::dimension2d& size) +{ + CNullDriver::OnResize(size); + glViewport(0, 0, size.Width, size.Height); +} + + +//! Returns type of video driver +E_DRIVER_TYPE COpenGLDriver::getDriverType() const +{ + return EDT_OGLES1; +} + + +//! returns color format +ECOLOR_FORMAT COpenGLDriver::getColorFormat() const +{ + return ColorFormat; +} + + +//! Sets a vertex shader constant. +void COpenGLDriver::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount) +{ +#ifdef GL_vertex_program + for (s32 i=0; isetPixelShaderConstant(), not VideoDriver->setPixelShaderConstant()."); + return false; +} + + +//! Adds a new material renderer to the VideoDriver, using pixel and/or +//! vertex shaders to render geometry. +s32 COpenGLDriver::addShaderMaterial(const c8* vertexShaderProgram, + const c8* pixelShaderProgram, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, s32 userData) +{ + s32 nr = -1; + COpenGLShaderMaterialRenderer* r = new COpenGLShaderMaterialRenderer( + this, nr, vertexShaderProgram, pixelShaderProgram, + callback, getMaterialRenderer(baseMaterial), userData); + + r->drop(); + return nr; +} + + +//! Adds a new material renderer to the VideoDriver, using GLSL to render geometry. +s32 COpenGLDriver::addHighLevelShaderMaterial( + const c8* vertexShaderProgram, + const c8* vertexShaderEntryPointName, + E_VERTEX_SHADER_TYPE vsCompileTarget, + const c8* pixelShaderProgram, + const c8* pixelShaderEntryPointName, + E_PIXEL_SHADER_TYPE psCompileTarget, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, + s32 userData) +{ + s32 nr = -1; + + COpenGLSLMaterialRenderer* r = new COpenGLSLMaterialRenderer( + this, nr, vertexShaderProgram, vertexShaderEntryPointName, + vsCompileTarget, pixelShaderProgram, pixelShaderEntryPointName, psCompileTarget, + callback,getMaterialRenderer(baseMaterial), userData); + + r->drop(); + return nr; +} + +//! Returns a pointer to the IVideoDriver interface. (Implementation for +//! IMaterialRendererServices) +IVideoDriver* COpenGLDriver::getVideoDriver() +{ + return this; +} + + +//! Returns pointer to the IGPUProgrammingServices interface. +IGPUProgrammingServices* COpenGLDriver::getGPUProgrammingServices() +{ + return this; +} + + +ITexture* COpenGLDriver::addRenderTargetTexture(const core::dimension2d& size, const c8* name) +{ + //disable mip-mapping + bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS); + setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false); + + video::ITexture* rtt = 0; + if (name==0) + name="rt"; +#if defined(GL_framebuffer_object) + // if driver supports FrameBufferObjects, use them + if (queryFeature(EVDF_FRAMEBUFFER_OBJECT)) + { + rtt = new COpenGLTexture(size, name, this); + addTexture(rtt); + rtt->drop(); + } + else +#endif + { + rtt = addTexture(size, name, ECF_A8R8G8B8); + if (rtt) + { + rtt->grab(); + static_cast(rtt)->setIsRenderTarget(true); + } + } + + //restore mip-mapping + setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, generateMipLevels); + + return rtt; +} + + +//! Returns the maximum amount of primitives (mostly vertices) which +//! the device is able to render with one drawIndexedTriangleList +//! call. +u32 COpenGLDriver::getMaximalPrimitiveCount() const +{ + return 65535;// TODO: Fix all loaders to auto-split and then return the correct value: MaxIndices; +} + + +//! set or reset render target +bool COpenGLDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuffer, + bool clearZBuffer, SColor color) +{ + // check for right driver type + + if (texture && texture->getDriverType() != EDT_OGLES1) + { + os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR); + return false; + } + + // check if we should set the previous RT back + + setTexture(0, 0); + ResetRenderStates=true; + if (RenderTargetTexture!=0) + { + RenderTargetTexture->unbindRTT(); + } + + if (texture) + { + // we want to set a new target. so do this. + RenderTargetTexture = static_cast(texture); + RenderTargetTexture->bindRTT(); + CurrentRendertargetSize = texture->getSize(); + } + else + { + glViewport(0,0,ScreenSize.Width,ScreenSize.Height); + RenderTargetTexture = 0; + CurrentRendertargetSize = core::dimension2d(0,0); + } + + GLbitfield mask = 0; + if (clearBackBuffer) + { + const f32 inv = 1.0f / 255.0f; + glClearColor(color.getRed() * inv, color.getGreen() * inv, + color.getBlue() * inv, color.getAlpha() * inv); + + mask |= GL_COLOR_BUFFER_BIT; + } + if (clearZBuffer) + { + glDepthMask(GL_TRUE); + LastMaterial.ZWriteEnable=true; + mask |= GL_DEPTH_BUFFER_BIT; + } + + glClear(mask); + + return true; +} + + +// returns the current size of the screen or rendertarget +const core::dimension2d& COpenGLDriver::getCurrentRenderTargetSize() const +{ + if ( CurrentRendertargetSize.Width == 0 ) + return ScreenSize; + else + return CurrentRendertargetSize; +} + + +//! Clears the ZBuffer. +void COpenGLDriver::clearZBuffer() +{ + GLboolean enabled = GL_TRUE; + glGetBooleanv(GL_DEPTH_WRITEMASK, &enabled); + + glDepthMask(GL_TRUE); + glClear(GL_DEPTH_BUFFER_BIT); + + glDepthMask(enabled); +} + + +//! Returns an image created from the last rendered frame. +IImage* COpenGLDriver::createScreenShot() +{ + IImage* newImage = new CImage(ECF_A8R8G8B8, ScreenSize); + + u8* pixels = static_cast(newImage->lock()); + if (!pixels) + { + newImage->drop(); + return 0; + } + + // allows to read pixels in top-to-bottom order +#ifdef GL_MESA_pack_invert + if (FeatureAvailable[IRR_MESA_pack_invert]) + glPixelStorei(GL_PACK_INVERT_MESA, GL_TRUE); +#endif + + // We want to read the front buffer to get the latest render finished. + glReadBuffer(GL_FRONT); + glReadPixels(0, 0, ScreenSize.Width, ScreenSize.Height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + glReadBuffer(GL_BACK); + +#ifdef GL_MESA_pack_invert + if (FeatureAvailable[IRR_MESA_pack_invert]) + glPixelStorei(GL_PACK_INVERT_MESA, GL_FALSE); + else +#endif + { + // opengl images are horizontally flipped, so we have to fix that here. + const s32 pitch=newImage->getPitch(); + u8* p2 = pixels + (ScreenSize.Height - 1) * pitch; + u8* tmpBuffer = new u8[pitch]; + for (s32 i=0; i < ScreenSize.Height; i += 2) + { + memcpy(tmpBuffer, pixels, pitch); + memcpy(pixels, p2, pitch); + memcpy(p2, tmpBuffer, pitch); + pixels += pitch; + p2 -= pitch; + } + delete [] tmpBuffer; + } + + newImage->unlock(); + + if (testGLError()) + { + newImage->drop(); + return 0; + } + + return newImage; +} + + +//! Set/unset a clipping plane. +bool COpenGLDriver::setClipPlane(u32 index, const core::plane3df& plane, bool enable) +{ + if (index >= MaxUserClipPlanes) + return false; + + UserClipPlane[index]=plane; + enableClipPlane(index, enable); + return true; +} + + +void COpenGLDriver::uploadClipPlane(u32 index) +{ + // opengl needs an array of doubles for the plane equation + float clip_plane[4]; + clip_plane[0] = UserClipPlane[index].Normal.X; + clip_plane[1] = UserClipPlane[index].Normal.Y; + clip_plane[2] = UserClipPlane[index].Normal.Z; + clip_plane[3] = UserClipPlane[index].D; + glClipPlanef(GL_CLIP_PLANE0 + index, clip_plane); +} + + +//! Enable/disable a clipping plane. +void COpenGLDriver::enableClipPlane(u32 index, bool enable) +{ + if (index >= MaxUserClipPlanes) + return; + if (enable) + { + if (!UserClipPlaneEnabled[index]) + { + uploadClipPlane(index); + glEnable(GL_CLIP_PLANE0 + index); + } + } + else + glDisable(GL_CLIP_PLANE0 + index); + + UserClipPlaneEnabled[index]=enable; +} + + +} // end namespace +} // end namespace + +#endif // _IRR_COMPILE_WITH_OGLES1_ + +namespace irr +{ +namespace video +{ + + +// ----------------------------------- +// WINDOWS VERSION +// ----------------------------------- +#ifdef _IRR_USE_WINDOWS_DEVICE_ +IVideoDriver* createOpenGLDriver(const core::dimension2d& screenSize, + HWND window, u32 bits, bool stencilBuffer, io::IFileSystem* io, bool vsync, bool antiAlias) +{ +#ifdef _IRR_COMPILE_WITH_OGLES1_ + COpenGLDriver* ogl = new COpenGLDriver(screenSize, window, stencilBuffer, io, antiAlias); + if (!ogl->initDriver(screenSize, window, bits, vsync, stencilBuffer)) + { + ogl->drop(); + ogl = 0; + } + return ogl; +#else + return 0; +#endif // _IRR_COMPILE_WITH_OGLES1_ +} +#endif // _IRR_USE_WINDOWS_DEVICE_ + +// ----------------------------------- +// MACOSX VERSION +// ----------------------------------- +#if defined(_IRR_USE_OSX_DEVICE_) +IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params, + io::IFileSystem* io, CIrrDeviceMacOSX *device) +{ +#ifdef _IRR_COMPILE_WITH_OGLES1_ + return new COpenGLDriver(params, io, device); +#else + return 0; +#endif // _IRR_COMPILE_WITH_OGLES1_ +} +#endif // _IRR_USE_OSX_DEVICE_ + +// ----------------------------------- +// X11/SDL VERSION +// ----------------------------------- +#if defined(_IRR_USE_LINUX_DEVICE_) || defined(_IRR_USE_SDL_DEVICE_) +IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params, + io::IFileSystem* io) +{ +#ifdef _IRR_COMPILE_WITH_OGLES1_ + return new COpenGLDriver(params, io); +#else + return 0; +#endif // _IRR_COMPILE_WITH_OGLES1_ +} +#endif // _IRR_USE_LINUX_DEVICE_ + +} // end namespace +} // end namespace + + diff --git a/source/Irrlicht/COGLESDriver.h b/source/Irrlicht/COGLESDriver.h new file mode 100644 index 00000000..4e105cbc --- /dev/null +++ b/source/Irrlicht/COGLESDriver.h @@ -0,0 +1,384 @@ +// Copyright (C) 2002-2008 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#ifndef __C_VIDEO_OPEN_GL_H_INCLUDED__ +#define __C_VIDEO_OPEN_GL_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#if defined(_IRR_WINDOWS_API_) + // include windows headers for HWND + #define WIN32_LEAN_AND_MEAN + #include +#elif defined(_IRR_USE_OSX_DEVICE_) + #include "CIrrDeviceMacOSX.h" +#endif + +#ifdef _IRR_COMPILE_WITH_OPENGL_ + +#include "CNullDriver.h" +#include "IMaterialRendererServices.h" +#include "SIrrCreationParameters.h" + +#include +#include + +namespace irr +{ +namespace video +{ + class COpenGLTexture; + + class COpenGLDriver : public CNullDriver, public IMaterialRendererServices + { + public: + + #ifdef _IRR_WINDOWS_API_ + //! win32 constructor + COpenGLDriver(const core::dimension2d& screenSize, HWND window, + bool stencilBuffer, io::IFileSystem* io, bool antiAlias); + + //! inits the windows specific parts of the open gl driver + bool initDriver(const core::dimension2d& screenSize, HWND window, + u32 bits, bool vsync, bool stencilBuffer); + #endif + + #if defined(_IRR_USE_LINUX_DEVICE_) || defined(_IRR_USE_SDL_DEVICE_) + COpenGLDriver(const SIrrlichtCreationParameters& params, io::IFileSystem* io); + #endif + + #ifdef _IRR_USE_OSX_DEVICE_ + COpenGLDriver(const SIrrlichtCreationParameters& params, + io::IFileSystem* io, CIrrDeviceMacOSX *device); + #endif + + //! destructor + virtual ~COpenGLDriver(); + + //! clears the zbuffer + virtual bool beginScene(bool backBuffer=true, bool zBuffer=true, + SColor color=SColor(255,0,0,0), + void* windowId=0, + core::rect* sourceRect=0); + + //! presents the rendered scene on the screen, returns false if failed + virtual bool endScene(); + + //! sets transformation + virtual void setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat); + + + struct SHWBufferLink_opengl : public SHWBufferLink + { + SHWBufferLink_opengl(const scene::IMeshBuffer *_MeshBuffer): SHWBufferLink(_MeshBuffer), vbo_verticesID(0),vbo_indicesID(0){} + + GLuint vbo_verticesID; //tmp + GLuint vbo_indicesID; //tmp + + GLuint vbo_verticesSize; //tmp + GLuint vbo_indicesSize; //tmp + + }; + + bool updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer); + bool updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer); + + //! updates hardware buffer if needed + virtual bool updateHardwareBuffer(SHWBufferLink *HWBuffer); + + //! Create hardware buffer from mesh + virtual SHWBufferLink *createHardwareBuffer(const scene::IMeshBuffer* mb); + + //! Delete hardware buffer (only some drivers can) + virtual void deleteHardwareBuffer(SHWBufferLink *HWBuffer); + + //! Draw hardware buffer + virtual void drawHardwareBuffer(SHWBufferLink *HWBuffer); + + //! draws a vertex primitive list + virtual void drawVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType); + + void drawVertexPrimitiveList2d3d(const void* vertices, u32 vertexCount, const u16* indexList, u32 primitiveCount, E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, bool threed=true); + + //! queries the features of the driver, returns true if feature is available + virtual bool queryFeature(E_VIDEO_DRIVER_FEATURE feature) const + { + return FeatureEnabled[feature] && COpenGLExtensionHandler::queryFeature(feature); + } + + //! Sets a material. All 3d drawing functions draw geometry now + //! using this material. + //! \param material: Material to be used from now on. + virtual void setMaterial(const SMaterial& material); + + //! draws an 2d image, using a color (if color is other then Color(255,255,255,255)) and the alpha channel of the texture if wanted. + virtual void draw2DImage(const video::ITexture* texture, const core::position2d& destPos, + const core::rect& sourceRect, const core::rect* clipRect = 0, + SColor color=SColor(255,255,255,255), bool useAlphaChannelOfTexture=false); + + //! draws a set of 2d images, using a color and the alpha + /** channel of the texture if desired. The images are drawn + beginning at pos and concatenated in one line. All drawings + are clipped against clipRect (if != 0). + The subtextures are defined by the array of sourceRects + and are chosen by the indices given. + \param texture: Texture to be drawn. + \param pos: Upper left 2d destination position where the image will be drawn. + \param sourceRects: Source rectangles of the image. + \param indices: List of indices which choose the actual rectangle used each time. + \param clipRect: Pointer to rectangle on the screen where the image is clipped to. + This pointer can be 0. Then the image is not clipped. + \param color: Color with which the image is colored. + Note that the alpha component is used: If alpha is other than 255, the image will be transparent. + \param useAlphaChannelOfTexture: If true, the alpha channel of the texture is + used to draw the image. */ + virtual void draw2DImage(const video::ITexture* texture, + const core::position2d& pos, + const core::array >& sourceRects, + const core::array& indices, + const core::rect* clipRect=0, + SColor color=SColor(255,255,255,255), + bool useAlphaChannelOfTexture=false); + + //! Draws a part of the texture into the rectangle. + virtual void draw2DImage(const video::ITexture* texture, const core::rect& destRect, + const core::rect& sourceRect, const core::rect* clipRect = 0, + const video::SColor* const colors=0, bool useAlphaChannelOfTexture=false); + + //! draw an 2d rectangle + virtual void draw2DRectangle(SColor color, const core::rect& pos, + const core::rect* clip = 0); + + //!Draws an 2d rectangle with a gradient. + virtual void draw2DRectangle(const core::rect& pos, + SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown, + const core::rect* clip = 0); + + //! Draws a 2d line. + virtual void draw2DLine(const core::position2d& start, + const core::position2d& end, + SColor color=SColor(255,255,255,255)); + + //! Draws a 3d line. + virtual void draw3DLine(const core::vector3df& start, + const core::vector3df& end, + SColor color = SColor(255,255,255,255)); + + //! \return Returns the name of the video driver. Example: In case of the Direct3D8 + //! driver, it would return "Direct3D8.1". + virtual const wchar_t* getName() const; + + //! deletes all dynamic lights there are + virtual void deleteAllDynamicLights(); + + //! adds a dynamic light + virtual void addDynamicLight(const SLight& light); + + //! returns the maximal amount of dynamic lights the device can handle + virtual u32 getMaximalDynamicLightAmount() const; + + //! Sets the dynamic ambient light color. The default color is + //! (0,0,0,0) which means it is dark. + //! \param color: New color of the ambient light. + virtual void setAmbientLight(const SColorf& color); + + //! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do + //! this: First, draw all geometry. Then use this method, to draw the shadow + //! volume. Then, use IVideoDriver::drawStencilShadow() to visualize the shadow. + virtual void drawStencilShadowVolume(const core::vector3df* triangles, s32 count, bool zfail); + + //! Fills the stencil shadow with color. After the shadow volume has been drawn + //! into the stencil buffer using IVideoDriver::drawStencilShadowVolume(), use this + //! to draw the color of the shadow. + virtual void drawStencilShadow(bool clearStencilBuffer=false, + video::SColor leftUpEdge = video::SColor(0,0,0,0), + video::SColor rightUpEdge = video::SColor(0,0,0,0), + video::SColor leftDownEdge = video::SColor(0,0,0,0), + video::SColor rightDownEdge = video::SColor(0,0,0,0)); + + //! sets a viewport + virtual void setViewPort(const core::rect& area); + + //! Sets the fog mode. + virtual void setFog(SColor color, bool linearFog, f32 start, + f32 end, f32 density, bool pixelFog, bool rangeFog); + + //! Only used by the internal engine. Used to notify the driver that + //! the window was resized. + virtual void OnResize(const core::dimension2d& size); + + //! Returns type of video driver + virtual E_DRIVER_TYPE getDriverType() const; + + //! get color format of the current color buffer + virtual ECOLOR_FORMAT getColorFormat() const; + + //! Returns the transformation set by setTransform + virtual const core::matrix4& getTransform(E_TRANSFORMATION_STATE state) const; + + //! Can be called by an IMaterialRenderer to make its work easier. + virtual void setBasicRenderStates(const SMaterial& material, const SMaterial& lastmaterial, + bool resetAllRenderstates); + + //! Sets a vertex shader constant. + virtual void setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount=1); + + //! Sets a pixel shader constant. + virtual void setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount=1); + + //! Sets a constant for the vertex shader based on a name. + virtual bool setVertexShaderConstant(const c8* name, const f32* floats, int count); + + //! Sets a constant for the pixel shader based on a name. + virtual bool setPixelShaderConstant(const c8* name, const f32* floats, int count); + + //! sets the current Texture + //! Returns whether setting was a success or not. + bool setTexture(u32 stage, const video::ITexture* texture); + + //! disables all textures beginning with the optional fromStage parameter. Otherwise all texture stages are disabled. + //! Returns whether disabling was successful or not. + bool disableTextures(u32 fromStage=0); + + //! Adds a new material renderer to the VideoDriver, using + //! extGLGetObjectParameteriv(shaderHandle, GL_OBJECT_COMPILE_STATUS_ARB, &status) + //! pixel and/or vertex shaders to render geometry. + virtual s32 addShaderMaterial(const c8* vertexShaderProgram, const c8* pixelShaderProgram, + IShaderConstantSetCallBack* callback, E_MATERIAL_TYPE baseMaterial, s32 userData); + + //! Adds a new material renderer to the VideoDriver, using GLSL to render geometry. + virtual s32 addHighLevelShaderMaterial(const c8* vertexShaderProgram, const c8* vertexShaderEntryPointName, + E_VERTEX_SHADER_TYPE vsCompileTarget, const c8* pixelShaderProgram, const c8* pixelShaderEntryPointName, + E_PIXEL_SHADER_TYPE psCompileTarget, IShaderConstantSetCallBack* callback, E_MATERIAL_TYPE baseMaterial, + s32 userData); + + //! Returns pointer to the IGPUProgrammingServices interface. + virtual IGPUProgrammingServices* getGPUProgrammingServices(); + + //! Returns a pointer to the IVideoDriver interface. (Implementation for + //! IMaterialRendererServices) + virtual IVideoDriver* getVideoDriver(); + + //! Returns the maximum amount of primitives (mostly vertices) which + //! the device is able to render with one drawIndexedTriangleList + //! call. + virtual u32 getMaximalPrimitiveCount() const; + + virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, + const c8* name); + + virtual bool setRenderTarget(video::ITexture* texture, bool clearBackBuffer, + bool clearZBuffer, SColor color); + + //! Clears the ZBuffer. + virtual void clearZBuffer(); + + //! Returns an image created from the last rendered frame. + virtual IImage* createScreenShot(); + + //! checks if an OpenGL error has happend and prints it + //! for performance reasons only available in debug mode + bool testGLError(); + + //! Set/unset a clipping plane. + //! There are at least 6 clipping planes available for the user to set at will. + //! \param index: The plane index. Must be between 0 and MaxUserClipPlanes. + //! \param plane: The plane itself. + //! \param enable: If true, enable the clipping plane else disable it. + virtual bool setClipPlane(u32 index, const core::plane3df& plane, bool enable=false); + + //! Enable/disable a clipping plane. + //! There are at least 6 clipping planes available for the user to set at will. + //! \param index: The plane index. Must be between 0 and MaxUserClipPlanes. + //! \param enable: If true, enable the clipping plane else disable it. + virtual void enableClipPlane(u32 index, bool enable); + + //! Returns the graphics card vendor name. + virtual core::stringc getVendorInfo() {return vendorName;}; + + private: + + void uploadClipPlane(u32 index); + + //! inits the parts of the open gl driver used on all platforms + bool genericDriverInit(const core::dimension2d& screenSize, bool stencilBuffer); + //! returns a device dependent texture from a software surface (IImage) + virtual video::ITexture* createDeviceDependentTexture(IImage* surface, const char* name); + + //! creates a transposed matrix in supplied GLfloat array to pass to OpenGL + inline void createGLMatrix(GLfloat gl_matrix[16], const core::matrix4& m); + inline void createGLTextureMatrix(GLfloat gl_matrix[16], const core::matrix4& m); + + //! Set GL pipeline to desired texture wrap modes of the material + void setWrapMode(const SMaterial& material); + + //! sets the needed renderstates + void setRenderStates3DMode(); + + //! sets the needed renderstates + void setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel); + + // returns the current size of the screen or rendertarget + virtual const core::dimension2d& getCurrentRenderTargetSize() const; + + void createMaterialRenderers(); + + + core::stringw Name; + core::matrix4 Matrices[ETS_COUNT]; + core::array ColorBuffer; + + //! enumeration for rendering modes such as 2d and 3d for minizing the switching of renderStates. + enum E_RENDER_MODE + { + ERM_NONE = 0, // no render state has been set yet. + ERM_2D, // 2d drawing rendermode + ERM_3D // 3d rendering mode + }; + + E_RENDER_MODE CurrentRenderMode; + //! bool to make all renderstates reset if set to true. + bool ResetRenderStates; + bool Transformation3DChanged; + bool AntiAlias; + + SMaterial Material, LastMaterial; + COpenGLTexture* RenderTargetTexture; + const ITexture* CurrentTexture[MATERIAL_MAX_TEXTURES]; + s32 LastSetLight; + core::array UserClipPlane; + core::array UserClipPlaneEnabled; + + core::dimension2d CurrentRendertargetSize; + + core::stringc vendorName; + + core::matrix4 TextureFlipMatrix; + + //! Color buffer format + ECOLOR_FORMAT ColorFormat; + + #ifdef _IRR_WINDOWS_API_ + HDC HDc; // Private GDI Device Context + HWND Window; + HGLRC HRc; // Permanent Rendering Context + #elif defined(_IRR_USE_LINUX_DEVICE_) + GLXDrawable Drawable; + #elif defined(_IRR_USE_OSX_DEVICE_) + CIrrDeviceMacOSX *_device; + #endif + EGLDisplay EglDisplay; + EGLSurface EglSurface; + EGLContext EglContext; + }; + +} // end namespace video +} // end namespace irr + + +#endif // _IRR_COMPILE_WITH_OPENGL_ +#endif + diff --git a/source/Irrlicht/Makefile b/source/Irrlicht/Makefile index cec6a877..e02c41d1 100644 --- a/source/Irrlicht/Makefile +++ b/source/Irrlicht/Makefile @@ -28,7 +28,7 @@ IRRMESHOBJ = $(IRRMESHLOADER) $(IRRMESHWRITER) \ IRROBJ = CBillboardSceneNode.o CCameraSceneNode.o CDummyTransformationSceneNode.o CEmptySceneNode.o CGeometryCreator.o CLightSceneNode.o CMeshManipulator.o CMetaTriangleSelector.o COctTreeSceneNode.o COctTreeTriangleSelector.o CSceneCollisionManager.o CSceneManager.o CShadowVolumeSceneNode.o CSkyBoxSceneNode.o CSkyDomeSceneNode.o CTerrainSceneNode.o CTerrainTriangleSelector.o CVolumeLightSceneNode.o CCubeSceneNode.o CSphereSceneNode.o CTextSceneNode.o CTriangleBBSelector.o CTriangleSelector.o CWaterSurfaceSceneNode.o CMeshCache.o CDefaultSceneNodeAnimatorFactory.o CDefaultSceneNodeFactory.o IRRPARTICLEOBJ = CParticleAnimatedMeshSceneNodeEmitter.o CParticleBoxEmitter.o CParticleCylinderEmitter.o CParticleMeshEmitter.o CParticlePointEmitter.o CParticleRingEmitter.o CParticleSphereEmitter.o CParticleAttractionAffector.o CParticleFadeOutAffector.o CParticleGravityAffector.o CParticleRotationAffector.o CParticleSystemSceneNode.o IRRANIMOBJ = CSceneNodeAnimatorCameraFPS.o CSceneNodeAnimatorCameraMaya.o CSceneNodeAnimatorCollisionResponse.o CSceneNodeAnimatorDelete.o CSceneNodeAnimatorFlyCircle.o CSceneNodeAnimatorFlyStraight.o CSceneNodeAnimatorFollowSpline.o CSceneNodeAnimatorRotation.o CSceneNodeAnimatorTexture.o -IRRDRVROBJ = CNullDriver.o COpenGLDriver.o COpenGLNormalMapRenderer.o COpenGLParallaxMapRenderer.o COpenGLShaderMaterialRenderer.o COpenGLTexture.o COpenGLSLMaterialRenderer.o COpenGLExtensionHandler.o CD3D8Driver.o CD3D8NormalMapRenderer.o CD3D8ParallaxMapRenderer.o CD3D8ShaderMaterialRenderer.o CD3D8Texture.o CD3D9Driver.o CD3D9HLSLMaterialRenderer.o CD3D9NormalMapRenderer.o CD3D9ParallaxMapRenderer.o CD3D9ShaderMaterialRenderer.o CD3D9Texture.o +IRRDRVROBJ = CNullDriver.o COpenGLDriver.o COpenGLNormalMapRenderer.o COpenGLParallaxMapRenderer.o COpenGLShaderMaterialRenderer.o COpenGLTexture.o COpenGLSLMaterialRenderer.o COpenGLExtensionHandler.o CD3D8Driver.o CD3D8NormalMapRenderer.o CD3D8ParallaxMapRenderer.o CD3D8ShaderMaterialRenderer.o CD3D8Texture.o CD3D9Driver.o CD3D9HLSLMaterialRenderer.o CD3D9NormalMapRenderer.o CD3D9ParallaxMapRenderer.o CD3D9ShaderMaterialRenderer.o CD3D9Texture.o COGLESDriver.o IRRIMAGEOBJ = CColorConverter.o CImage.o CImageLoaderBMP.o CImageLoaderJPG.o CImageLoaderPCX.o CImageLoaderPNG.o CImageLoaderPSD.o CImageLoaderTGA.o CImageLoaderPPM.o CImageLoaderWAL.o \ CImageWriterBMP.o CImageWriterJPG.o CImageWriterPCX.o CImageWriterPNG.o CImageWriterPPM.o CImageWriterPSD.o CImageWriterTGA.o IRRVIDEOOBJ = CVideoModeList.o CFPSCounter.o $(IRRDRVROBJ) $(IRRIMAGEOBJ)