├── bin
└── README.txt
├── assets
├── haxeui.png
├── img
│ ├── control-090.png
│ └── control-270.png
├── fonts
│ ├── Roboto-Regular.eot
│ ├── Roboto-Regular.ttf
│ ├── Roboto-Regular.woff
│ └── Roboto-Regular.woff2
├── styles
│ └── default
│ │ └── main.css
├── css
│ ├── dark.min.css
│ ├── ui.min.css
│ ├── dark.css
│ └── ui.css
├── shader
│ └── lyapunov.frag
└── ui
│ └── ui.xml
├── .gitignore
├── haxeui2-fractalgenerator.jpg
├── src
├── module.xml
├── MathUtils.hx
├── UI.hx
└── Main.hx
├── README.md
├── LICENSE
├── application.xml
└── haxe-shaderfun.hxproj
/bin/README.txt:
--------------------------------------------------------------------------------
1 | haxe build directory
--------------------------------------------------------------------------------
/assets/haxeui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maitag/haxe-shaderfun/HEAD/assets/haxeui.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bin/html5/
2 | bin/windows/
3 | bin/android/
4 | bin/linux/
5 | bin/flash/
6 | .build
7 |
--------------------------------------------------------------------------------
/assets/img/control-090.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maitag/haxe-shaderfun/HEAD/assets/img/control-090.png
--------------------------------------------------------------------------------
/assets/img/control-270.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maitag/haxe-shaderfun/HEAD/assets/img/control-270.png
--------------------------------------------------------------------------------
/haxeui2-fractalgenerator.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maitag/haxe-shaderfun/HEAD/haxeui2-fractalgenerator.jpg
--------------------------------------------------------------------------------
/assets/fonts/Roboto-Regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maitag/haxe-shaderfun/HEAD/assets/fonts/Roboto-Regular.eot
--------------------------------------------------------------------------------
/assets/fonts/Roboto-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maitag/haxe-shaderfun/HEAD/assets/fonts/Roboto-Regular.ttf
--------------------------------------------------------------------------------
/assets/fonts/Roboto-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maitag/haxe-shaderfun/HEAD/assets/fonts/Roboto-Regular.woff
--------------------------------------------------------------------------------
/assets/fonts/Roboto-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maitag/haxe-shaderfun/HEAD/assets/fonts/Roboto-Regular.woff2
--------------------------------------------------------------------------------
/src/module.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/MathUtils.hx:
--------------------------------------------------------------------------------
1 | package;
2 |
3 | class MathUtils {
4 | public static function round(number:Float, precision:Int):Float {
5 | var num = number;
6 | num = num * Math.pow(10, precision);
7 | num = Math.round( num ) / Math.pow(10, precision);
8 | return num;
9 | }
10 | }
--------------------------------------------------------------------------------
/assets/styles/default/main.css:
--------------------------------------------------------------------------------
1 | .label, .textfield {
2 | /*font-name: "fonts/Roboto-Regular.ttf";*/
3 | font-name: "_sans";
4 | font-size: 13px;
5 | }
6 |
7 | .flash .label, .flash .textfield {
8 | font-name: "_sans";
9 | }
10 |
11 | .scrollview {
12 | padding: 1px;
13 | padding-bottom: 2px;
14 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # haxe-shaderfun
2 |
3 |
4 | [lyapunov fat fractals](https://github.com/maitag/lyapunov-c#lyapunov-c) and [haxeui 2](https://github.com/haxeui/haxeui-openfl#haxeui-openfl)
5 |
6 | [click here to explore fractal set](http://maitag.de/semmi/haxeopenfl/haxeui2-fractalgenerator/?AAFDCbIBvgIrAjUCvcv/FDB34XJ0fv6HxTy/38OamZk/)
7 |
8 |
9 | [](http://maitag.de/semmi/haxeopenfl/haxeui2-fractalgenerator/?8QBvEMABagK+AnwCTwAWDTi8VX3d5dxYxUGSAEUAAIA/)
--------------------------------------------------------------------------------
/assets/css/dark.min.css:
--------------------------------------------------------------------------------
1 | .button{border:1px solid #191C21;background-color:#4B4E53;background-color-end:#37383C;color:#C6C6C8;padding}
2 | .button:hover{border:1px solid #191C21;background-color:#53565B;background-color-end:#3C3D41;color:#C1C2C6;}
3 | .button:down{border:1px solid #1C1D1F;background-color:#2C2D2F;background-color-end:#43484C;color:#A2A3A5;}
4 | .hslider .slider-value-background,.vslider .slider-value-background{border:1px solid #101010;background-color:#353535;background-color-end:#434343;filter:drop-shadow(1,45,#000000,0.5,2,2,1,3,true);padding:1px;}
5 | .hslider .slider-value-background{height:6px;}
6 | .vslider .slider-value-background{width:6px;}
7 | .hslider .slider-button,.vslider .slider-button{border:1px solid #101010;background-color:#E6E6E6;background-color-end:#A0A0A0;}
8 | .hslider .slider-value,.vslider .slider-value{background-color:#FD4653;background-color-end:#AC282F;}
9 |
10 |
--------------------------------------------------------------------------------
/assets/css/ui.min.css:
--------------------------------------------------------------------------------
1 | .label{color:#000000;vertical-align:center;}
2 | .hbox{width:100%;padding:0;}
3 | .vbox{padding:0;}
4 | #main{background-color:#707070;padding:10px;padding-left:14px;padding-bottom:14px;border:1px solid #222222;}
5 | .header{font-size:18px;color:#D0D0D0;vertical-align:center;}
6 | .header-small{font-size:11px;color:#C0C0C0;padding-bottom:10px;}
7 | .formula{width:100%;}
8 | .left{width:28%;}
9 | .middle{width:58%;}
10 | .right{width:14%;}
11 | .random-button{width:100%;}
12 | .col-label{horizontal-align:center;}
13 | .red .slider-value{background-color:#702211;background-color-end:#602211;}
14 | .green .slider-value{background-color:#1a661a;background-color-end:#1a551a;}
15 | .blue .slider-value{background-color:#223388;background-color-end:#223377;}
16 | .button{color:#C0C0C2;font-size:15px;}
17 | .hslider .slider-value-background{height:8px;}
18 | .vslider .slider-value-background{width:8px;}
19 | .hslider .slider-value{background-color:#AAAAAA;background-color-end:#888888;}
20 |
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Sylvio Sell
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/application.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/assets/css/dark.css:
--------------------------------------------------------------------------------
1 | /************************************************************************
2 | ** BUTTON
3 | *************************************************************************/
4 | .button {
5 | border: 1px solid #191C21;
6 | background-color: #4B4E53;
7 | background-color-end: #37383C;
8 | color: #C6C6C8;
9 | padding
10 | }
11 |
12 | .button:hover {
13 | border: 1px solid #191C21;
14 | background-color: #53565B;
15 | background-color-end: #3C3D41;
16 | color: #C1C2C6;
17 | }
18 |
19 | .button:down {
20 | border: 1px solid #1C1D1F;
21 | background-color: #2C2D2F;
22 | background-color-end: #43484C;
23 | color: #A2A3A5;
24 | }
25 |
26 | /************************************************************************
27 | ** HSLIDER / VSLIDER
28 | *************************************************************************/
29 | .hslider .slider-value-background, .vslider .slider-value-background {
30 | border: 1px solid #101010;
31 | background-color: #353535;
32 | background-color-end: #434343;
33 | filter: drop-shadow(1, 45, #000000, 0.5, 2, 2, 1, 3, true);
34 | padding: 1px;
35 | }
36 |
37 | .hslider .slider-value-background {
38 | height: 6px;
39 | }
40 |
41 | .vslider .slider-value-background {
42 | width: 6px;
43 | }
44 |
45 | .hslider .slider-button, .vslider .slider-button {
46 | border: 1px solid #101010;
47 | background-color: #E6E6E6;
48 | background-color-end: #A0A0A0;
49 | }
50 |
51 | .hslider .slider-value, .vslider .slider-value {
52 | background-color: #FD4653;
53 | background-color-end: #AC282F;
54 | }
55 |
--------------------------------------------------------------------------------
/assets/css/ui.css:
--------------------------------------------------------------------------------
1 | .label {
2 | color: #000000;
3 | vertical-align: center;
4 | }
5 |
6 | .hbox {
7 | width: 100%;
8 | padding:0;
9 | }
10 |
11 | .vbox {
12 | padding:0;
13 | }
14 |
15 | #main {
16 | background-color: #707070;
17 | padding: 10px;
18 | padding-left: 14px;
19 | padding-bottom: 14px;
20 | border: 1px solid #222222;
21 | }
22 |
23 | /* --- header labels ----------------- */
24 | .header {
25 | font-size: 18px;
26 | color: #D0D0D0;
27 | vertical-align: center;
28 | }
29 |
30 | .header-small {
31 | font-size: 11px;
32 | color: #C0C0C0;
33 | padding-bottom: 10px;
34 | }
35 |
36 |
37 | /* --- textfield for formula --- */
38 | .formula {
39 | width: 100%;
40 | }
41 |
42 | /* --- columns for upper parameters --- */
43 |
44 | .left {
45 | width: 28%;
46 | }
47 |
48 | .middle {
49 | width: 58%;
50 | }
51 |
52 | .right {
53 | width: 14%;
54 | }
55 |
56 |
57 | /* -------- random button ------------ */
58 | .random-button {
59 | width: 100%;
60 | }
61 |
62 |
63 | /* -------- color labels ------------- */
64 | .col-label {
65 | horizontal-align: center;
66 | }
67 |
68 |
69 | /* -------- colored sliders ---------- */
70 | .red .slider-value {
71 | background-color: #702211;
72 | background-color-end: #602211;
73 | }
74 |
75 | .green .slider-value {
76 | background-color: #1a661a;
77 | background-color-end: #1a551a;
78 | }
79 |
80 | .blue .slider-value {
81 | background-color: #223388;
82 | background-color-end: #223377;
83 | }
84 |
85 |
86 | /* --- overwriting dark.css theme --- */
87 | .button {
88 | color: #C0C0C2;
89 | font-size: 15px;
90 | }
91 |
92 | .hslider .slider-value-background {
93 | height: 8px;
94 | }
95 |
96 | .vslider .slider-value-background {
97 | width: 8px;
98 | }
99 |
100 | .hslider .slider-value {
101 | background-color: #AAAAAA;
102 | background-color-end: #888888;
103 | }
104 |
105 |
--------------------------------------------------------------------------------
/haxe-shaderfun.hxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | "$(CompilerPath)/haxelib" run lime build "$(OutputFile)" $(TargetBuild) -$(BuildConfig) -Dfdb
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/assets/shader/lyapunov.frag:
--------------------------------------------------------------------------------
1 | /*
2 | ###############################################################################
3 | # Author: Sylvio Sell - maitag - Rostock 2013 #
4 | # Homepage: http://maitag.de #
5 | # License: GNU General Public License (GPL), Version 2.0 #
6 | # #
7 | # more images about that lyapunov fractalcode at: #
8 | # http://maitag.de/~semmi/ #
9 | # (have fun!;) #
10 | ############################################################################### */
11 |
12 | varying vec2 vTexCoord;
13 | uniform vec2 uMouse, uResolution, uScale, uPosition;
14 | uniform vec2 uIteration, uParam;
15 | uniform float uStart;
16 | uniform float uBalance;
17 | uniform vec3 uColpos;
18 | uniform vec3 uColneg;
19 | uniform vec3 uColmid;
20 | uniform int uColtype;
21 |
22 | float func(float x, float y, float a, float b)
23 | {
24 | //return a*sin(x+y)*sin(x+y)+b;
25 | return #FORMULA;
26 | }
27 |
28 | float deriv(float x, float y, float a, float b)
29 | {
30 | //return a*sin(2.0*(x+y));
31 | return #DERIVATE;
32 | }
33 |
34 | void pre_step(inout float x, vec2 p, float p1, float p2)
35 | {
36 | x = func(x,p.x,p1,p2);
37 | x = func(x,p.y,p1,p2);
38 | }
39 |
40 | void main_step(inout float index, inout int iter, inout float x, vec2 p, float p1, float p2, float balance)
41 | {
42 | x = func(x,p.x,p1,p2);
43 | index += ( log(abs(deriv(x,p.x,p1,p2)))*balance + deriv(x,p.x,p1,p2)*(1.0-balance) ) / 2.0;
44 | x = func(x,p.y,p1,p2);
45 | index += ( log(abs(deriv(x,p.y,p1,p2)))*balance + deriv(x,p.y,p1,p2)*(1.0-balance) ) / 2.0;
46 | iter = iter + 2;
47 | }
48 |
49 | void main( void ) {
50 |
51 | // Parameter
52 | float x = uStart;
53 | vec2 p = (vTexCoord - uPosition) / uScale;
54 | float p1 = uParam.x;
55 | float p2 = uParam.y;
56 | int iter_pre = int(floor(uIteration.x));
57 | int iter_main = int(floor(uIteration.y));
58 | float nabla_pre = uIteration.x - float(iter_pre);
59 | float nabla_main = uIteration.y - float(iter_main);
60 |
61 | float index = 0.0;
62 | int iter = 0;
63 |
64 | // pre-iteration ##########################
65 |
66 | for (int i = 0; i < 21; i++) {
67 | if (i < iter_pre)
68 | {
69 | pre_step(x, p, p1, p2);
70 | }
71 | }
72 | if (nabla_pre != 0.0) {
73 | float x_pre = x;
74 | pre_step(x, p, p1, p2);
75 | x = x*nabla_pre + x_pre*(1.0-nabla_pre);
76 | }
77 |
78 | // main-iteration ########################
79 |
80 | for (int i = 0; i < 201; i++) {
81 | if (i < iter_main)
82 | {
83 | main_step(index, iter, x, p, p1, p2, uBalance);
84 | }
85 | }
86 |
87 | if (nabla_main == 0.0) {
88 | index = (iter != 0) ? index/float(iter) : 0.0;
89 | }
90 | else {
91 | float index_pre = (iter != 0) ? index/float(iter) : 0.0;
92 |
93 | main_step(index, iter, x, p, p1, p2, uBalance);
94 |
95 | index = (iter != 0) ? index/float(iter) : 0.0;
96 | index = index*nabla_main + index_pre*(1.0-nabla_main);
97 | }
98 |
99 | if (index > 0.0 && (uColtype==0 || uColtype==1)) {
100 | gl_FragColor = vec4(index*(uColpos-uColmid)+uColmid, 1.0);
101 | }
102 | else if (index < 0.0 && (uColtype==0 || uColtype==2)) {
103 | gl_FragColor = vec4(index*(uColmid-uColneg)+uColmid, 1.0);
104 | }
105 | else {
106 | gl_FragColor = vec4(uColmid, 1.0);
107 | }
108 | }
109 |
110 |
--------------------------------------------------------------------------------
/src/UI.hx:
--------------------------------------------------------------------------------
1 | package;
2 |
3 | import haxe.io.BytesInput;
4 | import haxe.io.BytesOutput;
5 | import haxe.ui.core.Component;
6 | import haxe.ui.core.MouseEvent;
7 | import haxe.ui.core.UIEvent;
8 |
9 | @:build(haxe.ui.macros.ComponentMacros.build("assets/ui/ui.xml"))
10 | class UI extends Component {
11 |
12 | public function new() {
13 | super();
14 |
15 | registerEvent(MouseEvent.MOUSE_DOWN, function(e:MouseEvent) { Main.uiIsdragging = true; });
16 | registerEvent(MouseEvent.MOUSE_UP , function(e:MouseEvent) { Main.dragmode = Main.uiIsdragging = false; });
17 |
18 | for (i in [iteration0, iteration1, param0, param1, start, balance, r1, g1, b1, r2, g2, b2, r3, g3, b3])
19 | i.registerEvent(MouseEvent.MOUSE_UP , updateChanges);
20 |
21 | iteration0.userData = [Main.iteration,0];
22 | iteration1.userData = [Main.iteration,1];
23 | param0.userData = [Main.param,0];
24 | param1.userData = [Main.param,1];
25 | start.userData = [Main.start,0];
26 | balance.userData= [Main.balance,0];
27 | r1.userData = [Main.colpos,0];
28 | g1.userData = [Main.colpos,1];
29 | b1.userData = [Main.colpos,2];
30 | r2.userData = [Main.colmid,0];
31 | g2.userData = [Main.colmid,1];
32 | b2.userData = [Main.colmid,2];
33 | r3.userData = [Main.colneg,0];
34 | g3.userData = [Main.colneg,1];
35 | b3.userData = [Main.colneg,2];
36 |
37 | // TODO
38 | changeFormula.onClick = function(e:UIEvent) { Main.updateFormula(formula.text); };
39 |
40 | iteration0.onChange = updateValue;
41 | iteration1.onChange = updateValue;
42 | param0.onChange = updateValue;
43 | param1.onChange = updateValue;
44 | start.onChange = updateValue;
45 | balance.onChange= updateValue;
46 | r1.onChange = updateValue;
47 | g1.onChange = updateValue;
48 | b1.onChange = updateValue;
49 | r2.onChange = updateValue;
50 | g2.onChange = updateValue;
51 | b2.onChange = updateValue;
52 | r3.onChange = updateValue;
53 | g3.onChange = updateValue;
54 | b3.onChange = updateValue;
55 |
56 | randomParam.onClick = updateChanges;
57 | randomColor.onClick = updateChanges;
58 | }
59 |
60 | private function updateChanges(e:UIEvent) {
61 | if (Main.changed) {
62 | Main.changed = false;
63 | Main.updateUrlParams();
64 | }
65 | }
66 |
67 | private function updateValue(e:UIEvent) {
68 | e.target.userData[0][e.target.userData[1]] = e.target.value.toFloat() / 255;
69 | Main.changed = true;
70 | }
71 |
72 | public function updateAll() {
73 | for (i in [iteration0, iteration1, param0, param1, start, balance, r1, g1, b1, r2, g2, b2, r3, g3, b3])
74 | i.userData[0][i.userData[1]] = i.value.toFloat() / 255;
75 | }
76 |
77 | public function serializeParams():BytesOutput
78 | {
79 | var b = new BytesOutput();
80 | b.writeInt16(iteration0.value);
81 | b.writeInt16(iteration1.value);
82 | b.writeInt16(param0.value);
83 | b.writeInt16(param1.value);
84 | b.writeInt16(start.value);
85 | b.writeInt16(balance.value);
86 | b.writeByte(r1.value);
87 | b.writeByte(g1.value);
88 | b.writeByte(b1.value);
89 | b.writeByte(r2.value);
90 | b.writeByte(g2.value);
91 | b.writeByte(b2.value);
92 | b.writeByte(r3.value);
93 | b.writeByte(g3.value);
94 | b.writeByte(b3.value);
95 | return(b);
96 | }
97 |
98 | public function unSerializeParams(b:BytesInput)
99 | {
100 | iteration0.value = b.readInt16();
101 | iteration1.value = b.readInt16();
102 | param0.value = b.readInt16();
103 | param1.value = b.readInt16();
104 | start.value = b.readInt16();
105 | balance.value = b.readInt16();
106 | r1.value = b.readByte();
107 | g1.value = b.readByte();
108 | b1.value = b.readByte();
109 | r2.value = b.readByte();
110 | g2.value = b.readByte();
111 | b2.value = b.readByte();
112 | r3.value = b.readByte();
113 | g3.value = b.readByte();
114 | b3.value = b.readByte();
115 | }
116 |
117 |
118 | }
--------------------------------------------------------------------------------
/assets/ui/ui.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
--------------------------------------------------------------------------------
/src/Main.hx:
--------------------------------------------------------------------------------
1 | package;
2 |
3 | import haxe.io.BytesInput;
4 | import haxe.io.BytesOutput;
5 |
6 | #if html5
7 | import js.Boot;
8 | import js.Browser;
9 | #end
10 |
11 | import haxe.Timer;
12 | import haxe.io.Bytes;
13 | import haxe.crypto.Base64;
14 |
15 | import haxe.ui.Toolkit;
16 | import haxe.ui.core.Screen;
17 |
18 | import openfl.Lib;
19 | import openfl.display.OpenGLView;
20 | import openfl.display.StageDisplayState;
21 | import openfl.events.Event;
22 | import openfl.events.KeyboardEvent;
23 | import openfl.events.MouseEvent;
24 | import openfl.events.TouchEvent;
25 | import openfl.geom.Rectangle;
26 | import openfl.ui.Keyboard;
27 |
28 | import lime.Assets;
29 |
30 | import peote.view.PeoteView;
31 | import peote.view.displaylist.DisplaylistType;
32 |
33 | import Formula;
34 |
35 | class Main {
36 | static var view:OpenGLView;
37 | static var width:Int;
38 | static var height:Int;
39 | static var mouse_x:Float = 0;
40 | static var mouse_y:Float = 0;
41 | static var dragstart_x:Float = 0;
42 | static var dragstart_y:Float = 0;
43 | public static var dragmode:Bool = false;
44 | public static var uiIsdragging:Bool = false;
45 | public static var changed:Bool = false;
46 | static var zoom:Float = 1.0;
47 | static var zoomstep:Float = 1.2;
48 |
49 | static var peoteView:PeoteView;
50 | static var frame:Int = 0;
51 |
52 | // shader uniform vars
53 | static var position:Array = [0, 0];
54 | static var scale:Array = [400, 400];
55 | static var coltype:Array = [0];
56 |
57 | public static var iteration:Array = [3, 5];
58 | public static var param:Array = [1.9, 2.3];
59 | public static var balance:Array = [0.5];
60 | public static var start:Array = [0.5];
61 | public static var colpos:Array = [1,0,0];
62 | public static var colmid:Array = [0,0,0];
63 | public static var colneg:Array = [0,0,1];
64 |
65 | static var ui:UI;
66 |
67 | static var lyapunovShader:String;
68 | static var formula:String;
69 | static var formulaBytes:Bytes;
70 |
71 | public static function main()
72 | {
73 | initPeoteView();
74 |
75 | Toolkit.init();
76 |
77 | ui = new UI();
78 | Screen.instance.addComponent(ui);
79 | // stage events -----------------------------------------
80 | Lib.current.stage.addEventListener( Event.RESIZE, function(e) { onWindowResize( Lib.current.stage.stageWidth, Lib.current.stage.stageHeight ); } );
81 |
82 | // mouse or touch events depends on "first click"
83 | Lib.current.stage.addEventListener( MouseEvent.MOUSE_DOWN, onMouseDown);
84 | Lib.current.stage.addEventListener( MouseEvent.MOUSE_MOVE, onMouseMove );
85 | Lib.current.stage.addEventListener( MouseEvent.MOUSE_UP, onMouseUp );
86 |
87 | Lib.current.stage.addEventListener( TouchEvent.TOUCH_BEGIN, firstTouchBeginEvent );
88 |
89 | Lib.current.stage.addEventListener( MouseEvent.MOUSE_WHEEL, onMouseWheel );
90 | Lib.current.stage.addEventListener( KeyboardEvent.KEY_DOWN, onKeyDown );
91 |
92 | // stop dragging if mouse leaves app-window
93 | Lib.current.stage.addEventListener( Event.MOUSE_LEAVE, function(e:MouseEvent) {
94 | stopDrag();
95 | ui.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_UP));
96 | });
97 |
98 | getUrlParams();
99 | }
100 |
101 | static function firstTouchBeginEvent(e:TouchEvent):Void
102 | {
103 | Lib.current.stage.removeEventListener( TouchEvent.TOUCH_BEGIN, firstTouchBeginEvent);
104 | Lib.current.stage.removeEventListener( MouseEvent.MOUSE_DOWN, onMouseDown);
105 | Lib.current.stage.removeEventListener( MouseEvent.MOUSE_MOVE, onMouseMove );
106 | Lib.current.stage.removeEventListener( MouseEvent.MOUSE_UP, onMouseUp );
107 |
108 | Lib.current.stage.addEventListener( TouchEvent.TOUCH_BEGIN, onTouchBegin );
109 | Lib.current.stage.addEventListener( TouchEvent.TOUCH_MOVE, onTouchMove );
110 | Lib.current.stage.addEventListener( TouchEvent.TOUCH_END, onTouchEnd );
111 |
112 | onTouchBegin(e);
113 | }
114 |
115 | static function initPeoteView ()
116 | {
117 | if (OpenGLView.isSupported) {
118 |
119 | peoteView = new PeoteView({maxPrograms:10});
120 |
121 | lyapunovShader = loadShader("shader/lyapunov.frag");
122 |
123 | peoteView.setProgram( {
124 | program:0,
125 | fshaderSrc: parseShader(lyapunovShader,"a*sin(x+y)*sin(x+y)+b","a*sin(2.0*(x+y))"),
126 | vars: [
127 | "uPosition" => position,
128 | "uScale" => scale,
129 | "uIteration" => iteration,
130 | "uParam" => param,
131 | "uBalance"=> balance,
132 | "uStart"=> start,
133 | "uColpos"=> colpos,
134 | "uColmid"=> colmid,
135 | "uColneg"=> colneg,
136 | "uColtype"=> coltype,
137 | ]
138 | });
139 |
140 | peoteView.setDisplaylist( {
141 | displaylist:0,
142 | type:DisplaylistType.SIMPLE,
143 | maxElements:1,
144 | x:0,
145 | y:0,
146 | });
147 |
148 | peoteView.setElement( {
149 | element:0,
150 | displaylist:0,
151 | program:0,
152 | x: 0,
153 | y: 0,
154 | w: 2000,
155 | h: 2000
156 | });
157 |
158 |
159 | // ---------------------------------------------------------------
160 |
161 | view = new OpenGLView ();
162 | view.render = renderView;
163 | Lib.current.stage.addChild(view);
164 | }
165 | }
166 |
167 | // ----------- Render Loop ------------------------------------
168 | static function renderView (rect:Rectangle):Void
169 | {
170 | peoteView.render( Std.int(rect.width), Std.int(rect.height) );
171 | }
172 |
173 | // ----------- update shader formula ------------------------------------
174 | static public function updateFormula (_formula:String):Void
175 | {
176 | if (_formula != null && _formula != '' && _formula != formula && _formula.length < 255)
177 | {
178 | try {
179 | var f:Formula = new Formula(_formula);
180 | //trace("formula:" + f.toString());
181 | var p:Array = f.params();
182 | if ((p.indexOf("x") >-1) && (p.indexOf("y") >-1) ) {
183 | var wrongParams:Bool = false;
184 | for (i in p) if (!(i == "x" || i == "y" || i == "a" || i == "b")) wrongParams = true;
185 | if (!wrongParams) {
186 | formula = _formula;
187 | updateShader(f);
188 | formulaBytes = f.toBytes();
189 | updateUrlParams();
190 | ui.formula.backgroundColor = 0xeeeeee;
191 | }
192 | else {
193 | trace('Error: wrong params, only a and b are supported by param-sliders');
194 | ui.formula.backgroundColor = 0xffddcc;
195 | }
196 | } else {
197 | trace('Error: wrong params, need at least x and y');
198 | ui.formula.backgroundColor = 0xffddcc;
199 | }
200 | }
201 | catch (msg:String)
202 | {
203 | trace('Error: $msg');
204 | ui.formula.backgroundColor = 0xffddcc;
205 | }
206 | }
207 | }
208 |
209 | static public function updateShader (f:Formula):Void
210 | {
211 | //var glsl_formula :String = f.simplify().toString('glsl');
212 | //var glsl_derivate:String = f.derivate("x").simplify().toString('glsl');
213 | var glsl_formula :String = f.toString('glsl');
214 | var glsl_derivate:String = f.derivate("x").toString('glsl');
215 | //trace("formula:" + glsl_formula);
216 | //trace("derivate:" + glsl_derivate);
217 | peoteView.setProgram( {
218 | program:0,
219 | fshaderSrc: parseShader(lyapunovShader, glsl_formula, glsl_derivate),
220 | });
221 |
222 | }
223 |
224 | public static var rFORMULA: EReg = new EReg("#FORMULA","g");
225 | public static var rDERIVATE:EReg = new EReg("#DERIVATE","g");
226 | static public function parseShader(shadersrc:String, formula:String, derivate:String):String
227 | {
228 | return rFORMULA.replace(rDERIVATE.replace(shadersrc, derivate), formula);
229 | }
230 |
231 | static public function loadShader(url:String):String
232 | {
233 | var shadersrc:String = '';
234 | #if html5
235 | var req = js.Browser.createXMLHttpRequest();
236 | req.open('GET', url, false);
237 | req.send();
238 | shadersrc = req.responseText;
239 | /*
240 | Assets.loadText(url).onComplete (function (s) {
241 | shadersrc = s; trace(s);
242 | });*/
243 | // need synced:
244 | //shadersrc = Assets.loadText(url).result();
245 | #else
246 | shadersrc = Assets.getText(url);
247 | //shadersrc = Assets.loadText(url).result();
248 | //shadersrc = sys.io.File.getBytes(url).toString();
249 | #end
250 | return(shadersrc);
251 | }
252 |
253 | // ----------- URL handling ------------------------------------
254 | static public function updateUrlParams()
255 | {
256 | #if html5
257 | var b:BytesOutput = ui.serializeParams();
258 | b.writeFloat(position[0]);
259 | b.writeFloat(position[1]);
260 | b.writeFloat(zoom);
261 | b.writeBytes(formulaBytes, 0, formulaBytes.length);
262 | var params:String = Base64.encode(b.getBytes(),false);
263 | Browser.window.history.replaceState('haxeshaderfun', 'haxeshaderfun', Browser.location.pathname + '?' + params);
264 | #end
265 | }
266 |
267 | static function getUrlParams()
268 | {
269 | #if html5
270 | var e:EReg = new EReg("\\?([" + Base64.CHARS + "]+)$", "");
271 | if (e.match(Browser.document.URL)) {
272 | var bytes:Bytes = Base64.decode( e.matched(1) , false);
273 | var b:BytesInput = new BytesInput(bytes);
274 | //trace("position:"+b.position);
275 | if (b.length >= 33) {
276 | ui.unSerializeParams(b);
277 | position[0] = b.readFloat();
278 | position[1] = b.readFloat();
279 | zoom = b.readFloat();
280 | scale[0] = scale[1] = zoom * 400.0;
281 | //read rest into formula
282 | if (b.length > 33) {
283 | var o = new BytesOutput();
284 | o.writeBytes(bytes, b.position, (b.length - 33));
285 | //trace("o:", o);
286 | formulaBytes = o.getBytes();
287 | try {
288 | updateFormula(Formula.fromBytes(formulaBytes));
289 | ui.formula.text = formula;
290 | } catch (msg:String) {
291 | trace("ERROR: can not parse formula from url-parameters");
292 | }
293 | }
294 | }
295 | }
296 | #end
297 | ui.updateAll();
298 | }
299 |
300 | // ------------------------------------------------------------
301 | // ----------- EVENT HANDLER ----------------------------------
302 | static function onWindowResize (w:Int, h:Int):Void
303 | {
304 | width = w;
305 | height = h;
306 |
307 | var ui = Screen.instance.rootComponents[0];
308 | ui.left = w - ui.width;
309 | }
310 |
311 |
312 | // Mouse Events ---------------------------------------------
313 |
314 | static function onMouseDown (e:MouseEvent):Void
315 | {
316 | if ( e.buttonDown ) startDrag(e.stageX, e.stageY);
317 | }
318 |
319 | static function onMouseUp (e:MouseEvent):Void
320 | {
321 | stopDrag();
322 | }
323 |
324 | static function onMouseMove (e:MouseEvent):Void
325 | {
326 | moveDrag(e.stageX, e.stageY);
327 | }
328 |
329 | static function onMouseWheel (e:MouseEvent):Void
330 | {
331 | if ( e.delta > 0 )
332 | {
333 | if (zoom < 10000)
334 | {
335 | position[0] -= zoomstep * (mouse_x - position[0]) - (mouse_x - position[0]);
336 | position[1] -= zoomstep * (mouse_y - position[1]) - (mouse_y - position[1]);
337 | zoom *= zoomstep;
338 | }
339 | }
340 | else if ( zoom > 0.03 )
341 | {
342 | position[0] -= (mouse_x - position[0]) / zoomstep - (mouse_x - position[0]);
343 | position[1] -= (mouse_y - position[1]) / zoomstep - (mouse_y - position[1]);
344 | zoom /= zoomstep;
345 | }
346 |
347 | scale[0] = scale[1] = zoom * 400.0;
348 |
349 | updateUrlParams();
350 | }
351 |
352 | // Touch Events ---------------------------------------------
353 | static function onTouchBegin (e:TouchEvent):Void
354 | {
355 | startDrag(e.stageX, e.stageY);
356 | }
357 |
358 | static function onTouchMove (e:MouseEvent):Void
359 | {
360 | moveDrag(e.stageX, e.stageY);
361 | }
362 |
363 | static function onTouchEnd (e:TouchEvent):Void
364 | {
365 | stopDrag();
366 | }
367 |
368 | // Dragging --------------------------------------------------
369 | static inline function startDrag(x:Float, y:Float)
370 | {
371 | dragstart_x = position[0] - x;
372 | dragstart_y = position[1] - y;
373 | dragmode = true;
374 | }
375 |
376 | static inline function stopDrag()
377 | {
378 | dragmode = false;
379 | uiIsdragging = false;
380 | if (changed) {
381 | changed = false;
382 | updateUrlParams();
383 | }
384 | }
385 |
386 | static inline function moveDrag(x:Float, y:Float)
387 | {
388 | mouse_x = x;
389 | mouse_y = y;
390 | if (dragmode && !uiIsdragging)
391 | {
392 | position[0] = (dragstart_x + mouse_x);
393 | position[1] = (dragstart_y + mouse_y);
394 | changed = true;
395 | }
396 | }
397 |
398 | // Keyboard Events -------------------------------------------
399 |
400 | static function onKeyDown (k:KeyboardEvent):Void
401 | {
402 | switch (k.keyCode) {
403 | case Keyboard.F:
404 | #if html5
405 | var e:Dynamic = Browser.document.getElementById('openfl-content').getElementsByTagName('canvas')[0];
406 | var noFullscreen:Dynamic = untyped __js__("(!document.fullscreenElement && !document.mozFullScreenElement && !document.webkitFullscreenElement && !document.msFullscreenElement)");
407 |
408 | if ( noFullscreen)
409 | { // enter fullscreen
410 | if (e.requestFullScreen) e.requestFullScreen();
411 | else if (e.msRequestFullScreen) e.msRequestFullScreen();
412 | else if (e.mozRequestFullScreen) e.mozRequestFullScreen();
413 | else if (e.webkitRequestFullScreen) e.webkitRequestFullScreen();
414 | }
415 | else
416 | { // leave fullscreen
417 | var d:Dynamic = Browser.document;
418 | if (d.exitFullscreen) d.exitFullscreen();
419 | else if (d.msExitFullscreen) d.msExitFullscreen();
420 | else if (d.mozCancelFullScreen) d.mozCancelFullScreen();
421 | else if (d.webkitExitFullscreen) d.webkitExitFullscreen();
422 | }
423 | #else
424 | if(Lib.current.stage.displayState != StageDisplayState.FULL_SCREEN_INTERACTIVE)
425 | Lib.current.stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
426 | else Lib.current.stage.displayState = StageDisplayState.NORMAL;
427 | #end
428 |
429 | default:
430 | }
431 | }
432 | // ------------------------------------------------------------
433 |
434 | }
435 |
--------------------------------------------------------------------------------