diff --git a/examples/d3d/src/d3d.d b/examples/d3d/src/d3d.d index f05b9e2d..f168b136 100644 --- a/examples/d3d/src/d3d.d +++ b/examples/d3d/src/d3d.d @@ -5,6 +5,10 @@ import dlangui.graphics.scene.scene3d; import dlangui.graphics.scene.camera; import dlangui.graphics.scene.mesh; import dlangui.graphics.scene.material; +import dlangui.graphics.glsupport; +import dlangui.graphics.gldrawbuf; +import derelict.opengl3.gl3; +import derelict.opengl3.gl; mixin APP_ENTRY_POINT; @@ -12,34 +16,56 @@ mixin APP_ENTRY_POINT; extern (C) int UIAppMain(string[] args) { // create window Window window = Platform.instance.createWindow("DlangUI example - 3D Application", null, WindowFlag.Resizable, 600, 500); + window.mainWidget = new UiWidget(); - static if (false) { - VerticalLayout layout = new VerticalLayout(); - Button btn = new Button(null, "Button 1"d); - btn.fontSize = 32; - Button btn2 = new Button(null, "Button 2"d); - btn2.fontSize = 32; - layout.addChild(btn); - layout.addChild(btn2); - window.mainWidget = layout; - } else { + auto canvas = window.mainWidget.childById!CanvasWidget("canvas"); + canvas.onDrawListener = delegate(CanvasWidget canvas, DrawBuf buf, Rect rc) { + Log.w("canvas.onDrawListener clipRect=" ~ to!string(buf.clipRect)); + buf.fill(0xFFFFFF); + int x = rc.left; + int y = rc.top; + buf.fillRect(Rect(x+20, y+20, x+150, y+200), 0x80FF80); + buf.fillRect(Rect(x+90, y+80, x+250, y+250), 0x80FF80FF); + canvas.font.drawText(buf, x + 40, y + 50, "fillRect()"d, 0xC080C0); + buf.drawFrame(Rect(x + 400, y + 30, x + 550, y + 150), 0x204060, Rect(2,3,4,5), 0x80704020); + canvas.font.drawText(buf, x + 400, y + 5, "drawFrame()"d, 0x208020); + canvas.font.drawText(buf, x + 300, y + 100, "drawPixel()"d, 0x000080); + for (int i = 0; i < 80; i++) + buf.drawPixel(x+300 + i * 4, y+140 + i * 3 % 100, 0xFF0000 + i * 2); + canvas.font.drawText(buf, x + 200, y + 150, "drawLine()"d, 0x800020); + for (int i = 0; i < 40; i+=3) + buf.drawLine(Point(x+200 + i * 4, y+190), Point(x+150 + i * 7, y+320 + i * 2), 0x008000 + i * 5); + }; - // create some widget to show in window - //window.mainWidget = (new Button()).text("Hello, world!"d).margins(Rect(20,20,20,20)); - window.mainWidget = parseML(q{ - VerticalLayout { + + //MeshPart part = new MeshPart(); + + // show window + window.show(); + + // run message loop + return Platform.instance.enterMessageLoop(); +} + +class UiWidget : VerticalLayout { + this() { + super("OpenGLView"); + layoutWidth = FILL_PARENT; + layoutHeight = FILL_PARENT; + alignment = Align.Center; + parseML(q{ + { + id: glView margins: 10 padding: 10 backgroundColor: "#C0E0E070" // semitransparent yellow background - // red bold text with size = 150% of base style size and font face Arial - MainMenu {} TextWidget { text: "Hello World example for DlangUI"; textColor: "red"; fontSize: 150%; fontWeight: 800; fontFace: "Arial" } HorizontalLayout { - layoutWidth: fill - TextWidget { text: "Text 20%"; backgroundColor:"#80FF0000"; layoutWidth: 20% } + layoutWidth: fill + TextWidget { text: "Text 20%"; backgroundColor:"#80FF0000"; layoutWidth: 20% } VerticalLayout { - layoutWidth: 30% - TextWidget { text: "Text 30%"; backgroundColor:"#80FF00FF" } + layoutWidth: 30% + TextWidget { text: "Text 30%"; backgroundColor:"#80FF00FF" } TextWidget { text: "Text 30%"; backgroundColor:"#8000FFFF" } TextWidget { text: "Text 30%"; backgroundColor:"#8000FFFF" } } @@ -47,8 +73,8 @@ extern (C) int UIAppMain(string[] args) { } // arrange controls as form - table with two columns TableLayout { - colCount: 2 - TextWidget { text: "param 1" } + colCount: 2 + TextWidget { text: "param 1" } EditLine { id: edit1; text: "some text" } TextWidget { text: "param 2" } EditLine { id: edit2; text: "some text for param2" } @@ -71,58 +97,124 @@ extern (C) int UIAppMain(string[] args) { Button { id: btnCancel; text: "Cancel"; fontSize: 27px } } CanvasWidget { - id: canvas - minWidth: 500 - minHeight: 300 + id: canvas + minWidth: 500 + minHeight: 300 } } - }); + }, "", this); + // assign OpenGL drawable to child widget background + childById("glView").backgroundDrawable = DrawableRef(new OpenGLDrawable(&doDraw)); - MenuItem mainMenuItems = new MenuItem(); - MenuItem fileItem = new MenuItem(new Action(1, "MENU_FILE")); - fileItem.add(new Action(2, "MENU_FILE_OPEN"c, "document-open", KeyCode.KEY_O, KeyFlag.Control)); - fileItem.add(new Action(3, "MENU_FILE_SAVE"c, "document-save", KeyCode.KEY_S, KeyFlag.Control)); - mainMenuItems.add(fileItem); - window.mainWidget.childById!MainMenu("MAIN_MENU").menuItems = mainMenuItems; - auto canvas = window.mainWidget.childById!CanvasWidget("canvas"); - canvas.onDrawListener = delegate(CanvasWidget canvas, DrawBuf buf, Rect rc) { - Log.w("canvas.onDrawListener clipRect=" ~ to!string(buf.clipRect)); - buf.fill(0xFFFFFF); - int x = rc.left; - int y = rc.top; - buf.fillRect(Rect(x+20, y+20, x+150, y+200), 0x80FF80); - buf.fillRect(Rect(x+90, y+80, x+250, y+250), 0x80FF80FF); - canvas.font.drawText(buf, x + 40, y + 50, "fillRect()"d, 0xC080C0); - buf.drawFrame(Rect(x + 400, y + 30, x + 550, y + 150), 0x204060, Rect(2,3,4,5), 0x80704020); - canvas.font.drawText(buf, x + 400, y + 5, "drawFrame()"d, 0x208020); - canvas.font.drawText(buf, x + 300, y + 100, "drawPixel()"d, 0x000080); - for (int i = 0; i < 80; i++) - buf.drawPixel(x+300 + i * 4, y+140 + i * 3 % 100, 0xFF0000 + i * 2); - canvas.font.drawText(buf, x + 200, y + 150, "drawLine()"d, 0x800020); - for (int i = 0; i < 40; i+=3) - buf.drawLine(Point(x+200 + i * 4, y+190), Point(x+150 + i * 7, y+320 + i * 2), 0x008000 + i * 5); - }; + _scene = new Scene3d(); + _cam = new Camera(); + _cam.translation = vec3(0, 0, -5); + _scene.activeCamera = _cam; + mat4 camMatrix = _scene.viewProjectionMatrix; + VertexFormat vfmt = VertexFormat(VertexElementType.POSITION, VertexElementType.COLOR, VertexElementType.TEXCOORD0); + _mesh = new Mesh(vfmt); + _mesh.addVertex([1,2,3, 1,1,1,1, 0,0]); + _mesh.addVertex([-1,2,3, 1,1,1,1, 1,0]); + _mesh.addVertex([-1,-2,3, 1,1,1,1, 1,1]); + _mesh.addVertex([1,-2,3, 1,1,1,1, 0,1]); + _mesh.addPart(PrimitiveType.triangles, [0, 1, 2, 2, 3, 0]); + } - Scene3d scene = new Scene3d(); - Camera cam = new Camera(); - cam.translation = vec3(0, 0, -5); - scene.activeCamera = cam; - mat4 camMatrix = scene.viewProjectionMatrix; - VertexFormat vfmt = VertexFormat(VertexElementType.POSITION, VertexElementType.COLOR, VertexElementType.TEXCOORD0); - Mesh mesh = new Mesh(vfmt); - mesh.addVertex([1,2,3, 1,1,1,1, 0,0]); - mesh.addVertex([-1,2,3, 1,1,1,1, 1,0]); - mesh.addVertex([-1,-2,3, 1,1,1,1, 1,1]); - mesh.addVertex([1,-2,3, 1,1,1,1, 0,1]); - mesh.addPart(PrimitiveType.triangles, [0, 1, 2, 2, 3, 0]); + MyGLProgram _program; + Scene3d _scene; + Camera _cam; + Mesh _mesh; + GLTexture _tx; - //MeshPart part = new MeshPart(); - // show window - window.show(); + /// this is OpenGLDrawableDelegate implementation + private void doDraw(Rect windowRect, Rect rc) { + if (!_program) { + _program = new MyGLProgram(); + } + if (!_program.check()) + return; + if (!_tx) + _tx = new GLTexture("crate"); + if (!_tx.isValid) { + Log.e("Invalid texture"); + return; + } + mat4 camMatrix = _scene.viewProjectionMatrix; + _program.bind(); + _program.setUniform("matrix", camMatrix); + _tx.texture.setup(); + _tx.texture.setSamplerParams(true); - // run message loop - return Platform.instance.enterMessageLoop(); + _program.draw(_mesh); + + _tx.texture.unbind(); + _program.unbind(); + } } + + +// 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/mdpi/crate.png b/examples/d3d/views/res/mdpi/crate.png new file mode 100644 index 00000000..18687fff Binary files /dev/null and b/examples/d3d/views/res/mdpi/crate.png differ diff --git a/examples/d3d/views/resources.list b/examples/d3d/views/resources.list index 0abcf429..473da14c 100644 --- a/examples/d3d/views/resources.list +++ b/examples/d3d/views/resources.list @@ -2,3 +2,4 @@ res/i18n/en.ini res/i18n/ru.ini res/mdpi/cr3_logo.png res/mdpi/tx_fabric.jpg +res/mdpi/crate.png diff --git a/src/dlangui/graphics/glsupport.d b/src/dlangui/graphics/glsupport.d index 4fdc756c..86f506b9 100644 --- a/src/dlangui/graphics/glsupport.d +++ b/src/dlangui/graphics/glsupport.d @@ -266,6 +266,11 @@ class GLProgram : GraphicsEffect { protected int[string] _uniformLocations; protected int[string] _attribLocations; + /// get location for vertex attribute + override int getVertexElementLocation(VertexElementType type) { + return VERTEX_ELEMENT_NOT_FOUND; + } + /// get uniform location from program, returns -1 if location is not found int getUniformLocation(string variableName) { if (auto p = variableName in _uniformLocations)