1 ///
2 module isodi.object3d;
3 
4 import std.stdio;
5 import std.string;
6 
7 public {
8 
9     import isodi.bind;
10     import isodi.display;
11     import isodi.position;
12     import isodi.resource;
13 
14 }
15 
16 
17 @safe:
18 
19 
20 /// Represents an object that can be drawn on a 3D space.
21 abstract class Object3D {
22 
23     /// Display this object is connected to.
24     Display display;
25 
26     /// Get the current position of the object.
27     abstract const(Position) position() const;
28 
29     /// Get the current visual position of the object.
30     abstract const(Position) visualPosition() const;
31 
32     /// Params:
33     ///     display = Display to connect to.
34     this(Display display) {
35 
36         this.display = display;
37 
38     }
39 
40     /// Add a basic implementation for the position as a property, includes a setter.
41     mixin template Implement() {
42 
43         @safe:
44 
45         private Position _position;
46 
47         /// Get the current position of the object.
48         ///
49         /// This returns a const value, use `positionRef` to get a reference.
50         override const(Position) position() const { return _position; }
51 
52         /// Ditto
53         override const(Position) visualPosition() const { return position; }
54 
55         /// Get a reference to the position value.
56         ref Position positionRef() { return _position; }
57 
58         /// Set the new position.
59         Position position(Position value) { return _position = value; }
60 
61     }
62 
63     ///
64     static unittest {
65 
66         class Example : Object3D {
67 
68             mixin Object3D.Implement;
69 
70             this() {
71                 super(null);
72             }
73 
74         }
75 
76         auto ex = new Example;
77         assert(ex.position == .position(0, 0));
78 
79         ex.positionRef.x += 1;
80         assert(ex.position == .position(1, 0));
81 
82         ex.position = .position(2, 2);
83         assert(ex.position == .position(2, 2));
84 
85     }
86 
87     /// Implement the position as a const property. `_position` and `_visualPosition` must be set in constructor.
88     mixin template ImplementConst() {
89 
90         @safe:
91 
92         private const Position _position;
93         override const(Position) position() const { return _position; }
94 
95         private Position _visualPosition;
96 
97         /// Get the position the cell is displayed on.
98         override const(Position) visualPosition() const {
99 
100             return _visualPosition;
101 
102         }
103 
104         /// Set an offset for the visual position.
105         ///
106         /// $(B Note:) Mind that depth is initialized to 1 by default, which might cause unwanted effects. If you don't
107         /// want to offset it, use `positionOff`.
108         const(Position) offset(Position value) {
109 
110             return _visualPosition = _position.sum(value);
111 
112         }
113 
114         /// Reset the offset
115         void resetOffset() {
116 
117             _visualPosition = _position;
118 
119         }
120 
121     }
122 
123 }