]> gitweb.factorcode.org Git - factor.git/blob - extra/gpu/render/render.factor
Switch to https urls
[factor.git] / extra / gpu / render / render.factor
1 ! Copyright (C) 2009 Joe Groff.
2 ! See https://factorcode.org/license.txt for BSD license.
3 USING: accessors alien alien.c-types alien.data arrays assocs
4 classes classes.parser classes.struct classes.tuple
5 classes.tuple.private combinators combinators.tuple generic
6 generic.parser gpu.buffers gpu.framebuffers
7 gpu.framebuffers.private gpu.shaders gpu.shaders.private
8 gpu.textures gpu.textures.private kernel lexer math
9 math.parser math.vectors.simd opengl.gl parser quotations
10 sequences slots sorting specialized-arrays strings variants words ;
11 FROM: math => float ;
12 QUALIFIED-WITH: alien.c-types c
13 SPECIALIZED-ARRAYS: c:float c:int c:uchar c:ushort c:uint c:void* ;
14 IN: gpu.render
15
16 VARIANT: uniform-type
17     bool-uniform
18     bvec2-uniform
19     bvec3-uniform
20     bvec4-uniform
21     uint-uniform
22     uvec2-uniform
23     uvec3-uniform
24     uvec4-uniform
25     int-uniform
26     ivec2-uniform
27     ivec3-uniform
28     ivec4-uniform
29     float-uniform
30     vec2-uniform
31     vec3-uniform
32     vec4-uniform
33
34     mat2-uniform
35     mat2x3-uniform
36     mat2x4-uniform
37
38     mat3x2-uniform
39     mat3-uniform
40     mat3x4-uniform
41
42     mat4x2-uniform
43     mat4x3-uniform
44     mat4-uniform
45
46     texture-uniform ;
47
48 ALIAS: mat2x2-uniform mat2-uniform
49 ALIAS: mat3x3-uniform mat3-uniform
50 ALIAS: mat4x4-uniform mat4-uniform
51
52 TUPLE: uniform
53     { name         string   read-only initial: "" }
54     { uniform-type class    read-only initial: float-uniform }
55     { dim          maybe{ integer } read-only initial: f } ;
56
57 VARIANT: index-type
58     ubyte-indexes
59     ushort-indexes
60     uint-indexes ;
61
62 TUPLE: index-range
63     { start integer read-only }
64     { count integer read-only } ;
65
66 C: <index-range> index-range
67
68 TUPLE: multi-index-range
69     { starts uint-array read-only }
70     { counts uint-array read-only } ;
71
72 C: <multi-index-range> multi-index-range
73
74 TUPLE: index-elements
75     { ptr read-only }
76     { count integer read-only }
77     { index-type index-type read-only } ;
78
79 C: <index-elements> index-elements
80
81 TUPLE: multi-index-elements
82     { buffer maybe{ buffer } read-only }
83     { ptrs   read-only }
84     { counts uint-array read-only }
85     { index-type index-type read-only } ;
86
87 C: <multi-index-elements> multi-index-elements
88
89 UNION: vertex-indexes
90     index-range
91     multi-index-range
92     index-elements
93     multi-index-elements
94     uchar-array
95     ushort-array
96     uint-array ;
97
98 VARIANT: primitive-mode
99     points-mode
100     lines-mode
101     line-strip-mode
102     lines-with-adjacency-mode
103     line-strip-with-adjacency-mode
104     line-loop-mode
105     triangles-mode
106     triangle-strip-mode
107     triangles-with-adjacency-mode
108     triangle-strip-with-adjacency-mode
109     triangle-fan-mode ;
110
111 TUPLE: uniform-tuple ;
112
113 ERROR: invalid-uniform-type uniform ;
114
115 <PRIVATE
116
117 : gl-index-type ( index-type -- gl-index-type )
118     {
119         { ubyte-indexes  [ GL_UNSIGNED_BYTE  ] }
120         { ushort-indexes [ GL_UNSIGNED_SHORT ] }
121         { uint-indexes   [ GL_UNSIGNED_INT   ] }
122     } case ; inline
123
124 : gl-primitive-mode ( primitive-mode -- gl-primitive-mode )
125     {
126         { points-mode         [ GL_POINTS         ] }
127         { lines-mode          [ GL_LINES          ] }
128         { line-strip-mode     [ GL_LINE_STRIP     ] }
129         { line-loop-mode      [ GL_LINE_LOOP      ] }
130         { triangles-mode      [ GL_TRIANGLES      ] }
131         { triangle-strip-mode [ GL_TRIANGLE_STRIP ] }
132         { triangle-fan-mode   [ GL_TRIANGLE_FAN   ] }
133         { lines-with-adjacency-mode          [ GL_LINES_ADJACENCY          ] }
134         { line-strip-with-adjacency-mode     [ GL_LINE_STRIP_ADJACENCY     ] }
135         { triangles-with-adjacency-mode      [ GL_TRIANGLES_ADJACENCY      ] }
136         { triangle-strip-with-adjacency-mode [ GL_TRIANGLE_STRIP_ADJACENCY ] }
137     } case ; inline
138
139 GENERIC: render-vertex-indexes ( primitive-mode vertex-indexes -- )
140
141 GENERIC#: render-vertex-indexes-instanced 1 ( primitive-mode vertex-indexes instances -- )
142
143 GENERIC: gl-array-element-type ( array -- type )
144 M: uchar-array  gl-array-element-type drop GL_UNSIGNED_BYTE  ; inline
145 M: ushort-array gl-array-element-type drop GL_UNSIGNED_SHORT ; inline
146 M: uint-array   gl-array-element-type drop GL_UNSIGNED_INT   ; inline
147
148 M: index-range render-vertex-indexes
149     [ gl-primitive-mode ] [ [ start>> ] [ count>> ] bi ] bi* glDrawArrays ;
150
151 M: index-range render-vertex-indexes-instanced
152     [ gl-primitive-mode ] [ [ start>> ] [ count>> ] bi ] [ ] tri*
153     glDrawArraysInstanced ;
154
155 M: multi-index-range render-vertex-indexes
156     [ gl-primitive-mode ] [ [ starts>> ] [ counts>> dup length ] bi ] bi*
157     glMultiDrawArrays ;
158
159 M: index-elements render-vertex-indexes
160     [ gl-primitive-mode ]
161     [ [ count>> ] [ index-type>> gl-index-type ] [ ptr>> ] tri ] bi*
162     index-buffer [ glDrawElements ] with-gpu-data-ptr ;
163
164 M: index-elements render-vertex-indexes-instanced
165     [ gl-primitive-mode ]
166     [ [ count>> ] [ index-type>> gl-index-type ] [ ptr>> ] tri ]
167     [ ] tri*
168     swap index-buffer [ swap glDrawElementsInstanced ] with-gpu-data-ptr ;
169
170 M: specialized-array render-vertex-indexes
171     GL_ELEMENT_ARRAY_BUFFER 0 glBindBuffer
172     [ gl-primitive-mode ]
173     [ [ length ] [ gl-array-element-type ] [ >c-ptr ] tri ] bi*
174     glDrawElements ;
175
176 M: specialized-array render-vertex-indexes-instanced
177     GL_ELEMENT_ARRAY_BUFFER 0 glBindBuffer
178     [ gl-primitive-mode ]
179     [ [ length ] [ gl-array-element-type ] [ >c-ptr ] tri ]
180     [ ] tri* glDrawElementsInstanced ;
181
182 M: multi-index-elements render-vertex-indexes
183     [ gl-primitive-mode ]
184     [ { [ counts>> ] [ index-type>> gl-index-type ] [ ptrs>> dup length ] [ buffer>> ] } cleave ]
185     bi*
186     GL_ELEMENT_ARRAY_BUFFER swap [ handle>> ] [ 0 ] if* glBindBuffer glMultiDrawElements ;
187
188 : (bind-texture-unit) ( texture texture-unit -- )
189     swap [ GL_TEXTURE0 + glActiveTexture ] [ bind-texture drop ] bi* ; inline
190
191 GENERIC: (bind-uniform-textures) ( program-instance uniform-tuple -- )
192 GENERIC: (bind-uniforms) ( program-instance uniform-tuple -- )
193
194 M: uniform-tuple (bind-uniform-textures)
195     2drop ;
196 M: uniform-tuple (bind-uniforms)
197     2drop ;
198
199 : uniform-slot-type ( uniform -- type )
200     dup dim>> [ drop sequence ] [
201         uniform-type>> {
202             { bool-uniform    [ boolean ] }
203             { uint-uniform    [ integer ] }
204             { int-uniform     [ integer ] }
205             { float-uniform   [ float   ] }
206             { texture-uniform [ texture ] }
207             [ drop sequence ]
208         } case
209     ] if ;
210
211 : uniform>slot ( uniform -- slot )
212     [ name>> ] [ uniform-slot-type ] bi 2array ;
213
214 : uniform-type-texture-units ( uniform-type -- units )
215     dup texture-uniform = [ drop 1 ] [ "uniform-tuple-texture-units" word-prop 0 or ] if ;
216
217 : all-uniform-tuple-slots ( class -- slots )
218     dup "uniform-tuple-slots" word-prop
219     [ [ superclass-of all-uniform-tuple-slots ] dip append ] [ drop { } ] if* ;
220
221 DEFER: uniform-texture-accessors
222
223 : uniform-type-texture-accessors ( uniform-type -- accessors )
224     texture-uniform = [ { [ ] } ] [ { } ] if ;
225
226 : uniform-slot-texture-accessor ( uniform -- accessor )
227     [ name>> reader-word ] [ [ uniform-type>> ] [ dim>> ] bi uniform-texture-accessors ] bi
228     dup length 1 = [ first swap prefix ] [ [ ] 2sequence ] if ;
229
230 : uniform-tuple-texture-accessors ( uniform-type -- accessors )
231     all-uniform-tuple-slots [ uniform-type>> uniform-type-texture-units zero? ] reject
232     [ uniform-slot-texture-accessor ] map ;
233
234 : uniform-texture-accessors ( uniform-type dim -- accessors )
235     [
236         dup uniform-type?
237         [ uniform-type-texture-accessors ]
238         [ uniform-tuple-texture-accessors ] if
239     ] [
240         2dup swap empty? not and [
241             <iota> [
242                 [ swap nth ] swap prefix
243                 over length 1 = [ swap first append ] [ swap suffix ] if
244             ] with map
245         ] [ drop ] if
246     ] bi* ;
247
248 : texture-accessor>cleave ( unit accessors -- unit' cleaves )
249     dup last sequence?
250     [ [ last [ texture-accessor>cleave ] map ] [ but-last ] bi swap suffix \ cleave suffix ]
251     [ over suffix \ (bind-texture-unit) suffix [ 1 + ] dip ] if ;
252
253 : [bind-uniform-textures] ( class -- quot )
254     f uniform-texture-accessors
255     0 swap [ texture-accessor>cleave ] map nip
256     \ nip swap \ cleave [ ] 3sequence ;
257
258 UNION: binary-data
259     c-ptr specialized-array struct simd-128 ;
260
261 GENERIC: >uniform-bool-array ( sequence -- c-array )
262 GENERIC: >uniform-int-array ( sequence -- c-array )
263 GENERIC: >uniform-uint-array ( sequence -- c-array )
264 GENERIC: >uniform-float-array  ( sequence -- c-array )
265
266 GENERIC#: >uniform-bvec-array 1 ( sequence dim -- c-array )
267 GENERIC#: >uniform-ivec-array 1 ( sequence dim -- c-array )
268 GENERIC#: >uniform-uvec-array 1 ( sequence dim -- c-array )
269 GENERIC#: >uniform-vec-array  1 ( sequence dim -- c-array )
270
271 GENERIC#: >uniform-matrix 2 ( sequence cols rows -- c-array )
272
273 GENERIC#: >uniform-matrix-array 2 ( sequence cols rows -- c-array )
274
275 GENERIC: bind-uniform-bvec2 ( index sequence -- )
276 GENERIC: bind-uniform-bvec3 ( index sequence -- )
277 GENERIC: bind-uniform-bvec4 ( index sequence -- )
278 GENERIC: bind-uniform-ivec2 ( index sequence -- )
279 GENERIC: bind-uniform-ivec3 ( index sequence -- )
280 GENERIC: bind-uniform-ivec4 ( index sequence -- )
281 GENERIC: bind-uniform-uvec2 ( index sequence -- )
282 GENERIC: bind-uniform-uvec3 ( index sequence -- )
283 GENERIC: bind-uniform-uvec4 ( index sequence -- )
284 GENERIC: bind-uniform-vec2  ( index sequence -- )
285 GENERIC: bind-uniform-vec3  ( index sequence -- )
286 GENERIC: bind-uniform-vec4  ( index sequence -- )
287
288 M: object >uniform-bool-array [ >c-bool ] int-array{ } map-as ; inline
289 M: binary-data >uniform-bool-array ; inline
290
291 M: object >uniform-int-array c:int >c-array ; inline
292 M: binary-data >uniform-int-array ; inline
293
294 M: object >uniform-uint-array c:uint >c-array ; inline
295 M: binary-data >uniform-uint-array ; inline
296
297 M: object >uniform-float-array c:float >c-array ; inline
298 M: binary-data >uniform-float-array ; inline
299
300 M: object >uniform-bvec-array '[ _ head-slice [ >c-bool ] int-array{ } map-as ] map concat ; inline
301 M: binary-data >uniform-bvec-array drop ; inline
302
303 M: object >uniform-ivec-array '[ _ head ] map int-array{ } concat-as ; inline
304 M: binary-data >uniform-ivec-array drop ; inline
305
306 M: object >uniform-uvec-array '[ _ head ] map uint-array{ } concat-as ; inline
307 M: binary-data >uniform-uvec-array drop ; inline
308
309 M: object >uniform-vec-array '[ _ head ] map float-array{ } concat-as ; inline
310 M: binary-data >uniform-vec-array drop ; inline
311
312 M:: object >uniform-matrix ( sequence cols rows -- c-array )
313     sequence flip cols head-slice
314     [ rows head-slice c:float >c-array ] { } map-as concat ; inline
315 M: binary-data >uniform-matrix 2drop ; inline
316
317 M: object >uniform-matrix-array
318     '[ _ _ >uniform-matrix ] map concat ; inline
319 M: binary-data >uniform-matrix-array 2drop ; inline
320
321 M: object bind-uniform-bvec2 ( index sequence -- )
322     1 swap 2 head-slice [ >c-bool ] int-array{ } map-as glUniform2iv ; inline
323 M: binary-data bind-uniform-bvec2 ( index sequence -- )
324     1 swap glUniform2iv ; inline
325 M: object bind-uniform-bvec3 ( index sequence -- )
326     1 swap 3 head-slice [ >c-bool ] int-array{ } map-as glUniform3iv ; inline
327 M: binary-data bind-uniform-bvec3 ( index sequence -- )
328     1 swap glUniform3iv ; inline
329 M: object bind-uniform-bvec4 ( index sequence -- )
330     1 swap 4 head-slice [ >c-bool ] int-array{ } map-as glUniform4iv ; inline
331 M: binary-data bind-uniform-bvec4 ( index sequence -- )
332     1 swap glUniform4iv ; inline
333
334 M: object bind-uniform-ivec2 ( index sequence -- ) first2 glUniform2i ; inline
335 M: binary-data bind-uniform-ivec2 ( index sequence -- ) 1 swap glUniform2iv ; inline
336
337 M: object bind-uniform-ivec3 ( index sequence -- ) first3 glUniform3i ; inline
338 M: binary-data bind-uniform-ivec3 ( index sequence -- ) 1 swap glUniform3iv ; inline
339
340 M: object bind-uniform-ivec4 ( index sequence -- ) first4 glUniform4i ; inline
341 M: binary-data bind-uniform-ivec4 ( index sequence -- ) 1 swap glUniform4iv ; inline
342
343 M: object bind-uniform-uvec2 ( index sequence -- ) first2 glUniform2ui ; inline
344 M: binary-data bind-uniform-uvec2 ( index sequence -- ) 1 swap glUniform2uiv ; inline
345
346 M: object bind-uniform-uvec3 ( index sequence -- ) first3 glUniform3ui ; inline
347 M: binary-data bind-uniform-uvec3 ( index sequence -- ) 1 swap glUniform3uiv ; inline
348
349 M: object bind-uniform-uvec4 ( index sequence -- ) first4 glUniform4ui ; inline
350 M: binary-data bind-uniform-uvec4 ( index sequence -- ) 1 swap glUniform4uiv ; inline
351
352 M: object bind-uniform-vec2 ( index sequence -- ) first2 glUniform2f ; inline
353 M: binary-data bind-uniform-vec2 ( index sequence -- ) 1 swap glUniform2fv ; inline
354
355 M: object bind-uniform-vec3 ( index sequence -- ) first3 glUniform3f ; inline
356 M: binary-data bind-uniform-vec3 ( index sequence -- ) 1 swap glUniform3fv ; inline
357
358 M: object bind-uniform-vec4 ( index sequence -- ) first4 glUniform4f ; inline
359 M: binary-data bind-uniform-vec4 ( index sequence -- ) 1 swap glUniform4fv ; inline
360
361 DEFER: [bind-uniform-tuple]
362
363 :: [bind-uniform-array] ( value>>-quot type texture-unit name dim -- texture-unit' quot )
364     { name uniform-index } >quotation :> index-quot
365     { index-quot value>>-quot bi* } >quotation :> pre-quot
366
367     type H{
368         { bool-uniform  { dim swap >uniform-bool-array  glUniform1iv  } }
369         { int-uniform   { dim swap >uniform-int-array   glUniform1iv  } }
370         { uint-uniform  { dim swap >uniform-uint-array  glUniform1uiv } }
371         { float-uniform { dim swap >uniform-float-array glUniform1fv  } }
372
373         { bvec2-uniform { dim swap 2 >uniform-bvec-array glUniform2iv  } }
374         { ivec2-uniform { dim swap 2 >uniform-ivec-array glUniform2i  } }
375         { uvec2-uniform { dim swap 2 >uniform-uvec-array glUniform2ui } }
376         { vec2-uniform  { dim swap 2 >uniform-vec-array  glUniform2f  } }
377
378         { bvec3-uniform { dim swap 3 >uniform-bvec-array glUniform3iv  } }
379         { ivec3-uniform { dim swap 3 >uniform-ivec-array glUniform3i  } }
380         { uvec3-uniform { dim swap 3 >uniform-uvec-array glUniform3ui } }
381         { vec3-uniform  { dim swap 3 >uniform-vec-array  glUniform3f  } }
382
383         { bvec4-uniform { dim swap 4 >uniform-bvec-array glUniform4iv  } }
384         { ivec4-uniform { dim swap 4 >uniform-ivec-array glUniform4iv  } }
385         { uvec4-uniform { dim swap 4 >uniform-uvec-array glUniform4uiv } }
386         { vec4-uniform  { dim swap 4 >uniform-vec-array  glUniform4fv  } }
387
388         { mat2-uniform   { [ dim 0 ] dip 2 2 >uniform-matrix-array glUniformMatrix2fv   } }
389         { mat2x3-uniform { [ dim 0 ] dip 2 3 >uniform-matrix-array glUniformMatrix2x3fv } }
390         { mat2x4-uniform { [ dim 0 ] dip 2 4 >uniform-matrix-array glUniformMatrix2x4fv } }
391
392         { mat3x2-uniform { [ dim 0 ] dip 3 2 >uniform-matrix-array glUniformMatrix3x2fv } }
393         { mat3-uniform   { [ dim 0 ] dip 3 3 >uniform-matrix-array glUniformMatrix3fv   } }
394         { mat3x4-uniform { [ dim 0 ] dip 3 4 >uniform-matrix-array glUniformMatrix3x4fv } }
395
396         { mat4x2-uniform { [ dim 0 ] dip 4 2 >uniform-matrix-array glUniformMatrix4x2fv } }
397         { mat4x3-uniform { [ dim 0 ] dip 4 3 >uniform-matrix-array glUniformMatrix4x3fv } }
398         { mat4-uniform   { [ dim 0 ] dip 4 4 >uniform-matrix-array glUniformMatrix4fv   } }
399
400         { texture-uniform { drop dim dup <iota> [ texture-unit + ] int-array{ } map-as glUniform1iv } }
401     } at [ uniform invalid-uniform-type ] unless* >quotation :> value-quot
402
403     type uniform-type-texture-units dim * texture-unit +
404     pre-quot value-quot append ;
405
406 :: [bind-uniform-value] ( value>>-quot type texture-unit name -- texture-unit' quot )
407     { name uniform-index } >quotation :> index-quot
408     { index-quot value>>-quot bi* } >quotation :> pre-quot
409
410     type H{
411         { bool-uniform  [ >c-bool glUniform1i  ] }
412         { int-uniform   [ glUniform1i  ] }
413         { uint-uniform  [ glUniform1ui ] }
414         { float-uniform [ glUniform1f  ] }
415
416         { bvec2-uniform [ bind-uniform-bvec2 ] }
417         { ivec2-uniform [ bind-uniform-ivec2 ] }
418         { uvec2-uniform [ bind-uniform-uvec2 ] }
419         { vec2-uniform  [ bind-uniform-vec2  ] }
420
421         { bvec3-uniform [ bind-uniform-bvec3 ] }
422         { ivec3-uniform [ bind-uniform-ivec3 ] }
423         { uvec3-uniform [ bind-uniform-uvec3 ] }
424         { vec3-uniform  [ bind-uniform-vec3  ] }
425
426         { bvec4-uniform [ bind-uniform-bvec4 ] }
427         { ivec4-uniform [ bind-uniform-ivec4 ] }
428         { uvec4-uniform [ bind-uniform-uvec4 ] }
429         { vec4-uniform  [ bind-uniform-vec4  ] }
430
431         { mat2-uniform   [ [ 1 0 ] dip 2 2 >uniform-matrix glUniformMatrix2fv   ] }
432         { mat2x3-uniform [ [ 1 0 ] dip 2 3 >uniform-matrix glUniformMatrix2x3fv ] }
433         { mat2x4-uniform [ [ 1 0 ] dip 2 4 >uniform-matrix glUniformMatrix2x4fv ] }
434
435         { mat3x2-uniform [ [ 1 0 ] dip 3 2 >uniform-matrix glUniformMatrix3x2fv ] }
436         { mat3-uniform   [ [ 1 0 ] dip 3 3 >uniform-matrix glUniformMatrix3fv   ] }
437         { mat3x4-uniform [ [ 1 0 ] dip 3 4 >uniform-matrix glUniformMatrix3x4fv ] }
438
439         { mat4x2-uniform [ [ 1 0 ] dip 4 2 >uniform-matrix glUniformMatrix4x2fv ] }
440         { mat4x3-uniform [ [ 1 0 ] dip 4 3 >uniform-matrix glUniformMatrix4x3fv ] }
441         { mat4-uniform   [ [ 1 0 ] dip 4 4 >uniform-matrix glUniformMatrix4fv   ] }
442
443         { texture-uniform { drop texture-unit glUniform1i } }
444     } at [ uniform invalid-uniform-type ] unless* >quotation :> value-quot
445
446     type uniform-type-texture-units texture-unit +
447     pre-quot value-quot append ;
448
449 :: [bind-uniform-struct] ( value>>-quot type texture-unit name dim -- texture-unit' quot )
450     dim
451     [
452         <iota>
453         [ [ [ swap nth ] swap prefix ] map ]
454         [ [ number>string name "[" append "]." surround ] map ] bi
455     ] [
456         { [ ] }
457         name "." append 1array
458     ] if* :> ( quot-prefixes name-prefixes )
459     type all-uniform-tuple-slots :> uniforms
460
461     texture-unit quot-prefixes name-prefixes [| quot-prefix name-prefix |
462         uniforms name-prefix [bind-uniform-tuple]
463         quot-prefix prepend
464     ] 2map :> ( texture-unit' value-cleave )
465
466     texture-unit'
467     value>>-quot { value-cleave 2cleave } append ;
468
469 :: [bind-uniform] ( texture-unit uniform prefix -- texture-unit' quot )
470     prefix uniform name>> append hyphens>underscores :> name
471     uniform uniform-type>> :> type
472     uniform dim>> :> dim
473     uniform name>> reader-word 1quotation :> value>>-quot
474
475     value>>-quot type texture-unit name {
476         { [ type uniform-type? dim     and ] [ dim [bind-uniform-array] ] }
477         { [ type uniform-type? dim not and ] [ [bind-uniform-value] ] }
478         [ dim [bind-uniform-struct] ]
479     } cond ;
480
481 :: [bind-uniform-tuple] ( texture-unit uniforms prefix -- texture-unit' quot )
482     texture-unit uniforms [ prefix [bind-uniform] ] map :> ( texture-unit' uniforms-cleave )
483
484     texture-unit'
485     { uniforms-cleave 2cleave } >quotation ;
486
487 :: [bind-uniforms] ( superclass uniforms -- quot )
488     superclass "uniform-tuple-texture-units" word-prop 0 or :> first-texture-unit
489     superclass \ (bind-uniforms) lookup-method :> next-method
490     first-texture-unit uniforms "" [bind-uniform-tuple] nip :> bind-quot
491
492     { 2dup next-method } bind-quot [ ] append-as ;
493
494 : define-uniform-tuple-methods ( class superclass uniforms -- )
495     [
496         2drop
497         [ \ (bind-uniform-textures) create-method-in ]
498         [ [bind-uniform-textures] ] bi define
499     ] [
500         [ \ (bind-uniforms) create-method-in ] 2dip
501         [bind-uniforms] define
502     ] 3bi ;
503
504 : parse-uniform-tuple-definition ( -- class superclass uniforms )
505     scan-new-class scan-token {
506         { ";" [ uniform-tuple f ] }
507         { "<" [ scan-word parse-array-def [ first3 uniform boa ] map ] }
508         { "{" [
509             uniform-tuple
510             \ } parse-until parse-array-def swap prefix
511             [ first3 uniform boa ] map
512         ] }
513     } case ;
514
515 : (define-uniform-tuple) ( class superclass uniforms -- )
516     {
517         [ [ uniform>slot ] map define-tuple-class ]
518         [
519             [ uniform-type-texture-units ]
520             [
521                 [ [ uniform-type>> uniform-type-texture-units ] [ dim>> 1 or ] bi * ]
522                 [ + ] map-reduce
523             ] bi* +
524             "uniform-tuple-texture-units" set-word-prop
525         ]
526         [ nip "uniform-tuple-slots" set-word-prop ]
527         [ define-uniform-tuple-methods ]
528     } 3cleave ;
529
530 : true-subclasses ( class -- seq )
531     [ subclasses ] keep [ = ] curry reject ;
532
533 PRIVATE>
534
535 : define-uniform-tuple ( class superclass uniforms -- )
536     (define-uniform-tuple) ; inline
537
538 SYNTAX: UNIFORM-TUPLE:
539     parse-uniform-tuple-definition define-uniform-tuple ;
540
541 <PRIVATE
542
543 : bind-unnamed-output-attachments ( framebuffer attachments -- )
544     [ gl-attachment ] with map
545     dup length 1 =
546     [ first glDrawBuffer ]
547     [ [ length ] [ c:int >c-array ] bi glDrawBuffers ] if ;
548
549 : bind-named-output-attachments ( program-instance framebuffer attachments -- )
550     rot '[ first _ swap output-index ] sort-with values
551     bind-unnamed-output-attachments ;
552
553 : bind-output-attachments ( program-instance framebuffer attachments -- )
554     dup first sequence?
555     [ bind-named-output-attachments ] [ nipd bind-unnamed-output-attachments ] if ;
556
557 GENERIC: bind-transform-feedback-output ( output -- )
558
559 M: buffer bind-transform-feedback-output
560     [ GL_TRANSFORM_FEEDBACK_BUFFER 0 ] dip handle>> glBindBufferBase ; inline
561
562 M: buffer-range bind-transform-feedback-output
563     [ GL_TRANSFORM_FEEDBACK_BUFFER 0 ] dip
564     [ handle>> ] [ offset>> ] [ size>> ] tri glBindBufferRange ; inline
565
566 M: buffer-ptr bind-transform-feedback-output
567     buffer-ptr>range bind-transform-feedback-output ; inline
568
569 : gl-feedback-primitive-mode ( primitive-mode -- gl-mode )
570     {
571         { points-mode         [ GL_POINTS    ] }
572         { lines-mode          [ GL_LINES     ] }
573         { line-strip-mode     [ GL_LINES     ] }
574         { line-loop-mode      [ GL_LINES     ] }
575         { triangles-mode      [ GL_TRIANGLES ] }
576         { triangle-strip-mode [ GL_TRIANGLES ] }
577         { triangle-fan-mode   [ GL_TRIANGLES ] }
578     } case ;
579
580 PRIVATE>
581
582 UNION: transform-feedback-output buffer buffer-range POSTPONE: f ;
583
584 TUPLE: render-set
585     { primitive-mode primitive-mode read-only }
586     { vertex-array vertex-array initial: T{ vertex-array-collection } read-only }
587     { uniforms uniform-tuple read-only }
588     { indexes vertex-indexes initial: T{ index-range } read-only }
589     { instances maybe{ integer } initial: f read-only }
590     { framebuffer maybe{ any-framebuffer } initial: system-framebuffer read-only }
591     { output-attachments sequence initial: { default-attachment } read-only }
592     { transform-feedback-output transform-feedback-output initial: f read-only } ;
593
594 : <render-set> ( x quot-assoc -- render-set )
595     render-set swap 1make-tuple ; inline
596
597 : 2<render-set> ( x y quot-assoc -- render-set )
598     render-set swap 2make-tuple ; inline
599
600 : 3<render-set> ( x y z quot-assoc -- render-set )
601     render-set swap 3make-tuple ; inline
602
603 : bind-uniforms ( program-instance uniforms -- )
604     [ (bind-uniform-textures) ] [ (bind-uniforms) ] 2bi ; inline
605
606 : render ( render-set -- )
607     {
608         [ vertex-array>> program-instance>> handle>> glUseProgram ]
609         [
610             [ vertex-array>> program-instance>> ] [ uniforms>> ] bi
611             bind-uniforms
612         ]
613         [
614             framebuffer>>
615             [ GL_DRAW_FRAMEBUFFER swap framebuffer-handle glBindFramebuffer ]
616             [ GL_DRAW_FRAMEBUFFER 0 glBindFramebuffer GL_RASTERIZER_DISCARD glEnable ] if*
617         ]
618         [
619             [ vertex-array>> program-instance>> ]
620             [ framebuffer>> ]
621             [ output-attachments>> ] tri
622             bind-output-attachments
623         ]
624         [ vertex-array>> bind-vertex-array ]
625         [
626             dup transform-feedback-output>> [
627                 [ primitive-mode>> gl-feedback-primitive-mode glBeginTransformFeedback ]
628                 [ bind-transform-feedback-output ] bi*
629             ] [ drop ] if*
630         ]
631
632         [
633             [ primitive-mode>> ] [ indexes>> ] [ instances>> ] tri
634             [ render-vertex-indexes-instanced ]
635             [ render-vertex-indexes ] if*
636         ]
637
638         [ transform-feedback-output>> [ glEndTransformFeedback ] when ]
639         [ framebuffer>> [ GL_RASTERIZER_DISCARD glDisable ] unless ]
640     } cleave ; inline