diff --git a/dlangui-monod-linux.dproj b/dlangui-monod-linux.dproj index 1c13adaf..e272d9da 100644 --- a/dlangui-monod-linux.dproj +++ b/dlangui-monod-linux.dproj @@ -280,12 +280,13 @@ + - + diff --git a/dlangui-monod-osx.dproj b/dlangui-monod-osx.dproj index e9c493b4..087da1de 100644 --- a/dlangui-monod-osx.dproj +++ b/dlangui-monod-osx.dproj @@ -139,6 +139,7 @@ + @@ -198,7 +199,7 @@ - + diff --git a/dlangui-monod-windows.dproj b/dlangui-monod-windows.dproj index a300caa6..fb289892 100644 --- a/dlangui-monod-windows.dproj +++ b/dlangui-monod-windows.dproj @@ -117,7 +117,7 @@ - + diff --git a/dlangui-msvc.visualdproj b/dlangui-msvc.visualdproj index 2cdd21e0..18c6ca82 100644 --- a/dlangui-msvc.visualdproj +++ b/dlangui-msvc.visualdproj @@ -771,6 +771,7 @@ + @@ -778,7 +779,7 @@ - + diff --git a/examples/d3d/d3d-msvc.visualdproj b/examples/d3d/d3d-msvc.visualdproj index 72b19e55..ba2a9942 100644 --- a/examples/d3d/d3d-msvc.visualdproj +++ b/examples/d3d/d3d-msvc.visualdproj @@ -53,8 +53,8 @@ $(CC) -c 1 $(DMDInstallDir)windows\bin\dmd.exe - $(SolutionDir)/src $(SolutionDir)/3rdparty $(SolutionDir)/deps/DerelictGL3/source $(SolutionDir)/deps/DerelictUtil/source $(SolutionDir)/deps/DerelictFT/source $(SolutionDir)/deps/DerelictSDL2/source - views views/res views/res/i18n views/res/mdpi views/res/hdpi + $(SolutionDir)/../dlangui/src $(SolutionDir)/../dlangui/3rdparty $(SolutionDir)/../dlangui/deps/DerelictGL3/source $(SolutionDir)/../dlangui/deps/DerelictUtil/source $(SolutionDir)/../dlangui/deps/DerelictFT/source $(SolutionDir)/../dlangui/deps/DerelictSDL2/source + views views/res views/res/i18n views/res/mdpi views/res/hdpi views/res/shaders $(ConfigurationName) $(OutDir) @@ -155,8 +155,8 @@ $(CC) -c 1 $(DMDInstallDir)windows\bin\dmd.exe - $(SolutionDir)/src $(SolutionDir)/3rdparty $(SolutionDir)/deps/DerelictGL3/source $(SolutionDir)/deps/DerelictUtil/source $(SolutionDir)/deps/DerelictFT/source $(SolutionDir)/deps/DerelictSDL2/source - views views/res views/res/i18n views/res/mdpi views/res/hdpi + $(SolutionDir)/../dlangui/src $(SolutionDir)/../dlangui/3rdparty $(SolutionDir)/../dlangui/deps/DerelictGL3/source $(SolutionDir)/../dlangui/deps/DerelictUtil/source $(SolutionDir)/../dlangui/deps/DerelictFT/source $(SolutionDir)/../dlangui/deps/DerelictSDL2/source + views views/res views/res/i18n views/res/mdpi views/res/hdpi views/res/shaders $(ConfigurationName) $(OutDir) @@ -257,8 +257,8 @@ $(CC) -c 1 $(DMDInstallDir)windows\bin\dmd.exe - $(SolutionDir)/src $(SolutionDir)/3rdparty $(SolutionDir)/deps/DerelictGL3/source $(SolutionDir)/deps/DerelictUtil/source $(SolutionDir)/deps/DerelictFT/source $(SolutionDir)/deps/DerelictSDL2/source - views views/res views/res/i18n views/res/mdpi views/res/hdpi + $(SolutionDir)/../dlangui/src $(SolutionDir)/../dlangui/3rdparty $(SolutionDir)/../dlangui/deps/DerelictGL3/source $(SolutionDir)/../dlangui/deps/DerelictUtil/source $(SolutionDir)/../dlangui/deps/DerelictFT/source $(SolutionDir)/../dlangui/deps/DerelictSDL2/source + views views/res views/res/i18n views/res/mdpi views/res/hdpi views/res/shaders $(ConfigurationName) $(OutDir) @@ -359,8 +359,8 @@ $(CC) -c 1 $(DMDInstallDir)windows\bin\dmd.exe - $(SolutionDir)/src $(SolutionDir)/3rdparty $(SolutionDir)/deps/DerelictGL3/source $(SolutionDir)/deps/DerelictUtil/source $(SolutionDir)/deps/DerelictFT/source $(SolutionDir)/deps/DerelictSDL2/source - views views/res views/res/i18n views/res/mdpi views/res/hdpi + $(SolutionDir)/../dlangui/src $(SolutionDir)/../dlangui/3rdparty $(SolutionDir)/../dlangui/deps/DerelictGL3/source $(SolutionDir)/../dlangui/deps/DerelictUtil/source $(SolutionDir)/../dlangui/deps/DerelictFT/source $(SolutionDir)/../dlangui/deps/DerelictSDL2/source + views views/res views/res/i18n views/res/mdpi views/res/hdpi views/res/shaders $(ConfigurationName) $(OutDir) diff --git a/examples/d3d/dub.json b/examples/d3d/dub.json index 78db38dc..b41e6cca 100644 --- a/examples/d3d/dub.json +++ b/examples/d3d/dub.json @@ -5,7 +5,7 @@ "license": "Boost", "authors": ["Vadim Lopatin"], - "stringImportPaths": ["views", "views/res", "views/res/i18n", "views/res/mdpi"], + "stringImportPaths": ["views", "views/res", "views/res/i18n", "views/res/mdpi", "views/res/shaders"], "targetPath": "bin", "targetName": "d3d", diff --git a/examples/d3d/src/d3d.d b/examples/d3d/src/d3d.d index ceb5aeeb..e0db3c7d 100644 --- a/examples/d3d/src/d3d.d +++ b/examples/d3d/src/d3d.d @@ -5,6 +5,7 @@ import dlangui.graphics.scene.scene3d; import dlangui.graphics.scene.camera; import dlangui.graphics.scene.mesh; import dlangui.graphics.scene.material; +import dlangui.graphics.scene.effect; import dlangui.graphics.glsupport; import dlangui.graphics.gldrawbuf; import derelict.opengl3.gl3; @@ -228,7 +229,7 @@ class UiWidget : VerticalLayout, CellVisitor { } float angle = 0; - MyGLProgram _program; + EffectRef _program; Scene3d _scene; Camera _cam; Mesh _mesh; @@ -239,11 +240,9 @@ class UiWidget : VerticalLayout, CellVisitor { /// this is OpenGLDrawableDelegate implementation private void doDraw(Rect windowRect, Rect rc) { - if (!_program) { - _program = new MyGLProgram(); + if (_program.isNull) { + _program = EffectCache.instance.get("textured.vert", "textured.frag"); } - if (!_program.check()) - return; if (!_tx) _tx = new GLTexture("crate"); if (!_blockstx) @@ -373,65 +372,3 @@ class TestVisitor : CellVisitor { } } -// Simple texture + color shader -class MyGLProgram : GLProgram { - @property override string vertexSource() { - return q{ - in vec4 vertex; - in vec4 colAttr; - in vec4 texCoord; - out vec4 col; - out vec4 texc; - uniform mat4 matrix; - void main(void) - { - gl_Position = matrix * vertex; - col = colAttr; - texc = texCoord; - } - }; - - } - @property override string fragmentSource() { - return q{ - uniform sampler2D tex; - in vec4 col; - in vec4 texc; - out vec4 outColor; - void main(void) - { - outColor = texture(tex, texc.st) * col; - } - }; - } - - // attribute locations - protected int matrixLocation; - protected int vertexLocation; - protected int colAttrLocation; - protected int texCoordLocation; - - override bool initLocations() { - matrixLocation = getUniformLocation("matrix"); - vertexLocation = getAttribLocation("vertex"); - colAttrLocation = getAttribLocation("colAttr"); - texCoordLocation = getAttribLocation("texCoord"); - return matrixLocation >= 0 && vertexLocation >= 0 && colAttrLocation >= 0 && texCoordLocation >= 0; - } - - /// get location for vertex attribute - override int getVertexElementLocation(VertexElementType type) { - switch(type) with(VertexElementType) { - case POSITION: - return vertexLocation; - case COLOR: - return colAttrLocation; - case TEXCOORD0: - return texCoordLocation; - default: - return super.getVertexElementLocation(type); - } - } - -} - diff --git a/examples/d3d/views/res/shaders/textured.frag b/examples/d3d/views/res/shaders/textured.frag new file mode 100644 index 00000000..062696ae --- /dev/null +++ b/examples/d3d/views/res/shaders/textured.frag @@ -0,0 +1,8 @@ +uniform sampler2D tex; +in vec4 col; +in vec4 texc; +out vec4 outColor; +void main(void) +{ + outColor = texture(tex, texc.st) * col; +} diff --git a/examples/d3d/views/res/shaders/textured.vert b/examples/d3d/views/res/shaders/textured.vert new file mode 100644 index 00000000..9fa0dad6 --- /dev/null +++ b/examples/d3d/views/res/shaders/textured.vert @@ -0,0 +1,12 @@ +in vec4 vertex; +in vec4 colAttr; +in vec4 texCoord; +out vec4 col; +out vec4 texc; +uniform mat4 matrix; +void main(void) +{ + gl_Position = matrix * vertex; + col = colAttr; + texc = texCoord; +} diff --git a/examples/d3d/views/resources.list b/examples/d3d/views/resources.list index e6dca3c6..28d55c35 100644 --- a/examples/d3d/views/resources.list +++ b/examples/d3d/views/resources.list @@ -4,3 +4,5 @@ res/mdpi/cr3_logo.png res/mdpi/tx_fabric.jpg res/mdpi/crate.png res/mdpi/blocks.png +res/shaders/textured.vert +res/shaders/textured.frag diff --git a/src/dlangui/graphics/resources.d b/src/dlangui/graphics/resources.d index 3daa5ef0..180d599b 100644 --- a/src/dlangui/graphics/resources.d +++ b/src/dlangui/graphics/resources.d @@ -119,6 +119,11 @@ struct EmbeddedResourceList { void addResources(EmbeddedResource[] resources) { list ~= resources; } + void dumpEmbeddedResources() { + foreach(r; list) { + Log.d("EmbeddedResource: ", r.name); + } + } /// find by exact file name EmbeddedResource * find(string name) { // search backwards to allow overriding standard resources (which are added first) @@ -147,7 +152,7 @@ struct EmbeddedResourceList { // search backwards to allow overriding standard resources (which are added first) for (int i = cast(int)list.length - 1; i >= 0; i--) { string s = list[i].name; - if (s.equal(xmlname) || s.equal(pngname) || s.equal(png9name) + if (s.equal(name) || s.equal(xmlname) || s.equal(pngname) || s.equal(png9name) || s.equal(jpgname) || s.equal(jpegname) || s.equal(xpmname)) return &list[i]; } diff --git a/src/dlangui/graphics/scene/effect.d b/src/dlangui/graphics/scene/effect.d new file mode 100644 index 00000000..e29a87cc --- /dev/null +++ b/src/dlangui/graphics/scene/effect.d @@ -0,0 +1,182 @@ +module dlangui.graphics.scene.effect; + +public import dlangui.core.config; +static if (ENABLE_OPENGL): + +import dlangui.core.types; +import dlangui.core.logger; +import dlangui.graphics.glsupport; +import dlangui.graphics.gldrawbuf; +import dlangui.graphics.scene.mesh; + +/// Reference counted Effect object +alias EffectRef = Ref!Effect; + +/// Effect ID +struct EffectId { + string vertexShaderName; + string fragmentShaderName; + string definitions; + this(string vertexShader, string fragmentShader, string defs) { + vertexShaderName = vertexShader; + fragmentShaderName = fragmentShader; + definitions = defs; + } + + size_t toHash() const @safe pure nothrow + { + size_t hash; + foreach (char c; vertexShaderName) + hash = (hash * 9) + c; + hash = (hash * 31) + 198237283; + foreach (char c; fragmentShaderName) + hash = (hash * 9) + c; + hash = (hash * 31) + 84574112; + foreach (char c; definitions) + hash = (hash * 9) + c; + return hash; + } + + bool opEquals(ref const EffectId s) const @safe pure nothrow + { + return + std.string.cmp(this.vertexShaderName, s.vertexShaderName) == 0 && + std.string.cmp(this.fragmentShaderName, s.fragmentShaderName) == 0 && + std.string.cmp(this.definitions, s.definitions) == 0; + } +} + +/// Effect (aka OpenGL program) +class Effect : GLProgram { + EffectId _id; + string[string] _defs; + + @property ref const(EffectId) id() const { return _id; } + this(EffectId id) { + _id = id; + init(); + } + this(string vertexShader, string fragmentShader, string defs) { + _id = EffectId(vertexShader, fragmentShader, defs); + init(); + } + + ~this() { + _instance.onObjectDestroyed(_id); + } + + protected void init() { + // parse defs + import std.array : split; + string[] defs = _id.definitions.split(";"); + foreach(def; defs) { + assert(def.length > 0); + string[] items = def.split(" "); + if (items.length > 0) { + _defs[items[0]] = items.length > 1 ? items[1] : ""; + } + } + // compile shaders + if (!check()) { + Log.e("Failed to compile shaders ", _id.vertexShaderName, " ", _id.fragmentShaderName, " ", _id.definitions); + assert(false); + } + } + + protected string preProcessSource(string src) { + // TODO: preprocess source code + return src; + } + + protected string loadVertexSource(string resourceId) { + import dlangui.graphics.resources; + import std.string : endsWith; + string filename; + filename = drawableCache.findResource(resourceId); + if (!filename) { + Log.e("Shader source resource file not found for resourceId ", resourceId); + assert(false); + } + if (!filename.endsWith(".vert") && !filename.endsWith(".frag")) { + Log.e("Shader source resource name should have .vert or .frag extension, but found ", filename); + assert(false); + } + string s = cast(string)loadResourceBytes(filename); + if (!s) { + Log.e("Cannot read shader source resource ", resourceId, " from file ", filename); + assert(false); + } + return s; + } + + @property override string vertexSource() { + return preProcessSource(loadVertexSource(_id.vertexShaderName)); + } + + @property override string fragmentSource() { + return preProcessSource(loadVertexSource(_id.fragmentShaderName)); + } + + // attribute locations + protected int matrixLocation; + protected int vertexLocation; + protected int colAttrLocation; + protected int texCoordLocation; + + override bool initLocations() { + matrixLocation = getUniformLocation("matrix"); + vertexLocation = getAttribLocation("vertex"); + colAttrLocation = getAttribLocation("colAttr"); + texCoordLocation = getAttribLocation("texCoord"); + return matrixLocation >= 0 && vertexLocation >= 0 && colAttrLocation >= 0 && texCoordLocation >= 0; + } + + /// get location for vertex attribute + override int getVertexElementLocation(VertexElementType type) { + switch(type) with(VertexElementType) { + case POSITION: + return vertexLocation; + case COLOR: + return colAttrLocation; + case TEXCOORD0: + return texCoordLocation; + default: + return super.getVertexElementLocation(type); + } + } + +} + +/// Effects cache +class EffectCache { + private Effect[EffectId] _map; + + /// returns effect cache singleton instance + static @property EffectCache instance() { + if (!_instance) + _instance = new EffectCache(); + return _instance; + } + + static private void onObjectDestroyed(EffectId id) { + if (id in _instance._map) + _instance._map.remove(id); + } + + /// get effect from cache or create new if not exist + Effect get(string vertexShader, string fragmentShader, string defs = null) { + return get(EffectId(vertexShader, fragmentShader, defs)); + } + + /// get effect from cache or create new if not exist + Effect get(const EffectId id) { + if (auto p = id in _map) { + return *p; + } + Effect e = new Effect(id); + _map[id] = e; + return e; + } +} + +private __gshared EffectCache _instance; diff --git a/src/dlangui/graphics/scene/mesh.d b/src/dlangui/graphics/scene/mesh.d index 7772a23f..8b006f5c 100644 --- a/src/dlangui/graphics/scene/mesh.d +++ b/src/dlangui/graphics/scene/mesh.d @@ -2,6 +2,7 @@ module dlangui.graphics.scene.mesh; import dlangui.graphics.scene.material; import dlangui.core.math3d; +import dlangui.core.types; /// vertex element type enum VertexElementType : ubyte { @@ -43,7 +44,7 @@ class VertexBuffer { enum VERTEX_ELEMENT_NOT_FOUND = -1; /// Base class for graphics effect / program - e.g. for OpenGL shader program -abstract class GraphicsEffect { +abstract class GraphicsEffect : RefCountedObject { /// get location for vertex attribute int getVertexElementLocation(VertexElementType type); diff --git a/src/dlangui/graphics/xpm/reader.d b/src/dlangui/graphics/xpm/reader.d index f4c3eaed..c063c768 100644 --- a/src/dlangui/graphics/xpm/reader.d +++ b/src/dlangui/graphics/xpm/reader.d @@ -9,7 +9,7 @@ module dlangui.graphics.xpm.reader; * */ -import dlangui.graphics.xpm.colors; +import dlangui.graphics.xpm.xpmcolors; import dlangui.graphics.colors; import dlangui.graphics.drawbuf; diff --git a/src/dlangui/graphics/xpm/colors.d b/src/dlangui/graphics/xpm/xpmcolors.d similarity index 99% rename from src/dlangui/graphics/xpm/colors.d rename to src/dlangui/graphics/xpm/xpmcolors.d index 4470b9e1..ebebe8ce 100644 --- a/src/dlangui/graphics/xpm/colors.d +++ b/src/dlangui/graphics/xpm/xpmcolors.d @@ -1,5 +1,5 @@ -module dlangui.graphics.xpm.colors; +module dlangui.graphics.xpm.xpmcolors; import std.algorithm : cmp; ///Represents for predefined xpm color