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