├── LICENSE ├── README.mkd ├── bin ├── fmodex.dll ├── fx │ ├── pp_combine.hlsl │ ├── pp_common.hlsl │ ├── pp_resolve.hlsl │ ├── qnoise.hlsl │ └── snoise.hlsl ├── live_coding.exe ├── media │ ├── bgm.mp3 │ └── tex.bmp └── save │ ├── aegis.hlsl │ ├── clouds.hlsl │ ├── guitar.hlsl │ ├── julia.hlsl │ ├── julia3d.hlsl │ ├── mandelbox.hlsl │ ├── mandelbrot4d.hlsl │ ├── mandelbulb.hlsl │ ├── menger.hlsl │ ├── penrose.hlsl │ ├── piano.hlsl │ ├── sierpinski.hlsl │ ├── sphere.hlsl │ └── tunnel.hlsl ├── live_coding.sln ├── live_coding.vcxproj ├── snap.png └── src ├── ayw ├── common_helper.h ├── constant.hpp ├── vector.hpp └── vector_helper.hpp ├── common.cpp ├── common.hpp ├── d3d_app.cpp ├── d3d_app.hpp ├── editable_text.cpp ├── editable_text.hpp ├── hr_timer.cpp ├── hr_timer.hpp ├── keywords.hpp ├── main.cpp ├── post_process.cpp ├── post_process.hpp ├── shader_header.cpp ├── shader_header.hpp ├── sound_player.cpp ├── sound_player.hpp ├── syntax_highlighter.cpp ├── syntax_highlighter.hpp ├── text_editor.cpp └── text_editor.hpp /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Yuwen Wu 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 | -------------------------------------------------------------------------------- /README.mkd: -------------------------------------------------------------------------------- 1 | This is a live coding tool for HLSL, inspired by: 2 | 3 | - iq. http://www.iquilezles.org/live/index.htm 4 | - githole. https://github.com/githole/Live-Coder 5 | 6 | ![screenshot](https://github.com/atyuwen/hlsl_live_coding/raw/master/snap.png) 7 | 8 | + Dependencies 9 | 10 | [If you won't bother the compiling stuff, just run bin/live_coding.exe and play around.] 11 | 12 | To compile, you will need following libs: 13 | 14 | - DirectSDK, June 2010. 15 | - Boost 1.41(or newer). 16 | - FMOD 4.32(or newer). 17 | 18 | Only vs2010 project is provided, so please use vs2010 to compile. 19 | 20 | + Live Coding 21 | 22 | The program only runs on Win7. The way of typing codes is very like vs2010 except mouse is not supported, you can only use keyboard to move caret and input. 23 | 24 | Following list some shortkeys, see src/TextEditor.cpp for more. 25 | 26 | - Ctrl + 'S' : save codes to file and compile. 27 | - Ctrl + 'O' : open an existing file. 28 | - Ctrl + 'M' : turn on/off music. 29 | - Ctrl + '-' : decrease volume. 30 | - Ctrl + '=' : increase volume. 31 | 32 | - Tab : auto jump (when the next char is ')' or '}'). 33 | - Ctrl + ',' : jump into next scope. 34 | - Ctrl + '.' : jump out of current scope. 35 | - Ctrl + 'C' : copy current selection. (or current line if select none) 36 | - Ctrl + 'L' : cut current line. 37 | 38 | - F1 : toggle show/hide text editor. 39 | - F2 : toggle antialiasing. 40 | 41 | Have fun! 42 | -------------------------------------------------------------------------------- /bin/fmodex.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atyuwen/hlsl_live_coding/c402d73ff80d81e84f1241109d8b93e729853061/bin/fmodex.dll -------------------------------------------------------------------------------- /bin/fx/pp_combine.hlsl: -------------------------------------------------------------------------------- 1 | Texture2D src_texture0 : register(t0); 2 | Texture2D src_texture1 : register(t1); 3 | 4 | float4 ps_main(in float4 sc : SV_POSITION) : SV_TARGET 5 | { 6 | int3 p = int3(sc.xy, 0); 7 | float4 col0 = src_texture0.Load(p); 8 | float4 col1 = src_texture1.Load(p); 9 | return lerp(saturate(col0), saturate(col1), col1.a); 10 | } 11 | -------------------------------------------------------------------------------- /bin/fx/pp_common.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer Parameters 2 | { 3 | float2 subpixel_jitter; 4 | } 5 | 6 | void vs_main(in float3 in_pos : POSITION, 7 | in float2 in_tex : TEXCOORD, 8 | out float2 out_tex: TEXCOORD, 9 | out float4 out_pos: SV_POSITION) 10 | { 11 | out_pos = float4(in_pos.xy, 0, 1); 12 | out_tex = in_tex + subpixel_jitter; 13 | } 14 | 15 | float4 ps_main(in float2 in_tex : TEXCOORD) : SV_TARGET 16 | { 17 | return float4(0.3, 0.3, 0.3, 1); 18 | } 19 | -------------------------------------------------------------------------------- /bin/fx/pp_resolve.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer Parameters 2 | { 3 | float2 interleave; 4 | } 5 | 6 | Texture2D src_texture0 : register(t0); 7 | 8 | float4 resolve(in float4 sc : SV_POSITION) : SV_TARGET 9 | { 10 | int3 p = int3(sc.xy, 0); 11 | float3 col = src_texture0.Load(p).rgb; 12 | return float4(saturate(col), 0.02); 13 | } 14 | 15 | float4 halfres_resolve(in float4 sc : SV_POSITION) : SV_TARGET 16 | { 17 | int2 p = int2(sc.xy); 18 | clip(-abs(fmod(p, 2) - interleave)); 19 | float3 col = src_texture0.Load(int3(p / 2, 0)).rgb; 20 | return float4(saturate(col), 0.08); 21 | } 22 | 23 | float4 halfres_copy(in float4 sc : SV_POSITION) : SV_TARGET 24 | { 25 | int3 p = int3(sc.xy / 2, 0); 26 | return saturate(src_texture0.Load(p)); 27 | } 28 | -------------------------------------------------------------------------------- /bin/fx/qnoise.hlsl: -------------------------------------------------------------------------------- 1 | // migrated from iq's GLSL code 2 | 3 | float4 __hash(float4 n) 4 | { 5 | return frac(sin(n) * 43758.5453); 6 | } 7 | 8 | float qnoise(float2 x) 9 | { 10 | float2 p = floor(x); 11 | float2 f = frac(x); 12 | f = f * f * (3.0 - 2.0 * f); 13 | float n = p.x + p.y * 57.0; 14 | float4 h = __hash(n + float4(113, 114, 170, 171)); 15 | float2 v = lerp(h.xz, h.yw, f.x); 16 | return lerp(v.x, v.y, f.y); 17 | } 18 | 19 | float qnoise(float3 x) 20 | { 21 | float3 p = floor(x); 22 | float3 f = frac(x); 23 | f = f * f * (3.0 - 2.0 * f); 24 | 25 | float n = dot(p, float3(1, 57, 113)); 26 | float4 h0 = __hash(n + float4(0, 57, 113, 170)); 27 | float4 h1 = __hash(n + float4(1, 58, 114, 171)); 28 | 29 | float4 u = lerp(h0, h1, f.x); 30 | float2 v = lerp(u.xz, u.yw, f.y); 31 | return lerp(v.x, v.y, f.z); 32 | } 33 | -------------------------------------------------------------------------------- /bin/fx/snoise.hlsl: -------------------------------------------------------------------------------- 1 | // Simplex noise function. 2 | // Migrated from Ian McEwan's glsl code, see: https://github.com/ashima/webgl-noise 3 | // Copyright (C) 2011 Ashima Arts. All rights reserved. 4 | 5 | #define __mod289(x) ((x) - floor((x) * (1.0 / 289.0)) * 289.0) 6 | 7 | #define __permute(x) (__mod289((((x) * 34.0) + 1.0) * (x))) 8 | 9 | #define __taylor_inv_sqrt(x) (1.79284291400159 - 0.85373472095314 * (x)) 10 | 11 | float snoise(float2 v) 12 | { 13 | const float4 C = float4( 0.211324865405187, // (3.0-sqrt(3.0))/6.0 14 | 0.366025403784439, // 0.5*(sqrt(3.0)-1.0) 15 | -0.577350269189626, // -1.0 + 2.0 * C.x 16 | 0.024390243902439); // 1.0 / 41.0 17 | // First corner 18 | float2 i = floor(v + dot(v, C.yy)); 19 | float2 x0 = v - i + dot(i, C.xx); 20 | 21 | // Other corners 22 | float2 i1; 23 | i1 = (x0.x > x0.y) ? float2(1.0, 0.0) : float2(0.0, 1.0); 24 | float4 x12 = x0.xyxy + C.xxzz; 25 | x12.xy -= i1; 26 | 27 | // Permutations 28 | i = __mod289(i); // Avoid truncation effects in permutation 29 | float3 p = __permute(__permute(i.y + float3(0.0, i1.y, 1.0)) + i.x + float3(0.0, i1.x, 1.0)); 30 | 31 | float3 m = max(0.5 - float3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0); 32 | m = m * m; 33 | m = m * m; 34 | 35 | // Gradients: 41 points uniformly over a line, mapped onto a diamond. 36 | // The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287) 37 | float3 x = 2.0 * frac(p * C.www) - 1.0; 38 | float3 h = abs(x) - 0.5; 39 | float3 ox = floor(x + 0.5); 40 | float3 a0 = x - ox; 41 | 42 | // Normalise gradients implicitly by scaling m 43 | m *= __taylor_inv_sqrt(a0*a0 + h*h); 44 | 45 | // Compute final noise value at P 46 | float3 g; 47 | g.x = a0.x * x0.x + h.x * x0.y; 48 | g.yz = a0.yz * x12.xz + h.yz * x12.yw; 49 | return 130.0 * dot(m, g); 50 | } 51 | 52 | float snoise(float3 v) 53 | { 54 | const float2 C = float2(1.0/6.0, 1.0/3.0); 55 | const float4 D = float4(0.0, 0.5, 1.0, 2.0); 56 | 57 | // First corner 58 | float3 i = floor(v + dot(v, C.yyy) ); 59 | float3 x0 = v - i + dot(i, C.xxx) ; 60 | 61 | // Other corners 62 | float3 g = step(x0.yzx, x0.xyz); 63 | float3 l = 1.0 - g; 64 | float3 i1 = min( g.xyz, l.zxy ); 65 | float3 i2 = max( g.xyz, l.zxy ); 66 | 67 | float3 x1 = x0 - i1 + C.xxx; 68 | float3 x2 = x0 - i2 + C.yyy; // 2.0 * C.x = 1/3 = C.y 69 | float3 x3 = x0 - D.yyy; // -1.0 + 3.0 * C.x = -0.5 = -D.y 70 | 71 | // Permutations 72 | i = __mod289(i); 73 | float4 p = __permute( __permute( __permute( 74 | i.z + float4(0.0, i1.z, i2.z, 1.0)) 75 | + i.y + float4(0.0, i1.y, i2.y, 1.0)) 76 | + i.x + float4(0.0, i1.x, i2.x, 1.0)); 77 | 78 | // Gradients: 7x7 points over a square, mapped onto an octahedron. 79 | // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) 80 | float n_ = 0.142857142857; // 1.0/7.0 81 | float3 ns = n_ * D.wyz - D.xzx; 82 | 83 | float4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p, 7*7) 84 | 85 | float4 x_ = floor(j * ns.z); 86 | float4 y_ = floor(j - 7.0 * x_ ); // mod(j, N) 87 | 88 | float4 x = x_ * ns.x + ns.yyyy; 89 | float4 y = y_ * ns.x + ns.yyyy; 90 | float4 h = 1.0 - abs(x) - abs(y); 91 | 92 | float4 b0 = float4(x.xy, y.xy); 93 | float4 b1 = float4(x.zw, y.zw); 94 | 95 | float4 s0 = floor(b0) * 2.0 + 1.0; 96 | float4 s1 = floor(b1) * 2.0 + 1.0; 97 | float4 sh = -step(h, 0); 98 | 99 | float4 a0 = b0.xzyw + s0.xzyw * sh.xxyy ; 100 | float4 a1 = b1.xzyw + s1.xzyw * sh.zzww ; 101 | 102 | float3 p0 = float3(a0.xy, h.x); 103 | float3 p1 = float3(a0.zw, h.y); 104 | float3 p2 = float3(a1.xy, h.z); 105 | float3 p3 = float3(a1.zw, h.w); 106 | 107 | //Normalise gradients 108 | float4 norm = __taylor_inv_sqrt(float4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); 109 | p0 *= norm.x; 110 | p1 *= norm.y; 111 | p2 *= norm.z; 112 | p3 *= norm.w; 113 | 114 | // Mix final noise value 115 | float4 m = max(0.6 - float4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); 116 | m = m * m; 117 | return 42.0 * dot(m * m, float4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3))); 118 | } 119 | 120 | float4 __grad4(float j, float4 ip) 121 | { 122 | const float4 ones = float4(1.0, 1.0, 1.0, -1.0); 123 | float4 p,s; 124 | 125 | p.xyz = floor(frac(float3(j, j, j) * ip.xyz) * 7.0) * ip.z - 1.0; 126 | p.w = 1.5 - dot(abs(p.xyz), ones.xyz); 127 | s = 1.0 - step(0.0, p); 128 | p.xyz = p.xyz + (s.xyz * 2.0 - 1.0) * s.www; 129 | 130 | return p; 131 | } 132 | 133 | // (sqrt(5) - 1) / 4 = F4, used once below 134 | #define __F4 0.309016994374947451 135 | 136 | float snoise(float4 v) 137 | { 138 | const float4 C = float4( 0.138196601125011, // (5 - sqrt(5)) / 20 = G4 139 | 0.276393202250021, // 2 * G4 140 | 0.414589803375032, // 3 * G4 141 | -0.447213595499958); // -1 + 4 * G4 142 | 143 | // First corner 144 | float4 i = floor(v + dot(v, float4(__F4, __F4, __F4, __F4))); 145 | float4 x0 = v - i + dot(i, C.xxxx); 146 | 147 | // Other corners 148 | 149 | // Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI) 150 | float4 i0; 151 | float3 isX = step( x0.yzw, x0.xxx ); 152 | float3 isYZ = step( x0.zww, x0.yyz ); 153 | i0.x = isX.x + isX.y + isX.z; 154 | i0.yzw = 1.0 - isX; 155 | i0.y += isYZ.x + isYZ.y; 156 | i0.zw += 1.0 - isYZ.xy; 157 | i0.z += isYZ.z; 158 | i0.w += 1.0 - isYZ.z; 159 | 160 | // i0 now contains the unique values 0,1,2,3 in each channel 161 | float4 i3 = clamp( i0, 0.0, 1.0 ); 162 | float4 i2 = clamp( i0-1.0, 0.0, 1.0 ); 163 | float4 i1 = clamp( i0-2.0, 0.0, 1.0 ); 164 | 165 | float4 x1 = x0 - i1 + C.xxxx; 166 | float4 x2 = x0 - i2 + C.yyyy; 167 | float4 x3 = x0 - i3 + C.zzzz; 168 | float4 x4 = x0 + C.wwww; 169 | 170 | // Permutations 171 | i = __mod289(i); 172 | float j0 = __permute( __permute( __permute( __permute(i.w) + i.z) + i.y) + i.x); 173 | float4 j1 = __permute( __permute( __permute( __permute ( 174 | i.w + float4(i1.w, i2.w, i3.w, 1.0 )) 175 | + i.z + float4(i1.z, i2.z, i3.z, 1.0 )) 176 | + i.y + float4(i1.y, i2.y, i3.y, 1.0 )) 177 | + i.x + float4(i1.x, i2.x, i3.x, 1.0 )); 178 | 179 | // Gradients: 7x7x6 points over a cube, mapped onto a 4-cross polytope 180 | // 7*7*6 = 294, which is close to the ring size 17*17 = 289. 181 | float4 ip = float4(1.0/294.0, 1.0/49.0, 1.0/7.0, 0.0) ; 182 | 183 | float4 p0 = __grad4(j0, ip); 184 | float4 p1 = __grad4(j1.x, ip); 185 | float4 p2 = __grad4(j1.y, ip); 186 | float4 p3 = __grad4(j1.z, ip); 187 | float4 p4 = __grad4(j1.w, ip); 188 | 189 | // Normalise gradients 190 | float4 norm = __taylor_inv_sqrt(float4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); 191 | p0 *= norm.x; 192 | p1 *= norm.y; 193 | p2 *= norm.z; 194 | p3 *= norm.w; 195 | p4 *= __taylor_inv_sqrt(dot(p4,p4)); 196 | 197 | // Mix contributions from the five corners 198 | float3 m0 = max(0.6 - float3(dot(x0,x0), dot(x1,x1), dot(x2,x2)), 0.0); 199 | float2 m1 = max(0.6 - float2(dot(x3,x3), dot(x4,x4) ), 0.0); 200 | m0 = m0 * m0; 201 | m1 = m1 * m1; 202 | return 49.0 * ( dot(m0 * m0, float3( dot( p0, x0 ), dot( p1, x1 ), dot( p2, x2 ))) 203 | + dot(m1 * m1, float2( dot( p3, x3 ), dot( p4, x4 ) ) ) ) ; 204 | } 205 | -------------------------------------------------------------------------------- /bin/live_coding.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atyuwen/hlsl_live_coding/c402d73ff80d81e84f1241109d8b93e729853061/bin/live_coding.exe -------------------------------------------------------------------------------- /bin/media/bgm.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atyuwen/hlsl_live_coding/c402d73ff80d81e84f1241109d8b93e729853061/bin/media/bgm.mp3 -------------------------------------------------------------------------------- /bin/media/tex.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atyuwen/hlsl_live_coding/c402d73ff80d81e84f1241109d8b93e729853061/bin/media/tex.bmp -------------------------------------------------------------------------------- /bin/save/aegis.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer Parameters 2 | { 3 | float4 time; 4 | float4 view; 5 | float4 fft; 6 | } 7 | 8 | bool rect(int2 p, int l, int r, int b, int t) 9 | { 10 | return (l <= p.x && p.x <= r && b <= p.y && p.y <= t); 11 | } 12 | 13 | float4 ps_main(in float2 in_tex : TEXCOORD) : SV_TARGET 14 | { 15 | float progress = fmod(time.x, 300) / 300; 16 | int2 p = in_tex * view.xy; 17 | if (p.x > 640 || p.y > 320) return float4(0.1, 0.1, 0.1, 1); 18 | p.y = 320 - p.y; 19 | 20 | float3 c = 0.15; 21 | if (rect(p, 14, 625, 30, 308)) 22 | c = 0.3; 23 | if (rect(p, 15, 624, 31, 307)) 24 | c = 0.1; 25 | 26 | if (rect(p, 14, 625, 15, 17)) 27 | { 28 | float s = (p.x - 14) / 610.0; 29 | if (s < progress) 30 | c = lerp(float3(0.2, 0.3, 0.4), float3(0.8, 0.4, 0.5), s); 31 | else c = 0.1; 32 | if (p.y == 15) c += 0.15; 33 | } 34 | 35 | float l = progress * 606 + 14; 36 | if (rect(p, l, l + 6, 10, 21)) c = 0; 37 | if (rect(p, l, l + 5, 11, 21)) c = 0.4; 38 | if (rect(p, l + 1, l + 5, 11, 20)) c = 0.3; 39 | 40 | p = int2(p.x - 16, p.y - 32); 41 | float2 fq = p / float2(19, 5); 42 | int2 q = floor(fq); 43 | int2 r = p - q * float2(19, 5); 44 | if (q.x >= 0 && q.x < 32 && q.y >= 0 && q.y < 55) 45 | { 46 | c = float3(0.16, 0.18, 0.19); 47 | float v = snoise(float2(q.x, 20 * time.x) * 0.1) * 0.4 + 0.1 + fft.xz; 48 | if (q.y < v * 55) 49 | { 50 | float2 s = q / float2(31, 59); 51 | c = lerp(float3(0.4, 0.12, 0.1), float3(0.1, 0.4, 0.5), s.x); 52 | c = lerp(c, c + 0.6, s.y); 53 | } 54 | 55 | if (r.x > 17 || r.y > 3) c = 0.15; 56 | 57 | float m = abs(fq.y / 55 - 0.5) * 2; 58 | c += pow(m, 12) * float3(0.2, 0.23, 0.26); 59 | } 60 | return float4(c, 1); 61 | } 62 | -------------------------------------------------------------------------------- /bin/save/clouds.hlsl: -------------------------------------------------------------------------------- 1 | // migrated from iq's GLSL code 2 | // Created by inigo quilez - iq/2013 3 | 4 | cbuffer Parameters : register(b0) 5 | { 6 | float4 time; 7 | float4 view; 8 | float4 freq; 9 | float4 mpos; 10 | } 11 | 12 | float fbm(float3 p) 13 | { 14 | float f; 15 | f = 0.5000 * qnoise(p); p = p * 2.02; 16 | f += 0.2500 * qnoise(p); p = p * 2.03; 17 | f += 0.1250 * qnoise(p); p = p * 2.01; 18 | f += 0.0625 * qnoise(p); 19 | return f; 20 | } 21 | 22 | float4 map(in float3 p) 23 | { 24 | float d = 0.5 - p.y; 25 | d += 3.0 * fbm( p*1.0 - float3(1.0,0.1,0.0) * time.x); 26 | float4 res = saturate(d); 27 | res.xyz = lerp(1.15*float3(1.0,0.95,0.8), float3(0.7,0.7,0.7), res.x); 28 | return res; 29 | } 30 | 31 | static float3 sundir = float3(-1,0,0); 32 | 33 | float4 raymarch(in float3 ro, in float3 rd) 34 | { 35 | float4 sum = 0; 36 | float t = 0.0; 37 | for(int i = 0; i < 44; i++) 38 | { 39 | float3 pos = ro + t*rd; 40 | float4 col = map( pos ); 41 | float dif = saturate((col.w - map(pos+0.3*sundir).w)/0.6); 42 | float3 brdf = float3(0.65,0.68,0.7)*1.35 + 0.45*float3(0.7, 0.5, 0.3)*dif; 43 | 44 | col.xyz *= brdf; 45 | col.a *= 0.35; 46 | col.rgb *= col.a; 47 | 48 | sum = sum + col*(1.0 - sum.a); 49 | t += max(0.1,0.05*t); 50 | } 51 | sum.xyz /= (0.001+sum.w); 52 | return saturate(sum); 53 | } 54 | 55 | float4 ps_main(in float2 tc : TEXCOORD) : SV_TARGET 56 | { 57 | float2 p = tc * 2 - 1; 58 | p *= float2(view.x * view.w, -1); 59 | float2 mo = -1 + 2 * mpos.xy / view.xy; 60 | 61 | // camera 62 | float3 ro = 4.0*normalize(float3(cos(2.75-3.0*mo.x), 0.7+(mo.y+1.0), sin(2.75-3.0*mo.x))); 63 | float3 ta = float3(0.0, 1.0, 0.0); 64 | float3 ww = normalize( ta - ro); 65 | float3 uu = normalize(cross( float3(0.0,1.0,0.0), ww )); 66 | float3 vv = normalize(cross(ww,uu)); 67 | float3 rd = normalize( p.x*uu + p.y*vv + 1.5*ww ); 68 | 69 | float4 res = raymarch( ro, rd ); 70 | float sun = saturate(dot(sundir,rd)); 71 | float3 col = float3(0.6,0.71,0.75) - rd.y*0.2*float3(1.0,0.5,1.0) + 0.15*0.5; 72 | col += 0.2*float3(1.0,.6,0.1) * pow(sun, 8.0); 73 | col *= 0.95; 74 | col = lerp(col, res.xyz, res.w); 75 | col += 0.1*float3(1.0,0.4,0.2) * pow(sun, 2.0); 76 | 77 | return float4( col, 1.0 ); 78 | } 79 | -------------------------------------------------------------------------------- /bin/save/guitar.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer Parameters 2 | { 3 | float4 time; 4 | float4 view; 5 | float4 freq; 6 | float4 mpos; 7 | } 8 | 9 | float body(float3 p) 10 | { 11 | p.x *= 0.6; 12 | float d1 = length(p.xy) - 0.4; 13 | p.y -= 0.5; 14 | float d2 = length(p.xy) - 0.18; 15 | float d = lerp(d1, d2, saturate((p.y + 0.9) * 0.8)); 16 | d = max(d, abs(p.z) - 0.1); 17 | return d; 18 | } 19 | 20 | float neck(float3 p, out float id) 21 | { 22 | id = 1; 23 | p.y -= 1; 24 | float t = min(p.y + 0.7, 1.21); 25 | float h = saturate(p.y + 0.7 - 1.21); 26 | p.z -= 0.114 - saturate(t) * 0.02 - h * 0.15; 27 | if (p.z > -0.012) id = 2; 28 | p.x *= (1 + 0.3 * t) - min(12 * h, 0.4 + h); 29 | p.y *= (1 + h * abs(p.x)); 30 | float s = clamp((t - 0.32) * 10, 0.3, 1); 31 | float d = length(p.xz * float2(1, s)) - 0.05; 32 | p.z += 0.3; 33 | s = fmod(pow(t, 0.48) + 2.005, 0.036) - 0.002; 34 | s = saturate(0.004 - s * s * 800 * t); 35 | if (s > 0 && p.z > 0.3) id = 3; 36 | p.z -= s; 37 | d = max(d, length(p.xz) - 0.3); 38 | d = max(d, abs(p.y) - 0.74); 39 | return d * 0.7; 40 | } 41 | 42 | float inner(float3 p) 43 | { 44 | p.y -= 0.32; 45 | float d1 = max(length(p.xy) - 0.1, -p.z); 46 | float d2 = max(length(p.xy) - 0.2, abs(p.z) - 0.09); 47 | return min(d1, d2); 48 | } 49 | 50 | float bridge(float3 p, out float id) 51 | { 52 | id = 1; 53 | p.y += 0.06; 54 | p.z += clamp(abs(p.x) * 0.12, 0.01, 0.02) - 0.11; 55 | float d = length(max(abs(p) - float3(0.15, 0.02, 0.02), 0)) * 0.9; 56 | float d2 = length(max(abs(p - float3(0, 0.012, 0)) - float3(0.07, 0.003, 0.027), 0)); 57 | if (d2 < d) {d = d2; id = 2;} 58 | if (abs(p.x) > 0.06) return d; 59 | p.x = fmod(p.x + 2, 0.02) - 0.01; 60 | p.z -= 0.025; 61 | float d3 = length(p.xyz) - 0.005; 62 | if (d3 < d) {d = d3; id = 3;} 63 | return d; 64 | } 65 | 66 | float screws(float3 p) 67 | { 68 | float t = min(p.y - 1.53, 0.18); 69 | p.z -= 0.075 - 0.15 * t; 70 | p.y = fmod(t - p.z * 0.2, 0.06) - 0.03; 71 | p.x = abs(p.x) - 0.033; 72 | float r = p.z < 0 ? 0.01 : 0.005; 73 | float d = max(length(p.xy) - r, abs(p.z) - 0.035); 74 | d = min(d, max(length(p.xy) - 0.009, abs(p.z) - 0.02)); 75 | p.z += 0.024; 76 | d = min(d, max(length(p.yz) - 0.004, abs(p.x) - 0.03)); 77 | 78 | // handle 79 | p.x -= 0.02 + 0.05 * t; 80 | float h = length(p.xyz) - 0.014; 81 | p.x -= 0.01; 82 | h = max(h, length(max(abs(p.xyz) - float3(0.01, 0.01, 0.004), 0))); 83 | d = min(d, h); 84 | return d * 0.9; 85 | } 86 | 87 | float strings(float3 p) 88 | { 89 | p.y -= 0.72; 90 | float t = min(p.y + 0.785, 1.57); 91 | p.x *= (1 + 0.4 * t); 92 | if (abs(p.x) > 0.06) return 1e3; 93 | 94 | float f = saturate(p.y - 0.78); 95 | if (p.y > 0) p.y *= 0.65 + 3.6 * abs(p.x); 96 | p.x += clamp(-sign(p.x) * 0.2 * f, -abs(p.x), abs(p.x)); 97 | p.z += 0.15 * f; 98 | 99 | float r = 0.0006 - p.x * 0.006; 100 | p.z -= 0.125 - 0.015 * t; 101 | p.x = fmod(p.x + 2, 0.02) - 0.01; 102 | float d = length(p.xz) - r; 103 | d = max(d, abs(p.y) - 0.785); 104 | return d; 105 | } 106 | 107 | float2 DE(float3 p) 108 | { 109 | // bounding box 110 | float3 bb = saturate(abs(p.xyz) - float3(0.5, 2, 0.3)); 111 | if (any(bb)) return float2(length(bb) + 0.01, -1); 112 | 113 | float d = body(p); 114 | float id = 1; 115 | float sid = 0; 116 | float t = neck(p, sid); 117 | if (t < d) {d = t; id = 2 + sid * 0.1;} 118 | t = -inner(p); 119 | if (t > d) {d = t; id = 3;} 120 | t = bridge(p, sid); 121 | if (t < d) {d = t; id = 4 + sid * 0.1;} 122 | t = screws(p); 123 | if (t < d) {d = t; id = 5;} 124 | t = strings(p); 125 | if (t < d) {d = t; id = 6;} 126 | return float2(d, id); 127 | } 128 | 129 | float4 ray_marching(float3 ro, float3 rd) 130 | { 131 | float3 p = ro; 132 | for (int i = 0; i < 64; ++i) 133 | { 134 | float2 d = DE(p); 135 | p += d.x * rd; 136 | if (d.x < 0.0001) return float4(p, d.y); 137 | } 138 | 139 | float t = (-0.4 - ro.y) / rd.y; 140 | float3 floorp = ro + t * rd; 141 | if (t > 0) return float4(floorp, 0); 142 | return float4(ro, -1); 143 | } 144 | 145 | float3 brdf(float3 diff, float m, float3 N, float3 L, float3 V) 146 | { 147 | float3 H = normalize(V + L); 148 | float3 F = 0.05 + 0.95 * pow(1 - dot(V, H), 5); 149 | float3 R = F * pow(max(dot(N, H), 0), m); 150 | return diff + R * (m + 8) / 8; 151 | } 152 | 153 | float4 shade(float3 ro, float3 rd) 154 | { 155 | float4 rm = ray_marching(ro, rd); 156 | if (rm.w < 0) return float4(0, 0, 0, 0); 157 | 158 | float3 p = rm.xyz; 159 | float k = DE(p).x; 160 | float gx = DE(p + float3(1e-5, 0, 0)).x - k; 161 | float gy = DE(p + float3(0, 1e-5, 0)).x - k; 162 | float gz = DE(p + float3(0, 0, 1e-5)).x - k; 163 | float3 N = normalize(float3(gx, gy, gz)); 164 | 165 | float ao = 0; 166 | ao += DE(p + 0.01 * N).x * 50; 167 | ao += DE(p + 0.02 * N).x * 10; 168 | 169 | float3 L = normalize(float3(-0.1, 1, 1)); 170 | float sr = ray_marching(p + 0.001 * L, L).w; 171 | float shadow = sr > 0 ? 0 : 1; 172 | 173 | float3 diff = 0.8; 174 | float m = 10; 175 | if (rm.w < 0.9) // floor 176 | { 177 | shadow = saturate(0.4 + 0.6 * shadow + 0.3 * length(p.xz)); 178 | return float4(float3(0.02, 0.02, 0.02) * shadow, 1); 179 | } 180 | if (rm.w < 1.9) // body 181 | { 182 | float3 C = float3(0.8, 0.6, 0.2); 183 | float s = length(p.xy - float2(0, 0.32)); 184 | if (abs(s - 0.12) < 0.008) C = float3(0.01, 0.004, 0); 185 | 186 | diff = lerp(float3(0.02, 0.008, 0.001), C, saturate(N.z)); 187 | float r = qnoise(200 * p.xzz + 2 * qnoise(5 * p.yyz)); 188 | diff *= (r * 0.3 + 0.7); 189 | if (abs(abs(p.z) - 0.08) < 0.005) diff = 0.8; 190 | } 191 | else if (rm.w < 2.25) // neck 192 | { 193 | diff = float3(0.3, 0.18, 0.1) * (0.7 + qnoise(300 * p) * 0.3); 194 | if (rm.w > 2.15) diff *= 0.4; 195 | } 196 | else if (rm.w < 2.9) 197 | { 198 | diff = float3(0.8, 0.6, 0.4); 199 | m = 80; 200 | } 201 | else if (rm.w < 3.9) // inner 202 | { 203 | diff = float3(0.25, 0.2, 0.15) * (0.5 + 0.5 * qnoise(400 * p.xzz)); 204 | } 205 | else if (rm.w < 4.15) // bridge 206 | { 207 | diff = 0; 208 | } 209 | else if (rm.w < 4.25) 210 | { 211 | diff = 0.7; 212 | } 213 | else if (rm.w < 4.35) 214 | { 215 | diff = 0.04; m = 80; 216 | } 217 | else if (rm.w < 5.9) // screws 218 | { 219 | m = 50; 220 | } 221 | else // strings 222 | { 223 | m = 50; 224 | } 225 | float3 f = brdf(diff, m, N, L, -rd); 226 | 227 | float3 A = 0.2; 228 | float3 C = (saturate(dot(N, L)) * f * shadow + A * diff) * ao; 229 | return float4(C, 1); 230 | } 231 | 232 | float4 ps_main(in float2 tc : TEXCOORD) : SV_TARGET 233 | { 234 | float3 p = float3((tc * 2 - 1), 0); 235 | p.xy *= float2(view.x * view.w, -1); 236 | 237 | float3 param = mpos.xyz * float3(-0.005, 0.005, -0.1) + float3(0.4, 0.3, 7); 238 | float4 rot; 239 | sincos(param.x, rot.x, rot.y); 240 | sincos(param.y, rot.z, rot.w); 241 | 242 | float3 rt = float3(0, 0.6, 0); 243 | float3 ro = float3(rot.x * rot.w, abs(rot.y) * rot.z, rot.y); 244 | ro = ro * param.z; 245 | 246 | float3 cd = normalize(rt - ro); 247 | float3 cr = normalize(cross(cd, float3(0, 1, 0))); 248 | float3 cu = cross(cr, cd); 249 | 250 | float3 rd = normalize(p.x * cr + p.y * cu + 5 * cd); 251 | float4 radiance = shade(ro, rd); 252 | 253 | float3 col = float3(0.02, 0.02, 0.02); 254 | col = lerp(col, radiance.rgb, radiance.a); 255 | return float4(pow(col, 0.45), 1); 256 | } 257 | -------------------------------------------------------------------------------- /bin/save/julia.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer Parameters 2 | { 3 | float4 time; 4 | float4 view; 5 | float4 freq; 6 | float4 mpos; 7 | } 8 | 9 | float4 ps_main(in float2 in_tex : TEXCOORD) : SV_TARGET 10 | { 11 | float2 p = (in_tex - 0.5) * 3.0; 12 | p -= mpos.xy * 0.003; 13 | p *= 1 / max(0.5, 1 + mpos.z * 0.1); 14 | float t = time.x - step(0.4, freq.x) * 0.5; 15 | float2 c = float2(0.3 + sin(t * 0.3) * 0.2, 0.5 + snoise(time.xy * 0.1) * 0.3); 16 | 17 | float3 trap = 10; 18 | for (int i; i < 32; ++i) 19 | { 20 | p = float2(p.x * p.x - p.y * p.y, 2 * p.x * p.y) + c; 21 | float l = length(p); 22 | trap = min(trap, float3(p, l)); 23 | if (l > 1.5) break; 24 | } 25 | 26 | float3 col = 0.5 * lerp(float3(0.1, 0.3, 0.4), float3(0.2, 0.9, 0.8), trap.x * 0.1); 27 | col += 0.3 * lerp(float3(0.1, 0.0, 0.4), float3(0.8, 0.2, 0.9), trap.y * 0.1); 28 | col += 0.2 * lerp(float3(0.8, 0.4, 0.1), float3(0.0, 1.3, 0.5), trap.z); 29 | 30 | return float4(col, 1); 31 | } 32 | -------------------------------------------------------------------------------- /bin/save/julia3d.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer Parameters 2 | { 3 | float4 time; 4 | float4 view; 5 | float4 freq; 6 | float4 mpos; 7 | } 8 | 9 | float3 mul3d(float3 a, float3 b) 10 | { 11 | float3 c; 12 | c.x = dot(a.xy, b.xz) - dot(a.yz, b.yz); 13 | c.y = dot(a.xy, b.yx); 14 | c.z = dot(a.xz, b.zx); 15 | return c; 16 | } 17 | 18 | float DE(float3 p) 19 | { 20 | float3 b = float3(0.24, 0.38, 0.83); 21 | float3 c = p; 22 | float3 d = 1; 23 | float r = length(c); 24 | for (int i = 0; i < 16 && r < 3; ++i) 25 | { 26 | d = 2 * mul3d(c, d); 27 | c = mul3d(c, c) + b; 28 | r = length(c); 29 | } 30 | float dr = length(d); 31 | return 0.5 * log(r) * r / dr; 32 | } 33 | 34 | float4 ray_marching(float3 ro, float3 rd) 35 | { 36 | for (int i = 0; i < 64; ++i) 37 | { 38 | float d = DE(ro); 39 | ro += d * rd; 40 | if (d < 0.01) return float4(ro, i); 41 | } 42 | return float4(ro, -1); 43 | } 44 | 45 | float4 shade(float3 ro, float3 rd) 46 | { 47 | float4 rm = ray_marching(ro, rd); 48 | if (rm.w < 0) return float4(0, 0, 0, 0); 49 | 50 | float3 p = rm.xyz; 51 | float k = DE(p); 52 | float gx = DE(p + float3(1e-5, 0, 0)) - k; 53 | float gy = DE(p + float3(0, 1e-5, 0)) - k; 54 | float gz = DE(p + float3(0, 0, 1e-5)) - k; 55 | float3 N = normalize(float3(gx, gy, gz)); 56 | 57 | float ao = 0; 58 | ao += DE(p + 0.2 * N) * 2.5; 59 | ao += DE(p + 0.5 * N) * 1.0; 60 | 61 | float3 L = normalize(float3(-2, 1, 0.5)); 62 | float3 C = float3(0.3, 0.2, 0.8); 63 | float D = 0.7; 64 | float A = 0.1; 65 | float3 col = (A + D * saturate(dot(L, N))) * ao * C; 66 | return float4(col , 1); 67 | } 68 | 69 | float4 ps_main(in float2 tc : TEXCOORD) : SV_TARGET 70 | { 71 | float3 p = float3((tc * 2 - 1), 0); 72 | p.xy *= float2(view.x * view.w, -1); 73 | 74 | float3 param = mpos.xyz * float3(-0.005, 0.005, -0.1) + float3(0.4, 0.3, 18); 75 | float4 rot; 76 | sincos(param.x, rot.x, rot.y); 77 | sincos(param.y, rot.z, rot.w); 78 | 79 | float3 rt = float3(0, 0, 0); 80 | float3 ro = float3(rot.x * rot.w, abs(rot.y) * rot.z, rot.y); 81 | ro = ro * param.z; 82 | 83 | float3 cd = normalize(rt - ro); 84 | float3 cr = normalize(cross(cd, float3(0, 1, 0))); 85 | float3 cu = cross(cr, cd); 86 | 87 | float3 rd = normalize(p.x * cr + p.y * cu + 10 * cd); 88 | float4 radiance = shade(ro, rd); 89 | 90 | float3 col = float3(0.02, 0.02, 0.02); 91 | col = lerp(col, radiance.rgb, radiance.a); 92 | return float4(pow(col, 0.45), 1); 93 | } -------------------------------------------------------------------------------- /bin/save/mandelbox.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer Parameters 2 | { 3 | float4 time; 4 | float4 view; 5 | float4 freq; 6 | float4 mpos; 7 | } 8 | 9 | float DE(float3 p) 10 | { 11 | const float scale = 9; 12 | const float3 boxfold = float3(1, 1, 1); 13 | const float spherefold = 0.2; 14 | 15 | float4 c0 = float4(p, 1); 16 | float4 c = c0; 17 | for (int i = 0; i < 4; ++i) 18 | { 19 | c.xyz = clamp(c.xyz, -boxfold, boxfold) * 2 - c.xyz; 20 | float rr = dot(c.xyz, c.xyz); 21 | c *= saturate(max(spherefold / rr, spherefold)); 22 | c = c * scale + c0; 23 | } 24 | return ((length(c.xyz) - (scale - 1)) / c.w - pow(scale, -3)); 25 | } 26 | 27 | float4 ray_marching(float3 ro, float3 rd) 28 | { 29 | for (int i = 0; i < 128; ++i) 30 | { 31 | float d = DE(ro); 32 | ro += d * rd; 33 | if (d < 0.001) return float4(ro, i); 34 | } 35 | return float4(ro, -1); 36 | } 37 | 38 | float4 shade(float3 ro, float3 rd) 39 | { 40 | float4 rm = ray_marching(ro, rd); 41 | if (rm.w < 0) return float4(0, 0, 0, 0); 42 | 43 | float3 p = rm.xyz; 44 | float k = DE(p); 45 | float gx = DE(p + float3(1e-5, 0, 0)) - k; 46 | float gy = DE(p + float3(0, 1e-5, 0)) - k; 47 | float gz = DE(p + float3(0, 0, 1e-5)) - k; 48 | float3 N = normalize(float3(gx, gy, gz)); 49 | float3 L = normalize(float3(-1, 1, 2)); 50 | 51 | float3 C = float3(0.5, 0.8, 0.9); 52 | float shadow = saturate(DE(p + L * 0.1) - k) / 0.1; 53 | float ao = 1 - rm.w / 128; ao = ao * ao; 54 | float A = 0.1; 55 | float3 col = (A + saturate(dot(L, N)) * shadow) * ao * C; 56 | 57 | return float4(col , 1); 58 | } 59 | 60 | float4 ps_main(in float2 tc : TEXCOORD) : SV_TARGET 61 | { 62 | float3 p = float3((tc * 2 - 1), 0); 63 | p.xy *= float2(view.x * view.w, -1); 64 | 65 | float3 param = mpos.xyz * float3(-0.005, 0.005, -0.5) + float3(0.4, 0.3, 40); 66 | float4 rot; 67 | sincos(param.x, rot.x, rot.y); 68 | sincos(param.y, rot.z, rot.w); 69 | 70 | float3 rt = float3(0, 0, 0); 71 | float3 ro = float3(rot.x * rot.w, abs(rot.y) * rot.z, rot.y); 72 | ro = ro * param.z; 73 | 74 | float3 cd = normalize(rt - ro); 75 | float3 cr = normalize(cross(cd, float3(0, 1, 0))); 76 | float3 cu = cross(cr, cd); 77 | 78 | float3 rd = normalize(p.x * cr + p.y * cu + 3 * cd); 79 | float4 radiance = shade(ro, rd); 80 | 81 | float3 col = float3(0.02, 0.02, 0.02); 82 | col = lerp(col, radiance.rgb, radiance.a); 83 | return float4(pow(col, 0.45), 1); 84 | } 85 | -------------------------------------------------------------------------------- /bin/save/mandelbrot4d.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer Parameters 2 | { 3 | float4 time; 4 | float4 view; 5 | float4 freq; 6 | float4 mpos; 7 | } 8 | 9 | float4 mul4d(float4 a, float4 b) 10 | { 11 | float4 c; 12 | c.x = a.x * b.x - dot(a.yzw, b.yzw); 13 | c.yzw = cross(a.yzw, b.yzw) + b.x * a.yzw + a.x * b.yzw; 14 | return c; 15 | } 16 | 17 | float DE(float3 p) 18 | { 19 | float4 c = 0; 20 | float4 d = 0; 21 | float r = 0; 22 | for (int i = 0; i < 16 && r < 3; ++i) 23 | { 24 | d = 2 * mul4d(c, d) + 1; 25 | p.z = -p.z; // to break the boring symmetry 26 | c = mul4d(c, c) + float4(p, 0); 27 | r = length(c); 28 | } 29 | float dr = length(d); 30 | return 0.5 * log(r) * r / dr; 31 | } 32 | 33 | float4 ray_marching(float3 ro, float3 rd) 34 | { 35 | for (int i = 0; i < 64; ++i) 36 | { 37 | float d = DE(ro); 38 | ro += d * rd; 39 | if (d < 0.002) return float4(ro, i); 40 | } 41 | return float4(ro, -1); 42 | } 43 | 44 | float4 shade(float3 ro, float3 rd) 45 | { 46 | float4 rm = ray_marching(ro, rd); 47 | if (rm.w < 0) return float4(0, 0, 0, 0); 48 | float ao = 1 - rm.w / 64; 49 | float3 C = lerp(float3(0.8, 0.0, 0.3), float3(0.8, 0.8, 0.9), abs(snoise(rm.xyz))); 50 | return float4(C * ao, 1); 51 | } 52 | 53 | float4 ps_main(in float2 tc : TEXCOORD) : SV_TARGET 54 | { 55 | float3 p = float3((tc * 2 - 1), 0); 56 | p.xy *= float2(view.x * view.w, -1); 57 | 58 | float3 param = mpos.xyz * float3(-0.002, 0.005, -0.1) + float3(0.2, 1.0, 14); 59 | float4 rot; 60 | sincos(param.x, rot.x, rot.y); 61 | sincos(param.y, rot.z, rot.w); 62 | 63 | float3 rt = float3(0, 0, 0); 64 | float3 ro = float3(rot.x * rot.w, abs(rot.y) * rot.z, rot.y); 65 | ro = ro * param.z; 66 | 67 | float3 cd = normalize(rt - ro); 68 | float3 cr = normalize(cross(cd, float3(0, 1, 0))); 69 | float3 cu = cross(cr, cd); 70 | 71 | float3 rd = normalize(p.x * cr + p.y * cu + 10 * cd); 72 | float4 radiance = shade(ro, rd); 73 | 74 | float3 col = float3(0.02, 0.02, 0.02); 75 | col = lerp(col, radiance.rgb, radiance.a); 76 | return float4(pow(col, 0.45), 1); 77 | } -------------------------------------------------------------------------------- /bin/save/mandelbulb.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer Parameters 2 | { 3 | float4 time; 4 | float4 view; 5 | float4 freq; 6 | float4 mpos; 7 | } 8 | 9 | float DE(float3 p) 10 | { 11 | float3 c = p; 12 | float r = length(c); 13 | float dr = 1; 14 | for (int i = 0; i < 4 && r < 3; ++i) 15 | { 16 | float xr = pow(r, 7); 17 | dr = 6 * xr * dr + 1; 18 | 19 | float theta = atan2(c.y, c.x) * 8; 20 | float phi = asin(c.z / r) * 8; 21 | r = xr * r; 22 | c = r * float3(cos(phi) * cos(theta), cos(phi) * sin(theta), sin(phi)); 23 | 24 | c += p; 25 | r = length(c); 26 | } 27 | return 0.35 * log(r) * r / dr; 28 | } 29 | 30 | float4 ray_marching(float3 ro, float3 rd) 31 | { 32 | for (int i = 0; i < 64; ++i) 33 | { 34 | float d = DE(ro); 35 | ro += d * rd; 36 | if (d < 0.001) return float4(ro, i); 37 | } 38 | return float4(ro, -1); 39 | } 40 | 41 | float4 shade(float3 ro, float3 rd) 42 | { 43 | float4 rm = ray_marching(ro, rd); 44 | if (rm.w < 0) return float4(0, 0, 0, 0); 45 | 46 | float3 p = rm.xyz; 47 | float k = DE(p); 48 | float gx = DE(p + float3(1e-5, 0, 0)) - k; 49 | float gy = DE(p + float3(0, 1e-5, 0)) - k; 50 | float gz = DE(p + float3(0, 0, 1e-5)) - k; 51 | float3 N = normalize(float3(gx, gy, gz)); 52 | 53 | float ao = 0; 54 | ao += DE(p + 0.1 * N) * 2.5; 55 | ao += DE(p + 0.2 * N) * 1.0; 56 | 57 | float3 L = normalize(float3(-1, 1, 2)); 58 | float4 S = ray_marching(p + N * 0.01, L); 59 | float3 C = lerp(float3(0.6, 0.8, 0.6), float3(1.0, 0.0, 0.0), rm.w / 64); 60 | float D = 0.7 * (S.w < 0 ? 1 : 0); 61 | 62 | float A = 0.1; 63 | float3 col = (A + D * saturate(dot(L, N))) * ao * C; 64 | return float4(col , 1); 65 | } 66 | 67 | float4 ps_main(in float2 tc : TEXCOORD) : SV_TARGET 68 | { 69 | float3 p = float3((tc * 2 - 1), 0); 70 | p.xy *= float2(view.x * view.w, -1); 71 | 72 | float3 param = mpos.xyz * float3(-0.005, 0.005, -0.1) + float3(0.4, 0.3, 4.5); 73 | float4 rot; 74 | sincos(param.x, rot.x, rot.y); 75 | sincos(param.y, rot.z, rot.w); 76 | 77 | float3 rt = float3(0, 0, 0); 78 | float3 ro = float3(rot.x * rot.w, abs(rot.y) * rot.z, rot.y); 79 | ro = ro * param.z; 80 | 81 | float3 cd = normalize(rt - ro); 82 | float3 cr = normalize(cross(cd, float3(0, 1, 0))); 83 | float3 cu = cross(cr, cd); 84 | 85 | float3 rd = normalize(p.x * cr + p.y * cu + 3 * cd); 86 | float4 radiance = shade(ro, rd); 87 | 88 | float3 col = float3(0.02, 0.02, 0.02); 89 | col = lerp(col, radiance.rgb, radiance.a); 90 | return float4(pow(col, 0.45), 1); 91 | } -------------------------------------------------------------------------------- /bin/save/menger.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer Parameters 2 | { 3 | float4 time; 4 | float4 view; 5 | float4 freq; 6 | float4 mpos; 7 | } 8 | 9 | float box(float3 p) 10 | { 11 | p = abs(p) - 1; 12 | return min(max(p.x,max(p.y,p.z)), 0) + length(max(p, 0)); 13 | } 14 | 15 | float DE(float3 p) 16 | { 17 | float d = box(p); 18 | float scale = 1.0; 19 | for(int i = 0; i < 4; ++i) 20 | { 21 | float3 a = fmod(p + 1, 2 * scale) - scale; 22 | scale /= 3; 23 | float3 r = abs(a / scale); 24 | float da = max(r.x, r.y); 25 | float db = max(r.y, r.z); 26 | float dc = max(r.z, r.x); 27 | float c = min(da, min(db, dc)) - 1; 28 | d = max(d, -c * scale); 29 | } 30 | return d; 31 | } 32 | 33 | float4 ray_marching(float3 ro, float3 rd) 34 | { 35 | for (int i = 0; i < 64; ++i) 36 | { 37 | float d = DE(ro); 38 | ro += d * rd; 39 | if (d < 0.001) return float4(ro, i); 40 | } 41 | return float4(ro, -1); 42 | } 43 | 44 | float4 shade(float3 ro, float3 rd) 45 | { 46 | float4 rm = ray_marching(ro, rd); 47 | if (rm.w < 0) return float4(0, 0, 0, 0); 48 | 49 | float3 p = rm.xyz; 50 | float k = DE(p); 51 | float gx = DE(p + float3(1e-5, 0, 0)) - k; 52 | float gy = DE(p + float3(0, 1e-5, 0)) - k; 53 | float gz = DE(p + float3(0, 0, 1e-5)) - k; 54 | float3 N = normalize(float3(gx, gy, gz)); 55 | 56 | float ao = 0; 57 | ao += DE(p + 0.2 * N) * 2.5; 58 | ao += DE(p + 0.5 * N) * 1.0; 59 | 60 | float3 L = normalize(float3(-2, 1, 1)); 61 | float4 S = ray_marching(p + N * 0.001, L); 62 | float3 C = float3(0.3, 0.2, 0.3) + 0.2 * snoise(p * 100); 63 | float D = 0.7 * (S.w < 0 ? 1 : 0); 64 | float A = 0.1; 65 | float3 col = (A + D * saturate(dot(L, N))) * ao * C; 66 | return float4(col , 1); 67 | } 68 | 69 | float4 ps_main(in float2 tc : TEXCOORD) : SV_TARGET 70 | { 71 | float3 p = float3((tc * 2 - 1), 0); 72 | p.xy *= float2(view.x * view.w, -1); 73 | 74 | float3 param = mpos.xyz * float3(-0.005, 0.005, -0.1) + float3(0.4, 0.3, 18); 75 | float4 rot; 76 | sincos(param.x, rot.x, rot.y); 77 | sincos(param.y, rot.z, rot.w); 78 | 79 | float3 rt = float3(0, 0, 0); 80 | float3 ro = float3(rot.x * rot.w, abs(rot.y) * rot.z, rot.y); 81 | ro = ro * param.z; 82 | 83 | float3 cd = normalize(rt - ro); 84 | float3 cr = normalize(cross(cd, float3(0, 1, 0))); 85 | float3 cu = cross(cr, cd); 86 | 87 | float3 rd = normalize(p.x * cr + p.y * cu + 10 * cd); 88 | float4 radiance = shade(ro, rd); 89 | 90 | float3 col = float3(0.02, 0.02, 0.02); 91 | col = lerp(col, radiance.rgb, radiance.a); 92 | return float4(pow(col, 0.45), 1); 93 | } -------------------------------------------------------------------------------- /bin/save/penrose.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer Parameters 2 | { 3 | float4 time; 4 | float4 view; 5 | float4 freq; 6 | float4 mpos; 7 | } 8 | 9 | float box(float3 p, float3 s) 10 | { 11 | p = abs(p) - s; 12 | return min(max(p.x,max(p.y,p.z)), 0) + length(max(p, 0)); 13 | } 14 | 15 | float3 rotateY(float3 p, float sint, float cost) 16 | { 17 | float3 np; 18 | np.y = p.y; 19 | np.x = dot(p.xz, float2(cost, sint)); 20 | np.z = dot(p.xz, float2(-sint, cost)); 21 | return np; 22 | } 23 | 24 | float partA(float3 p) 25 | { 26 | float k = saturate(sin(time.x * 2) * 0.5 - 0.2); 27 | p = rotateY(p, sin(k), cos(k)); 28 | 29 | float a = box(p, float3(1, 6, 1)); 30 | p = rotateY(p, 0, 1); 31 | p.xy -= float2(2, 5); 32 | a = min(a, box(p, float3(3, 1, 1))); 33 | return a; 34 | } 35 | 36 | float partB(float3 p) 37 | { 38 | float k = saturate(sin(time.x * 2) * 0.5 - 0.2); 39 | p = rotateY(p, sin(k), cos(k)); 40 | 41 | float3 op = p; 42 | p = rotateY(p, -1, 0); 43 | p.xy -= float2(2, -5); 44 | return box(p, float3(3, 1, 1)); 45 | } 46 | 47 | float partC(float3 p) 48 | { 49 | p.xy -= float2(8, 5); 50 | p = rotateY(p, 0, 1); 51 | float c = box(p, float3(3, 1, 1)); 52 | p = rotateY(p, -1, 0); 53 | p.xz -= float2(-2, 2); 54 | c = min(c, box(p, float3(3, 1, 1))); 55 | return c; 56 | } 57 | 58 | float DE(float3 p) 59 | { 60 | float a = partA(p); 61 | float b = partB(p); 62 | float c = partC(p); 63 | return min(min(a, b), c); 64 | } 65 | 66 | float4 ray_marching(float3 ro, float3 rd) 67 | { 68 | float4 A = float4(ro, 0); 69 | int i = 0; 70 | for (i = 0; i < 64; ++i) 71 | { 72 | float d = partA(A.xyz); 73 | A += float4(d * rd, d); 74 | if (d < 0.0003) break; 75 | } 76 | if (i > 63) A.w = 1000; 77 | 78 | float4 B = float4(ro, 0); 79 | for (i = 0; i < 64; ++i) 80 | { 81 | float d = partB(B.xyz); 82 | B += float4(d * rd, d); 83 | if (d < 0.0003) break; 84 | } 85 | if (i > 63) B.w = 1000; 86 | 87 | float4 C = float4(ro, 0); 88 | for (i = 0; i < 64; ++i) 89 | { 90 | float d = partC(C.xyz); 91 | C += float4(d * rd, d); 92 | if (d < 0.0003) break; 93 | } 94 | if (i > 63) C.w = 1000; 95 | 96 | float4 AB = A.w < B.w ? A : B; 97 | if (B.w < 100) return AB; 98 | return AB.w < C.w ? AB : C; 99 | } 100 | 101 | float4 shade(float3 ro, float3 rd) 102 | { 103 | float4 rm = ray_marching(ro, rd); 104 | if (rm.w > 100) return float4(0, 0, 0, 0); 105 | 106 | float3 p = rm.xyz - rd * 0.001; 107 | float k = DE(p); 108 | float gx = DE(p + float3(1e-5, 0, 0)) - k; 109 | float gy = DE(p + float3(0, 1e-5, 0)) - k; 110 | float gz = DE(p + float3(0, 0, 1e-5)) - k; 111 | float3 N = normalize(float3(gx, gy, gz)); 112 | 113 | float3 col = float3(0.85, 0.53, 0.64); 114 | if (abs(N.x) > 0.5) col = float3(0.47, 0.52, 0.68); 115 | if (abs(N.y) > 0.3) col = float3(0.9, 0.9, 0.8); 116 | return float4(col, 1); 117 | } 118 | 119 | float4 ps_main(in float2 tc : TEXCOORD) : SV_TARGET 120 | { 121 | float3 p = float3((tc * 2 - 1), 0); 122 | p.xy *= float2(view.x * view.w, -1); 123 | 124 | const float sinphi = sqrt(3.0) / 3.0; 125 | const float cosphi = sqrt(2.0 / 3.0); 126 | 127 | // ortho view 128 | p.x *= cosphi; 129 | float3 ro = p * 20 + float3(2, 14, 20); 130 | float3 rd = float3(0, -sinphi, -cosphi); 131 | 132 | // 45 degree 133 | const float sc45 = sqrt(2.0) / 2.0; 134 | ro = rotateY(ro, sc45, sc45); 135 | rd = rotateY(rd, sc45, sc45); 136 | 137 | // shading 138 | float4 radiance = shade(ro, rd); 139 | 140 | float3 A = float3(0.8, 0.7, 0.6); 141 | if (frac((sin(tc.x * 122.39) + tc.y) * 239.383) < 0.001) A = 1.0; 142 | float3 B = float3(0.2, 0.8, 0.7); 143 | float3 col = lerp(A, B, 0.4 * tc.x + 0.7 * tc.y); 144 | col = lerp(col, radiance.rgb, radiance.a); 145 | return float4(col, 1); 146 | } -------------------------------------------------------------------------------- /bin/save/piano.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer Parameters 2 | { 3 | float4 time; 4 | float4 view; 5 | float4 fft; 6 | } 7 | 8 | float white_keys(float3 p) 9 | { 10 | float ox = p.x; 11 | p.x = fmod(abs(ox + 0.03), 0.06) - 0.03; 12 | float d1 = length(max(abs(p) - float3(0.023, 0.002, 0.2), 0)) - 0.005; 13 | p.y += 0.04; 14 | float d2 = length(max(abs(p) - float3(0.023, 0.04, 0.18), 0)) - 0.002; 15 | 16 | int r = fmod(floor(ox / 0.06) + 70, 7); 17 | if (r == 0 || r == 4) return min(d1, d2); 18 | 19 | p.x = fmod(abs(ox), 0.06) - 0.03; 20 | p.z -= 0.1; 21 | float3 t = abs(p) - float3(0.02, 0.1, 0.15); 22 | float d3 = min(max(t.x, max(t.y, t.z)), 0) + length(max(t, 0)); 23 | return max(min(d1, d2), -d3); 24 | } 25 | 26 | float black_keys(float3 p) 27 | { 28 | int r = fmod(floor(p.x / 0.06) + 70, 7); 29 | if (r == 0 || r == 4) return 1000; 30 | p.x = fmod(abs(p.x), 0.06) - 0.03; 31 | p.x *= (1 + 10 * p.y); 32 | p.y += 0.5 * p.z * p.z; 33 | p.z -= 0.08; 34 | p.y -= 0.014; 35 | return length(max(abs(p) - float3(0.01, 0.03, 0.122), 0)) - 0.003; 36 | } 37 | 38 | float boards(float3 p) 39 | { 40 | p.z += 0.3; 41 | p.y += 0.065; 42 | float d1 = length(max(abs(p) - float3(2, 0.05, 0.02), 0)) - 0.01; 43 | p.z -= 0.53; 44 | float d2 = length(max(abs(p) - float3(2, 0.13, 0.007), 0)) - 0.01; 45 | return min(d1, d2); 46 | } 47 | 48 | float2 piano(float3 p) 49 | { 50 | float d1 = white_keys(p); 51 | float d2 = black_keys(p); 52 | float d3 = boards(p); 53 | float2 t = d1 < d2 ? float2(d1, 1) : float2(d2, 2); 54 | return t.x < d3 ? t : float2(d3, 3); 55 | } 56 | 57 | float4 ray_marching(float3 ro, float3 rd) 58 | { 59 | for (int i = 0; i < 32; ++i) 60 | { 61 | float2 dm = piano(ro); 62 | if (dm.x < 0.001) return float4(ro, dm.y); 63 | ro += rd * dm.x; 64 | } 65 | return float4(ro, -1); 66 | } 67 | 68 | float3 brdf(float3 diff, float m, float3 N, float3 L, float3 V) 69 | { 70 | float3 H = normalize(V + L); 71 | float3 F = 0.05 + 0.95 * pow(1 - dot(V, H), 5); 72 | float3 R = F * pow(max(dot(N, H), 0), m); 73 | return diff + R * (m + 8) / 8; 74 | } 75 | 76 | float3 lit_white_keys(float3 p, float3 N) 77 | { 78 | float3 V = normalize(float3(0, 3, -5)); 79 | float3 L = normalize(float3(3, 3, -1)); 80 | float3 C = 2 * brdf(0.9, 50, N, L, V) * max(dot(N, L), 0.1); 81 | float ao = 0; 82 | ao += 0.5 * (0.02 - piano(p + 0.02 * N).x); 83 | ao += 0.25 * (0.04 - piano(p + 0.04 * N).x); 84 | ao += 0.125 * (0.06 - piano(p + 0.06 * N).x); 85 | ao = max(1 - 50 * ao, 0.2); 86 | float shadow = 0; 87 | shadow += black_keys(p + 0.02 * L).x; 88 | shadow += black_keys(p + 0.04 * L).x; 89 | shadow += black_keys(p + 0.06 * L).x; 90 | shadow = min(60 * shadow, 1.0); 91 | return C * ao * shadow; 92 | } 93 | 94 | float3 lit_black_keys(float3 p, float3 N) 95 | { 96 | float3 V = normalize(float3(0, 3, -5)); 97 | float3 L = normalize(float3(0, 3, 2)); 98 | return 2 * brdf(0, 50, N, L, V); 99 | } 100 | 101 | float3 lit_boards(float3 p, float3 N) 102 | { 103 | float3 V = normalize(float3(0, 3, -5)); 104 | float3 L = normalize(float3(0, 3, 2)); 105 | return max(brdf(0, 50, N, L, V), 0.005); 106 | } 107 | 108 | float4 do_lighting(float3 ro, float3 rd) 109 | { 110 | float4 rm = ray_marching(ro, rd); 111 | if (rm.w < 0) return float4(0, 0, 0, 0); 112 | 113 | float gx = (piano(rm.xyz + float3(0.0001, 0, 0)) - piano(rm.xyz - float3(0.0001, 0, 0))).x; 114 | float gy = (piano(rm.xyz + float3(0, 0.0001, 0)) - piano(rm.xyz - float3(0, 0.0001, 0))).x; 115 | float gz = (piano(rm.xyz + float3(0, 0, 0.0001)) - piano(rm.xyz - float3(0, 0, 0.0001))).x; 116 | float3 N = normalize(float3(gx, gy, gz)); 117 | 118 | if (rm.w < 1.5) return float4(lit_white_keys(rm.xyz, N), 1); 119 | else if (rm.w < 2.5) return float4(lit_black_keys(rm.xyz, N), 1); 120 | else return float4(lit_boards(rm.xyz, N), 1); 121 | } 122 | 123 | #define FSAA 0 124 | 125 | float4 ps_main(in float2 in_tex : TEXCOORD) : SV_TARGET 126 | { 127 | float2 p = (in_tex - 0.5) * 2 * float2(1, -view.y / view.x); 128 | if (abs(p.y) > 200.0 / 1024.0) return 0; 129 | 130 | float3 ro = float3(0, 3, -5); 131 | float3 rt = float3(0, 0, 0); 132 | float3 cd = normalize(rt - ro); 133 | float3 cr = normalize(cross(cd, float3(0, 1, 0))); 134 | float3 cu = cross(cr, cd); 135 | 136 | float3 rd = normalize(p.x * cr + p.y * cu + 5 * cd); 137 | float4 radiance = do_lighting(ro, rd); 138 | 139 | float3 col = 0.06 - 0.06 * length(p - float2(0.2, 0.3)); 140 | col = lerp(col, radiance.rgb, radiance.a); 141 | return float4(pow(col, 0.45), 1); 142 | } 143 | -------------------------------------------------------------------------------- /bin/save/sierpinski.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer Parameters 2 | { 3 | float4 time; 4 | float4 view; 5 | float4 freq; 6 | float4 mpos; 7 | } 8 | 9 | float DE(float3 p) 10 | { 11 | for (int i = 0; i < 16; ++i) 12 | { 13 | if (p.x + p.y < 0) p.xy = -p.yx; 14 | if (p.x + p.z < 0) p.xz = -p.zx; 15 | if (p.z + p.y < 0) p.zy = -p.yz; 16 | p = 2 * p - 1; 17 | } 18 | return length(p - 1) * pow(2, -16); 19 | } 20 | 21 | float4 ray_marching(float3 ro, float3 rd) 22 | { 23 | for (int i = 0; i < 64; ++i) 24 | { 25 | float d = DE(ro); 26 | ro += d * rd; 27 | if (d < 0.003) return float4(ro, i); 28 | } 29 | return float4(ro, -1); 30 | } 31 | 32 | float4 shade(float3 ro, float3 rd) 33 | { 34 | float4 rm = ray_marching(ro, rd); 35 | if (rm.w < 0) return float4(0, 0, 0, 0); 36 | 37 | float aol = 1 - rm.w / 64.0; 38 | float3 diff = float3(0.1, 0.2, 0.2); 39 | diff += float3(0.08, 0.04, 0.02) * snoise(rm.xyz * 10); 40 | return float4(diff * (aol * aol), 1); 41 | } 42 | 43 | float4 ps_main(in float2 tc : TEXCOORD) : SV_TARGET 44 | { 45 | float3 p = float3((tc * 2 - 1), 0); 46 | p.xy *= float2(view.x * view.w, -1); 47 | 48 | float3 gx = normalize(float3( 1, -1, 0)); 49 | float3 gy = normalize(float3( 1, 1, 1)); 50 | float3 gz = normalize(float3(-1, -1, 2)); 51 | 52 | float3 param = mpos.xyz * float3(-0.005, 0.005, -0.1) + float3(0.2, 0, 8); 53 | float4 rot; 54 | sincos(param.x, rot.x, rot.y); 55 | sincos(param.y, rot.z, rot.w); 56 | 57 | float3 rt = float3(0.25, 0.25, 0.25); 58 | float3 ro = rot.x * rot.w * gx + abs(rot.y) * rot.z * gy + rot.y * gz; 59 | ro = ro * param.z; 60 | 61 | float3 cd = normalize(rt - ro); 62 | float3 cr = normalize(cross(cd, gy)); 63 | float3 cu = cross(cr, cd); 64 | 65 | float3 rd = normalize(p.x * cr + p.y * cu + 5 * cd); 66 | float4 radiance = shade(ro, rd); 67 | 68 | float3 col = float3(0.02, 0.02, 0.02); 69 | col = lerp(col, radiance.rgb, radiance.a); 70 | return float4(pow(col, 0.45), 1); 71 | } -------------------------------------------------------------------------------- /bin/save/sphere.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer Parameters 2 | { 3 | float4 time; 4 | float4 view; 5 | float4 freq; 6 | float4 mpos; 7 | } 8 | 9 | float sphere(float3 p, float r) 10 | { 11 | return length(p - r) - r; 12 | } 13 | 14 | float corner(float3 p) 15 | { 16 | return min(p.x, min(p.y, p.z)); 17 | } 18 | 19 | float2 DE(float3 p) 20 | { 21 | float d1 = sphere(p, 1); 22 | float d2 = corner(p); 23 | return d1 < d2 ? float2(d1, 1) : float2(d2, 2); 24 | } 25 | 26 | float4 ray_marching(float3 ro, float3 rd) 27 | { 28 | for (int i = 0; i < 128; ++i) 29 | { 30 | float2 d = DE(ro); 31 | ro += d.x * rd; 32 | if (d.x < 0.001) return float4(ro, d.y); 33 | } 34 | return float4(ro, -1); 35 | } 36 | 37 | float3 brdf(float3 diff, float m, float3 N, float3 L, float3 V) 38 | { 39 | float3 H = normalize(V + L); 40 | float3 F = 0.05 + 0.95 * pow(1 - dot(V, H), 5); 41 | float3 R = F * pow(max(dot(N, H), 0), m); 42 | return diff + R * (m + 8) / 8; 43 | } 44 | 45 | float fbm(float3 p) 46 | { 47 | float f; 48 | f = 0.5000 * qnoise(p); p = p * 2.02; 49 | f += 0.2500 * qnoise(p); p = p * 2.03; 50 | f += 0.1250 * qnoise(p); p = p * 2.01; 51 | f += 0.0625 * qnoise(p); 52 | return f; 53 | } 54 | 55 | float4 shade(inout float3 ro, inout float3 rd) 56 | { 57 | float4 rm = ray_marching(ro, rd); 58 | if (rm.w < 0) return 0; 59 | 60 | float3 diff, N; 61 | float m, r; 62 | if (rm.w < 1.5) 63 | { 64 | float s = abs(sin(5.6 * fbm(rm.xyz * 3.4))); 65 | diff = lerp(float3(0.55, 0.3, 0.25), float3(1, 1, 1), s); 66 | N = rm.xyz - 1; 67 | m = 50; 68 | r = saturate(1 - abs(dot(-rd, N)) + 0.2); 69 | } 70 | else 71 | { 72 | float s = saturate(length(step(0.01, fmod(rm.xyz, 0.3))) - 1); 73 | diff = s * float3(0.4, 0.4, 0.4) + float3(0.2, 0.2, 0.2) + 0.1 * qnoise(rm.xyz * 78); 74 | diff = diff / (1 + dot(rm.xyz, rm.xyz)); 75 | N = normalize(1 - step(0.001, rm.xyz)); 76 | m = 10; 77 | r = 0; 78 | } 79 | 80 | float ao = 0.2; 81 | ao += saturate(DE(rm.xyz + 0.1 * N).x) * 4; 82 | ao += saturate(DE(rm.xyz + 0.2 * N).x) * 2; 83 | ao += saturate(DE(rm.xyz + 0.4 * N).x) * 1; 84 | 85 | float3 L = normalize(float3(0.6, 1, 1)); 86 | float shadow = exp((DE(rm.xyz + 0.6 * L).x - 0.6) * 3); 87 | 88 | float3 f = brdf(diff, m, N, L, -rd); 89 | float3 C = saturate(dot(N, L) + 0.3) * f * ao * shadow; 90 | rd = reflect(rd, N); 91 | ro = rm.xyz + rd * 0.01; 92 | return float4(C, r); 93 | } 94 | 95 | float4 ps_main(in float2 tc : TEXCOORD) : SV_TARGET 96 | { 97 | float3 p = float3((tc * 2 - 1), 0); 98 | p.xy *= float2(view.x * view.w, -1); 99 | 100 | float3 param = mpos.xyz * float3(-0.005, 0.005, -0.1) + float3(0.8, 0.7, 12); 101 | float4 rot; 102 | sincos(param.x, rot.x, rot.y); 103 | sincos(param.y, rot.z, rot.w); 104 | 105 | float3 rt = float3(1, 1.2, 1); 106 | float3 ro = float3(rot.x * rot.w, abs(rot.y) * rot.z, rot.y); 107 | ro = ro * param.z; 108 | 109 | float3 cd = normalize(rt - ro); 110 | float3 cr = normalize(cross(cd, float3(0, 1, 0))); 111 | float3 cu = cross(cr, cd); 112 | 113 | float3 rd = normalize(p.x * cr + p.y * cu + 5 * cd); 114 | float4 col = shade(ro, rd); 115 | if (col.a > 0) 116 | { 117 | float4 col2 = shade(ro, rd); 118 | col = lerp(col, col2, col.a); 119 | } 120 | return float4(pow(col.rgb, 0.45), 1); 121 | } 122 | -------------------------------------------------------------------------------- /bin/save/tunnel.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer Parameters 2 | { 3 | float4 time; 4 | float4 view; 5 | float4 freq; 6 | float4 mpos; 7 | } 8 | 9 | Texture2D tex; 10 | SamplerState samp; 11 | 12 | float4 ps_main(in float2 in_tex : TEXCOORD) : SV_TARGET 13 | { 14 | float2 p = (in_tex - 0.5) * 2 + mpos.xy * view.zw; 15 | float a = atan2(p.y, p.x); 16 | float r = length(p); 17 | float2 tc = float2(a / 6.28, 0.3 * time.x + 0.1 / r); 18 | float3 s = tex.Sample(samp, tc); 19 | s *= 1 + step(0.4, freq.x); 20 | s *= r * r; 21 | return float4(s, 1); 22 | } 23 | -------------------------------------------------------------------------------- /live_coding.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "live_coding", "live_coding.vcxproj", "{B42C522B-FC98-4041-B882-1916C8D7759A}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {B42C522B-FC98-4041-B882-1916C8D7759A}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {B42C522B-FC98-4041-B882-1916C8D7759A}.Debug|Win32.Build.0 = Debug|Win32 14 | {B42C522B-FC98-4041-B882-1916C8D7759A}.Release|Win32.ActiveCfg = Release|Win32 15 | {B42C522B-FC98-4041-B882-1916C8D7759A}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /live_coding.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | false 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | {B42C522B-FC98-4041-B882-1916C8D7759A} 47 | live_coding 48 | 49 | 50 | 51 | Application 52 | true 53 | MultiByte 54 | 55 | 56 | Application 57 | false 58 | true 59 | MultiByte 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | $(SolutionDir);$(ExecutablePath) 73 | 74 | 75 | E:\Microsoft DirectX SDK %28June 2010%29\Include;$(IncludePath) 76 | 77 | 78 | E:\Microsoft DirectX SDK %28June 2010%29\Lib\x86;$(LibraryPath) 79 | 80 | 81 | $(ExcludePath) 82 | $(SolutionDir)\bin\ 83 | $(ProjectName)_debug 84 | 85 | 86 | $(SolutionDir);$(ExecutablePath) 87 | 88 | 89 | E:\Microsoft DirectX SDK %28June 2010%29\Include;$(IncludePath) 90 | 91 | 92 | E:\Microsoft DirectX SDK %28June 2010%29\Lib\x86;$(LibraryPath) 93 | 94 | 95 | $(ExcludePath) 96 | $(SolutionDir)\bin\ 97 | 98 | 99 | 100 | Level3 101 | Disabled 102 | E:\FMOD SoundSystem\FMOD Programmers API Windows\api\inc 103 | 104 | 105 | true 106 | E:\FMOD SoundSystem\FMOD Programmers API Windows\api\lib 107 | fmodex_vc.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 108 | 109 | 110 | 111 | 112 | Level3 113 | MaxSpeed 114 | true 115 | true 116 | E:\FMOD SoundSystem\FMOD Programmers API Windows\api\inc 117 | 118 | 119 | true 120 | true 121 | true 122 | E:\FMOD SoundSystem\FMOD Programmers API Windows\api\lib 123 | fmodex_vc.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 124 | 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atyuwen/hlsl_live_coding/c402d73ff80d81e84f1241109d8b93e729853061/snap.png -------------------------------------------------------------------------------- /src/ayw/common_helper.h: -------------------------------------------------------------------------------- 1 | // file: common_helper.h 2 | // path: AywProc\AywProc\core\include 3 | // purpose: define some common macros 4 | // 5 | // author: atyuwen 6 | // homepage: http://code.google.com/p/aywproc/ 7 | // 8 | // created: 2010/05/26 9 | // history: 10 | // 11 | ////////////////////////////////////////////////////////////////////// 12 | 13 | #ifndef _COMMON_HELPER_H_ 14 | #define _COMMON_HELPER_H_ 15 | 16 | #define DECLARE_CONVERSION_TO_POINTER(Type, addr) \ 17 | Type * ptr() \ 18 | { \ 19 | return (Type *)(addr); \ 20 | } \ 21 | const Type * ptr() const \ 22 | { \ 23 | return (const Type *)(addr); \ 24 | } 25 | 26 | #define DECLARE_SUBSCRIPT_OPERATOR(Type, addr) \ 27 | Type & operator [] (size_t i) \ 28 | { \ 29 | return (addr)[i]; \ 30 | } \ 31 | const Type & operator [] (size_t i) const \ 32 | { \ 33 | return (addr)[i]; \ 34 | } 35 | 36 | #define DECLARE_NATIVE_ITERATOR(Type, addr, n) \ 37 | typedef Type value_type; \ 38 | typedef value_type* iterator; \ 39 | typedef const value_type* const_iterator; \ 40 | iterator begin() {return iterator(addr);} \ 41 | iterator end() {return iterator(addr) + (n);} \ 42 | const_iterator begin() const {return const_iterator(addr);} \ 43 | const_iterator end() const {return const_iterator(addr) + (n);} 44 | 45 | #endif // _COMMON_HELPER_H_ -------------------------------------------------------------------------------- /src/ayw/constant.hpp: -------------------------------------------------------------------------------- 1 | // file: constant.hpp 2 | // path: AywProc\AywProc\core\include 3 | // purpose: define some mathematical constants 4 | // 5 | // author: atyuwen 6 | // homepage: http://code.google.com/p/aywproc/ 7 | // 8 | // created: 2010/04/21 9 | // history: 10 | // 11 | ////////////////////////////////////////////////////////////////////// 12 | 13 | #ifndef _CONSTANT_HPP_ 14 | #define _CONSTANT_HPP_ 15 | 16 | namespace Ayw 17 | { 18 | static const float c_pi = 3.14159265f; // [ pi ] 19 | static const float c_pi_r = 0.318309886f; // [ 1 / pi ] 20 | static const float c_e = 2.71828183f; // [ e ] 21 | static const float c_ln2 = 0.693147181f; // [ ln(2) ] 22 | static const float c_ln2_r = 1.44269504f; // [ 1/ln(2) = log2(e) ] 23 | static const float c_ln10 = 2.30258509f; // [ ln(10)] 24 | static const float c_ln10_r = 0.434294482f; // [ 1/ln(10) = log10(e) ] 25 | static const float c_sqrt2 = 1.41421356f; // [ sqrt(2)] 26 | static const float c_sqrt2_r = 0.707106781f; // [ 1 / sqrt(2) ] 27 | 28 | static const float c_eps = 1.0e-9f; 29 | } 30 | 31 | #endif // _CONSTANT_HPP_ -------------------------------------------------------------------------------- /src/ayw/vector.hpp: -------------------------------------------------------------------------------- 1 | // file: vector.hpp 2 | // path: AywProc\AywProc\core\include 3 | // purpose: vector template class 4 | // 5 | // author: atyuwen 6 | // homepage: http://code.google.com/p/aywproc/ 7 | // 8 | // created: 2010/04/20 9 | // history: 10 | // 11 | ////////////////////////////////////////////////////////////////////// 12 | 13 | #ifndef _VECTOR_HPP_ 14 | #define _VECTOR_HPP_ 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include "common_helper.h" 21 | #include "vector_helper.hpp" 22 | 23 | namespace Ayw 24 | { 25 | template struct vector_2t; 26 | template struct vector_3t; 27 | template struct vector_4t; 28 | 29 | typedef vector_2t float2; 30 | typedef vector_3t float3; 31 | typedef vector_4t float4; 32 | 33 | template 34 | struct vector_2t 35 | { 36 | public: 37 | vector_2t(Type nx = Type(), Type ny = Type()) 38 | : x(nx) 39 | , y(ny) 40 | { 41 | } 42 | 43 | public: 44 | DECLARE_CONVERSION_TO_POINTER(Type, &x) 45 | DECLARE_SUBSCRIPT_OPERATOR(Type, &x) 46 | DECLARE_NATIVE_ITERATOR(Type, &x, 2) 47 | DECLARE_SWIZZLING_FOR_VECTOR_2T(); 48 | 49 | public: 50 | Type length_sqr() const 51 | { 52 | return x * x + y * y; 53 | } 54 | 55 | Type length() const 56 | { 57 | BOOST_STATIC_ASSERT(boost::is_floating_point::value); 58 | return std::sqrt(length_sqr()); 59 | } 60 | 61 | vector_2t& normalize() 62 | { 63 | BOOST_STATIC_ASSERT(boost::is_floating_point::value); 64 | return (*this) /= length(); 65 | } 66 | 67 | public: 68 | vector_2t& operator += (const vector_2t &rhs) 69 | { 70 | x += rhs.x; 71 | y += rhs.y; 72 | return *this; 73 | } 74 | 75 | vector_2t& operator -= (const vector_2t &rhs) 76 | { 77 | x -= rhs.x; 78 | y -= rhs.y; 79 | return *this; 80 | } 81 | 82 | vector_2t& operator *= (Type scale) 83 | { 84 | x *= scale; 85 | y *= scale; 86 | return *this; 87 | } 88 | 89 | vector_2t& operator /= (Type scale) 90 | { 91 | BOOST_STATIC_ASSERT(boost::is_floating_point::value); 92 | Type scale_r = 1 / scale; 93 | return (*this) *= scale_r; 94 | } 95 | 96 | vector_2t& operator *= (const vector_2t &rhs) 97 | { 98 | x *= rhs.x; 99 | y *= rhs.y; 100 | return *this; 101 | } 102 | 103 | vector_2t& operator /= (const vector_2t &rhs) 104 | { 105 | BOOST_STATIC_ASSERT(boost::is_floating_point::value); 106 | x /= rhs.x; 107 | y /= rhs.y; 108 | return *this; 109 | } 110 | 111 | public: 112 | Type x; 113 | Type y; 114 | }; 115 | 116 | template 117 | struct vector_3t 118 | { 119 | public: 120 | vector_3t(Type nx = Type(), Type ny = Type(),Type nz = Type()) 121 | : x(nx) 122 | , y(ny) 123 | , z(nz) 124 | { 125 | } 126 | 127 | public: 128 | DECLARE_CONVERSION_TO_POINTER(Type, &x) 129 | DECLARE_SUBSCRIPT_OPERATOR(Type, &x) 130 | DECLARE_NATIVE_ITERATOR(Type, &x, 3) 131 | DECLARE_SWIZZLING_FOR_VECTOR_3T(); 132 | 133 | public: 134 | Type length_sqr() const 135 | { 136 | return x * x + y * y + z * z; 137 | } 138 | 139 | Type length() const 140 | { 141 | BOOST_STATIC_ASSERT(boost::is_floating_point::value); 142 | return std::sqrt(length_sqr()); 143 | } 144 | 145 | vector_3t& normalize() 146 | { 147 | BOOST_STATIC_ASSERT(boost::is_floating_point::value); 148 | return (*this) /= length(); 149 | } 150 | 151 | public: 152 | vector_3t& operator += (const vector_3t &rhs) 153 | { 154 | x += rhs.x; 155 | y += rhs.y; 156 | z += rhs.z; 157 | return *this; 158 | } 159 | 160 | vector_3t& operator -= (const vector_3t &rhs) 161 | { 162 | x -= rhs.x; 163 | y -= rhs.y; 164 | z -= rhs.z; 165 | return *this; 166 | } 167 | 168 | vector_3t& operator *= (Type scale) 169 | { 170 | x *= scale; 171 | y *= scale; 172 | z *= scale; 173 | return *this; 174 | } 175 | 176 | vector_3t& operator /= (Type scale) 177 | { 178 | BOOST_STATIC_ASSERT(boost::is_floating_point::value); 179 | Type scale_r = 1 / scale; 180 | return (*this) *= scale_r; 181 | } 182 | 183 | vector_3t& operator *= (const vector_3t &rhs) 184 | { 185 | x *= rhs.x; 186 | y *= rhs.y; 187 | z *= rhs.z; 188 | return *this; 189 | } 190 | 191 | vector_3t& operator /= (const vector_3t &rhs) 192 | { 193 | BOOST_STATIC_ASSERT(boost::is_floating_point::value); 194 | x /= rhs.x; 195 | y /= rhs.y; 196 | z /= rhs.z; 197 | return *this; 198 | } 199 | 200 | public: 201 | Type x; 202 | Type y; 203 | Type z; 204 | }; 205 | 206 | template 207 | struct vector_4t 208 | { 209 | public: 210 | vector_4t(Type nx = Type(), Type ny = Type(), Type nz = Type(), Type nw = Type()) 211 | : x(nx) 212 | , y(ny) 213 | , z(nz) 214 | , w(nw) 215 | { 216 | } 217 | 218 | public: 219 | DECLARE_CONVERSION_TO_POINTER(Type, &x) 220 | DECLARE_SUBSCRIPT_OPERATOR(Type, &x) 221 | DECLARE_NATIVE_ITERATOR(Type, &x, 4) 222 | DECLARE_SWIZZLING_FOR_VECTOR_4T(); 223 | 224 | public: 225 | Type length_sqr() const 226 | { 227 | return x * x + y * y + z * z + w * w; 228 | } 229 | 230 | Type length() const 231 | { 232 | BOOST_STATIC_ASSERT(boost::is_floating_point::value); 233 | return std::sqrt(length_sqr()); 234 | } 235 | 236 | vector_4t& normalize() 237 | { 238 | BOOST_STATIC_ASSERT(boost::is_floating_point::value); 239 | return (*this) /= length(); 240 | } 241 | 242 | public: 243 | vector_4t& operator += (const vector_4t &rhs) 244 | { 245 | x += rhs.x; 246 | y += rhs.y; 247 | z += rhs.z; 248 | w += rhs.w; 249 | return *this; 250 | } 251 | 252 | vector_4t& operator -= (const vector_4t &rhs) 253 | { 254 | x -= rhs.x; 255 | y -= rhs.y; 256 | z -= rhs.z; 257 | z -= rhs.w; 258 | return *this; 259 | } 260 | 261 | vector_4t& operator *= (Type scale) 262 | { 263 | x *= scale; 264 | y *= scale; 265 | z *= scale; 266 | w *= scale; 267 | return *this; 268 | } 269 | 270 | vector_4t& operator /= (Type scale) 271 | { 272 | BOOST_STATIC_ASSERT(boost::is_floating_point::value); 273 | Type scale_r = 1 / scale; 274 | return (*this) *= scale_r; 275 | } 276 | 277 | vector_4t& operator *= (const vector_4t &rhs) 278 | { 279 | x *= rhs.x; 280 | y *= rhs.y; 281 | z *= rhs.z; 282 | w *= rhs.w; 283 | return *this; 284 | } 285 | 286 | vector_4t& operator /= (const vector_4t &rhs) 287 | { 288 | BOOST_STATIC_ASSERT(boost::is_floating_point::value); 289 | x /= rhs.x; 290 | y /= rhs.y; 291 | z /= rhs.z; 292 | w /= rhs.w; 293 | return *this; 294 | } 295 | 296 | public: 297 | Type x; 298 | Type y; 299 | Type z; 300 | Type w; 301 | }; 302 | 303 | ////////////////////////////////////////////////////////////////////////// 304 | // negation 305 | template 306 | vector_2t operator - (const vector_2t &operand) 307 | { 308 | return vector_2t(-operand.x, -operand.y); 309 | } 310 | 311 | template 312 | vector_3t operator - (const vector_3t &operand) 313 | { 314 | return vector_3t(-operand.x, -operand.y, -operand.z); 315 | } 316 | 317 | template 318 | vector_4t operator - (const vector_4t &operand) 319 | { 320 | return vector_4t(-operand.x, -operand.y, -operand.z, -operand.w); 321 | } 322 | 323 | ////////////////////////////////////////////////////////////////////////// 324 | // addition 325 | template 326 | vector_2t operator + (const vector_2t &lhs, const vector_2t &rhs) 327 | { 328 | return vector_2t (lhs.x + rhs.x, lhs.y + rhs.y); 329 | } 330 | 331 | template 332 | vector_3t operator + (const vector_3t &lhs, const vector_3t &rhs) 333 | { 334 | return vector_3t (lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z); 335 | } 336 | 337 | template 338 | vector_4t operator + (const vector_4t &lhs, const vector_4t &rhs) 339 | { 340 | return vector_4t (lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); 341 | } 342 | 343 | ////////////////////////////////////////////////////////////////////////// 344 | // subtraction 345 | template 346 | vector_2t operator - (const vector_2t &lhs, const vector_2t &rhs) 347 | { 348 | return vector_2t (lhs.x - rhs.x, lhs.y - rhs.y); 349 | } 350 | 351 | template 352 | vector_3t operator - (const vector_3t &lhs, const vector_3t &rhs) 353 | { 354 | return vector_3t (lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z); 355 | } 356 | 357 | template 358 | vector_4t operator - (const vector_4t &lhs, const vector_4t &rhs) 359 | { 360 | return vector_4t (lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); 361 | } 362 | 363 | ////////////////////////////////////////////////////////////////////////// 364 | // multiplication : vector * scalar 365 | template 366 | vector_2t operator * (const vector_2t &lhs, const S& scale) 367 | { 368 | return vector_2t (lhs.x * scale, lhs.y * scale); 369 | } 370 | 371 | template 372 | vector_3t operator * (const vector_3t &lhs, const S& scale) 373 | { 374 | return vector_3t (lhs.x * scale, lhs.y * scale, lhs.z * scale); 375 | } 376 | 377 | template 378 | vector_4t operator * (const vector_4t &lhs, const S& scale) 379 | { 380 | return vector_4t (lhs.x * scale, lhs.y * scale, lhs.z * scale, lhs.w * scale); 381 | } 382 | 383 | ////////////////////////////////////////////////////////////////////////// 384 | // multiplication : scalar * vector 385 | template 386 | vector_2t operator * (const S& scale , const vector_2t &rhs) 387 | { 388 | return vector_2t (rhs.x * scale, rhs.y * scale); 389 | } 390 | 391 | template 392 | vector_3t operator * (const S& scale , const vector_3t &rhs) 393 | { 394 | return vector_3t (rhs.x * scale, rhs.y * scale, rhs.z * scale); 395 | } 396 | 397 | template 398 | vector_4t operator * (const S& scale , const vector_4t &rhs) 399 | { 400 | return vector_4t (rhs.x * scale, rhs.y * scale, rhs.z * scale, rhs.w * scale); 401 | } 402 | 403 | ////////////////////////////////////////////////////////////////////////// 404 | // division : vector / scalar 405 | template 406 | vector_2t operator / (const vector_2t &lhs, const S& scale) 407 | { 408 | BOOST_STATIC_ASSERT(boost::is_floating_point::value); 409 | Type scale_r = static_cast(1) / scale; 410 | return lhs * scale_r; 411 | } 412 | 413 | template 414 | vector_3t operator / (const vector_3t &lhs, const S& scale) 415 | { 416 | BOOST_STATIC_ASSERT(boost::is_floating_point::value); 417 | Type scale_r = static_cast(1) / scale; 418 | return lhs * scale_r; 419 | } 420 | 421 | template 422 | vector_4t operator / (const vector_4t &lhs, const S& scale) 423 | { 424 | BOOST_STATIC_ASSERT(boost::is_floating_point::value); 425 | Type scale_r = static_cast(1) / scale; 426 | return lhs * scale_r; 427 | } 428 | 429 | ////////////////////////////////////////////////////////////////////////// 430 | // piecewise multiplication : vector * vector 431 | template 432 | vector_2t operator * (const vector_2t &lhs, const vector_2t &rhs) 433 | { 434 | return vector_2t (lhs.x * rhs.x, lhs.y * rhs.y); 435 | } 436 | 437 | template 438 | vector_3t operator * (const vector_3t &lhs, const vector_3t &rhs) 439 | { 440 | return vector_3t (lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z); 441 | } 442 | 443 | template 444 | vector_4t operator * (const vector_4t &lhs, const vector_4t &rhs) 445 | { 446 | return vector_4t (lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); 447 | } 448 | 449 | ////////////////////////////////////////////////////////////////////////// 450 | // piecewise division : vector / vector 451 | template 452 | vector_2t operator / (const vector_2t &lhs, const vector_2t &rhs) 453 | { 454 | BOOST_STATIC_ASSERT(boost::is_floating_point::value); 455 | return vector_2t (lhs.x / rhs.x, lhs.y / rhs.y); 456 | } 457 | 458 | template 459 | vector_3t operator / (const vector_3t &lhs, const vector_3t &rhs) 460 | { 461 | BOOST_STATIC_ASSERT(boost::is_floating_point::value); 462 | return vector_3t (lhs.x / rhs.x, lhs.y / rhs.y, lhs.z / rhs.z); 463 | } 464 | 465 | template 466 | vector_4t operator / (const vector_4t &lhs, const vector_4t &rhs) 467 | { 468 | BOOST_STATIC_ASSERT(boost::is_floating_point::value); 469 | return vector_4t (lhs.x / rhs.x, lhs.y / rhs.y, lhs.z / rhs.z, lhs.w / rhs.w); 470 | } 471 | 472 | ////////////////////////////////////////////////////////////////////////// 473 | // normalization 474 | template 475 | vector_2t normalize(const vector_2t &operand) 476 | { 477 | vector_2t vec(operand); 478 | return vec.normalize(); 479 | } 480 | 481 | template 482 | vector_3t normalize(const vector_3t &operand) 483 | { 484 | vector_3t vec(operand); 485 | return vec.normalize(); 486 | } 487 | 488 | template 489 | vector_4t normalize(const vector_4t &operand) 490 | { 491 | vector_4t vec(operand); 492 | return vec.normalize(); 493 | } 494 | 495 | ////////////////////////////////////////////////////////////////////////// 496 | // dot product 497 | template 498 | Type dot(const vector_2t &lhs, const vector_2t &rhs) 499 | { 500 | return lhs.x * rhs.x + lhs.y * rhs.y; 501 | } 502 | 503 | template 504 | Type dot(const vector_3t &lhs, const vector_3t &rhs) 505 | { 506 | return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z; 507 | } 508 | 509 | template 510 | Type dot(const vector_4t &lhs, const vector_4t &rhs) 511 | { 512 | return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z + lhs.w * rhs.w; 513 | } 514 | 515 | ////////////////////////////////////////////////////////////////////////// 516 | // cross product 517 | template 518 | Type cross(const vector_2t &lhs, const vector_2t &rhs) 519 | { 520 | return lhs.x * rhs.y - lhs.y * rhs.x; 521 | } 522 | 523 | template 524 | vector_3t cross(const vector_3t &lhs, const vector_3t &rhs) 525 | { 526 | return vector_3t ( 527 | lhs.y * rhs.z - lhs.z * rhs.y, 528 | rhs.x * lhs.z - lhs.x * rhs.z, 529 | lhs.x * rhs.y - lhs.y * rhs.x); 530 | } 531 | } 532 | 533 | #include "vector_helper.hpp" 534 | 535 | #endif // _VECTOR_HPP_ -------------------------------------------------------------------------------- /src/ayw/vector_helper.hpp: -------------------------------------------------------------------------------- 1 | // file: vector_helper.hpp 2 | // path: AywProc\AywProc\core\include 3 | // purpose: define some macros to generate implementation codes for 4 | // swizzle operations 5 | // author: atyuwen 6 | // homepage: http://code.google.com/p/aywproc/ 7 | // 8 | // created: 2010/04/21 9 | // history: 10 | // 11 | ////////////////////////////////////////////////////////////////////// 12 | 13 | #ifndef MOUNT_VECTOR_HELPER_MACROS 14 | #define MOUNT_VECTOR_HELPER_MACROS 15 | 16 | #include 17 | 18 | #define SEQ_VECTOR_2T (x)(y) 19 | #define SEQ_VECTOR_3T (x)(y)(z) 20 | #define SEQ_VECTOR_4T (x)(y)(z)(w) 21 | 22 | #define IMPL_SWIZZLE_OP_TO_2T(_, seq) \ 23 | vector_2t BOOST_PP_SEQ_CAT(seq)() const \ 24 | { \ 25 | return vector_2t(BOOST_PP_SEQ_ENUM(seq)); \ 26 | } 27 | 28 | #define IMPL_SWIZZLE_OP_TO_3T(_, seq) \ 29 | vector_3t BOOST_PP_SEQ_CAT(seq)() const \ 30 | { \ 31 | return vector_3t(BOOST_PP_SEQ_ENUM(seq)); \ 32 | } 33 | 34 | #define IMPL_SWIZZLE_OP_TO_4T(_, seq) \ 35 | vector_4t BOOST_PP_SEQ_CAT(seq)() const \ 36 | { \ 37 | return vector_4t(BOOST_PP_SEQ_ENUM(seq)); \ 38 | } 39 | 40 | #define GEN_SWIZZLE_OP_2T_TO_2T() \ 41 | BOOST_PP_SEQ_FOR_EACH_PRODUCT(IMPL_SWIZZLE_OP_TO_2T, (SEQ_VECTOR_2T)(SEQ_VECTOR_2T)) 42 | 43 | #define GEN_SWIZZLE_OP_2T_TO_3T() \ 44 | BOOST_PP_SEQ_FOR_EACH_PRODUCT(IMPL_SWIZZLE_OP_TO_3T, (SEQ_VECTOR_2T)(SEQ_VECTOR_2T)(SEQ_VECTOR_2T)) 45 | 46 | #define GEN_SWIZZLE_OP_2T_TO_4T() \ 47 | BOOST_PP_SEQ_FOR_EACH_PRODUCT(IMPL_SWIZZLE_OP_TO_4T, (SEQ_VECTOR_2T)(SEQ_VECTOR_2T)(SEQ_VECTOR_2T)(SEQ_VECTOR_2T)) 48 | 49 | #define GEN_SWIZZLE_OP_3T_TO_2T() \ 50 | BOOST_PP_SEQ_FOR_EACH_PRODUCT(IMPL_SWIZZLE_OP_TO_2T, (SEQ_VECTOR_3T)(SEQ_VECTOR_3T)) 51 | 52 | #define GEN_SWIZZLE_OP_3T_TO_3T() \ 53 | BOOST_PP_SEQ_FOR_EACH_PRODUCT(IMPL_SWIZZLE_OP_TO_3T, (SEQ_VECTOR_3T)(SEQ_VECTOR_3T)(SEQ_VECTOR_3T)) 54 | 55 | #define GEN_SWIZZLE_OP_3T_TO_4T() \ 56 | BOOST_PP_SEQ_FOR_EACH_PRODUCT(IMPL_SWIZZLE_OP_TO_4T, (SEQ_VECTOR_3T)(SEQ_VECTOR_3T)(SEQ_VECTOR_3T)(SEQ_VECTOR_3T)) 57 | 58 | #define GEN_SWIZZLE_OP_4T_TO_2T() \ 59 | BOOST_PP_SEQ_FOR_EACH_PRODUCT(IMPL_SWIZZLE_OP_TO_2T, (SEQ_VECTOR_4T)(SEQ_VECTOR_4T)) 60 | 61 | #define GEN_SWIZZLE_OP_4T_TO_3T() \ 62 | BOOST_PP_SEQ_FOR_EACH_PRODUCT(IMPL_SWIZZLE_OP_TO_3T, (SEQ_VECTOR_4T)(SEQ_VECTOR_4T)(SEQ_VECTOR_4T)) 63 | 64 | #define GEN_SWIZZLE_OP_4T_TO_4T() \ 65 | BOOST_PP_SEQ_FOR_EACH_PRODUCT(IMPL_SWIZZLE_OP_TO_4T, (SEQ_VECTOR_4T)(SEQ_VECTOR_4T)(SEQ_VECTOR_4T)(SEQ_VECTOR_4T)) 66 | 67 | #define DECLARE_SWIZZLING_FOR_VECTOR_2T() \ 68 | GEN_SWIZZLE_OP_2T_TO_2T() \ 69 | GEN_SWIZZLE_OP_2T_TO_3T() \ 70 | GEN_SWIZZLE_OP_2T_TO_4T() 71 | 72 | #define DECLARE_SWIZZLING_FOR_VECTOR_3T() \ 73 | GEN_SWIZZLE_OP_3T_TO_2T() \ 74 | GEN_SWIZZLE_OP_3T_TO_3T() \ 75 | GEN_SWIZZLE_OP_3T_TO_4T() 76 | 77 | #define DECLARE_SWIZZLING_FOR_VECTOR_4T() \ 78 | GEN_SWIZZLE_OP_4T_TO_2T() \ 79 | GEN_SWIZZLE_OP_4T_TO_3T() \ 80 | GEN_SWIZZLE_OP_4T_TO_4T() 81 | 82 | #else // unmount these macros 83 | 84 | #undef MOUNT_VECTOR_HELPER_MACROS 85 | 86 | #undef SEQ_VECTOR_2T 87 | #undef SEQ_VECTOR_3T 88 | #undef SEQ_VECTOR_4T 89 | 90 | #undef IMPL_SWIZZLE_OP_TO_2T 91 | #undef IMPL_SWIZZLE_OP_TO_3T 92 | #undef IMPL_SWIZZLE_OP_TO_4T 93 | 94 | #undef GEN_SWIZZLE_OP_2T_TO_2T 95 | #undef GEN_SWIZZLE_OP_2T_TO_3T 96 | #undef GEN_SWIZZLE_OP_2T_TO_4T 97 | #undef GEN_SWIZZLE_OP_3T_TO_2T 98 | #undef GEN_SWIZZLE_OP_3T_TO_3T 99 | #undef GEN_SWIZZLE_OP_3T_TO_4T 100 | #undef GEN_SWIZZLE_OP_4T_TO_2T 101 | #undef GEN_SWIZZLE_OP_4T_TO_3T 102 | #undef GEN_SWIZZLE_OP_4T_TO_4T 103 | 104 | #undef DECLARE_SWIZZLING_FOR_VECTOR_2T 105 | #undef DECLARE_SWIZZLING_FOR_VECTOR_3T 106 | #undef DECLARE_SWIZZLING_FOR_VECTOR_4T 107 | 108 | #endif -------------------------------------------------------------------------------- /src/common.cpp: -------------------------------------------------------------------------------- 1 | #include "common.hpp" 2 | 3 | void MessageBoxf(tstring format, ...) 4 | { 5 | va_list args; 6 | TCHAR msg[1024]; 7 | va_start(args, format); 8 | wvsprintf(msg, format.c_str(), args); 9 | va_end(args); 10 | MessageBox(NULL, msg, TEXT("debug"), MB_OK); 11 | } 12 | -------------------------------------------------------------------------------- /src/common.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _COMMON_HPP_INCLUDED_ 2 | #define _COMMON_HPP_INCLUDED_ 3 | 4 | #define NOMINMAX 5 | #define WIN32_LEAN_AND_MEAN 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #pragma comment(lib, "d3d11.lib") 20 | #pragma comment(lib, "d3d10_1.lib") 21 | #pragma comment(lib, "d3dx11.lib") 22 | #pragma comment(lib, "d3dx10.lib") 23 | #pragma comment(lib, "dxgi.lib") 24 | #pragma comment(lib, "d2d1.lib") 25 | #pragma comment(lib, "dwrite.lib") 26 | 27 | #include "ayw/vector.hpp" 28 | using Ayw::float2; 29 | using Ayw::float3; 30 | using Ayw::float4; 31 | 32 | #include 33 | #include 34 | 35 | #ifdef UNICODE 36 | #define tchar wchar_t 37 | #define tstring std::wstring 38 | #else 39 | #define tchar char 40 | #define tstring std::string 41 | #endif 42 | 43 | template 44 | DestType lexical_cast_no_exception(const SrcType& arg) 45 | { 46 | try 47 | { 48 | return boost::lexical_cast(arg); 49 | } 50 | catch (boost::bad_lexical_cast &) 51 | { 52 | return DestType(); 53 | } 54 | } 55 | 56 | #define to_string(arg) lexical_cast_no_exception(arg) 57 | #define to_wstring(arg) lexical_cast_no_exception(arg) 58 | #define to_tstring(arg) lexical_cast_no_exception(arg) 59 | 60 | void MessageBoxf(tstring format, ...); 61 | 62 | #define SAFE_RELEASE(p) if (p != NULL) {p->Release(); p = NULL;} 63 | 64 | #endif // _COMMON_HPP_INCLUDED_ -------------------------------------------------------------------------------- /src/d3d_app.cpp: -------------------------------------------------------------------------------- 1 | #include "common.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include "ayw/vector.hpp" 7 | #include "ayw/constant.hpp" 8 | #include "d3d_app.hpp" 9 | using namespace Ayw; 10 | 11 | const tstring g_app_title = TEXT("LiVE HLSL"); 12 | 13 | const int g_aa_sample = 4; 14 | const float g_aa_warm_time = 0.2f; 15 | 16 | struct ShaderParameters 17 | { 18 | float4 time; // time related parameters 19 | float4 view; // (view width, view height, 1 / width, 1 / height) 20 | float4 freq; // the short time FFT of the background music 21 | float4 mpos; // (mouse.x, mouse.y, mouse.wheel, 0) 22 | }; 23 | 24 | ShaderParameters g_shader_param; 25 | 26 | ////////////////////////////////////////////////////////////////////////// 27 | // static accessors 28 | ////////////////////////////////////////////////////////////////////////// 29 | D3DApp g_app; 30 | 31 | D3DApp* D3DApp::GetApp() 32 | { 33 | return &g_app; 34 | } 35 | 36 | ID3D11Device* D3DApp::GetD3D11Device() 37 | { 38 | return g_app.m_d3d11_device; 39 | } 40 | 41 | ID3D11DeviceContext* D3DApp::GetD3D11DeviceContext() 42 | { 43 | return g_app.m_d3d11_device_context; 44 | } 45 | 46 | IDWriteFactory* D3DApp::GetDWriteFactory() 47 | { 48 | return g_app.m_dwrite_factory; 49 | } 50 | 51 | HRTimer* D3DApp::GetTimer() 52 | { 53 | return &g_app.m_timer; 54 | } 55 | 56 | PostProcessPtr D3DApp::GetPostProcess() 57 | { 58 | return g_app.m_custom_pp; 59 | } 60 | 61 | SoundPlayerPtr D3DApp::GetSoundPlayer() 62 | { 63 | return g_app.m_sound_player; 64 | } 65 | 66 | ////////////////////////////////////////////////////////////////////////// 67 | // constructor / destructor 68 | ////////////////////////////////////////////////////////////////////////// 69 | D3DApp::D3DApp() 70 | : m_hinstance(NULL) 71 | , m_hwnd(NULL) 72 | , m_swap_chain(NULL) 73 | , m_d3d11_device(NULL) 74 | , m_d3d11_device_context(NULL) 75 | , m_depthstencil_buffer(NULL) 76 | , m_back_buffer_rtv(NULL) 77 | , m_depthstencil_view(NULL) 78 | , m_back_buffer(NULL) 79 | , m_d3d10_device(NULL) 80 | , m_dwrite_factory(NULL) 81 | , m_d2d_rendertarget(NULL) 82 | , m_d2d_texture(NULL) 83 | , m_shared_texture(NULL) 84 | , m_keyed_mutex11(NULL) 85 | , m_keyed_mutex10(NULL) 86 | , m_parameter_buffer(NULL) 87 | , m_jitter_buffer(NULL) 88 | , m_interleave_buffer(NULL) 89 | , m_custom_texture(NULL) 90 | , m_hide_editor(false) 91 | , m_mouse_wheel(0) 92 | , m_half_resolution(false) 93 | , m_aa_enabled(false) 94 | , m_aa_control_time(0) 95 | , m_aa_frame_idx(false) 96 | { 97 | ZeroMemory(m_offscreen_textures, sizeof(m_offscreen_textures)); 98 | ZeroMemory(m_offscreen_srvs, sizeof(m_offscreen_srvs)); 99 | ZeroMemory(m_offscreen_rtvs, sizeof(m_offscreen_rtvs)); 100 | } 101 | 102 | D3DApp::~D3DApp() 103 | { 104 | SAFE_RELEASE(m_interleave_buffer); 105 | SAFE_RELEASE(m_jitter_buffer); 106 | SAFE_RELEASE(m_parameter_buffer); 107 | SAFE_RELEASE(m_custom_texture); 108 | 109 | for (int i = 0; i != ARRAYSIZE(m_offscreen_textures); ++i) 110 | { 111 | SAFE_RELEASE(m_offscreen_rtvs[i]); 112 | SAFE_RELEASE(m_offscreen_srvs[i]); 113 | SAFE_RELEASE(m_offscreen_textures[i]); 114 | } 115 | 116 | SAFE_RELEASE(m_depthstencil_buffer); 117 | SAFE_RELEASE(m_back_buffer_rtv); 118 | SAFE_RELEASE(m_depthstencil_view); 119 | SAFE_RELEASE(m_back_buffer); 120 | 121 | SAFE_RELEASE(m_dwrite_factory); 122 | SAFE_RELEASE(m_d2d_rendertarget); 123 | SAFE_RELEASE(m_d2d_texture); 124 | 125 | SAFE_RELEASE(m_shared_texture); 126 | SAFE_RELEASE(m_keyed_mutex11); 127 | SAFE_RELEASE(m_keyed_mutex10); 128 | 129 | SAFE_RELEASE(m_d3d11_device_context); 130 | SAFE_RELEASE(m_d3d10_device); 131 | SAFE_RELEASE(m_d3d11_device); 132 | SAFE_RELEASE(m_swap_chain); 133 | } 134 | 135 | ////////////////////////////////////////////////////////////////////////// 136 | // public interfaces 137 | ////////////////////////////////////////////////////////////////////////// 138 | bool D3DApp::Initialize(HINSTANCE hinstance, int width, int height) 139 | { 140 | m_hinstance = hinstance; 141 | m_width = width; 142 | m_height = height; 143 | 144 | if (!InitializeWindow()) 145 | { 146 | MessageBox(NULL, TEXT("Error creating window"), TEXT("Error"), MB_OK | MB_ICONERROR); 147 | return false; 148 | } 149 | if (!InitializeD3D()) 150 | { 151 | MessageBox(NULL, TEXT("Error initializing D3D"), TEXT("Error"), MB_OK | MB_ICONERROR); 152 | return false; 153 | } 154 | if (!InitializeScene()) 155 | { 156 | MessageBox(NULL, TEXT("Error initializing scene"), TEXT("Error"), MB_OK | MB_ICONERROR); 157 | return false; 158 | } 159 | if (!InitializeShaders()) 160 | { 161 | MessageBox(NULL, TEXT("Error initializing shaders"), TEXT("Error"), MB_OK | MB_ICONERROR); 162 | return false; 163 | } 164 | 165 | m_text_editor = TextEditorPtr(new TextEditor); 166 | if (!m_text_editor->Initialize(m_d2d_rendertarget)) 167 | { 168 | MessageBox(NULL, TEXT("Error initializing text editor"), TEXT("Error"), MB_OK | MB_ICONERROR); 169 | return false; 170 | } 171 | 172 | m_sound_player = SoundPlayerPtr(new SoundPlayer); 173 | if (!m_sound_player->Initialize()) 174 | { 175 | MessageBox(NULL, TEXT("Error initializing sound player"), TEXT("Error"), MB_OK | MB_ICONERROR); 176 | return false; 177 | } 178 | m_sound_player->PlaySound(TEXT("media/bgm.mp3"), true); 179 | m_sound_player->SetMute(true); 180 | 181 | m_timer.Start(); 182 | RegisterTimerEvents(); 183 | return true; 184 | } 185 | 186 | int D3DApp::Run() 187 | { 188 | MSG msg; 189 | ZeroMemory(&msg, sizeof(msg)); 190 | while (true) 191 | { 192 | if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 193 | { 194 | if (msg.message == WM_QUIT) break; 195 | TranslateMessage(&msg); 196 | DispatchMessage(&msg); 197 | } 198 | else 199 | { 200 | m_timer.SyncTick(1.0f / 60); 201 | UpdateScene(m_timer.GetDeltaTime()); 202 | RenderScene(); 203 | } 204 | } 205 | return msg.wParam; 206 | } 207 | 208 | void D3DApp::Destroy() 209 | { 210 | 211 | } 212 | 213 | int D3DApp::GetWidth() const 214 | { 215 | return m_width; 216 | } 217 | 218 | int D3DApp::GetHeight() const 219 | { 220 | return m_height; 221 | } 222 | 223 | float2 D3DApp::GetMousePos(int from_event /*= 0*/) const 224 | { 225 | if (from_event == 0) return m_mouse_pos; 226 | 227 | if (m_recorded_mouse_pos.find(from_event) != m_recorded_mouse_pos.end()) 228 | { 229 | return m_mouse_pos - m_recorded_mouse_pos.at(from_event); 230 | } 231 | return float2(0, 0); 232 | } 233 | 234 | float D3DApp::GetMouseWheel() const 235 | { 236 | return m_mouse_wheel; 237 | } 238 | 239 | ////////////////////////////////////////////////////////////////////////// 240 | // window procedure 241 | ////////////////////////////////////////////////////////////////////////// 242 | LRESULT CALLBACK D3DApp::WindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) 243 | { 244 | D3DApp* app = D3DApp::GetApp(); 245 | TextEditorPtr editor = app->m_text_editor; 246 | switch (message) 247 | { 248 | case WM_DESTROY: 249 | PostQuitMessage(0); 250 | return 0; 251 | case WM_KEYDOWN: 252 | { 253 | bool held_control = (GetKeyState(VK_CONTROL) & 0x80) != 0; 254 | bool held_shift = (GetKeyState(VK_SHIFT) & 0x80) != 0; 255 | UINT key_code = static_cast(wparam); 256 | 257 | if (key_code == VK_F1) 258 | { 259 | app->m_hide_editor = !app->m_hide_editor; 260 | return 0; 261 | } 262 | else if (key_code == VK_F2) 263 | { 264 | if (app->m_sound_player) 265 | { 266 | bool mute = app->m_sound_player->GetMute(); 267 | app->m_sound_player->SetMute(!mute); 268 | } 269 | return 0; 270 | } 271 | else if (key_code == VK_F3) 272 | { 273 | app->m_aa_enabled = !app->m_aa_enabled; 274 | app->m_aa_control_time = 0; 275 | return 0; 276 | } 277 | else if (key_code == VK_F4) 278 | { 279 | app->m_half_resolution = !app->m_half_resolution; 280 | app->m_aa_control_time = 0; 281 | return 0; 282 | } 283 | else if (key_code == VK_OEM_PLUS && held_control) 284 | { 285 | if (app->m_sound_player) app->m_sound_player->ChangeVolume(0.1f); 286 | return 0; 287 | } 288 | else if (key_code == VK_OEM_MINUS && held_control) 289 | { 290 | if (app->m_sound_player) app->m_sound_player->ChangeVolume(-0.1f); 291 | return 0; 292 | } 293 | else if (key_code == 'N' && held_control) 294 | { 295 | if (editor) editor->NewFile(); 296 | app->m_recorded_mouse_pos.clear(); 297 | app->m_mouse_wheel = 0; 298 | app->m_hide_editor = false; 299 | g_shader_param.mpos = float4(0, 0, 0, 0); 300 | app->m_aa_control_time = 0; 301 | return 0; 302 | } 303 | else if (key_code == 'O' && held_control) 304 | { 305 | if (editor) editor->OpenFile(); 306 | app->m_recorded_mouse_pos.clear(); 307 | app->m_mouse_wheel = 0; 308 | g_shader_param.mpos = float4(0, 0, 0, 0); 309 | app->m_aa_control_time = 0; 310 | return 0; 311 | } 312 | else if (key_code == 'S' && held_control) 313 | { 314 | if (editor) editor->SaveFile(held_shift); 315 | app->m_aa_control_time = 0; 316 | return 0; 317 | } 318 | break; 319 | } 320 | 321 | case WM_LBUTTONDOWN: 322 | case WM_RBUTTONDOWN: 323 | case WM_MBUTTONDOWN: 324 | app->m_recorded_mouse_pos[message] = float2( 325 | static_cast(GET_X_LPARAM(lparam)), static_cast(GET_Y_LPARAM(lparam))); 326 | break; 327 | 328 | case WM_LBUTTONUP: 329 | app->m_recorded_mouse_pos.erase(WM_LBUTTONDOWN); 330 | break; 331 | case WM_RBUTTONUP: 332 | app->m_recorded_mouse_pos.erase(WM_RBUTTONDOWN); 333 | break; 334 | case WM_MBUTTONUP: 335 | app->m_recorded_mouse_pos.erase(WM_MBUTTONDOWN); 336 | app->m_mouse_wheel = 0; 337 | break; 338 | 339 | case WM_MOUSEMOVE: 340 | app->m_mouse_pos = float2( 341 | static_cast(GET_X_LPARAM(lparam)), static_cast(GET_Y_LPARAM(lparam))); 342 | break; 343 | 344 | case WM_MOUSEWHEEL: 345 | app->m_mouse_wheel += GET_WHEEL_DELTA_WPARAM(wparam) / static_cast(WHEEL_DELTA); 346 | break;; 347 | } 348 | 349 | if (editor && !app->m_hide_editor) 350 | { 351 | if (editor->HandleWindowMessage(hwnd, message, wparam, lparam)) 352 | { 353 | return 0; 354 | } 355 | } 356 | 357 | return DefWindowProc(hwnd, message, wparam, lparam); 358 | } 359 | 360 | ////////////////////////////////////////////////////////////////////////// 361 | // timer events procedure 362 | ////////////////////////////////////////////////////////////////////////// 363 | void D3DApp::RegisterTimerEvents() 364 | { 365 | m_timer.AddEvent(0.1f, boost::bind(&D3DApp::TimerEventsProc, this, _1, _2), TEXT("update_title")); 366 | } 367 | 368 | void D3DApp::TimerEventsProc(int cnt, const tstring& tag) 369 | { 370 | if (tag == TEXT("update_title")) 371 | { 372 | float delta_time = m_timer.GetDeltaTime(); 373 | float fps = 1.0f / std::max(delta_time, Ayw::c_eps); 374 | float cpu_time = m_timer.GetCPUDeltaTime() * 1000; 375 | float gpu_time = m_timer.GetGPUDeltaTime() * 1000; 376 | 377 | char title[512] = {0}; 378 | sprintf_s(title, 379 | TEXT("%s [ ShowEditor(F1):%s | BgMusic(F2):%s | Anti-Aliasing(F3):%s | Half-Res(F4):%s ] [ FPS:%.1f | CPU:%.1fms | GPU:%.1fms ]"), 380 | g_app_title.c_str(), 381 | !m_hide_editor ? TEXT("on") : TEXT("off"), 382 | !m_sound_player->GetMute() ? TEXT("on") : TEXT("off"), 383 | m_aa_enabled ? TEXT("on") : TEXT("off"), 384 | m_half_resolution ? TEXT("on") : TEXT("off"), 385 | fps, 386 | cpu_time, 387 | gpu_time); 388 | 389 | SetWindowText(m_hwnd, title); 390 | } 391 | } 392 | 393 | ////////////////////////////////////////////////////////////////////////// 394 | // private subroutines 395 | ////////////////////////////////////////////////////////////////////////// 396 | bool D3DApp::InitializeWindow() 397 | { 398 | WNDCLASSEX wc; 399 | tstring wnd_class = TEXT("aywd3dapp"); 400 | wc.cbSize = sizeof(WNDCLASSEX); 401 | wc.style = CS_HREDRAW | CS_VREDRAW; 402 | wc.lpfnWndProc = D3DApp::WindowProc; 403 | wc.cbClsExtra = NULL; 404 | wc.cbWndExtra = NULL; 405 | wc.hInstance = m_hinstance; 406 | wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); 407 | wc.hCursor = LoadCursor(NULL, IDC_ARROW); 408 | wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 2); 409 | wc.lpszMenuName = NULL; 410 | wc.lpszClassName = wnd_class.c_str(); 411 | wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); 412 | if (!RegisterClassEx(&wc)) 413 | { 414 | return false; 415 | } 416 | 417 | RECT rect = {0, 0, m_width, m_height}; 418 | DWORD wnd_style = WS_OVERLAPPEDWINDOW & (~(WS_SIZEBOX | WS_MAXIMIZEBOX | WS_MINIMIZEBOX)); 419 | AdjustWindowRect(&rect, wnd_style, FALSE); 420 | m_hwnd = CreateWindowEx( 421 | NULL, 422 | wnd_class.c_str(), 423 | g_app_title.c_str(), 424 | wnd_style, 425 | CW_USEDEFAULT, 426 | CW_USEDEFAULT, 427 | rect.right - rect.left, 428 | rect.bottom - rect.top, 429 | NULL, 430 | NULL, 431 | m_hinstance, 432 | this); 433 | 434 | if (m_hwnd == NULL) 435 | { 436 | return false; 437 | } 438 | 439 | ShowWindow(m_hwnd, SW_SHOWNORMAL); 440 | UpdateWindow(m_hwnd); 441 | 442 | GetClientRect(m_hwnd, &rect); 443 | m_width = rect.right - rect.left; 444 | m_height = rect.bottom - rect.top; 445 | return true; 446 | } 447 | 448 | bool D3DApp::InitializeD3D() 449 | { 450 | // describe our SwapChain Buffer 451 | DXGI_MODE_DESC mode_desc; 452 | ZeroMemory(&mode_desc, sizeof(DXGI_MODE_DESC)); 453 | mode_desc.Width = m_width; 454 | mode_desc.Height = m_height; 455 | mode_desc.RefreshRate.Numerator = 60; 456 | mode_desc.RefreshRate.Denominator = 1; 457 | mode_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; 458 | mode_desc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; 459 | mode_desc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; 460 | 461 | // describe our SwapChain 462 | DXGI_SWAP_CHAIN_DESC swapchain_desc; 463 | ZeroMemory(&swapchain_desc, sizeof(DXGI_SWAP_CHAIN_DESC)); 464 | swapchain_desc.BufferDesc = mode_desc; 465 | swapchain_desc.SampleDesc.Count = 1; 466 | swapchain_desc.SampleDesc.Quality = 0; 467 | swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 468 | swapchain_desc.BufferCount = 1; 469 | swapchain_desc.OutputWindow = m_hwnd; 470 | swapchain_desc.Windowed = TRUE; 471 | swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; 472 | 473 | // create DXGI factory to enumerate adapters 474 | IDXGIFactory1 *dxgi_factory; 475 | HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&dxgi_factory); 476 | 477 | // use the first adapter 478 | IDXGIAdapter1 *adapter; 479 | hr = dxgi_factory->EnumAdapters1(0, &adapter); 480 | dxgi_factory->Release(); 481 | 482 | // create our Direct3D 11 Device and SwapChain 483 | hr = D3D11CreateDeviceAndSwapChain(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, D3D11_CREATE_DEVICE_BGRA_SUPPORT, 484 | NULL, NULL, D3D11_SDK_VERSION, &swapchain_desc, &m_swap_chain, &m_d3d11_device, NULL, &m_d3d11_device_context); 485 | 486 | // initialize Direct2D, Direct3D 10.1, DirectWrite 487 | InitializeDWrite(adapter); 488 | 489 | // release the Adapter interface 490 | adapter->Release(); 491 | 492 | // create our BackBuffer and Render Target 493 | hr = m_swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&m_back_buffer); 494 | hr = m_d3d11_device->CreateRenderTargetView(m_back_buffer, NULL, &m_back_buffer_rtv); 495 | 496 | // describe our Depth/Stencil Buffer 497 | D3D11_TEXTURE2D_DESC depthstencil_desc; 498 | depthstencil_desc.Width = m_width; 499 | depthstencil_desc.Height = m_height; 500 | depthstencil_desc.MipLevels = 1; 501 | depthstencil_desc.ArraySize = 1; 502 | depthstencil_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; 503 | depthstencil_desc.SampleDesc.Count = 1; 504 | depthstencil_desc.SampleDesc.Quality = 0; 505 | depthstencil_desc.Usage = D3D11_USAGE_DEFAULT; 506 | depthstencil_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; 507 | depthstencil_desc.CPUAccessFlags = 0; 508 | depthstencil_desc.MiscFlags = 0; 509 | 510 | // create the Depth/Stencil View 511 | m_d3d11_device->CreateTexture2D(&depthstencil_desc, NULL, &m_depthstencil_buffer); 512 | m_d3d11_device->CreateDepthStencilView(m_depthstencil_buffer, NULL, &m_depthstencil_view); 513 | 514 | // set render target views and depth stencil view 515 | m_d3d11_device_context->OMSetRenderTargets(1, &m_back_buffer_rtv, m_depthstencil_view); 516 | 517 | // create a shader resource review from the texture D2D will render to 518 | hr = m_d3d11_device->CreateShaderResourceView(m_shared_texture, NULL, &m_d2d_texture); 519 | 520 | // create off-screen textures 521 | CD3D11_TEXTURE2D_DESC offscreen_tex_desc(DXGI_FORMAT_R16G16B16A16_FLOAT, m_width, m_height); 522 | offscreen_tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; 523 | offscreen_tex_desc.MipLevels = 1; 524 | for (int i = 0; i != ARRAYSIZE(m_offscreen_textures); ++i) 525 | { 526 | m_d3d11_device->CreateTexture2D(&offscreen_tex_desc, NULL, &m_offscreen_textures[i]); 527 | m_d3d11_device->CreateShaderResourceView(m_offscreen_textures[i], NULL, &m_offscreen_srvs[i]); 528 | m_d3d11_device->CreateRenderTargetView(m_offscreen_textures[i], NULL, &m_offscreen_rtvs[i]); 529 | } 530 | 531 | // create a constant buffer 532 | D3D11_BUFFER_DESC buffer_desc; 533 | ZeroMemory(&buffer_desc, sizeof(D3D11_BUFFER_DESC)); 534 | buffer_desc.Usage = D3D11_USAGE_DYNAMIC; 535 | buffer_desc.ByteWidth = sizeof(ShaderParameters); 536 | buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; 537 | buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 538 | buffer_desc.MiscFlags = 0; 539 | hr = m_d3d11_device->CreateBuffer(&buffer_desc, NULL, &m_parameter_buffer); 540 | 541 | buffer_desc.ByteWidth = sizeof(float4); 542 | hr = m_d3d11_device->CreateBuffer(&buffer_desc, NULL, &m_jitter_buffer); 543 | hr = m_d3d11_device->CreateBuffer(&buffer_desc, NULL, &m_interleave_buffer); 544 | 545 | // create a texture from file 546 | D3DX11CreateShaderResourceViewFromFile(m_d3d11_device, TEXT("media/tex.bmp"), NULL, NULL, &m_custom_texture, &hr); 547 | 548 | return true; 549 | } 550 | 551 | void D3DApp::SetViewport(int width, int height) 552 | { 553 | // set view port 554 | D3D11_VIEWPORT view_port; 555 | view_port.Width = static_cast(width); 556 | view_port.Height = static_cast(height); 557 | view_port.MinDepth = 0.0f; 558 | view_port.MaxDepth = 1.0f; 559 | view_port.TopLeftX = 0; 560 | view_port.TopLeftY = 0; 561 | m_d3d11_device_context->RSSetViewports(1, &view_port); 562 | } 563 | 564 | bool D3DApp::InitializeDWrite(IDXGIAdapter1* adapter) 565 | { 566 | // create our Direc3D 10.1 Device 567 | HRESULT hr = D3D10CreateDevice1(adapter, D3D10_DRIVER_TYPE_HARDWARE, NULL,D3D10_CREATE_DEVICE_BGRA_SUPPORT, 568 | D3D10_FEATURE_LEVEL_9_3, D3D10_1_SDK_VERSION, &m_d3d10_device); 569 | 570 | // create Shared Texture that Direct3D 10.1 will render on 571 | D3D11_TEXTURE2D_DESC shared_tex_desc; 572 | ZeroMemory(&shared_tex_desc, sizeof(shared_tex_desc)); 573 | shared_tex_desc.Width = m_width; 574 | shared_tex_desc.Height = m_height; 575 | shared_tex_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; 576 | shared_tex_desc.MipLevels = 1; 577 | shared_tex_desc.ArraySize = 1; 578 | shared_tex_desc.SampleDesc.Count = 1; 579 | shared_tex_desc.Usage = D3D11_USAGE_DEFAULT; 580 | shared_tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; 581 | shared_tex_desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX; 582 | hr = m_d3d11_device->CreateTexture2D(&shared_tex_desc, NULL, &m_shared_texture); 583 | 584 | // get the keyed mutex for the shared texture (for D3D11) 585 | hr = m_shared_texture->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)&m_keyed_mutex11); 586 | 587 | // get the shared handle needed to open the shared texture in D3D10.1 588 | IDXGIResource *shared_resource10; 589 | HANDLE shared_handle10; 590 | hr = m_shared_texture->QueryInterface(__uuidof(IDXGIResource), (void**)&shared_resource10); 591 | hr = shared_resource10->GetSharedHandle(&shared_handle10); 592 | shared_resource10->Release(); 593 | 594 | // open the surface for the shared texture in D3D10.1 595 | IDXGISurface1 *shared_surface10; 596 | hr = m_d3d10_device->OpenSharedResource(shared_handle10, __uuidof(IDXGISurface1), (void**)(&shared_surface10)); 597 | hr = shared_surface10->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)&m_keyed_mutex10); 598 | 599 | // create D2D factory 600 | ID2D1Factory *d2d_factory; 601 | hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory), (void**)&d2d_factory); 602 | D2D1_RENDER_TARGET_PROPERTIES rendertaget_properties; 603 | ZeroMemory(&rendertaget_properties, sizeof(rendertaget_properties)); 604 | rendertaget_properties.type = D2D1_RENDER_TARGET_TYPE_HARDWARE; 605 | rendertaget_properties.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED); 606 | hr = d2d_factory->CreateDxgiSurfaceRenderTarget(shared_surface10, &rendertaget_properties, &m_d2d_rendertarget); 607 | shared_surface10->Release(); 608 | d2d_factory->Release(); 609 | 610 | // DirectWrite 611 | hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), 612 | reinterpret_cast(&m_dwrite_factory)); 613 | 614 | m_d3d10_device->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_POINTLIST); 615 | return true; 616 | } 617 | 618 | bool D3DApp::InitializeScene() 619 | { 620 | return true; 621 | } 622 | 623 | bool D3DApp::InitializeShaders() 624 | { 625 | m_custom_pp = PostProcessPtr(new PostProcess); 626 | 627 | m_combine_pp = PostProcessPtr(new PostProcess); 628 | if (!m_combine_pp->LoadPixelShaderFromFile(TEXT("pp_combine.hlsl"), TEXT("ps_main"))) 629 | { 630 | return false; 631 | } 632 | 633 | m_resolve_pp = PostProcessPtr(new PostProcess(true)); 634 | if (!m_resolve_pp->LoadPixelShaderFromFile(TEXT("pp_resolve.hlsl"), TEXT("resolve"))) 635 | { 636 | return false; 637 | } 638 | 639 | m_halfres_resolve_pp = PostProcessPtr(new PostProcess(true)); 640 | if (!m_halfres_resolve_pp->LoadPixelShaderFromFile(TEXT("pp_resolve.hlsl"), TEXT("halfres_resolve"))) 641 | { 642 | return false; 643 | } 644 | 645 | m_halfres_copy_pp = PostProcessPtr(new PostProcess(true)); 646 | if (!m_halfres_copy_pp->LoadPixelShaderFromFile(TEXT("pp_resolve.hlsl"), TEXT("halfres_copy"))) 647 | { 648 | return false; 649 | } 650 | 651 | return true; 652 | } 653 | 654 | void D3DApp::UpdateScene(float delta_time) 655 | { 656 | m_text_editor->Update(delta_time); 657 | m_sound_player->Update(delta_time); 658 | 659 | // get sound spectrum 660 | std::vector spectrum; 661 | m_sound_player->GetSpectrum(1024, spectrum); 662 | float low_freq = *std::max_element(spectrum.begin(), spectrum.begin() + 16 ); 663 | float mid_low_freq = *std::max_element(spectrum.begin() + 16, spectrum.begin() + 64 ); 664 | float mid_high_freq = *std::max_element(spectrum.begin() + 64, spectrum.begin() + 128); 665 | float high_freq = *std::max_element(spectrum.begin() + 128, spectrum.begin() + 256); 666 | float4 freq(low_freq, mid_low_freq, mid_high_freq, high_freq); 667 | 668 | // mouse interaction 669 | float2 mouse_pos = GetMousePos(WM_RBUTTONDOWN); 670 | float mouse_wheel = GetMouseWheel(); 671 | float4 mpos(mouse_pos.x, mouse_pos.y, mouse_wheel, 0); 672 | float4 delta = mpos - g_shader_param.mpos; 673 | if (m_aa_enabled) 674 | { 675 | if (delta.length_sqr() > 1e-3) m_aa_control_time = 0; 676 | else m_aa_control_time += std::min(delta_time, g_aa_warm_time * 0.5f); 677 | } 678 | 679 | // update shader parameters 680 | const float smooth_factor = 0.8f; 681 | g_shader_param.time = float4(m_timer.GetTime(), 0, 0, 0); 682 | g_shader_param.view = float4(static_cast(m_width), static_cast(m_height), 1.0f / m_width, 1.0f / m_height); 683 | g_shader_param.freq = g_shader_param.freq * smooth_factor + freq * (1 - smooth_factor); 684 | g_shader_param.mpos = g_shader_param.mpos * smooth_factor + mpos * (1 - smooth_factor); 685 | } 686 | 687 | void D3DApp::RenderScene() 688 | { 689 | m_timer.BeginGPUTimming(); 690 | SetViewport(m_width, m_height); 691 | m_d3d11_device_context->ClearRenderTargetView(m_back_buffer_rtv, float4(0, 0, 0, 1).ptr()); 692 | m_d3d11_device_context->ClearDepthStencilView(m_depthstencil_view, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 255); 693 | 694 | bool enable_aa = false; 695 | if (m_aa_enabled && m_aa_control_time > g_aa_warm_time) 696 | { 697 | enable_aa = true; 698 | static std::vector perm(g_aa_sample * g_aa_sample); 699 | if (m_aa_frame_idx == 0) 700 | { 701 | for (int i = 0; i != perm.size(); ++i) perm[i] = i; 702 | std::random_shuffle(perm.begin(), perm.end()); 703 | } 704 | 705 | // stratified sampling 706 | int sample = perm[m_aa_frame_idx]; 707 | float2 jitter(static_cast(sample % g_aa_sample), static_cast(sample / g_aa_sample)); 708 | float2 offset = float2(g_aa_sample / 2.0f, g_aa_sample / 2.0f); 709 | offset += float2(static_cast(rand()), static_cast(rand())) / RAND_MAX;; 710 | jitter = (jitter - offset) / float2(static_cast(m_width * g_aa_sample), static_cast(m_height * g_aa_sample)); 711 | if (m_half_resolution) 712 | { 713 | jitter = jitter * 2.0f; 714 | float interleave_x = static_cast(sample % g_aa_sample >= (g_aa_sample / 2)); 715 | float interleave_y = static_cast(sample / g_aa_sample >= (g_aa_sample / 2)); 716 | UpdateConstantBuffer(m_interleave_buffer, float4(interleave_x, interleave_y, 0, 0)); 717 | } 718 | 719 | UpdateConstantBuffer(m_jitter_buffer, float4(jitter.x, jitter.y, 0, 0)); 720 | m_d3d11_device_context->VSSetConstantBuffers(0, 1, &m_jitter_buffer); 721 | 722 | m_aa_frame_idx = (m_aa_frame_idx + 1) % (g_aa_sample * g_aa_sample); 723 | } 724 | else 725 | { 726 | m_aa_frame_idx = 0; 727 | } 728 | 729 | if (m_half_resolution) SetViewport(m_width / 2, m_height / 2); 730 | { 731 | UpdateConstantBuffer(m_parameter_buffer, g_shader_param); 732 | m_custom_pp->SetParameters(0, m_parameter_buffer); 733 | if (m_custom_texture != NULL) 734 | { 735 | m_custom_pp->InputPin(0, m_custom_texture); 736 | } 737 | m_custom_pp->OutputPin(0, m_offscreen_rtvs[enable_aa | m_half_resolution]); 738 | m_custom_pp->Apply(); 739 | } 740 | if (m_half_resolution) SetViewport(m_width, m_height); 741 | 742 | if (enable_aa) 743 | { 744 | UpdateConstantBuffer(m_jitter_buffer, float4(0, 0, 0, 0)); 745 | m_d3d11_device_context->VSSetConstantBuffers(0, 1, &m_jitter_buffer); 746 | 747 | if (m_half_resolution) 748 | { 749 | m_halfres_resolve_pp->SetParameters(0, m_interleave_buffer); 750 | m_halfres_resolve_pp->InputPin(0, m_offscreen_srvs[1]); 751 | m_halfres_resolve_pp->OutputPin(0, m_offscreen_rtvs[0]); 752 | m_halfres_resolve_pp->Apply(); 753 | } 754 | else 755 | { 756 | m_resolve_pp->InputPin(0, m_offscreen_srvs[1]); 757 | m_resolve_pp->OutputPin(0, m_offscreen_rtvs[0]); 758 | m_resolve_pp->Apply(); 759 | } 760 | } 761 | else if (m_half_resolution) 762 | { 763 | m_halfres_copy_pp->InputPin(0, m_offscreen_srvs[1]); 764 | m_halfres_copy_pp->OutputPin(0, m_offscreen_rtvs[0]); 765 | m_halfres_copy_pp->Apply(); 766 | } 767 | 768 | RenderOverlay(); 769 | m_combine_pp->InputPin(0, m_offscreen_srvs[0]); 770 | m_combine_pp->InputPin(1, m_d2d_texture); 771 | m_combine_pp->OutputPin(0, m_back_buffer_rtv); 772 | m_combine_pp->Apply(); 773 | 774 | m_timer.EndGPUTimming(); 775 | m_swap_chain->Present(0, 0); 776 | } 777 | 778 | void D3DApp::RenderOverlay() 779 | { 780 | // release the d3d11 device 781 | m_keyed_mutex11->ReleaseSync(0); 782 | 783 | // switch to the d3d10.1 device 784 | m_keyed_mutex10->AcquireSync(0, 5); 785 | 786 | // draw d2d content 787 | m_d2d_rendertarget->BeginDraw(); 788 | 789 | // clear d2d background 790 | m_d2d_rendertarget->Clear(D2D1::ColorF(0.0f, 0.0f, 0.0f, 0.0f)); 791 | 792 | // draw text editor 793 | if (!m_hide_editor) 794 | { 795 | m_text_editor->Render(m_d2d_rendertarget); 796 | } 797 | 798 | // end draw 799 | m_d2d_rendertarget->EndDraw(); 800 | 801 | // release the d3d10.1 device 802 | m_keyed_mutex10->ReleaseSync(1); 803 | 804 | // switch back to the d3d11 device 805 | m_keyed_mutex11->AcquireSync(1, 5); 806 | } 807 | -------------------------------------------------------------------------------- /src/d3d_app.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _D3D_APP_HPP_INCLUDED_ 2 | #define _D3D_APP_HPP_INCLUDED_ 3 | 4 | #include "hr_timer.hpp" 5 | #include "post_process.hpp" 6 | #include "text_editor.hpp" 7 | #include "sound_player.hpp" 8 | 9 | class D3DApp 10 | { 11 | public: 12 | D3DApp(); 13 | virtual ~D3DApp(); 14 | 15 | public: 16 | bool Initialize(HINSTANCE hinstance, int width, int height); 17 | int Run(); 18 | void Destroy(); 19 | 20 | int GetWidth() const; 21 | int GetHeight() const; 22 | 23 | float2 GetMousePos(int from_event = 0) const; 24 | float GetMouseWheel() const; 25 | 26 | public: 27 | static D3DApp* GetApp(); 28 | static ID3D11Device* GetD3D11Device(); 29 | static ID3D11DeviceContext* GetD3D11DeviceContext(); 30 | static IDWriteFactory* GetDWriteFactory(); 31 | static HRTimer* GetTimer(); 32 | static PostProcessPtr GetPostProcess(); 33 | static SoundPlayerPtr GetSoundPlayer(); 34 | 35 | public: 36 | static LRESULT CALLBACK WindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); 37 | void RegisterTimerEvents(); 38 | void TimerEventsProc(int cnt, const tstring& tag); 39 | 40 | private: 41 | bool InitializeWindow(); 42 | bool InitializeD3D(); 43 | bool InitializeScene(); 44 | bool InitializeShaders(); 45 | 46 | void UpdateScene(float delta_time); 47 | void RenderScene(); 48 | 49 | void SetViewport(int width, int height); 50 | 51 | template 52 | void UpdateConstantBuffer(ID3D11Buffer *buffer, const T& content) 53 | { 54 | D3D11_MAPPED_SUBRESOURCE res; 55 | m_d3d11_device_context->Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &res); 56 | *static_cast(res.pData) = content; 57 | m_d3d11_device_context->Unmap(buffer, 0); 58 | } 59 | 60 | bool InitializeDWrite(IDXGIAdapter1* adapter); 61 | void RenderOverlay(); 62 | 63 | private: 64 | HINSTANCE m_hinstance; 65 | int m_width; 66 | int m_height; 67 | HWND m_hwnd; 68 | HRTimer m_timer; 69 | 70 | IDXGISwapChain* m_swap_chain; 71 | ID3D11Device* m_d3d11_device; 72 | ID3D11DeviceContext* m_d3d11_device_context; 73 | ID3D11Texture2D* m_back_buffer; 74 | ID3D11Texture2D* m_depthstencil_buffer; 75 | ID3D11RenderTargetView* m_back_buffer_rtv; 76 | ID3D11DepthStencilView* m_depthstencil_view; 77 | 78 | ID3D11Texture2D* m_offscreen_textures[2]; 79 | ID3D11RenderTargetView* m_offscreen_rtvs[2]; 80 | ID3D11ShaderResourceView* m_offscreen_srvs[2]; 81 | 82 | ID3D10Device1* m_d3d10_device; 83 | IDWriteFactory* m_dwrite_factory; 84 | ID2D1RenderTarget* m_d2d_rendertarget; 85 | ID3D11ShaderResourceView* m_d2d_texture; 86 | 87 | ID3D11Texture2D* m_shared_texture; 88 | IDXGIKeyedMutex* m_keyed_mutex11; 89 | IDXGIKeyedMutex* m_keyed_mutex10; 90 | 91 | PostProcessPtr m_custom_pp; 92 | PostProcessPtr m_resolve_pp; 93 | PostProcessPtr m_combine_pp; 94 | PostProcessPtr m_halfres_resolve_pp; 95 | PostProcessPtr m_halfres_copy_pp; 96 | ID3D11Buffer* m_parameter_buffer; 97 | ID3D11ShaderResourceView* m_custom_texture; 98 | ID3D11Buffer* m_jitter_buffer; 99 | ID3D11Buffer* m_interleave_buffer; 100 | 101 | TextEditorPtr m_text_editor; 102 | bool m_hide_editor; 103 | SoundPlayerPtr m_sound_player; 104 | 105 | std::map m_recorded_mouse_pos; 106 | float2 m_mouse_pos; 107 | float m_mouse_wheel; 108 | 109 | bool m_half_resolution; 110 | bool m_aa_enabled; 111 | int m_aa_frame_idx; 112 | float m_aa_control_time; 113 | }; 114 | 115 | #endif // _D3D_APP_HPP_INCLUDED_ -------------------------------------------------------------------------------- /src/editable_text.cpp: -------------------------------------------------------------------------------- 1 | #include "common.hpp" 2 | #include "editable_text.hpp" 3 | 4 | #include 5 | 6 | ////////////////////////////////////////////////////////////////////////// 7 | // constructor / destructor 8 | ////////////////////////////////////////////////////////////////////////// 9 | EditableText::EditableText() 10 | { 11 | SetCaretPos(0); 12 | SetSelection(0, 0); 13 | UpdateHorizenPos(); 14 | } 15 | 16 | EditableText::~EditableText() 17 | { 18 | 19 | } 20 | 21 | bool EditableText::Selection::IsValid(int text_length /* = -1 */) const 22 | { 23 | if (start_pos == end_pos) return false; 24 | 25 | if (text_length >= 0) 26 | { 27 | if (start_pos > static_cast(text_length)) return false; 28 | if (end_pos > static_cast(text_length)) return false; 29 | } 30 | 31 | return true; 32 | } 33 | 34 | ////////////////////////////////////////////////////////////////////////// 35 | // public interfaces 36 | ////////////////////////////////////////////////////////////////////////// 37 | void EditableText::SetText(const std::wstring& text) 38 | { 39 | m_text = text; 40 | SetCaretPos(0); 41 | UpdateHorizenPos(); 42 | 43 | m_undo_records.clear(); 44 | m_redo_records.clear(); 45 | } 46 | 47 | void EditableText::SetCaretPos(size_t pos, bool extend_selection /*= false*/) 48 | { 49 | SetCaretPosInner(pos, extend_selection); 50 | UpdateHorizenPos(); 51 | } 52 | 53 | void EditableText::MoveCharLeft(bool extend_selection /*= false*/) 54 | { 55 | if (m_caret_pos > 0) 56 | { 57 | SetCaretPos(m_caret_pos - 1, extend_selection); 58 | } 59 | } 60 | 61 | void EditableText::MoveCharRight(bool extend_selection /*= false*/) 62 | { 63 | size_t pos = m_caret_pos; 64 | SetCaretPos(pos + 1, extend_selection); 65 | } 66 | 67 | void EditableText::MoveWordLeft(bool extend_selection /*= false*/) 68 | { 69 | int pos = m_caret_pos - 1; 70 | for (; pos >= 0; --pos) 71 | { 72 | if (!isspace(m_text[pos])) break; 73 | if (pos != m_caret_pos - 1 && m_text[pos] == '\n') break; 74 | } 75 | 76 | if (pos < 0 || m_text[pos] == '\n') 77 | { 78 | SetCaretPos(pos + 1, extend_selection); 79 | } 80 | else if (!isalnum(m_text[pos]) && m_text[pos] != '_') 81 | { 82 | SetCaretPos(pos, extend_selection); 83 | } 84 | else 85 | { 86 | for (; pos >= 0; --pos) 87 | { 88 | if (!isalnum(m_text[pos]) && m_text[pos] != '_') break; 89 | } 90 | SetCaretPos(pos + 1, extend_selection); 91 | } 92 | } 93 | 94 | void EditableText::MoveWordRight(bool extend_selection /*= false*/) 95 | { 96 | size_t pos = m_caret_pos; 97 | if (pos < m_text.length() && m_text[pos] == '\n') pos += 1; 98 | 99 | if (pos == m_caret_pos) 100 | { 101 | for (; pos < m_text.length(); ++pos) 102 | { 103 | if (!isalnum(m_text[pos]) && m_text[pos] != '_') break; 104 | } 105 | if (pos == m_caret_pos && pos < m_text.length()) pos += 1; 106 | } 107 | 108 | for (; pos < m_text.length(); ++pos) 109 | { 110 | if (!isspace(m_text[pos]) || m_text[pos] == '\n') break; 111 | } 112 | 113 | SetCaretPos(pos, extend_selection); 114 | } 115 | 116 | void EditableText::MoveLineUp(bool extend_selection /*= false*/) 117 | { 118 | size_t pos = GetLineBeginPos(m_caret_pos); 119 | if (pos > 0) 120 | { 121 | pos = GetLineBeginPos(pos - 1); 122 | } 123 | 124 | size_t end_pos = GetLineEndPos(pos); 125 | pos = std::min(pos + m_horizen_pos, end_pos); 126 | SetCaretPosInner(pos, extend_selection); 127 | } 128 | 129 | void EditableText::MoveLineDown(bool extend_selection /*= false*/) 130 | { 131 | size_t pos = GetLineEndPos(m_caret_pos); 132 | if (pos < m_text.length()) 133 | { 134 | pos = GetLineEndPos(pos + 1); 135 | } 136 | 137 | size_t start_pos = GetLineBeginPos(pos); 138 | pos = std::min(start_pos + m_horizen_pos, pos); 139 | SetCaretPosInner(pos, extend_selection); 140 | } 141 | 142 | void EditableText::MoveLineBegin(bool extend_selection /*= false*/) 143 | { 144 | size_t pos = GetLineBeginPos(m_caret_pos); 145 | SetCaretPos(pos, extend_selection); 146 | } 147 | 148 | void EditableText::MoveLineHome(bool extend_selection /*= false*/) 149 | { 150 | size_t pos = GetLineBeginPos(m_caret_pos); 151 | for (; pos < m_text.length(); ++pos) 152 | { 153 | if (!isspace(m_text[pos]) || m_text[pos] == '\n') break; 154 | } 155 | SetCaretPos(pos, extend_selection); 156 | } 157 | 158 | void EditableText::MoveLineEnd(bool extend_selection /*= false*/) 159 | { 160 | size_t pos = GetLineEndPos(m_caret_pos); 161 | SetCaretPos(pos, extend_selection); 162 | } 163 | 164 | void EditableText::MoveTextBegin(bool extend_selection /*= false*/) 165 | { 166 | SetCaretPos(0, extend_selection); 167 | } 168 | 169 | void EditableText::MoveTextEnd(bool extend_selection /*= false*/) 170 | { 171 | SetCaretPos(m_text.length(), extend_selection); 172 | } 173 | 174 | void EditableText::MoveToLine(size_t line, bool extend_selection /*= false*/) 175 | { 176 | size_t pos = GetTextPos(line, 0); 177 | SetCaretPos(pos, extend_selection); 178 | } 179 | 180 | void EditableText::InsertChar(wchar_t c) 181 | { 182 | std::wstring str(1, c); 183 | InsertText(str); 184 | } 185 | 186 | void EditableText::InsertText(const std::wstring& text) 187 | { 188 | DeleteSelection(); 189 | m_text.insert(m_text.begin() + m_caret_pos, text.begin(), text.end()); 190 | SetCaretPos(m_caret_pos + text.length()); 191 | 192 | EditOperation op = {EO_Insert, m_caret_pos - text.length(), text}; 193 | m_undo_records.push_back(op); 194 | m_redo_records.clear(); 195 | } 196 | 197 | void EditableText::DeleteSelection() 198 | { 199 | if (!m_selection.IsValid()) return; 200 | 201 | size_t left = std::min(m_selection.start_pos, m_selection.end_pos); 202 | size_t right = std::max(m_selection.start_pos, m_selection.end_pos); 203 | std::wstring text_to_del(m_text.begin() + left, m_text.begin() + right); 204 | m_text.erase(m_text.begin() + left, m_text.begin() + right); 205 | SetCaretPos(left); 206 | 207 | EditOperation op = {EO_Delete, left, text_to_del}; 208 | m_undo_records.push_back(op); 209 | m_redo_records.clear(); 210 | } 211 | 212 | void EditableText::CopyToClipboard() const 213 | { 214 | if (!m_selection.IsValid()) return; 215 | 216 | if (OpenClipboard(NULL)) 217 | { 218 | if (EmptyClipboard()) 219 | { 220 | size_t left = std::min(m_selection.start_pos, m_selection.end_pos); 221 | size_t right = std::max(m_selection.start_pos, m_selection.end_pos); 222 | std::wstring selected_text = m_text.substr(left, right - left); 223 | 224 | size_t num_bytes = sizeof(wchar_t) * (selected_text.length() + 1); 225 | HGLOBAL clipboard_data = GlobalAlloc(GMEM_DDESHARE | GMEM_ZEROINIT, num_bytes); 226 | 227 | if (clipboard_data != NULL) 228 | { 229 | void* memory = GlobalLock(clipboard_data); 230 | if (memory != NULL) 231 | { 232 | memcpy(memory, selected_text.c_str(), num_bytes); 233 | GlobalUnlock(clipboard_data); 234 | if (SetClipboardData(CF_UNICODETEXT, clipboard_data) != NULL) 235 | { 236 | clipboard_data = NULL; 237 | } 238 | } 239 | GlobalFree(clipboard_data); 240 | } 241 | } 242 | CloseClipboard(); 243 | } 244 | } 245 | 246 | void EditableText::PasteFromClipboard() 247 | { 248 | DeleteSelection(); 249 | 250 | if (OpenClipboard(NULL)) 251 | { 252 | HGLOBAL clipboard_data = GetClipboardData(CF_UNICODETEXT); 253 | if (clipboard_data != NULL) 254 | { 255 | void* memory = GlobalLock(clipboard_data); 256 | wchar_t* text = reinterpret_cast(memory); 257 | InsertText(text); 258 | } 259 | } 260 | } 261 | 262 | void EditableText::Undo() 263 | { 264 | if (m_undo_records.empty()) return; 265 | 266 | EditOperation op = m_undo_records.back(); 267 | m_undo_records.pop_back(); 268 | m_redo_records.push_back(op); 269 | 270 | if (op.type == EO_Delete) 271 | { 272 | m_text.insert(m_text.begin() + op.pos, op.text.begin(), op.text.end()); 273 | SetCaretPos(op.pos + op.text.length()); 274 | } 275 | else if (op.type == EO_Insert) 276 | { 277 | m_text.erase(m_text.begin() + op.pos, m_text.begin() + op.pos + op.text.length()); 278 | SetCaretPos(op.pos); 279 | } 280 | } 281 | 282 | void EditableText::Redo() 283 | { 284 | if (m_redo_records.empty()) return; 285 | 286 | EditOperation op = m_redo_records.back(); 287 | m_redo_records.pop_back(); 288 | m_undo_records.push_back(op); 289 | 290 | if (op.type == EO_Insert) 291 | { 292 | m_text.insert(m_text.begin() + op.pos, op.text.begin(), op.text.end()); 293 | SetCaretPos(op.pos + op.text.length()); 294 | } 295 | else if (op.type == EO_Delete) 296 | { 297 | m_text.erase(m_text.begin() + op.pos, m_text.begin() + op.pos + op.text.length()); 298 | SetCaretPos(op.pos); 299 | } 300 | } 301 | 302 | const std::wstring& EditableText::GetText() const 303 | { 304 | return m_text; 305 | } 306 | 307 | size_t EditableText::GetTextPos(size_t line, size_t column) const 308 | { 309 | size_t cur_line = 0; 310 | size_t pos = 0; 311 | for (; pos < m_text.length(); ++pos) 312 | { 313 | if (cur_line == line) break; 314 | if (m_text[pos] == '\n') ++cur_line; 315 | } 316 | 317 | size_t line_end = GetLineEndPos(pos); 318 | if (line_end - pos < column) return line_end; 319 | return pos + column; 320 | } 321 | 322 | size_t EditableText::GetCaretPos() const 323 | { 324 | return m_caret_pos; 325 | } 326 | 327 | size_t EditableText::GetCaretLine() const 328 | { 329 | return std::count_if(m_text.begin(), m_text.begin() + m_caret_pos, 330 | [](wchar_t c) {return c == '\n';}); 331 | } 332 | 333 | EditableText::Selection EditableText::GetSelection() const 334 | { 335 | return m_selection; 336 | } 337 | 338 | ////////////////////////////////////////////////////////////////////////// 339 | // private subroutines 340 | ////////////////////////////////////////////////////////////////////////// 341 | void EditableText::SetSelection(size_t start, size_t end) 342 | { 343 | m_selection.start_pos = start; 344 | m_selection.end_pos = end; 345 | } 346 | 347 | void EditableText::SetSelectionStart(size_t start) 348 | { 349 | m_selection.start_pos = start; 350 | } 351 | 352 | void EditableText::SetSelectionEnd(size_t end) 353 | { 354 | m_selection.end_pos = end; 355 | } 356 | 357 | size_t EditableText::GetLineBeginPos(size_t current_pos) const 358 | { 359 | int pos = current_pos - 1; 360 | for (; pos >= 0; --pos) 361 | { 362 | if (m_text[pos] == '\n') break; 363 | } 364 | return pos + 1; 365 | } 366 | 367 | size_t EditableText::GetLineEndPos(size_t current_pos) const 368 | { 369 | size_t pos = current_pos; 370 | for (; pos < m_text.length(); ++pos) 371 | { 372 | if (m_text[pos] == '\n') break; 373 | } 374 | return pos; 375 | } 376 | 377 | void EditableText::SetCaretPosInner(size_t pos, bool extend_selection /*= false*/) 378 | { 379 | pos = std::min(pos, m_text.length()); 380 | m_caret_pos = pos; 381 | 382 | if (extend_selection) 383 | { 384 | SetSelectionEnd(m_caret_pos); 385 | } 386 | else 387 | { 388 | SetSelection(m_caret_pos, m_caret_pos); 389 | } 390 | } 391 | 392 | void EditableText::UpdateHorizenPos() 393 | { 394 | size_t pos = GetLineBeginPos(m_caret_pos); 395 | m_horizen_pos = m_caret_pos - pos; 396 | } 397 | -------------------------------------------------------------------------------- /src/editable_text.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _EDITABLE_TEXT_HPP_INCLUDED_ 2 | #define _EDITABLE_TEXT_HPP_INCLUDED_ 3 | 4 | #include 5 | #include 6 | 7 | class EditableText 8 | { 9 | public: 10 | enum EditType 11 | { 12 | EO_Insert, 13 | EO_Delete, 14 | }; 15 | 16 | struct EditOperation 17 | { 18 | EditType type; 19 | size_t pos; 20 | std::wstring text; 21 | }; 22 | 23 | struct Selection 24 | { 25 | size_t start_pos; 26 | size_t end_pos; 27 | bool IsValid(int text_length = -1) const; 28 | }; 29 | 30 | public: 31 | EditableText(); 32 | virtual ~EditableText(); 33 | 34 | public: 35 | void SetText(const std::wstring& text); 36 | void SetCaretPos(size_t pos, bool extend_selection = false); 37 | 38 | void MoveCharLeft(bool extend_selection = false); 39 | void MoveCharRight(bool extend_selection = false); 40 | void MoveWordLeft(bool extend_selection = false); 41 | void MoveWordRight(bool extend_selection = false); 42 | 43 | void MoveLineUp(bool extend_selection = false); 44 | void MoveLineDown(bool extend_selection = false); 45 | void MoveLineBegin(bool extend_selection = false); 46 | void MoveLineHome(bool extend_selection = false); 47 | void MoveLineEnd(bool extend_selection = false); 48 | void MoveTextBegin(bool extend_selection = false); 49 | void MoveTextEnd(bool extend_selection = false); 50 | void MoveToLine(size_t line, bool extend_selection = false); 51 | 52 | void InsertChar(wchar_t c); 53 | void InsertText(const std::wstring& text); 54 | void DeleteSelection(); 55 | 56 | void CopyToClipboard() const; 57 | void PasteFromClipboard(); 58 | 59 | void Undo(); 60 | void Redo(); 61 | 62 | const std::wstring& GetText() const; 63 | size_t GetTextPos(size_t line, size_t column) const; 64 | 65 | size_t GetCaretPos() const; 66 | size_t GetCaretLine() const; 67 | Selection GetSelection() const; 68 | 69 | private: 70 | void SetSelection(size_t start, size_t end); 71 | void SetSelectionStart(size_t start); 72 | void SetSelectionEnd(size_t end); 73 | 74 | size_t GetLineBeginPos(size_t current_pos) const; 75 | size_t GetLineEndPos(size_t current_pos) const; 76 | 77 | void SetCaretPosInner(size_t pos, bool extend_selection = false); 78 | void UpdateHorizenPos(); 79 | 80 | private: 81 | std::wstring m_text; 82 | size_t m_caret_pos; 83 | size_t m_horizen_pos; 84 | Selection m_selection; 85 | 86 | std::vector m_undo_records; 87 | std::vector m_redo_records; 88 | }; 89 | 90 | #endif // _EDITABLE_TEXT_HPP_INCLUDED_ -------------------------------------------------------------------------------- /src/hr_timer.cpp: -------------------------------------------------------------------------------- 1 | #include "common.hpp" 2 | #include "hr_timer.hpp" 3 | #include "d3d_app.hpp" 4 | #include 5 | 6 | ////////////////////////////////////////////////////////////////////////// 7 | // constructor / destructor 8 | ////////////////////////////////////////////////////////////////////////// 9 | HRTimer::HRTimer() 10 | : m_count_start(0) 11 | , m_count_tick(0) 12 | , m_count_delta(0) 13 | , m_count_delta_busy(0) 14 | , m_count_per_second(1) 15 | , m_count_delta_gpu(0) 16 | , m_count_per_second_gpu(1) 17 | , m_first_tick(true) 18 | , m_query_idx(0) 19 | , m_query_number(0) 20 | , m_query_skipped(false) 21 | { 22 | ZeroMemory(m_query_timestamp_start, sizeof(m_query_timestamp_start)); 23 | ZeroMemory(m_query_timestamp_end, sizeof(m_query_timestamp_end)); 24 | ZeroMemory(m_query_timestamp_disjoint, sizeof(m_query_timestamp_disjoint)); 25 | } 26 | 27 | HRTimer::~HRTimer() 28 | { 29 | timeEndPeriod(1); 30 | 31 | for (int i = 0; i != gpu_query_buffer_size; ++i) 32 | { 33 | SAFE_RELEASE(m_query_timestamp_start[i]); 34 | SAFE_RELEASE(m_query_timestamp_end[i]); 35 | SAFE_RELEASE(m_query_timestamp_disjoint[i]); 36 | } 37 | } 38 | 39 | ////////////////////////////////////////////////////////////////////////// 40 | // public interfaces 41 | ////////////////////////////////////////////////////////////////////////// 42 | void HRTimer::Start() 43 | { 44 | timeBeginPeriod(1); 45 | 46 | LARGE_INTEGER frequency_count; 47 | QueryPerformanceFrequency(&frequency_count); 48 | m_count_per_second = frequency_count.QuadPart; 49 | QueryPerformanceCounter(&frequency_count); 50 | m_count_start = frequency_count.QuadPart; 51 | 52 | CD3D11_QUERY_DESC query_timestamp_desc(D3D11_QUERY_TIMESTAMP); 53 | CD3D11_QUERY_DESC query_timestamp_disjoint_desc(D3D11_QUERY_TIMESTAMP_DISJOINT); 54 | 55 | for (int i = 0; i != gpu_query_buffer_size; ++i) 56 | { 57 | D3DApp::GetD3D11Device()->CreateQuery(&query_timestamp_desc, &m_query_timestamp_start[i]); 58 | D3DApp::GetD3D11Device()->CreateQuery(&query_timestamp_desc, &m_query_timestamp_end[i]); 59 | D3DApp::GetD3D11Device()->CreateQuery(&query_timestamp_disjoint_desc, &m_query_timestamp_disjoint[i]); 60 | } 61 | } 62 | 63 | void HRTimer::Tick() 64 | { 65 | LARGE_INTEGER frequency_count; 66 | QueryPerformanceCounter(&frequency_count); 67 | m_count_delta = frequency_count.QuadPart - m_count_tick; 68 | m_count_tick = frequency_count.QuadPart; 69 | 70 | if (m_first_tick) 71 | { 72 | m_count_delta = 0; 73 | m_first_tick = false; 74 | } 75 | else 76 | { 77 | m_count_delta = std::max(0, m_count_delta); 78 | } 79 | 80 | TickTimerEvents(GetDeltaTime()); 81 | } 82 | 83 | void HRTimer::SyncTick(float sync_period) 84 | { 85 | if (m_first_tick) 86 | { 87 | m_count_delta_busy = 0; 88 | return Tick(); 89 | } 90 | 91 | LARGE_INTEGER frequency_count; 92 | QueryPerformanceCounter(&frequency_count); 93 | m_count_delta_busy = frequency_count.QuadPart - m_count_tick; 94 | float delta_time = static_cast(m_count_delta_busy) / m_count_per_second; 95 | if (delta_time < sync_period) 96 | { 97 | int waiting_ms = static_cast((sync_period - delta_time) * 1000); 98 | if (waiting_ms > 1) Sleep(waiting_ms - 1); 99 | do 100 | { 101 | Sleep(0); 102 | QueryPerformanceCounter(&frequency_count); 103 | long long count_delta = frequency_count.QuadPart - m_count_tick; 104 | delta_time = static_cast(count_delta) / m_count_per_second; 105 | } while (delta_time < sync_period); 106 | } 107 | 108 | Tick(); 109 | } 110 | 111 | float HRTimer::GetTime() const 112 | { 113 | LARGE_INTEGER frequency_count; 114 | QueryPerformanceCounter(&frequency_count); 115 | return static_cast(frequency_count.QuadPart - m_count_start) / m_count_per_second; 116 | } 117 | 118 | float HRTimer::GetDeltaTime() const 119 | { 120 | return static_cast(m_count_delta) / m_count_per_second; 121 | } 122 | 123 | float HRTimer::GetCPUDeltaTime() const 124 | { 125 | return static_cast(m_count_delta_busy) / m_count_per_second; 126 | } 127 | 128 | float HRTimer::GetGPUDeltaTime() const 129 | { 130 | return static_cast(m_count_delta_gpu) / m_count_per_second_gpu; 131 | } 132 | 133 | void HRTimer::BeginGPUTimming() 134 | { 135 | if (m_query_number == gpu_query_buffer_size) 136 | { 137 | m_query_skipped = true; 138 | return; 139 | } 140 | 141 | m_query_skipped = false; 142 | D3DApp::GetD3D11DeviceContext()->Begin(m_query_timestamp_disjoint[m_query_idx]); 143 | D3DApp::GetD3D11DeviceContext()->End(m_query_timestamp_start[m_query_idx]); 144 | } 145 | 146 | void HRTimer::EndGPUTimming() 147 | { 148 | if (!m_query_skipped) 149 | { 150 | D3DApp::GetD3D11DeviceContext()->End(m_query_timestamp_end[m_query_idx]); 151 | D3DApp::GetD3D11DeviceContext()->End(m_query_timestamp_disjoint[m_query_idx]); 152 | m_query_idx = (m_query_idx + 1) % gpu_query_buffer_size; 153 | m_query_number += 1; 154 | } 155 | 156 | int feeded = 0; 157 | for (; feeded != m_query_number; ++feeded) 158 | { 159 | int read_idx = (m_query_idx - m_query_number + feeded + gpu_query_buffer_size) % gpu_query_buffer_size; 160 | 161 | UINT64 timestamp_start; 162 | UINT64 timestamp_end; 163 | D3D11_QUERY_DATA_TIMESTAMP_DISJOINT timestamp_disjoint; 164 | 165 | bool query_complete = true; 166 | query_complete &= D3DApp::GetD3D11DeviceContext()->GetData( 167 | m_query_timestamp_start[read_idx], ×tamp_start, sizeof(timestamp_start), 0) == S_OK; 168 | query_complete &= D3DApp::GetD3D11DeviceContext()->GetData( 169 | m_query_timestamp_end[read_idx], ×tamp_end, sizeof(timestamp_end), 0) == S_OK; 170 | query_complete &= D3DApp::GetD3D11DeviceContext()->GetData( 171 | m_query_timestamp_disjoint[read_idx], ×tamp_disjoint, sizeof(timestamp_disjoint), 0) == S_OK; 172 | 173 | if (!query_complete) break; 174 | 175 | if (!timestamp_disjoint.Disjoint) 176 | { 177 | m_count_per_second_gpu = timestamp_disjoint.Frequency; 178 | m_count_delta_gpu = timestamp_end - timestamp_start; 179 | } 180 | } 181 | m_query_number -= feeded; 182 | } 183 | 184 | void HRTimer::RemoveEvent(const tstring& tag) 185 | { 186 | for (auto it = m_timer_events.begin(); it != m_timer_events.end();) 187 | { 188 | if (it->tag == tag) it = m_timer_events.erase(it); 189 | else ++it; 190 | } 191 | } 192 | 193 | void HRTimer::TickTimerEvents(float delta_time) 194 | { 195 | for (auto it = m_timer_events.begin(); it != m_timer_events.end();) 196 | { 197 | it->cur_time += delta_time; 198 | if (it->cur_time > it->tot_time) 199 | { 200 | // issue callback 201 | (it->callback)(it->cur_count, it->tag); 202 | it->cur_time = 0; 203 | if (++(it->cur_count) == it->tot_count) 204 | { 205 | it = m_timer_events.erase(it); 206 | continue; 207 | } 208 | } 209 | ++it; 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /src/hr_timer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _HR_TIMER_HPP_INCLUDED_ 2 | #define _HR_TIMER_HPP_INCLUDED_ 3 | 4 | #include 5 | #include 6 | 7 | typedef boost::function TimerEventCallBack; 8 | 9 | static const int gpu_query_buffer_size = 4; 10 | 11 | class HRTimer 12 | { 13 | struct TimerEvent 14 | { 15 | tstring tag; 16 | int cur_count; 17 | int tot_count; 18 | float cur_time; 19 | float tot_time; 20 | TimerEventCallBack callback; 21 | }; 22 | 23 | public: 24 | HRTimer(); 25 | ~HRTimer(); 26 | 27 | public: 28 | void Start(); 29 | void Tick(); 30 | void SyncTick(float sync_period); 31 | 32 | float GetTime() const; 33 | float GetDeltaTime() const; 34 | float GetCPUDeltaTime() const; 35 | 36 | void BeginGPUTimming(); 37 | void EndGPUTimming(); 38 | float GetGPUDeltaTime() const; 39 | 40 | template 41 | void AddEvent(float interval, Func callback, const tstring& tag = TEXT(""), int tot_cnt = 0) 42 | { 43 | TimerEvent evt = { 44 | tag, 45 | 0, 46 | tot_cnt, 47 | 0, 48 | interval, 49 | TimerEventCallBack(callback) 50 | }; 51 | m_timer_events.push_back(evt); 52 | } 53 | 54 | void RemoveEvent(const tstring& tag); 55 | 56 | private: 57 | void TickTimerEvents(float delta_time); 58 | 59 | private: 60 | long long m_count_start; 61 | long long m_count_tick; 62 | long long m_count_delta; 63 | long long m_count_delta_busy; 64 | long long m_count_per_second; 65 | 66 | long long m_count_delta_gpu; 67 | long long m_count_per_second_gpu; 68 | 69 | ID3D11Query *m_query_timestamp_start[gpu_query_buffer_size]; 70 | ID3D11Query *m_query_timestamp_end[gpu_query_buffer_size]; 71 | ID3D11Query *m_query_timestamp_disjoint[gpu_query_buffer_size]; 72 | int m_query_idx; 73 | int m_query_number; 74 | bool m_query_skipped; 75 | 76 | bool m_first_tick; 77 | std::list m_timer_events; 78 | }; 79 | 80 | #endif // _HR_TIMER_HPP_INCLUDED_ -------------------------------------------------------------------------------- /src/keywords.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _KEYWORDS_INCLUDED_HPP_ 2 | #define _KEYWORDS_INCLUDED_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | #define MAKE_SUFFIX_1D(_, i, s) L#s##L#i, 8 | #define MAKE_SUFFIX_2D_1(_, j, s) L#s##L"1"##L"x"##L#j, 9 | #define MAKE_SUFFIX_2D_2(_, j, s) L#s##L"2"##L"x"##L#j, 10 | #define MAKE_SUFFIX_2D_3(_, j, s) L#s##L"3"##L"x"##L#j, 11 | #define MAKE_SUFFIX_2D_4(_, j, s) L#s##L"4"##L"x"##L#j, 12 | 13 | #define DECLARE_TYPE_1D(type) \ 14 | L###type, BOOST_PP_REPEAT_FROM_TO(2, 5, MAKE_SUFFIX_1D, type) 15 | 16 | #define DECLARE_TYPE_2D(type) \ 17 | BOOST_PP_REPEAT_FROM_TO(1, 5, MAKE_SUFFIX_2D_1, type) \ 18 | BOOST_PP_REPEAT_FROM_TO(1, 5, MAKE_SUFFIX_2D_2, type) \ 19 | BOOST_PP_REPEAT_FROM_TO(1, 5, MAKE_SUFFIX_2D_3, type) \ 20 | BOOST_PP_REPEAT_FROM_TO(1, 5, MAKE_SUFFIX_2D_4, type) 21 | 22 | #define DECLARE_SEMANTIC(semantic, n) \ 23 | L###semantic, BOOST_PP_REPEAT(n, MAKE_SUFFIX_1D, semantic) 24 | 25 | static const std::wstring kewords[] = 26 | { 27 | DECLARE_TYPE_1D(bool) 28 | DECLARE_TYPE_1D(int) 29 | DECLARE_TYPE_1D(half) 30 | DECLARE_TYPE_1D(float) 31 | DECLARE_TYPE_2D(float) 32 | L"blendstate", L"break", L"buffer", 33 | L"cbuffer", L"class", L"compile", L"const", L"continue", 34 | L"depthstencilstate", L"depthstencilview", L"discard", L"do", L"double", L"define", 35 | L"else", L"extern", L"endif", 36 | L"false", L"for", 37 | L"geometryshader", 38 | L"if", L"in", L"inline", L"ifdef", L"ifndef", L"inout", L"interface", 39 | L"matrix", 40 | L"namespace", L"nointerpolation", 41 | L"out", 42 | L"pass", L"pixelshader", L"precise", 43 | L"rasterizerstate", L"rendertargetview", L"return", L"register", 44 | L"sampler", L"sampler1D", L"sampler2D", L"sampler3D", L"samplerCUBE", L"SamplerState", L"SamplerComparisonState", L"shared", L"stateblock", L"stateblock_state", L"static", L"string", L"struct", L"switch", 45 | L"tbuffer", L"technique", L"technique10", L"texture", L"Texture1D", L"Texture1DArray", L"Texture2D", L"Texture2DArray", L"Texture2DMS", L"Texture2DMSArray", L"Texture3D", L"TextureCube", L"TextureCubeArray", L"true", L"typedef", 46 | L"uniform", 47 | L"vector", L"vertexshader", L"void", L"volatile", L"while", 48 | }; 49 | 50 | static const std::wstring semantics[] = 51 | { 52 | DECLARE_SEMANTIC(binormal, 12) 53 | DECLARE_SEMANTIC(blendindices, 12) 54 | DECLARE_SEMANTIC(blendweight, 12) 55 | DECLARE_SEMANTIC(color, 16) 56 | DECLARE_SEMANTIC(depth, 16) 57 | DECLARE_SEMANTIC(normal, 12) 58 | DECLARE_SEMANTIC(position, 12) 59 | DECLARE_SEMANTIC(positiont, 0) 60 | DECLARE_SEMANTIC(psize, 12) 61 | DECLARE_SEMANTIC(tangent, 12) 62 | DECLARE_SEMANTIC(texcoord, 16) 63 | DECLARE_SEMANTIC(color, 16) 64 | DECLARE_SEMANTIC(fog, 0) 65 | DECLARE_SEMANTIC(tessfactor, 12) 66 | DECLARE_SEMANTIC(vface, 0) 67 | DECLARE_SEMANTIC(vpos, 0) 68 | DECLARE_SEMANTIC(sv_clipdistance, 8) 69 | DECLARE_SEMANTIC(sv_culldistance, 8) 70 | DECLARE_SEMANTIC(sv_coverage, 0) 71 | DECLARE_SEMANTIC(sv_depth, 0) 72 | DECLARE_SEMANTIC(sv_dispatchthreadid, 0) 73 | DECLARE_SEMANTIC(sv_domainlocation, 0) 74 | DECLARE_SEMANTIC(sv_groupid, 0) 75 | DECLARE_SEMANTIC(sv_groupindex, 0) 76 | DECLARE_SEMANTIC(sv_groupthreadid, 0) 77 | DECLARE_SEMANTIC(sv_gsinstanceid, 0) 78 | DECLARE_SEMANTIC(sv_insidetessfactor, 0) 79 | DECLARE_SEMANTIC(sv_isfrontface, 0) 80 | DECLARE_SEMANTIC(sv_position, 0) 81 | DECLARE_SEMANTIC(sv_rendertargetarrayindex, 0) 82 | DECLARE_SEMANTIC(sv_sampleindex, 0) 83 | DECLARE_SEMANTIC(sv_target, 8) 84 | DECLARE_SEMANTIC(sv_tessfactor, 0) 85 | DECLARE_SEMANTIC(sv_viewportarrayindex, 0) 86 | DECLARE_SEMANTIC(sv_instanceid, 0) 87 | DECLARE_SEMANTIC(sv_primitiveid, 0) 88 | DECLARE_SEMANTIC(sv_vertexid, 0) 89 | }; 90 | 91 | static const std::wstring global_funcs[] = 92 | { 93 | L"abs", 94 | L"acos", 95 | L"all", 96 | L"AllMemoryBarrier", 97 | L"AllMemoryBarrierWithGroupSync", 98 | L"any", 99 | L"asdouble", 100 | L"asfloat", 101 | L"asfloat", 102 | L"asin", 103 | L"asint", 104 | L"asint", 105 | L"asuint", 106 | L"asuint", 107 | L"atan", 108 | L"atan2", 109 | L"ceil", 110 | L"clamp", 111 | L"clip", 112 | L"cos", 113 | L"cosh", 114 | L"countbits", 115 | L"cross", 116 | L"D3DCOLORtoUBYTE4", 117 | L"ddx", 118 | L"ddx_coarse", 119 | L"ddx_fine", 120 | L"ddy", 121 | L"ddy_coarse", 122 | L"ddy_fine", 123 | L"degrees", 124 | L"determinant", 125 | L"DeviceMemoryBarrier", 126 | L"DeviceMemoryBarrierWithGroupSync", 127 | L"distance", 128 | L"dot", 129 | L"dst", 130 | L"EvaluateAttributeAtCentroid", 131 | L"EvaluateAttributeAtSample", 132 | L"EvaluateAttributeSnapped", 133 | L"exp", 134 | L"exp2", 135 | L"f16tof32", 136 | L"f32tof16", 137 | L"faceforward", 138 | L"firstbithigh", 139 | L"firstbitlow", 140 | L"floor", 141 | L"fmod", 142 | L"frac", 143 | L"frexp", 144 | L"fwidth", 145 | L"GetRenderTargetSampleCount", 146 | L"GetRenderTargetSamplePosition", 147 | L"GroupMemoryBarrier", 148 | L"GroupMemoryBarrierWithGroupSync", 149 | L"InterlockedAdd", 150 | L"InterlockedAnd", 151 | L"InterlockedCompareExchange", 152 | L"InterlockedCompareStore", 153 | L"InterlockedExchange", 154 | L"InterlockedMax", 155 | L"InterlockedMin", 156 | L"InterlockedOr", 157 | L"InterlockedXor", 158 | L"isfinite", 159 | L"isinf", 160 | L"isnan", 161 | L"ldexp", 162 | L"length", 163 | L"lerp", 164 | L"lit", 165 | L"log", 166 | L"log10", 167 | L"log2", 168 | L"mad", 169 | L"max", 170 | L"min", 171 | L"modf", 172 | L"mul", 173 | L"noise", 174 | L"normalize", 175 | L"pow", 176 | L"Process2DQuadTessFactorsAvg", 177 | L"Process2DQuadTessFactorsMax", 178 | L"Process2DQuadTessFactorsMin", 179 | L"ProcessIsolineTessFactors", 180 | L"ProcessQuadTessFactorsAvg", 181 | L"ProcessQuadTessFactorsMax", 182 | L"ProcessQuadTessFactorsMin", 183 | L"ProcessTriTessFactorsAvg", 184 | L"ProcessTriTessFactorsMax", 185 | L"ProcessTriTessFactorsMin", 186 | L"radians", 187 | L"rcp", 188 | L"reflect", 189 | L"refract", 190 | L"reversebits", 191 | L"round", 192 | L"rsqrt", 193 | L"saturate", 194 | L"sign", 195 | L"sin", 196 | L"sincos", 197 | L"sinh", 198 | L"smoothstep", 199 | L"sqrt", 200 | L"step", 201 | L"tan", 202 | L"tanh", 203 | L"tex1D", 204 | L"tex1D", 205 | L"tex1Dbias", 206 | L"tex1Dgrad", 207 | L"tex1Dlod", 208 | L"tex1Dproj", 209 | L"tex2D", 210 | L"tex2D", 211 | L"tex2Dbias", 212 | L"tex2Dgrad", 213 | L"tex2Dlod", 214 | L"tex2Dproj", 215 | L"tex3D", 216 | L"tex3D", 217 | L"tex3Dbias", 218 | L"tex3Dgrad", 219 | L"tex3Dlod", 220 | L"tex3Dproj", 221 | L"texCUBE", 222 | L"texCUBE", 223 | L"texCUBEbias", 224 | L"texCUBEgrad", 225 | L"texCUBElod", 226 | L"texCUBEproj", 227 | L"transpose", 228 | L"trunc", 229 | }; 230 | 231 | static const std::wstring extend_funcs[] = 232 | { 233 | L"snoise", 234 | L"qnoise", 235 | }; 236 | 237 | static const std::wstring member_funcs[] = 238 | { 239 | L"Append", 240 | L"RestartStrip", 241 | L"CalculateLevelOfDetail", 242 | L"CalculateLevelOfDetailUnclamped", 243 | L"Gather", 244 | L"GetDimensions", 245 | L"GetSamplePosition", 246 | L"Load", 247 | L"Sample", 248 | L"SampleBias", 249 | L"SampleCmp", 250 | L"SampleCmpLevelZero", 251 | L"SampleGrad", 252 | L"SampleLevel", 253 | }; 254 | 255 | #undef MAKE_SUFFIX_1D 256 | #undef MAKE_SUFFIX_2D_1 257 | #undef MAKE_SUFFIX_2D_2 258 | #undef MAKE_SUFFIX_2D_3 259 | #undef MAKE_SUFFIX_2D_4 260 | #undef DECLARE_TYPE_1D 261 | #undef DECLARE_TYPE_2D 262 | #undef DECLARE_SEMANTIC 263 | 264 | #endif // _KEYWORDS_INCLUDED_HPP_ -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "common.hpp" 2 | #include "d3d_app.hpp" 3 | 4 | const int width = 1280; 5 | const int height = 768; 6 | 7 | int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShow) 8 | { 9 | D3DApp *app = D3DApp::GetApp(); 10 | if (app->Initialize(hInstance, width, height)) { 11 | app->Run(); 12 | } 13 | app->Destroy(); 14 | } 15 | -------------------------------------------------------------------------------- /src/post_process.cpp: -------------------------------------------------------------------------------- 1 | #include "common.hpp" 2 | #include "post_process.hpp" 3 | #include "d3d_app.hpp" 4 | 5 | #include 6 | 7 | ////////////////////////////////////////////////////////////////////////// 8 | // constructor / destructor 9 | ////////////////////////////////////////////////////////////////////////// 10 | PostProcess::PostProcess(bool blend_enable /* = false */) 11 | : m_vertex_buffer(NULL) 12 | , m_index_buffer(NULL) 13 | , m_vertex_shader(NULL) 14 | , m_pixel_shader(NULL) 15 | , m_vertex_layout(NULL) 16 | , m_raster_state(NULL) 17 | , m_blend_state(NULL) 18 | , m_sampler_state(NULL) 19 | , m_depth_stencil_state(NULL) 20 | { 21 | InitVertexBuffer(); 22 | InitIndexBuffer(); 23 | InitVertexShader(); 24 | 25 | InitRasterState(); 26 | InitBlendState(blend_enable); 27 | InitSamplerState(); 28 | 29 | LoadPixelShaderFromFile(TEXT("pp_common.hlsl"), TEXT("ps_main")); 30 | } 31 | 32 | PostProcess::~PostProcess() 33 | { 34 | SAFE_RELEASE(m_vertex_buffer); 35 | SAFE_RELEASE(m_index_buffer); 36 | SAFE_RELEASE(m_vertex_shader); 37 | SAFE_RELEASE(m_pixel_shader); 38 | SAFE_RELEASE(m_vertex_layout); 39 | SAFE_RELEASE(m_raster_state); 40 | SAFE_RELEASE(m_blend_state); 41 | SAFE_RELEASE(m_sampler_state); 42 | SAFE_RELEASE(m_depth_stencil_state); 43 | } 44 | 45 | ////////////////////////////////////////////////////////////////////////// 46 | // public interfaces 47 | ////////////////////////////////////////////////////////////////////////// 48 | void PostProcess::Apply() const 49 | { 50 | UINT stride = sizeof(Vertex); 51 | UINT offset = 0; 52 | D3DApp::GetD3D11DeviceContext()->IASetVertexBuffers(0, 1, &m_vertex_buffer, &stride, &offset); 53 | D3DApp::GetD3D11DeviceContext()->IASetIndexBuffer(m_index_buffer, DXGI_FORMAT_R32_UINT, 0); 54 | 55 | D3DApp::GetD3D11DeviceContext()->IASetInputLayout(m_vertex_layout); 56 | D3DApp::GetD3D11DeviceContext()->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); 57 | 58 | ID3D11RenderTargetView* rtvs[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = {NULL}; 59 | for each(auto &it in m_output_pins) {rtvs[it.first] = it.second;} 60 | D3DApp::GetD3D11DeviceContext()->OMSetRenderTargets(ARRAYSIZE(rtvs), rtvs, NULL); 61 | 62 | ID3D11ShaderResourceView* srvs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] = {NULL}; 63 | for each(auto &it in m_input_pins) 64 | { 65 | srvs[it.first] = it.second; 66 | } 67 | D3DApp::GetD3D11DeviceContext()->PSSetShaderResources(0, ARRAYSIZE(srvs), srvs); 68 | D3DApp::GetD3D11DeviceContext()->PSSetSamplers(0, 1, &m_sampler_state); 69 | 70 | D3DApp::GetD3D11DeviceContext()->RSSetState(m_raster_state); 71 | D3DApp::GetD3D11DeviceContext()->OMSetBlendState(m_blend_state, NULL, 0xFFFFFFFF); 72 | D3DApp::GetD3D11DeviceContext()->OMSetDepthStencilState(m_depth_stencil_state, 0); 73 | 74 | D3DApp::GetD3D11DeviceContext()->VSSetShader(m_vertex_shader, NULL, 0); 75 | D3DApp::GetD3D11DeviceContext()->GSSetShader(NULL, NULL, 0); 76 | D3DApp::GetD3D11DeviceContext()->PSSetShader(m_pixel_shader, NULL, 0); 77 | D3DApp::GetD3D11DeviceContext()->DrawIndexed(6, 0, 0); 78 | } 79 | 80 | void PostProcess::InputPin(int slot, ID3D11ShaderResourceView* srv) 81 | { 82 | m_input_pins[slot] = srv; 83 | } 84 | 85 | void PostProcess::OutputPin(int slot, ID3D11RenderTargetView* rtv) 86 | { 87 | m_output_pins[slot] = rtv; 88 | } 89 | 90 | void PostProcess::SetParameters(int slot, ID3D11Buffer* cbuffer) 91 | { 92 | D3DApp::GetD3D11DeviceContext()->PSSetConstantBuffers(slot, 1, &cbuffer); 93 | } 94 | 95 | bool PostProcess::LoadPixelShaderFromFile(const tstring& file_name, const tstring& entry_point) 96 | { 97 | tstring file_path = TEXT("fx/") + file_name; 98 | ID3DBlob* error_buffer = NULL; 99 | ID3DBlob* pixel_shader_buffer = NULL; 100 | ID3D11PixelShader* pixel_shader = NULL; 101 | 102 | HRESULT hr = D3DX11CompileFromFile( 103 | file_path.c_str(), 104 | NULL, 105 | NULL, 106 | to_string(entry_point).c_str(), 107 | "ps_4_0", 108 | D3D10_SHADER_DEBUG, 109 | 0, 110 | NULL, 111 | &pixel_shader_buffer, 112 | &error_buffer, 113 | NULL); 114 | 115 | if (FAILED(hr)) 116 | { 117 | if (error_buffer != NULL) 118 | { 119 | std::string error_message = static_cast(error_buffer->GetBufferPointer()); 120 | m_error_message = to_tstring(error_message); 121 | } 122 | SAFE_RELEASE(pixel_shader_buffer); 123 | SAFE_RELEASE(error_buffer); 124 | return false; 125 | } 126 | 127 | hr = D3DApp::GetD3D11Device()->CreatePixelShader( 128 | pixel_shader_buffer->GetBufferPointer(), 129 | pixel_shader_buffer->GetBufferSize(), 130 | NULL, 131 | &pixel_shader); 132 | 133 | if (FAILED(hr)) 134 | { 135 | m_error_message = TEXT("create pixel shader failed."); 136 | SAFE_RELEASE(pixel_shader_buffer); 137 | SAFE_RELEASE(error_buffer); 138 | return false; 139 | } 140 | 141 | SAFE_RELEASE(m_pixel_shader); 142 | m_pixel_shader = pixel_shader; 143 | SAFE_RELEASE(pixel_shader_buffer); 144 | SAFE_RELEASE(error_buffer); 145 | return true; 146 | } 147 | 148 | bool PostProcess::LoadPixelShaderFromMemory(const tstring& shader_content, const tstring& entry_point) 149 | { 150 | ID3DBlob* error_buffer = NULL; 151 | ID3DBlob* pixel_shader_buffer = NULL; 152 | ID3D11PixelShader* pixel_shader = NULL; 153 | 154 | std::string shader_content_str = to_string(shader_content); 155 | HRESULT hr = D3DX11CompileFromMemory( 156 | shader_content_str.c_str(), 157 | shader_content_str.length(), 158 | NULL, 159 | NULL, 160 | NULL, 161 | to_string(entry_point).c_str(), 162 | "ps_4_0", 163 | D3D10_SHADER_DEBUG, 164 | 0, 165 | NULL, 166 | &pixel_shader_buffer, 167 | &error_buffer, 168 | NULL); 169 | 170 | if (FAILED(hr)) 171 | { 172 | if (error_buffer != NULL) 173 | { 174 | std::string error_message = static_cast(error_buffer->GetBufferPointer()); 175 | m_error_message = to_tstring(error_message); 176 | } 177 | SAFE_RELEASE(pixel_shader_buffer); 178 | SAFE_RELEASE(error_buffer); 179 | return false; 180 | } 181 | 182 | hr = D3DApp::GetD3D11Device()->CreatePixelShader( 183 | pixel_shader_buffer->GetBufferPointer(), 184 | pixel_shader_buffer->GetBufferSize(), 185 | NULL, 186 | &pixel_shader); 187 | 188 | if (FAILED(hr)) 189 | { 190 | m_error_message = TEXT("create pixel shader failed."); 191 | SAFE_RELEASE(pixel_shader_buffer); 192 | SAFE_RELEASE(error_buffer); 193 | return false; 194 | } 195 | 196 | SAFE_RELEASE(m_pixel_shader); 197 | m_pixel_shader = pixel_shader; 198 | SAFE_RELEASE(pixel_shader_buffer); 199 | SAFE_RELEASE(error_buffer); 200 | return true; 201 | } 202 | 203 | tstring PostProcess::GetErrorMessage() const 204 | { 205 | return m_error_message; 206 | } 207 | 208 | ////////////////////////////////////////////////////////////////////////// 209 | // private subroutines 210 | ////////////////////////////////////////////////////////////////////////// 211 | void PostProcess::InitVertexBuffer() 212 | { 213 | Vertex vertices[] = { 214 | {float3(-1.0f, -1.0f, 0.0f), float2(0.0f, 1.0f)}, 215 | {float3(-1.0f, 1.0f, 0.0f), float2(0.0f, 0.0f)}, 216 | {float3( 1.0f, 1.0f, 0.0f), float2(1.0f, 0.0f)}, 217 | {float3( 1.0f, -1.0f, 0.0f), float2(1.0f, 1.0f)}, 218 | }; 219 | 220 | D3D11_BUFFER_DESC vertex_buffer_desc; 221 | ZeroMemory(&vertex_buffer_desc, sizeof(vertex_buffer_desc)); 222 | vertex_buffer_desc.Usage = D3D11_USAGE_DEFAULT;1, 223 | vertex_buffer_desc.ByteWidth = sizeof(vertices); 224 | vertex_buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; 225 | vertex_buffer_desc.CPUAccessFlags = 0; 226 | vertex_buffer_desc.MiscFlags = 0; 227 | 228 | D3D11_SUBRESOURCE_DATA vertices_data; 229 | ZeroMemory(&vertices_data, sizeof(vertices_data)); 230 | vertices_data.pSysMem = vertices; 231 | D3DApp::GetD3D11Device()->CreateBuffer(&vertex_buffer_desc, &vertices_data, &m_vertex_buffer); 232 | } 233 | 234 | void PostProcess::InitIndexBuffer() 235 | { 236 | unsigned int indices[] = { 237 | 0, 1, 2, 238 | 0, 2, 3, 239 | }; 240 | 241 | D3D11_BUFFER_DESC index_buffer_desc; 242 | ZeroMemory(&index_buffer_desc, sizeof(index_buffer_desc)); 243 | index_buffer_desc.Usage = D3D11_USAGE_DEFAULT; 244 | index_buffer_desc.ByteWidth = sizeof(indices); 245 | index_buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER; 246 | index_buffer_desc.CPUAccessFlags = 0; 247 | index_buffer_desc.MiscFlags = 0; 248 | 249 | D3D11_SUBRESOURCE_DATA indices_data; 250 | ZeroMemory(&indices_data, sizeof(indices_data)); 251 | indices_data.pSysMem = indices; 252 | D3DApp::GetD3D11Device()->CreateBuffer(&index_buffer_desc, &indices_data, &m_index_buffer); 253 | } 254 | 255 | void PostProcess::InitVertexShader() 256 | { 257 | ID3DBlob *vertex_shader_buffer = NULL; 258 | D3DX11CompileFromFile( 259 | TEXT("fx/pp_common.hlsl"), 260 | NULL, 261 | NULL, 262 | "vs_main", 263 | "vs_4_0", 264 | 0, 265 | 0, 266 | NULL, 267 | &vertex_shader_buffer, 268 | NULL, 269 | NULL); 270 | 271 | D3DApp::GetD3D11Device()->CreateVertexShader( 272 | vertex_shader_buffer->GetBufferPointer(), 273 | vertex_shader_buffer->GetBufferSize(), 274 | NULL, 275 | &m_vertex_shader); 276 | 277 | // create vertex layout 278 | D3D11_INPUT_ELEMENT_DESC layout[] = { 279 | {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, 280 | {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}, 281 | }; 282 | UINT num_elements = ARRAYSIZE(layout); 283 | D3DApp::GetD3D11Device()->CreateInputLayout( 284 | layout, 285 | num_elements, 286 | vertex_shader_buffer->GetBufferPointer(), 287 | vertex_shader_buffer->GetBufferSize(), 288 | &m_vertex_layout); 289 | 290 | SAFE_RELEASE(vertex_shader_buffer); 291 | } 292 | 293 | void PostProcess::InitRasterState() 294 | { 295 | CD3D11_RASTERIZER_DESC raster_state_desc(D3D11_DEFAULT); 296 | raster_state_desc.CullMode = D3D11_CULL_NONE; 297 | raster_state_desc.DepthClipEnable = false; 298 | D3DApp::GetD3D11Device()->CreateRasterizerState(&raster_state_desc, &m_raster_state); 299 | } 300 | 301 | void PostProcess::InitBlendState(bool blend_enable) 302 | { 303 | D3D11_BLEND_DESC blend_desc; 304 | D3D11_RENDER_TARGET_BLEND_DESC target_blend_desc; 305 | target_blend_desc.BlendEnable = blend_enable; 306 | target_blend_desc.SrcBlend = D3D11_BLEND_SRC_ALPHA; 307 | target_blend_desc.DestBlend = D3D11_BLEND_INV_SRC_ALPHA; 308 | target_blend_desc.BlendOp = D3D11_BLEND_OP_ADD; 309 | target_blend_desc.SrcBlendAlpha = D3D11_BLEND_ONE; 310 | target_blend_desc.DestBlendAlpha = D3D11_BLEND_ZERO; 311 | target_blend_desc.BlendOpAlpha = D3D11_BLEND_OP_ADD; 312 | target_blend_desc.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; 313 | 314 | blend_desc.AlphaToCoverageEnable = false; 315 | blend_desc.IndependentBlendEnable = false; 316 | blend_desc.RenderTarget[0] = target_blend_desc; 317 | D3DApp::GetD3D11Device()->CreateBlendState(&blend_desc, &m_blend_state); 318 | } 319 | 320 | void PostProcess::InitSamplerState() 321 | { 322 | CD3D11_SAMPLER_DESC sampler_desc(D3D11_DEFAULT); 323 | sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; 324 | sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; 325 | sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; 326 | D3DApp::GetD3D11Device()->CreateSamplerState(&sampler_desc, &m_sampler_state); 327 | } 328 | 329 | void PostProcess::InitDepthStencilState() 330 | { 331 | CD3D11_DEPTH_STENCIL_DESC ds_desc(D3D11_DEFAULT); 332 | ds_desc.DepthEnable = FALSE; 333 | D3DApp::GetD3D11Device()->CreateDepthStencilState(&ds_desc, &m_depth_stencil_state); 334 | } 335 | -------------------------------------------------------------------------------- /src/post_process.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _POST_PROCESS_INCLUDED_HPP_ 2 | #define _POST_PROCESS_INCLUDED_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | class PostProcess; 8 | typedef boost::shared_ptr PostProcessPtr; 9 | 10 | class PostProcess 11 | { 12 | struct Vertex { 13 | float3 pos; 14 | float2 tex; 15 | }; 16 | 17 | public: 18 | PostProcess(bool blend_enable = false); 19 | virtual ~PostProcess(); 20 | 21 | public: 22 | void Apply() const; 23 | 24 | bool LoadPixelShaderFromFile(const tstring& file_name, const tstring& entry_point); 25 | bool LoadPixelShaderFromMemory(const tstring& shader_content, const tstring& entry_point); 26 | tstring GetErrorMessage() const; 27 | 28 | void InputPin(int slot, ID3D11ShaderResourceView* srv); 29 | void OutputPin(int slot, ID3D11RenderTargetView* rtv); 30 | void SetParameters(int slot, ID3D11Buffer* cbuffer); 31 | 32 | private: 33 | void InitVertexBuffer(); 34 | void InitIndexBuffer(); 35 | void InitVertexShader(); 36 | 37 | void InitRasterState(); 38 | void InitBlendState(bool blend_enable); 39 | void InitSamplerState(); 40 | void InitDepthStencilState(); 41 | 42 | private: 43 | ID3D11Buffer* m_vertex_buffer; 44 | ID3D11Buffer* m_index_buffer; 45 | 46 | ID3D11VertexShader* m_vertex_shader; 47 | ID3D11PixelShader* m_pixel_shader; 48 | ID3D11InputLayout* m_vertex_layout; 49 | 50 | ID3D11RasterizerState* m_raster_state; 51 | ID3D11BlendState* m_blend_state; 52 | ID3D11SamplerState* m_sampler_state; 53 | ID3D11DepthStencilState* m_depth_stencil_state; 54 | tstring m_error_message; 55 | 56 | std::map m_input_pins; 57 | std::map m_output_pins; 58 | }; 59 | 60 | #endif // _POST_PROCESS_INCLUDED_HPP_ -------------------------------------------------------------------------------- /src/shader_header.cpp: -------------------------------------------------------------------------------- 1 | #include "common.hpp" 2 | #include "shader_header.hpp" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace ShaderHeader 9 | { 10 | static const tstring headers[] = 11 | { 12 | TEXT("snoise.hlsl"), 13 | TEXT("qnoise.hlsl"), 14 | }; 15 | 16 | static tstring g_shader_header; 17 | static size_t g_num_lines; 18 | 19 | void InitShaderHeader() 20 | { 21 | for (int i = 0; i != ARRAYSIZE(headers); ++i) 22 | { 23 | tstring file_path = TEXT("fx/") + headers[i]; 24 | std::ifstream ifs(file_path.c_str()); 25 | if (!ifs.is_open()) return; 26 | 27 | ifs.seekg(0, std::ios::end); 28 | int length = static_cast(ifs.tellg()); 29 | 30 | std::vector buffer(length + 1); 31 | ifs.seekg(0, std::ios::beg); 32 | ifs.read(&buffer[0], length); 33 | ifs.close(); 34 | 35 | g_shader_header.append(&buffer[0]); 36 | } 37 | 38 | g_shader_header.append(1, '\n'); 39 | g_num_lines = std::count_if(g_shader_header.begin(), g_shader_header.end(), 40 | [](tchar c){return c == '\n';}); 41 | } 42 | 43 | const tstring& GetHeaderText() 44 | { 45 | return g_shader_header; 46 | } 47 | 48 | size_t GetHeaderLines() 49 | { 50 | return g_num_lines; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/shader_header.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _SHADER_HEADER_HPP_INCLUDED_ 2 | #define _SHADER_HEADER_HPP_INCLUDED_ 3 | 4 | #include "common.hpp" 5 | 6 | namespace ShaderHeader 7 | { 8 | void InitShaderHeader(); 9 | 10 | const tstring& GetHeaderText(); 11 | 12 | size_t GetHeaderLines(); 13 | } 14 | 15 | #endif // _SHADER_HEADER_HPP_INCLUDED_ 16 | -------------------------------------------------------------------------------- /src/sound_player.cpp: -------------------------------------------------------------------------------- 1 | #include "common.hpp" 2 | #include "sound_player.hpp" 3 | 4 | #include 5 | 6 | ////////////////////////////////////////////////////////////////////////// 7 | // constructor / destructor 8 | ////////////////////////////////////////////////////////////////////////// 9 | SoundPlayer::SoundPlayer() 10 | : m_system(NULL) 11 | , m_sound(NULL) 12 | , m_channel(NULL) 13 | { 14 | 15 | } 16 | 17 | SoundPlayer::~SoundPlayer() 18 | { 19 | if (m_sound != NULL) 20 | { 21 | m_sound->release(); 22 | m_sound = NULL; 23 | } 24 | 25 | if (m_system != NULL) 26 | { 27 | m_system->release(); 28 | m_system = NULL; 29 | } 30 | } 31 | 32 | ////////////////////////////////////////////////////////////////////////// 33 | // public interfaces 34 | ////////////////////////////////////////////////////////////////////////// 35 | bool SoundPlayer::Initialize() 36 | { 37 | FMOD_RESULT result; 38 | result = FMOD::System_Create(&m_system); 39 | if (result != FMOD_OK) return false; 40 | 41 | m_system->init(32, FMOD_INIT_NORMAL, 0); 42 | if (result != FMOD_OK) return false; 43 | return true; 44 | } 45 | 46 | void SoundPlayer::Update(float delta_time) 47 | { 48 | m_system->update(); 49 | } 50 | 51 | void SoundPlayer::PlaySound(const tstring& file_path, bool loop /* = false */) 52 | { 53 | FMOD_RESULT result; 54 | FMOD_MODE mode = FMOD_SOFTWARE; 55 | if (loop) mode |= FMOD_LOOP_NORMAL; 56 | 57 | if (m_sound != NULL) m_sound->release(); 58 | result = m_system->createStream(file_path.c_str(), mode, 0, &m_sound); 59 | if (result != FMOD_OK) return; 60 | 61 | result = m_system->playSound(FMOD_CHANNEL_FREE, m_sound, false, &m_channel); 62 | if (result != FMOD_OK) return; 63 | } 64 | 65 | void SoundPlayer::GetSpectrum(size_t num_sections, std::vector &out_spectrum) 66 | { 67 | std::vector spectrum_l(num_sections); 68 | std::vector spectrum_r(num_sections); 69 | 70 | m_system->getSpectrum(&spectrum_l[0], num_sections, 0, FMOD_DSP_FFT_WINDOW_RECT); 71 | m_system->getSpectrum(&spectrum_r[0], num_sections, 1, FMOD_DSP_FFT_WINDOW_RECT); 72 | 73 | out_spectrum.resize(num_sections); 74 | for (size_t i = 0; i != num_sections; ++i) 75 | { 76 | out_spectrum[i] = (spectrum_l[i] + spectrum_r[i]) * 0.5f; 77 | } 78 | } 79 | 80 | bool SoundPlayer::GetMute() const 81 | { 82 | if (m_channel) 83 | { 84 | bool mute; 85 | m_channel->getMute(&mute); 86 | return mute; 87 | } 88 | return true; 89 | } 90 | 91 | void SoundPlayer::SetMute(bool mute) 92 | { 93 | if (m_channel) 94 | { 95 | m_channel->setMute(mute); 96 | } 97 | } 98 | 99 | void SoundPlayer::ChangeVolume(float delta_volume) 100 | { 101 | if (m_channel) 102 | { 103 | float volume; 104 | m_channel->getVolume(&volume); 105 | volume += delta_volume; 106 | if (volume < 0.0f) volume = 0.0f; 107 | if (volume > 1.0f) volume = 1.0f; 108 | m_channel->setVolume(volume); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/sound_player.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _SOUND_PLAYER_INCLUDED_HPP_ 2 | #define _SOUND_PLAYER_INCLUDED_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | class SoundPlayer; 8 | typedef boost::shared_ptr SoundPlayerPtr; 9 | 10 | namespace FMOD 11 | { 12 | class System; 13 | class Sound; 14 | class Channel; 15 | } 16 | 17 | class SoundPlayer 18 | { 19 | public: 20 | SoundPlayer(); 21 | virtual ~SoundPlayer(); 22 | 23 | public: 24 | bool Initialize(); 25 | void Update(float delta_time); 26 | 27 | void PlaySound(const tstring& file_path, bool loop = false); 28 | 29 | bool GetMute() const; 30 | void SetMute(bool mute); 31 | void ChangeVolume(float delta_volume); 32 | 33 | void GetSpectrum(size_t num_sections, std::vector &out_spectrum); 34 | 35 | private: 36 | FMOD::System* m_system; 37 | FMOD::Sound* m_sound; 38 | FMOD::Channel* m_channel; 39 | }; 40 | 41 | #endif // _SOUND_PLAYER_INCLUDED_HPP_ -------------------------------------------------------------------------------- /src/syntax_highlighter.cpp: -------------------------------------------------------------------------------- 1 | #include "common.hpp" 2 | #include "syntax_highlighter.hpp" 3 | 4 | #include "keywords.hpp" 5 | #include 6 | #include 7 | 8 | ////////////////////////////////////////////////////////////////////////// 9 | // constructor / destructor 10 | ////////////////////////////////////////////////////////////////////////// 11 | SyntaxHighlighter::SyntaxHighlighter() 12 | { 13 | 14 | } 15 | 16 | SyntaxHighlighter::~SyntaxHighlighter() 17 | { 18 | 19 | } 20 | 21 | SyntaxHighlighter:: 22 | Token::Token(const std::wstring& text, size_t start, size_t end, 23 | TokenType type, size_t depth, size_t indent) 24 | : start_pos(start) 25 | , end_pos(end) 26 | , type(type) 27 | , depth(depth) 28 | , indent(indent) 29 | { 30 | word = text.substr(start_pos, end_pos - start_pos); 31 | } 32 | 33 | SyntaxHighlighter:: 34 | DrawStyle::DrawStyle(const float3& color, bool bold, bool underlined) 35 | : color(color) 36 | , bold(bold) 37 | , underlined(underlined) 38 | , brush(NULL) 39 | { 40 | 41 | } 42 | 43 | SyntaxHighlighter:: 44 | DrawStyle::~DrawStyle() 45 | { 46 | SAFE_RELEASE(brush); 47 | } 48 | 49 | ////////////////////////////////////////////////////////////////////////// 50 | // public interfaces 51 | ////////////////////////////////////////////////////////////////////////// 52 | void SyntaxHighlighter::Intialize(ID2D1RenderTarget* d2d_rt) 53 | { 54 | m_keywords_set.clear(); 55 | m_keywords_set.insert(kewords, kewords + ARRAYSIZE(kewords)); 56 | 57 | m_semantics_set.clear(); 58 | m_semantics_set.insert(semantics, semantics + ARRAYSIZE(semantics)); 59 | 60 | m_global_funcs_set.clear(); 61 | m_global_funcs_set.insert(global_funcs, global_funcs + ARRAYSIZE(global_funcs)); 62 | m_global_funcs_set.insert(extend_funcs, extend_funcs + ARRAYSIZE(extend_funcs)); 63 | 64 | m_member_funcs_set.clear(); 65 | m_member_funcs_set.insert(member_funcs, member_funcs + ARRAYSIZE(member_funcs)); 66 | 67 | InitDrawStyles(d2d_rt); 68 | } 69 | 70 | void SyntaxHighlighter::Hightlight(const std::wstring& text, size_t start_pos, size_t end_pos, size_t caret_pos, IDWriteTextLayout* layout) 71 | { 72 | Parse(text); 73 | 74 | for (int i = 0; i != m_tokens.size(); ++i) 75 | { 76 | Token& tok = m_tokens[i]; 77 | DrawStyle& style = m_draw_styles[tok.type]; 78 | 79 | if (tok.end_pos < start_pos) continue; 80 | if (tok.start_pos >= end_pos) break; 81 | 82 | size_t range_start = tok.start_pos > start_pos ? tok.start_pos - start_pos : 0; 83 | size_t range_end = tok.end_pos < end_pos ? tok.end_pos - start_pos : end_pos - start_pos; 84 | DWRITE_TEXT_RANGE range = {range_start, range_end - range_start}; 85 | 86 | layout->SetDrawingEffect(style.brush, range); 87 | 88 | if (style.bold) 89 | { 90 | layout->SetFontWeight(DWRITE_FONT_WEIGHT_BOLD, range); 91 | } 92 | if (style.underlined) 93 | { 94 | layout->SetUnderline(true, range); 95 | } 96 | } 97 | 98 | // highlight the active scope. 99 | size_t caret_depth = FetchDepth(caret_pos); 100 | for (int i = FetchTokenBackward(caret_pos); i >= 0; --i) 101 | { 102 | Token& tok = m_tokens[i]; 103 | if (tok.end_pos < start_pos) break; 104 | 105 | if (tok.type == TT_Separator && tok.depth < caret_depth) 106 | { 107 | size_t range_start = tok.start_pos > start_pos ? tok.start_pos - start_pos : 0; 108 | size_t range_end = tok.end_pos < end_pos ? tok.end_pos - start_pos : end_pos - start_pos; 109 | DWRITE_TEXT_RANGE range = {range_start, range_end - range_start}; 110 | 111 | layout->SetFontWeight(DWRITE_FONT_WEIGHT_BOLD, range); 112 | break; 113 | } 114 | } 115 | 116 | for (int i = FetchTokenForward(caret_pos); i != m_tokens.size(); ++i) 117 | { 118 | Token& tok = m_tokens[i]; 119 | if (tok.start_pos >= end_pos) break; 120 | 121 | if (tok.type == TT_Separator && tok.depth < caret_depth) 122 | { 123 | size_t range_start = tok.start_pos > start_pos ? tok.start_pos - start_pos : 0; 124 | size_t range_end = tok.end_pos < end_pos ? tok.end_pos - start_pos : end_pos - start_pos; 125 | DWRITE_TEXT_RANGE range = {range_start, range_end - range_start}; 126 | 127 | layout->SetFontWeight(DWRITE_FONT_WEIGHT_BOLD, range); 128 | break; 129 | } 130 | } 131 | 132 | return; 133 | } 134 | 135 | size_t SyntaxHighlighter::GetNumberTokens() const 136 | { 137 | return m_tokens.size(); 138 | } 139 | 140 | const SyntaxHighlighter::Token& SyntaxHighlighter::GetToken(size_t idx) const 141 | { 142 | return m_tokens[idx]; 143 | } 144 | 145 | int SyntaxHighlighter::FetchTokenForward(size_t pos) const 146 | { 147 | auto it = std::upper_bound(m_tokens.begin(), m_tokens.end(), pos, 148 | [](size_t lhs, const Token& rhs) {return lhs < rhs.end_pos;}); 149 | return it - m_tokens.begin(); 150 | } 151 | 152 | int SyntaxHighlighter::FetchTokenBackward(size_t pos) const 153 | { 154 | auto it = std::upper_bound(m_tokens.begin(), m_tokens.end(), pos, 155 | [](size_t lhs, const Token& rhs) {return lhs < rhs.start_pos + 1;}); 156 | 157 | if (it == m_tokens.begin()) return -1; 158 | else return it - 1 - m_tokens.begin(); 159 | } 160 | 161 | size_t SyntaxHighlighter::FetchIndent(size_t pos) const 162 | { 163 | int idx = FetchTokenBackward(pos); 164 | if (idx == -1) return 0; 165 | 166 | const Token& tok = m_tokens[idx]; 167 | if (tok.type == TT_Separator && (tok.word == L"{" || tok.word == L"(")) 168 | { 169 | return tok.indent + 1; 170 | } 171 | return tok.indent; 172 | } 173 | 174 | size_t SyntaxHighlighter::FetchDepth(size_t pos) const 175 | { 176 | int idx = FetchTokenBackward(pos); 177 | if (idx == -1) return 0; 178 | 179 | const Token& tok = m_tokens[idx]; 180 | if (tok.type == TT_Separator && (tok.word == L"{" || tok.word == L"(")) 181 | { 182 | return tok.depth + 1; 183 | } 184 | return tok.depth; 185 | } 186 | 187 | ////////////////////////////////////////////////////////////////////////// 188 | // private subroutines 189 | ////////////////////////////////////////////////////////////////////////// 190 | void SyntaxHighlighter::InitDrawStyles(ID2D1RenderTarget* d2d_rt) 191 | { 192 | m_draw_styles.resize(Num_TokenTypes); 193 | 194 | m_draw_styles[TT_Word ] = DrawStyle(float3(1.00f, 1.00f, 1.00f), false, false); 195 | m_draw_styles[TT_Keyword ] = DrawStyle(float3(0.54f, 0.68f, 0.94f), true, false); 196 | m_draw_styles[TT_Constant ] = DrawStyle(float3(0.83f, 0.73f, 0.91f), false, false); 197 | m_draw_styles[TT_Function ] = DrawStyle(float3(0.96f, 0.68f, 0.41f), true , false); 198 | m_draw_styles[TT_Member ] = DrawStyle(float3(0.96f, 0.68f, 0.41f), true , false); 199 | m_draw_styles[TT_Semantic ] = DrawStyle(float3(0.98f, 0.69f, 0.81f), false, false); 200 | m_draw_styles[TT_Comment ] = DrawStyle(float3(0.54f, 0.94f, 0.85f), false, false); 201 | m_draw_styles[TT_Separator ] = DrawStyle(float3(1.00f, 1.00f, 1.00f), false, false); 202 | m_draw_styles[TT_Illegal ] = DrawStyle(float3(1.00f, 1.00f, 1.00f), false, true ); 203 | 204 | // create brushes 205 | for (int i = 0; i != Num_TokenTypes; ++i) 206 | { 207 | DrawStyle& style = m_draw_styles[i]; 208 | D2D1_COLOR_F d2d_color = D2D1::ColorF(style.color.x, style.color.y, style.color.z); 209 | d2d_rt->CreateSolidColorBrush(d2d_color, &style.brush); 210 | } 211 | } 212 | 213 | void SyntaxHighlighter::Parse(const std::wstring& text) 214 | { 215 | m_tokens.clear(); 216 | 217 | size_t pos = 0; 218 | TokenContext context = {TE_Normal, 0, 0}; 219 | 220 | while(pos < text.length()) 221 | { 222 | ParseToken(pos, context, text); 223 | } 224 | } 225 | 226 | void SyntaxHighlighter::ParseToken(size_t &pos, TokenContext& context, const std::wstring& text) 227 | { 228 | wchar_t current_char = text[pos]; 229 | wchar_t next_char = pos + 1 < text.length() ? text[pos + 1] : 0; 230 | 231 | // space 232 | if (isspace(current_char)) 233 | { 234 | if (context.env == TE_LineComment && current_char == '\n') 235 | { 236 | context.env = TE_Normal; 237 | } 238 | pos += 1; 239 | return; 240 | } 241 | 242 | // block comment begin 243 | if (current_char == '/' && next_char == '*') 244 | { 245 | if (context.env != TE_LineComment) context.env = TE_BlockComment; 246 | Token tok(text, pos, pos + 2, TT_Comment); 247 | m_tokens.push_back(tok); 248 | ResolveToken(context, tok); 249 | pos += 2; 250 | return; 251 | } 252 | 253 | // block comment end 254 | if (current_char == '*' && next_char == '/') 255 | { 256 | Token tok(text, pos, pos + 2, TT_Comment); 257 | if (context.env != TE_BlockComment && context.env != TE_LineComment) tok.type = TT_Illegal; 258 | if (context.env == TE_BlockComment) context.env = TE_Normal; 259 | m_tokens.push_back(tok); 260 | ResolveToken(context, tok); 261 | pos += 2; 262 | return; 263 | } 264 | 265 | // line comment 266 | if (current_char == '/' && next_char == '/') 267 | { 268 | if (context.env != TE_BlockComment) context.env = TE_LineComment; 269 | Token tok(text, pos, pos + 2, TT_Comment); 270 | m_tokens.push_back(tok); 271 | ResolveToken(context, tok); 272 | pos += 2; 273 | return; 274 | } 275 | 276 | // word 277 | if (isalpha(current_char) || current_char == '_') 278 | { 279 | int start_pos = pos; 280 | for (pos = pos + 1; pos < text.length(); ++pos) 281 | { 282 | if (!isalnum(text[pos]) && text[pos] != '_') break; 283 | } 284 | 285 | Token tok(text, start_pos, pos, TT_Word); 286 | ResolveToken(context, tok); 287 | m_tokens.push_back(tok); 288 | return; 289 | } 290 | 291 | // literal constant 292 | if (isdigit(current_char) || current_char == '.' && isdigit(next_char)) 293 | { 294 | int start_pos = pos; 295 | bool meet_digit = false; 296 | bool meet_dot = false; 297 | bool meet_exp = false; 298 | bool meet_suffix = false; 299 | bool illegal = false; 300 | for (; pos < text.length() && (isalnum(text[pos]) || text[pos] == '.'); ++pos) 301 | { 302 | if (illegal) continue; 303 | if (meet_suffix) {illegal = true; continue;} 304 | 305 | if (isdigit(text[pos])) 306 | { 307 | meet_digit = true; 308 | } 309 | else if (text[pos] == '.') 310 | { 311 | if (!meet_dot && !meet_exp) meet_dot = true; 312 | else illegal = true; 313 | } 314 | else if (isalpha(text[pos])) 315 | { 316 | if (!meet_digit) illegal = true; 317 | else if (tolower(text[pos]) == 'f') meet_suffix = true; 318 | else if (!meet_exp && tolower(text[pos]) == 'e') 319 | { 320 | if (pos + 1 < text.length() && text[pos + 1] == '-') ++pos; 321 | if (pos + 1 < text.length() && isdigit(text[pos + 1])) meet_exp = true; 322 | else illegal = true; 323 | } 324 | else illegal = true; 325 | } 326 | } 327 | 328 | Token tok(text, start_pos, pos); 329 | tok.type = illegal ? TT_Illegal : TT_Constant; 330 | ResolveToken(context, tok); 331 | m_tokens.push_back(tok); 332 | return; 333 | } 334 | 335 | // other separators 336 | { 337 | Token tok(text, pos, pos + 1, TT_Separator); 338 | ResolveToken(context, tok); 339 | m_tokens.push_back(tok); 340 | pos += 1; 341 | return; 342 | } 343 | } 344 | 345 | void SyntaxHighlighter::ResolveToken(TokenContext& context, Token &tok) 346 | { 347 | tok.depth = context.depth; 348 | tok.indent = context.indent; 349 | 350 | const std::wstring& word = tok.word; 351 | if (context.env == TE_LineComment || context.env == TE_BlockComment) 352 | { 353 | tok.type = TT_Comment; 354 | } 355 | else if (context.env == TE_Dot) 356 | { 357 | context.env = TE_Normal; 358 | if (tok.type == TT_Word) 359 | { 360 | if (m_member_funcs_set.find(word) != m_member_funcs_set.end()) tok.type = TT_Member; 361 | } 362 | else tok.type = TT_Illegal; 363 | } 364 | else if (context.env == TE_Colon) 365 | { 366 | context.env = TE_Normal; 367 | if (tok.type == TT_Word) 368 | { 369 | std::wstring word_lower_case = word; 370 | std::transform(word.begin(), word.end(), word_lower_case.begin(), ::tolower); 371 | 372 | if (m_semantics_set.find(word_lower_case) != m_semantics_set.end()) tok.type = TT_Semantic; 373 | else if (m_keywords_set.find(word) != m_keywords_set.end()) tok.type = TT_Keyword; 374 | else if (m_global_funcs_set.find(word) != m_global_funcs_set.end()) tok.type = TT_Function; 375 | } 376 | } 377 | else if (context.env == TE_Normal) 378 | { 379 | if (tok.type == TT_Separator) 380 | { 381 | if (word == L".") context.env = TE_Dot; 382 | else if (word == L":") context.env = TE_Colon; 383 | else if (word == L"{" || word == L"(") 384 | { 385 | context.depth += 1; 386 | if (word == L"{") context.indent += 1; 387 | } 388 | else if (word == L"}" || word == L")") 389 | { 390 | if (context.depth > 0) context.depth -= 1; 391 | if (word == L"}" && context.indent > 0) context.indent -= 1; 392 | tok.depth = context.depth; 393 | tok.indent = context.indent; 394 | } 395 | } 396 | 397 | if (tok.type == TT_Word) 398 | { 399 | if (m_keywords_set.find(word) != m_keywords_set.end()) tok.type = TT_Keyword; 400 | else if (m_global_funcs_set.find(word) != m_global_funcs_set.end()) tok.type = TT_Function; 401 | } 402 | } 403 | } 404 | -------------------------------------------------------------------------------- /src/syntax_highlighter.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _SYNTAX_HIGHLIGHTER_INCLUDED_HPP_ 2 | #define _SYNTAX_HIGHLIGHTER_INCLUDED_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | class SyntaxHighlighter 8 | { 9 | public: 10 | enum TokenEnv 11 | { 12 | TE_Normal, 13 | TE_Dot, 14 | TE_Colon, 15 | TE_LineComment, 16 | TE_BlockComment, 17 | }; 18 | 19 | struct TokenContext 20 | { 21 | TokenEnv env; 22 | size_t depth; 23 | size_t indent; 24 | }; 25 | 26 | enum TokenType 27 | { 28 | TT_Word, 29 | TT_Keyword, 30 | TT_Constant, 31 | TT_Function, 32 | TT_Member, 33 | TT_Semantic, 34 | TT_Comment, 35 | TT_Separator, 36 | TT_Illegal, 37 | Num_TokenTypes, 38 | }; 39 | 40 | struct Token 41 | { 42 | size_t start_pos; 43 | size_t end_pos; 44 | std::wstring word; 45 | 46 | TokenType type; 47 | size_t depth; 48 | size_t indent; 49 | 50 | Token(const std::wstring& text, size_t start, size_t end, 51 | TokenType type = TT_Word, size_t depth = 0, size_t indent = 0); 52 | }; 53 | 54 | struct DrawStyle 55 | { 56 | float3 color; 57 | bool bold; 58 | bool underlined; 59 | ID2D1SolidColorBrush* brush; 60 | 61 | DrawStyle(const float3& color = float3(), bool bold = false, bool underlined = false); 62 | ~DrawStyle(); 63 | }; 64 | 65 | public: 66 | SyntaxHighlighter(); 67 | virtual ~SyntaxHighlighter(); 68 | 69 | public: 70 | void Intialize(ID2D1RenderTarget* d2d_rt); 71 | void Hightlight(const std::wstring& text, size_t start_pos, size_t end_pos, size_t caret_pos, IDWriteTextLayout* layout); 72 | 73 | size_t GetNumberTokens() const; 74 | const Token& GetToken(size_t idx) const; 75 | 76 | int FetchTokenForward(size_t pos) const; 77 | int FetchTokenBackward(size_t pos) const; 78 | 79 | size_t FetchIndent(size_t pos) const; 80 | size_t FetchDepth(size_t pos) const; 81 | 82 | private: 83 | void InitDrawStyles(ID2D1RenderTarget* d2d_rt); 84 | 85 | void Parse(const std::wstring& text); 86 | void ParseToken(size_t &pos, TokenContext& context, const std::wstring& text); 87 | 88 | void ResolveToken(TokenContext& context, Token& tok); 89 | 90 | private: 91 | std::set m_keywords_set; 92 | std::set m_semantics_set; 93 | std::set m_global_funcs_set; 94 | std::set m_member_funcs_set; 95 | 96 | std::vector m_tokens; 97 | std::vector m_draw_styles; 98 | }; 99 | 100 | #endif // _SYNTAX_HIGHLIGHTER_INCLUDED_HPP_ -------------------------------------------------------------------------------- /src/text_editor.cpp: -------------------------------------------------------------------------------- 1 | #include "common.hpp" 2 | #include "text_editor.hpp" 3 | #include "d3d_app.hpp" 4 | #include "shader_header.hpp" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | ////////////////////////////////////////////////////////////////////////// 11 | // default shader content 12 | ////////////////////////////////////////////////////////////////////////// 13 | const wchar_t default_shader_content[] = 14 | L"cbuffer Parameters : register(b0)\n" 15 | L"{\n" 16 | L" float4 time; // (app time, 0, 0, 0)\n" 17 | L" float4 view; // (view width, view height, 1 / width, 1 / height)\n" 18 | L" float4 freq; // (bass, low, mid, high) freq part of the background music\n" 19 | L" float4 mpos; // (mouse.x, mouse.y, mouse.wheel, 0)\n" 20 | L"}\n" 21 | L"\n" 22 | L"float4 ps_main(in float2 tc : TEXCOORD) : SV_TARGET\n" 23 | L"{\n" 24 | L" return float4(0.3, 0.3, 0.3, 1);\n" 25 | L"}\n" 26 | ; 27 | 28 | const size_t MAX_NUM_LINES = 25; 29 | 30 | ////////////////////////////////////////////////////////////////////////// 31 | // constructor / destructor 32 | ////////////////////////////////////////////////////////////////////////// 33 | TextEditor::TextEditor() 34 | : m_text_format(NULL) 35 | , m_text_format_small(NULL) 36 | , m_text_layout(NULL) 37 | , m_default_brush(NULL) 38 | , m_line_offset(0) 39 | { 40 | 41 | } 42 | 43 | TextEditor::~TextEditor() 44 | { 45 | SAFE_RELEASE(m_text_format); 46 | SAFE_RELEASE(m_text_format_small); 47 | SAFE_RELEASE(m_text_layout); 48 | SAFE_RELEASE(m_default_brush); 49 | } 50 | 51 | TextEditor::CompileError::CompileError() 52 | { 53 | Clear(); 54 | } 55 | 56 | void TextEditor::CompileError::Clear() 57 | { 58 | row = -1; 59 | column = -1; 60 | message.clear(); 61 | 62 | remain_time = 0; 63 | is_located = false; 64 | location = float2(0, 0); 65 | alpha = 0; 66 | } 67 | 68 | ////////////////////////////////////////////////////////////////////////// 69 | // public interfaces 70 | ////////////////////////////////////////////////////////////////////////// 71 | bool TextEditor::Initialize(ID2D1RenderTarget* d2d_rt) 72 | { 73 | HRESULT hr = S_OK; 74 | 75 | // create text format 76 | hr = D3DApp::GetDWriteFactory()->CreateTextFormat( 77 | L"Consolas", 78 | NULL, 79 | DWRITE_FONT_WEIGHT_REGULAR, 80 | DWRITE_FONT_STYLE_NORMAL, 81 | DWRITE_FONT_STRETCH_NORMAL, 82 | 16.0f, 83 | L"en-us", 84 | &m_text_format); 85 | 86 | if (FAILED(hr)) 87 | { 88 | return false; 89 | } 90 | 91 | m_text_format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); 92 | m_text_format->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR); 93 | m_text_format->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP); 94 | 95 | // create text format (small) 96 | hr = D3DApp::GetDWriteFactory()->CreateTextFormat( 97 | L"Consolas", 98 | NULL, 99 | DWRITE_FONT_WEIGHT_REGULAR, 100 | DWRITE_FONT_STYLE_NORMAL, 101 | DWRITE_FONT_STRETCH_NORMAL, 102 | 13.0f, 103 | L"en-us", 104 | &m_text_format_small); 105 | 106 | if (FAILED(hr)) 107 | { 108 | return false; 109 | } 110 | 111 | m_text_format_small->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); 112 | m_text_format_small->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR); 113 | m_text_format_small->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP); 114 | 115 | // init editable text 116 | m_editable_text.SetText(default_shader_content); 117 | 118 | // create text layout 119 | const int text_box_width = D3DApp::GetApp()->GetWidth() - 300; 120 | const int text_box_height = D3DApp::GetApp()->GetHeight() - 300; 121 | hr = D3DApp::GetDWriteFactory()->CreateTextLayout( 122 | m_editable_text.GetText().c_str(), 123 | m_editable_text.GetText().length(), 124 | m_text_format, 125 | static_cast(text_box_width), 126 | static_cast(text_box_height), 127 | &m_text_layout); 128 | 129 | if (FAILED(hr)) 130 | { 131 | return false; 132 | } 133 | 134 | // create default brush 135 | hr = d2d_rt->CreateSolidColorBrush(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f), &m_default_brush); 136 | if (FAILED(hr)) 137 | { 138 | return false; 139 | } 140 | 141 | // init syntax highlighter 142 | m_syntax_hightlighter.Intialize(d2d_rt); 143 | RefreshTextLayout(); 144 | 145 | // init common headers for shader 146 | ShaderHeader::InitShaderHeader(); 147 | 148 | return true; 149 | } 150 | 151 | void TextEditor::Update(float delta_time) 152 | { 153 | m_caret_idle_time += delta_time; 154 | 155 | if (m_compile_error.remain_time > 0) 156 | { 157 | m_compile_error.remain_time -= delta_time; 158 | 159 | if (m_compile_error.remain_time > 1.0f) 160 | { 161 | m_compile_error.alpha = 1.0f; 162 | } 163 | else 164 | { 165 | m_compile_error.alpha = m_compile_error.remain_time; 166 | } 167 | } 168 | } 169 | 170 | void TextEditor::Render(ID2D1RenderTarget* d2d_rt) const 171 | { 172 | D2D1_RECT_F rect = D2D1::RectF(100, 100, 200 + m_text_layout->GetMaxWidth(), 200 + m_text_layout->GetMaxHeight()); 173 | 174 | // draw dynamic boarder 175 | d2d_rt->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); 176 | m_default_brush->SetColor(D2D1::ColorF(0.0f, 0.0f, 0.0f, 0.6f)); 177 | float margin = cos(D3DApp::GetTimer()->GetTime() * 5) * 2 + 4; 178 | D2D1_RECT_F rect_dyn = D2D1::RectF(rect.left - margin, rect.top - margin, rect.right + margin, rect.bottom + margin); 179 | d2d_rt->DrawRectangle(rect_dyn, m_default_brush); 180 | 181 | // draw rect and border 182 | d2d_rt->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); 183 | m_default_brush->SetColor(D2D1::ColorF(0.0f, 0.0f, 0.0f, 0.3f)); 184 | d2d_rt->FillRectangle(rect, m_default_brush); 185 | m_default_brush->SetColor(D2D1::ColorF(0.0f, 0.0f, 0.0f, 0.6f)); 186 | d2d_rt->DrawRectangle(rect, m_default_brush); 187 | 188 | // draw highlighted line's background 189 | m_default_brush->SetColor(D2D1::ColorF(0.0f, 0.0f, 0.0f, 0.5f)); 190 | D2D1_RECT_F rect_line = D2D1::RectF(rect.left, m_caret_loc_hight.y + 150, rect.right, m_caret_loc_hight.y + m_caret_loc_hight.z + 150); 191 | d2d_rt->FillRectangle(rect_line, m_default_brush); 192 | 193 | // draw selected text's background 194 | m_default_brush->SetColor(D2D1::ColorF(0.0f, 0.8f, 0.8f, 0.5f)); 195 | for each(auto &it in m_selection_fields) 196 | { 197 | D2D1_RECT_F field = D2D1::RectF(it.x + 150, it.y + 150, it.x + it.z + 150, it.y + it.w + 150); 198 | d2d_rt->FillRectangle(field, m_default_brush); 199 | } 200 | 201 | // draw text 202 | m_default_brush->SetColor(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f)); 203 | d2d_rt->DrawTextLayout(D2D1::Point2F(150, 150), m_text_layout, m_default_brush); 204 | 205 | // draw caret 206 | m_default_brush->SetColor(D2D1::ColorF(1.0f, 1.0f, 1.0f, abs(cos(m_caret_idle_time * 3.0f)))); 207 | D2D1_POINT_2F pt1 = D2D1::Point2F(m_caret_loc_hight.x + 150, m_caret_loc_hight.y + 150); 208 | D2D1_POINT_2F pt2 = D2D1::Point2F(m_caret_loc_hight.x + 150, m_caret_loc_hight.y + m_caret_loc_hight.z + 150); 209 | d2d_rt->DrawLine(pt1, pt2, m_default_brush, 2.0f); 210 | 211 | // draw compile error tip 212 | if (m_compile_error.alpha > 0) 213 | { 214 | m_default_brush->SetColor(D2D1::ColorF(1.0f, 1.0f, 1.0f, 0.9f * m_compile_error.alpha)); 215 | d2d_rt->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); 216 | float2 error_loc = m_compile_error.location + float2(150, 150); 217 | D2D1_RECT_F err_rect = D2D1::RectF(rect.left, error_loc.y - 16.0f, rect.right, error_loc.y); 218 | D2D1_ROUNDED_RECT tip_rect = D2D1::RoundedRect(err_rect, 3.0f, 3.0f); 219 | d2d_rt->FillRoundedRectangle(tip_rect, m_default_brush); 220 | 221 | m_default_brush->SetColor(D2D1::ColorF(0.7f, 0.0f, 0.0f, m_compile_error.alpha)); 222 | if (!m_compile_error.is_located) 223 | { 224 | m_text_format_small->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER); 225 | } 226 | else if (m_compile_error.location.x > m_text_layout->GetMaxWidth() / 2.0f) 227 | { 228 | m_text_format_small->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); 229 | } 230 | else 231 | { 232 | m_text_format_small->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_TRAILING); 233 | } 234 | 235 | D2D1_RECT_F msg_rect =D2D1::RectF(err_rect.left + 10.0f, err_rect.top, err_rect.right - 10.0f, err_rect.bottom); 236 | d2d_rt->DrawTextA(m_compile_error.message.c_str(), m_compile_error.message.length(), m_text_format_small, msg_rect, m_default_brush); 237 | 238 | if (m_compile_error.is_located) 239 | { 240 | float2 arrow_loc = error_loc + float2(0, cos(D3DApp::GetTimer()->GetTime() * 5.0f) * 3.0f - 2.0f); 241 | d2d_rt->DrawLine(D2D1::Point2F(arrow_loc.x, arrow_loc.y), D2D1::Point2F(arrow_loc.x, arrow_loc.y - 12.0f), m_default_brush); 242 | d2d_rt->DrawLine(D2D1::Point2F(arrow_loc.x, arrow_loc.y), D2D1::Point2F(arrow_loc.x - 4.0f, arrow_loc.y - 5.0f), m_default_brush); 243 | d2d_rt->DrawLine(D2D1::Point2F(arrow_loc.x, arrow_loc.y), D2D1::Point2F(arrow_loc.x + 4.0f, arrow_loc.y - 5.0f), m_default_brush); 244 | } 245 | } 246 | } 247 | 248 | const std::wstring& TextEditor::GetText() const 249 | { 250 | return m_editable_text.GetText(); 251 | } 252 | 253 | void TextEditor::NewFile() 254 | { 255 | if (!m_file_path.empty()) 256 | { 257 | SaveFile(); 258 | m_file_path.clear(); 259 | } 260 | m_editable_text.MoveTextBegin(); 261 | m_editable_text.MoveTextEnd(true); 262 | m_editable_text.InsertText(default_shader_content); 263 | m_editable_text.SetCaretPos(0); 264 | RefreshTextLayout(); 265 | ReloadPixelShader(); 266 | } 267 | 268 | void TextEditor::OpenFile() 269 | { 270 | OPENFILENAMEW ofn; 271 | ZeroMemory(&ofn, sizeof(ofn)); 272 | ofn.lStructSize = sizeof(ofn); 273 | std::vector file_path(512 + 1); 274 | ofn.lpstrFile = &file_path[0]; 275 | ofn.nMaxFile = 512; 276 | 277 | std::vector directory(512 + 1); 278 | GetCurrentDirectoryW(512, &directory[0]); 279 | std::wstring init_dir = std::wstring(&directory[0]) + L"\\save\\"; 280 | ofn.lpstrInitialDir = init_dir.c_str(); 281 | 282 | if (GetOpenFileNameW(&ofn)) 283 | { 284 | m_file_path = std::wstring(&file_path[0]); 285 | 286 | std::wifstream ifs(m_file_path.c_str()); 287 | if (!ifs.is_open()) return; 288 | 289 | ifs.seekg(0, std::ios::end); 290 | int length = static_cast(ifs.tellg()); 291 | 292 | std::vector buffer(length + 1); 293 | ifs.seekg(0, std::ios::beg); 294 | ifs.read(&buffer[0], length); 295 | ifs.close(); 296 | 297 | m_editable_text.SetText(std::wstring(&buffer[0])); 298 | } 299 | RefreshTextLayout(); 300 | ReloadPixelShader(); 301 | } 302 | 303 | void TextEditor::SaveFile(bool save_as_new /*= false*/) 304 | { 305 | if (m_file_path.empty() || save_as_new) 306 | { 307 | OPENFILENAMEW ofn; 308 | ZeroMemory(&ofn, sizeof(ofn)); 309 | ofn.lStructSize = sizeof(ofn); 310 | std::vector file_path(512 + 1); 311 | ofn.lpstrFile = &file_path[0]; 312 | ofn.nMaxFile = 512; 313 | 314 | std::vector directory(512 + 1); 315 | GetCurrentDirectoryW(512, &directory[0]); 316 | std::wstring init_dir = std::wstring(&directory[0]) + L"\\save\\"; 317 | ofn.lpstrInitialDir = init_dir.c_str(); 318 | 319 | if (GetSaveFileNameW(&ofn)) 320 | { 321 | m_file_path = std::wstring(&file_path[0]); 322 | } 323 | } 324 | 325 | if (m_file_path.empty()) return; 326 | 327 | std::wofstream ofs(m_file_path.c_str()); 328 | if (!ofs.is_open()) return; 329 | 330 | ofs.write(m_editable_text.GetText().c_str(), m_editable_text.GetText().length()); 331 | ofs.close(); 332 | 333 | ReloadPixelShader(); 334 | } 335 | 336 | bool TextEditor::HandleWindowMessage(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) 337 | { 338 | switch (message) 339 | { 340 | case WM_KEYDOWN: 341 | OnKeyPress(static_cast(wparam)); 342 | return true; 343 | 344 | case WM_CHAR: 345 | OnKeyCharacter(static_cast(wparam)); 346 | return true; 347 | 348 | case WM_LBUTTONDOWN: 349 | case WM_RBUTTONDOWN: 350 | case WM_MBUTTONDOWN: 351 | SetCapture(hwnd); 352 | OnMousePress(message, static_cast(GET_X_LPARAM(lparam)), static_cast(GET_Y_LPARAM(lparam))); 353 | return true; 354 | 355 | case WM_LBUTTONUP: 356 | case WM_RBUTTONUP: 357 | case WM_MBUTTONUP: 358 | ReleaseCapture(); 359 | OnMouseRelease(message, static_cast(GET_X_LPARAM(lparam)), static_cast(GET_Y_LPARAM(lparam))); 360 | return true; 361 | 362 | case WM_LBUTTONDBLCLK: 363 | case WM_MBUTTONDBLCLK: 364 | case WM_RBUTTONDBLCLK: 365 | OnMouseDoubleClick(message, static_cast(GET_X_LPARAM(lparam)), static_cast(GET_Y_LPARAM(lparam))); 366 | return true; 367 | 368 | case WM_MOUSEMOVE: 369 | OnMouseMove(static_cast(GET_X_LPARAM(lparam)), static_cast(GET_Y_LPARAM(lparam))); 370 | return true; 371 | 372 | case WM_MOUSEWHEEL: 373 | OnMouseScroll(0, GET_WHEEL_DELTA_WPARAM(wparam) / static_cast(WHEEL_DELTA)); 374 | return true; 375 | case WM_MOUSEHWHEEL: 376 | OnMouseScroll(GET_WHEEL_DELTA_WPARAM(lparam) / static_cast(WHEEL_DELTA), 0); 377 | return true; 378 | 379 | case WM_MOUSELEAVE: 380 | case WM_CAPTURECHANGED: 381 | OnMouseExit(); 382 | return true; 383 | } 384 | return false; 385 | } 386 | 387 | ////////////////////////////////////////////////////////////////////////// 388 | // private subroutines 389 | ////////////////////////////////////////////////////////////////////////// 390 | void TextEditor::RefreshTextLayout() 391 | { 392 | size_t cur_line = m_editable_text.GetCaretLine(); 393 | if (m_line_offset > cur_line) 394 | { 395 | m_line_offset = cur_line; 396 | } 397 | else if (m_line_offset + MAX_NUM_LINES - 1 < cur_line) 398 | { 399 | m_line_offset = cur_line - MAX_NUM_LINES + 1; 400 | } 401 | 402 | size_t subtext_begin = m_editable_text.GetTextPos(m_line_offset, 0); 403 | size_t subtext_end = m_editable_text.GetTextPos(m_line_offset + MAX_NUM_LINES, 0); 404 | std::wstring subtext = m_editable_text.GetText().substr(subtext_begin, subtext_end - subtext_begin); 405 | IDWriteTextLayout* new_layout = NULL; 406 | HRESULT hr = D3DApp::GetDWriteFactory()->CreateTextLayout( 407 | subtext.c_str(), 408 | subtext.length(), 409 | m_text_format, 410 | static_cast(m_text_layout->GetMaxWidth()), 411 | static_cast(m_text_layout->GetMaxHeight()), 412 | &new_layout); 413 | 414 | if (SUCCEEDED(hr)) 415 | { 416 | SAFE_RELEASE(m_text_layout); 417 | m_text_layout = new_layout; 418 | m_syntax_hightlighter.Hightlight( 419 | m_editable_text.GetText(), 420 | subtext_begin, subtext_end, 421 | m_editable_text.GetCaretPos(), 422 | m_text_layout); 423 | 424 | // get the caret location 425 | { 426 | DWRITE_HIT_TEST_METRICS hit_test_metrics; 427 | m_text_layout->HitTestTextPosition( 428 | m_editable_text.GetCaretPos() - subtext_begin, 429 | false, 430 | &m_caret_loc_hight.x, 431 | &m_caret_loc_hight.y, 432 | &hit_test_metrics); 433 | 434 | m_caret_loc_hight.z = hit_test_metrics.height; 435 | } 436 | 437 | // get the selection ranges 438 | m_selection_fields.clear(); 439 | EditableText::Selection selection = m_editable_text.GetSelection(); 440 | if (selection.IsValid()) 441 | { 442 | size_t left = std::min(selection.start_pos, selection.end_pos); 443 | size_t right = std::max(selection.start_pos, selection.end_pos); 444 | left = left > subtext_begin ? left - subtext_begin : 0; 445 | right = right < subtext_end ? right - subtext_begin : subtext_end - subtext_begin; 446 | 447 | UINT32 num_sections; 448 | m_text_layout->HitTestTextRange( 449 | left, 450 | right - left, 451 | 0, 452 | 0, 453 | NULL, 454 | 0, 455 | &num_sections); 456 | 457 | std::vector hit_test_metrics(num_sections); 458 | m_text_layout->HitTestTextRange( 459 | left, 460 | right - left, 461 | 0, 462 | 0, 463 | &hit_test_metrics[0], 464 | static_cast(hit_test_metrics.size()), 465 | &num_sections); 466 | 467 | m_selection_fields.resize(num_sections); 468 | for (int i = 0; i != m_selection_fields.size(); ++i) 469 | { 470 | m_selection_fields[i].x = hit_test_metrics[i].left; 471 | m_selection_fields[i].y = hit_test_metrics[i].top; 472 | m_selection_fields[i].z = hit_test_metrics[i].width; 473 | m_selection_fields[i].w = hit_test_metrics[i].height; 474 | } 475 | } 476 | } 477 | 478 | m_caret_idle_time = 0; 479 | } 480 | 481 | void TextEditor::OnMousePress(UINT message, float x, float y) 482 | { 483 | 484 | } 485 | 486 | void TextEditor::OnMouseRelease(UINT message, float x, float y) 487 | { 488 | 489 | } 490 | 491 | void TextEditor::OnMouseDoubleClick( UINT message, float x, float y ) 492 | { 493 | 494 | } 495 | 496 | void TextEditor::OnMouseMove(float x, float y) 497 | { 498 | 499 | } 500 | 501 | void TextEditor::OnMouseScroll(float x_scroll, float y_scroll) 502 | { 503 | 504 | } 505 | 506 | void TextEditor::OnMouseExit() 507 | { 508 | 509 | } 510 | 511 | void TextEditor::OnKeyPress(UINT32 key_code) 512 | { 513 | bool held_shift = (GetKeyState(VK_SHIFT) & 0x80) != 0; 514 | bool held_control = (GetKeyState(VK_CONTROL) & 0x80) != 0; 515 | 516 | switch (key_code) 517 | { 518 | case VK_RETURN: 519 | if (held_control && held_shift) 520 | { 521 | m_editable_text.MoveLineEnd(); 522 | m_editable_text.InsertChar('\n'); 523 | } 524 | else if (held_control) 525 | { 526 | m_editable_text.MoveLineBegin(); 527 | m_editable_text.InsertChar('\n'); 528 | m_editable_text.MoveCharLeft(); 529 | } 530 | else 531 | { 532 | m_editable_text.InsertChar('\n'); 533 | } 534 | AutoIndent(); 535 | RefreshTextLayout(); 536 | break; 537 | 538 | case VK_BACK: 539 | if (!m_editable_text.GetSelection().IsValid()) 540 | { 541 | if (held_control) m_editable_text.MoveWordLeft(true); 542 | else m_editable_text.MoveCharLeft(true); 543 | } 544 | m_editable_text.DeleteSelection(); 545 | RefreshTextLayout(); 546 | break; 547 | 548 | case VK_DELETE: 549 | if (!m_editable_text.GetSelection().IsValid()) 550 | { 551 | if (held_control) m_editable_text.MoveWordRight(true); 552 | else m_editable_text.MoveCharRight(true); 553 | } 554 | m_editable_text.DeleteSelection(); 555 | RefreshTextLayout(); 556 | break; 557 | 558 | case VK_LEFT: 559 | if (held_control) 560 | { 561 | m_editable_text.MoveWordLeft(held_shift); 562 | } 563 | else 564 | { 565 | m_editable_text.MoveCharLeft(held_shift); 566 | } 567 | RefreshTextLayout(); 568 | break; 569 | 570 | case VK_RIGHT: 571 | if (held_control) 572 | { 573 | m_editable_text.MoveWordRight(held_shift); 574 | } 575 | else 576 | { 577 | m_editable_text.MoveCharRight(held_shift); 578 | } 579 | RefreshTextLayout(); 580 | break; 581 | 582 | case VK_UP: 583 | m_editable_text.MoveLineUp(held_shift); 584 | RefreshTextLayout(); 585 | break; 586 | 587 | case VK_DOWN: 588 | m_editable_text.MoveLineDown(held_shift); 589 | RefreshTextLayout(); 590 | break; 591 | 592 | case VK_HOME: 593 | if (held_control) 594 | { 595 | m_editable_text.MoveTextBegin(held_shift); 596 | } 597 | else 598 | { 599 | m_editable_text.MoveLineHome(held_shift); 600 | } 601 | RefreshTextLayout(); 602 | break; 603 | 604 | case VK_END: 605 | if (held_control) 606 | { 607 | m_editable_text.MoveTextEnd(held_shift); 608 | } 609 | else 610 | { 611 | m_editable_text.MoveLineEnd(held_shift); 612 | } 613 | RefreshTextLayout(); 614 | break; 615 | 616 | case 'L': 617 | if (held_control) 618 | { 619 | // cut current line (include trailing '\n'). 620 | m_editable_text.MoveLineBegin(); 621 | m_editable_text.MoveLineEnd(true); 622 | m_editable_text.MoveCharRight(true); 623 | m_editable_text.CopyToClipboard(); 624 | m_editable_text.DeleteSelection(); 625 | RefreshTextLayout(); 626 | } 627 | break; 628 | 629 | case 'A': 630 | if (held_control) 631 | { 632 | m_editable_text.MoveTextBegin(); 633 | m_editable_text.MoveTextEnd(true); 634 | RefreshTextLayout(); 635 | } 636 | break; 637 | 638 | case 'C': 639 | if (held_control) 640 | { 641 | // it nothing is selected, copy current line (include trailing '\n'). 642 | if (!m_editable_text.GetSelection().IsValid()) 643 | { 644 | size_t pos = m_editable_text.GetCaretPos(); 645 | m_editable_text.MoveLineBegin(); 646 | m_editable_text.MoveLineEnd(true); 647 | m_editable_text.MoveCharRight(true); 648 | m_editable_text.CopyToClipboard(); 649 | m_editable_text.SetCaretPos(pos); 650 | } 651 | else 652 | { 653 | m_editable_text.CopyToClipboard(); 654 | } 655 | } 656 | break; 657 | 658 | case 'X': 659 | if (held_control) 660 | { 661 | m_editable_text.CopyToClipboard(); 662 | m_editable_text.DeleteSelection(); 663 | RefreshTextLayout(); 664 | } 665 | break; 666 | 667 | case 'V': 668 | if (held_control) 669 | { 670 | m_editable_text.PasteFromClipboard(); 671 | RefreshTextLayout(); 672 | } 673 | break; 674 | 675 | case 'Z': 676 | if (held_control) 677 | { 678 | m_editable_text.Undo(); 679 | RefreshTextLayout(); 680 | } 681 | break; 682 | 683 | case 'Y': 684 | if (held_control) 685 | { 686 | m_editable_text.Redo(); 687 | RefreshTextLayout(); 688 | } 689 | break; 690 | 691 | case VK_TAB: 692 | AutoJumpOver(); 693 | RefreshTextLayout(); 694 | break; 695 | 696 | case VK_OEM_COMMA: 697 | if (held_control) 698 | { 699 | AutoJumpInto(); 700 | RefreshTextLayout(); 701 | } 702 | break; 703 | 704 | case VK_OEM_PERIOD: 705 | if (held_control) 706 | { 707 | AutoJumpOut(); 708 | RefreshTextLayout(); 709 | } 710 | break; 711 | 712 | case VK_F7: 713 | ReloadPixelShader(); 714 | break; 715 | 716 | default: 717 | break; 718 | } 719 | } 720 | 721 | void TextEditor::OnKeyCharacter(UINT32 char_code) 722 | { 723 | // only handle normal characters 724 | if (char_code >= 0x20 && char_code < 0x7F) 725 | { 726 | wchar_t c = static_cast(char_code); 727 | if (c == '{') 728 | { 729 | m_editable_text.InsertText(L"{\n}"); 730 | m_editable_text.MoveCharLeft(); 731 | AutoIndent(); 732 | m_editable_text.MoveLineBegin(); 733 | m_editable_text.MoveCharLeft(); 734 | m_editable_text.InsertChar('\n'); 735 | AutoIndent(); 736 | } 737 | else if (c == '}') 738 | { 739 | m_editable_text.InsertChar(c); 740 | AutoIndent(); 741 | } 742 | else if (c == '(') 743 | { 744 | EditableText::Selection selection = m_editable_text.GetSelection(); 745 | if (selection.IsValid()) 746 | { 747 | size_t left = std::min(selection.start_pos, selection.end_pos); 748 | size_t right = std::max(selection.start_pos, selection.end_pos); 749 | m_editable_text.SetCaretPos(left); 750 | m_editable_text.InsertChar('('); 751 | m_editable_text.SetCaretPos(right + 1); 752 | m_editable_text.InsertChar(')'); 753 | } 754 | else 755 | { 756 | m_editable_text.InsertText(L"()"); 757 | m_editable_text.MoveCharLeft(false); 758 | } 759 | } 760 | else 761 | { 762 | m_editable_text.InsertChar(static_cast(char_code)); 763 | } 764 | RefreshTextLayout(); 765 | } 766 | } 767 | 768 | void TextEditor::AutoIndent() 769 | { 770 | RefreshTextLayout(); 771 | 772 | size_t pos = m_editable_text.GetCaretPos(); 773 | m_editable_text.MoveLineBegin(); 774 | size_t line_begin = m_editable_text.GetCaretPos(); 775 | m_editable_text.MoveLineHome(); 776 | size_t line_home = m_editable_text.GetCaretPos(); 777 | 778 | size_t indent = m_syntax_hightlighter.FetchIndent(line_home + 1); 779 | int num_space_should = indent * 2; 780 | int name_space_have = line_home - line_begin; 781 | 782 | int diff = num_space_should - name_space_have; 783 | if (diff > 0) 784 | { 785 | std::wstring str(diff, ' '); 786 | m_editable_text.InsertText(str); 787 | } 788 | else 789 | { 790 | m_editable_text.SetCaretPos(line_home + diff, true); 791 | m_editable_text.DeleteSelection(); 792 | } 793 | } 794 | 795 | void TextEditor::AutoJumpOver() 796 | { 797 | RefreshTextLayout(); 798 | 799 | if (m_editable_text.GetSelection().IsValid()) 800 | { 801 | m_editable_text.InsertText(L" "); 802 | return; 803 | } 804 | 805 | size_t pos = m_editable_text.GetCaretPos(); 806 | m_editable_text.MoveLineHome(); 807 | size_t line_home = m_editable_text.GetCaretPos(); 808 | if (pos <= line_home) 809 | { 810 | m_editable_text.InsertText(L" "); 811 | return; 812 | } 813 | 814 | m_editable_text.SetCaretPos(pos); 815 | m_editable_text.MoveWordRight(); 816 | size_t jump_pos = m_editable_text.GetCaretPos(); 817 | int idx = m_syntax_hightlighter.FetchTokenBackward(jump_pos); 818 | if (idx != -1) 819 | { 820 | const SyntaxHighlighter::Token& tok = m_syntax_hightlighter.GetToken(idx); 821 | const std::wstring &word = tok.word; 822 | if (word == L"}" || word == L")") jump_pos = tok.end_pos; 823 | else jump_pos = pos; 824 | } 825 | 826 | if (pos == jump_pos) 827 | { 828 | m_editable_text.SetCaretPos(pos); 829 | m_editable_text.InsertText(L" "); 830 | } 831 | else m_editable_text.SetCaretPos(jump_pos); 832 | } 833 | 834 | void TextEditor::AutoJumpInto() 835 | { 836 | RefreshTextLayout(); 837 | 838 | size_t pos = m_editable_text.GetCaretPos(); 839 | size_t depth = m_syntax_hightlighter.FetchDepth(pos); 840 | 841 | int idx = m_syntax_hightlighter.FetchTokenBackward(pos); 842 | for (size_t i = idx + 1; i < m_syntax_hightlighter.GetNumberTokens(); ++i) 843 | { 844 | if (m_syntax_hightlighter.GetToken(i).depth < depth) break; 845 | 846 | if (m_syntax_hightlighter.GetToken(i).depth > depth) 847 | { 848 | pos = m_syntax_hightlighter.GetToken(i).start_pos; 849 | m_editable_text.SetCaretPos(pos); 850 | break; 851 | } 852 | } 853 | } 854 | 855 | void TextEditor::AutoJumpOut() 856 | { 857 | RefreshTextLayout(); 858 | 859 | size_t pos = m_editable_text.GetCaretPos(); 860 | size_t depth = m_syntax_hightlighter.FetchDepth(pos); 861 | 862 | int idx = m_syntax_hightlighter.FetchTokenBackward(pos); 863 | for (size_t i = idx + 1; i < m_syntax_hightlighter.GetNumberTokens(); ++i) 864 | { 865 | if (m_syntax_hightlighter.GetToken(i).depth < depth) 866 | { 867 | pos = m_syntax_hightlighter.GetToken(i).end_pos; 868 | m_editable_text.SetCaretPos(pos); 869 | break; 870 | } 871 | } 872 | } 873 | 874 | void TextEditor::ReloadPixelShader() 875 | { 876 | const std::wstring &text = m_editable_text.GetText(); 877 | tstring shader_content = ShaderHeader::GetHeaderText(); 878 | shader_content.append(text.begin(), text.end()); 879 | 880 | bool compiled_ok = D3DApp::GetPostProcess()->LoadPixelShaderFromMemory(shader_content, TEXT("ps_main")); 881 | if (compiled_ok) 882 | { 883 | m_compile_error.Clear(); 884 | } 885 | else 886 | { 887 | ParseCompileError(D3DApp::GetPostProcess()->GetErrorMessage()); 888 | } 889 | } 890 | 891 | void TextEditor::ParseCompileError(const tstring& fxc_error) 892 | { 893 | m_compile_error.Clear(); 894 | 895 | if (!fxc_error.empty()) 896 | { 897 | std::istringstream iss(fxc_error); 898 | 899 | if (fxc_error[0] == '(') 900 | { 901 | char igored_char; 902 | iss >> igored_char; 903 | iss >> m_compile_error.row >> igored_char >> m_compile_error.column; 904 | iss >> igored_char >> igored_char; 905 | 906 | m_compile_error.row -= 1 + ShaderHeader::GetHeaderLines(); 907 | m_compile_error.column -= 1; 908 | } 909 | 910 | std::string ignored_word; 911 | iss >> ignored_word >> ignored_word; 912 | 913 | assert(iss.good()); 914 | std::wstring message(fxc_error.begin() + static_cast(iss.tellg()), fxc_error.end()); 915 | m_compile_error.message = message.substr(1, message.find_first_of('\n')); 916 | 917 | // calculate error location 918 | if (m_compile_error.row < static_cast(m_line_offset)) 919 | { 920 | m_compile_error.location = float2(0, -20.0f); 921 | } 922 | else if (m_compile_error.row >= static_cast(m_line_offset + MAX_NUM_LINES)) 923 | { 924 | m_compile_error.location = float2(0, m_text_layout->GetMaxHeight() + 30.0f); 925 | } 926 | else 927 | { 928 | size_t subtext_begin = m_editable_text.GetTextPos(m_line_offset, 0); 929 | size_t error_pos = m_editable_text.GetTextPos(m_compile_error.row, m_compile_error.column); 930 | 931 | assert(error_pos >= subtext_begin); 932 | DWRITE_HIT_TEST_METRICS hit_test_metrics; 933 | m_text_layout->HitTestTextPosition( 934 | error_pos - subtext_begin, 935 | false, 936 | &m_compile_error.location.x, 937 | &m_compile_error.location.y, 938 | &hit_test_metrics); 939 | 940 | m_compile_error.is_located = true; 941 | } 942 | 943 | m_compile_error.remain_time = 3.0f; 944 | m_compile_error.alpha = 1.0f; 945 | } 946 | } 947 | -------------------------------------------------------------------------------- /src/text_editor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TEXT_EDITOR_INCLUDED_HPP_ 2 | #define _TEXT_EDITOR_INCLUDED_HPP_ 3 | 4 | #include 5 | #include 6 | #include "syntax_highlighter.hpp" 7 | #include "editable_text.hpp" 8 | 9 | class TextEditor; 10 | typedef boost::shared_ptr TextEditorPtr; 11 | 12 | class TextEditor 13 | { 14 | struct CompileError 15 | { 16 | int row; 17 | int column; 18 | std::wstring message; 19 | 20 | bool is_located; 21 | float2 location; 22 | float remain_time; 23 | float alpha; 24 | 25 | CompileError(); 26 | void Clear(); 27 | }; 28 | 29 | public: 30 | TextEditor(); 31 | virtual ~TextEditor(); 32 | 33 | public: 34 | bool Initialize(ID2D1RenderTarget* d2d_rt); 35 | bool HandleWindowMessage(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); 36 | 37 | void Update(float delta_time); 38 | void Render(ID2D1RenderTarget* d2d_rt) const; 39 | 40 | const std::wstring& GetText() const; 41 | 42 | void NewFile(); 43 | void OpenFile(); 44 | void SaveFile(bool save_as_new = false); 45 | 46 | private: 47 | void RefreshTextLayout(); 48 | 49 | void AutoIndent(); 50 | void AutoJumpOver(); 51 | void AutoJumpInto(); 52 | void AutoJumpOut(); 53 | 54 | void ReloadPixelShader(); 55 | void ParseCompileError(const tstring& fxc_error); 56 | 57 | void OnMousePress(UINT message, float x, float y); 58 | void OnMouseRelease(UINT message, float x, float y); 59 | void OnMouseDoubleClick(UINT message, float x, float y); 60 | void OnMouseMove(float x, float y); 61 | void OnMouseScroll(float x_scroll, float y_scroll); 62 | void OnMouseExit(); 63 | void OnKeyPress(UINT32 key_code); 64 | void OnKeyCharacter(UINT32 char_code); 65 | 66 | private: 67 | EditableText m_editable_text; 68 | std::wstring m_file_path; 69 | 70 | SyntaxHighlighter m_syntax_hightlighter; 71 | CompileError m_compile_error; 72 | 73 | size_t m_line_offset; 74 | float3 m_caret_loc_hight; 75 | float m_caret_idle_time; 76 | std::vector m_selection_fields; 77 | 78 | IDWriteTextFormat* m_text_format; 79 | IDWriteTextFormat* m_text_format_small; 80 | IDWriteTextLayout* m_text_layout; 81 | ID2D1SolidColorBrush* m_default_brush; 82 | }; 83 | 84 | #endif // _TEXT_EDITOR_INCLUDED_HPP_ 85 | --------------------------------------------------------------------------------