put OpenGL support under conditional compilation: version(USE_OPENGL)

This commit is contained in:
Vadim Lopatin 2014-03-12 10:29:06 +04:00
parent 0cff3908fe
commit 3113577041
8 changed files with 213 additions and 166 deletions

View File

@ -59,8 +59,10 @@ struct Rect {
align(1) align(1)
struct Glyph struct Glyph
{ {
///< 0: unique id of glyph (for drawing in hardware accelerated scenes) version (USE_OPENGL) {
uint id; ///< 0: unique id of glyph (for drawing in hardware accelerated scenes)
uint id;
}
///< 4: width of glyph black box ///< 4: width of glyph black box
ubyte blackBoxX; ubyte blackBoxX;
///< 5: height of glyph black box ///< 5: height of glyph black box

View File

@ -46,20 +46,26 @@ struct NinePatch {
Rect padding; Rect padding;
} }
/// non thread safe version (USE_OPENGL) {
private __gshared uint drawBufIdGenerator = 0; /// non thread safe
private __gshared uint drawBufIdGenerator = 0;
}
/// drawing buffer - image container which allows to perform some drawing operations /// drawing buffer - image container which allows to perform some drawing operations
class DrawBuf : RefCountedObject { class DrawBuf : RefCountedObject {
protected uint _id;
protected Rect _clipRect; protected Rect _clipRect;
protected NinePatch * _ninePatch; protected NinePatch * _ninePatch;
@property uint id() { version (USE_OPENGL) {
return _id; protected uint _id;
/// unique ID of drawbug instance, for using with hardware accelerated rendering for caching
@property uint id() { return _id; }
} }
this() { this() {
_id = drawBufIdGenerator++; version (USE_OPENGL) {
_id = drawBufIdGenerator++;
}
} }
protected void function(uint) _onDestroyCallback; protected void function(uint) _onDestroyCallback;
@property void onDestroyCallback(void function(uint) callback) { _onDestroyCallback = callback; } @property void onDestroyCallback(void function(uint) callback) { _onDestroyCallback = callback; }

View File

@ -18,14 +18,16 @@ enum FontWeight : int {
Bold = 800 Bold = 800
} }
private __gshared void function(uint id) _glyphDestroyCallback; version (USE_OPENGL) {
/// get glyph destroy callback (to cleanup OpenGL caches) private __gshared void function(uint id) _glyphDestroyCallback;
@property void function(uint id) glyphDestroyCallback() { return _glyphDestroyCallback; } /// get glyph destroy callback (to cleanup OpenGL caches)
/// set glyph destroy callback (to cleanup OpenGL caches) @property void function(uint id) glyphDestroyCallback() { return _glyphDestroyCallback; }
@property void glyphDestroyCallback(void function(uint id) callback) { _glyphDestroyCallback = callback; } /// set glyph destroy callback (to cleanup OpenGL caches)
@property void glyphDestroyCallback(void function(uint id) callback) { _glyphDestroyCallback = callback; }
private __gshared uint _nextGlyphId; private __gshared uint _nextGlyphId;
uint nextGlyphId() { return _nextGlyphId++; } uint nextGlyphId() { return _nextGlyphId++; }
}
struct GlyphCache struct GlyphCache
{ {
@ -66,10 +68,12 @@ struct GlyphCache
void cleanup() { void cleanup() {
uint dst = 0; uint dst = 0;
// notify about destroyed glyphs // notify about destroyed glyphs
if (_glyphDestroyCallback !is null) version (USE_OPENGL) {
for (uint src = 0; src < _len; src++) if (_glyphDestroyCallback !is null)
if (_data[src].lastUsage == 0) for (uint src = 0; src < _len; src++)
_glyphDestroyCallback(_data[src].id); if (_data[src].lastUsage == 0)
_glyphDestroyCallback(_data[src].id);
}
for (uint src = 0; src < _len; src++) { for (uint src = 0; src < _len; src++) {
if (_data[src].lastUsage != 0) { if (_data[src].lastUsage != 0) {
_data[src].lastUsage = 0; _data[src].lastUsage = 0;
@ -83,9 +87,11 @@ struct GlyphCache
// removes all entries // removes all entries
void clear() { void clear() {
if (_glyphDestroyCallback !is null) version (USE_OPENGL) {
for (uint src = 0; src < _len; src++) if (_glyphDestroyCallback !is null)
_glyphDestroyCallback(_data[src].id); for (uint src = 0; src < _len; src++)
_glyphDestroyCallback(_data[src].id);
}
_data = null; _data = null;
_len = 0; _len = 0;
} }

View File

@ -1,5 +1,7 @@
module dlangui.graphics.gldrawbuf; module dlangui.graphics.gldrawbuf;
version (USE_OPENGL) {
import dlangui.graphics.drawbuf; import dlangui.graphics.drawbuf;
import dlangui.core.logger; import dlangui.core.logger;
private import dlangui.graphics.glsupport; private import dlangui.graphics.glsupport;
@ -819,7 +821,7 @@ public:
} }
~this() { ~this() {
} }
}; }
}

View File

@ -1,5 +1,7 @@
module dlangui.graphics.glsupport; module dlangui.graphics.glsupport;
version(USE_OPENGL) {
import dlangui.core.logger; import dlangui.core.logger;
private import derelict.opengl3.gl3; private import derelict.opengl3.gl3;
//private import gl3n.linalg; //private import gl3n.linalg;
@ -657,3 +659,6 @@ void setRotation(int x, int y, int rotationAngle) {
matrix2.copyDataTo(m); matrix2.copyDataTo(m);
*/ */
} }
}

View File

@ -51,13 +51,15 @@ public class Platform {
abstract public int enterMessageLoop(); abstract public int enterMessageLoop();
} }
private __gshared bool _OPENGL_ENABLED = false; version (USE_OPENGL) {
/// check if hardware acceleration is enabled private __gshared bool _OPENGL_ENABLED = false;
@property bool openglEnabled() { return _OPENGL_ENABLED; } /// check if hardware acceleration is enabled
/// call on app initialization if OpenGL support is detected @property bool openglEnabled() { return _OPENGL_ENABLED; }
void setOpenglEnabled() { /// call on app initialization if OpenGL support is detected
_OPENGL_ENABLED = true; void setOpenglEnabled() {
glyphDestroyCallback = &onGlyphDestroyedCallback; _OPENGL_ENABLED = true;
glyphDestroyCallback = &onGlyphDestroyedCallback;
}
} }
version (Windows) { version (Windows) {

View File

@ -131,7 +131,9 @@ class Win32Font : Font {
return null; return null;
Glyph g; Glyph g;
g.id = nextGlyphId(); version (USE_OPENGL) {
g.id = nextGlyphId();
}
g.blackBoxX = cast(ubyte)metrics.gmBlackBoxX; g.blackBoxX = cast(ubyte)metrics.gmBlackBoxX;
g.blackBoxY = cast(ubyte)metrics.gmBlackBoxY; g.blackBoxY = cast(ubyte)metrics.gmBlackBoxY;
g.originX = cast(byte)metrics.gmptGlyphOrigin.x; g.originX = cast(byte)metrics.gmptGlyphOrigin.x;

View File

@ -18,7 +18,6 @@ import dlangui.graphics.images;
import dlangui.graphics.fonts; import dlangui.graphics.fonts;
import dlangui.graphics.glsupport; import dlangui.graphics.glsupport;
import dlangui.core.logger; import dlangui.core.logger;
//import derelict.opengl3.wgl;
pragma(lib, "gdi32.lib"); pragma(lib, "gdi32.lib");
pragma(lib, "user32.lib"); pragma(lib, "user32.lib");
@ -31,95 +30,97 @@ immutable WIN_CLASS_NAME = "DLANGUI_APP";
__gshared HINSTANCE _hInstance; __gshared HINSTANCE _hInstance;
__gshared int _cmdShow; __gshared int _cmdShow;
bool setupPixelFormat(HDC hDC) version (USE_OPENGL) {
{ bool setupPixelFormat(HDC hDC)
PIXELFORMATDESCRIPTOR pfd = {
PIXELFORMATDESCRIPTOR.sizeof, /* size */
1, /* version */
PFD_SUPPORT_OPENGL |
PFD_DRAW_TO_WINDOW |
PFD_DOUBLEBUFFER, /* support double-buffering */
PFD_TYPE_RGBA, /* color type */
16, /* prefered color depth */
0, 0, 0, 0, 0, 0, /* color bits (ignored) */
0, /* no alpha buffer */
0, /* alpha bits (ignored) */
0, /* no accumulation buffer */
0, 0, 0, 0, /* accum bits (ignored) */
16, /* depth buffer */
0, /* no stencil buffer */
0, /* no auxiliary buffers */
0, /* main layer PFD_MAIN_PLANE */
0, /* reserved */
0, 0, 0, /* no layer, visible, damage masks */
};
int pixelFormat;
pixelFormat = ChoosePixelFormat(hDC, &pfd);
if (pixelFormat == 0) {
Log.e("ChoosePixelFormat failed.");
return false;
}
if (SetPixelFormat(hDC, pixelFormat, &pfd) != TRUE) {
Log.e("SetPixelFormat failed.");
return false;
}
return true;
}
HPALETTE setupPalette(HDC hDC)
{
import core.stdc.stdlib;
HPALETTE hPalette = NULL;
int pixelFormat = GetPixelFormat(hDC);
PIXELFORMATDESCRIPTOR pfd;
LOGPALETTE* pPal;
int paletteSize;
DescribePixelFormat(hDC, pixelFormat, PIXELFORMATDESCRIPTOR.sizeof, &pfd);
if (pfd.dwFlags & PFD_NEED_PALETTE) {
paletteSize = 1 << pfd.cColorBits;
} else {
return null;
}
pPal = cast(LOGPALETTE*)
malloc(LOGPALETTE.sizeof + paletteSize * PALETTEENTRY.sizeof);
pPal.palVersion = 0x300;
pPal.palNumEntries = cast(ushort)paletteSize;
/* build a simple RGB color palette */
{ {
int redMask = (1 << pfd.cRedBits) - 1; PIXELFORMATDESCRIPTOR pfd = {
int greenMask = (1 << pfd.cGreenBits) - 1; PIXELFORMATDESCRIPTOR.sizeof, /* size */
int blueMask = (1 << pfd.cBlueBits) - 1; 1, /* version */
int i; PFD_SUPPORT_OPENGL |
PFD_DRAW_TO_WINDOW |
PFD_DOUBLEBUFFER, /* support double-buffering */
PFD_TYPE_RGBA, /* color type */
16, /* prefered color depth */
0, 0, 0, 0, 0, 0, /* color bits (ignored) */
0, /* no alpha buffer */
0, /* alpha bits (ignored) */
0, /* no accumulation buffer */
0, 0, 0, 0, /* accum bits (ignored) */
16, /* depth buffer */
0, /* no stencil buffer */
0, /* no auxiliary buffers */
0, /* main layer PFD_MAIN_PLANE */
0, /* reserved */
0, 0, 0, /* no layer, visible, damage masks */
};
int pixelFormat;
for (i=0; i<paletteSize; ++i) { pixelFormat = ChoosePixelFormat(hDC, &pfd);
pPal.palPalEntry[i].peRed = cast(ubyte)( if (pixelFormat == 0) {
(((i >> pfd.cRedShift) & redMask) * 255) / redMask); Log.e("ChoosePixelFormat failed.");
pPal.palPalEntry[i].peGreen = cast(ubyte)( return false;
(((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask);
pPal.palPalEntry[i].peBlue = cast(ubyte)(
(((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask);
pPal.palPalEntry[i].peFlags = 0;
} }
if (SetPixelFormat(hDC, pixelFormat, &pfd) != TRUE) {
Log.e("SetPixelFormat failed.");
return false;
}
return true;
} }
hPalette = CreatePalette(pPal); HPALETTE setupPalette(HDC hDC)
free(pPal); {
import core.stdc.stdlib;
HPALETTE hPalette = NULL;
int pixelFormat = GetPixelFormat(hDC);
PIXELFORMATDESCRIPTOR pfd;
LOGPALETTE* pPal;
int paletteSize;
if (hPalette) { DescribePixelFormat(hDC, pixelFormat, PIXELFORMATDESCRIPTOR.sizeof, &pfd);
SelectPalette(hDC, hPalette, FALSE);
RealizePalette(hDC); if (pfd.dwFlags & PFD_NEED_PALETTE) {
paletteSize = 1 << pfd.cColorBits;
} else {
return null;
}
pPal = cast(LOGPALETTE*)
malloc(LOGPALETTE.sizeof + paletteSize * PALETTEENTRY.sizeof);
pPal.palVersion = 0x300;
pPal.palNumEntries = cast(ushort)paletteSize;
/* build a simple RGB color palette */
{
int redMask = (1 << pfd.cRedBits) - 1;
int greenMask = (1 << pfd.cGreenBits) - 1;
int blueMask = (1 << pfd.cBlueBits) - 1;
int i;
for (i=0; i<paletteSize; ++i) {
pPal.palPalEntry[i].peRed = cast(ubyte)(
(((i >> pfd.cRedShift) & redMask) * 255) / redMask);
pPal.palPalEntry[i].peGreen = cast(ubyte)(
(((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask);
pPal.palPalEntry[i].peBlue = cast(ubyte)(
(((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask);
pPal.palPalEntry[i].peFlags = 0;
}
}
hPalette = CreatePalette(pPal);
free(pPal);
if (hPalette) {
SelectPalette(hDC, hPalette, FALSE);
RealizePalette(hDC);
}
return hPalette;
} }
return hPalette; private __gshared bool DERELICT_GL3_RELOADED = false;
} }
private __gshared bool DERELICT_GL3_RELOADED = false;
class Win32Window : Window { class Win32Window : Window {
private HWND _hwnd; private HWND _hwnd;
@ -142,56 +143,62 @@ class Win32Window : Window {
null, // window menu handle null, // window menu handle
_hInstance, // program instance handle _hInstance, // program instance handle
cast(void*)this); // creation parameters cast(void*)this); // creation parameters
/* initialize OpenGL rendering */
HDC hDC = GetDC(_hwnd);
if (!DERELICT_GL3_RELOADED || openglEnabled) {
if (setupPixelFormat(hDC)) {
_hPalette = setupPalette(hDC);
_hGLRC = wglCreateContext(hDC);
if (_hGLRC) {
wglMakeCurrent(hDC, _hGLRC);
if (!DERELICT_GL3_RELOADED) { version (USE_OPENGL) {
// run this code only once
DERELICT_GL3_RELOADED = true; /* initialize OpenGL rendering */
try { HDC hDC = GetDC(_hwnd);
import derelict.opengl3.gl3;
DerelictGL3.reload(); if (!DERELICT_GL3_RELOADED || openglEnabled) {
// successful if (setupPixelFormat(hDC)) {
if (initShaders()) { _hPalette = setupPalette(hDC);
setOpenglEnabled(); _hGLRC = wglCreateContext(hDC);
useOpengl = true; if (_hGLRC) {
} else { wglMakeCurrent(hDC, _hGLRC);
Log.e("Failed to compile shaders");
if (!DERELICT_GL3_RELOADED) {
// run this code only once
DERELICT_GL3_RELOADED = true;
try {
import derelict.opengl3.gl3;
DerelictGL3.reload();
// successful
if (initShaders()) {
setOpenglEnabled();
useOpengl = true;
} else {
Log.e("Failed to compile shaders");
}
} catch (Exception e) {
Log.e("Derelict exception", e);
} }
} catch (Exception e) { } else {
Log.e("Derelict exception", e); if (initShaders()) {
setOpenglEnabled();
useOpengl = true;
} else {
Log.e("Failed to compile shaders");
}
} }
} else {
if (initShaders()) {
setOpenglEnabled();
useOpengl = true;
} else {
Log.e("Failed to compile shaders");
}
} }
} else {
Log.e("Pixelformat failed");
// disable GL
DERELICT_GL3_RELOADED = true;
} }
} else {
Log.e("Pixelformat failed");
// disable GL
DERELICT_GL3_RELOADED = true;
} }
} }
} }
~this() { ~this() {
Log.d("Window destructor"); Log.d("Window destructor");
import derelict.opengl3.wgl; version (USE_OPENGL) {
if (_hGLRC) { import derelict.opengl3.wgl;
uninitShaders(); if (_hGLRC) {
wglMakeCurrent (null, null) ; uninitShaders();
wglDeleteContext(_hGLRC); wglMakeCurrent (null, null) ;
_hGLRC = null; wglDeleteContext(_hGLRC);
_hGLRC = null;
}
} }
if (_hwnd) if (_hwnd)
DestroyWindow(_hwnd); DestroyWindow(_hwnd);
@ -225,9 +232,20 @@ class Win32Window : Window {
void onDestroy() { void onDestroy() {
Log.d("Window onDestroy"); Log.d("Window onDestroy");
} }
void onPaint() {
Log.d("onPaint()"); private void paintUsingGDI() {
if (useOpengl && _hGLRC) { PAINTSTRUCT ps;
HDC hdc = BeginPaint(_hwnd, &ps);
scope(exit) EndPaint(_hwnd, &ps);
Win32ColorDrawBuf buf = getDrawBuf();
buf.fill(0x808080);
onDraw(buf);
buf.drawTo(hdc, 0, 0);
}
version (USE_OPENGL) {
private void paintUsingOpenGL() {
// hack to stop infinite WM_PAINT loop // hack to stop infinite WM_PAINT loop
PAINTSTRUCT ps; PAINTSTRUCT ps;
HDC hdc2 = BeginPaint(_hwnd, &ps); HDC hdc2 = BeginPaint(_hwnd, &ps);
@ -268,15 +286,19 @@ class Win32Window : Window {
//Log.d("onPaint() end drawing opengl"); //Log.d("onPaint() end drawing opengl");
SwapBuffers(hdc); SwapBuffers(hdc);
wglMakeCurrent(hdc, null); wglMakeCurrent(hdc, null);
} else { }
PAINTSTRUCT ps; }
HDC hdc = BeginPaint(_hwnd, &ps);
scope(exit) EndPaint(_hwnd, &ps);
Win32ColorDrawBuf buf = getDrawBuf(); void onPaint() {
buf.fill(0x808080); Log.d("onPaint()");
onDraw(buf); version (USE_OPENGL) {
buf.drawTo(hdc, 0, 0); if (useOpengl && _hGLRC) {
paintUsingOpenGL();
} else {
paintUsingGDI();
}
} else {
paintUsingGDI();
} }
} }
} }
@ -391,7 +413,7 @@ int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int
Win32FontManager fontMan = new Win32FontManager(); Win32FontManager fontMan = new Win32FontManager();
FontManager.instance = fontMan; FontManager.instance = fontMan;
{ version (USE_OPENGL) {
import derelict.opengl3.gl3; import derelict.opengl3.gl3;
DerelictGL3.load(); DerelictGL3.load();