]> gitweb.factorcode.org Git - factor.git/blob - extra/gpu/state/state.factor
Specialized array overhaul
[factor.git] / extra / gpu / state / state.factor
1 ! (c)2009 Joe Groff bsd license
2 USING: accessors alien.c-types arrays byte-arrays combinators gpu
3 kernel literals math math.rectangles opengl opengl.gl sequences
4 variants specialized-arrays ;
5 SPECIALIZED-ARRAY: int
6 SPECIALIZED-ARRAY: float
7 IN: gpu.state
8
9 UNION: ?rect rect POSTPONE: f ;
10 UNION: ?float float POSTPONE: f ;
11
12 TUPLE: viewport-state
13     { rect rect read-only } ;
14 C: <viewport-state> viewport-state
15
16 TUPLE: scissor-state
17     { rect ?rect read-only } ;
18 C: <scissor-state> scissor-state
19
20 TUPLE: multisample-state
21     { multisample? boolean read-only }
22     { sample-alpha-to-coverage? boolean read-only }
23     { sample-alpha-to-one? boolean read-only }
24     { sample-coverage ?float read-only }
25     { invert-sample-coverage? boolean read-only } ;
26 C: <multisample-state> multisample-state
27
28 VARIANT: comparison
29     cmp-never cmp-always
30     cmp-less cmp-less-equal cmp-equal
31     cmp-greater-equal cmp-greater cmp-not-equal ;
32 VARIANT: stencil-op
33     op-keep op-zero
34     op-replace op-invert
35     op-inc-sat op-dec-sat
36     op-inc-wrap op-dec-wrap ;
37
38 UNION: ?comparison comparison POSTPONE: f ;
39
40 TUPLE: stencil-mode
41     { value integer initial: 0 read-only }
42     { mask integer initial: HEX: FFFFFFFF read-only }
43     { comparison comparison initial: cmp-always read-only }
44     { stencil-fail-op stencil-op initial: op-keep read-only }
45     { depth-fail-op stencil-op initial: op-keep read-only }
46     { depth-pass-op stencil-op initial: op-keep read-only } ;
47 C: <stencil-mode> stencil-mode
48
49 UNION: ?stencil-mode stencil-mode POSTPONE: f ;
50
51 TUPLE: stencil-state
52     { front-mode ?stencil-mode initial: f read-only }
53     { back-mode ?stencil-mode initial: f read-only } ;
54 C: <stencil-state> stencil-state
55
56 TUPLE: depth-range-state
57     { near float initial: 0.0 read-only }
58     { far  float initial: 1.0 read-only } ;
59 C: <depth-range-state> depth-range-state
60
61 TUPLE: depth-state
62     { comparison ?comparison initial: f read-only } ;
63 C: <depth-state> depth-state
64
65 VARIANT: blend-equation
66     eq-add eq-subtract eq-reverse-subtract eq-min eq-max ;
67 VARIANT: blend-function
68     func-zero func-one
69     func-source func-one-minus-source
70     func-dest func-one-minus-dest
71     func-constant func-one-minus-constant
72     func-source-alpha func-one-minus-source-alpha
73     func-dest-alpha func-one-minus-dest-alpha
74     func-constant-alpha func-one-minus-constant-alpha ;
75
76 VARIANT: source-only-blend-function
77     func-source-alpha-saturate ;
78
79 UNION: source-blend-function blend-function source-only-blend-function ;
80
81 TUPLE: blend-mode
82     { equation blend-equation initial: eq-add read-only }
83     { source-function source-blend-function initial: func-source-alpha read-only }
84     { dest-function blend-function initial: func-one-minus-source-alpha read-only } ;
85 C: <blend-mode> blend-mode
86
87 UNION: ?blend-mode blend-mode POSTPONE: f ;
88
89 TUPLE: blend-state
90     { constant-color sequence initial: f read-only }
91     { rgb-mode ?blend-mode read-only }
92     { alpha-mode ?blend-mode read-only } ;
93 C: <blend-state> blend-state
94
95 TUPLE: mask-state
96     { color sequence initial: { t t t t } read-only }
97     { depth boolean initial: t read-only }
98     { stencil-front integer initial: HEX: FFFFFFFF read-only }
99     { stencil-back integer initial: HEX: FFFFFFFF read-only } ;
100 C: <mask-state> mask-state
101
102 VARIANT: triangle-face
103     face-ccw face-cw ;
104 VARIANT: triangle-cull
105     cull-front cull-back cull-all ;
106 VARIANT: triangle-mode
107     triangle-points triangle-lines triangle-fill ;
108
109 UNION: ?triangle-cull triangle-cull POSTPONE: f ;
110     
111 TUPLE: triangle-cull-state
112     { front-face triangle-face initial: face-ccw read-only }
113     { cull ?triangle-cull initial: f read-only } ;
114 C: <triangle-cull-state> triangle-cull-state
115
116 TUPLE: triangle-state
117     { front-mode triangle-mode initial: triangle-fill read-only }
118     { back-mode triangle-mode initial: triangle-fill read-only }
119     { antialias? boolean initial: f read-only } ;
120 C: <triangle-state> triangle-state
121
122 VARIANT: point-sprite-origin 
123     origin-upper-left origin-lower-left ;
124
125 TUPLE: point-state
126     { size ?float initial: 1.0 read-only }
127     { sprite-origin point-sprite-origin initial: origin-upper-left read-only }
128     { fade-threshold float initial: 1.0 read-only } ;
129 C: <point-state> point-state
130
131 TUPLE: line-state
132     { width float initial: 1.0 read-only }
133     { antialias? boolean initial: f read-only } ;
134 C: <line-state> line-state
135
136 UNION: gpu-state
137     viewport-state
138     triangle-cull-state
139     triangle-state
140     point-state
141     line-state
142     scissor-state
143     multisample-state
144     stencil-state
145     depth-range-state
146     depth-state
147     blend-state
148     mask-state ;
149
150 <PRIVATE
151
152 : gl-triangle-face ( triangle-face -- face )
153     { 
154         { face-ccw [ GL_CCW ] }
155         { face-cw  [ GL_CW  ] }
156     } case ;
157
158 : gl-triangle-face> ( triangle-face -- face )
159     { 
160         { $ GL_CCW [ face-ccw ] }
161         { $ GL_CW  [ face-cw  ] }
162     } case ;
163
164 : gl-triangle-cull ( triangle-cull -- cull )
165     {
166         { cull-front [ GL_FRONT          ] }
167         { cull-back  [ GL_BACK           ] }
168         { cull-all   [ GL_FRONT_AND_BACK ] }
169     } case ;
170
171 : gl-triangle-cull> ( triangle-cull -- cull )
172     {
173         { $ GL_FRONT          [ cull-front ] }
174         { $ GL_BACK           [ cull-back  ] }
175         { $ GL_FRONT_AND_BACK [ cull-all   ] }
176     } case ;
177
178 : gl-triangle-mode ( triangle-mode -- mode )
179     {
180         { triangle-points [ GL_POINT ] }
181         { triangle-lines  [ GL_LINE  ] }
182         { triangle-fill   [ GL_FILL  ] }
183     } case ;
184
185 : gl-triangle-mode> ( triangle-mode -- mode )
186     {
187         { $ GL_POINT [ triangle-points ] }
188         { $ GL_LINE  [ triangle-lines  ] }
189         { $ GL_FILL  [ triangle-fill   ] }
190     } case ;
191
192 : gl-point-sprite-origin ( point-sprite-origin -- sprite-origin )
193     {
194         { origin-upper-left [ GL_UPPER_LEFT ] }
195         { origin-lower-left [ GL_LOWER_LEFT ] }
196     } case ;
197
198 : gl-point-sprite-origin> ( point-sprite-origin -- sprite-origin )
199     {
200         { $ GL_UPPER_LEFT [ origin-upper-left ] }
201         { $ GL_LOWER_LEFT [ origin-lower-left ] }
202     } case ;
203
204 : gl-comparison ( comparison -- comparison )
205     {
206         { cmp-never         [ GL_NEVER    ] } 
207         { cmp-always        [ GL_ALWAYS   ] }
208         { cmp-less          [ GL_LESS     ] }
209         { cmp-less-equal    [ GL_LEQUAL   ] }
210         { cmp-equal         [ GL_EQUAL    ] }
211         { cmp-greater-equal [ GL_GEQUAL   ] }
212         { cmp-greater       [ GL_GREATER  ] }
213         { cmp-not-equal     [ GL_NOTEQUAL ] }
214     } case ;
215
216 : gl-comparison> ( comparison -- comparison )
217     {
218         { $ GL_NEVER    [ cmp-never         ] } 
219         { $ GL_ALWAYS   [ cmp-always        ] }
220         { $ GL_LESS     [ cmp-less          ] }
221         { $ GL_LEQUAL   [ cmp-less-equal    ] }
222         { $ GL_EQUAL    [ cmp-equal         ] }
223         { $ GL_GEQUAL   [ cmp-greater-equal ] }
224         { $ GL_GREATER  [ cmp-greater       ] }
225         { $ GL_NOTEQUAL [ cmp-not-equal     ] }
226     } case ;
227
228 : gl-stencil-op ( stencil-op -- op )
229     {
230         { op-keep [ GL_KEEP ] }
231         { op-zero [ GL_ZERO ] }
232         { op-replace [ GL_REPLACE ] }
233         { op-invert [ GL_INVERT ] }
234         { op-inc-sat [ GL_INCR ] }
235         { op-dec-sat [ GL_DECR ] }
236         { op-inc-wrap [ GL_INCR_WRAP ] }
237         { op-dec-wrap [ GL_DECR_WRAP ] }
238     } case ;
239
240 : gl-stencil-op> ( op -- op )
241     {
242         { $ GL_KEEP      [ op-keep     ] }
243         { $ GL_ZERO      [ op-zero     ] }
244         { $ GL_REPLACE   [ op-replace  ] }
245         { $ GL_INVERT    [ op-invert   ] }
246         { $ GL_INCR      [ op-inc-sat  ] }
247         { $ GL_DECR      [ op-dec-sat  ] }
248         { $ GL_INCR_WRAP [ op-inc-wrap ] }
249         { $ GL_DECR_WRAP [ op-dec-wrap ] }
250     } case ;
251
252 : (set-stencil-mode) ( gl-face stencil-mode -- )
253     {
254         [ [ comparison>> gl-comparison ] [ value>> ] [ mask>> ] tri glStencilFuncSeparate ]
255         [
256             [ stencil-fail-op>> ] [ depth-fail-op>> ] [ depth-pass-op>> ] tri
257             [ gl-stencil-op ] tri@ glStencilOpSeparate
258         ]
259     } 2cleave ;
260
261 : gl-blend-equation ( blend-equation -- blend-equation )
262     {
263         { eq-add              [ GL_FUNC_ADD              ] }
264         { eq-subtract         [ GL_FUNC_SUBTRACT         ] }
265         { eq-reverse-subtract [ GL_FUNC_REVERSE_SUBTRACT ] }
266         { eq-min              [ GL_MIN                   ] }
267         { eq-max              [ GL_MAX                   ] }
268     } case ;
269
270 : gl-blend-equation> ( blend-equation -- blend-equation )
271     {
272         { $ GL_FUNC_ADD              [ eq-add              ] }
273         { $ GL_FUNC_SUBTRACT         [ eq-subtract         ] }
274         { $ GL_FUNC_REVERSE_SUBTRACT [ eq-reverse-subtract ] }
275         { $ GL_MIN                   [ eq-min              ] }
276         { $ GL_MAX                   [ eq-max              ] }
277     } case ;
278
279 : gl-blend-function ( blend-function -- blend-function )
280     {
281         { func-zero                     [ GL_ZERO                     ] }
282         { func-one                      [ GL_ONE                      ] }
283         { func-source                   [ GL_SRC_COLOR                ] }
284         { func-one-minus-source         [ GL_ONE_MINUS_SRC_COLOR      ] }
285         { func-dest                     [ GL_DST_COLOR                ] }
286         { func-one-minus-dest           [ GL_ONE_MINUS_DST_COLOR      ] }
287         { func-constant                 [ GL_CONSTANT_COLOR           ] }
288         { func-one-minus-constant       [ GL_ONE_MINUS_CONSTANT_COLOR ] }
289         { func-source-alpha             [ GL_SRC_ALPHA                ] }
290         { func-one-minus-source-alpha   [ GL_ONE_MINUS_SRC_ALPHA      ] }
291         { func-dest-alpha               [ GL_DST_ALPHA                ] }
292         { func-one-minus-dest-alpha     [ GL_ONE_MINUS_DST_ALPHA      ] }
293         { func-constant-alpha           [ GL_CONSTANT_ALPHA           ] }
294         { func-one-minus-constant-alpha [ GL_ONE_MINUS_CONSTANT_ALPHA ] }
295         { func-source-alpha-saturate    [ GL_SRC_ALPHA_SATURATE       ] }
296     } case ;
297
298 : gl-blend-function> ( blend-function -- blend-function )
299     {
300         { $ GL_ZERO                     [ func-zero                     ] }
301         { $ GL_ONE                      [ func-one                      ] }
302         { $ GL_SRC_COLOR                [ func-source                   ] }
303         { $ GL_ONE_MINUS_SRC_COLOR      [ func-one-minus-source         ] }
304         { $ GL_DST_COLOR                [ func-dest                     ] }
305         { $ GL_ONE_MINUS_DST_COLOR      [ func-one-minus-dest           ] }
306         { $ GL_CONSTANT_COLOR           [ func-constant                 ] }
307         { $ GL_ONE_MINUS_CONSTANT_COLOR [ func-one-minus-constant       ] }
308         { $ GL_SRC_ALPHA                [ func-source-alpha             ] }
309         { $ GL_ONE_MINUS_SRC_ALPHA      [ func-one-minus-source-alpha   ] }
310         { $ GL_DST_ALPHA                [ func-dest-alpha               ] }
311         { $ GL_ONE_MINUS_DST_ALPHA      [ func-one-minus-dest-alpha     ] }
312         { $ GL_CONSTANT_ALPHA           [ func-constant-alpha           ] }
313         { $ GL_ONE_MINUS_CONSTANT_ALPHA [ func-one-minus-constant-alpha ] }
314         { $ GL_SRC_ALPHA_SATURATE       [ func-source-alpha-saturate    ] }
315     } case ;
316
317 PRIVATE>
318
319 GENERIC: set-gpu-state* ( state -- )
320
321 M: viewport-state set-gpu-state*
322     rect>> [ loc>> first2 ] [ dim>> first2 ] bi glViewport ;
323
324 M: triangle-cull-state set-gpu-state*
325     {
326         [ front-face>> gl-triangle-face glFrontFace ]
327         [ GL_CULL_FACE swap cull>> [ gl-triangle-cull glCullFace glEnable ] [ glDisable ] if* ]
328     } cleave ;
329
330 M: triangle-state set-gpu-state*
331     {
332         [ GL_FRONT swap front-mode>> gl-triangle-mode glPolygonMode ]
333         [ GL_BACK swap back-mode>> gl-triangle-mode glPolygonMode ]
334         [ GL_POLYGON_SMOOTH swap antialias?>> [ glEnable ] [ glDisable ] if ]
335     } cleave ;
336
337 M: point-state set-gpu-state*
338     {
339         [ GL_VERTEX_PROGRAM_POINT_SIZE swap size>> [ glPointSize glDisable ] [ glEnable ] if* ]
340         [ GL_POINT_SPRITE_COORD_ORIGIN swap sprite-origin>> gl-point-sprite-origin glPointParameteri ]
341         [ GL_POINT_FADE_THRESHOLD_SIZE swap fade-threshold>> glPointParameterf ]
342     } cleave ;
343
344 M: line-state set-gpu-state*
345     {
346         [ width>> glLineWidth ]
347         [ GL_LINE_SMOOTH swap antialias?>> [ glEnable ] [ glDisable ] if ]
348     } cleave ;
349
350 M: scissor-state set-gpu-state*
351     GL_SCISSOR_TEST swap rect>>
352     [ [ loc>> first2 ] [ dim>> first2 ] bi glViewport glEnable ]
353     [ glDisable ] if* ;
354
355 M: multisample-state set-gpu-state*
356     dup multisample?>> [
357         GL_MULTISAMPLE glEnable
358         {
359             [ GL_SAMPLE_ALPHA_TO_COVERAGE swap sample-alpha-to-coverage?>>
360                 [ glEnable ] [ glDisable ] if
361             ]
362             [ GL_SAMPLE_ALPHA_TO_ONE swap sample-alpha-to-one?>>
363                 [ glEnable ] [ glDisable ] if
364             ]
365             [ GL_SAMPLE_COVERAGE swap [ invert-sample-coverage?>> >c-bool ] [ sample-coverage>> ] bi
366                 [ swap glSampleCoverage glEnable ] [ drop glDisable ] if*
367             ]
368         } cleave
369     ] [ drop GL_MULTISAMPLE glDisable ] if ;
370
371 M: stencil-state set-gpu-state*
372     [ ] [ front-mode>> ] [ back-mode>> ] tri or
373     [
374         GL_STENCIL_TEST glEnable
375         [ front-mode>> GL_FRONT swap (set-stencil-mode) ]
376         [ back-mode>> GL_BACK swap (set-stencil-mode) ] bi
377     ] [ drop GL_STENCIL_TEST glDisable ] if ;
378
379 M: depth-range-state set-gpu-state*
380     [ near>> ] [ far>> ] bi glDepthRange ;
381
382 M: depth-state set-gpu-state*
383     GL_DEPTH_TEST swap comparison>> [ gl-comparison glDepthFunc glEnable ] [ glDisable ] if* ;
384
385 M: blend-state set-gpu-state*
386     [ ] [ rgb-mode>> ] [ alpha-mode>> ] tri or
387     [
388         GL_BLEND glEnable
389         [ constant-color>> [ first4 glBlendColor ] when* ]
390         [
391             [ rgb-mode>> ] [ alpha-mode>> ] bi {
392                 [ [ equation>> gl-blend-equation ] bi@ glBlendEquationSeparate ]
393                 [
394                     [
395                         [ source-function>> gl-blend-function ]
396                         [ dest-function>> gl-blend-function ] bi
397                     ] bi@ glBlendFuncSeparate
398                 ]
399             } 2cleave
400         ] bi
401     ] [ drop GL_BLEND glDisable ] if ;
402
403 M: mask-state set-gpu-state*
404     {
405         [ color>> [ >c-bool ] map first4 glColorMask ]
406         [ depth>> >c-bool glDepthMask ]
407         [ GL_FRONT swap stencil-front>> glStencilMaskSeparate ]
408         [ GL_BACK  swap stencil-back>> glStencilMaskSeparate ]
409     } cleave ;
410
411 : set-gpu-state ( states -- )
412     dup sequence?
413     [ [ set-gpu-state* ] each ]
414     [ set-gpu-state* ] if ; inline
415
416 <PRIVATE
417
418 : get-gl-bool ( enum -- value )
419     0 <uchar> [ glGetBooleanv ] keep *uchar c-bool> ;
420 : get-gl-int ( enum -- value )
421     0 <int> [ glGetIntegerv ] keep *int ;
422 : get-gl-float ( enum -- value )
423     0 <float> [ glGetFloatv ] keep *float ;
424
425 : get-gl-bools ( enum count -- value )
426     <byte-array> [ glGetBooleanv ] keep [ c-bool> ] { } map-as ;
427 : get-gl-ints ( enum count -- value )
428     <int-array> [ glGetIntegerv ] keep ;
429 : get-gl-floats ( enum count -- value )
430     <float-array> [ glGetFloatv ] keep ;
431
432 : get-gl-rect ( enum -- value )
433     4 get-gl-ints first4 [ 2array ] 2bi@ <rect> ;
434
435 : gl-enabled? ( enum -- ? )
436     glIsEnabled c-bool> ;
437
438 PRIVATE>
439
440 : get-viewport-state ( -- viewport-state )
441     GL_VIEWPORT get-gl-rect <viewport-state> ;
442
443 : get-scissor-state ( -- scissor-state )
444     GL_SCISSOR_TEST get-gl-bool
445     [ GL_SCISSOR_BOX get-gl-rect ] [ f ] if
446     <scissor-state> ;
447
448 : get-multisample-state ( -- multisample-state )
449     GL_MULTISAMPLE gl-enabled?
450     GL_SAMPLE_ALPHA_TO_COVERAGE gl-enabled?
451     GL_SAMPLE_ALPHA_TO_ONE gl-enabled?
452     GL_SAMPLE_COVERAGE gl-enabled? [
453         GL_SAMPLE_COVERAGE_VALUE get-gl-float
454         GL_SAMPLE_COVERAGE_INVERT get-gl-bool
455     ] [ f f ] if
456     <multisample-state> ;
457
458 : get-stencil-state ( -- stencil-state )
459     GL_STENCIL_TEST gl-enabled? [
460         GL_STENCIL_REF get-gl-int
461         GL_STENCIL_VALUE_MASK get-gl-int
462         GL_STENCIL_FUNC get-gl-int gl-comparison>
463         GL_STENCIL_FAIL get-gl-int gl-stencil-op>
464         GL_STENCIL_PASS_DEPTH_FAIL get-gl-int gl-stencil-op>
465         GL_STENCIL_PASS_DEPTH_PASS get-gl-int gl-stencil-op>
466         <stencil-mode>
467
468         GL_STENCIL_BACK_REF get-gl-int
469         GL_STENCIL_BACK_VALUE_MASK get-gl-int
470         GL_STENCIL_BACK_FUNC get-gl-int gl-comparison>
471         GL_STENCIL_BACK_FAIL get-gl-int gl-stencil-op>
472         GL_STENCIL_BACK_PASS_DEPTH_FAIL get-gl-int gl-stencil-op>
473         GL_STENCIL_BACK_PASS_DEPTH_PASS get-gl-int gl-stencil-op>
474         <stencil-mode>
475     ] [ f f ] if
476     <stencil-state> ;
477
478 : get-depth-range-state ( -- depth-range-state )
479     GL_DEPTH_RANGE 2 get-gl-floats first2 <depth-range-state> ;
480
481 : get-depth-state ( -- depth-state )
482     GL_DEPTH_TEST gl-enabled?
483     [ GL_DEPTH_FUNC get-gl-int gl-comparison> ] [ f ] if
484     <depth-state> ;
485
486 : get-blend-state ( -- blend-state )
487     GL_BLEND gl-enabled? [
488         GL_BLEND_COLOR 4 get-gl-floats
489
490         GL_BLEND_EQUATION_RGB get-gl-int gl-blend-equation>
491         GL_BLEND_SRC_RGB get-gl-int gl-blend-function>
492         GL_BLEND_DST_RGB get-gl-int gl-blend-function>
493         <blend-mode>
494
495         GL_BLEND_EQUATION_ALPHA get-gl-int gl-blend-equation>
496         GL_BLEND_SRC_ALPHA get-gl-int gl-blend-function>
497         GL_BLEND_DST_ALPHA get-gl-int gl-blend-function>
498         <blend-mode>
499     ] [ f f f ] if
500     <blend-state> ;
501
502 : get-mask-state ( -- mask-state )
503     GL_COLOR_WRITEMASK 4 get-gl-bools 
504     GL_DEPTH_WRITEMASK get-gl-bool
505     GL_STENCIL_WRITEMASK get-gl-int
506     GL_STENCIL_BACK_WRITEMASK get-gl-int
507     <mask-state> ;
508
509 : get-triangle-cull-state ( -- triangle-cull-state )
510     GL_FRONT_FACE get-gl-int gl-triangle-face>
511     GL_CULL_FACE gl-enabled?
512     [ GL_CULL_FACE_MODE get-gl-int gl-triangle-cull> ]
513     [ f ] if
514     <triangle-cull-state> ;
515
516 : get-triangle-state ( -- triangle-state )
517     GL_POLYGON_MODE 2 get-gl-ints
518     first2 [ gl-triangle-mode> ] bi@
519     GL_POLYGON_SMOOTH gl-enabled?
520     <triangle-state> ;
521
522 : get-point-state ( -- point-state )
523     GL_VERTEX_PROGRAM_POINT_SIZE gl-enabled?
524     [ f ] [ GL_POINT_SIZE get-gl-float ] if
525     GL_POINT_SPRITE_COORD_ORIGIN get-gl-int gl-point-sprite-origin> 
526     GL_POINT_FADE_THRESHOLD_SIZE get-gl-float
527     <point-state> ;
528
529 : get-line-state ( -- line-state )
530     GL_LINE_WIDTH get-gl-float
531     GL_LINE_SMOOTH gl-enabled?
532     <line-state> ;