Add support for (experimental) WebGL1 driver for emscripten (still work in process).

It's a reduced OGLES2 driver which tries to work only with bound buffers.
This allows emsripten to compile without "-s FULL_ES2=1" (the WebGL simulation) 
which is a lot faster. Driver can already run simply examples, but is not yet complete.


git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/branches/ogl-es@5441 dfc29bdd-3216-0410-991c-e03cc46cb475
master
cutealien 2017-04-19 17:30:37 +00:00
parent d3c91b659d
commit 4a5eaeb45d
16 changed files with 546 additions and 50 deletions

View File

@ -1,6 +1,7 @@
--------------------------
Changes in ogl-es (not yet released - will be merged with trunk at some point)
- Add support for (experimental) WebGL1 driver for emscripten (still work in process)
- Add support for emscripten. Thanks @labsin for the patch.
- Add IVideoDriver::getAmbientLight function so shaders can access global ambient light easier
- Merge material changes for COGLES1MaterialRenderer_LIGHTMAP and COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL which had been done in OGL in trunk (r2740) to ensure materials look the same on all platforms.

View File

@ -51,14 +51,17 @@ namespace video
/** Performs hardware accelerated rendering of 3D and 2D
primitives. */
EDT_OPENGL,
//! OpenGL-ES 1.x driver, for embedded and mobile systems
EDT_OGLES1,
//! OpenGL-ES 2.x driver, for embedded and mobile systems
/** Supports shaders etc. */
EDT_OGLES2,
//! WebGL1 friendly subset of OpenGL-ES 2.x driver for Emscripten
EDT_WEBGL1,
//! No driver, just for counting the elements
EDT_COUNT
};
@ -73,7 +76,8 @@ namespace video
"OpenGL 1.x/2.x/3.x",
"OpenGL ES1",
"OpenGL ES2",
0
"WebGL 1",
0
};
const c8* const DRIVER_TYPE_NAMES_SHORT[] =
@ -84,6 +88,9 @@ namespace video
"d3d8",
"d3d9",
"opengl",
"ogles1",
"ogles2",
"webgl1",
0
};

View File

@ -97,6 +97,7 @@
#define _IRR_COMPILE_WITH_OSX_DEVICE_
#define NO_IRR_COMPILE_WITH_OGLES1_
#define NO_IRR_COMPILE_WITH_OGLES2_
#define NO_IRR_COMPILE_WITH_WEBGL1_
#endif
#endif
@ -106,6 +107,7 @@
#define NO_IRR_COMPILE_WITH_OPENGL_
#define NO_IRR_COMPILE_WITH_OGLES1_
#define _IRR_COMPILE_WITH_OGLES2_
#define _IRR_COMPILE_WITH_WEBGL1_
#define _IRR_COMPILE_WITH_EGL_MANAGER_
#define _IRR_COMPILE_WITH_SDL_DEVICE_
#define NO_IRR_COMPILE_WITH_X11_DEVICE_
@ -253,6 +255,16 @@ define out. */
#undef _IRR_COMPILE_WITH_OGLES2_
#endif
//! Define _IRR_COMPILE_WITH_WEBGL1_ to compile Irrlicht engine with a WebGL friendly
//! subset of the OpenGL ES 2.0 driver.
#define _IRR_COMPILE_WITH_WEBGL1_
#ifdef NO_IRR_COMPILE_WITH_WEBGL1_
#undef _IRR_COMPILE_WITH_WEBGL1_
#endif
#ifdef _IRR_COMPILE_WITH_WEBGL1_
#define _IRR_COMPILE_WITH_OGLES2_ // it's a subset of OGL ES2, so always needed when using WebGL
#endif
//! Define required options for OpenGL ES 2.0 drivers.
#if defined(_IRR_COMPILE_WITH_OGLES2_)
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) || defined(_IRR_COMPILE_WITH_X11_DEVICE_) || defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_)

View File

@ -259,40 +259,40 @@ namespace irr
is defined, false if joysticks are not supported or support is compiled out.
*/
virtual bool activateJoysticks(core::array<SJoystickInfo>& joystickInfo) =0;
//! Activate accelerometer.
virtual bool activateAccelerometer(float updateInterval = 0.016666f) = 0;
//! Deactivate accelerometer.
virtual bool deactivateAccelerometer() = 0;
//! Is accelerometer active.
virtual bool isAccelerometerActive() = 0;
//! Is accelerometer available.
virtual bool isAccelerometerAvailable() = 0;
//! Activate gyroscope.
virtual bool activateGyroscope(float updateInterval = 0.016666f) = 0;
//! Deactivate gyroscope.
virtual bool deactivateGyroscope() = 0;
//! Is gyroscope active.
virtual bool isGyroscopeActive() = 0;
//! Is gyroscope available.
virtual bool isGyroscopeAvailable() = 0;
//! Activate device motion.
virtual bool activateDeviceMotion(float updateInterval = 0.016666f) = 0;
//! Deactivate device motion.
virtual bool deactivateDeviceMotion() = 0;
//! Is device motion active.
virtual bool isDeviceMotionActive() = 0;
//! Is device motion available.
virtual bool isDeviceMotionAvailable() = 0;
@ -377,6 +377,12 @@ namespace irr
return true;
#else
return false;
#endif
case video::EDT_WEBGL1:
#ifdef _IRR_COMPILE_WITH_WEBGL1_
return true;
#else
return false;
#endif
default:
return false;

View File

@ -12,7 +12,7 @@
#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_)
#include <android/native_activity.h>
#endif
namespace irr
{
namespace video
@ -37,7 +37,7 @@ bool CEGLManager::initialize(const SIrrlichtCreationParameters& params, const SE
{
if (EglWindow != 0 && EglDisplay != EGL_NO_DISPLAY)
return true;
// store new data
Params=params;
Data=data;
@ -49,7 +49,7 @@ bool CEGLManager::initialize(const SIrrlichtCreationParameters& params, const SE
EglDisplay = eglGetDisplay((NativeDisplayType)Data.OpenGLWin32.HDc);
#elif defined(_IRR_EMSCRIPTEN_PLATFORM_)
EglWindow = 0;
EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
#elif defined(_IRR_COMPILE_WITH_X11_DEVICE_)
EglWindow = (NativeWindowType)Data.OpenGLLinux.X11Window;
EglDisplay = eglGetDisplay((NativeDisplayType)Data.OpenGLLinux.X11Display);
@ -135,6 +135,7 @@ bool CEGLManager::generateSurface()
EglOpenGLBIT = EGL_OPENGL_ES_BIT;
break;
case EDT_OGLES2:
case EDT_WEBGL1:
EglOpenGLBIT = EGL_OPENGL_ES2_BIT;
break;
default:
@ -300,6 +301,7 @@ bool CEGLManager::generateContext()
OpenGLESVersion = 1;
break;
case EDT_OGLES2:
case EDT_WEBGL1:
OpenGLESVersion = 2;
break;
default:

View File

@ -73,6 +73,10 @@ namespace irr
#ifdef _IRR_COMPILE_WITH_OGLES2_
IVideoDriver* createOGLES2Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);
#endif
#ifdef _IRR_COMPILE_WITH_WEBGL1_
IVideoDriver* createWebGL1Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);
#endif
}
} // end namespace irr
@ -84,7 +88,7 @@ namespace
Atom X_ATOM_TEXT;
Atom X_ATOM_NETWM_MAXIMIZE_VERT;
Atom X_ATOM_NETWM_MAXIMIZE_HORZ;
Atom X_ATOM_NETWM_STATE;
Atom X_ATOM_NETWM_STATE;
};
namespace irr
@ -559,7 +563,7 @@ bool CIrrDeviceLinux::createWindow()
}
initXAtoms();
// check netwm support
Atom WMCheck = XInternAtom(XDisplay, "_NET_SUPPORTING_WM_CHECK", true);
if (WMCheck != None)
@ -635,6 +639,22 @@ void CIrrDeviceLinux::createDriver()
}
#else
os::Printer::log("No OpenGL-ES2 support compiled in.", ELL_ERROR);
#endif
break;
case video::EDT_WEBGL1:
#ifdef _IRR_COMPILE_WITH_WEBGL1_
{
video::SExposedVideoData data;
data.OpenGLLinux.X11Window = XWindow;
data.OpenGLLinux.X11Display = XDisplay;
ContextManager = new video::CEGLManager();
ContextManager->initialize(CreationParams, data);
VideoDriver = video::createWebGL1Driver(CreationParams, FileSystem, ContextManager);
}
#else
os::Printer::log("No WebGL1 support compiled in.", ELL_ERROR);
#endif
break;
case video::DEPRECATED_EDT_DIRECT3D8_NO_LONGER_EXISTS:
@ -1390,7 +1410,7 @@ void CIrrDeviceLinux::maximizeWindow()
XSendEvent(XDisplay, DefaultRootWindow(XDisplay), false,
SubstructureNotifyMask|SubstructureRedirectMask, &ev);
}
XMapWindow(XDisplay, XWindow);
#endif
}
@ -1416,7 +1436,7 @@ void CIrrDeviceLinux::restoreWindow()
XSendEvent(XDisplay, DefaultRootWindow(XDisplay), false,
SubstructureNotifyMask|SubstructureRedirectMask, &ev);
}
XMapWindow(XDisplay, XWindow);
#endif
}
@ -1965,7 +1985,7 @@ void CIrrDeviceLinux::initXAtoms()
X_ATOM_TEXT = XInternAtom (XDisplay, "TEXT", False);
X_ATOM_NETWM_MAXIMIZE_VERT = XInternAtom(XDisplay, "_NET_WM_STATE_MAXIMIZED_VERT", true);
X_ATOM_NETWM_MAXIMIZE_HORZ = XInternAtom(XDisplay, "_NET_WM_STATE_MAXIMIZED_HORZ", true);
X_ATOM_NETWM_STATE = XInternAtom(XDisplay, "_NET_WM_STATE", true);
X_ATOM_NETWM_STATE = XInternAtom(XDisplay, "_NET_WM_STATE", true);
#endif
}

View File

@ -48,6 +48,10 @@ namespace irr
#if defined(_IRR_COMPILE_WITH_OGLES2_) && defined(_IRR_EMSCRIPTEN_PLATFORM_)
IVideoDriver* createOGLES2Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);
#endif
#if defined(_IRR_COMPILE_WITH_WEBGL1_) && defined(_IRR_EMSCRIPTEN_PLATFORM_)
IVideoDriver* createWebGL1Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);
#endif
} // end namespace video
} // end namespace irr
@ -293,6 +297,21 @@ void CIrrDeviceSDL::createDriver()
#endif
break;
case video::EDT_WEBGL1:
#if defined(_IRR_COMPILE_WITH_WEBGL1_) && defined(_IRR_EMSCRIPTEN_PLATFORM_)
{
video::SExposedVideoData data;
ContextManager = new video::CEGLManager();
ContextManager->initialize(CreationParams, data);
VideoDriver = video::createWebGL1Driver(CreationParams, FileSystem, ContextManager);
}
#else
os::Printer::log("No WebGL1 support compiled in.", ELL_ERROR);
#endif
break;
case video::EDT_NULL:
VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize);
break;

View File

@ -1241,6 +1241,9 @@ void CIrrDeviceWin32::createDriver()
os::Printer::log("OpenGL-ES2 driver was not compiled in.", ELL_ERROR);
#endif
break;
case EDT_WEBGL1:
os::Printer::log("WebGL1 driver not supported on Win32 device.", ELL_ERROR);
break;
case video::EDT_SOFTWARE:
#ifdef _IRR_COMPILE_WITH_SOFTWARE_
switchToFullScreen();

View File

@ -29,6 +29,15 @@
#include "android_native_app_glue.h"
#endif
// Add as first line to a function to get info is was called once.
#define FIRST_CALL \
static bool first = true; \
if ( first ) \
{\
first = false; \
os::Printer::log(__FILE__, irr::core::stringc(__LINE__).c_str(), ELL_ERROR); \
}
namespace irr
{
namespace video
@ -36,7 +45,7 @@ namespace video
COGLES2Driver::COGLES2Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager) :
CNullDriver(io, params.WindowSize), COGLES2ExtensionHandler(), CacheHandler(0), MaterialRenderer2D(0), CurrentRenderMode(ERM_NONE),
ResetRenderStates(true), Transformation3DChanged(true), AntiAlias(params.AntiAlias), OGLES2ShaderPath(params.OGLES2ShaderPath),
ResetRenderStates(true), LockRenderStateMode(false), Transformation3DChanged(true), AntiAlias(params.AntiAlias), OGLES2ShaderPath(params.OGLES2ShaderPath),
ColorFormat(ECF_R8G8B8), Params(params), ContextManager(contextManager)
{
#ifdef _DEBUG
@ -65,9 +74,6 @@ COGLES2Driver::COGLES2Driver(const SIrrlichtCreationParameters& params, io::IFil
getProfiler().add(EPID_ES2_DRAW_SHADOW, L"shadows", L"ES2");
}
)
core::dimension2d<u32> windowSize(0, 0);
if (!ContextManager)
return;
@ -76,10 +82,6 @@ COGLES2Driver::COGLES2Driver(const SIrrlichtCreationParameters& params, io::IFil
ContextManager->generateContext();
ExposedData = ContextManager->getContext();
ContextManager->activateContext(ExposedData);
windowSize = params.WindowSize;
genericDriverInit(windowSize, params.Stencilbuffer);
}
COGLES2Driver::~COGLES2Driver()
@ -659,6 +661,7 @@ COGLES2Driver::~COGLES2Driver()
//! Draw hardware buffer
void COGLES2Driver::drawHardwareBuffer(SHWBufferLink *_HWBuffer)
{
FIRST_CALL;
if (!_HWBuffer)
return;
@ -719,6 +722,7 @@ COGLES2Driver::~COGLES2Driver()
const void* indexList, u32 primitiveCount,
E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)
{
FIRST_CALL;
if (!primitiveCount || !vertexCount)
return;
@ -876,6 +880,7 @@ COGLES2Driver::~COGLES2Driver()
const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect, SColor color,
bool useAlphaChannelOfTexture)
{
FIRST_CALL;
if (!texture)
return;
@ -1014,6 +1019,7 @@ COGLES2Driver::~COGLES2Driver()
const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect,
const video::SColor* const colors, bool useAlphaChannelOfTexture)
{
FIRST_CALL;
if (!texture)
return;
@ -1093,6 +1099,7 @@ COGLES2Driver::~COGLES2Driver()
void COGLES2Driver::draw2DImage(const video::ITexture* texture, u32 layer, bool flip)
{
FIRST_CALL;
chooseMaterial2D();
Material.TextureLayer[0].Texture = const_cast<ITexture*>(texture);
@ -1140,6 +1147,7 @@ COGLES2Driver::~COGLES2Driver()
const core::rect<s32>* clipRect,
SColor color, bool useAlphaChannelOfTexture)
{
FIRST_CALL;
if (!texture)
return;
@ -1302,6 +1310,7 @@ COGLES2Driver::~COGLES2Driver()
const core::rect<s32>* clipRect, SColor color,
bool useAlphaChannelOfTexture)
{
FIRST_CALL;
if (!texture)
return;
@ -1398,6 +1407,7 @@ COGLES2Driver::~COGLES2Driver()
const core::rect<s32>& position,
const core::rect<s32>* clip)
{
FIRST_CALL;
IRR_PROFILE(CProfileScope p1(EPID_ES2_DRAW_2DRECTANGLE);)
chooseMaterial2D();
@ -1444,6 +1454,7 @@ COGLES2Driver::~COGLES2Driver()
SColor colorLeftDown, SColor colorRightDown,
const core::rect<s32>* clip)
{
FIRST_CALL;
IRR_PROFILE(CProfileScope p1(EPID_ES2_DRAW_2DRECTANGLE);)
core::rect<s32> pos = position;
@ -1491,6 +1502,7 @@ COGLES2Driver::~COGLES2Driver()
void COGLES2Driver::draw2DLine(const core::position2d<s32>& start,
const core::position2d<s32>& end, SColor color)
{
FIRST_CALL;
IRR_PROFILE(CProfileScope p1(EPID_ES2_DRAW_2DLINE);)
if (start==end)
@ -1529,6 +1541,7 @@ COGLES2Driver::~COGLES2Driver()
//! Draws a pixel
void COGLES2Driver::drawPixel(u32 x, u32 y, const SColor &color)
{
FIRST_CALL;
const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
if (x > (u32)renderTargetSize.Width || y > (u32)renderTargetSize.Height)
return;
@ -1675,6 +1688,9 @@ COGLES2Driver::~COGLES2Driver()
{
IRR_PROFILE(CProfileScope p1(EPID_ES2_SET_RENDERSTATE_3D);)
if ( LockRenderStateMode )
return;
if (CurrentRenderMode != ERM_3D)
{
// Reset Texture Stages
@ -1961,18 +1977,21 @@ COGLES2Driver::~COGLES2Driver()
{
IRR_PROFILE(CProfileScope p1(EPID_ES2_SET_RENDERSTATE_2D);)
if (CurrentRenderMode != ERM_2D)
{
// unset last 3d material
if (CurrentRenderMode == ERM_3D)
{
if (static_cast<u32>(LastMaterial.MaterialType) < MaterialRenderers.size())
MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial();
}
if ( LockRenderStateMode )
return;
CurrentRenderMode = ERM_2D;
if (CurrentRenderMode != ERM_2D)
{
// unset last 3d material
if (CurrentRenderMode == ERM_3D)
{
if (static_cast<u32>(LastMaterial.MaterialType) < MaterialRenderers.size())
MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial();
}
CurrentRenderMode = ERM_2D;
}
MaterialRenderer2D->OnSetMaterial(Material, LastMaterial, true, 0);
LastMaterial = Material;
@ -2081,6 +2100,7 @@ COGLES2Driver::~COGLES2Driver()
//! Draws a shadow volume into the stencil buffer.
void COGLES2Driver::drawStencilShadowVolume(const core::array<core::vector3df>& triangles, bool zfail, u32 debugDataVisible)
{
FIRST_CALL;
IRR_PROFILE(CProfileScope p1(EPID_ES2_DRAW_SHADOW);)
const u32 count=triangles.size();
@ -2161,6 +2181,7 @@ COGLES2Driver::~COGLES2Driver()
video::SColor leftUpEdge, video::SColor rightUpEdge,
video::SColor leftDownEdge, video::SColor rightDownEdge)
{
FIRST_CALL;
IRR_PROFILE(CProfileScope p1(EPID_ES2_DRAW_SHADOW);)
if (!StencilBuffer)
@ -2208,6 +2229,7 @@ COGLES2Driver::~COGLES2Driver()
void COGLES2Driver::draw3DLine(const core::vector3df& start,
const core::vector3df& end, SColor color)
{
FIRST_CALL;
IRR_PROFILE(CProfileScope p1(EPID_ES2_DRAW_3DLINE);)
setRenderStates3DMode();
@ -2384,9 +2406,9 @@ COGLES2Driver::~COGLES2Driver()
bool COGLES2Driver::setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil)
{
if (target && target->getDriverType() != EDT_OGLES2)
if (target && target->getDriverType() != EDT_OGLES2 && target->getDriverType() != EDT_WEBGL1)
{
os::Printer::log("Fatal Error: Tried to set a render target not owned by this driver.", ELL_ERROR);
os::Printer::log("Fatal Error: Tried to set a render target not owned by OGLES2 driver.", ELL_ERROR);
return false;
}
@ -2858,7 +2880,9 @@ class IContextManager;
IVideoDriver* createOGLES2Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager)
{
#ifdef _IRR_COMPILE_WITH_OGLES2_
return new COGLES2Driver(params, io, contextManager);
COGLES2Driver* driver = new COGLES2Driver(params, io, contextManager);
driver->genericDriverInit(params.WindowSize, params.Stencilbuffer); // don't call in constructor, it uses virtual function calls of driver
return driver;
#else
return 0;
#endif // _IRR_COMPILE_WITH_OGLES2_

View File

@ -44,10 +44,13 @@ namespace video
class COGLES2Driver : public CNullDriver, public IMaterialRendererServices, public COGLES2ExtensionHandler
{
friend class COpenGLCoreTexture<COGLES2Driver>;
friend IVideoDriver* createOGLES2Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);
protected:
//! constructor (use createOGLES2Driver instead)
COGLES2Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);
public:
//! constructor
COGLES2Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);
//! destructor
virtual ~COGLES2Driver();
@ -315,9 +318,11 @@ namespace video
COGLES2CacheHandler* getCacheHandler() const;
private:
protected:
//! inits the opengl-es driver
bool genericDriverInit(const core::dimension2d<u32>& screenSize, bool stencilBuffer);
virtual bool genericDriverInit(const core::dimension2d<u32>& screenSize, bool stencilBuffer);
void chooseMaterial2D();
virtual ITexture* createDeviceDependentTexture(const io::path& name, IImage* image) _IRR_OVERRIDE_;
@ -332,7 +337,25 @@ namespace video
//! sets the needed renderstates
void setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel);
void chooseMaterial2D();
//! Prevent setRenderStateMode calls to do anything.
// hack to allow drawing meshbuffers in 2D mode.
// Better solution would be passing this flag through meshbuffers,
// but the way this is currently implemented in Irrlicht makes this tricky to implement
void lockRenderStateMode()
{
LockRenderStateMode = true;
}
//! Allow setRenderStateMode calls to work again
void unlockRenderStateMode()
{
LockRenderStateMode = false;
}
void draw2D3DVertexPrimitiveList(const void* vertices,
u32 vertexCount, const void* indexList, u32 primitiveCount,
E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType,
E_INDEX_TYPE iType, bool is3D);
void createMaterialRenderers();
@ -355,6 +378,7 @@ namespace video
E_RENDER_MODE CurrentRenderMode;
//! bool to make all renderstates reset if set to true.
bool ResetRenderStates;
bool LockRenderStateMode;
bool Transformation3DChanged;
u8 AntiAlias;
irr::io::path OGLES2ShaderPath;

View File

@ -2719,7 +2719,7 @@ bool COGLES1Driver::setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SCol
{
if (target && target->getDriverType() != EDT_OGLES1)
{
os::Printer::log("Fatal Error: Tried to set a render target not owned by this driver.", ELL_ERROR);
os::Printer::log("Fatal Error: Tried to set a render target not owned by OpenGL driver.", ELL_ERROR);
return false;
}

View File

@ -100,6 +100,8 @@ class COpenGLCoreCacheHandler
texture = 0;
os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR);
os::Printer::log("Texture type", irr::core::stringc((int)type), ELL_ERROR);
os::Printer::log("Driver (or cache handler) type", irr::core::stringc((int)DriverType), ELL_ERROR);
}
}

View File

@ -187,7 +187,7 @@ public:
if (LockImage)
LockImage->drop();
for (u32 i = 0; i < Image.size(); ++i)
Image[i]->drop();
}

View File

@ -0,0 +1,296 @@
// Copyright (C) 2017 Michael Zeilfelder
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in Irrlicht.h
#include "CWebGL1Driver.h"
#ifdef _IRR_COMPILE_WITH_WEBGL1_
#include "COpenGLCoreTexture.h"
#include "COpenGLCoreRenderTarget.h"
#include "COpenGLCoreCacheHandler.h"
#include "EVertexAttributes.h"
// Add as first line to a function to get info is was called once.
#define FIRST_CALL \
static bool first = true; \
if ( first ) \
{\
first = false; \
os::Printer::log(__FILE__, irr::core::stringc(__LINE__).c_str(), ELL_ERROR); \
}
namespace irr
{
namespace video
{
CWebGL1Driver::CWebGL1Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager) :
COGLES2Driver(params, io, contextManager)
, MBDraw2DRectangle(0), MBDraw2DImageBatch(0)
{
#ifdef _DEBUG
setDebugName("CWebGL1Driver");
#endif
setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false); // so far causing errors, have to figure out later
}
CWebGL1Driver::~CWebGL1Driver()
{
if ( MBDraw2DRectangle )
MBDraw2DRectangle->drop();
if ( MBDraw2DImageBatch )
MBDraw2DImageBatch->drop();
}
//! Returns type of video driver
E_DRIVER_TYPE CWebGL1Driver::getDriverType() const
{
return EDT_WEBGL1;
}
//! Draws a mesh buffer
void CWebGL1Driver::drawMeshBuffer(const scene::IMeshBuffer* mb)
{
if ( mb )
{
// OK - this is bad and I hope I can find a better solution.
// Basically casting away a const which shouldn't be cast away.
// Not a nice surprise for users to see their mesh changes I guess :-(
scene::IMeshBuffer* mbUglyHack = const_cast<scene::IMeshBuffer*>(mb);
// We can't allow any buffers which are not bound to some VBO.
if ( mb->getHardwareMappingHint_Vertex() == scene::EHM_NEVER)
mbUglyHack->setHardwareMappingHint(scene::EHM_STREAM, scene::EBT_VERTEX);
if ( mb->getHardwareMappingHint_Index() == scene::EHM_NEVER)
mbUglyHack->setHardwareMappingHint(scene::EHM_STREAM, scene::EBT_INDEX);
COGLES2Driver::drawMeshBuffer(mb);
}
}
//! draw a 2d rectangle
void CWebGL1Driver::draw2DRectangle(SColor color,
const core::rect<s32>& position,
const core::rect<s32>* clip)
{
FIRST_CALL;
chooseMaterial2D();
Material.TextureLayer[0].Texture = 0;
CacheHandler->getTextureCache().set(0, 0);
setRenderStates2DMode(color.getAlpha() < 255, false, false);
lockRenderStateMode();
core::rect<s32> pos = position;
if (clip)
pos.clipAgainst(*clip);
if (!pos.isValid())
return;
const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
f32 left = (f32)pos.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
f32 right = (f32)pos.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
f32 down = 2.f - (f32)pos.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
f32 top = 2.f - (f32)pos.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
if ( !MBDraw2DRectangle )
{
MBDraw2DRectangle = createSimpleMeshBuffer(4, scene::EPT_TRIANGLE_FAN);
}
MBDraw2DRectangle->Vertices[0] = S3DVertex(left, top, 0, 0, 0, 1, color, 0, 0);
MBDraw2DRectangle->Vertices[1] = S3DVertex(right, top, 0, 0, 0, 1, color, 0, 0);
MBDraw2DRectangle->Vertices[2] = S3DVertex(right, down, 0, 0, 0, 1, color, 0, 0);
MBDraw2DRectangle->Vertices[3] = S3DVertex(left, down, 0, 0, 0, 1, color, 0, 0);
MBDraw2DRectangle->setDirty(scene::EBT_VERTEX);
drawMeshBuffer(MBDraw2DRectangle);
unlockRenderStateMode();
}
void CWebGL1Driver::draw2DImageBatch(const video::ITexture* texture,
const core::array<core::position2d<s32> >& positions,
const core::array<core::rect<s32> >& sourceRects,
const core::rect<s32>* clipRect,
SColor color, bool useAlphaChannelOfTexture)
{
if (!texture)
return;
const irr::u32 drawCount = core::min_<u32>(positions.size(), sourceRects.size());
if ( !drawCount )
return;
if ( !MBDraw2DImageBatch)
{
// We can only allocate for one image, otherwise we would have to re-bind the buffer on every frame as it can change size
MBDraw2DImageBatch = createSimpleMeshBuffer(4, scene::EPT_TRIANGLE_FAN);
}
chooseMaterial2D();
Material.TextureLayer[0].Texture = const_cast<ITexture*>(texture);
if (!CacheHandler->getTextureCache().set(0, texture))
return;
setRenderStates2DMode(color.getAlpha() < 255, true, useAlphaChannelOfTexture);
lockRenderStateMode();
for (u32 i = 0; i < drawCount; i++)
{
core::position2d<s32> targetPos = positions[i];
core::position2d<s32> sourcePos = sourceRects[i].UpperLeftCorner;
// This needs to be signed as it may go negative.
core::dimension2d<s32> sourceSize(sourceRects[i].getSize());
if (clipRect)
{
if (targetPos.X < clipRect->UpperLeftCorner.X)
{
sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X;
if (sourceSize.Width <= 0)
continue;
sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X;
targetPos.X = clipRect->UpperLeftCorner.X;
}
if (targetPos.X + (s32)sourceSize.Width > clipRect->LowerRightCorner.X)
{
sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X;
if (sourceSize.Width <= 0)
continue;
}
if (targetPos.Y < clipRect->UpperLeftCorner.Y)
{
sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y;
if (sourceSize.Height <= 0)
continue;
sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y;
targetPos.Y = clipRect->UpperLeftCorner.Y;
}
if (targetPos.Y + (s32)sourceSize.Height > clipRect->LowerRightCorner.Y)
{
sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y;
if (sourceSize.Height <= 0)
continue;
}
}
// clip these coordinates
if (targetPos.X < 0)
{
sourceSize.Width += targetPos.X;
if (sourceSize.Width <= 0)
continue;
sourcePos.X -= targetPos.X;
targetPos.X = 0;
}
const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width)
{
sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width;
if (sourceSize.Width <= 0)
continue;
}
if (targetPos.Y < 0)
{
sourceSize.Height += targetPos.Y;
if (sourceSize.Height <= 0)
continue;
sourcePos.Y -= targetPos.Y;
targetPos.Y = 0;
}
if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height)
{
sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height;
if (sourceSize.Height <= 0)
continue;
}
// ok, we've clipped everything.
// now draw it.
core::rect<f32> tcoords;
tcoords.UpperLeftCorner.X = (((f32)sourcePos.X)) / texture->getOriginalSize().Width ;
tcoords.UpperLeftCorner.Y = (((f32)sourcePos.Y)) / texture->getOriginalSize().Height;
tcoords.LowerRightCorner.X = tcoords.UpperLeftCorner.X + ((f32)(sourceSize.Width) / texture->getOriginalSize().Width);
tcoords.LowerRightCorner.Y = tcoords.UpperLeftCorner.Y + ((f32)(sourceSize.Height) / texture->getOriginalSize().Height);
const core::rect<s32> poss(targetPos, sourceSize);
f32 left = (f32)poss.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
f32 right = (f32)poss.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
f32 down = 2.f - (f32)poss.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
f32 top = 2.f - (f32)poss.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
MBDraw2DImageBatch->Vertices[0] = S3DVertex(left, top, 0, 0, 0, 1, color, tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);
MBDraw2DImageBatch->Vertices[1] = S3DVertex(right, top, 0, 0, 0, 1, color, tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);
MBDraw2DImageBatch->Vertices[2] = S3DVertex(right, down, 0, 0, 0, 1, color, tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);
MBDraw2DImageBatch->Vertices[3] = S3DVertex(left, down, 0, 0, 0, 1, color, tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);
MBDraw2DImageBatch->setDirty(scene::EBT_VERTEX);
drawMeshBuffer(MBDraw2DImageBatch);
}
unlockRenderStateMode();
}
scene::SMeshBuffer* CWebGL1Driver::createSimpleMeshBuffer(irr::u32 numVertices, scene::E_PRIMITIVE_TYPE primitiveType, scene::E_HARDWARE_MAPPING vertexMappingHint, scene::E_HARDWARE_MAPPING indexMappingHint) const
{
scene::SMeshBuffer* mbResult = new scene::SMeshBuffer();
mbResult->Vertices.set_used(numVertices);
mbResult->Indices.set_used(numVertices);
for ( irr::u32 i=0; i < numVertices; ++i )
mbResult->Indices[i] = i;
mbResult->setPrimitiveType(primitiveType);
mbResult->setHardwareMappingHint(vertexMappingHint, scene::EBT_VERTEX);
mbResult->setHardwareMappingHint(indexMappingHint, scene::EBT_INDEX);
mbResult->setDirty();
return mbResult;
}
} // end namespace video
} // end namespace irr
#endif // _IRR_COMPILE_WITH_WEBGL1_
namespace irr
{
namespace video
{
#ifndef _IRR_COMPILE_WITH_WEBGL1_
class IVideoDriver;
class IContextManager;
#endif
IVideoDriver* createWebGL1Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager)
{
#ifdef _IRR_COMPILE_WITH_WEBGL1_
CWebGL1Driver* driver = new CWebGL1Driver(params, io, contextManager);
driver->genericDriverInit(params.WindowSize, params.Stencilbuffer); // don't call in constructor, it uses virtual function calls of driver
return driver;
#else
return 0;
#endif // _IRR_COMPILE_WITH_WEBGL1_
}
} // end namespace
} // end namespace

View File

@ -0,0 +1,77 @@
// Copyright (C) 2017 Michael Zeilfelder
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in Irrlicht.h
#ifndef __C_WEBGL1_DRIVER_H_INCLUDED__
#define __C_WEBGL1_DRIVER_H_INCLUDED__
#include "IrrCompileConfig.h"
#include "SIrrCreationParameters.h"
#ifdef _IRR_COMPILE_WITH_WEBGL1_
#include "COGLES2Driver.h"
#include "CMeshBuffer.h"
#include "EHardwareBufferFlags.h"
namespace irr
{
namespace video
{
//! WebGL friendly subset of OGL ES 2.0.
//! Written for use with emscripten
class CWebGL1Driver : public COGLES2Driver
{
friend class COpenGLCoreTexture<CWebGL1Driver>;
friend IVideoDriver* createWebGL1Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);
protected:
//! constructor
CWebGL1Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);
public:
//! destructor
virtual ~CWebGL1Driver();
//! Returns type of video driver
virtual E_DRIVER_TYPE getDriverType() const _IRR_OVERRIDE_;
//! is vbo recommended on this mesh?
virtual bool isHardwareBufferRecommend(const scene::IMeshBuffer* mb) _IRR_OVERRIDE_
{
return true; // All buffers must be bound, WebGL doesn't allow sending unbound buffers at all.
}
//! Draws a mesh buffer
virtual void drawMeshBuffer(const scene::IMeshBuffer* mb) _IRR_OVERRIDE_;
//! draw an 2d rectangle
virtual void draw2DRectangle(SColor color, const core::rect<s32>& pos,
const core::rect<s32>* clip = 0) _IRR_OVERRIDE_;
void draw2DImageBatch(const video::ITexture* texture,
const core::array<core::position2d<s32> >& positions,
const core::array<core::rect<s32> >& sourceRects,
const core::rect<s32>* clipRect,
SColor color,
bool useAlphaChannelOfTexture) _IRR_OVERRIDE_;
protected:
// create a meshbuffer which has as many vertices as indices
scene::SMeshBuffer* createSimpleMeshBuffer(irr::u32 numVertices, scene::E_PRIMITIVE_TYPE primitiveType, scene::E_HARDWARE_MAPPING vertexMappingHint=scene::EHM_STREAM, scene::E_HARDWARE_MAPPING indexMappingHint=scene::EHM_STATIC) const;
private:
// Because we can't have unbound buffers in webgl we give all drawing functions bound buffers
// which they can use.
scene::SMeshBuffer* MBDraw2DRectangle;
scene::SMeshBuffer* MBDraw2DImageBatch;
};
} // end namespace video
} // end namespace irr
#endif // _IRR_COMPILE_WITH_WEBGL1_
#endif // __C_WEBGL1_DRIVER_H_INCLUDED__

View File

@ -38,7 +38,10 @@ IRRMESHOBJ = $(IRRMESHLOADER) $(IRRMESHWRITER) \
IRROBJ = CBillboardSceneNode.o CCameraSceneNode.o CDummyTransformationSceneNode.o CEmptySceneNode.o CGeometryCreator.o CLightSceneNode.o CMeshManipulator.o CMetaTriangleSelector.o COctreeSceneNode.o COctreeTriangleSelector.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 CSceneLoaderIrr.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 CParticleScaleAffector.o
IRRANIMOBJ = CSceneNodeAnimatorCameraFPS.o CSceneNodeAnimatorCameraMaya.o CSceneNodeAnimatorCollisionResponse.o CSceneNodeAnimatorDelete.o CSceneNodeAnimatorFlyCircle.o CSceneNodeAnimatorFlyStraight.o CSceneNodeAnimatorFollowSpline.o CSceneNodeAnimatorRotation.o CSceneNodeAnimatorTexture.o
IRRDRVROBJ = CNullDriver.o COpenGLCacheHandler.o COpenGLDriver.o COpenGLNormalMapRenderer.o COpenGLParallaxMapRenderer.o COpenGLShaderMaterialRenderer.o COpenGLSLMaterialRenderer.o COpenGLExtensionHandler.o CD3D9Driver.o CD3D9HLSLMaterialRenderer.o CD3D9NormalMapRenderer.o CD3D9ParallaxMapRenderer.o CD3D9ShaderMaterialRenderer.o CD3D9Texture.o COGLESDriver.o COGLESExtensionHandler.o COGLES2Driver.o COGLES2ExtensionHandler.o COGLES2FixedPipelineRenderer.o COGLES2MaterialRenderer.o COGLES2NormalMapRenderer.o COGLES2ParallaxMapRenderer.o COGLES2Renderer2D.o CGLXManager.o CWGLManager.o CEGLManager.o
IRRDRVROBJ = CNullDriver.o COpenGLCacheHandler.o COpenGLDriver.o COpenGLNormalMapRenderer.o COpenGLParallaxMapRenderer.o COpenGLShaderMaterialRenderer.o COpenGLSLMaterialRenderer.o COpenGLExtensionHandler.o \
CD3D9Driver.o CD3D9HLSLMaterialRenderer.o CD3D9NormalMapRenderer.o CD3D9ParallaxMapRenderer.o CD3D9ShaderMaterialRenderer.o CD3D9Texture.o \
COGLESDriver.o COGLESExtensionHandler.o COGLES2Driver.o COGLES2ExtensionHandler.o COGLES2FixedPipelineRenderer.o COGLES2MaterialRenderer.o COGLES2NormalMapRenderer.o COGLES2ParallaxMapRenderer.o COGLES2Renderer2D.o CWebGL1Driver.o \
CGLXManager.o CWGLManager.o CEGLManager.o
IRRIMAGEOBJ = CColorConverter.o CImage.o CImageLoaderBMP.o CImageLoaderDDS.o CImageLoaderJPG.o CImageLoaderPCX.o CImageLoaderPNG.o CImageLoaderPSD.o CImageLoaderPVR.o CImageLoaderTGA.o CImageLoaderPPM.o CImageLoaderWAL.o CImageLoaderRGB.o \
CImageWriterBMP.o CImageWriterJPG.o CImageWriterPCX.o CImageWriterPNG.o CImageWriterPPM.o CImageWriterPSD.o CImageWriterTGA.o
IRRVIDEOOBJ = CVideoModeList.o CFPSCounter.o $(IRRDRVROBJ) $(IRRIMAGEOBJ)