From: Jerome St-Louis Date: Tue, 29 Sep 2015 19:32:47 +0000 (-0400) Subject: samples/guiAndGfx: eC port of JFD's Mekano X-Git-Tag: 0.44.13~58 X-Git-Url: http://ecere.com/cgi-bin/gitweb.cgi?p=sdk;a=commitdiff_plain;h=c1af37d3e44598dec203e5521ef0bd9c810b92f3 samples/guiAndGfx: eC port of JFD's Mekano - A mechanic simulation featuring springs by Jonathan Fillion-Deneault - Ported this classic Ecere sample which was using the C++ Ecere class library from ~2003 to eC --- diff --git a/samples/guiAndGfx/mekano/mekano.ec b/samples/guiAndGfx/mekano/mekano.ec new file mode 100644 index 0000000..b48d595 --- /dev/null +++ b/samples/guiAndGfx/mekano/mekano.ec @@ -0,0 +1,3 @@ +import "mekanownd" + +MekanoWnd mekano { displayDriver = "OpenGL"; }; diff --git a/samples/guiAndGfx/mekano/mekano.epj b/samples/guiAndGfx/mekano/mekano.epj new file mode 100644 index 0000000..ab8c3f3 --- /dev/null +++ b/samples/guiAndGfx/mekano/mekano.epj @@ -0,0 +1,112 @@ +{ + "Version" : 0.2, + "ModuleName" : "mekano", + "Options" : { + "Warnings" : "All", + "Debug" : false, + "Profile" : false, + "TargetType" : "Executable", + "TargetFileName" : "mekano", + "TargetDirectory" : "", + "Libraries" : [ + "ecere" + ] + }, + "Configurations" : [ + { + "Name" : "Debug", + "Options" : { + "Debug" : true, + "PreprocessorDefinitions" : [ + "IMPORT_STATIC=\"\"" + ], + "Console" : true + } + }, + { + "Name" : "Release", + "Options" : { + "Optimization" : "Speed", + "PreprocessorDefinitions" : [ + "IMPORT_STATIC=static" + ], + "Libraries" : [ + "ecereStatic" + ], + "LinkerOptions" : [ + "-static" + ], + "LibraryDirs" : [ + "../../../ecere/obj/static.win32" + ], + "Console" : true, + "Compress" : true, + "FastMath" : true + }, + "Platforms" : [ + { + "Name" : "win32", + "Options" : { + "Libraries" : [ + "dxguid", + "ddraw", + "dinput", + "winmm", + "opengl32", + "ws2_32", + "kernel32", + "user32", + "gdi32", + "mpr", + "advapi32", + "shell32", + "winspool", + "imm32", + "ungif", + "jpeg", + "png", + "z", + "freetype" + ] + } + } + ] + } + ], + "Files" : [ + { + "Folder" : "src", + "Files" : [ + "./mekano.ec", + "./mekanodisplay.ec", + "./mekanoobject.ec", + "./mekanoobjectfixed.ec", + "./mekanoobjectgravity.ec", + "./mekanoobjectpolygonal.ec", + "./mekanoobjectspring.ec", + "./mekanopoint.ec", + "./mekanopolygon.ec", + "./mekanopolygonalbox.ec", + "./mekanosimulation.ec", + "./mekanownd.ec", + "./vector.ec" + ] + } + ], + "ResourcesPath" : "..\\..\\..\\", + "Resources" : [ + { + "Folder" : "ecere", + "Files" : [ + { + "Folder" : "shaders", + "Files" : [ + "../../../ecere/src/gfx/drivers/gl3/fixed.frag", + "../../../ecere/src/gfx/drivers/gl3/fixed.vertex" + ] + } + ] + }, + "data/ecere.bmp" + ] +} diff --git a/samples/guiAndGfx/mekano/mekanodisplay.ec b/samples/guiAndGfx/mekano/mekanodisplay.ec new file mode 100644 index 0000000..46552cd --- /dev/null +++ b/samples/guiAndGfx/mekano/mekanodisplay.ec @@ -0,0 +1,115 @@ +import "mekanopolygon" + +define COLORSPRING = orange; +define COLORPOLY = magenta; +define COLORBOX = blue; +define COLORCROSS = lime; + +class MekanoDisplay +{ + Surface surface; + +public: + void drawPolygon(Vector2D position, MekanoPolygon polygon) + { + List points=polygon.points; + if(points.count > 1) + { + MekanoPoint point1, point2 = null, firstpoint = null; + Vector2D point_pos1, point_pos2; + bool first = true; + + surface.foreground = COLORPOLY; + + for(p : points) + { + if(first) + { + point2 = firstpoint = p; + first = false; + } + else + { + point1 = point2; + point2 = p; + point_pos1=point1.localPosition; + point_pos2=point2.localPosition; + + surface.DrawLine((int)(position.x+point_pos1.x), (int)(position.y+point_pos1.y), + (int)(position.x+point_pos2.x), (int)(position.y+point_pos2.y)); + } + } + point_pos1=point2.localPosition; + point_pos2=firstpoint.localPosition; + surface.DrawLine((int)(position.x+point_pos1.x), (int)(position.y+point_pos1.y), + (int)(position.x+point_pos2.x), (int)(position.y+point_pos2.y)); + } + } + + void drawBox(Vector2D position, int width) + { + surface.foreground = COLORBOX; + surface.Rectangle( + (short)position.x-width/2, (short)position.y-width/2, + (short)position.x+width/2, (short)position.y+width/2); + } + + void drawCrossHair(Vector2D position, int width) + { + surface.foreground = COLORCROSS; + surface.HLine((short)position.x-width/2, (short)position.x+width/2, + (short)position.y); + surface.VLine((short)position.y-width/2, (short)position.y+width/2, + (short)position.x); + } + + void drawSpring(Vector2D pos1, Vector2D pos2, int zigs) + { + int t; + float lzig, h = 10.0; + Vector2D d=pos1; + Vector2D o; + Vector2D u, n; + Vector2D a1, a2; + + surface.foreground = COLORSPRING; + + o.subtract(pos2, pos1); + + u=o.unit; + n=o.normal; + lzig=o.length/zigs; + + // a1=u*(lzig*1/4)+n*h; + { + Vector2D t1, t2; + t1.scale(u, lzig*1/4); + t2.scale(n, h); + a1.add(t1, t2); + } + + // a2=u*(lzig*2/4)-n*h*2.0; + { + Vector2D t1, t2; + t1.scale(u, lzig*2/4); + t2.scale(n, h*2.0f); + a2.subtract(t1, t2); + } + + for (t=0; t m_Points { }; + +public: + + ~MekanoObject() + { + m_Points.Free(); + } + + property MekanoSimulation simulation { set { value.addObject(this); } } + + mass = 1.0f; + inertiaMoment = 10; + angularFriction = 0.1f; + + property float cosRotation { get { return m_fCosRotation; } }; + property float sinRotation { get { return m_fSinRotation; } }; + + property float mass + { + set { m_fMass=value; } + get { return m_fMass; } + } + + property float inertiaMoment + { + set { m_fInertiaMoment=value; } + get { return m_fInertiaMoment; } + } + + property float boundingRadius + { + set { m_fBoundingRadius=value; } + get { return m_fBoundingRadius; } + } + + property float angularSpeed + { + set { m_fAngularSpeed=value; } + get { return m_fAngularSpeed; } + } + + property float angularAcceleration + { + set { m_fAngularAcceleration=value; } + get { return m_fAngularAcceleration; } + } + + property float angularFriction + { + set { m_fAngularFriction=value; } + get { return m_fAngularFriction; } + } + + property Vector2D lastPosition + { + set { m_LastPosition=value; } + get { value = m_LastPosition; } + } + + property Vector2D position + { + set { m_Position=value; } + get { value = m_Position; } + } + + property Vector2D speed + { + set { m_Speed=value; } + get { value = m_Speed; } + } + + property Vector2D acceleration + { + set { m_Acceleration=value; } + get { value = m_Acceleration; } + } + + property Vector2D deltaPosition { get { value.subtract(m_Position, m_LastPosition); } }; + + property ObjectAttributes attributes { set { m_Attributes=value; } get { return m_Attributes; } } + + property Vector2D AppliedForce + { + set { m_AppliedForce=value; } + get { value = m_AppliedForce; } + } + + property float appliedTorque + { + set { m_fAppliedTorque=value; } + get { return m_fAppliedTorque; } + } + + property List points { get { return m_Points; } }; + + property MekanoPoint centerPoint + { + get + { + for(p : m_Points; p.type == center) + return p; + return null; + } + } + + property float rotation + { + get { return m_fRotation; } + set + { + m_fRotation=value; + m_fCosRotation=(float)cos(value); + m_fSinRotation=(float)sin(value); + } + } + + virtual void resetForces() { m_AppliedForce = { }, m_fAppliedTorque = 0; }; + virtual void exertForces(MekanoSimulation sim); + virtual void applyForce(Vector2D f, MekanoPoint pt); + virtual void draw(MekanoDisplay display); + virtual void step(Time dt) { lastPosition = m_Position; } + virtual bool isInside(Vector2D v) { return false; } + virtual bool isColliding(MekanoPoint pt, Vector2D normal) { return false; } + + void computeBoundingRadius() + { + for(p : m_Points; p.type == vertex) + p.computeBoundingRadius(); + } +} diff --git a/samples/guiAndGfx/mekano/mekanoobjectfixed.ec b/samples/guiAndGfx/mekano/mekanoobjectfixed.ec new file mode 100644 index 0000000..21bfba9 --- /dev/null +++ b/samples/guiAndGfx/mekano/mekanoobjectfixed.ec @@ -0,0 +1,12 @@ +import "mekanoobject" + +define CROSSHAIRWIDTH = 10; + +class MekanoObjectFixed : MekanoObject +{ +public: + void draw(MekanoDisplay display) + { + display.drawCrossHair(m_Position, CROSSHAIRWIDTH); + } +}; diff --git a/samples/guiAndGfx/mekano/mekanoobjectgravity.ec b/samples/guiAndGfx/mekano/mekanoobjectgravity.ec new file mode 100644 index 0000000..0c50aa4 --- /dev/null +++ b/samples/guiAndGfx/mekano/mekanoobjectgravity.ec @@ -0,0 +1,24 @@ +import "mekanosimulation" + +class MekanoObjectGravity : MekanoObject +{ + Vector2D gravity; + +public: + property Vector2D gravity + { + set { gravity = value; } + get { value = gravity; } + } + + void exertForces(MekanoSimulation sim) + { + for(o : sim.objectList) + for(p : o.points; p.type == center) + { + Vector2D f; + f.scale(gravity, o.mass); + o.applyForce(f, p); + } + } +} diff --git a/samples/guiAndGfx/mekano/mekanoobjectpolygonal.ec b/samples/guiAndGfx/mekano/mekanoobjectpolygonal.ec new file mode 100644 index 0000000..348f643 --- /dev/null +++ b/samples/guiAndGfx/mekano/mekanoobjectpolygonal.ec @@ -0,0 +1,54 @@ +import "mekanoobject" +import "mekanopolygon" + +class MekanoObjectPolygonal : MekanoObject +{ +private: + List m_Polygons { }; + +public: + property List polygons { get { return m_Polygons; } } + + void addPolygon(MekanoPolygon polygon) + { + m_Polygons.Add(polygon); + } + + ~MekanoObjectPolygonal() + { + m_Polygons.Free(); + } + + void computePoints() + { + for(poly : m_Polygons) + { + for(p : poly.points) + { + p.lastLocalPosition = p.localPosition; + p.computeLocalPosition(); + } + } + } + + void draw(MekanoDisplay display) + { + MekanoObject::draw(display); + for(p : m_Polygons) + display.drawPolygon(m_Position, p); + } + + bool isInside(Vector2D v) + { + Vector2D localposition; + float radius = boundingRadius; + localposition.subtract(v, position); + if(radius) + if(localposition.length > radius) + return false; + + for(p : m_Polygons; p.isInside(localposition)) + return true; + return false; + } +} diff --git a/samples/guiAndGfx/mekano/mekanoobjectspring.ec b/samples/guiAndGfx/mekano/mekanoobjectspring.ec new file mode 100644 index 0000000..dda7c7b --- /dev/null +++ b/samples/guiAndGfx/mekano/mekanoobjectspring.ec @@ -0,0 +1,94 @@ +import "mekanoobject" + +define DEFAULTZIGS = 5; + +class MekanoObjectSpring : MekanoObject +{ +private: + float m_fLength; + float m_fRestitution; + float m_fDamping; + bool m_bLinked; + int m_nZigs; + + MekanoPoint m_pLinkPoints[2]; + +public: + + m_nZigs=DEFAULTZIGS; + m_fRestitution=1; + m_fDamping=2; + + property float length + { + set { m_fLength=value; } + get { return m_fLength; } + } + + property float damping + { + set { m_fDamping=value; } + get { return m_fDamping; } + } + + property float restitution + { + set { m_fRestitution=value; } + get { return m_fRestitution; } + } + + property int zigs + { + set { m_nZigs=value; } + get { return m_nZigs; } + } + + void draw(MekanoDisplay display) + { + if(m_bLinked) + { + Vector2D pos0=m_pLinkPoints[0].screenPosition; + Vector2D pos1=m_pLinkPoints[1].screenPosition; + display.drawSpring(pos0, pos1, m_nZigs); + } + } + + void exertForces(MekanoSimulation sim) + { + if(m_bLinked) + { + Vector2D relativepos; + Vector2D relativespeed; + Vector2D damping, force; + MekanoObject obj0, obj1; + float stretch; + + obj0=m_pLinkPoints[0].object; + obj1=m_pLinkPoints[1].object; + + relativepos.subtract(m_pLinkPoints[1].screenPosition, m_pLinkPoints[0].screenPosition); + relativespeed.subtract(obj1.speed, obj0.speed); + stretch=relativepos.length-m_fLength; + + //damping=relativespeed*m_fDamping*(relativespeed%relativepos)/(relativepos%relativepos); + damping.scale(relativespeed, m_fDamping); + force.scale(relativepos.unit, stretch*m_fRestitution); + + obj0.applyForce(force, m_pLinkPoints[0]); + obj0.applyForce(damping, m_pLinkPoints[0]); + + force.scale(force, -1); + damping.scale(force, -1); + + obj1.applyForce(force, m_pLinkPoints[1]); + obj1.applyForce(damping, m_pLinkPoints[1]); + } + } + + void link(MekanoPoint p1, MekanoPoint p2) + { + m_pLinkPoints[0]=p1; + m_pLinkPoints[1]=p2; + m_bLinked=true; + } +} diff --git a/samples/guiAndGfx/mekano/mekanopoint.ec b/samples/guiAndGfx/mekano/mekanopoint.ec new file mode 100644 index 0000000..4861087 --- /dev/null +++ b/samples/guiAndGfx/mekano/mekanopoint.ec @@ -0,0 +1,39 @@ +import "vector" +import "mekanoobject" + +public enum MekanoPointType { unknown, center, vertex }; + +class MekanoPoint : struct // TOFIX: Container issues with this : private Vector2D +{ +private: + Vector2D pt; + MekanoPointType m_Type; + MekanoObject m_pObject; + Vector2D m_LastLocalPosition; + Vector2D m_LocalPosition; + Vector2D m_ScreenPosition; + +public: + property MekanoObject object { set { m_pObject = value; value.addPoint(this); } get { return m_pObject; } } + property MekanoPointType type { set { m_Type = value; } get { return m_Type; } } + property float x { set { pt.x = value; } get { return pt.x; } } + property float y { set { pt.y = value; } get { return pt.y; } } + + property Vector2D lastLocalPosition { set { m_LastLocalPosition = value; } } + property Vector2D localPosition { get { value = m_LocalPosition; } } + property Vector2D deltaLocalPosition { get { value.subtract(m_LocalPosition, m_LastLocalPosition); } } + property Vector2D screenPosition { get { value.add(m_LocalPosition, m_pObject.position); } } + property Vector2D deltaScreenPosition { get { value.add(deltaLocalPosition, m_pObject.deltaPosition); } } + + void computeLocalPosition() + { + m_LocalPosition = { x*m_pObject.cosRotation - y * m_pObject.sinRotation, x*m_pObject.sinRotation + y*m_pObject.cosRotation }; + } + + void computeBoundingRadius() + { + float l = pt.length; + if(m_pObject.boundingRadius < l) + m_pObject.boundingRadius = l; + } +}; diff --git a/samples/guiAndGfx/mekano/mekanopolygon.ec b/samples/guiAndGfx/mekano/mekanopolygon.ec new file mode 100644 index 0000000..5e29487 --- /dev/null +++ b/samples/guiAndGfx/mekano/mekanopolygon.ec @@ -0,0 +1,56 @@ +import "mekanoobjectpolygonal" + +class MekanoPolygon +{ + List m_Points { }; + +public: + property MekanoObjectPolygonal polygonal { set { value.addPolygon(this); } } + + property List points { get { return m_Points; } } + + void addPoint(MekanoPoint point) + { + m_Points.Add(point); + } + + bool ::crosses(Vector2D c, Vector2D p1, Vector2D p2) + { + if(c.y>Min(p1.y, p2.y) && c.y 1) + { + int c = 0; + MekanoPoint point1, point2 = null, firstpoint = null; + bool first = true; + + for(p : m_Points) + { + if(first) + { + firstpoint = point2 = p; + first = false; + } + else + { + point1 = point2; + point2 = p; + if(crosses(v, point1.localPosition, point2.localPosition)) + c++; + } + } + if(crosses(v, point2.localPosition, firstpoint.localPosition)) + c++; + return c & 1; + } + return false; + } +} diff --git a/samples/guiAndGfx/mekano/mekanopolygonalbox.ec b/samples/guiAndGfx/mekano/mekanopolygonalbox.ec new file mode 100644 index 0000000..ec6a76f --- /dev/null +++ b/samples/guiAndGfx/mekano/mekanopolygonalbox.ec @@ -0,0 +1,80 @@ +import "mekanoobjectpolygonal" + +enum ObjBoxPointType { topPoint = 1, bottomPoint = 2 }; + +class MekanoPolygonalBox : MekanoObjectPolygonal +{ +private: + float m_fSize; + +public: + property int size + { + get { return (int)m_fSize; } + set + { + MekanoPolygon polygon { this }; + + MekanoPoint { this, type = center }; + polygon.addPoint(MekanoPoint { this, type = vertex, -value/2+2, -value/2+2 }); + polygon.addPoint(MekanoPoint { this, type = vertex, 0, -value/2 }); // 1 + polygon.addPoint(MekanoPoint { this, type = vertex, value/2-2, -value/2+2 }); + polygon.addPoint(MekanoPoint { this, type = vertex, value/2-2, value/2-2 }); + polygon.addPoint(MekanoPoint { this, type = vertex, 0, value/2 }); // 4 + polygon.addPoint(MekanoPoint { this, type = vertex, -value/2+2, value/2-2 }); + m_fSize = value; + + computeBoundingRadius(); + } + } + + void applyForce(Vector2D v, MekanoPoint pt) + { + m_AppliedForce.add(m_AppliedForce, v); + m_fAppliedTorque += v.dotProduct(pt.localPosition.normal); + } + + void step(Time dt) + { + MekanoObjectPolygonal::step(dt); + + // Translation + m_Acceleration.divide(m_AppliedForce, m_fMass); + + m_Speed.x+=m_Acceleration.x*(float)dt; + m_Speed.y+=m_Acceleration.y*(float)dt; + + m_Position.x+=m_Speed.x*(float)dt; + m_Position.y+=m_Speed.y*(float)dt; + + // Rotation + m_fAngularAcceleration=m_fAppliedTorque/m_fInertiaMoment; + m_fAngularSpeed+=m_fAngularAcceleration*(float)dt; + + // FIXME: Air friction here? + m_fAngularSpeed-=m_fAngularFriction*m_fAngularSpeed; + + rotation += +m_fAngularSpeed*(float)dt; + computePoints(); + } + + MekanoPoint getCertainPoint(ObjBoxPointType type) + { + List polygons = this.polygons; + if(polygons.count) + { + MekanoPolygon polygon = polygons[0]; + int index = 0, lookup = type == topPoint ? 1 : 4; + for(p : polygon.points; index++ == lookup) + return p; + } + return null; + } + + void draw(MekanoDisplay display) + { + MekanoObjectPolygonal::draw(display); + if(attributes.highlighted) + display.drawCrossHair(position, 10); + } +} diff --git a/samples/guiAndGfx/mekano/mekanosimulation.ec b/samples/guiAndGfx/mekano/mekanosimulation.ec new file mode 100644 index 0000000..8bc4adc --- /dev/null +++ b/samples/guiAndGfx/mekano/mekanosimulation.ec @@ -0,0 +1,75 @@ +import "mekanodisplay" + +class MekanoSimulation +{ +private: + List m_Objects { }; + + float m_fTimeMultiplier; + Time m_LastTime; + +public: + timeMultiplier = 1.0f; + m_LastTime = GetTime(); + + property float timeMultiplier + { + get { return m_fTimeMultiplier; } + set { m_fTimeMultiplier=value; } + } + + property List objectList + { + get { return m_Objects; } + } + + property Time elapsedSeconds + { + get + { + Time time = GetTime(), diff=time - m_LastTime; + m_LastTime = time; + return diff; + } + } + + void render(MekanoDisplay display) + { + for(o : m_Objects) + o.draw(display); + } + + void step(Time dt) + { + for(o : m_Objects; !o.attributes.steady) + o.step(dt); + } + + void stepDelta() + { + step(elapsedSeconds * m_fTimeMultiplier); + } + + void exertForces() + { + for(o : m_Objects) + o.exertForces(this); + } + + void resetForces() + { + for(o : m_Objects) + o.resetForces(); + } + + void addObject(MekanoObject object) + { + incref object; + m_Objects.Add(object); + } + + void empty() + { + m_Objects.Free(); + } +} diff --git a/samples/guiAndGfx/mekano/mekanownd.ec b/samples/guiAndGfx/mekano/mekanownd.ec new file mode 100644 index 0000000..e2c553b --- /dev/null +++ b/samples/guiAndGfx/mekano/mekanownd.ec @@ -0,0 +1,161 @@ +import "mekanoobjectfixed" +import "mekanoobjectspring" +import "mekanopolygonalbox" +import "mekanoobjectgravity" + +class MekanoWnd : Window +{ +private: + Point mouse; + MekanoDisplay display { }; + MekanoSimulation simulation { timeMultiplier = 4.0f }; + + MekanoObjectFixed fix; + fix = { simulation, position = { 300, 50 } }; + MekanoPolygonalBox pbox; + pbox = { simulation, size = 20, mass = 10, inertiaMoment = 200 }; + MekanoObjectSpring spring; + spring = { simulation, length = 60, restitution = 30 }; + + MekanoObjectGravity gravity { gravity = { 0, 10 } }; + + MekanoPolygonalBox lastbox; + bool selected, dragging, buttondown; + +public: + + caption = "Mekano"; + hasMaximize = true, hasMinimize = true, hasClose = true; + borderStyle = sizable; + clientSize = { 640, 480 }; + background = slateGray; + + BitmapResource bg { ":ecere.bmp", window = this }; + + MekanoWnd() + { + RandomSeed((uint)(((uint64)(GetTime() * 1000)) & MAXDWORD)); + pbox.position = { GetRandom(0,500), 110 }; + spring.link(MekanoPoint { fix, type = center }, pbox.getCertainPoint(topPoint)); + lastbox = pbox; + } + + ~MekanoWnd() + { + simulation.empty(); + } + + Timer timer + { + this, started = true; + + bool DelayExpired() + { + simulation.resetForces(); + + simulation.exertForces(); + simulation.stepDelta(); + + if(!buttondown) dragging = false; + + for(object : simulation.objectList) + { + ObjectAttributes attributes=object.attributes; + if(attributes.selected) + if(dragging) + object.position = { mouse.x, mouse.y }; + + attributes.selected = false; + attributes.steady = false; + + if(object.isInside({ mouse.x, mouse.y })) + { + attributes.highlighted = true; + if(buttondown) + { + dragging=true; + attributes.selected = true; + attributes.steady = true; + } + } + else + { + attributes.selected = false; + attributes.highlighted = false; + } + object.attributes = attributes; + } + Update(null); + + return true; + } + }; + + void OnRedraw(Surface surface) + { + //surface.Tile(bg.bitmap, 0, 0, clientSize.w, clientSize.h); + display.surface = surface; + simulation.render(display); + } + + bool OnRightButtonDown(int x, int y, Modifiers mods) + { + /* + fix = MekanoObjectFixed { simulation, position = { x, y } }; + spring = { simulation, length = 30; restitution = 2; }; + + spring.link(MekanoPoint { fix, type = center }, pbox.centerPoint); + */ + + //int c; for(c = 0; c<400; c++) { + pbox = + { + simulation, + size = 20, + position = { x, y }, + mass = 10 + }; + + spring = + { + simulation, + length = 40, + restitution = 10 + }; + + spring.link(lastbox.getCertainPoint(bottomPoint), pbox.getCertainPoint(topPoint)); + lastbox=pbox; + //} + return true; + } + + bool OnLeftButtonUp(int x, int y, Modifiers mods) + { + buttondown=false; + ReleaseCapture(); + return true; + } + + bool OnLeftButtonDown(int x, int y, Modifiers mods) + { + buttondown=true; + Capture(); + return true; + } + + bool OnMouseMove(int x, int y, Modifiers mods) + { + mouse = { x, y }; + return true; + } + + bool OnKeyDown(Key key, unichar ch) + { + switch(key) + { + case escape: Destroy(0); return false; + case f: ((GuiApplication)__thisModule.application).fullScreen ^= true; return false; + } + return true; + } +} diff --git a/samples/guiAndGfx/mekano/vector.ec b/samples/guiAndGfx/mekano/vector.ec new file mode 100644 index 0000000..6223f38 --- /dev/null +++ b/samples/guiAndGfx/mekano/vector.ec @@ -0,0 +1,15 @@ +import IMPORT_STATIC "ecere" + +struct Vector2D : Pointf +{ + float dotProduct(Vector2D v) { return x*v.x + y*v.y; } + void scale(Vector2D v, float s) { this = { v.x*s, v.y*s }; } + void divide(Vector2D v, float s) { this = { v.x/s, v.y/s }; } + void add(Vector2D a, Vector2D v) { this = { a.x+v.x, a.y+v.y }; } + void subtract(Vector2D a, Vector2D v) { this = { a.x-v.x, a.y-v.y }; } + void normalize() { float norm = length; this = norm ? { x / norm, y / norm } : { 0, 0 }; } + + property float length { get { return (float)sqrt(x*x+y*y); } } + property Vector2D normal { get { value = { -y, x }; value.normalize(); } } + property Vector2D unit { get { value = this; value.normalize(); } } +};