<commit_before>// Copyright 2016 <NAME>
//
// 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.

package graphicscommand

import (
	"fmt"
	"image"
	"os"
	"strings"

	"github.com/hajimehoshi/ebiten/internal/affine"
	"github.com/hajimehoshi/ebiten/internal/driver"
	"github.com/hajimehoshi/ebiten/internal/graphics"
	"github.com/hajimehoshi/ebiten/internal/png"
)

type lastCommand int

const (
	lastCommandNone lastCommand = iota
	lastCommandClear
	lastCommandDrawTriangles
	lastCommandReplacePixels
)

// Image represents an image that is implemented with OpenGL.
type Image struct {
	image          driver.Image
	width          int
	height         int
	internalWidth  int
	internalHeight int
	screen         bool

	// id is an indentifier for the image. This is used only when dummping the information.
	//
	// This is duplicated with driver.Image's ID, but this id is still necessary because this image might not
	// have its driver.Image.
	id int

	bufferedRP []*driver.ReplacePixelsArgs

	lastCommand lastCommand
}

var nextID = 1

func genNextID() int {
	id := nextID
	nextID++
	return id
}

// NewImage returns a new image.
//
// Note that the image is not initialized yet.
func NewImage(width, height int) *Image {
	i := &Image{
		width:  width,
		height: height,
		id:     genNextID(),
	}
	c := &newImageCommand{
		result: i,
		width:  width,
		height: height,
	}
	theCommandQueue.Enqueue(c)
	return i
}

func NewScreenFramebufferImage(width, height int) *Image {
	i := &Image{
		width:  width,
		height: height,
		screen: true,
		id:     genNextID(),
	}
	c := &newScreenFramebufferImageCommand{
		result: i,
		width:  width,
		height: height,
	}
	theCommandQueue.Enqueue(c)
	return i
}

func (i *Image) resolveBufferedReplacePixels() {
	if len(i.bufferedRP) == 0 {
		return
	}
	c := &replacePixelsCommand{
		dst:  i,
		args: i.bufferedRP,
	}
	theCommandQueue.Enqueue(c)
	i.bufferedRP = nil
}

func (i *Image) Dispose() {
	c := &disposeImageCommand{
		target: i,
	}
	theCommandQueue.Enqueue(c)
}

func (i *Image) InternalSize() (int, int) {
	if i.internalWidth == 0 {
		i.internalWidth = graphics.InternalImageSize(i.width)
	}
	if i.internalHeight == 0 {
		i.internalHeight = graphics.InternalImageSize(i.height)
	}
	return i.internalWidth, i.internalHeight
}

// DrawTriangles draws triangles with the given image.
//
// The vertex floats are:
//
//   0:  Destination X in pixels
//   1:  Destination Y in pixels
//   2:  Source X in pixels (not texels!)
//   3:  Source Y in pixels
//   4:  Bounds of the source min X in pixels
//   5:  Bounds of the source min Y in pixels
//   6:  Bounds of the source max X in pixels
//   7:  Bounds of the source max Y in pixels
//   8:  Color R [0.0-1.0]
//   9:  Color G
//   10: Color B
//   11: Color Y
//
// src and shader are exclusive and only either is non-nil.
func (i *Image) DrawTriangles(src *Image, vertices []float32, indices []uint16, clr *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, shader *Shader, uniforms map[int]interface{}) {
	if src.screen {
		panic("graphicscommand: the screen image cannot be the rendering source")
	}

	if i.lastCommand == lastCommandNone {
		if !i.screen && mode != driver.CompositeModeClear {
			panic("graphicscommand: the image must be cleared first")
		}
	}

	var us map[int]interface{}
	if src != nil {
		src.resolveBufferedReplacePixels()
	} else {
		us = map[int]interface{}{}
		for k, v := range uniforms {
			switch v := v.(type) {
			case *Image:
				v.resolveBufferedReplacePixels()
				us[k] = v.image
			default:<commit_msg>graphicscommand: Bug fix: test failures<commit_after>// Copyright 2016 <NAME>
//
// 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.

package graphicscommand

import (
	"fmt"
	"image"
	"os"
	"strings"

	"github.com/hajimehoshi/ebiten/internal/affine"
	"github.com/hajimehoshi/ebiten/internal/driver"
	"github.com/hajimehoshi/ebiten/internal/graphics"
	"github.com/hajimehoshi/ebiten/internal/png"
)

type lastCommand int

const (
	lastCommandNone lastCommand = iota
	lastCommandClear
	lastCommandDrawTriangles
	lastCommandReplacePixels
)

// Image represents an image that is implemented with OpenGL.
type Image struct {
	image          driver.Image
	width          int
	height         int
	internalWidth  int
	internalHeight int
	screen         bool

	// id is an indentifier for the image. This is used only when dummping the information.
	//
	// This is duplicated with driver.Image's ID, but this id is still necessary because this image might not
	// have its driver.Image.
	id int

	bufferedRP []*driver.ReplacePixelsArgs

	lastCommand lastCommand
}

var nextID = 1

func genNextID() int {
	id := nextID
	nextID++
	return id
}

// NewImage returns a new image.
//
// Note that the image is not initialized yet.
func NewImage(width, height int) *Image {
	i := &Image{
		width:  width,
		height: height,
		id:     genNextID(),
	}
	c := &newImageCommand{
		result: i,
		width:  width,
		height: height,
	}
	theCommandQueue.Enqueue(c)
	return i
}

func NewScreenFramebufferImage(width, height int) *Image {
	i := &Image{
		width:  width,
		height: height,
		screen: true,
		id:     genNextID(),
	}
	c := &newScreenFramebufferImageCommand{
		result: i,
		width:  width,
		height: height,
	}
	theCommandQueue.Enqueue(c)
	return i
}

func (i *Image) resolveBufferedReplacePixels() {
	if len(i.bufferedRP) == 0 {
		return
	}
	c := &replacePixelsCommand{
		dst:  i,
		args: i.bufferedRP,
	}
	theCommandQueue.Enqueue(c)
	i.bufferedRP = nil
}

func (i *Image) Dispose() {
	c := &disposeImageCommand{
		target: i,
	}
	theCommandQueue.Enqueue(c)
}

func (i *Image) InternalSize() (int, int) {
	if i.internalWidth == 0 {
		i.internalWidth = graphics.InternalImageSize(i.width)
	}
	if i.internalHeight == 0 {
		i.internalHeight = graphics.InternalImageSize(i.height)
	}
	return i.internalWidth, i.internalHeight
}

// DrawTriangles draws triangles with the given image.
//
// The vertex floats are:
//
//   0:  Destination X in pixels
//   1:  Destination Y in pixels
//   2:  Source X in pixels (not texels!)
//   3:  Source Y in pixels
//   4:  Bounds of the source min X in pixels
//   5:  Bounds of the source min Y in pixels
//   6:  Bounds of the source max X in pixels
//   7:  Bounds of the source max Y in pixels
//   8:  Color R [0.0-1.0]
//   9:  Color G
//   10: Color B
//   11: Color Y
//
// src and shader are exclusive and only either is non-nil.
func (i *Image) DrawTriangles(src *Image, vertices []float32, indices []uint16, clr *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, shader *Shader, uniforms map[int]interface{}) {
	if src != nil && src.screen {
		panic("graphicscommand: the screen image cannot be the rendering source")
	}

	if i.lastCommand == lastCommandNone {
		if !i.screen && mode != driver.CompositeModeClear {
			panic("graphicscommand: the image must be cleared first")
		}
	}

	var us map[int]interface{}
	if src != nil {
		src.resolveBufferedReplacePixels()
	} else {
		us = map[int]interface{}{}
		for k, v := range uniforms {
			switch v := v.(type) {
			case *Image:
				v.resolveBufferedReplacePixels()
				us[k] = v.image
			default:
{'fraction_non_alphanumeric': 0.10872220864891277, 'fraction_numerical': 0.008306865379916931, 'mean_word_length': 3.324881141045959, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2342992', 'n_tokens_mistral': 2810, 'n_tokens_neox': 2659, 'n_words': 905}