mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 02:38:53 +01:00
all: allow integer uniform variables for Kage shaders
Closes #2305 Updates #2448
This commit is contained in:
parent
4ff9a12930
commit
1ecac8d834
4
image.go
4
image.go
@ -505,7 +505,7 @@ type DrawTrianglesShaderOptions struct {
|
||||
|
||||
// Uniforms is a set of uniform variables for the shader.
|
||||
// The keys are the names of the uniform variables.
|
||||
// The values must be float or []float.
|
||||
// The values must be a numeric type or a slice of a numeric type.
|
||||
// If the uniform variable type is an array, a vector or a matrix,
|
||||
// you have to specify linearly flattened values as a slice.
|
||||
// For example, if the uniform variable type is [4]vec4, the number of the slice values will be 16.
|
||||
@ -665,7 +665,7 @@ type DrawRectShaderOptions struct {
|
||||
|
||||
// Uniforms is a set of uniform variables for the shader.
|
||||
// The keys are the names of the uniform variables.
|
||||
// The values must be float or []float.
|
||||
// The values must be a numeric type or a slice of a numeric type.
|
||||
// If the uniform variable type is an array, a vector or a matrix,
|
||||
// you have to specify linearly flattened values as a slice.
|
||||
// For example, if the uniform variable type is [4]vec4, the number of the slice values will be 16.
|
||||
|
@ -1732,6 +1732,12 @@ func (s *Shader) flattenUniforms(uniforms [][]uint32) []uint32 {
|
||||
} else {
|
||||
fs = append(fs, 0)
|
||||
}
|
||||
case shaderir.Int:
|
||||
if u != nil {
|
||||
fs = append(fs, u...)
|
||||
} else {
|
||||
fs = append(fs, 0)
|
||||
}
|
||||
case shaderir.Vec2:
|
||||
if u != nil {
|
||||
fs = append(fs, u...)
|
||||
@ -1806,6 +1812,17 @@ func (s *Shader) flattenUniforms(uniforms [][]uint32) []uint32 {
|
||||
} else {
|
||||
fs = append(fs, make([]uint32, (t.Length-1)*4+1)...)
|
||||
}
|
||||
case shaderir.Int:
|
||||
if u != nil {
|
||||
for j := 0; j < t.Length; j++ {
|
||||
fs = append(fs, u[j])
|
||||
if j < t.Length-1 {
|
||||
fs = append(fs, 0, 0, 0)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fs = append(fs, make([]uint32, (t.Length-1)*4+1)...)
|
||||
}
|
||||
case shaderir.Vec2:
|
||||
if u != nil {
|
||||
for j := 0; j < t.Length; j++ {
|
||||
|
@ -375,7 +375,7 @@ func (c *context) uniformInt(p program, location string, v int) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *context) uniformFloats(p program, location string, v []float32, typ shaderir.Type) bool {
|
||||
func (c *context) uniforms(p program, location string, v []uint32, typ shaderir.Type) bool {
|
||||
l := int32(c.locationCache.GetUniformLocation(c, p, location))
|
||||
if l == invalidUniform {
|
||||
return false
|
||||
@ -391,6 +391,8 @@ func (c *context) uniformFloats(p program, location string, v []float32, typ sha
|
||||
switch base {
|
||||
case shaderir.Float:
|
||||
gl.Uniform1fv(l, len, (*float32)(gl.Ptr(v)))
|
||||
case shaderir.Int:
|
||||
gl.Uniform1iv(l, len, (*int32)(gl.Ptr(v)))
|
||||
case shaderir.Vec2:
|
||||
gl.Uniform2fv(l, len, (*float32)(gl.Ptr(v)))
|
||||
case shaderir.Vec3:
|
||||
|
@ -344,7 +344,7 @@ func (c *context) uniformInt(p program, location string, v int) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *context) uniformFloats(p program, location string, v []float32, typ shaderir.Type) bool {
|
||||
func (c *context) uniforms(p program, location string, v []uint32, typ shaderir.Type) bool {
|
||||
l := c.locationCache.GetUniformLocation(c, p, location)
|
||||
if l == invalidUniform {
|
||||
return false
|
||||
@ -357,19 +357,21 @@ func (c *context) uniformFloats(p program, location string, v []float32, typ sha
|
||||
|
||||
switch base {
|
||||
case shaderir.Float:
|
||||
c.ctx.Uniform1fv(int32(l), v)
|
||||
c.ctx.Uniform1fv(int32(l), uint32sToFloat32s(v))
|
||||
case shaderir.Int:
|
||||
c.ctx.Uniform1iv(int32(l), uint32sToInt32s(v))
|
||||
case shaderir.Vec2:
|
||||
c.ctx.Uniform2fv(int32(l), v)
|
||||
c.ctx.Uniform2fv(int32(l), uint32sToFloat32s(v))
|
||||
case shaderir.Vec3:
|
||||
c.ctx.Uniform3fv(int32(l), v)
|
||||
c.ctx.Uniform3fv(int32(l), uint32sToFloat32s(v))
|
||||
case shaderir.Vec4:
|
||||
c.ctx.Uniform4fv(int32(l), v)
|
||||
c.ctx.Uniform4fv(int32(l), uint32sToFloat32s(v))
|
||||
case shaderir.Mat2:
|
||||
c.ctx.UniformMatrix2fv(int32(l), false, v)
|
||||
c.ctx.UniformMatrix2fv(int32(l), false, uint32sToFloat32s(v))
|
||||
case shaderir.Mat3:
|
||||
c.ctx.UniformMatrix3fv(int32(l), false, v)
|
||||
c.ctx.UniformMatrix3fv(int32(l), false, uint32sToFloat32s(v))
|
||||
case shaderir.Mat4:
|
||||
c.ctx.UniformMatrix4fv(int32(l), false, v)
|
||||
c.ctx.UniformMatrix4fv(int32(l), false, uint32sToFloat32s(v))
|
||||
default:
|
||||
panic(fmt.Sprintf("opengl: unexpected type: %s", typ.String()))
|
||||
}
|
||||
|
@ -451,7 +451,7 @@ func (c *context) uniformInt(p program, location string, v int) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *context) uniformFloats(p program, location string, v []float32, typ shaderir.Type) bool {
|
||||
func (c *context) uniforms(p program, location string, v []uint32, typ shaderir.Type) bool {
|
||||
gl := c.gl
|
||||
l := c.locationCache.GetUniformLocation(c, p, location)
|
||||
if l.equal(invalidUniform) {
|
||||
@ -463,46 +463,58 @@ func (c *context) uniformFloats(p program, location string, v []float32, typ sha
|
||||
base = typ.Sub[0].Main
|
||||
}
|
||||
|
||||
arr := jsutil.TemporaryFloat32Array(len(v), v)
|
||||
|
||||
switch base {
|
||||
case shaderir.Float:
|
||||
arr := jsutil.TemporaryFloat32Array(len(v), uint32sToFloat32s(v))
|
||||
if c.usesWebGL2() {
|
||||
gl.uniform1fv.Invoke(js.Value(l), arr, 0, len(v))
|
||||
} else {
|
||||
gl.uniform1fv.Invoke(js.Value(l), arr.Call("subarray", 0, len(v)))
|
||||
}
|
||||
case shaderir.Int:
|
||||
arr := jsutil.TemporaryInt32Array(len(v), uint32sToInt32s(v))
|
||||
if c.usesWebGL2() {
|
||||
gl.uniform1iv.Invoke(js.Value(l), arr, 0, len(v))
|
||||
} else {
|
||||
gl.uniform1iv.Invoke(js.Value(l), arr.Call("subarray", 0, len(v)))
|
||||
}
|
||||
case shaderir.Vec2:
|
||||
arr := jsutil.TemporaryFloat32Array(len(v), uint32sToFloat32s(v))
|
||||
if c.usesWebGL2() {
|
||||
gl.uniform2fv.Invoke(js.Value(l), arr, 0, len(v))
|
||||
} else {
|
||||
gl.uniform2fv.Invoke(js.Value(l), arr.Call("subarray", 0, len(v)))
|
||||
}
|
||||
case shaderir.Vec3:
|
||||
arr := jsutil.TemporaryFloat32Array(len(v), uint32sToFloat32s(v))
|
||||
if c.usesWebGL2() {
|
||||
gl.uniform3fv.Invoke(js.Value(l), arr, 0, len(v))
|
||||
} else {
|
||||
gl.uniform3fv.Invoke(js.Value(l), arr.Call("subarray", 0, len(v)))
|
||||
}
|
||||
case shaderir.Vec4:
|
||||
arr := jsutil.TemporaryFloat32Array(len(v), uint32sToFloat32s(v))
|
||||
if c.usesWebGL2() {
|
||||
gl.uniform4fv.Invoke(js.Value(l), arr, 0, len(v))
|
||||
} else {
|
||||
gl.uniform4fv.Invoke(js.Value(l), arr.Call("subarray", 0, len(v)))
|
||||
}
|
||||
case shaderir.Mat2:
|
||||
arr := jsutil.TemporaryFloat32Array(len(v), uint32sToFloat32s(v))
|
||||
if c.usesWebGL2() {
|
||||
gl.uniformMatrix2fv.Invoke(js.Value(l), false, arr, 0, len(v))
|
||||
} else {
|
||||
gl.uniformMatrix2fv.Invoke(js.Value(l), false, arr.Call("subarray", 0, len(v)))
|
||||
}
|
||||
case shaderir.Mat3:
|
||||
arr := jsutil.TemporaryFloat32Array(len(v), uint32sToFloat32s(v))
|
||||
if c.usesWebGL2() {
|
||||
gl.uniformMatrix3fv.Invoke(js.Value(l), false, arr, 0, len(v))
|
||||
} else {
|
||||
gl.uniformMatrix3fv.Invoke(js.Value(l), false, arr.Call("subarray", 0, len(v)))
|
||||
}
|
||||
case shaderir.Mat4:
|
||||
arr := jsutil.TemporaryFloat32Array(len(v), uint32sToFloat32s(v))
|
||||
if c.usesWebGL2() {
|
||||
gl.uniformMatrix4fv.Invoke(js.Value(l), false, arr, 0, len(v))
|
||||
} else {
|
||||
|
@ -31,6 +31,8 @@ func Ptr(data any) unsafe.Pointer {
|
||||
addr = unsafe.Pointer(&v[0])
|
||||
case []uint16:
|
||||
addr = unsafe.Pointer(&v[0])
|
||||
case []uint32:
|
||||
addr = unsafe.Pointer(&v[0])
|
||||
case []float32:
|
||||
addr = unsafe.Pointer(&v[0])
|
||||
default:
|
||||
|
@ -163,8 +163,9 @@ package gl
|
||||
// typedef void (APIENTRYP GPTEXIMAGE2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * pixels);
|
||||
// typedef void (APIENTRYP GPTEXPARAMETERI)(GLenum target, GLenum pname, GLint param);
|
||||
// typedef void (APIENTRYP GPTEXSUBIMAGE2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels);
|
||||
// typedef void (APIENTRYP GPUNIFORM1I)(GLint location, GLint v0);
|
||||
// typedef void (APIENTRYP GPUNIFORM1FV)(GLint location, GLsizei count, const GLfloat * value);
|
||||
// typedef void (APIENTRYP GPUNIFORM1I)(GLint location, GLint v0);
|
||||
// typedef void (APIENTRYP GPUNIFORM1IV)(GLint location, GLsizei count, const GLint * value);
|
||||
// typedef void (APIENTRYP GPUNIFORM2FV)(GLint location, GLsizei count, const GLfloat * value);
|
||||
// typedef void (APIENTRYP GPUNIFORM3FV)(GLint location, GLsizei count, const GLfloat * value);
|
||||
// typedef void (APIENTRYP GPUNIFORM4FV)(GLint location, GLsizei count, const GLfloat * value);
|
||||
@ -382,10 +383,13 @@ package gl
|
||||
// static void glowTexSubImage2D(GPTEXSUBIMAGE2D fnptr, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels) {
|
||||
// (*fnptr)(target, level, xoffset, yoffset, width, height, format, type, pixels);
|
||||
// }
|
||||
// static void glowUniform1fv(GPUNIFORM1FV fnptr, GLint location, GLsizei count, const GLfloat * value) {
|
||||
// (*fnptr)(location, count, value);
|
||||
// }
|
||||
// static void glowUniform1i(GPUNIFORM1I fnptr, GLint location, GLint v0) {
|
||||
// (*fnptr)(location, v0);
|
||||
// }
|
||||
// static void glowUniform1fv(GPUNIFORM1FV fnptr, GLint location, GLsizei count, const GLfloat * value) {
|
||||
// static void glowUniform1iv(GPUNIFORM1IV fnptr, GLint location, GLsizei count, const GLint * value) {
|
||||
// (*fnptr)(location, count, value);
|
||||
// }
|
||||
// static void glowUniform2fv(GPUNIFORM2FV fnptr, GLint location, GLsizei count, const GLfloat * value) {
|
||||
@ -494,8 +498,9 @@ var (
|
||||
gpTexImage2D C.GPTEXIMAGE2D
|
||||
gpTexParameteri C.GPTEXPARAMETERI
|
||||
gpTexSubImage2D C.GPTEXSUBIMAGE2D
|
||||
gpUniform1i C.GPUNIFORM1I
|
||||
gpUniform1fv C.GPUNIFORM1FV
|
||||
gpUniform1i C.GPUNIFORM1I
|
||||
gpUniform1iv C.GPUNIFORM1IV
|
||||
gpUniform2fv C.GPUNIFORM2FV
|
||||
gpUniform3fv C.GPUNIFORM3FV
|
||||
gpUniform4fv C.GPUNIFORM4FV
|
||||
@ -791,12 +796,16 @@ func TexSubImage2D(target uint32, level int32, xoffset int32, yoffset int32, wid
|
||||
C.glowTexSubImage2D(gpTexSubImage2D, (C.GLenum)(target), (C.GLint)(level), (C.GLint)(xoffset), (C.GLint)(yoffset), (C.GLsizei)(width), (C.GLsizei)(height), (C.GLenum)(format), (C.GLenum)(xtype), pixels)
|
||||
}
|
||||
|
||||
func Uniform1fv(location int32, count int32, value *float32) {
|
||||
C.glowUniform1fv(gpUniform1fv, (C.GLint)(location), (C.GLsizei)(count), (*C.GLfloat)(unsafe.Pointer(value)))
|
||||
}
|
||||
|
||||
func Uniform1i(location int32, v0 int32) {
|
||||
C.glowUniform1i(gpUniform1i, (C.GLint)(location), (C.GLint)(v0))
|
||||
}
|
||||
|
||||
func Uniform1fv(location int32, count int32, value *float32) {
|
||||
C.glowUniform1fv(gpUniform1fv, (C.GLint)(location), (C.GLsizei)(count), (*C.GLfloat)(unsafe.Pointer(value)))
|
||||
func Uniform1iv(location int32, count int32, value *int32) {
|
||||
C.glowUniform1iv(gpUniform1iv, (C.GLint)(location), (C.GLsizei)(count), (*C.GLint)(unsafe.Pointer(value)))
|
||||
}
|
||||
|
||||
func Uniform2fv(location int32, count int32, value *float32) {
|
||||
@ -1044,13 +1053,17 @@ func InitWithProcAddrFunc(getProcAddr func(name string) unsafe.Pointer) error {
|
||||
if gpTexSubImage2D == nil {
|
||||
return errors.New("gl: glTexSubImage2D is missing")
|
||||
}
|
||||
gpUniform1fv = (C.GPUNIFORM1FV)(getProcAddr("glUniform1fv"))
|
||||
if gpUniform1fv == nil {
|
||||
return errors.New("gl: glUniform1fv is missing")
|
||||
}
|
||||
gpUniform1i = (C.GPUNIFORM1I)(getProcAddr("glUniform1i"))
|
||||
if gpUniform1i == nil {
|
||||
return errors.New("gl: glUniform1i is missing")
|
||||
}
|
||||
gpUniform1fv = (C.GPUNIFORM1FV)(getProcAddr("glUniform1fv"))
|
||||
if gpUniform1fv == nil {
|
||||
return errors.New("gl: glUniform1fv is missing")
|
||||
gpUniform1iv = (C.GPUNIFORM1IV)(getProcAddr("glUniform1iv"))
|
||||
if gpUniform1iv == nil {
|
||||
return errors.New("gl: glUniform1iv is missing")
|
||||
}
|
||||
gpUniform2fv = (C.GPUNIFORM2FV)(getProcAddr("glUniform2fv"))
|
||||
if gpUniform2fv == nil {
|
||||
|
@ -81,8 +81,9 @@ var (
|
||||
gpTexImage2D uintptr
|
||||
gpTexParameteri uintptr
|
||||
gpTexSubImage2D uintptr
|
||||
gpUniform1i uintptr
|
||||
gpUniform1fv uintptr
|
||||
gpUniform1i uintptr
|
||||
gpUniform1iv uintptr
|
||||
gpUniform2fv uintptr
|
||||
gpUniform3fv uintptr
|
||||
gpUniform4fv uintptr
|
||||
@ -378,12 +379,16 @@ func TexSubImage2D(target uint32, level int32, xoffset int32, yoffset int32, wid
|
||||
purego.SyscallN(gpTexSubImage2D, uintptr(target), uintptr(level), uintptr(xoffset), uintptr(yoffset), uintptr(width), uintptr(height), uintptr(format), uintptr(xtype), uintptr(pixels))
|
||||
}
|
||||
|
||||
func Uniform1fv(location int32, count int32, value *float32) {
|
||||
purego.SyscallN(gpUniform1fv, uintptr(location), uintptr(count), uintptr(unsafe.Pointer(value)))
|
||||
}
|
||||
|
||||
func Uniform1i(location int32, v0 int32) {
|
||||
purego.SyscallN(gpUniform1i, uintptr(location), uintptr(v0))
|
||||
}
|
||||
|
||||
func Uniform1fv(location int32, count int32, value *float32) {
|
||||
purego.SyscallN(gpUniform1fv, uintptr(location), uintptr(count), uintptr(unsafe.Pointer(value)))
|
||||
func Uniform1iv(location int32, count int32, value *int32) {
|
||||
purego.SyscallN(gpUniform1iv, uintptr(location), uintptr(count), uintptr(unsafe.Pointer(value)))
|
||||
}
|
||||
|
||||
func Uniform2fv(location int32, count int32, value *float32) {
|
||||
@ -631,13 +636,17 @@ func InitWithProcAddrFunc(getProcAddr func(name string) uintptr) error {
|
||||
if gpTexSubImage2D == 0 {
|
||||
return errors.New("gl: glTexSubImage2D is missing")
|
||||
}
|
||||
gpUniform1fv = getProcAddr("glUniform1fv")
|
||||
if gpUniform1fv == 0 {
|
||||
return errors.New("gl: glUniform1fv is missing")
|
||||
}
|
||||
gpUniform1i = getProcAddr("glUniform1i")
|
||||
if gpUniform1i == 0 {
|
||||
return errors.New("gl: glUniform1i is missing")
|
||||
}
|
||||
gpUniform1fv = getProcAddr("glUniform1fv")
|
||||
if gpUniform1fv == 0 {
|
||||
return errors.New("gl: glUniform1fv is missing")
|
||||
gpUniform1iv = getProcAddr("glUniform1iv")
|
||||
if gpUniform1iv == 0 {
|
||||
return errors.New("gl: glUniform1iv is missing")
|
||||
}
|
||||
gpUniform2fv = getProcAddr("glUniform2fv")
|
||||
if gpUniform2fv == 0 {
|
||||
|
@ -80,10 +80,11 @@ type gl struct {
|
||||
texSubImage2D js.Value
|
||||
texParameteri js.Value
|
||||
uniform1fv js.Value
|
||||
uniform1i js.Value
|
||||
uniform1iv js.Value
|
||||
uniform2fv js.Value
|
||||
uniform3fv js.Value
|
||||
uniform4fv js.Value
|
||||
uniform1i js.Value
|
||||
uniformMatrix2fv js.Value
|
||||
uniformMatrix3fv js.Value
|
||||
uniformMatrix4fv js.Value
|
||||
@ -156,10 +157,11 @@ func (c *context) newGL(v js.Value) *gl {
|
||||
texSubImage2D: v.Get("texSubImage2D").Call("bind", v),
|
||||
texParameteri: v.Get("texParameteri").Call("bind", v),
|
||||
uniform1fv: v.Get("uniform1fv").Call("bind", v),
|
||||
uniform1i: v.Get("uniform1i").Call("bind", v),
|
||||
uniform1iv: v.Get("uniform1iv").Call("bind", v),
|
||||
uniform2fv: v.Get("uniform2fv").Call("bind", v),
|
||||
uniform3fv: v.Get("uniform3fv").Call("bind", v),
|
||||
uniform4fv: v.Get("uniform4fv").Call("bind", v),
|
||||
uniform1i: v.Get("uniform1i").Call("bind", v),
|
||||
uniformMatrix2fv: v.Get("uniformMatrix2fv").Call("bind", v),
|
||||
uniformMatrix3fv: v.Get("uniformMatrix3fv").Call("bind", v),
|
||||
uniformMatrix4fv: v.Get("uniformMatrix4fv").Call("bind", v),
|
||||
|
@ -332,6 +332,10 @@ func (DefaultContext) Uniform1i(location int32, v0 int32) {
|
||||
C.glUniform1i(C.GLint(location), C.GLint(v0))
|
||||
}
|
||||
|
||||
func (DefaultContext) Uniform1iv(location int32, value []int32) {
|
||||
C.glUniform1iv(C.GLint(location), C.GLsizei(len(value)), (*C.GLint)(unsafe.Pointer(&value[0])))
|
||||
}
|
||||
|
||||
func (DefaultContext) Uniform2fv(location int32, value []float32) {
|
||||
C.glUniform2fv(C.GLint(location), C.GLsizei(len(value)/2), (*C.GLfloat)(unsafe.Pointer(&value[0])))
|
||||
}
|
||||
|
@ -306,6 +306,10 @@ func (g *GomobileContext) Uniform1i(location int32, v0 int32) {
|
||||
g.ctx.Uniform1i(gl.Uniform{Value: location}, int(v0))
|
||||
}
|
||||
|
||||
func (g *GomobileContext) Uniform1iv(location int32, value []int32) {
|
||||
g.ctx.Uniform1iv(gl.Uniform{Value: location}, value)
|
||||
}
|
||||
|
||||
func (g *GomobileContext) Uniform2fv(location int32, value []float32) {
|
||||
g.ctx.Uniform2fv(gl.Uniform{Value: location}, value)
|
||||
}
|
||||
|
@ -76,6 +76,7 @@ type Context interface {
|
||||
TexSubImage2D(target uint32, level int32, xoffset int32, yoffset int32, width int32, height int32, format uint32, xtype uint32, pixels []byte)
|
||||
Uniform1fv(location int32, value []float32)
|
||||
Uniform1i(location int32, v0 int32)
|
||||
Uniform1iv(location int32, value []int32)
|
||||
Uniform2fv(location int32, value []float32)
|
||||
Uniform3fv(location int32, value []float32)
|
||||
Uniform4fv(location int32, value []float32)
|
||||
|
@ -223,7 +223,7 @@ func (g *Graphics) useProgram(program program, uniforms []uniformVariable, textu
|
||||
if u.value == nil {
|
||||
continue
|
||||
}
|
||||
if got, expected := len(u.value), u.typ.FloatCount(); got != expected {
|
||||
if got, expected := len(u.value), u.typ.Uint32Count(); got != expected {
|
||||
// Copy a shaderir.Type value once. Do not pass u.typ directly to fmt.Errorf arguments, or
|
||||
// the value u would be allocated on heap.
|
||||
typ := u.typ
|
||||
@ -234,7 +234,7 @@ func (g *Graphics) useProgram(program program, uniforms []uniformVariable, textu
|
||||
if ok && areSameUint32Array(cached, u.value) {
|
||||
continue
|
||||
}
|
||||
g.context.uniformFloats(program, u.name, uint32sToFloat32s(u.value), u.typ)
|
||||
g.context.uniforms(program, u.name, u.value, u.typ)
|
||||
if g.state.lastUniforms == nil {
|
||||
g.state.lastUniforms = map[string][]uint32{}
|
||||
}
|
||||
@ -284,3 +284,7 @@ loop:
|
||||
func uint32sToFloat32s(s []uint32) []float32 {
|
||||
return unsafe.Slice((*float32)(unsafe.Pointer(&s[0])), len(s))
|
||||
}
|
||||
|
||||
func uint32sToInt32s(s []uint32) []int32 {
|
||||
return unsafe.Slice((*int32)(unsafe.Pointer(&s[0])), len(s))
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ var (
|
||||
arrayBuffer = js.Global().Get("ArrayBuffer")
|
||||
uint8Array = js.Global().Get("Uint8Array")
|
||||
float32Array = js.Global().Get("Float32Array")
|
||||
int32Array = js.Global().Get("Int32Array")
|
||||
)
|
||||
|
||||
var (
|
||||
@ -38,6 +39,9 @@ var (
|
||||
|
||||
// temporaryFloat32Array is a Float32ArrayBuffer whose underlying buffer is always temporaryArrayBuffer.
|
||||
temporaryFloat32Array = float32Array.New(temporaryArrayBuffer)
|
||||
|
||||
// temporaryInt32Array is a Float32ArrayBuffer whose underlying buffer is always temporaryArrayBuffer.
|
||||
temporaryInt32Array = int32Array.New(temporaryArrayBuffer)
|
||||
)
|
||||
|
||||
func ensureTemporaryArrayBufferSize(byteLength int) {
|
||||
@ -49,6 +53,7 @@ func ensureTemporaryArrayBufferSize(byteLength int) {
|
||||
temporaryArrayBuffer = arrayBuffer.New(bufl)
|
||||
temporaryUint8Array = uint8Array.New(temporaryArrayBuffer)
|
||||
temporaryFloat32Array = float32Array.New(temporaryArrayBuffer)
|
||||
temporaryInt32Array = int32Array.New(temporaryArrayBuffer)
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,7 +71,7 @@ func TemporaryUint8ArrayFromUint8Slice(minLength int, data []uint8) js.Value {
|
||||
// data must be a slice of a numeric type for initialization, or nil if you don't need initialization.
|
||||
func TemporaryUint8ArrayFromUint16Slice(minLength int, data []uint16) js.Value {
|
||||
ensureTemporaryArrayBufferSize(minLength * 2)
|
||||
copyUint16SliceToTemporaryArrayBuffer(data)
|
||||
copySliceToTemporaryArrayBuffer(data)
|
||||
return temporaryUint8Array
|
||||
}
|
||||
|
||||
@ -75,7 +80,7 @@ func TemporaryUint8ArrayFromUint16Slice(minLength int, data []uint16) js.Value {
|
||||
// data must be a slice of a numeric type for initialization, or nil if you don't need initialization.
|
||||
func TemporaryUint8ArrayFromFloat32Slice(minLength int, data []float32) js.Value {
|
||||
ensureTemporaryArrayBufferSize(minLength * 4)
|
||||
copyFloat32SliceToTemporaryArrayBuffer(data)
|
||||
copySliceToTemporaryArrayBuffer(data)
|
||||
return temporaryUint8Array
|
||||
}
|
||||
|
||||
@ -84,6 +89,15 @@ func TemporaryUint8ArrayFromFloat32Slice(minLength int, data []float32) js.Value
|
||||
// data must be a slice of a numeric type for initialization, or nil if you don't need initialization.
|
||||
func TemporaryFloat32Array(minLength int, data []float32) js.Value {
|
||||
ensureTemporaryArrayBufferSize(minLength * 4)
|
||||
copyFloat32SliceToTemporaryArrayBuffer(data)
|
||||
copySliceToTemporaryArrayBuffer(data)
|
||||
return temporaryFloat32Array
|
||||
}
|
||||
|
||||
// TemporaryInt32Array returns a Int32Array whose length is at least minLength.
|
||||
// Be careful that the length can exceed the given minLength.
|
||||
// data must be a slice of a numeric type for initialization, or nil if you don't need initialization.
|
||||
func TemporaryInt32Array(minLength int, data []int32) js.Value {
|
||||
ensureTemporaryArrayBufferSize(minLength * 4)
|
||||
copySliceToTemporaryArrayBuffer(data)
|
||||
return temporaryInt32Array
|
||||
}
|
||||
|
@ -27,18 +27,14 @@ func copyUint8SliceToTemporaryArrayBuffer(src []uint8) {
|
||||
js.CopyBytesToJS(temporaryUint8Array, src)
|
||||
}
|
||||
|
||||
func copyUint16SliceToTemporaryArrayBuffer(src []uint16) {
|
||||
if len(src) == 0 {
|
||||
return
|
||||
}
|
||||
js.CopyBytesToJS(temporaryUint8Array, unsafe.Slice((*byte)(unsafe.Pointer(&src[0])), len(src)*2))
|
||||
runtime.KeepAlive(src)
|
||||
type numeric interface {
|
||||
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64
|
||||
}
|
||||
|
||||
func copyFloat32SliceToTemporaryArrayBuffer(src []float32) {
|
||||
func copySliceToTemporaryArrayBuffer[T numeric](src []T) {
|
||||
if len(src) == 0 {
|
||||
return
|
||||
}
|
||||
js.CopyBytesToJS(temporaryUint8Array, unsafe.Slice((*byte)(unsafe.Pointer(&src[0])), len(src)*4))
|
||||
js.CopyBytesToJS(temporaryUint8Array, unsafe.Slice((*byte)(unsafe.Pointer(&src[0])), len(src)*int(unsafe.Sizeof(T(0)))))
|
||||
runtime.KeepAlive(src)
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ func FragmentPrelude(version GLSLVersion) string {
|
||||
}
|
||||
prelude := prefix + `#if defined(GL_ES)
|
||||
precision highp float;
|
||||
precision highp int;
|
||||
#else
|
||||
#define lowp
|
||||
#define mediump
|
||||
|
@ -43,6 +43,9 @@ func calculateMemoryOffsets(uniforms []shaderir.Type) []int {
|
||||
case shaderir.Float:
|
||||
offsets = append(offsets, head)
|
||||
head += 4
|
||||
case shaderir.Int:
|
||||
offsets = append(offsets, head)
|
||||
head += 4
|
||||
case shaderir.Vec2:
|
||||
if head%boundaryInBytes >= 4*3 {
|
||||
head = align(head)
|
||||
@ -79,7 +82,7 @@ func calculateMemoryOffsets(uniforms []shaderir.Type) []int {
|
||||
// TODO: What if the array has 2 or more dimensions?
|
||||
head = align(head)
|
||||
offsets = append(offsets, head)
|
||||
n := u.Sub[0].FloatCount()
|
||||
n := u.Sub[0].Uint32Count()
|
||||
switch u.Sub[0].Main {
|
||||
case shaderir.Mat2:
|
||||
n = 6
|
||||
@ -95,7 +98,7 @@ func calculateMemoryOffsets(uniforms []shaderir.Type) []int {
|
||||
// TODO: Implement this
|
||||
panic("hlsl: offset for a struct is not implemented yet")
|
||||
default:
|
||||
panic(fmt.Sprintf("hlsl: unexpected type: %d", u.Main))
|
||||
panic(fmt.Sprintf("hlsl: unexpected type: %s", u.String()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,7 @@ func (t *Type) String() string {
|
||||
case Mat4:
|
||||
return "mat4"
|
||||
case Array:
|
||||
return fmt.Sprintf("%s[%d]", t.Sub[0].String(), t.Length)
|
||||
return fmt.Sprintf("[%d]%s", t.Length, t.Sub[0].String())
|
||||
case Struct:
|
||||
str := "struct{"
|
||||
sub := make([]string, 0, len(t.Sub))
|
||||
@ -81,8 +81,10 @@ func (t *Type) String() string {
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Type) FloatCount() int {
|
||||
func (t *Type) Uint32Count() int {
|
||||
switch t.Main {
|
||||
case Int:
|
||||
return 1
|
||||
case Float:
|
||||
return 1
|
||||
case Vec2:
|
||||
@ -98,7 +100,7 @@ func (t *Type) FloatCount() int {
|
||||
case Mat4:
|
||||
return 16
|
||||
case Array:
|
||||
return t.Length * t.Sub[0].FloatCount()
|
||||
return t.Length * t.Sub[0].Uint32Count()
|
||||
default: // TODO: Parse a struct correctly
|
||||
return -1
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ package ui
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/mipmap"
|
||||
@ -48,17 +49,37 @@ func (s *Shader) MarkDisposed() {
|
||||
func (s *Shader) ConvertUniforms(uniforms map[string]any) [][]uint32 {
|
||||
nameToU32s := map[string][]uint32{}
|
||||
for name, v := range uniforms {
|
||||
switch v := v.(type) {
|
||||
case float32:
|
||||
nameToU32s[name] = []uint32{math.Float32bits(v)}
|
||||
case []float32:
|
||||
u32s := make([]uint32, len(v))
|
||||
for i := range v {
|
||||
u32s[i] = math.Float32bits(v[i])
|
||||
v := reflect.ValueOf(v)
|
||||
t := v.Type()
|
||||
switch t.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
nameToU32s[name] = []uint32{uint32(v.Int())}
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
nameToU32s[name] = []uint32{uint32(v.Uint())}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
nameToU32s[name] = []uint32{math.Float32bits(float32(v.Float()))}
|
||||
case reflect.Slice:
|
||||
// TODO: Allow reflect.Array (#2448)
|
||||
u32s := make([]uint32, v.Len())
|
||||
switch t.Elem().Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
for i := range u32s {
|
||||
u32s[i] = uint32(v.Index(i).Int())
|
||||
}
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
for i := range u32s {
|
||||
u32s[i] = uint32(v.Index(i).Uint())
|
||||
}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
for i := range u32s {
|
||||
u32s[i] = math.Float32bits(float32(v.Index(i).Float()))
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("ebiten: unexpected uniform value type: %s (%s)", name, v.Kind().String()))
|
||||
}
|
||||
nameToU32s[name] = u32s
|
||||
default:
|
||||
panic(fmt.Sprintf("ebiten: unexpected uniform value type: %s, %T", name, v))
|
||||
panic(fmt.Sprintf("ebiten: unexpected uniform value type: %s (%s)", name, v.Kind().String()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,7 +105,7 @@ func (s *Shader) ConvertUniforms(uniforms map[string]any) [][]uint32 {
|
||||
continue
|
||||
}
|
||||
t := s.uniformNameToType[name]
|
||||
us[idx] = make([]uint32, t.FloatCount())
|
||||
us[idx] = make([]uint32, t.Uint32Count())
|
||||
}
|
||||
|
||||
// TODO: Panic if uniforms include an invalid name
|
||||
|
113
shader_test.go
113
shader_test.go
@ -548,10 +548,13 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
|
||||
const w, h = 1, 1
|
||||
|
||||
dst := ebiten.NewImage(w, h)
|
||||
defer dst.Dispose()
|
||||
|
||||
s, err := ebiten.NewShader([]byte(shader.Shader))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer s.Dispose()
|
||||
|
||||
op := &ebiten.DrawRectShaderOptions{}
|
||||
op.Uniforms = shader.Uniforms
|
||||
@ -1269,3 +1272,113 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestShaderUniformInt(t *testing.T) {
|
||||
const ints = `package main
|
||||
|
||||
var U0 int
|
||||
var U1 int
|
||||
var U2 int
|
||||
var U3 int
|
||||
|
||||
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
|
||||
return vec4(float(U0)/255.0, float(U1)/255.0, float(U2)/255.0, float(U3)/255.0)
|
||||
}
|
||||
`
|
||||
|
||||
const intArray = `package main
|
||||
|
||||
var U [4]int
|
||||
|
||||
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
|
||||
return vec4(float(U[0])/255.0, float(U[1])/255.0, float(U[2])/255.0, float(U[3])/255.0)
|
||||
}
|
||||
`
|
||||
|
||||
testCases := []struct {
|
||||
Name string
|
||||
Uniforms map[string]any
|
||||
Shader string
|
||||
Want color.RGBA
|
||||
}{
|
||||
{
|
||||
Name: "0xff",
|
||||
Uniforms: map[string]any{
|
||||
"U0": 0xff,
|
||||
"U1": 0xff,
|
||||
"U2": 0xff,
|
||||
"U3": 0xff,
|
||||
},
|
||||
Shader: ints,
|
||||
Want: color.RGBA{0xff, 0xff, 0xff, 0xff},
|
||||
},
|
||||
{
|
||||
Name: "int",
|
||||
Uniforms: map[string]any{
|
||||
"U0": int8(0x24),
|
||||
"U1": int16(0x3f),
|
||||
"U2": int32(0x6a),
|
||||
"U3": int64(0x88),
|
||||
},
|
||||
Shader: ints,
|
||||
Want: color.RGBA{0x24, 0x3f, 0x6a, 0x88},
|
||||
},
|
||||
{
|
||||
Name: "uint",
|
||||
Uniforms: map[string]any{
|
||||
"U0": uint8(0x85),
|
||||
"U1": uint16(0xa3),
|
||||
"U2": uint32(0x08),
|
||||
"U3": uint64(0xd3),
|
||||
},
|
||||
Shader: ints,
|
||||
Want: color.RGBA{0x85, 0xa3, 0x08, 0xd3},
|
||||
},
|
||||
{
|
||||
Name: "0xff,array",
|
||||
Uniforms: map[string]any{
|
||||
"U": []int{0xff, 0xff, 0xff, 0xff},
|
||||
},
|
||||
Shader: intArray,
|
||||
Want: color.RGBA{0xff, 0xff, 0xff, 0xff},
|
||||
},
|
||||
{
|
||||
Name: "int,array",
|
||||
Uniforms: map[string]any{
|
||||
"U": []int16{0x24, 0x3f, 0x6a, 0x88},
|
||||
},
|
||||
Shader: intArray,
|
||||
Want: color.RGBA{0x24, 0x3f, 0x6a, 0x88},
|
||||
},
|
||||
{
|
||||
Name: "uint,array",
|
||||
Uniforms: map[string]any{
|
||||
"U": []uint8{0x85, 0xa3, 0x08, 0xd3},
|
||||
},
|
||||
Shader: intArray,
|
||||
Want: color.RGBA{0x85, 0xa3, 0x08, 0xd3},
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
const w, h = 1, 1
|
||||
|
||||
dst := ebiten.NewImage(w, h)
|
||||
defer dst.Dispose()
|
||||
|
||||
s, err := ebiten.NewShader([]byte(tc.Shader))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer s.Dispose()
|
||||
|
||||
op := &ebiten.DrawRectShaderOptions{}
|
||||
op.Uniforms = tc.Uniforms
|
||||
dst.DrawRectShader(w, h, s, op)
|
||||
if got, want := dst.At(0, 0).(color.RGBA), tc.Want; !sameColors(got, want, 1) {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user