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