]> gitweb.factorcode.org Git - factor.git/blob - extra/terrain/terrain.factor
Merge branch 'master' of git://factorcode.org/git/factor
[factor.git] / extra / terrain / terrain.factor
1 USING: accessors arrays combinators game-input game-loop
2 game-input.scancodes grouping kernel literals locals
3 math math.constants math.functions math.matrices math.order
4 math.vectors opengl opengl.capabilities opengl.gl
5 opengl.shaders opengl.textures opengl.textures.private
6 sequences sequences.product specialized-arrays.float
7 terrain.generation terrain.shaders ui ui.gadgets
8 ui.gadgets.worlds ui.pixel-formats game-worlds method-chains ;
9 IN: terrain
10
11 CONSTANT: FOV $[ 2.0 sqrt 1+ ]
12 CONSTANT: NEAR-PLANE $[ 1.0 2048.0 / ]
13 CONSTANT: FAR-PLANE 1.0
14 CONSTANT: PLAYER-START-LOCATION { 0.5 0.51 0.5 }
15 CONSTANT: PLAYER-HEIGHT $[ 3.0 1024.0 / ]
16 CONSTANT: GRAVITY $[ 1.0 4096.0 / ]
17 CONSTANT: JUMP $[ 1.0 1024.0 / ]
18 CONSTANT: MOUSE-SCALE $[ 1.0 10.0 / ]
19 CONSTANT: MOVEMENT-SPEED $[ 1.0 16384.0 / ]
20 CONSTANT: FRICTION 0.95
21 CONSTANT: COMPONENT-SCALE { 0.5 0.01 0.002 0.0 }
22
23 CONSTANT: terrain-vertex-size { 512 512 }
24 CONSTANT: terrain-vertex-distance { $[ 1.0 512.0 / ] $[ 1.0 512.0 / ] }
25 CONSTANT: terrain-vertex-row-length $[ 512 1 + 2 * ]
26
27 TUPLE: player
28     location yaw pitch velocity ;
29
30 TUPLE: terrain-world < game-world
31     player
32     terrain terrain-segment terrain-texture terrain-program
33     terrain-vertex-buffer ;
34
35 M: terrain-world tick-length
36     drop 1000 30 /i ;
37
38 : frustum ( dim -- -x x -y y near far )
39     dup first2 min v/n
40     NEAR-PLANE FOV / v*n first2 [ [ neg ] keep ] bi@
41     NEAR-PLANE FAR-PLANE ;
42
43 : set-modelview-matrix ( gadget -- )
44     GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT bitor glClear
45     GL_MODELVIEW glMatrixMode
46     glLoadIdentity
47     player>>
48     [ pitch>> 1.0 0.0 0.0 glRotatef ]
49     [ yaw>> 0.0 1.0 0.0 glRotatef ]
50     [ location>> vneg first3 glTranslatef ] tri ;
51
52 : vertex-array-vertex ( x z -- vertex )
53     [ terrain-vertex-distance first * ]
54     [ terrain-vertex-distance second * ] bi*
55     [ 0 ] dip float-array{ } 3sequence ;
56
57 : vertex-array-row ( z -- vertices )
58     dup 1 + 2array
59     terrain-vertex-size first 1 + iota
60     2array [ first2 swap vertex-array-vertex ] product-map
61     concat ;
62
63 : vertex-array ( -- vertices )
64     terrain-vertex-size second iota
65     [ vertex-array-row ] map concat ;
66
67 : >vertex-buffer ( bytes -- buffer )
68     [ GL_ARRAY_BUFFER ] dip GL_STATIC_DRAW <gl-buffer> ;
69
70 : draw-vertex-buffer-row ( i -- )
71     [ GL_TRIANGLE_STRIP ] dip
72     terrain-vertex-row-length * terrain-vertex-row-length
73     glDrawArrays ;
74
75 : draw-vertex-buffer ( buffer -- )
76     [ GL_ARRAY_BUFFER ] dip [
77         3 GL_FLOAT 0 f glVertexPointer
78         terrain-vertex-size second iota [ draw-vertex-buffer-row ] each
79     ] with-gl-buffer ;
80
81 : degrees ( deg -- rad )
82     pi 180.0 / * ;
83
84 :: eye-rotate ( yaw pitch v -- v' )
85     yaw degrees neg :> y
86     pitch degrees neg :> p
87     y cos :> cosy
88     y sin :> siny
89     p cos :> cosp
90     p sin :> sinp
91
92     cosy         0.0       siny        neg  3array
93     siny sinp *  cosp      cosy sinp *      3array
94     siny cosp *  sinp neg  cosy cosp *      3array 3array
95     v swap v.m ;
96
97 : forward-vector ( player -- v )
98     yaw>> 0.0
99     { 0.0 0.0 $ MOVEMENT-SPEED } vneg eye-rotate ;
100 : rightward-vector ( player -- v )
101     yaw>> 0.0
102     { $ MOVEMENT-SPEED 0.0 0.0 } eye-rotate ;
103
104 : walk-forward ( player -- )
105     dup forward-vector [ v+ ] curry change-velocity drop ;
106 : walk-backward ( player -- )
107     dup forward-vector [ v- ] curry change-velocity drop ;
108 : walk-leftward ( player -- )
109     dup rightward-vector [ v- ] curry change-velocity drop ;
110 : walk-rightward ( player -- )
111     dup rightward-vector [ v+ ] curry change-velocity drop ;
112 : jump ( player -- )
113     [ { 0.0 $ JUMP 0.0 } v+ ] change-velocity drop ;
114
115 : clamp-pitch ( pitch -- pitch' )
116     90.0 min -90.0 max ;
117
118 : rotate-with-mouse ( player mouse -- )
119     [ dx>> MOUSE-SCALE * [ + ] curry change-yaw ]
120     [ dy>> MOUSE-SCALE * [ + clamp-pitch ] curry change-pitch ] bi
121     drop ;
122
123 :: handle-input ( world -- )
124     world player>> :> player
125     read-keyboard keys>> :> keys
126     key-w keys nth [ player walk-forward ] when 
127     key-s keys nth [ player walk-backward ] when 
128     key-a keys nth [ player walk-leftward ] when 
129     key-d keys nth [ player walk-rightward ] when 
130     key-space keys nth [ player jump ] when 
131     key-escape keys nth [ world close-window ] when
132     player read-mouse rotate-with-mouse
133     reset-mouse ;
134
135 : apply-friction ( velocity -- velocity' )
136     FRICTION v*n ;
137
138 : apply-gravity ( velocity -- velocity' )
139     1 over [ GRAVITY - ] change-nth ;
140
141 : clamp-coords ( coords dim -- coords' )
142     [ { 0 0 } vmax ] dip { 2 2 } v- vmin ;
143
144 :: pixel-indices ( coords dim -- indices )
145     coords vfloor [ >integer ] map dim clamp-coords :> floor-coords
146     floor-coords first2 dim first * + :> base-index
147     base-index dim first + :> next-row-index
148
149     base-index
150     base-index 1 +
151     next-row-index
152     next-row-index 1 + 4array ;
153
154 :: terrain-height-at ( segment point -- height )
155     segment dim>> :> dim
156     dim point v* :> pixel
157     pixel dup vfloor v- :> pixel-mantissa
158     segment bitmap>> 4 <groups> :> pixels
159     pixel dim pixel-indices :> indices
160     
161     indices [ pixels nth COMPONENT-SCALE v. 255.0 / ] map
162     first4 pixel-mantissa bilerp ;
163
164 : collide ( segment location -- location' )
165     [ [ first ] [ third ] bi 2array terrain-height-at PLAYER-HEIGHT + ]
166     [ [ 1 ] 2dip [ max ] with change-nth ]
167     [ ] tri ;
168
169 : tick-player ( world player -- )
170     [ apply-friction apply-gravity ] change-velocity
171     dup velocity>> [ v+ [ terrain-segment>> ] dip collide ] curry with change-location
172     drop ;
173
174 M: terrain-world tick*
175     [ dup focused?>> [ handle-input ] [ drop ] if ]
176     [ dup player>> tick-player ] bi ;
177
178 : set-heightmap-texture-parameters ( texture -- )
179     GL_TEXTURE_2D GL_TEXTURE0 bind-texture-unit
180     GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER GL_LINEAR glTexParameteri
181     GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER GL_LINEAR glTexParameteri
182     GL_TEXTURE_2D GL_TEXTURE_WRAP_S GL_CLAMP_TO_EDGE glTexParameteri
183     GL_TEXTURE_2D GL_TEXTURE_WRAP_T GL_CLAMP_TO_EDGE glTexParameteri ;
184
185 BEFORE: terrain-world begin-world
186     "2.0" { "GL_ARB_vertex_buffer_object" "GL_ARB_shader_objects" }
187     require-gl-version-or-extensions
188     GL_DEPTH_TEST glEnable
189     GL_TEXTURE_2D glEnable
190     GL_VERTEX_ARRAY glEnableClientState
191     0.5 0.5 0.5 1.0 glClearColor
192     PLAYER-START-LOCATION 0.0 0.0 { 0.0 0.0 0.0 } player boa >>player
193     <terrain> [ >>terrain ] keep
194     { 0 0 } terrain-segment [ >>terrain-segment ] keep
195     make-texture [ set-heightmap-texture-parameters ] keep >>terrain-texture
196     terrain-vertex-shader terrain-pixel-shader <simple-gl-program>
197     >>terrain-program
198     vertex-array >vertex-buffer >>terrain-vertex-buffer
199     drop ;
200
201 AFTER: terrain-world end-world
202     {
203         [ terrain-vertex-buffer>> delete-gl-buffer ]
204         [ terrain-program>> delete-gl-program ]
205         [ terrain-texture>> delete-texture ]
206     } cleave ;
207
208 M: terrain-world resize-world
209     GL_PROJECTION glMatrixMode
210     glLoadIdentity
211     dim>> [ [ 0 0 ] dip first2 glViewport ]
212     [ frustum glFrustum ] bi ;
213
214 M: terrain-world draw-world*
215     [ set-modelview-matrix ]
216     [ terrain-texture>> GL_TEXTURE_2D GL_TEXTURE0 bind-texture-unit ]
217     [ dup terrain-program>> [
218         [ "heightmap" glGetUniformLocation 0 glUniform1i ]
219         [ "component_scale" glGetUniformLocation COMPONENT-SCALE first4 glUniform4f ] bi
220         terrain-vertex-buffer>> draw-vertex-buffer
221     ] with-gl-program ]
222     tri gl-error ;
223
224 M: terrain-world pref-dim* drop { 640 480 } ;
225
226 : terrain-window ( -- )
227     [
228         f T{ world-attributes
229             { world-class terrain-world }
230             { title "Terrain" }
231             { pixel-format-attributes {
232                 windowed
233                 double-buffered
234                 T{ depth-bits { value 24 } }
235             } }
236             { grab-input? t }
237         } open-window
238     ] with-ui ;
239
240 MAIN: terrain-window