mirror of https://github.com/buggins/dlangui.git
Implement simple Scene3d drawing: #183
This commit is contained in:
parent
d882a203c0
commit
92a348974f
|
@ -280,9 +280,11 @@
|
|||
<Compile Include="src\dlangui\graphics\images.d" />
|
||||
<Compile Include="src\dlangui\graphics\resources.d" />
|
||||
<Compile Include="src\dlangui\graphics\scene\camera.d" />
|
||||
<Compile Include="src\dlangui\graphics\scene\drawableobject.d" />
|
||||
<Compile Include="src\dlangui\graphics\scene\effect.d" />
|
||||
<Compile Include="src\dlangui\graphics\scene\material.d" />
|
||||
<Compile Include="src\dlangui\graphics\scene\mesh.d" />
|
||||
<Compile Include="src\dlangui\graphics\scene\model.d" />
|
||||
<Compile Include="src\dlangui\graphics\scene\node.d" />
|
||||
<Compile Include="src\dlangui\graphics\scene\scene3d.d" />
|
||||
<Compile Include="src\dlangui\graphics\scene\transform.d" />
|
||||
|
|
|
@ -139,9 +139,11 @@
|
|||
<Compile Include="src\dlangui\graphics\images.d" />
|
||||
<Compile Include="src\dlangui\graphics\resources.d" />
|
||||
<Compile Include="src\dlangui\graphics\scene\camera.d" />
|
||||
<Compile Include="src\dlangui\graphics\scene\drawableobject.d" />
|
||||
<Compile Include="src\dlangui\graphics\scene\effect.d" />
|
||||
<Compile Include="src\dlangui\graphics\scene\material.d" />
|
||||
<Compile Include="src\dlangui\graphics\scene\mesh.d" />
|
||||
<Compile Include="src\dlangui\graphics\scene\model.d" />
|
||||
<Compile Include="src\dlangui\graphics\scene\node.d" />
|
||||
<Compile Include="src\dlangui\graphics\scene\scene3d.d" />
|
||||
<Compile Include="src\dlangui\graphics\scene\transform.d" />
|
||||
|
|
|
@ -771,9 +771,11 @@
|
|||
<Folder name="graphics">
|
||||
<Folder name="scene">
|
||||
<File path="src\dlangui\graphics\scene\camera.d" />
|
||||
<File path="src\dlangui\graphics\scene\drawableobject.d" />
|
||||
<File path="src\dlangui\graphics\scene\effect.d" />
|
||||
<File path="src\dlangui\graphics\scene\material.d" />
|
||||
<File path="src\dlangui\graphics\scene\mesh.d" />
|
||||
<File path="src\dlangui\graphics\scene\model.d" />
|
||||
<File path="src\dlangui\graphics\scene\node.d" />
|
||||
<File path="src\dlangui\graphics\scene\scene3d.d" />
|
||||
<File path="src\dlangui\graphics\scene\transform.d" />
|
||||
|
|
|
@ -6,6 +6,8 @@ import dlangui.graphics.scene.camera;
|
|||
import dlangui.graphics.scene.mesh;
|
||||
import dlangui.graphics.scene.material;
|
||||
import dlangui.graphics.scene.effect;
|
||||
import dlangui.graphics.scene.model;
|
||||
import dlangui.graphics.scene.node;
|
||||
import dlangui.graphics.glsupport;
|
||||
import dlangui.graphics.gldrawbuf;
|
||||
import derelict.opengl3.gl3;
|
||||
|
@ -114,7 +116,7 @@ class UiWidget : VerticalLayout, CellVisitor {
|
|||
int y0 = 0;
|
||||
int z0 = 0;
|
||||
|
||||
_mesh = Mesh.createCubeMesh(vec3(x0+ 0, y0 + 0, z0 + 0), 0.3f);
|
||||
Mesh _mesh = Mesh.createCubeMesh(vec3(x0+ 0, y0 + 0, z0 + 0), 0.3f);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
_mesh.addCubeMesh(vec3(x0+ 0, y0+0, z0+ i * 2 + 1.0f), 0.2f, vec4(i / 12, 1, 1, 1));
|
||||
_mesh.addCubeMesh(vec3(x0+ i * 2 + 1.0f, y0+0, z0+ 0), 0.2f, vec4(1, i / 12, 1, 1));
|
||||
|
@ -126,6 +128,11 @@ class UiWidget : VerticalLayout, CellVisitor {
|
|||
_mesh.addCubeMesh(vec3(x0+ i * 2 + 1.0f, y0+-i * 2 + 1.0f, z0+ i * 2 + 1.0f), 0.2f, vec4(i / 12, 1 - i / 12, i / 12, 1));
|
||||
_mesh.addCubeMesh(vec3(x0+ -i * 2 - 1.0f, y0+-i * 2 - 1.0f, z0+ -i * 2 - 1.0f), 0.2f, vec4(1 - i / 12, i / 12, i / 12, 1));
|
||||
}
|
||||
Material cubeMaterial = new Material(EffectId("textured.vert", "textured.frag", null), "crate");
|
||||
Model cubeDrawable = new Model(cubeMaterial, _mesh);
|
||||
Node3d cubeNode = new Node3d("cubes", cubeDrawable);
|
||||
_scene.addChild(cubeNode);
|
||||
|
||||
|
||||
_minerMesh = new Mesh(VertexFormat(VertexElementType.POSITION, VertexElementType.NORMAL, VertexElementType.COLOR, VertexElementType.TEXCOORD0));
|
||||
_world = new World();
|
||||
|
@ -146,6 +153,12 @@ class UiWidget : VerticalLayout, CellVisitor {
|
|||
|
||||
_world.camPosition = Position(Vector3d(0, 3, 0), Vector3d(0, 0, 1));
|
||||
updateMinerMesh();
|
||||
|
||||
Material minerMaterial = new Material(EffectId("textured.vert", "textured.frag", null), "blocks");
|
||||
Model minerDrawable = new Model(minerMaterial, _minerMesh);
|
||||
Node3d minerNode = new Node3d("miner", minerDrawable);
|
||||
_scene.addChild(minerNode);
|
||||
|
||||
//CellVisitor visitor = new TestVisitor();
|
||||
//Log.d("Testing cell visitor");
|
||||
//long ts = currentTimeMillis;
|
||||
|
@ -229,28 +242,13 @@ class UiWidget : VerticalLayout, CellVisitor {
|
|||
}
|
||||
float angle = 0;
|
||||
|
||||
EffectRef _program;
|
||||
Scene3d _scene;
|
||||
Scene3dRef _scene;
|
||||
Camera _cam;
|
||||
Mesh _mesh;
|
||||
Mesh _minerMesh;
|
||||
GLTexture _tx;
|
||||
GLTexture _blockstx;
|
||||
|
||||
|
||||
/// this is OpenGLDrawableDelegate implementation
|
||||
private void doDraw(Rect windowRect, Rect rc) {
|
||||
if (_program.isNull) {
|
||||
_program = EffectCache.instance.get("textured.vert", "textured.frag");
|
||||
}
|
||||
if (!_tx)
|
||||
_tx = new GLTexture("crate");
|
||||
if (!_blockstx)
|
||||
_blockstx = new GLTexture("blocks");
|
||||
if (!_tx.isValid || !_blockstx.isValid) {
|
||||
Log.e("Invalid texture");
|
||||
return;
|
||||
}
|
||||
_cam.setPerspective(rc.width, rc.height, 45.0f, near, far);
|
||||
_cam.setIdentity();
|
||||
//_cam.translate(vec3(
|
||||
|
@ -329,33 +327,13 @@ class UiWidget : VerticalLayout, CellVisitor {
|
|||
checkgl!glEnable(GL_DEPTH_TEST);
|
||||
checkgl!glCullFace(GL_BACK);
|
||||
|
||||
_program.bind();
|
||||
_program.setUniform("matrix", projectionViewModelMatrix);
|
||||
_tx.texture.setup();
|
||||
_tx.texture.setSamplerParams(true);
|
||||
_scene.drawScene(false);
|
||||
|
||||
_program.draw(_mesh);
|
||||
|
||||
_tx.texture.unbind();
|
||||
|
||||
_blockstx.texture.setup();
|
||||
_blockstx.texture.setSamplerParams(false);
|
||||
|
||||
_program.draw(_minerMesh);
|
||||
|
||||
_blockstx.texture.unbind();
|
||||
|
||||
_program.unbind();
|
||||
checkgl!glDisable(GL_DEPTH_TEST);
|
||||
checkgl!glDisable(GL_CULL_FACE);
|
||||
}
|
||||
|
||||
~this() {
|
||||
destroy(_scene);
|
||||
if (_program)
|
||||
destroy(_program);
|
||||
if (_tx)
|
||||
destroy(_tx);
|
||||
destroy(_world);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,8 @@ class Camera : Node3d {
|
|||
|
||||
protected bool _enabled;
|
||||
|
||||
this() {
|
||||
this(string ID = null) {
|
||||
super(ID);
|
||||
_enabled = true;
|
||||
setPerspective(4.0f, 3.0f, 45.0f, 0.1f, 100.0f);
|
||||
}
|
||||
|
@ -30,6 +31,11 @@ class Camera : Node3d {
|
|||
_enabled = v;
|
||||
}
|
||||
|
||||
/// returns true if some changes occured in projection or view matrix since last matrix getter call
|
||||
@property bool viewChanged() {
|
||||
return _dirtyTransform || _dirtyViewProjection || _dirtyView;
|
||||
}
|
||||
|
||||
/// get projection matrix
|
||||
@property ref const(mat4) projectionMatrix() {
|
||||
return _projectionMatrix;
|
||||
|
|
|
@ -12,40 +12,6 @@ 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;
|
||||
|
@ -181,3 +147,43 @@ class EffectCache {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// Effect ID
|
||||
struct EffectId {
|
||||
string vertexShaderName;
|
||||
string fragmentShaderName;
|
||||
string definitions;
|
||||
this(string vertexShader, string fragmentShader, string defs) {
|
||||
vertexShaderName = vertexShader;
|
||||
fragmentShaderName = fragmentShader;
|
||||
definitions = defs;
|
||||
}
|
||||
|
||||
/// returns true if ID is not assigned
|
||||
@property bool empty() {
|
||||
return !vertexShaderName.length || !vertexShaderName.length;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,16 +7,32 @@ import dlangui.core.logger;
|
|||
import dlangui.graphics.glsupport;
|
||||
import dlangui.graphics.gldrawbuf;
|
||||
import dlangui.graphics.scene.effect;
|
||||
import dlangui.graphics.scene.node;
|
||||
import dlangui.graphics.scene.mesh;
|
||||
|
||||
/// Reference counted Material object
|
||||
alias MaterialRef = Ref!Material;
|
||||
|
||||
class Material : RefCountedObject {
|
||||
protected EffectRef _effect;
|
||||
protected EffectId _effectId;
|
||||
protected TextureRef _texture;
|
||||
protected string _textureId;
|
||||
// TODO: more material properties
|
||||
|
||||
@property EffectRef effect() { return _effect; }
|
||||
this() {
|
||||
}
|
||||
|
||||
this(EffectId effectId, string textureId) {
|
||||
_effectId = effectId;
|
||||
_textureId = textureId;
|
||||
}
|
||||
|
||||
@property EffectRef effect() {
|
||||
if (_effect.isNull && !_effectId.empty)
|
||||
_effect = EffectCache.instance.get(_effectId);
|
||||
return _effect;
|
||||
}
|
||||
/// set as effect instance
|
||||
@property Material effect(EffectRef e) {
|
||||
_effect = e;
|
||||
|
@ -24,11 +40,19 @@ class Material : RefCountedObject {
|
|||
}
|
||||
/// set as effect id
|
||||
@property Material effect(EffectId effectId) {
|
||||
_effect = EffectCache.instance.get(effectId);
|
||||
if (_effectId == effectId)
|
||||
return this; // no change
|
||||
_effectId = effectId;
|
||||
_effect.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
@property TextureRef texture() { return _texture; }
|
||||
@property TextureRef texture() {
|
||||
if (_texture.isNull && _textureId.length) {
|
||||
_texture = GLTextureCache.instance.get(_textureId);
|
||||
}
|
||||
return _texture;
|
||||
}
|
||||
/// set texture
|
||||
@property Material texture(TextureRef e) {
|
||||
_texture = e;
|
||||
|
@ -36,7 +60,32 @@ class Material : RefCountedObject {
|
|||
}
|
||||
/// set texture from resourceId
|
||||
@property Material texture(string resourceId) {
|
||||
_texture = GLTextureCache.instance.get(resourceId);
|
||||
if (_textureId == resourceId)
|
||||
return this; // no change
|
||||
_texture.clear();
|
||||
_textureId = resourceId;
|
||||
return this;
|
||||
}
|
||||
|
||||
void bind(Node3d node) {
|
||||
assert(!effect.isNull);
|
||||
effect.bind();
|
||||
if (!texture.isNull) {
|
||||
texture.texture.setup();
|
||||
texture.texture.setSamplerParams(true);
|
||||
}
|
||||
// TODO: more uniforms
|
||||
_effect.setUniform("matrix", node.projectionViewModelMatrix);
|
||||
}
|
||||
|
||||
void drawMesh(Mesh mesh) {
|
||||
effect.draw(mesh);
|
||||
}
|
||||
|
||||
void unbind() {
|
||||
if (!texture.isNull) {
|
||||
texture.texture.unbind();
|
||||
}
|
||||
effect.unbind();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,21 +5,33 @@ import dlangui.core.math3d;
|
|||
import dlangui.graphics.scene.transform;
|
||||
import dlangui.core.collections;
|
||||
import dlangui.graphics.scene.scene3d;
|
||||
import dlangui.graphics.scene.drawableobject;
|
||||
|
||||
/// 3D scene node
|
||||
class Node3d : Transform {
|
||||
protected Node3d _parent;
|
||||
protected Scene3d _scene;
|
||||
protected string _id;
|
||||
protected DrawableObjectRef _drawable;
|
||||
|
||||
protected mat4 _worldMatrix;
|
||||
|
||||
protected ObjectList!Node3d _children;
|
||||
|
||||
this() {
|
||||
this(string id = null) {
|
||||
super();
|
||||
_id = id;
|
||||
}
|
||||
|
||||
this(string id, DrawableObject drawable) {
|
||||
super();
|
||||
_id = id;
|
||||
_drawable = drawable;
|
||||
}
|
||||
|
||||
/// drawable attached to node
|
||||
@property ref DrawableObjectRef drawable() { return _drawable; }
|
||||
|
||||
/// returns scene for node
|
||||
@property Scene3d scene() {
|
||||
if (_scene)
|
||||
|
@ -41,11 +53,12 @@ class Node3d : Transform {
|
|||
return _children[index];
|
||||
}
|
||||
|
||||
/// add child node
|
||||
void addChild(Node3d node) {
|
||||
/// add child node, return current node
|
||||
Node3d addChild(Node3d node) {
|
||||
_children.add(node);
|
||||
node.parent = this;
|
||||
node.scene = scene;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// removes and destroys child node by index
|
||||
|
@ -53,6 +66,8 @@ class Node3d : Transform {
|
|||
destroy(_children.remove(index));
|
||||
}
|
||||
|
||||
@property ref ObjectList!Node3d children() { return _children; }
|
||||
|
||||
/// parent node
|
||||
@property Node3d parent() {
|
||||
return _parent;
|
||||
|
@ -60,6 +75,7 @@ class Node3d : Transform {
|
|||
|
||||
@property Node3d parent(Node3d v) {
|
||||
_parent = v;
|
||||
_scene = v.scene;
|
||||
return this;
|
||||
}
|
||||
/// id of node
|
||||
|
@ -71,4 +87,9 @@ class Node3d : Transform {
|
|||
_id = v;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// returns projectionMatrix * viewMatrix * modelMatrix
|
||||
@property mat4 projectionViewModelMatrix() {
|
||||
return _scene.projectionViewMatrix * matrix;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
module dlangui.graphics.scene.scene3d;
|
||||
|
||||
import dlangui.core.types;
|
||||
import dlangui.graphics.scene.node;
|
||||
import dlangui.graphics.scene.camera;
|
||||
|
||||
public import dlangui.core.math3d;
|
||||
|
||||
/// Reference counted Scene3d object
|
||||
alias Scene3dRef = Ref!Scene3d;
|
||||
|
||||
/// 3D scene
|
||||
class Scene3d : Node3d {
|
||||
|
||||
|
@ -47,6 +51,29 @@ class Scene3d : Node3d {
|
|||
static mat4 dummyIdentityMatrix;
|
||||
return dummyIdentityMatrix;
|
||||
}
|
||||
|
||||
protected bool _wireframe;
|
||||
void drawScene(bool wireframe) {
|
||||
_wireframe = wireframe;
|
||||
visit(this, &sceneDrawVisitor);
|
||||
}
|
||||
|
||||
protected bool sceneDrawVisitor(Node3d node) {
|
||||
if (!node.drawable.isNull)
|
||||
node.drawable.draw(node, _wireframe);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// depth-first recursive node traversion, stops if visitor returns true
|
||||
bool visit(Node3d node, bool delegate(Node3d node) visitor) {
|
||||
bool res = visitor(node);
|
||||
if (res)
|
||||
return true;
|
||||
foreach(child; node.children) {
|
||||
bool res = visit(child, visitor);
|
||||
if (res)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
module dlangui.graphics.scene.transform;
|
||||
|
||||
import dlangui.core.math3d;
|
||||
import dlangui.core.types;
|
||||
|
||||
/// 3d transform: scale + translation + rotation
|
||||
class Transform {
|
||||
class Transform : RefCountedObject {
|
||||
// transform flags
|
||||
protected bool _dirtyTransform = true;
|
||||
protected bool _hasScale = false;
|
||||
|
|
Loading…
Reference in New Issue