code.witches.io/go/sdl2@v0.1.1/surface.go (about)

     1  package sdl
     2  
     3  // #include <SDL2/SDL_surface.h>
     4  import "C"
     5  import (
     6  	"image"
     7  	"image/color"
     8  	"image/draw"
     9  	"unsafe"
    10  
    11  	"code.witches.io/go/sdl2/compat"
    12  	"code.witches.io/go/sdl2/internal"
    13  )
    14  
    15  type Surface C.struct_SDL_Surface
    16  
    17  func (s *Surface) FillRect(rect *Rect, color uint32) error {
    18  	r := rect.toInternal()
    19  	if C.SDL_FillRect((*C.struct_SDL_Surface)(s), (*C.struct_SDL_Rect)(unsafe.Pointer(r)), C.Uint32(color)) != 0 {
    20  		return GetError()
    21  	}
    22  	return nil
    23  }
    24  
    25  func (s *Surface) FillRects(rects []*Rect, color uint32) error {
    26  	r := make([]*internal.Rect, len(rects))
    27  	for i, rect := range rects {
    28  		r[i] = rect.toInternal()
    29  	}
    30  	if C.SDL_FillRects((*C.struct_SDL_Surface)(s), (*C.struct_SDL_Rect)(unsafe.Pointer(&r[0])), C.int(len(r)), C.Uint32(color)) != 0 {
    31  		return GetError()
    32  	}
    33  	return nil
    34  }
    35  
    36  func (s *Surface) Free() {
    37  	if s != nil {
    38  		C.SDL_FreeSurface((*C.struct_SDL_Surface)(s))
    39  	}
    40  }
    41  
    42  func (s *Surface) BlitSurface(srcRect *Rect, dst *Surface, dstRect *Rect) error {
    43  	srcR := srcRect.toInternal()
    44  	dstR := dstRect.toInternal()
    45  	r := int(C.SDL_BlitSurface((*C.struct_SDL_Surface)(s), (*C.struct_SDL_Rect)(unsafe.Pointer(srcR)), (*C.struct_SDL_Surface)(dst), (*C.struct_SDL_Rect)(unsafe.Pointer(dstR))))
    46  	if r != 0 {
    47  		return GetError()
    48  	}
    49  	return nil
    50  }
    51  
    52  func (s *Surface) AlphaMod() (a uint8, err error) {
    53  	if C.SDL_GetSurfaceAlphaMod((*C.struct_SDL_Surface)(s), (*C.Uint8)(unsafe.Pointer(&a))) != 0 {
    54  		return 0, GetError()
    55  	}
    56  	return a, nil
    57  }
    58  
    59  func (s *Surface) ColorMod() (r, g, b uint8, err error) {
    60  	if C.SDL_GetSurfaceColorMod((*C.struct_SDL_Surface)(s), (*C.Uint8)(unsafe.Pointer(&r)), (*C.Uint8)(unsafe.Pointer(&g)), (*C.Uint8)(unsafe.Pointer(&b))) != 0 {
    61  		return 0, 0, 0, GetError()
    62  	}
    63  	return r, g, b, nil
    64  }
    65  
    66  func (s *Surface) SetAlphaMod(a uint8) error {
    67  	if C.SDL_SetSurfaceAlphaMod((*C.struct_SDL_Surface)(s), C.Uint8(a)) != 0 {
    68  		return GetError()
    69  	}
    70  	return nil
    71  }
    72  
    73  func (s *Surface) SetColorMod(r, g, b uint8) error {
    74  	if C.SDL_SetSurfaceColorMod((*C.struct_SDL_Surface)(s), C.Uint8(r), C.Uint8(g), C.Uint8(b)) != 0 {
    75  		return GetError()
    76  	}
    77  	return nil
    78  }
    79  
    80  func (s *Surface) ClipRect() Rect {
    81  	var r internal.Rect
    82  	C.SDL_GetClipRect((*C.struct_SDL_Surface)(s), (*C.struct_SDL_Rect)(unsafe.Pointer(&r)))
    83  	var rect Rect
    84  	rect.fromInternal(r)
    85  	return rect
    86  }
    87  
    88  func (s *Surface) SetClipRect(r *Rect) bool {
    89  	return C.SDL_SetClipRect((*C.struct_SDL_Surface)(s), (*C.struct_SDL_Rect)(unsafe.Pointer(r.toInternal()))) == C.SDL_TRUE
    90  }
    91  
    92  func (s *Surface) Lock() error {
    93  	if C.SDL_LockSurface((*C.struct_SDL_Surface)(s)) != 0 {
    94  		return GetError()
    95  	}
    96  	return nil
    97  }
    98  
    99  func (s *Surface) Unlock() {
   100  	C.SDL_UnlockSurface((*C.struct_SDL_Surface)(s))
   101  }
   102  
   103  func (s *Surface) ColorModel() color.Model {
   104  	return color.NRGBAModel
   105  }
   106  
   107  func (s *Surface) Bounds() image.Rectangle {
   108  	r := s.ClipRect()
   109  	return image.Rect(r.X, r.Y, r.X+r.W, r.Y+r.H)
   110  }
   111  
   112  func (s *Surface) At(x, y int) color.Color {
   113  	_surface := (*C.struct_SDL_Surface)(s)
   114  	_format := (*PixelFormatS)(unsafe.Pointer(_surface.format))
   115  	_pixel := *(*uint32)(unsafe.Pointer(uintptr(_surface.pixels) + uintptr(y)*uintptr(_surface.pitch) + uintptr(x)*uintptr(_format.bytesPerPixel)))
   116  	r := uint8(((_pixel & _format.RMask) >> _format.RShift) << _format.RLoss)
   117  	g := uint8(((_pixel & _format.GMask) >> _format.GShift) << _format.GLoss)
   118  	b := uint8(((_pixel & _format.BMask) >> _format.BShift) << _format.BLoss)
   119  	a := uint8(((_pixel & _format.AMask) >> _format.AShift) << _format.ALoss)
   120  	//return color.RGBA{
   121  	//	R: uint8(uint16(r) * uint16(a) / 255),
   122  	//	G: uint8(uint16(g) * uint16(a) / 255),
   123  	//	B: uint8(uint16(b) * uint16(a) / 255),
   124  	//	A: a,
   125  	//}
   126  	return color.NRGBA{
   127  		R: r,
   128  		G: g,
   129  		B: b,
   130  		A: a,
   131  	}
   132  }
   133  
   134  func (s Surface) Format() PixelFormatS {
   135  	return *(*PixelFormatS)(unsafe.Pointer(s.format))
   136  }
   137  
   138  func (s *Surface) Pixels() []byte {
   139  	return unsafe.Slice((*byte)(unsafe.Pointer(s.pixels)), s.Height()*s.Pitch())
   140  }
   141  
   142  func (s *Surface) Width() int {
   143  	return int(s.w)
   144  }
   145  
   146  func (s *Surface) Height() int {
   147  	return int(s.h)
   148  }
   149  
   150  func (s *Surface) Pitch() int {
   151  	return int(s.pitch)
   152  }
   153  
   154  func (s *Surface) SetPixelFormatPalette(palette *Palette) error {
   155  	return SetPixelFormatPalette((*PixelFormatS)(unsafe.Pointer(s.format)), palette)
   156  }
   157  
   158  func ConvertSurface(src *Surface, format *PixelFormatS) (*Surface, error) {
   159  	surface := C.SDL_ConvertSurface(
   160  		(*C.struct_SDL_Surface)(src),
   161  		(*C.struct_SDL_PixelFormat)(unsafe.Pointer(format)),
   162  		0,
   163  	)
   164  	if surface == nil {
   165  		return nil, GetError()
   166  	}
   167  	return (*Surface)(surface), nil
   168  }
   169  
   170  func (s *Surface) Convert(format *PixelFormatS) (*Surface, error) {
   171  	return ConvertSurface(s, format)
   172  }
   173  
   174  func ConvertSurfaceFormat(src *Surface, format PixelFormat) (*Surface, error) {
   175  	surface := C.SDL_ConvertSurfaceFormat(
   176  		(*C.struct_SDL_Surface)(src),
   177  		C.Uint32(format),
   178  		0,
   179  	)
   180  	if surface == nil {
   181  		return nil, GetError()
   182  	}
   183  	return (*Surface)(surface), nil
   184  }
   185  
   186  func (s *Surface) ConvertFormat(format PixelFormat) (*Surface, error) {
   187  	return ConvertSurfaceFormat(s, format)
   188  }
   189  
   190  func CreateRGBSurfaceWithFormat(flags uint32, width, height, depth int, format PixelFormat) (*Surface, error) {
   191  	surface := C.SDL_CreateRGBSurfaceWithFormat(0, C.int(width), C.int(height), C.int(depth), C.Uint32(format))
   192  	if surface == nil {
   193  		return nil, GetError()
   194  	}
   195  	return (*Surface)(surface), nil
   196  }
   197  
   198  func (s *Surface) Image() draw.Image {
   199  	f := s.Format()
   200  	a := imageAdapter{
   201  		surface: s,
   202  	}
   203  	a.model = a.ColorModel()
   204  	a.bounds = a.Bounds()
   205  	p := f.Palette()
   206  	if p != nil {
   207  		a2 := imageAdapterPalette{
   208  			imageAdapter: a,
   209  		}
   210  		p := a2.ColorModel().(color.Palette)
   211  		a2.palette = &p
   212  		return a2
   213  	}
   214  	return a
   215  }
   216  
   217  type imageAdapter struct {
   218  	surface *Surface
   219  	model   color.Model
   220  	bounds  image.Rectangle
   221  }
   222  
   223  func (a imageAdapter) ColorModel() color.Model {
   224  	if PixelFormat(a.surface.format.format) == PixelFormatARGB2101010 {
   225  		return compat.ARGB2101010Model
   226  	}
   227  	return &genericModel{(*PixelFormatS)(unsafe.Pointer(a.surface.format))}
   228  }
   229  
   230  func (a imageAdapter) Bounds() image.Rectangle {
   231  	return image.Rect(
   232  		0,
   233  		0,
   234  		int((*C.struct_SDL_Surface)(a.surface).w),
   235  		int((*C.struct_SDL_Surface)(a.surface).h),
   236  	)
   237  }
   238  
   239  func (a imageAdapter) At(x, y int) color.Color {
   240  	if !(image.Point{x, y}.In(a.bounds)) {
   241  		if PixelFormat(a.surface.format.format) == PixelFormatARGB2101010 {
   242  			return compat.ARGB2101010{ARGB: 0}
   243  		}
   244  		return genericColor{data: 0, info: (*PixelFormatS)(unsafe.Pointer(a.surface.format))}
   245  	}
   246  	bpp := int(a.surface.format.BytesPerPixel)
   247  	i := y*int(a.surface.pitch) + x*bpp
   248  	s := (*[4]byte)(unsafe.Add(unsafe.Pointer(a.surface.pixels), i))[:bpp:bpp]
   249  	var data uint32
   250  	switch bpp {
   251  	case 4:
   252  		data = uint32(s[3])<<24 | uint32(s[2])<<16 | uint32(s[1])<<8 | uint32(s[0])
   253  	case 3:
   254  		data = uint32(s[2])<<16 | uint32(s[1])<<8 | uint32(s[0])
   255  	case 2:
   256  		data = uint32(s[1])<<8 | uint32(s[0])
   257  	case 1:
   258  		data = uint32(s[0])
   259  	}
   260  	if PixelFormat(a.surface.format.format) == PixelFormatARGB2101010 {
   261  		return compat.ARGB2101010{ARGB: data}
   262  	}
   263  	return genericColor{data: data, info: (*PixelFormatS)(unsafe.Pointer(a.surface.format))}
   264  }
   265  
   266  func (a imageAdapter) Set(x, y int, c color.Color) {
   267  	if !(image.Point{x, y}.In(a.bounds)) {
   268  		return
   269  	}
   270  	var data uint32
   271  	switch c := a.model.Convert(c).(type) {
   272  	case genericColor:
   273  		data = c.data
   274  	case compat.ARGB2101010:
   275  		data = c.ARGB
   276  	default:
   277  		panic("unexpected color model")
   278  	}
   279  	bpp := int(a.surface.format.BytesPerPixel)
   280  	i := y*int(a.surface.pitch) + x*bpp
   281  	s := (*[4]byte)(unsafe.Add(unsafe.Pointer(a.surface.pixels), i))[:bpp:bpp]
   282  	switch bpp {
   283  	case 4:
   284  		s[3] = uint8(data>>24) & 0xff
   285  		fallthrough
   286  	case 3:
   287  		s[2] = uint8(data>>16) & 0xff
   288  		fallthrough
   289  	case 2:
   290  		s[1] = uint8(data>>8) & 0xff
   291  		fallthrough
   292  	case 1:
   293  		s[0] = uint8(data) & 0xff
   294  	}
   295  }
   296  
   297  type imageAdapterPalette struct {
   298  	imageAdapter
   299  	palette *color.Palette
   300  }
   301  
   302  func (a imageAdapterPalette) At(x, y int) color.Color {
   303  	if len(*a.palette) == 0 {
   304  		return nil
   305  	}
   306  	return (*a.palette)[a.ColorIndexAt(x, y)]
   307  }
   308  
   309  func (a imageAdapterPalette) ColorIndexAt(x, y int) uint8 {
   310  	if !(image.Point{x, y}.In(a.bounds)) {
   311  		return 0
   312  	}
   313  	bpp := a.surface.format.BitsPerPixel
   314  	by := uint(x*int(bpp)) / 8
   315  	bi := uint(x*int(bpp)) % 8
   316  	i := y*int(a.surface.pitch) + int(by)
   317  	s := (*[2]byte)(unsafe.Add(unsafe.Pointer(a.surface.pixels), i))[:2:2]
   318  	index := uint32(s[1])<<8 | uint32(s[0])
   319  	return uint8(index>>bi) & ((1 << bpp) - 1)
   320  }
   321  
   322  func (a imageAdapterPalette) Set(x, y int, c color.Color) {
   323  	if !(image.Point{x, y}.In(a.bounds)) {
   324  		return
   325  	}
   326  	bpp := a.surface.format.BitsPerPixel
   327  	by := uint(x*int(bpp)) / 8
   328  	bi := uint(x*int(bpp)) % 8
   329  	i := y*int(a.surface.pitch) + int(by)
   330  	s := (*[2]byte)(unsafe.Add(unsafe.Pointer(a.surface.pixels), i))[:2:2]
   331  	index := uint32(a.palette.Index(c))
   332  	s[0] &= (1 << bi) - 1
   333  	s[0] |= uint8((index << bi) & 0xff)
   334  	s[1] &= ^((1 << ((bi + uint(bpp)) % 8)) - 1)
   335  	s[1] |= uint8((index << bi) >> 8 & 0xff)
   336  	// todo check if this is correct
   337  }
   338  
   339  func (a imageAdapterPalette) ColorModel() color.Model {
   340  	f := a.surface.Format()
   341  	p := f.Palette()
   342  	cs := make(color.Palette, 0, len(p))
   343  	for _, c := range p {
   344  		cs = append(cs, color.NRGBA{R: c.R, G: c.G, B: c.B, A: c.A})
   345  	}
   346  	return cs
   347  }
   348  
   349  type genericColor struct {
   350  	data uint32
   351  	info *PixelFormatS
   352  }
   353  
   354  func (c genericColor) RGBA() (r, g, b, a uint32) {
   355  	switch {
   356  	case c.info.AMask == 0:
   357  		a = 0xff
   358  	default:
   359  		a = c.data & c.info.AMask
   360  		a >>= c.info.AShift
   361  		a <<= c.info.ALoss
   362  	}
   363  	r = c.data & c.info.RMask
   364  	r >>= c.info.RShift
   365  	r <<= c.info.RLoss
   366  	r |= r << 8
   367  	r *= a
   368  	r /= 0xff
   369  	g = c.data & c.info.GMask
   370  	g >>= c.info.GShift
   371  	g <<= c.info.GLoss
   372  	g |= g << 8
   373  	g *= a
   374  	g /= 0xff
   375  	b = c.data & c.info.BMask
   376  	b >>= c.info.BShift
   377  	b <<= c.info.BLoss
   378  	b |= b << 8
   379  	b *= a
   380  	b /= 0xff
   381  	a |= a << 8
   382  	return
   383  }
   384  
   385  type genericModel struct {
   386  	info *PixelFormatS
   387  }
   388  
   389  func (m *genericModel) Convert(c color.Color) color.Color {
   390  	if om, ok := c.(genericColor); ok && om.info == m.info {
   391  		return c
   392  	}
   393  	r, g, b, a := c.RGBA()
   394  	if a == 0 {
   395  		return genericColor{data: 0, info: m.info}
   396  	}
   397  	r = (r * 0xffff) / a
   398  	g = (g * 0xffff) / a
   399  	b = (b * 0xffff) / a
   400  	r >>= m.info.RLoss
   401  	r <<= m.info.RShift
   402  	r &= m.info.RMask
   403  	g >>= m.info.GLoss
   404  	g <<= m.info.GShift
   405  	g &= m.info.RMask
   406  	b >>= m.info.BLoss
   407  	b <<= m.info.BShift
   408  	b &= m.info.BMask
   409  	a >>= m.info.ALoss
   410  	a <<= m.info.AShift
   411  	a &= m.info.AMask
   412  	return genericColor{data: r | g | b | a, info: m.info}
   413  }