diff --git a/dlanguilib.sln b/dlanguilib.sln index b699e1c1..24d76de8 100644 --- a/dlanguilib.sln +++ b/dlanguilib.sln @@ -10,20 +10,6 @@ Project("{002A2DE9-8BB6-484D-9802-7E4AD4084715}") = "example1", "examples\exampl EndProject Project("{002A2DE9-8BB6-484D-9802-7E4AD4084715}") = "test", "examples\test\test.visualdproj", "{BE84DF39-64E6-449D-89E0-8E92404003CB}" EndProject -Project("{002A2DE9-8BB6-484D-9802-7E4AD4084715}") = "DerelictUtil", "3rdparty\DerelictUtil\DerelictUtil.visualdproj", "{B83A0CDA-F51B-46C0-A23C-65F5CA2994F0}" -EndProject -Project("{002A2DE9-8BB6-484D-9802-7E4AD4084715}") = "DerelictGL3", "3rdparty\DerelictGL3\DerelictGL3.visualdproj", "{2636C1E1-FF8E-4424-B3F9-764DA9A4B556}" - ProjectSection(ProjectDependencies) = postProject - {B83A0CDA-F51B-46C0-A23C-65F5CA2994F0} = {B83A0CDA-F51B-46C0-A23C-65F5CA2994F0} - EndProjectSection -EndProject -Project("{002A2DE9-8BB6-484D-9802-7E4AD4084715}") = "DerelictFT", "3rdparty\DerelictFT\DerelictFT.visualdproj", "{6E4F189A-D7B0-4ABD-8942-20E10C309D01}" - ProjectSection(ProjectDependencies) = postProject - {B83A0CDA-F51B-46C0-A23C-65F5CA2994F0} = {B83A0CDA-F51B-46C0-A23C-65F5CA2994F0} - EndProjectSection -EndProject -Project("{002A2DE9-8BB6-484D-9802-7E4AD4084715}") = "gl3n", "3rdparty\gl3n\gl3n.visualdproj", "{6EDE8E99-6487-4505-94E9-C717112526A4}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -42,22 +28,6 @@ Global {BE84DF39-64E6-449D-89E0-8E92404003CB}.Debug|Win32.Build.0 = Debug|Win32 {BE84DF39-64E6-449D-89E0-8E92404003CB}.Release|Win32.ActiveCfg = Release|Win32 {BE84DF39-64E6-449D-89E0-8E92404003CB}.Release|Win32.Build.0 = Release|Win32 - {B83A0CDA-F51B-46C0-A23C-65F5CA2994F0}.Debug|Win32.ActiveCfg = Debug|Win32 - {B83A0CDA-F51B-46C0-A23C-65F5CA2994F0}.Debug|Win32.Build.0 = Debug|Win32 - {B83A0CDA-F51B-46C0-A23C-65F5CA2994F0}.Release|Win32.ActiveCfg = Release|Win32 - {B83A0CDA-F51B-46C0-A23C-65F5CA2994F0}.Release|Win32.Build.0 = Release|Win32 - {2636C1E1-FF8E-4424-B3F9-764DA9A4B556}.Debug|Win32.ActiveCfg = Debug|Win32 - {2636C1E1-FF8E-4424-B3F9-764DA9A4B556}.Debug|Win32.Build.0 = Debug|Win32 - {2636C1E1-FF8E-4424-B3F9-764DA9A4B556}.Release|Win32.ActiveCfg = Release|Win32 - {2636C1E1-FF8E-4424-B3F9-764DA9A4B556}.Release|Win32.Build.0 = Release|Win32 - {6E4F189A-D7B0-4ABD-8942-20E10C309D01}.Debug|Win32.ActiveCfg = Debug|Win32 - {6E4F189A-D7B0-4ABD-8942-20E10C309D01}.Debug|Win32.Build.0 = Debug|Win32 - {6E4F189A-D7B0-4ABD-8942-20E10C309D01}.Release|Win32.ActiveCfg = Release|Win32 - {6E4F189A-D7B0-4ABD-8942-20E10C309D01}.Release|Win32.Build.0 = Release|Win32 - {6EDE8E99-6487-4505-94E9-C717112526A4}.Debug|Win32.ActiveCfg = Debug|Win32 - {6EDE8E99-6487-4505-94E9-C717112526A4}.Debug|Win32.Build.0 = Debug|Win32 - {6EDE8E99-6487-4505-94E9-C717112526A4}.Release|Win32.ActiveCfg = Release|Win32 - {6EDE8E99-6487-4505-94E9-C717112526A4}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/dlanguilib.visualdproj b/dlanguilib.visualdproj index ccc444cb..e43d4261 100644 --- a/dlanguilib.visualdproj +++ b/dlanguilib.visualdproj @@ -47,7 +47,7 @@ 0 0 $(DMDInstallDir)windows\bin\dmd.exe - 3rdparty 3rdparty/libpng/source + 3rdparty 3rdparty/libpng/source ../DerelictGL3/source ../DerelictUtil/source $(ConfigurationName) $(OutDir) @@ -141,7 +141,7 @@ 0 0 $(DMDInstallDir)windows\bin\dmd.exe - 3rdparty 3rdparty/libpng/source + 3rdparty 3rdparty/libpng/source ../DerelictGL3/source $(ConfigurationName) $(OutDir) @@ -190,6 +190,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -258,6 +294,7 @@ + diff --git a/examples/example1/example1.visualdproj b/examples/example1/example1.visualdproj index f59270ab..1550e39d 100644 --- a/examples/example1/example1.visualdproj +++ b/examples/example1/example1.visualdproj @@ -47,7 +47,7 @@ 0 0 $(DMDInstallDir)windows\bin\dmd.exe - $(SolutionDir)/src $(SolutionDir)/3rdparty $(SolutionDir)/3rdparty/libpng/source + $(SolutionDir)/src $(SolutionDir)/3rdparty $(SolutionDir)/3rdparty/libpng/source $(SolutionDir)/../DerelictGL3/source $(SolutionDir)/../DerelictUtil/source $(SolutionDir)/../gl3n $(ConfigurationName) $(OutDir) @@ -84,7 +84,7 @@ libpng15.lib dlangui.lib phobos.lib ole32.lib kernel32.lib user32.lib comctl32.lib comdlg32.lib dlangui.lib - ../../Debug ../../3rdparty/libpng/lib 3rdparty/libpng/lib + ../../Debug ../../3rdparty/libpng/lib 3rdparty/libpng/lib ../../../DerelictOpenGL3/source $(OutDir)\$(ProjectName).exe diff --git a/examples/example1/winmain.d b/examples/example1/winmain.d index d93f1c0c..8ecc3ec9 100644 --- a/examples/example1/winmain.d +++ b/examples/example1/winmain.d @@ -5,8 +5,8 @@ import std.stdio; /// workaround for link issue when WinMain is located in library version(Windows) { - import win32.windows; - import dlangui.platforms.windows.winapp; + private import win32.windows; + private import dlangui.platforms.windows.winapp; extern (Windows) int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) diff --git a/src/dlangui/graphics/glsupport.d b/src/dlangui/graphics/glsupport.d new file mode 100644 index 00000000..eace601a --- /dev/null +++ b/src/dlangui/graphics/glsupport.d @@ -0,0 +1,490 @@ +module dlangui.graphics.glsupport; + +import dlangui.core.logger; +private import derelict.opengl3.gl3; +private import gl3n.linalg; +private import dlangui.core.types; + +// utility function to fill 4-float array of vertex colors with converted CR 32bit color +private void LVGLFillColor(uint color, float * buf, int count) { + float r = ((color >> 16) & 255) / 255.0f; + float g = ((color >> 8) & 255) / 255.0f; + float b = ((color >> 0) & 255) / 255.0f; + float a = (((color >> 24) & 255) ^ 255) / 255.0f; + for (int i=0; i 1) + { + GLchar[] msg = new GLchar[blen + 1]; + GLchar * pmsg = &msg[0]; + glGetShaderInfoLog(shader, blen, &slen, pmsg); + Log.d("Shader compilation error: ", fromStringz(pmsg)); + } + return 0; + } + } + bool compile() { + vertexShader = compileShader(vertexSource, GL_VERTEX_SHADER); + fragmentShader = compileShader(fragmentSource, GL_FRAGMENT_SHADER); + if (!vertexShader || !fragmentShader) { + error = true; + return false; + } + program = glCreateProgram(); + glAttachShader(program, vertexShader); + glAttachShader(program, fragmentShader); + glLinkProgram(program); + GLint isLinked = 0; + glGetProgramiv(program, GL_LINK_STATUS, &isLinked); + if (!isLinked) { + GLint maxLength = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); + GLchar[] msg = new GLchar[maxLength + 1]; + GLchar * pmsg = &msg[0]; + glGetProgramInfoLog(program, maxLength, &maxLength, pmsg); + Log.e("Error while linking program: ", fromStringz(pmsg)); + error = true; + return false; + } + glDetachShader(program, vertexShader); + glDetachShader(program, fragmentShader); + glUseProgram(program); + if (!initLocations()) { + Log.e("some of locations were not found"); + error = true; + } + initialized = true; + return true; + } + bool initLocations() { + return true; + } + bool use() { + if (!initialized) + return false; + glUseProgram(program); + checkError("glUseProgram"); + return true; + } + void release() { + glUseProgram(0); + checkError("glUseProgram(0)"); + } + ~this() { + clear(); + } + void clear() { + // TODO: cleanup + if (program) + glDeleteProgram(program); + if (vertexShader) + glDeleteShader(vertexShader); + if (fragmentShader) + glDeleteShader(fragmentShader); + program = vertexShader = fragmentShader = 0; + initialized = false; + } +} + +class SolidFillProgram : GLProgram { + @property override string vertexSource() { + return + "attribute highp vec4 vertex;\n" + "attribute lowp vec4 colAttr;\n" + "varying lowp vec4 col;\n" + "uniform mediump mat4 matrix;\n" + "void main(void)\n" + "{\n" + " gl_Position = matrix * vertex;\n" + " col = colAttr;\n" + "}\n"; + + } + @property override string fragmentSource() { + return + "uniform sampler2D texture;\n" + "varying lowp vec4 col;\n" + "void main(void)\n" + "{\n" + " gl_FragColor = col;\n" + "}\n"; + } + + void beforeExecute() { + glEnable(GL_BLEND); + glDisable(GL_CULL_FACE); + checkError("glEnable(GL_BLEND)"); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + checkError("glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)"); + use(); + glUniformMatrix4fv(matrixLocation, 1, false, m.value_ptr); + } + + void afterExecute() { + release(); + } + + protected GLint matrixLocation; + protected GLint vertexLocation; + protected GLint colAttrLocation; + override bool initLocations() { + bool res = super.initLocations(); + matrixLocation = glGetUniformLocation(program, "matrix"); + vertexLocation = glGetAttribLocation(program, "vertex"); + colAttrLocation = glGetAttribLocation(program, "colAttr"); + return res && matrixLocation >= 0 && vertexLocation >= 0 && colAttrLocation >= 0; + } + + bool execute(float[] vertices, float[] colors) { + if (error) + return false; + if (!initialized) + if (!compile()) + return false; + beforeExecute(); + + glEnableVertexAttribArray(vertexLocation); + glEnableVertexAttribArray(colAttrLocation); + + glVertexAttribPointer(vertexLocation, 4, GL_FLOAT, GL_FALSE, 0, vertices.ptr); + glVertexAttribPointer(colAttrLocation, 4, GL_FLOAT, GL_FALSE, 0, colors.ptr); + + glDrawArrays(GL_TRIANGLES, 0, 6); + checkError("glDrawArrays"); + glDisableVertexAttribArray(vertexLocation); + glDisableVertexAttribArray(colAttrLocation); + + afterExecute(); + glBindTexture(GL_TEXTURE_2D, 0); + checkError("glBindTexture"); + return true; + } +} + +class TextureProgram : SolidFillProgram { + @property override string vertexSource() { + return + "attribute highp vec4 vertex;\n" + "attribute lowp vec4 colAttr;\n" + "attribute mediump vec4 texCoord;\n" + "varying lowp vec4 col;\n" + "varying mediump vec4 texc;\n" + "uniform mediump mat4 matrix;\n" + "void main(void)\n" + "{\n" + " gl_Position = matrix * vertex;\n" + " col = colAttr;\n" + " texc = texCoord;\n" + "}\n"; + + } + @property override string fragmentSource() { + return + "uniform sampler2D texture;\n" + "varying lowp vec4 col;\n" + "varying mediump vec4 texc;\n" + "void main(void)\n" + "{\n" + " gl_FragColor = texture2D(texture, texc.st) * col;\n" + "}\n"; + } + + GLint texCoordLocation; + override bool initLocations() { + bool res = super.initLocations(); + texCoordLocation = glGetAttribLocation(program, "texCoord"); + return res && texCoordLocation >= 0; + } + + bool execute(float[] vertices, float[] texcoords, float[] colors, uint textureId, bool linear) { + if (error) + return false; + if (!initialized) + if (!compile()) + return false; + beforeExecute(); + glActiveTexture(GL_TEXTURE0); + checkError("glActiveTexture GL_TEXTURE0"); + glBindTexture(GL_TEXTURE_2D, textureId); + checkError("glBindTexture"); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST); + checkError("drawColorAndTextureRect - glTexParameteri"); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR : GL_NEAREST); + checkError("drawColorAndTextureRect - glTexParameteri"); + + glEnableVertexAttribArray(vertexLocation); + glEnableVertexAttribArray(colAttrLocation); + glEnableVertexAttribArray(texCoordLocation); + + glVertexAttribPointer(vertexLocation, 4, GL_FLOAT, GL_FALSE, 0, vertices.ptr); + glVertexAttribPointer(colAttrLocation, 4, GL_FLOAT, GL_FALSE, 0, colors.ptr); + glVertexAttribPointer(texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, texcoords.ptr); + + glDrawArrays(GL_TRIANGLES, 0, 6); + checkError("glDrawArrays"); + + glDisableVertexAttribArray(vertexLocation); + glDisableVertexAttribArray(colAttrLocation); + glDisableVertexAttribArray(texCoordLocation); + + afterExecute(); + glBindTexture(GL_TEXTURE_2D, 0); + checkError("glBindTexture"); + return true; + } +} + +__gshared TextureProgram _textureProgram; +__gshared SolidFillProgram _solidFillProgram; + +bool initShaders() { + if (_textureProgram is null) { + _textureProgram = new TextureProgram(); + if (!_textureProgram.compile()) + return false; + } + if (_solidFillProgram is null) { + _solidFillProgram = new SolidFillProgram(); + if (!_solidFillProgram.compile()) + return false; + } + Log.d("Shaders compiled successfully"); + return true; +} diff --git a/src/dlangui/platforms/common/platform.d b/src/dlangui/platforms/common/platform.d index d791c16e..eae604e3 100644 --- a/src/dlangui/platforms/common/platform.d +++ b/src/dlangui/platforms/common/platform.d @@ -50,6 +50,14 @@ public class Platform { abstract public int enterMessageLoop(); } +private __gshared bool _OPENGL_ENABLED = false; +/// check if hardware acceleration is enabled +@property bool openglEnabled() { return _OPENGL_ENABLED; } +/// call on app initialization if OpenGL support is detected +void setOpenglEnabled() { + _OPENGL_ENABLED = true; +} + version (Windows) { immutable char PATH_DELIMITER = '\\'; } diff --git a/src/dlangui/platforms/windows/winapp.d b/src/dlangui/platforms/windows/winapp.d index 32ab3b35..5abce7f1 100644 --- a/src/dlangui/platforms/windows/winapp.d +++ b/src/dlangui/platforms/windows/winapp.d @@ -14,7 +14,9 @@ import dlangui.platforms.windows.win32fonts; import dlangui.platforms.windows.win32drawbuf; import dlangui.graphics.drawbuf; import dlangui.graphics.fonts; +import dlangui.graphics.glsupport; import dlangui.core.logger; +//import derelict.opengl3.wgl; pragma(lib, "gdi32.lib"); pragma(lib, "user32.lib"); @@ -27,11 +29,105 @@ immutable WIN_CLASS_NAME = "DLANGUI_APP"; __gshared HINSTANCE _hInstance; __gshared int _cmdShow; +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; + int greenMask = (1 << pfd.cGreenBits) - 1; + int blueMask = (1 << pfd.cBlueBits) - 1; + int i; + + for (i=0; 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; +} + +private __gshared bool DERELICT_GL3_RELOADED = false; + class Win32Window : Window { private HWND _hwnd; + HGLRC _hGLRC; // opengl context + HPALETTE _hPalette; string _caption; Win32ColorDrawBuf _drawbuf; + bool useOpengl; this(string windowCaption, Window parent) { + import derelict.opengl3.wgl; _caption = windowCaption; _hwnd = CreateWindow(toUTF16z(WIN_CLASS_NAME), // window class name toUTF16z(windowCaption), // window caption @@ -44,6 +140,54 @@ class Win32Window : Window { null, // window menu handle _hInstance, // program instance handle 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) { + // 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); + } + } else { + useOpengl = true; + } + } + } else { + Log.e("Pixelformat failed"); + // disable GL + DERELICT_GL3_RELOADED = true; + } + } + } + ~this() { + Log.d("Window destructor"); + import derelict.opengl3.wgl; + if (_hGLRC) { + wglMakeCurrent (null, null) ; + wglDeleteContext(_hGLRC); + _hGLRC = null; + } + if (_hwnd) + DestroyWindow(_hwnd); + _hwnd = null; } Win32ColorDrawBuf getDrawBuf() { //RECT rect; @@ -68,10 +212,39 @@ class Win32Window : Window { SetWindowTextW(_hwnd, toUTF16z(_caption)); } void onCreate() { - writeln("Window onCreate"); + Log.d("Window onCreate"); } void onDestroy() { - writeln("Window onDestroy"); + Log.d("Window onDestroy"); + } + void onPaint() { + Log.d("onPaint()"); + if (useOpengl && _hGLRC) { + import derelict.opengl3.gl3; + import derelict.opengl3.wgl; + //Log.d("onPaint() start drawing opengl viewport: ", _dx, "x", _dy); + //PAINTSTRUCT ps; + //HDC hdc = BeginPaint(_hwnd, &ps); + //scope(exit) EndPaint(_hwnd, &ps); + HDC hdc = GetDC(_hwnd); + wglMakeCurrent(hdc, _hGLRC); + glDisable(GL_DEPTH_TEST); + glViewport(0, 0, _dx, _dy); + glClearColor(0.5f, 0.5f, 0.5f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + //Log.d("onPaint() end drawing opengl"); + glFlush(); + SwapBuffers(hdc); + } else { + 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); + } } } @@ -185,6 +358,24 @@ int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int Win32FontManager fontMan = new Win32FontManager(); FontManager.instance = fontMan; + { + import derelict.opengl3.gl3; + DerelictGL3.load(); + + // just to check OpenGL context + Log.i("Trying to setup OpenGL context"); + Win32Window tmpWindow = new Win32Window("", null); + destroy(tmpWindow); + if (openglEnabled) + Log.i("OpenGL support is enabled"); + else + Log.w("OpenGL support is disabled"); + // process messages + platform.enterMessageLoop(); + } + + // Load versions 1.2+ and all supported ARB and EXT extensions. + Log.i("Entering UIAppMain: ", args); int result = UIAppMain(args); Log.i("UIAppMain returned ", result); @@ -196,7 +387,6 @@ extern(Windows) LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; - PAINTSTRUCT ps; RECT rect; void * p = cast(void*)GetWindowLongPtr(hwnd, GWLP_USERDATA); Win32Window window = p is null ? null : cast(Win32Window)(p); @@ -232,14 +422,8 @@ LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) //int dx = rect.right - rect.left; //int dy = rect.bottom - rect.top; //window.onResize(dx, dy); - - hdc = BeginPaint(hwnd, &ps); - scope(exit) EndPaint(hwnd, &ps); - - Win32ColorDrawBuf buf = window.getDrawBuf(); - buf.fill(0x808080); - window.onDraw(buf); - buf.drawTo(hdc, 0, 0); + if (window !is null) + window.onPaint(); } return 0; // processed