2016-06-02 19:34:34 +02:00
// Copyright 2016 Hajime Hoshi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2018-10-28 12:10:05 +01:00
package graphicscommand
2016-06-02 19:34:34 +02:00
import (
2016-06-03 05:41:18 +02:00
"fmt"
2019-08-27 15:33:14 +02:00
"math"
2016-06-02 19:34:34 +02:00
2018-08-05 14:30:06 +02:00
"github.com/hajimehoshi/ebiten/internal/affine"
2019-03-30 14:26:27 +01:00
"github.com/hajimehoshi/ebiten/internal/driver"
2018-10-28 12:25:52 +01:00
"github.com/hajimehoshi/ebiten/internal/graphics"
2020-05-17 20:45:58 +02:00
"github.com/hajimehoshi/ebiten/internal/shaderir"
2020-05-24 12:15:18 +02:00
"github.com/hajimehoshi/ebiten/internal/web"
2016-06-02 19:34:34 +02:00
)
2019-03-30 14:26:27 +01:00
var theGraphicsDriver driver . Graphics
2019-03-30 14:13:48 +01:00
2019-03-30 14:26:27 +01:00
func SetGraphicsDriver ( driver driver . Graphics ) {
2019-03-30 14:13:48 +01:00
theGraphicsDriver = driver
}
2019-05-26 12:08:46 +02:00
func NeedsRestoring ( ) bool {
2019-05-26 14:40:10 +02:00
if theGraphicsDriver == nil {
2019-05-26 15:15:31 +02:00
// This happens on initialization.
// Return true for fail-safe
return true
2019-05-26 14:40:10 +02:00
}
2019-05-26 12:08:46 +02:00
return theGraphicsDriver . NeedsRestoring ( )
}
2020-05-24 12:15:18 +02:00
// IsShaderAvailable reports whether shaders are available. This function is only for testing.
func IsShaderAvailable ( ) bool {
if ! theGraphicsDriver . IsGL ( ) {
return false
}
if web . IsBrowser ( ) {
return false
}
return true
}
2017-09-11 20:12:17 +02:00
// command represents a drawing command.
//
2019-04-22 16:12:03 +02:00
// A command for drawing that is created when Image functions are called like DrawTriangles,
2017-09-11 20:12:17 +02:00
// or Fill.
// A command is not immediately executed after created. Instaed, it is queued after created,
// and executed only when necessary.
2016-06-02 19:34:34 +02:00
type command interface {
2018-03-04 16:45:03 +01:00
fmt . Stringer
2018-11-11 15:51:16 +01:00
Exec ( indexOffset int ) error
2018-03-04 15:35:14 +01:00
NumVertices ( ) int
2018-06-10 10:06:40 +02:00
NumIndices ( ) int
2018-03-18 11:58:32 +01:00
AddNumVertices ( n int )
2018-06-10 10:06:40 +02:00
AddNumIndices ( n int )
2020-05-17 20:45:58 +02:00
CanMergeWithDrawTrianglesCommand ( dst , src * Image , color * affine . ColorM , mode driver . CompositeMode , filter driver . Filter , address driver . Address , shader * Shader ) bool
2016-06-02 19:34:34 +02:00
}
2019-06-21 20:50:56 +02:00
type size struct {
width float32
height float32
}
2017-09-16 08:49:29 +02:00
// commandQueue is a command queue for drawing commands.
2016-06-02 19:34:34 +02:00
type commandQueue struct {
2017-09-18 18:37:24 +02:00
// commands is a queue of drawing commands.
commands [ ] command
// vertices represents a vertices data in OpenGL's array buffer.
vertices [ ] float32
2018-03-04 15:35:14 +01:00
// nvertices represents the current length of vertices.
// nvertices must <= len(vertices).
2017-09-18 18:37:24 +02:00
// vertices is never shrunk since re-extending a vertices buffer is heavy.
2018-06-10 10:10:11 +02:00
//
// TODO: This is a number of float32 values, not a number of vertices.
// Rename or fix the program.
2018-03-04 15:35:14 +01:00
nvertices int
2018-05-30 17:53:02 +02:00
2019-06-26 04:45:06 +02:00
srcSizes [ ] size
2019-06-21 20:50:56 +02:00
2018-06-10 10:06:40 +02:00
indices [ ] uint16
nindices int
2018-06-09 21:55:44 +02:00
2018-06-10 10:06:40 +02:00
tmpNumIndices int
nextIndex int
2018-07-11 19:11:18 +02:00
err error
2016-06-02 19:34:34 +02:00
}
2017-09-16 08:49:29 +02:00
// theCommandQueue is the command queue for the current process.
2017-05-26 15:32:38 +02:00
var theCommandQueue = & commandQueue { }
2017-01-18 17:26:56 +01:00
2017-09-18 18:37:24 +02:00
// appendVertices appends vertices to the queue.
2020-05-24 09:43:08 +02:00
func ( q * commandQueue ) appendVertices ( vertices [ ] float32 , src * Image ) {
2018-03-04 15:35:14 +01:00
if len ( q . vertices ) < q . nvertices + len ( vertices ) {
n := q . nvertices + len ( vertices ) - len ( q . vertices )
2017-01-18 17:26:56 +01:00
q . vertices = append ( q . vertices , make ( [ ] float32 , n ) ... )
2019-06-26 04:45:06 +02:00
q . srcSizes = append ( q . srcSizes , make ( [ ] size , n / graphics . VertexFloatNum ) ... )
2017-01-18 17:26:56 +01:00
}
2018-06-16 18:09:05 +02:00
copy ( q . vertices [ q . nvertices : ] , vertices )
2019-09-27 19:31:04 +02:00
2019-09-28 16:09:20 +02:00
n := len ( vertices ) / graphics . VertexFloatNum
base := q . nvertices / graphics . VertexFloatNum
2020-05-24 09:43:08 +02:00
width := float32 ( 1 )
height := float32 ( 1 )
2020-05-30 08:07:24 +02:00
// src is nil when a shader is used and there are no images in the uniform variables.
2020-05-24 09:43:08 +02:00
if src != nil {
w , h := src . InternalSize ( )
width = float32 ( w )
height = float32 ( h )
}
2019-09-27 19:31:04 +02:00
for i := 0 ; i < n ; i ++ {
idx := base + i
2019-06-26 04:45:06 +02:00
q . srcSizes [ idx ] . width = width
q . srcSizes [ idx ] . height = height
2019-06-21 20:50:56 +02:00
}
2018-03-04 15:35:14 +01:00
q . nvertices += len ( vertices )
2016-06-02 19:34:34 +02:00
}
2018-06-10 10:06:40 +02:00
func ( q * commandQueue ) appendIndices ( indices [ ] uint16 , offset uint16 ) {
if len ( q . indices ) < q . nindices + len ( indices ) {
n := q . nindices + len ( indices ) - len ( q . indices )
q . indices = append ( q . indices , make ( [ ] uint16 , n ) ... )
2018-06-03 11:48:14 +02:00
}
2018-06-09 21:55:44 +02:00
for i := range indices {
2018-06-10 10:06:40 +02:00
q . indices [ q . nindices + i ] = indices [ i ] + offset
2018-06-09 21:55:44 +02:00
}
2018-06-10 10:06:40 +02:00
q . nindices += len ( indices )
2018-06-03 11:48:14 +02:00
}
2019-04-22 16:12:03 +02:00
// EnqueueDrawTrianglesCommand enqueues a drawing-image command.
2020-05-26 15:50:33 +02:00
func ( q * commandQueue ) EnqueueDrawTrianglesCommand ( dst , src * Image , vertices [ ] float32 , indices [ ] uint16 , color * affine . ColorM , mode driver . CompositeMode , filter driver . Filter , address driver . Address , shader * Shader , uniforms [ ] interface { } ) {
2018-11-06 17:49:45 +01:00
if len ( indices ) > graphics . IndicesNum {
2019-04-22 16:12:03 +02:00
panic ( fmt . Sprintf ( "graphicscommand: len(indices) must be <= graphics.IndicesNum but not at EnqueueDrawTrianglesCommand: len(indices): %d, graphics.IndicesNum: %d" , len ( indices ) , graphics . IndicesNum ) )
2018-06-03 11:48:14 +02:00
}
2018-06-09 21:55:44 +02:00
split := false
2018-11-06 17:49:45 +01:00
if q . tmpNumIndices + len ( indices ) > graphics . IndicesNum {
2018-06-10 10:06:40 +02:00
q . tmpNumIndices = 0
2018-06-09 21:55:44 +02:00
q . nextIndex = 0
split = true
}
2020-05-17 20:45:58 +02:00
if src != nil {
2020-05-24 09:43:08 +02:00
q . appendVertices ( vertices , src )
2020-05-17 20:45:58 +02:00
} else {
2020-05-24 09:43:08 +02:00
var img * Image
2020-05-30 08:07:24 +02:00
for _ , v := range uniforms {
if i , ok := v . ( * Image ) ; ok {
2020-05-24 09:43:08 +02:00
img = i
2020-05-30 08:07:24 +02:00
break
2020-05-24 09:43:08 +02:00
}
}
q . appendVertices ( vertices , img )
2020-05-17 20:45:58 +02:00
}
2018-06-10 10:06:40 +02:00
q . appendIndices ( indices , uint16 ( q . nextIndex ) )
2020-05-24 09:43:08 +02:00
q . nextIndex += len ( vertices ) / graphics . VertexFloatNum
2018-06-10 10:06:40 +02:00
q . tmpNumIndices += len ( indices )
2018-06-09 21:55:44 +02:00
2019-04-12 17:22:11 +02:00
// TODO: If dst is the screen, reorder the command to be the last.
2019-11-13 16:08:44 +01:00
if ! split && 0 < len ( q . commands ) {
2020-05-17 20:45:58 +02:00
if last := q . commands [ len ( q . commands ) - 1 ] ; last . CanMergeWithDrawTrianglesCommand ( dst , src , color , mode , filter , address , shader ) {
2019-11-13 16:08:44 +01:00
last . AddNumVertices ( len ( vertices ) )
last . AddNumIndices ( len ( indices ) )
return
}
}
2020-05-17 20:45:58 +02:00
2019-11-13 16:08:44 +01:00
c := & drawTrianglesCommand {
dst : dst ,
src : src ,
nvertices : len ( vertices ) ,
nindices : len ( indices ) ,
color : color ,
mode : mode ,
filter : filter ,
address : address ,
2020-05-17 20:45:58 +02:00
shader : shader ,
uniforms : uniforms ,
2019-11-13 16:08:44 +01:00
}
q . commands = append ( q . commands , c )
2017-05-02 15:45:09 +02:00
}
2019-05-08 04:58:02 +02:00
// Enqueue enqueues a drawing command other than a draw-triangles command.
2017-09-19 18:35:56 +02:00
//
2019-05-08 04:58:02 +02:00
// For a draw-triangles command, use EnqueueDrawTrianglesCommand.
2017-05-02 15:45:09 +02:00
func ( q * commandQueue ) Enqueue ( command command ) {
2019-04-12 17:22:11 +02:00
// TODO: If dst is the screen, reorder the command to be the last.
2016-11-03 09:40:52 +01:00
q . commands = append ( q . commands , command )
2016-10-25 04:53:00 +02:00
}
2019-08-27 15:33:14 +02:00
func fract ( x float32 ) float32 {
return x - float32 ( math . Floor ( float64 ( x ) ) )
}
2020-05-30 15:39:39 +02:00
const (
dstAdjustmentFactor = 1.0 / 256.0
texelAdjustmentFactor = 1.0 / 512.0
)
2017-09-19 18:35:56 +02:00
// Flush flushes the command queue.
2020-01-18 17:18:56 +01:00
func ( q * commandQueue ) Flush ( ) error {
2020-04-22 17:51:25 +02:00
if len ( q . commands ) == 0 {
return nil
}
2018-06-10 10:06:40 +02:00
es := q . indices
2018-06-03 14:47:08 +02:00
vs := q . vertices
2018-03-04 16:45:03 +01:00
if recordLog ( ) {
fmt . Println ( "--" )
}
2019-04-20 08:17:59 +02:00
2019-06-21 21:47:48 +02:00
if theGraphicsDriver . HasHighPrecisionFloat ( ) {
2019-09-26 20:28:07 +02:00
n := q . nvertices / graphics . VertexFloatNum
for i := 0 ; i < n ; i ++ {
2019-06-26 04:45:06 +02:00
s := q . srcSizes [ i ]
2019-08-27 15:33:14 +02:00
2019-09-20 16:59:04 +02:00
// Convert pixels to texels.
vs [ i * graphics . VertexFloatNum + 2 ] /= s . width
vs [ i * graphics . VertexFloatNum + 3 ] /= s . height
vs [ i * graphics . VertexFloatNum + 4 ] /= s . width
vs [ i * graphics . VertexFloatNum + 5 ] /= s . height
vs [ i * graphics . VertexFloatNum + 6 ] /= s . width
vs [ i * graphics . VertexFloatNum + 7 ] /= s . height
2019-08-27 15:33:14 +02:00
// Adjust the destination position to avoid jaggy (#929).
// This is not a perfect solution since texels on a texture can take a position on borders
// which can cause jaggy. But adjusting only edges should work in most cases.
// The ideal solution is to fix shaders, but this makes the applications slow by adding 'if'
// branches.
switch f := fract ( vs [ i * graphics . VertexFloatNum + 0 ] ) ; {
case 0.5 - dstAdjustmentFactor <= f && f < 0.5 :
vs [ i * graphics . VertexFloatNum + 0 ] -= f - ( 0.5 - dstAdjustmentFactor )
case 0.5 <= f && f < 0.5 + dstAdjustmentFactor :
vs [ i * graphics . VertexFloatNum + 0 ] += ( 0.5 + dstAdjustmentFactor ) - f
}
switch f := fract ( vs [ i * graphics . VertexFloatNum + 1 ] ) ; {
case 0.5 - dstAdjustmentFactor <= f && f < 0.5 :
vs [ i * graphics . VertexFloatNum + 1 ] -= f - ( 0.5 - dstAdjustmentFactor )
case 0.5 <= f && f < 0.5 + dstAdjustmentFactor :
vs [ i * graphics . VertexFloatNum + 1 ] += ( 0.5 + dstAdjustmentFactor ) - f
}
// Adjust regions not to violate neighborhoods (#317, #558, #724).
2019-06-21 21:47:48 +02:00
vs [ i * graphics . VertexFloatNum + 6 ] -= 1.0 / s . width * texelAdjustmentFactor
vs [ i * graphics . VertexFloatNum + 7 ] -= 1.0 / s . height * texelAdjustmentFactor
}
2019-10-19 09:28:53 +02:00
} else {
n := q . nvertices / graphics . VertexFloatNum
for i := 0 ; i < n ; i ++ {
s := q . srcSizes [ i ]
// Convert pixels to texels.
vs [ i * graphics . VertexFloatNum + 2 ] /= s . width
vs [ i * graphics . VertexFloatNum + 3 ] /= s . height
vs [ i * graphics . VertexFloatNum + 4 ] /= s . width
vs [ i * graphics . VertexFloatNum + 5 ] /= s . height
vs [ i * graphics . VertexFloatNum + 6 ] /= s . width
vs [ i * graphics . VertexFloatNum + 7 ] /= s . height
}
2019-06-21 20:50:56 +02:00
}
2020-05-29 22:19:49 +02:00
2019-04-20 08:17:59 +02:00
theGraphicsDriver . Begin ( )
2019-09-28 20:23:40 +02:00
cs := q . commands
for len ( cs ) > 0 {
2018-06-03 14:47:08 +02:00
nv := 0
ne := 0
nc := 0
2019-09-28 20:23:40 +02:00
for _ , c := range cs {
2018-11-06 17:49:45 +01:00
if c . NumIndices ( ) > graphics . IndicesNum {
2019-02-07 09:19:24 +01:00
panic ( fmt . Sprintf ( "graphicscommand: c.NumIndices() must be <= graphics.IndicesNum but not at Flush: c.NumIndices(): %d, graphics.IndicesNum: %d" , c . NumIndices ( ) , graphics . IndicesNum ) )
2018-06-03 14:47:08 +02:00
}
2018-11-06 17:49:45 +01:00
if ne + c . NumIndices ( ) > graphics . IndicesNum {
2018-06-03 14:47:08 +02:00
break
}
2018-06-03 11:48:14 +02:00
nv += c . NumVertices ( )
2018-06-10 10:06:40 +02:00
ne += c . NumIndices ( )
2018-06-03 14:47:08 +02:00
nc ++
2016-06-03 05:41:18 +02:00
}
2018-06-03 14:47:08 +02:00
if 0 < ne {
2019-03-30 14:13:48 +01:00
theGraphicsDriver . SetVertices ( vs [ : nv ] , es [ : ne ] )
2018-06-03 14:47:08 +02:00
es = es [ ne : ]
vs = vs [ nv : ]
2016-07-16 12:17:57 +02:00
}
2018-11-11 15:51:16 +01:00
indexOffset := 0
2019-09-28 20:23:40 +02:00
for _ , c := range cs [ : nc ] {
2018-11-11 15:51:16 +01:00
if err := c . Exec ( indexOffset ) ; err != nil {
2020-01-18 17:18:56 +01:00
return err
2016-07-16 12:17:57 +02:00
}
2018-03-04 16:45:03 +01:00
if recordLog ( ) {
fmt . Printf ( "%s\n" , c )
}
2018-11-11 15:51:16 +01:00
// TODO: indexOffset should be reset if the command type is different
2018-05-27 17:49:16 +02:00
// from the previous one. This fix is needed when another drawing command is
2019-04-22 16:12:03 +02:00
// introduced than drawTrianglesCommand.
2018-11-11 15:51:16 +01:00
indexOffset += c . NumIndices ( )
2016-07-16 12:17:57 +02:00
}
2019-09-28 20:23:40 +02:00
cs = cs [ nc : ]
2016-06-02 19:34:34 +02:00
}
2019-04-20 08:17:59 +02:00
theGraphicsDriver . End ( )
2019-09-26 17:34:55 +02:00
q . commands = q . commands [ : 0 ]
2018-03-04 15:35:14 +01:00
q . nvertices = 0
2018-06-10 10:06:40 +02:00
q . nindices = 0
q . tmpNumIndices = 0
2018-06-03 11:48:14 +02:00
q . nextIndex = 0
2020-01-18 17:18:56 +01:00
return nil
2016-06-02 19:34:34 +02:00
}
2017-09-19 18:35:56 +02:00
// FlushCommands flushes the command queue.
2020-01-18 17:18:56 +01:00
func FlushCommands ( ) error {
return theCommandQueue . Flush ( )
2016-06-10 22:48:09 +02:00
}
2019-04-22 16:12:03 +02:00
// drawTrianglesCommand represents a drawing command to draw an image on another image.
type drawTrianglesCommand struct {
2018-03-04 15:35:14 +01:00
dst * Image
src * Image
nvertices int
2018-06-10 10:06:40 +02:00
nindices int
2018-08-05 14:30:06 +02:00
color * affine . ColorM
2019-06-25 17:43:09 +02:00
mode driver . CompositeMode
filter driver . Filter
address driver . Address
2020-05-17 20:45:58 +02:00
shader * Shader
2020-05-26 15:50:33 +02:00
uniforms [ ] interface { }
2016-06-02 19:34:34 +02:00
}
2019-04-22 16:12:03 +02:00
func ( c * drawTrianglesCommand ) String ( ) string {
2019-07-19 16:18:07 +02:00
mode := ""
switch c . mode {
case driver . CompositeModeSourceOver :
mode = "source-over"
case driver . CompositeModeClear :
mode = "clear"
case driver . CompositeModeCopy :
mode = "copy"
case driver . CompositeModeDestination :
mode = "destination"
case driver . CompositeModeDestinationOver :
mode = "destination-over"
case driver . CompositeModeSourceIn :
mode = "source-in"
case driver . CompositeModeDestinationIn :
mode = "destination-in"
case driver . CompositeModeSourceOut :
mode = "source-out"
case driver . CompositeModeDestinationOut :
mode = "destination-out"
case driver . CompositeModeSourceAtop :
mode = "source-atop"
case driver . CompositeModeDestinationAtop :
mode = "destination-atop"
case driver . CompositeModeXor :
mode = "xor"
case driver . CompositeModeLighter :
mode = "lighter"
default :
panic ( fmt . Sprintf ( "graphicscommand: invalid composite mode: %d" , c . mode ) )
}
2020-05-17 20:45:58 +02:00
dst := fmt . Sprintf ( "%d" , c . dst . id )
if c . dst . screen {
dst += " (screen)"
}
if c . shader != nil {
return fmt . Sprintf ( "draw-triangles: dst: %s, shader, num of indices: %d, mode %s" , dst , c . nindices , mode )
}
2019-07-19 16:18:07 +02:00
filter := ""
switch c . filter {
case driver . FilterNearest :
filter = "nearest"
case driver . FilterLinear :
filter = "linear"
case driver . FilterScreen :
filter = "screen"
default :
panic ( fmt . Sprintf ( "graphicscommand: invalid filter: %d" , c . filter ) )
}
address := ""
switch c . address {
case driver . AddressClampToZero :
address = "clamp_to_zero"
case driver . AddressRepeat :
address = "repeat"
default :
panic ( fmt . Sprintf ( "graphicscommand: invalid address: %d" , c . address ) )
}
2019-07-20 07:29:04 +02:00
src := fmt . Sprintf ( "%d" , c . src . id )
if c . src . screen {
src += " (screen)"
}
2020-04-08 06:48:22 +02:00
return fmt . Sprintf ( "draw-triangles: dst: %s <- src: %s, num of indices: %d, colorm: %v, mode %s, filter: %s, address: %s" , dst , src , c . nindices , c . color , mode , filter , address )
2018-03-04 16:45:03 +01:00
}
2019-04-22 16:12:03 +02:00
// Exec executes the drawTrianglesCommand.
func ( c * drawTrianglesCommand ) Exec ( indexOffset int ) error {
2018-11-05 19:44:43 +01:00
// TODO: Is it ok not to bind any framebuffer here?
2018-06-10 10:06:40 +02:00
if c . nindices == 0 {
2016-06-03 05:41:18 +02:00
return nil
}
2018-11-05 19:44:43 +01:00
2020-05-17 20:45:58 +02:00
if c . shader != nil {
2020-05-26 15:50:33 +02:00
us := make ( [ ] interface { } , len ( c . uniforms ) )
2020-05-30 08:44:59 +02:00
firstImage := true
for i := 0 ; i < len ( c . uniforms ) ; i ++ {
switch v := c . uniforms [ i ] . ( type ) {
2020-05-24 19:31:54 +02:00
case * Image :
2020-05-30 08:44:59 +02:00
us [ i ] = v . image . ID ( )
2020-05-30 15:39:39 +02:00
if firstImage {
firstImage = false
continue
}
// Convert pixels to texels.
w , h := v . InternalSize ( )
i ++
region := c . uniforms [ i ] . ( [ ] float32 )
vs := [ ] float32 {
region [ 0 ] / float32 ( w ) ,
region [ 1 ] / float32 ( h ) ,
region [ 2 ] / float32 ( w ) ,
region [ 3 ] / float32 ( h ) ,
}
// Adjust regions not to violate neighborhoods (#317, #558, #724).
if theGraphicsDriver . HasHighPrecisionFloat ( ) {
vs [ 2 ] -= 1.0 / float32 ( w ) * texelAdjustmentFactor
vs [ 3 ] -= 1.0 / float32 ( h ) * texelAdjustmentFactor
2020-05-30 08:44:59 +02:00
}
2020-05-30 15:39:39 +02:00
us [ i ] = vs
2020-05-24 19:31:54 +02:00
default :
2020-05-30 08:44:59 +02:00
us [ i ] = v
2020-05-24 19:31:54 +02:00
}
}
2020-06-04 20:00:43 +02:00
// The last uniform variables are added at /shader.go and represents a viewport size.
w , h := c . dst . InternalSize ( )
viewport := us [ 0 ] . ( [ ] float32 )
viewport [ 0 ] = float32 ( w )
viewport [ 1 ] = float32 ( h )
2020-05-24 19:31:54 +02:00
return theGraphicsDriver . DrawShader ( c . dst . image . ID ( ) , c . shader . shader . ID ( ) , c . nindices , indexOffset , c . mode , us )
2018-11-05 19:44:43 +01:00
}
2020-05-17 20:45:58 +02:00
return theGraphicsDriver . Draw ( c . dst . image . ID ( ) , c . src . image . ID ( ) , c . nindices , indexOffset , c . mode , c . color , c . filter , c . address )
2016-06-02 19:34:34 +02:00
}
2019-04-22 16:12:03 +02:00
func ( c * drawTrianglesCommand ) NumVertices ( ) int {
2018-03-04 15:35:14 +01:00
return c . nvertices
}
2019-04-22 16:12:03 +02:00
func ( c * drawTrianglesCommand ) NumIndices ( ) int {
2018-06-10 10:06:40 +02:00
return c . nindices
2018-06-03 08:16:30 +02:00
}
2019-04-22 16:12:03 +02:00
func ( c * drawTrianglesCommand ) AddNumVertices ( n int ) {
2018-03-18 11:58:32 +01:00
c . nvertices += n
}
2019-04-22 16:12:03 +02:00
func ( c * drawTrianglesCommand ) AddNumIndices ( n int ) {
2018-06-10 10:06:40 +02:00
c . nindices += n
2018-06-03 08:16:30 +02:00
}
2019-11-13 16:08:44 +01:00
// CanMergeWithDrawTrianglesCommand returns a boolean value indicating whether the other drawTrianglesCommand can be merged
2019-04-22 16:12:03 +02:00
// with the drawTrianglesCommand c.
2020-05-17 20:45:58 +02:00
func ( c * drawTrianglesCommand ) CanMergeWithDrawTrianglesCommand ( dst , src * Image , color * affine . ColorM , mode driver . CompositeMode , filter driver . Filter , address driver . Address , shader * Shader ) bool {
// If a shader is used, commands are not merged.
//
// TODO: Merge shader commands considering uniform variables.
if c . shader != nil || shader != nil {
return false
}
2017-05-02 15:45:09 +02:00
if c . dst != dst {
2016-10-25 04:53:00 +02:00
return false
}
2017-05-02 15:45:09 +02:00
if c . src != src {
2016-10-25 04:53:00 +02:00
return false
}
2018-08-05 14:30:06 +02:00
if ! c . color . Equals ( color ) {
return false
}
2017-05-02 15:45:09 +02:00
if c . mode != mode {
2016-10-25 04:53:00 +02:00
return false
}
2018-02-13 18:02:48 +01:00
if c . filter != filter {
return false
}
2018-12-23 19:00:00 +01:00
if c . address != address {
return false
}
2016-10-25 04:53:00 +02:00
return true
}
2017-09-19 18:35:56 +02:00
// replacePixelsCommand represents a command to replace pixels of an image.
2016-06-02 19:34:34 +02:00
type replacePixelsCommand struct {
2019-11-21 15:42:46 +01:00
dst * Image
args [ ] * driver . ReplacePixelsArgs
2016-06-02 19:34:34 +02:00
}
2018-03-04 16:45:03 +01:00
func ( c * replacePixelsCommand ) String ( ) string {
2019-11-21 15:42:46 +01:00
return fmt . Sprintf ( "replace-pixels: dst: %d, len(args): %d" , c . dst . id , len ( c . args ) )
2018-03-04 16:45:03 +01:00
}
2017-09-19 18:35:56 +02:00
// Exec executes the replacePixelsCommand.
2018-11-11 15:51:16 +01:00
func ( c * replacePixelsCommand ) Exec ( indexOffset int ) error {
2019-11-21 15:42:46 +01:00
c . dst . image . ReplacePixels ( c . args )
2016-06-02 19:34:34 +02:00
return nil
}
2016-06-11 15:52:07 +02:00
2018-03-04 15:35:14 +01:00
func ( c * replacePixelsCommand ) NumVertices ( ) int {
return 0
}
2018-06-10 10:06:40 +02:00
func ( c * replacePixelsCommand ) NumIndices ( ) int {
2018-06-03 08:16:30 +02:00
return 0
}
2018-03-18 11:58:32 +01:00
func ( c * replacePixelsCommand ) AddNumVertices ( n int ) {
}
2018-06-10 10:06:40 +02:00
func ( c * replacePixelsCommand ) AddNumIndices ( n int ) {
2018-06-03 08:16:30 +02:00
}
2020-05-17 20:45:58 +02:00
func ( c * replacePixelsCommand ) CanMergeWithDrawTrianglesCommand ( dst , src * Image , color * affine . ColorM , mode driver . CompositeMode , filter driver . Filter , address driver . Address , shader * Shader ) bool {
2018-03-18 11:58:32 +01:00
return false
}
2018-07-11 19:40:06 +02:00
type pixelsCommand struct {
result [ ] byte
img * Image
}
// Exec executes a pixelsCommand.
2018-11-11 15:51:16 +01:00
func ( c * pixelsCommand ) Exec ( indexOffset int ) error {
2018-11-04 11:06:13 +01:00
p , err := c . img . image . Pixels ( )
2018-07-11 19:40:06 +02:00
if err != nil {
return err
}
c . result = p
return nil
}
2018-03-04 16:45:03 +01:00
func ( c * pixelsCommand ) String ( ) string {
2019-07-19 16:18:07 +02:00
return fmt . Sprintf ( "pixels: image: %d" , c . img . id )
2018-03-04 16:45:03 +01:00
}
2018-07-11 19:40:06 +02:00
func ( c * pixelsCommand ) NumVertices ( ) int {
return 0
}
func ( c * pixelsCommand ) NumIndices ( ) int {
return 0
}
func ( c * pixelsCommand ) AddNumVertices ( n int ) {
}
func ( c * pixelsCommand ) AddNumIndices ( n int ) {
}
2020-05-17 20:45:58 +02:00
func ( c * pixelsCommand ) CanMergeWithDrawTrianglesCommand ( dst , src * Image , color * affine . ColorM , mode driver . CompositeMode , filter driver . Filter , address driver . Address , shader * Shader ) bool {
2018-07-11 19:40:06 +02:00
return false
}
2020-05-17 20:45:58 +02:00
// disposeImageCommand represents a command to dispose an image.
type disposeImageCommand struct {
2016-06-12 15:44:23 +02:00
target * Image
2016-06-11 15:52:07 +02:00
}
2020-05-17 20:45:58 +02:00
func ( c * disposeImageCommand ) String ( ) string {
return fmt . Sprintf ( "dispose-image: target: %d" , c . target . id )
2018-03-04 16:45:03 +01:00
}
2020-05-17 20:45:58 +02:00
// Exec executes the disposeImageCommand.
func ( c * disposeImageCommand ) Exec ( indexOffset int ) error {
2018-11-12 15:44:13 +01:00
c . target . image . Dispose ( )
2016-06-11 15:52:07 +02:00
return nil
}
2016-06-11 17:23:26 +02:00
2020-05-17 20:45:58 +02:00
func ( c * disposeImageCommand ) NumVertices ( ) int {
return 0
}
func ( c * disposeImageCommand ) NumIndices ( ) int {
return 0
}
func ( c * disposeImageCommand ) AddNumVertices ( n int ) {
}
func ( c * disposeImageCommand ) AddNumIndices ( n int ) {
}
func ( c * disposeImageCommand ) CanMergeWithDrawTrianglesCommand ( dst , src * Image , color * affine . ColorM , mode driver . CompositeMode , filter driver . Filter , address driver . Address , shader * Shader ) bool {
return false
}
// disposeShaderCommand represents a command to dispose a shader.
type disposeShaderCommand struct {
target * Shader
}
func ( c * disposeShaderCommand ) String ( ) string {
return fmt . Sprintf ( "dispose-shader: target" )
}
// Exec executes the disposeShaderCommand.
func ( c * disposeShaderCommand ) Exec ( indexOffset int ) error {
c . target . shader . Dispose ( )
return nil
}
func ( c * disposeShaderCommand ) NumVertices ( ) int {
2018-03-04 15:35:14 +01:00
return 0
}
2020-05-17 20:45:58 +02:00
func ( c * disposeShaderCommand ) NumIndices ( ) int {
2018-06-03 08:16:30 +02:00
return 0
}
2020-05-17 20:45:58 +02:00
func ( c * disposeShaderCommand ) AddNumVertices ( n int ) {
2018-03-18 11:58:32 +01:00
}
2020-05-17 20:45:58 +02:00
func ( c * disposeShaderCommand ) AddNumIndices ( n int ) {
2018-06-03 08:16:30 +02:00
}
2020-05-17 20:45:58 +02:00
func ( c * disposeShaderCommand ) CanMergeWithDrawTrianglesCommand ( dst , src * Image , color * affine . ColorM , mode driver . CompositeMode , filter driver . Filter , address driver . Address , shader * Shader ) bool {
2018-03-18 11:58:32 +01:00
return false
}
2017-09-19 18:35:56 +02:00
// newImageCommand represents a command to create an empty image with given width and height.
2016-06-11 17:23:26 +02:00
type newImageCommand struct {
2016-06-12 15:44:23 +02:00
result * Image
width int
height int
2016-06-11 17:23:26 +02:00
}
2018-03-04 16:45:03 +01:00
func ( c * newImageCommand ) String ( ) string {
2019-07-19 16:18:07 +02:00
return fmt . Sprintf ( "new-image: result: %d, width: %d, height: %d" , c . result . id , c . width , c . height )
2018-03-04 16:45:03 +01:00
}
2017-09-19 18:35:56 +02:00
// Exec executes a newImageCommand.
2018-11-11 15:51:16 +01:00
func ( c * newImageCommand ) Exec ( indexOffset int ) error {
2019-03-30 14:13:48 +01:00
i , err := theGraphicsDriver . NewImage ( c . width , c . height )
2016-06-11 17:23:26 +02:00
if err != nil {
return err
}
2018-11-04 11:36:33 +01:00
c . result . image = i
2016-06-11 17:23:26 +02:00
return nil
}
2016-06-17 21:46:33 +02:00
2018-03-04 15:35:14 +01:00
func ( c * newImageCommand ) NumVertices ( ) int {
return 0
}
2018-06-10 10:06:40 +02:00
func ( c * newImageCommand ) NumIndices ( ) int {
2018-06-03 08:16:30 +02:00
return 0
}
2018-03-18 11:58:32 +01:00
func ( c * newImageCommand ) AddNumVertices ( n int ) {
}
2018-06-10 10:06:40 +02:00
func ( c * newImageCommand ) AddNumIndices ( n int ) {
2018-06-03 08:16:30 +02:00
}
2020-05-17 20:45:58 +02:00
func ( c * newImageCommand ) CanMergeWithDrawTrianglesCommand ( dst , src * Image , color * affine . ColorM , mode driver . CompositeMode , filter driver . Filter , address driver . Address , shader * Shader ) bool {
2018-03-18 11:58:32 +01:00
return false
}
2017-09-19 18:35:56 +02:00
// newScreenFramebufferImageCommand is a command to create a special image for the screen.
2016-06-17 21:46:33 +02:00
type newScreenFramebufferImageCommand struct {
2018-02-24 15:35:55 +01:00
result * Image
width int
height int
2016-06-17 21:46:33 +02:00
}
2018-03-04 16:45:03 +01:00
func ( c * newScreenFramebufferImageCommand ) String ( ) string {
2019-07-19 16:18:07 +02:00
return fmt . Sprintf ( "new-screen-framebuffer-image: result: %d, width: %d, height: %d" , c . result . id , c . width , c . height )
2018-03-04 16:45:03 +01:00
}
2017-09-19 18:35:56 +02:00
// Exec executes a newScreenFramebufferImageCommand.
2018-11-11 15:51:16 +01:00
func ( c * newScreenFramebufferImageCommand ) Exec ( indexOffset int ) error {
2018-11-11 15:57:23 +01:00
var err error
2019-03-30 14:13:48 +01:00
c . result . image , err = theGraphicsDriver . NewScreenFramebufferImage ( c . width , c . height )
2018-11-11 15:57:23 +01:00
return err
2016-06-17 21:46:33 +02:00
}
2018-03-04 15:35:14 +01:00
func ( c * newScreenFramebufferImageCommand ) NumVertices ( ) int {
return 0
}
2018-03-18 11:58:32 +01:00
2018-06-10 10:06:40 +02:00
func ( c * newScreenFramebufferImageCommand ) NumIndices ( ) int {
2018-06-03 08:16:30 +02:00
return 0
}
2018-03-18 11:58:32 +01:00
func ( c * newScreenFramebufferImageCommand ) AddNumVertices ( n int ) {
}
2018-06-10 10:06:40 +02:00
func ( c * newScreenFramebufferImageCommand ) AddNumIndices ( n int ) {
2018-06-03 08:16:30 +02:00
}
2020-05-17 20:45:58 +02:00
func ( c * newScreenFramebufferImageCommand ) CanMergeWithDrawTrianglesCommand ( dst , src * Image , color * affine . ColorM , mode driver . CompositeMode , filter driver . Filter , address driver . Address , shader * Shader ) bool {
return false
}
// newShaderCommand is a command to create a shader.
type newShaderCommand struct {
result * Shader
ir * shaderir . Program
}
func ( c * newShaderCommand ) String ( ) string {
return fmt . Sprintf ( "new-shader-image" )
}
// Exec executes a newShaderCommand.
func ( c * newShaderCommand ) Exec ( indexOffset int ) error {
var err error
c . result . shader , err = theGraphicsDriver . NewShader ( c . ir )
return err
}
func ( c * newShaderCommand ) NumVertices ( ) int {
return 0
}
func ( c * newShaderCommand ) NumIndices ( ) int {
return 0
}
func ( c * newShaderCommand ) AddNumVertices ( n int ) {
}
func ( c * newShaderCommand ) AddNumIndices ( n int ) {
}
func ( c * newShaderCommand ) CanMergeWithDrawTrianglesCommand ( dst , src * Image , color * affine . ColorM , mode driver . CompositeMode , filter driver . Filter , address driver . Address , shader * Shader ) bool {
2018-03-18 11:58:32 +01:00
return false
}
2018-10-29 17:27:31 +01:00
2018-10-31 19:02:08 +01:00
// ResetGraphicsDriverState resets or initializes the current graphics driver state.
func ResetGraphicsDriverState ( ) error {
2019-03-30 14:13:48 +01:00
return theGraphicsDriver . Reset ( )
2018-10-29 17:27:31 +01:00
}