const std = @import("std");
pub const c = @import("c.zig").c;

pub const PixelFormat = enum(c_int) {
    pixelformatYv12, //Planar mode: Y + V + U  (3 planes)
    pixelformatIyuv, //Planar mode: Y + U + V  (3 planes)
    pixelformatYuy2, //Packed mode: Y0+U0+Y1+V0 (1 plane)
    pixelformatUyvy, //Packed mode: U0+Y0+V0+Y1 (1 plane)
    pixelformatYvyu, //Packed mode: Y0+V0+Y1+U0 (1 plane)
    pixelformatNv12, //Planar mode: Y + U/V interleaved  (2 planes)
    pixelformatNv21, //Planar mode: Y + V/U interleaved  (2 planes)
    pixelformatP010, //Planar mode: Y + U/V interleaved  (2 planes)
    pixelformatExternalOes, //Android video texture format
};

pub const BlendMode = u32;

pub const IOStream = opaque {
    pub inline fn loadBMP_IO(iostream: *IOStream, closeio: bool) ?*Surface {
        return c.SDL_LoadBMP_IO(iostream, closeio);
    }
};

pub const Rect = extern struct {
    x: c_int,
    y: c_int,
    w: c_int,
    h: c_int,
};

pub const Palette = extern struct {
    ncolors: c_int, // number of elements in `colors`.
    colors: ?*Color, // an array of colors, `ncolors` long.
    version: u32, // internal use only, do not touch.
    refcount: c_int, // internal use only, do not touch.
};

pub const Color = extern struct {
    r: u8,
    g: u8,
    b: u8,
    a: u8,
};

pub const Colorspace = enum(c_int) {
    colorspaceSrgb, //Equivalent to DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709
    colorRangeFull,
    colorPrimariesBt709,
    transferCharacteristicsSrgb,
    matrixCoefficientsIdentity,
    colorspaceSrgbLinear, //Equivalent to DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709
    transferCharacteristicsLinear,
    colorspaceHdr10, //Equivalent to DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020
    colorPrimariesBt2020,
    transferCharacteristicsPq,
    colorspaceJpeg, //Equivalent to DXGI_COLOR_SPACE_YCBCR_FULL_G22_NONE_P709_X601
    transferCharacteristicsBt601,
    matrixCoefficientsBt601,
    colorspaceBt601Limited, //Equivalent to DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601
    colorRangeLimited,
    colorPrimariesBt601,
    colorspaceBt601Full, //Equivalent to DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601
    colorspaceBt709Limited, //Equivalent to DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709
    transferCharacteristicsBt709,
    matrixCoefficientsBt709,
    colorspaceBt709Full, //Equivalent to DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709
    colorspaceBt2020Limited, //Equivalent to DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020
    matrixCoefficientsBt2020Ncl,
    colorspaceBt2020Full, //Equivalent to DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020
    colorspaceRgbDefault, //The default colorspace for RGB surfaces if no colorspace is specified
    colorspaceYuvDefault, //The default colorspace for YUV surfaces if no colorspace is specified
};

pub const PropertiesID = u32;

pub const SurfaceFlags = packed struct(u32) {
    surfacePreallocated: bool = false, // Surface uses preallocated pixel memory
    surfaceLockNeeded: bool = false, // Surface needs to be locked to access pixels
    surfaceLocked: bool = false, // Surface is currently locked
    surfaceSimdAligned: bool = false, // Surface uses pixel memory allocated with SDL_aligned_alloc()
    pad0: u27 = 0,
    rsvd: bool = false,
};

pub const ScaleMode = enum(c_int) {
    scalemodeNearest, //nearest pixel sampling
    scalemodeLinear, //linear filtering
};

pub const FlipMode = enum(c_int) {
    flipNone, //Do not flip
    flipHorizontal, //flip horizontally
    flipVertical, //flip vertically
};

pub const Surface = opaque {
    pub inline fn destroySurface(surface: *Surface) void {
        return c.SDL_DestroySurface(surface);
    }

    pub inline fn getSurfaceProperties(surface: *Surface) PropertiesID {
        return c.SDL_GetSurfaceProperties(surface);
    }

    pub inline fn setSurfaceColorspace(surface: *Surface, colorspace: Colorspace) bool {
        return c.SDL_SetSurfaceColorspace(surface, colorspace);
    }

    pub inline fn getSurfaceColorspace(surface: *Surface) Colorspace {
        return c.SDL_GetSurfaceColorspace(surface);
    }

    pub inline fn createSurfacePalette(surface: *Surface) ?*Palette {
        return c.SDL_CreateSurfacePalette(surface);
    }

    pub inline fn setSurfacePalette(surface: *Surface, palette: ?*Palette) bool {
        return c.SDL_SetSurfacePalette(surface, palette);
    }

    pub inline fn getSurfacePalette(surface: *Surface) ?*Palette {
        return c.SDL_GetSurfacePalette(surface);
    }

    pub inline fn addSurfaceAlternateImage(surface: *Surface, image: ?*Surface) bool {
        return c.SDL_AddSurfaceAlternateImage(surface, image);
    }

    pub inline fn surfaceHasAlternateImages(surface: *Surface) bool {
        return c.SDL_SurfaceHasAlternateImages(surface);
    }

    pub inline fn getSurfaceImages(surface: *Surface, count: *c_int) [*c][*c]Surface {
        return c.SDL_GetSurfaceImages(surface, @ptrCast(count));
    }

    pub inline fn removeSurfaceAlternateImages(surface: *Surface) void {
        return c.SDL_RemoveSurfaceAlternateImages(surface);
    }

    pub inline fn lockSurface(surface: *Surface) bool {
        return c.SDL_LockSurface(surface);
    }

    pub inline fn unlockSurface(surface: *Surface) void {
        return c.SDL_UnlockSurface(surface);
    }

    pub inline fn saveBMP_IO(surface: *Surface, dst: ?*IOStream, closeio: bool) bool {
        return c.SDL_SaveBMP_IO(surface, dst, closeio);
    }

    pub inline fn saveBMP(surface: *Surface, file: [*c]const u8) bool {
        return c.SDL_SaveBMP(surface, file);
    }

    pub inline fn setSurfaceRLE(surface: *Surface, enabled: bool) bool {
        return c.SDL_SetSurfaceRLE(surface, enabled);
    }

    pub inline fn surfaceHasRLE(surface: *Surface) bool {
        return c.SDL_SurfaceHasRLE(surface);
    }

    pub inline fn setSurfaceColorKey(surface: *Surface, enabled: bool, key: u32) bool {
        return c.SDL_SetSurfaceColorKey(surface, enabled, key);
    }

    pub inline fn surfaceHasColorKey(surface: *Surface) bool {
        return c.SDL_SurfaceHasColorKey(surface);
    }

    pub inline fn getSurfaceColorKey(surface: *Surface, key: *u32) bool {
        return c.SDL_GetSurfaceColorKey(surface, @ptrCast(key));
    }

    pub inline fn setSurfaceColorMod(surface: *Surface, r: u8, g: u8, b: u8) bool {
        return c.SDL_SetSurfaceColorMod(surface, r, g, b);
    }

    pub inline fn getSurfaceColorMod(surface: *Surface, r: [*c]u8, g: [*c]u8, b: [*c]u8) bool {
        return c.SDL_GetSurfaceColorMod(surface, r, g, b);
    }

    pub inline fn setSurfaceAlphaMod(surface: *Surface, alpha: u8) bool {
        return c.SDL_SetSurfaceAlphaMod(surface, alpha);
    }

    pub inline fn getSurfaceAlphaMod(surface: *Surface, alpha: [*c]u8) bool {
        return c.SDL_GetSurfaceAlphaMod(surface, alpha);
    }

    pub inline fn setSurfaceBlendMode(surface: *Surface, blendMode: BlendMode) bool {
        return c.SDL_SetSurfaceBlendMode(surface, @intFromEnum(blendMode));
    }

    pub inline fn getSurfaceBlendMode(surface: *Surface, blendMode: ?*BlendMode) bool {
        return c.SDL_GetSurfaceBlendMode(surface, @intFromEnum(blendMode));
    }

    pub inline fn setSurfaceClipRect(surface: *Surface, rect: *const Rect) bool {
        return c.SDL_SetSurfaceClipRect(surface, @ptrCast(rect));
    }

    pub inline fn getSurfaceClipRect(surface: *Surface, rect: ?*Rect) bool {
        return c.SDL_GetSurfaceClipRect(surface, rect);
    }

    pub inline fn flipSurface(surface: *Surface, flip: FlipMode) bool {
        return c.SDL_FlipSurface(surface, @intFromEnum(flip));
    }

    pub inline fn duplicateSurface(surface: *Surface) ?*Surface {
        return c.SDL_DuplicateSurface(surface);
    }

    pub inline fn scaleSurface(surface: *Surface, width: c_int, height: c_int, scaleMode: ScaleMode) ?*Surface {
        return c.SDL_ScaleSurface(surface, width, height, @intFromEnum(scaleMode));
    }

    pub inline fn convertSurface(surface: *Surface, format: PixelFormat) ?*Surface {
        return c.SDL_ConvertSurface(surface, @bitCast(format));
    }

    pub inline fn convertSurfaceAndColorspace(surface: *Surface, format: PixelFormat, palette: ?*Palette, colorspace: Colorspace, props: PropertiesID) ?*Surface {
        return c.SDL_ConvertSurfaceAndColorspace(surface, @bitCast(format), palette, colorspace, props);
    }

    pub inline fn premultiplySurfaceAlpha(surface: *Surface, linear: bool) bool {
        return c.SDL_PremultiplySurfaceAlpha(surface, linear);
    }

    pub inline fn clearSurface(surface: *Surface, r: f32, g: f32, b: f32, a: f32) bool {
        return c.SDL_ClearSurface(surface, r, g, b, a);
    }

    pub inline fn fillSurfaceRect(surface: *Surface, rect: *const Rect, color: u32) bool {
        return c.SDL_FillSurfaceRect(surface, @ptrCast(rect), color);
    }

    pub inline fn fillSurfaceRects(surface: *Surface, rects: *const Rect, count: c_int, color: u32) bool {
        return c.SDL_FillSurfaceRects(surface, @ptrCast(rects), count, color);
    }

    pub inline fn blitSurface(surface: *Surface, srcrect: *const Rect, dst: ?*Surface, dstrect: *const Rect) bool {
        return c.SDL_BlitSurface(surface, @ptrCast(srcrect), dst, @ptrCast(dstrect));
    }

    pub inline fn blitSurfaceUnchecked(surface: *Surface, srcrect: *const Rect, dst: ?*Surface, dstrect: *const Rect) bool {
        return c.SDL_BlitSurfaceUnchecked(surface, @ptrCast(srcrect), dst, @ptrCast(dstrect));
    }

    pub inline fn blitSurfaceScaled(surface: *Surface, srcrect: *const Rect, dst: ?*Surface, dstrect: *const Rect, scaleMode: ScaleMode) bool {
        return c.SDL_BlitSurfaceScaled(surface, @ptrCast(srcrect), dst, @ptrCast(dstrect), @intFromEnum(scaleMode));
    }

    pub inline fn blitSurfaceUncheckedScaled(surface: *Surface, srcrect: *const Rect, dst: ?*Surface, dstrect: *const Rect, scaleMode: ScaleMode) bool {
        return c.SDL_BlitSurfaceUncheckedScaled(surface, @ptrCast(srcrect), dst, @ptrCast(dstrect), @intFromEnum(scaleMode));
    }

    pub inline fn stretchSurface(surface: *Surface, srcrect: *const Rect, dst: ?*Surface, dstrect: *const Rect, scaleMode: ScaleMode) bool {
        return c.SDL_StretchSurface(surface, @ptrCast(srcrect), dst, @ptrCast(dstrect), @intFromEnum(scaleMode));
    }

    pub inline fn blitSurfaceTiled(surface: *Surface, srcrect: *const Rect, dst: ?*Surface, dstrect: *const Rect) bool {
        return c.SDL_BlitSurfaceTiled(surface, @ptrCast(srcrect), dst, @ptrCast(dstrect));
    }

    pub inline fn blitSurfaceTiledWithScale(surface: *Surface, srcrect: *const Rect, scale: f32, scaleMode: ScaleMode, dst: ?*Surface, dstrect: *const Rect) bool {
        return c.SDL_BlitSurfaceTiledWithScale(surface, @ptrCast(srcrect), scale, @intFromEnum(scaleMode), dst, @ptrCast(dstrect));
    }

    pub inline fn blitSurface9Grid(surface: *Surface, srcrect: *const Rect, left_width: c_int, right_width: c_int, top_height: c_int, bottom_height: c_int, scale: f32, scaleMode: ScaleMode, dst: ?*Surface, dstrect: *const Rect) bool {
        return c.SDL_BlitSurface9Grid(surface, @ptrCast(srcrect), left_width, right_width, top_height, bottom_height, scale, @intFromEnum(scaleMode), dst, @ptrCast(dstrect));
    }

    pub inline fn mapSurfaceRGB(surface: *Surface, r: u8, g: u8, b: u8) u32 {
        return c.SDL_MapSurfaceRGB(surface, r, g, b);
    }

    pub inline fn mapSurfaceRGBA(surface: *Surface, r: u8, g: u8, b: u8, a: u8) u32 {
        return c.SDL_MapSurfaceRGBA(surface, r, g, b, a);
    }

    pub inline fn readSurfacePixel(surface: *Surface, x: c_int, y: c_int, r: [*c]u8, g: [*c]u8, b: [*c]u8, a: [*c]u8) bool {
        return c.SDL_ReadSurfacePixel(surface, x, y, r, g, b, a);
    }

    pub inline fn readSurfacePixelFloat(surface: *Surface, x: c_int, y: c_int, r: *f32, g: *f32, b: *f32, a: *f32) bool {
        return c.SDL_ReadSurfacePixelFloat(surface, x, y, @ptrCast(r), @ptrCast(g), @ptrCast(b), @ptrCast(a));
    }

    pub inline fn writeSurfacePixel(surface: *Surface, x: c_int, y: c_int, r: u8, g: u8, b: u8, a: u8) bool {
        return c.SDL_WriteSurfacePixel(surface, x, y, r, g, b, a);
    }

    pub inline fn writeSurfacePixelFloat(surface: *Surface, x: c_int, y: c_int, r: f32, g: f32, b: f32, a: f32) bool {
        return c.SDL_WriteSurfacePixelFloat(surface, x, y, r, g, b, a);
    }
};

pub inline fn createSurface(width: c_int, height: c_int, format: PixelFormat) ?*Surface {
    return c.SDL_CreateSurface(width, height, @bitCast(format));
}

pub inline fn createSurfaceFrom(width: c_int, height: c_int, format: PixelFormat, pixels: ?*anyopaque, pitch: c_int) ?*Surface {
    return c.SDL_CreateSurfaceFrom(width, height, @bitCast(format), pixels, pitch);
}

pub inline fn loadBMP(file: [*c]const u8) ?*Surface {
    return c.SDL_LoadBMP(file);
}

pub inline fn convertPixels(width: c_int, height: c_int, src_format: PixelFormat, src: ?*const anyopaque, src_pitch: c_int, dst_format: PixelFormat, dst: ?*anyopaque, dst_pitch: c_int) bool {
    return c.SDL_ConvertPixels(width, height, @bitCast(src_format), src, src_pitch, @bitCast(dst_format), dst, dst_pitch);
}

pub inline fn convertPixelsAndColorspace(width: c_int, height: c_int, src_format: PixelFormat, src_colorspace: Colorspace, src_properties: PropertiesID, src: ?*const anyopaque, src_pitch: c_int, dst_format: PixelFormat, dst_colorspace: Colorspace, dst_properties: PropertiesID, dst: ?*anyopaque, dst_pitch: c_int) bool {
    return c.SDL_ConvertPixelsAndColorspace(width, height, @bitCast(src_format), src_colorspace, src_properties, src, src_pitch, @bitCast(dst_format), dst_colorspace, dst_properties, dst, dst_pitch);
}

pub inline fn premultiplyAlpha(width: c_int, height: c_int, src_format: PixelFormat, src: ?*const anyopaque, src_pitch: c_int, dst_format: PixelFormat, dst: ?*anyopaque, dst_pitch: c_int, linear: bool) bool {
    return c.SDL_PremultiplyAlpha(width, height, @bitCast(src_format), src, src_pitch, @bitCast(dst_format), dst, dst_pitch, linear);
}
