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"
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 ( )
}
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 )
2019-06-25 17:43:09 +02:00
CanMerge ( dst , src * Image , color * affine . ColorM , mode driver . CompositeMode , filter driver . Filter , address driver . Address ) 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.
2019-06-21 20:50:56 +02:00
func ( q * commandQueue ) appendVertices ( vertices [ ] float32 , width , height float32 ) {
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-06-21 20:50:56 +02:00
for i := 0 ; i < len ( vertices ) / graphics . VertexFloatNum ; i ++ {
idx := q . nvertices / graphics . VertexFloatNum + 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-06-25 17:43:09 +02:00
func ( q * commandQueue ) doEnqueueDrawTrianglesCommand ( dst , src * Image , nvertices , nindices int , color * affine . ColorM , mode driver . CompositeMode , filter driver . Filter , address driver . Address , forceNewCommand bool ) {
2018-11-06 17:49:45 +01:00
if nindices > graphics . IndicesNum {
2019-04-22 16:12:03 +02:00
panic ( fmt . Sprintf ( "graphicscommand: nindices must be <= graphics.IndicesNum but not at doEnqueueDrawTrianglesCommand: nindices: %d, graphics.IndicesNum: %d" , nindices , graphics . IndicesNum ) )
2018-06-03 14:47:08 +02:00
}
if ! forceNewCommand && 0 < len ( q . commands ) {
2018-12-23 19:00:00 +01:00
if last := q . commands [ len ( q . commands ) - 1 ] ; last . CanMerge ( dst , src , color , mode , filter , address ) {
2018-06-03 14:47:08 +02:00
last . AddNumVertices ( nvertices )
2018-06-10 10:06:40 +02:00
last . AddNumIndices ( nindices )
2018-06-03 14:47:08 +02:00
return
}
}
2019-04-22 16:12:03 +02:00
c := & drawTrianglesCommand {
2018-06-03 14:47:08 +02:00
dst : dst ,
src : src ,
nvertices : nvertices ,
2018-06-10 10:06:40 +02:00
nindices : nindices ,
2018-08-05 14:30:06 +02:00
color : color ,
2018-06-03 14:47:08 +02:00
mode : mode ,
filter : filter ,
2018-12-23 19:00:00 +01:00
address : address ,
2018-06-03 14:47:08 +02:00
}
q . commands = append ( q . commands , c )
}
2019-04-22 16:12:03 +02:00
// EnqueueDrawTrianglesCommand enqueues a drawing-image command.
2019-06-25 17:43:09 +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 ) {
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
}
2019-06-21 20:50:56 +02:00
n := len ( vertices ) / graphics . VertexFloatNum
2019-06-26 04:45:06 +02:00
q . appendVertices ( vertices , float32 ( graphics . InternalImageSize ( src . width ) ) , float32 ( graphics . InternalImageSize ( src . height ) ) )
2018-06-10 10:06:40 +02:00
q . appendIndices ( indices , uint16 ( q . nextIndex ) )
2019-06-21 20:50:56 +02:00
q . nextIndex += n
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-04-22 16:12:03 +02:00
q . doEnqueueDrawTrianglesCommand ( dst , src , len ( vertices ) , len ( indices ) , color , mode , filter , address , split )
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 ) ) )
}
2017-09-19 18:35:56 +02:00
// Flush flushes the command queue.
2018-07-11 19:11:18 +02:00
func ( q * commandQueue ) Flush ( ) {
if q . err != nil {
return
}
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-08-27 15:33:14 +02:00
const dstAdjustmentFactor = 1.0 / 256.0
2019-06-21 21:47:48 +02:00
const texelAdjustmentFactor = 1.0 / 512.0
2019-08-27 15:33:14 +02:00
2019-06-21 21:47:48 +02:00
for i := 0 ; i < q . nvertices / graphics . VertexFloatNum ; 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-06-21 20:50:56 +02:00
}
2019-04-20 08:17:59 +02:00
theGraphicsDriver . Begin ( )
2018-06-03 14:47:08 +02:00
for len ( q . commands ) > 0 {
nv := 0
ne := 0
nc := 0
for _ , c := range q . commands {
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
2018-06-03 14:47:08 +02:00
for _ , c := range q . commands [ : nc ] {
2018-11-11 15:51:16 +01:00
if err := c . Exec ( indexOffset ) ; err != nil {
2018-07-11 19:11:18 +02:00
q . err = err
return
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
}
2018-06-03 14:47:08 +02:00
if 0 < nc {
2016-07-16 12:17:57 +02:00
// Call glFlush to prevent black flicking (especially on Android (#226) and iOS).
2019-03-30 14:13:48 +01:00
theGraphicsDriver . Flush ( )
2016-07-15 21:17:44 +02:00
}
2018-06-03 14:47:08 +02:00
q . commands = q . commands [ nc : ]
2016-06-02 19:34:34 +02:00
}
2019-04-20 08:17:59 +02:00
theGraphicsDriver . End ( )
2017-05-26 15:32:38 +02:00
q . commands = nil
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
2018-07-11 19:11:18 +02:00
}
// Error returns an OpenGL error for the last command.
func Error ( ) error {
return theCommandQueue . err
2016-06-02 19:34:34 +02:00
}
2017-09-19 18:35:56 +02:00
// FlushCommands flushes the command queue.
2018-07-11 19:11:18 +02:00
func FlushCommands ( ) {
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
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 ) )
}
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
dst := fmt . Sprintf ( "%d" , c . dst . id )
if c . dst . screen {
dst += " (screen)"
}
src := fmt . Sprintf ( "%d" , c . src . id )
if c . src . screen {
src += " (screen)"
}
return fmt . Sprintf ( "draw-triangles: dst: %s <- src: %s, colorm: %v, mode %s, filter: %s, address: %s" , dst , src , 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
c . dst . image . SetAsDestination ( )
c . src . image . SetAsSource ( )
2019-03-30 14:13:48 +01:00
if err := theGraphicsDriver . Draw ( c . nindices , indexOffset , c . mode , c . color , c . filter , c . address ) ; err != nil {
2018-11-05 19:44:43 +01:00
return err
}
2016-06-03 05:41:18 +02:00
return nil
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-04-22 16:12:03 +02:00
// CanMerge returns a boolean value indicating whether the other drawTrianglesCommand can be merged
// with the drawTrianglesCommand c.
2019-06-25 17:43:09 +02:00
func ( c * drawTrianglesCommand ) CanMerge ( dst , src * Image , color * affine . ColorM , mode driver . CompositeMode , filter driver . Filter , address driver . Address ) bool {
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 {
2016-06-12 15:44:23 +02:00
dst * Image
2018-01-28 14:40:36 +01:00
pixels [ ] byte
2018-02-28 16:27:55 +01:00
x int
y int
width int
height int
2016-06-02 19:34:34 +02:00
}
2018-03-04 16:45:03 +01:00
func ( c * replacePixelsCommand ) String ( ) string {
2019-07-19 16:18:07 +02:00
return fmt . Sprintf ( "replace-pixels: dst: %d, x: %d, y: %d, width: %d, height: %d" , c . dst . id , c . x , c . y , c . width , c . height )
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 {
2018-11-10 17:35:10 +01:00
c . dst . image . ReplacePixels ( c . pixels , c . x , c . y , c . width , c . height )
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
}
2019-06-25 17:43:09 +02:00
func ( c * replacePixelsCommand ) CanMerge ( dst , src * Image , color * affine . ColorM , mode driver . CompositeMode , filter driver . Filter , address driver . Address ) 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 ) {
}
2019-06-25 17:43:09 +02:00
func ( c * pixelsCommand ) CanMerge ( dst , src * Image , color * affine . ColorM , mode driver . CompositeMode , filter driver . Filter , address driver . Address ) bool {
2018-07-11 19:40:06 +02:00
return false
}
2017-09-19 18:35:56 +02:00
// disposeCommand represents a command to dispose an image.
2016-06-11 15:52:07 +02:00
type disposeCommand struct {
2016-06-12 15:44:23 +02:00
target * Image
2016-06-11 15:52:07 +02:00
}
2018-03-04 16:45:03 +01:00
func ( c * disposeCommand ) String ( ) string {
2019-07-19 16:18:07 +02:00
return fmt . Sprintf ( "dispose: target: %d" , c . target . id )
2018-03-04 16:45:03 +01:00
}
2017-09-19 18:35:56 +02:00
// Exec executes the disposeCommand.
2018-11-11 15:51:16 +01:00
func ( c * disposeCommand ) 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
2018-03-04 15:35:14 +01:00
func ( c * disposeCommand ) NumVertices ( ) int {
return 0
}
2018-06-10 10:06:40 +02:00
func ( c * disposeCommand ) NumIndices ( ) int {
2018-06-03 08:16:30 +02:00
return 0
}
2018-03-18 11:58:32 +01:00
func ( c * disposeCommand ) AddNumVertices ( n int ) {
}
2018-06-10 10:06:40 +02:00
func ( c * disposeCommand ) AddNumIndices ( n int ) {
2018-06-03 08:16:30 +02:00
}
2019-06-25 17:43:09 +02:00
func ( c * disposeCommand ) CanMerge ( dst , src * Image , color * affine . ColorM , mode driver . CompositeMode , filter driver . Filter , address driver . Address ) 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
}
2019-06-25 17:43:09 +02:00
func ( c * newImageCommand ) CanMerge ( dst , src * Image , color * affine . ColorM , mode driver . CompositeMode , filter driver . Filter , address driver . Address ) 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
}
2019-06-25 17:43:09 +02:00
func ( c * newScreenFramebufferImageCommand ) CanMerge ( dst , src * Image , color * affine . ColorM , mode driver . CompositeMode , filter driver . Filter , address driver . Address ) 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
}