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 }