/* FNA3D - 3D Graphics Library for FNA
 *
 * Copyright (c) 2020-2024 Ethan Lee
 *
 * This software is provided 'as-is', without any express or implied warranty.
 * In no event will the authors be held liable for any damages arising from
 * the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 * claim that you wrote the original software. If you use this software in a
 * product, an acknowledgment in the product documentation would be
 * appreciated but is not required.
 *
 * 2. Altered source versions must be plainly marked as such, and must not be
 * misrepresented as being the original software.
 *
 * 3. This notice may not be removed or altered from any source distribution.
 *
 * Ethan "flibitijibibo" Lee <flibitijibibo@flibitijibibo.com>
 *
 */

#ifndef FNA3D_H
#define FNA3D_H

#ifdef _WIN32
#define FNA3DAPI __declspec(dllexport)
#define FNA3DCALL __cdecl
#else
#define FNA3DAPI
#define FNA3DCALL
#endif

#ifdef _MSC_VER
#define FNA3DDEPRECATED(msg) __declspec(deprecated(msg))
#else
#define FNA3DDEPRECATED(msg) __attribute__((deprecated(msg)))
#endif

/* -Wpedantic nameless union/struct silencing */
#ifndef FNA3DNAMELESS
#ifdef __GNUC__
#define FNA3DNAMELESS __extension__
#else
#define FNA3DNAMELESS
#endif /* __GNUC__ */
#endif /* FNA3DNAMELESS */

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/* Type Declarations */

typedef struct FNA3D_Device FNA3D_Device;
typedef struct FNA3D_Texture FNA3D_Texture;
typedef struct FNA3D_Buffer FNA3D_Buffer;
typedef struct FNA3D_Renderbuffer FNA3D_Renderbuffer;
typedef struct FNA3D_Effect FNA3D_Effect;
typedef struct FNA3D_Query FNA3D_Query;

/* Enumerations, should match XNA 4.0 */

typedef enum FNA3D_PresentInterval
{
	/* For the default presentation interval, we try to use an OS-provided
	 * feature (if available) to sync when meeting the target framerate
	 * while tearing if the program misses vblank.
	 */
	FNA3D_PRESENTINTERVAL_DEFAULT,
	FNA3D_PRESENTINTERVAL_ONE,
	FNA3D_PRESENTINTERVAL_TWO,
	FNA3D_PRESENTINTERVAL_IMMEDIATE
} FNA3D_PresentInterval;

typedef enum FNA3D_DisplayOrientation
{
	FNA3D_DISPLAYORIENTATION_DEFAULT,
	FNA3D_DISPLAYORIENTATION_LANDSCAPELEFT,
	FNA3D_DISPLAYORIENTATION_LANDSCAPERIGHT,
	FNA3D_DISPLAYORIENTATION_PORTRAIT
} FNA3D_DisplayOrientation;

typedef enum FNA3D_RenderTargetUsage
{
	FNA3D_RENDERTARGETUSAGE_DISCARDCONTENTS,
	FNA3D_RENDERTARGETUSAGE_PRESERVECONTENTS,
	FNA3D_RENDERTARGETUSAGE_PLATFORMCONTENTS
} FNA3D_RenderTargetUsage;

typedef enum FNA3D_ClearOptions
{
	FNA3D_CLEAROPTIONS_TARGET	= 1,
	FNA3D_CLEAROPTIONS_DEPTHBUFFER	= 2,
	FNA3D_CLEAROPTIONS_STENCIL	= 4
} FNA3D_ClearOptions;

typedef enum FNA3D_PrimitiveType
{
	FNA3D_PRIMITIVETYPE_TRIANGLELIST,
	FNA3D_PRIMITIVETYPE_TRIANGLESTRIP,
	FNA3D_PRIMITIVETYPE_LINELIST,
	FNA3D_PRIMITIVETYPE_LINESTRIP,
	FNA3D_PRIMITIVETYPE_POINTLIST_EXT
} FNA3D_PrimitiveType;

typedef enum FNA3D_IndexElementSize
{
	FNA3D_INDEXELEMENTSIZE_16BIT,
	FNA3D_INDEXELEMENTSIZE_32BIT
} FNA3D_IndexElementSize;

typedef enum FNA3D_SurfaceFormat
{
	FNA3D_SURFACEFORMAT_COLOR,
	FNA3D_SURFACEFORMAT_BGR565,
	FNA3D_SURFACEFORMAT_BGRA5551,
	FNA3D_SURFACEFORMAT_BGRA4444,
	FNA3D_SURFACEFORMAT_DXT1,
	FNA3D_SURFACEFORMAT_DXT3,
	FNA3D_SURFACEFORMAT_DXT5,
	FNA3D_SURFACEFORMAT_NORMALIZEDBYTE2,
	FNA3D_SURFACEFORMAT_NORMALIZEDBYTE4,
	FNA3D_SURFACEFORMAT_RGBA1010102,
	FNA3D_SURFACEFORMAT_RG32,
	FNA3D_SURFACEFORMAT_RGBA64,
	FNA3D_SURFACEFORMAT_ALPHA8,
	FNA3D_SURFACEFORMAT_SINGLE,
	FNA3D_SURFACEFORMAT_VECTOR2,
	FNA3D_SURFACEFORMAT_VECTOR4,
	FNA3D_SURFACEFORMAT_HALFSINGLE,
	FNA3D_SURFACEFORMAT_HALFVECTOR2,
	FNA3D_SURFACEFORMAT_HALFVECTOR4,
	FNA3D_SURFACEFORMAT_HDRBLENDABLE,
	FNA3D_SURFACEFORMAT_COLORBGRA_EXT,
	FNA3D_SURFACEFORMAT_COLORSRGB_EXT,
	FNA3D_SURFACEFORMAT_DXT5SRGB_EXT,
	FNA3D_SURFACEFORMAT_BC7_EXT,
	FNA3D_SURFACEFORMAT_BC7SRGB_EXT,
	FNA3D_SURFACEFORMAT_BYTE_EXT,
	FNA3D_SURFACEFORMAT_USHORT_EXT,
} FNA3D_SurfaceFormat;

typedef enum FNA3D_DepthFormat
{
	FNA3D_DEPTHFORMAT_NONE,
	FNA3D_DEPTHFORMAT_D16,
	FNA3D_DEPTHFORMAT_D24,
	FNA3D_DEPTHFORMAT_D24S8
} FNA3D_DepthFormat;

typedef enum FNA3D_CubeMapFace
{
	FNA3D_CUBEMAPFACE_POSITIVEX,
	FNA3D_CUBEMAPFACE_NEGATIVEX,
	FNA3D_CUBEMAPFACE_POSITIVEY,
	FNA3D_CUBEMAPFACE_NEGATIVEY,
	FNA3D_CUBEMAPFACE_POSITIVEZ,
	FNA3D_CUBEMAPFACE_NEGATIVEZ
} FNA3D_CubeMapFace;

typedef enum FNA3D_BufferUsage
{
	FNA3D_BUFFERUSAGE_NONE,
	FNA3D_BUFFERUSAGE_WRITEONLY
} FNA3D_BufferUsage;

typedef enum FNA3D_SetDataOptions
{
	FNA3D_SETDATAOPTIONS_NONE,
	FNA3D_SETDATAOPTIONS_DISCARD,
	FNA3D_SETDATAOPTIONS_NOOVERWRITE
} FNA3D_SetDataOptions;

typedef enum FNA3D_Blend
{
	FNA3D_BLEND_ONE,
	FNA3D_BLEND_ZERO,
	FNA3D_BLEND_SOURCECOLOR,
	FNA3D_BLEND_INVERSESOURCECOLOR,
	FNA3D_BLEND_SOURCEALPHA,
	FNA3D_BLEND_INVERSESOURCEALPHA,
	FNA3D_BLEND_DESTINATIONCOLOR,
	FNA3D_BLEND_INVERSEDESTINATIONCOLOR,
	FNA3D_BLEND_DESTINATIONALPHA,
	FNA3D_BLEND_INVERSEDESTINATIONALPHA,
	FNA3D_BLEND_BLENDFACTOR,
	FNA3D_BLEND_INVERSEBLENDFACTOR,
	FNA3D_BLEND_SOURCEALPHASATURATION
} FNA3D_Blend;

typedef enum FNA3D_BlendFunction
{
	FNA3D_BLENDFUNCTION_ADD,
	FNA3D_BLENDFUNCTION_SUBTRACT,
	FNA3D_BLENDFUNCTION_REVERSESUBTRACT,
	FNA3D_BLENDFUNCTION_MAX,
	FNA3D_BLENDFUNCTION_MIN
} FNA3D_BlendFunction;

typedef enum FNA3D_ColorWriteChannels
{
	FNA3D_COLORWRITECHANNELS_NONE	= 0,
	FNA3D_COLORWRITECHANNELS_RED	= 1,
	FNA3D_COLORWRITECHANNELS_GREEN	= 2,
	FNA3D_COLORWRITECHANNELS_BLUE	= 4,
	FNA3D_COLORWRITECHANNELS_ALPHA	= 8,
	FNA3D_COLORWRITECHANNELS_ALL	= 15
} FNA3D_ColorWriteChannels;

typedef enum FNA3D_StencilOperation
{
	FNA3D_STENCILOPERATION_KEEP,
	FNA3D_STENCILOPERATION_ZERO,
	FNA3D_STENCILOPERATION_REPLACE,
	FNA3D_STENCILOPERATION_INCREMENT,
	FNA3D_STENCILOPERATION_DECREMENT,
	FNA3D_STENCILOPERATION_INCREMENTSATURATION,
	FNA3D_STENCILOPERATION_DECREMENTSATURATION,
	FNA3D_STENCILOPERATION_INVERT
} FNA3D_StencilOperation;

typedef enum FNA3D_CompareFunction
{
	FNA3D_COMPAREFUNCTION_ALWAYS,
	FNA3D_COMPAREFUNCTION_NEVER,
	FNA3D_COMPAREFUNCTION_LESS,
	FNA3D_COMPAREFUNCTION_LESSEQUAL,
	FNA3D_COMPAREFUNCTION_EQUAL,
	FNA3D_COMPAREFUNCTION_GREATEREQUAL,
	FNA3D_COMPAREFUNCTION_GREATER,
	FNA3D_COMPAREFUNCTION_NOTEQUAL
} FNA3D_CompareFunction;

typedef enum FNA3D_CullMode
{
	FNA3D_CULLMODE_NONE,
	FNA3D_CULLMODE_CULLCLOCKWISEFACE,
	FNA3D_CULLMODE_CULLCOUNTERCLOCKWISEFACE
} FNA3D_CullMode;

typedef enum FNA3D_FillMode
{
	FNA3D_FILLMODE_SOLID,
	FNA3D_FILLMODE_WIREFRAME
} FNA3D_FillMode;

typedef enum FNA3D_TextureAddressMode
{
	FNA3D_TEXTUREADDRESSMODE_WRAP,
	FNA3D_TEXTUREADDRESSMODE_CLAMP,
	FNA3D_TEXTUREADDRESSMODE_MIRROR
} FNA3D_TextureAddressMode;

typedef enum FNA3D_TextureFilter
{
	FNA3D_TEXTUREFILTER_LINEAR,
	FNA3D_TEXTUREFILTER_POINT,
	FNA3D_TEXTUREFILTER_ANISOTROPIC,
	FNA3D_TEXTUREFILTER_LINEAR_MIPPOINT,
	FNA3D_TEXTUREFILTER_POINT_MIPLINEAR,
	FNA3D_TEXTUREFILTER_MINLINEAR_MAGPOINT_MIPLINEAR,
	FNA3D_TEXTUREFILTER_MINLINEAR_MAGPOINT_MIPPOINT,
	FNA3D_TEXTUREFILTER_MINPOINT_MAGLINEAR_MIPLINEAR,
	FNA3D_TEXTUREFILTER_MINPOINT_MAGLINEAR_MIPPOINT
} FNA3D_TextureFilter;

typedef enum FNA3D_VertexElementFormat
{
	FNA3D_VERTEXELEMENTFORMAT_SINGLE,
	FNA3D_VERTEXELEMENTFORMAT_VECTOR2,
	FNA3D_VERTEXELEMENTFORMAT_VECTOR3,
	FNA3D_VERTEXELEMENTFORMAT_VECTOR4,
	FNA3D_VERTEXELEMENTFORMAT_COLOR,
	FNA3D_VERTEXELEMENTFORMAT_BYTE4,
	FNA3D_VERTEXELEMENTFORMAT_SHORT2,
	FNA3D_VERTEXELEMENTFORMAT_SHORT4,
	FNA3D_VERTEXELEMENTFORMAT_NORMALIZEDSHORT2,
	FNA3D_VERTEXELEMENTFORMAT_NORMALIZEDSHORT4,
	FNA3D_VERTEXELEMENTFORMAT_HALFVECTOR2,
	FNA3D_VERTEXELEMENTFORMAT_HALFVECTOR4
} FNA3D_VertexElementFormat;

typedef enum FNA3D_VertexElementUsage
{
	FNA3D_VERTEXELEMENTUSAGE_POSITION,
	FNA3D_VERTEXELEMENTUSAGE_COLOR,
	FNA3D_VERTEXELEMENTUSAGE_TEXTURECOORDINATE,
	FNA3D_VERTEXELEMENTUSAGE_NORMAL,
	FNA3D_VERTEXELEMENTUSAGE_BINORMAL,
	FNA3D_VERTEXELEMENTUSAGE_TANGENT,
	FNA3D_VERTEXELEMENTUSAGE_BLENDINDICES,
	FNA3D_VERTEXELEMENTUSAGE_BLENDWEIGHT,
	FNA3D_VERTEXELEMENTUSAGE_DEPTH,
	FNA3D_VERTEXELEMENTUSAGE_FOG,
	FNA3D_VERTEXELEMENTUSAGE_POINTSIZE,
	FNA3D_VERTEXELEMENTUSAGE_SAMPLE,
	FNA3D_VERTEXELEMENTUSAGE_TESSELATEFACTOR
} FNA3D_VertexElementUsage;

/* Structures, should match XNA 4.0 */

typedef struct FNA3D_Color
{
	uint8_t r;
	uint8_t g;
	uint8_t b;
	uint8_t a;
} FNA3D_Color;

typedef struct FNA3D_Rect
{
	int32_t x;
	int32_t y;
	int32_t w;
	int32_t h;
} FNA3D_Rect;

typedef struct FNA3D_Vec4
{
	float x;
	float y;
	float z;
	float w;
} FNA3D_Vec4;

typedef struct FNA3D_Viewport
{
	int32_t x;
	int32_t y;
	int32_t w;
	int32_t h;
	float minDepth;
	float maxDepth;
} FNA3D_Viewport;

typedef struct FNA3D_PresentationParameters
{
	int32_t backBufferWidth;
	int32_t backBufferHeight;
	FNA3D_SurfaceFormat backBufferFormat;
	int32_t multiSampleCount;
	void* deviceWindowHandle;
	uint8_t isFullScreen;
	FNA3D_DepthFormat depthStencilFormat;
	FNA3D_PresentInterval presentationInterval;
	FNA3D_DisplayOrientation displayOrientation;
	FNA3D_RenderTargetUsage renderTargetUsage;
} FNA3D_PresentationParameters;

typedef struct FNA3D_BlendState
{
	FNA3D_Blend colorSourceBlend;
	FNA3D_Blend colorDestinationBlend;
	FNA3D_BlendFunction colorBlendFunction;
	FNA3D_Blend alphaSourceBlend;
	FNA3D_Blend alphaDestinationBlend;
	FNA3D_BlendFunction alphaBlendFunction;
	FNA3D_ColorWriteChannels colorWriteEnable;
	FNA3D_ColorWriteChannels colorWriteEnable1;
	FNA3D_ColorWriteChannels colorWriteEnable2;
	FNA3D_ColorWriteChannels colorWriteEnable3;
	FNA3D_Color blendFactor;
	int32_t multiSampleMask;
} FNA3D_BlendState;

typedef struct FNA3D_DepthStencilState
{
	uint8_t depthBufferEnable;
	uint8_t depthBufferWriteEnable;
	FNA3D_CompareFunction depthBufferFunction;
	uint8_t stencilEnable;
	int32_t stencilMask;
	int32_t stencilWriteMask;
	uint8_t twoSidedStencilMode;
	FNA3D_StencilOperation stencilFail;
	FNA3D_StencilOperation stencilDepthBufferFail;
	FNA3D_StencilOperation stencilPass;
	FNA3D_CompareFunction stencilFunction;
	FNA3D_StencilOperation ccwStencilFail;
	FNA3D_StencilOperation ccwStencilDepthBufferFail;
	FNA3D_StencilOperation ccwStencilPass;
	FNA3D_CompareFunction ccwStencilFunction;
	int32_t referenceStencil;
} FNA3D_DepthStencilState;

typedef struct FNA3D_RasterizerState
{
	FNA3D_FillMode fillMode;
	FNA3D_CullMode cullMode;
	float depthBias;
	float slopeScaleDepthBias;
	uint8_t scissorTestEnable;
	uint8_t multiSampleAntiAlias;
} FNA3D_RasterizerState;

typedef struct FNA3D_SamplerState
{
	FNA3D_TextureFilter filter;
	FNA3D_TextureAddressMode addressU;
	FNA3D_TextureAddressMode addressV;
	FNA3D_TextureAddressMode addressW;
	float mipMapLevelOfDetailBias;
	int32_t maxAnisotropy;
	int32_t maxMipLevel;
} FNA3D_SamplerState;

typedef struct FNA3D_VertexElement
{
	int32_t offset;
	FNA3D_VertexElementFormat vertexElementFormat;
	FNA3D_VertexElementUsage vertexElementUsage;
	int32_t usageIndex;
} FNA3D_VertexElement;

typedef struct FNA3D_VertexDeclaration
{
	int32_t vertexStride;
	int32_t elementCount;
	FNA3D_VertexElement *elements;
} FNA3D_VertexDeclaration;

typedef struct FNA3D_VertexBufferBinding
{
	FNA3D_Buffer *vertexBuffer;
	FNA3D_VertexDeclaration vertexDeclaration;
	int32_t vertexOffset;
	int32_t instanceFrequency;
} FNA3D_VertexBufferBinding;

typedef struct FNA3D_RenderTargetBinding
{
	/* Basic target information */
	#define FNA3D_RENDERTARGET_TYPE_2D 0
	#define FNA3D_RENDERTARGET_TYPE_CUBE 1
	uint8_t type;
	FNA3DNAMELESS union
	{
		struct
		{
			int32_t width;
			int32_t height;
		} twod;
		struct
		{
			int32_t size;
			FNA3D_CubeMapFace face;
		} cube;
	};

	/* If this is >1, you MUST call ResolveTarget after rendering! */
	int32_t levelCount;

	/* If this is >1, colorBuffer MUST be non-NULL! */
	int32_t multiSampleCount;

	/* Destination texture. This MUST be non-NULL! */
	FNA3D_Texture *texture;

	/* If this is non-NULL, you MUST call ResolveTarget after rendering! */
	FNA3D_Renderbuffer *colorBuffer;
} FNA3D_RenderTargetBinding;

/* Version API */

#define FNA3D_ABI_VERSION	 0
#define FNA3D_MAJOR_VERSION	26
#define FNA3D_MINOR_VERSION	 3
#define FNA3D_PATCH_VERSION	 0

#define FNA3D_COMPILED_VERSION ( \
	(FNA3D_ABI_VERSION * 100 * 100 * 100) + \
	(FNA3D_MAJOR_VERSION * 100 * 100) + \
	(FNA3D_MINOR_VERSION * 100) + \
	(FNA3D_PATCH_VERSION) \
)

FNA3DAPI uint32_t FNA3D_LinkedVersion(void);

/* Functions */

/* Logging */

typedef void (FNA3DCALL * FNA3D_LogFunc)(const char *msg);

/* Reroutes FNA3D's logging to custom logging functions.
 *
 * info:	Basic logs that might be useful to have stored for support.
 * warn:	Something went wrong, but it's really just annoying, not fatal.
 * error:	You better have this stored somewhere because it's crashing now!
 */
FNA3DAPI void FNA3D_HookLogFunctions(
	FNA3D_LogFunc info,
	FNA3D_LogFunc warn,
	FNA3D_LogFunc error
);

/* Init/Quit */

/* Selects the most suitable graphics rendering backend for the system, then
 * provides the application with context-sensitive bitflags for the OS window.
 *
 * Returns a bitflag value, typically SDL_WindowFlags masks.
 */
FNA3DAPI uint32_t FNA3D_PrepareWindowAttributes(void);

/* After your device is created, call this to check for high-DPI support.
 *
 * NOTE: This call is now deprecated, in favor of SDL_GetWindowSizeInPixels!
 *
 * Note that this will NOT work if it's called after the window is created but
 * before the device! Not all platforms create drawable surfaces at the same
 * time as the window!
 *
 * window:	The OS window handle, typically an SDL_Window*.
 * w:		Filled with the width of the window's drawable canvas.
 * h:		Filled with the height of the window's drawable canvas.
 */
FNA3DDEPRECATED("Use SDL_GetWindowSizeInPixels instead!")
FNA3DAPI void FNA3D_GetDrawableSize(void* window, int32_t *w, int32_t *h);

/* Creates a rendering context for use on the calling thread.
 *
 * presentationParameters:	The initial device/backbuffer settings.
 * debugMode:			Enable debugging and backend validation features
 *				at the cost of reduced overall performance.
 *
 * Returns a device ready for use. Be sure to only call device functions from
 * the thread that it was created on!
 */
FNA3DAPI FNA3D_Device* FNA3D_CreateDevice(
	FNA3D_PresentationParameters *presentationParameters,
	uint8_t debugMode
);

/* Destroys a rendering context previously returned by FNA3D_CreateDevice. */
FNA3DAPI void FNA3D_DestroyDevice(FNA3D_Device *device);

/* Presentation */

/* Presents the backbuffer to the window.
 *
 * sourceRectangle:		The region of the buffer to present (or NULL).
 * destinationRectangle:	The region of the window to update (or NULL).
 * overrideWindowHandle:	The OS window handle (not really "overridden").
 */
FNA3DAPI void FNA3D_SwapBuffers(
	FNA3D_Device *device,
	FNA3D_Rect *sourceRectangle,
	FNA3D_Rect *destinationRectangle,
	void* overrideWindowHandle
);

/* Drawing */

/* Clears the active draw buffers of any previous contents.
 *
 * options:	Bitflags to specify color/depth/stencil buffers for clearing.
 * color:	The new value of the cleared color buffer. It is STRONGLY
 *		recommended to use 0.0f and 1.0f for all color channels!
 * depth:	The new value of the cleared depth buffer.
 * stencil:	The new value of the cleared stencil buffer.
 */
FNA3DAPI void FNA3D_Clear(
	FNA3D_Device *device,
	FNA3D_ClearOptions options,
	FNA3D_Vec4 *color,
	float depth,
	int32_t stencil
);

/* Draws data from vertex/index buffers.
 *
 * primitiveType:	The primitive topology of the vertex data.
 * baseVertex:		The starting offset to read from the vertex buffer.
 * minVertexIndex:	The lowest index value expected from the index buffer.
 * numVertices:		The highest offset expected from the index buffer.
 * startIndex:		The starting offset to read from the index buffer.
 * primitiveCount:	The number of primitives to draw.
 * indices:		The index buffer to bind for this draw call.
 * indexElementSize:	The size of the index type for this index buffer.
 */
FNA3DAPI void FNA3D_DrawIndexedPrimitives(
	FNA3D_Device *device,
	FNA3D_PrimitiveType primitiveType,
	int32_t baseVertex,
	int32_t minVertexIndex,
	int32_t numVertices,
	int32_t startIndex,
	int32_t primitiveCount,
	FNA3D_Buffer *indices,
	FNA3D_IndexElementSize indexElementSize
);

/* Draws data from vertex/index buffers with instancing enabled.
 *
 * primitiveType:	The primitive topology of the vertex data.
 * baseVertex:		The starting offset to read from the vertex buffer.
 * minVertexIndex:	The lowest index value expected from the index buffer.
 * numVertices:		The highest offset expected from the index buffer.
 * startIndex:		The starting offset to read from the index buffer.
 * primitiveCount:	The number of primitives to draw.
 * instanceCount:	The number of instances that will be drawn.
 * indices:		The index buffer to bind for this draw call.
 * indexElementSize:	The size of the index type for this index buffer.
 */
FNA3DAPI void FNA3D_DrawInstancedPrimitives(
	FNA3D_Device *device,
	FNA3D_PrimitiveType primitiveType,
	int32_t baseVertex,
	int32_t minVertexIndex,
	int32_t numVertices,
	int32_t startIndex,
	int32_t primitiveCount,
	int32_t instanceCount,
	FNA3D_Buffer *indices,
	FNA3D_IndexElementSize indexElementSize
);

/* Draws data from vertex buffers.
 * primitiveType:	The primitive topology of the vertex data.
 * vertexStart:		The starting offset to read from the vertex buffer.
 * primitiveCount:	The number of primitives to draw.
 */
FNA3DAPI void FNA3D_DrawPrimitives(
	FNA3D_Device *device,
	FNA3D_PrimitiveType primitiveType,
	int32_t vertexStart,
	int32_t primitiveCount
);

/* Mutable Render States */

/* Sets the view dimensions for rendering, relative to the active render target.
 * It is required to call this at least once after calling SetRenderTargets, as
 * the renderer may need to adjust these dimensions to fit the backend's
 * potentially goofy coordinate systems.
 *
 * viewport: The new view dimensions for future draw calls.
 */
FNA3DAPI void FNA3D_SetViewport(FNA3D_Device *device, FNA3D_Viewport *viewport);

/* Sets the scissor box for rendering, relative to the active render target.
 * It is required to call this at least once after calling SetRenderTargets, as
 * the renderer may need to adjust these dimensions to fit the backend's
 * potentially goofy coordinate systems.
 *
 * scissor: The new scissor box for future draw calls.
 */
FNA3DAPI void FNA3D_SetScissorRect(FNA3D_Device *device, FNA3D_Rect *scissor);

/* Gets the blending factor used for current draw calls.
 *
 * blendFactor: Filled with color being used as the device blend factor.
 */
FNA3DAPI void FNA3D_GetBlendFactor(
	FNA3D_Device *device,
	FNA3D_Color *blendFactor
);

/* Sets the blending factor used for future draw calls.
 *
 * blendFactor: The color to use as the device blend factor.
 */
FNA3DAPI void FNA3D_SetBlendFactor(
	FNA3D_Device *device,
	FNA3D_Color *blendFactor
);

/* Gets the mask from which multisample fragment data is sampled from.
 *
 * Returns the coverage mask used to determine sample locations.
 */
FNA3DAPI int32_t FNA3D_GetMultiSampleMask(FNA3D_Device *device);

/* Sets the mask with which multisample fragment data will be sampled from.
 *
 * mask: The new coverage mask to use for determining sample locations.
 */
FNA3DAPI void FNA3D_SetMultiSampleMask(FNA3D_Device *device, int32_t mask);

/* Gets the reference value used for certain types of stencil testing.
 *
 * Returns the stencil reference value.
 */
FNA3DAPI int32_t FNA3D_GetReferenceStencil(FNA3D_Device *device);

/* Sets the reference value used for certain types of stencil testing.
 *
 * ref: The new stencil reference value.
 */
FNA3DAPI void FNA3D_SetReferenceStencil(FNA3D_Device *device, int32_t ref);

/* Immutable Render States */

/* Applies a blending state to use for future draw calls. This only needs to be
 * called when the state actually changes. Redundant calls may negatively affect
 * performance!
 *
 * blendState: The new parameters to use for color blending.
 */
FNA3DAPI void FNA3D_SetBlendState(
	FNA3D_Device *device,
	FNA3D_BlendState *blendState
);

/* Applies depth/stencil states to use for future draw calls. This only needs to
 * be called when the states actually change. Redundant calls may negatively
 * affect performance!
 *
 * depthStencilState: The new parameters to use for depth/stencil work.
 */
FNA3DAPI void FNA3D_SetDepthStencilState(
	FNA3D_Device *device,
	FNA3D_DepthStencilState *depthStencilState
);

/* Applies the rasterizing state to use for future draw calls.
 * It's generally a good idea to call this for each draw call, but if you really
 * wanted to you could try reducing it to when the state changes and when the
 * render target state changes.
 *
 * rasterizerState: The new parameters to use for rasterization work.
 */
FNA3DAPI void FNA3D_ApplyRasterizerState(
	FNA3D_Device *device,
	FNA3D_RasterizerState *rasterizerState
);

/* Updates a sampler slot with new texture/sampler data for future draw calls.
 * This should only be called on slots that have modified texture/sampler state.
 * Redundant calls may negatively affect performance!
 *
 * index:	The sampler slot to update.
 * texture:	The texture bound to this sampler.
 * sampler:	The new parameters to use for this slot's texture sampling.
 */
FNA3DAPI void FNA3D_VerifySampler(
	FNA3D_Device *device,
	int32_t index,
	FNA3D_Texture *texture,
	FNA3D_SamplerState *sampler
);

/* Updates a vertex sampler slot with new texture/sampler data for future draw
 * calls. This should only be called on slots that have modified texture/sampler
 * state. Redundant calls may negatively affect performance!
 *
 * index:	The vertex sampler slot to update.
 * texture:	The texture bound to this sampler.
 * sampler:	The new parameters to use for this slot's texture sampling.
 */
FNA3DAPI void FNA3D_VerifyVertexSampler(
	FNA3D_Device *device,
	int32_t index,
	FNA3D_Texture *texture,
	FNA3D_SamplerState *sampler
);

/* Updates the vertex attribute state to read from a set of vertex buffers. This
 * should be the very last thing you call before making a draw call, as this
 * does all the final prep work for the shader program before it's ready to use.
 *
 * bindings:		The vertex buffers and their attribute data.
 * numBindings:		The number of elements in the bindings array.
 * bindingsUpdated:	If the bindings array hasn't changed since the last
 *			update, this can be false. We'll only update the shader
 *			state, updating vertex attribute data only if we 100%
 *			have to, for a tiny performance improvement.
 * baseVertex:		This should be the same as the `baseVertex` parameter
 *			from your Draw*Primitives call, if applicable. Not every
 *			rendering backend has native base vertex support, so we
 *			work around it by passing this here.
 */
FNA3DAPI void FNA3D_ApplyVertexBufferBindings(
	FNA3D_Device *device,
	FNA3D_VertexBufferBinding *bindings,
	int32_t numBindings,
	uint8_t bindingsUpdated,
	int32_t baseVertex
);

/* Render Targets */

/* Sets the color/depth/stencil buffers to write future draw calls to.
 *
 * renderTargets:	The targets to write to, or NULL for the backbuffer.
 * numRenderTargets:	The size of the renderTargets array (can be 0).
 * depthStencilBuffer:	The depth/stencil renderbuffer (can be NULL).
 * depthFormat:		The format of the depth/stencil renderbuffer.
 * preserveTargetContents:
 * 			Set this to 1 to store the color/depth/stencil contents
 * 			for future use. Most of the time you'll want to
 * 			keep this at 0 to not waste GPU bandwidth.
 */
FNA3DAPI void FNA3D_SetRenderTargets(
	FNA3D_Device *device,
	FNA3D_RenderTargetBinding *renderTargets,
	int32_t numRenderTargets,
	FNA3D_Renderbuffer *depthStencilBuffer,
	FNA3D_DepthFormat depthFormat,
	uint8_t preserveTargetContents
);

/* After unsetting a render target, call this to resolve multisample targets or
 * generate mipmap data for the final texture.
 *
 * target: The render target to resolve once rendering is complete.
 */
FNA3DAPI void FNA3D_ResolveTarget(
	FNA3D_Device *device,
	FNA3D_RenderTargetBinding *target
);

/* Backbuffer Functions */

/* After modifying the OS window state, call this to reset the backbuffer to
 * match your window changes.
 *
 * presentationParameters: The new settings for the backbuffer.
 */
FNA3DAPI void FNA3D_ResetBackbuffer(
	FNA3D_Device *device,
	FNA3D_PresentationParameters *presentationParameters
);

/* Read the backbuffer's contents directly into client memory. This function is
 * basically one giant CPU/GPU sync point, do NOT ever call this during any
 * performance-critical situation! Just use it for screenshots.
 *
 * x:		The x offset of the backbuffer region to read.
 * y:		The y offset of the backbuffer region to read.
 * w:		The width of the backbuffer region to read.
 * h:		The height of the backbuffer region to read.
 * data:	The pointer to read the backbuffer data into.
 * dataLength:	The size of the backbuffer data in bytes.
 */
FNA3DAPI void FNA3D_ReadBackbuffer(
	FNA3D_Device *device,
	int32_t x,
	int32_t y,
	int32_t w,
	int32_t h,
	void* data,
	int32_t dataLength
);

/* Gets the current dimensions of the backbuffer.
 *
 * w:	Filled with the backbuffer's width.
 * h:	Filled with the backbuffer's height.
 */
FNA3DAPI void FNA3D_GetBackbufferSize(
	FNA3D_Device *device,
	int32_t *w,
	int32_t *h
);

/* Gets the current pixel format of the backbuffer.
 *
 * Returns the backbuffer's pixel format.
 */
FNA3DAPI FNA3D_SurfaceFormat FNA3D_GetBackbufferSurfaceFormat(
	FNA3D_Device *device
);

/* Gets the format of the backbuffer's depth/stencil buffer.
 *
 * Returns the backbuffer's depth/stencil format.
 */
FNA3DAPI FNA3D_DepthFormat FNA3D_GetBackbufferDepthFormat(FNA3D_Device *device);

/* Gets the multisample sample count of the backbuffer.
 *
 * Returns the backbuffer's multisample sample count.
 */
FNA3DAPI int32_t FNA3D_GetBackbufferMultiSampleCount(FNA3D_Device *device);

/* Textures */

/* Creates a 2D texture to be applied to VerifySampler.
 *
 * format:		The pixel format of the texture data.
 * width:		The width of the texture image.
 * height:		The height of the texture image.
 * levelCount:		The number of mipmap levels to allocate.
 * isRenderTarget:	Set this to 1 when using this with SetRenderTargets.
 *
 * Returns an allocated FNA3D_Texture* object. Note that the contents of the
 * texture are undefined, so you must call SetData at least once before drawing!
 */
FNA3DAPI FNA3D_Texture* FNA3D_CreateTexture2D(
	FNA3D_Device *device,
	FNA3D_SurfaceFormat format,
	int32_t width,
	int32_t height,
	int32_t levelCount,
	uint8_t isRenderTarget
);

/* Creates a 3D texture to be applied to VerifySampler.
 *
 * format:		The pixel format of the texture data.
 * width:		The width of the texture image.
 * height:		The height of the texture image.
 * depth:		The depth of the texture image.
 * levelCount:		The number of mipmap levels to allocate.
 *
 * Returns an allocated FNA3D_Texture* object. Note that the contents of the
 * texture are undefined, so you must call SetData at least once before drawing!
 */
FNA3DAPI FNA3D_Texture* FNA3D_CreateTexture3D(
	FNA3D_Device *device,
	FNA3D_SurfaceFormat format,
	int32_t width,
	int32_t height,
	int32_t depth,
	int32_t levelCount
);

/* Creates a texture cube to be applied to VerifySampler.
 *
 * format:		The pixel format of the texture data.
 * size:		The length of a single edge of the texture cube.
 * levelCount:		The number of mipmap levels to allocate.
 * isRenderTarget:	Set this to 1 when using this with SetRenderTargets.
 *
 * Returns an allocated FNA3D_Texture* object. Note that the contents of the
 * texture are undefined, so you must call SetData at least once before drawing!
 */
FNA3DAPI FNA3D_Texture* FNA3D_CreateTextureCube(
	FNA3D_Device *device,
	FNA3D_SurfaceFormat format,
	int32_t size,
	int32_t levelCount,
	uint8_t isRenderTarget
);

/* Sends a texture to be destroyed by the renderer. Note that we call it
 * "AddDispose" because it may not be immediately destroyed by the renderer if
 * this is not called from the main thread (for example, if a garbage collector
 * deletes the resource instead of the programmer).
 *
 * texture: The FNA3D_Texture to be destroyed.
 */
FNA3DAPI void FNA3D_AddDisposeTexture(
	FNA3D_Device *device,
	FNA3D_Texture *texture
);

/* Uploads image data to a 2D texture object.
 *
 * texture:	The texture to be updated.
 * x:		The x offset of the subregion being updated.
 * y:		The y offset of the subregion being updated.
 * w:		The width of the subregion being updated.
 * h:		The height of the subregion being updated.
 * level:	The mipmap level being updated.
 * data:	A pointer to the image data.
 * dataLength:	The size of the image data in bytes.
 */
FNA3DAPI void FNA3D_SetTextureData2D(
	FNA3D_Device *device,
	FNA3D_Texture *texture,
	int32_t x,
	int32_t y,
	int32_t w,
	int32_t h,
	int32_t level,
	void* data,
	int32_t dataLength
);

/* Uploads image data to a 3D texture object.
 *
 * texture:	The texture to be updated.
 * x:		The x offset of the subregion being updated.
 * y:		The y offset of the subregion being updated.
 * z:		The z offset of the subregion being updated.
 * w:		The width of the subregion being updated.
 * h:		The height of the subregion being updated.
 * d:		The depth of the subregion being updated.
 * level:	The mipmap level being updated.
 * data:	A pointer to the image data.
 * dataLength:	The size of the image data in bytes.
 */
FNA3DAPI void FNA3D_SetTextureData3D(
	FNA3D_Device *device,
	FNA3D_Texture *texture,
	int32_t x,
	int32_t y,
	int32_t z,
	int32_t w,
	int32_t h,
	int32_t d,
	int32_t level,
	void* data,
	int32_t dataLength
);

/* Uploads image data to a single face of a texture cube object.
 *
 * texture:	The texture to be updated.
 * x:		The x offset of the subregion being updated.
 * y:		The y offset of the subregion being updated.
 * w:		The width of the subregion being updated.
 * h:		The height of the subregion being updated.
 * cubeMapFace:	The face of the cube being updated.
 * level:	The mipmap level being updated.
 * data:	A pointer to the image data.
 * dataLength:	The size of the image data in bytes.
 */
FNA3DAPI void FNA3D_SetTextureDataCube(
	FNA3D_Device *device,
	FNA3D_Texture *texture,
	int32_t x,
	int32_t y,
	int32_t w,
	int32_t h,
	FNA3D_CubeMapFace cubeMapFace,
	int32_t level,
	void* data,
	int32_t dataLength
);

/* Uploads YUV image data to three ALPHA8 texture objects.
 *
 * y:		The texture storing the Y data.
 * u:		The texture storing the U (Cb) data.
 * v:		The texture storing the V (Cr) data.
 * yWidth:	The width of the Y plane.
 * yHeight:	The height of the Y plane.
 * uvWidth:	The width of the U/V planes.
 * uvHeight:	The height of the U/V planes.
 * data:	A pointer to the raw YUV image data.
 * dataLength:	The size of the image data in bytes.
 */
FNA3DAPI void FNA3D_SetTextureDataYUV(
	FNA3D_Device *device,
	FNA3D_Texture *y,
	FNA3D_Texture *u,
	FNA3D_Texture *v,
	int32_t yWidth,
	int32_t yHeight,
	int32_t uvWidth,
	int32_t uvHeight,
	void* data,
	int32_t dataLength
);

/* Pulls image data from a 2D texture into client memory. Like any GetData,
 * this is generally asking for a massive CPU/GPU sync point, don't call this
 * unless there's absolutely no other way to use the image data!
 *
 * texture:	The texture object being read.
 * x:		The x offset of the subregion being read.
 * y:		The y offset of the subregion being read.
 * w:		The width of the subregion being read.
 * h:		The height of the subregion being read.
 * level:	The mipmap level being read.
 * data:	The pointer being filled with the image data.
 * dataLength:	The size of the image data in bytes.
 */
FNA3DAPI void FNA3D_GetTextureData2D(
	FNA3D_Device *device,
	FNA3D_Texture *texture,
	int32_t x,
	int32_t y,
	int32_t w,
	int32_t h,
	int32_t level,
	void* data,
	int32_t dataLength
);

/* Pulls image data from a 3D texture into client memory. Like any GetData,
 * this is generally asking for a massive CPU/GPU sync point, don't call this
 * unless there's absolutely no other way to use the image data!
 *
 * texture:	The texture object being read.
 * x:		The x offset of the subregion being read.
 * y:		The y offset of the subregion being read.
 * z:		The z offset of the subregion being read.
 * w:		The width of the subregion being read.
 * h:		The height of the subregion being read.
 * d:		The depth of the subregion being read.
 * level:	The mipmap level being read.
 * data:	The pointer being filled with the image data.
 * dataLength:	The size of the image data in bytes.
 */
FNA3DAPI void FNA3D_GetTextureData3D(
	FNA3D_Device *device,
	FNA3D_Texture *texture,
	int32_t x,
	int32_t y,
	int32_t z,
	int32_t w,
	int32_t h,
	int32_t d,
	int32_t level,
	void* data,
	int32_t dataLength
);

/* Pulls image data from a single face of a texture cube object into client
 * memory. Like any GetData, this is generally asking for a massive CPU/GPU sync
 * point, don't call this unless there's absolutely no other way to use the
 * image data!
 *
 * texture:	The texture object being read.
 * x:		The x offset of the subregion being read.
 * y:		The y offset of the subregion being read.
 * w:		The width of the subregion being read.
 * h:		The height of the subregion being read.
 * cubeMapFace:	The face of the cube being read.
 * level:	The mipmap level being read.
 * data:	The pointer being filled with the image data.
 * dataLength:	The size of the image data in bytes.
 */
FNA3DAPI void FNA3D_GetTextureDataCube(
	FNA3D_Device *device,
	FNA3D_Texture *texture,
	int32_t x,
	int32_t y,
	int32_t w,
	int32_t h,
	FNA3D_CubeMapFace cubeMapFace,
	int32_t level,
	void* data,
	int32_t dataLength
);

/* Renderbuffers */

/* Creates a color buffer to be used by SetRenderTargets/ResolveTarget.
 *
 * width:		The width of the color buffer.
 * height:		The height of the color buffer.
 * format:		The pixel format of the color buffer.
 * multiSampleCount:	The MSAA value for the color buffer.
 * texture:		The texture that this buffer will be resolving to.
 *
 * Returns a color FNA3D_Renderbuffer object.
 */
FNA3DAPI FNA3D_Renderbuffer* FNA3D_GenColorRenderbuffer(
	FNA3D_Device *device,
	int32_t width,
	int32_t height,
	FNA3D_SurfaceFormat format,
	int32_t multiSampleCount,
	FNA3D_Texture *texture
);

/* Creates a depth/stencil buffer to be used by SetRenderTargets.
 *
 * width:		The width of the depth/stencil buffer.
 * height:		The height of the depth/stencil buffer.
 * format:		The storage format of the depth/stencil buffer.
 * multiSampleCount:	The MSAA value for the depth/stencil buffer.
 *
 * Returns a depth/stencil FNA3D_Renderbuffer object.
 */
FNA3DAPI FNA3D_Renderbuffer* FNA3D_GenDepthStencilRenderbuffer(
	FNA3D_Device *device,
	int32_t width,
	int32_t height,
	FNA3D_DepthFormat format,
	int32_t multiSampleCount
);

/* Sends a renderbuffer to be destroyed by the renderer. Note that we call it
 * "AddDispose" because it may not be immediately destroyed by the renderer if
 * this is not called from the main thread (for example, if a garbage collector
 * deletes the resource instead of the programmer).
 *
 * renderbuffer: The FNA3D_Renderbuffer to be destroyed.
 */
FNA3DAPI void FNA3D_AddDisposeRenderbuffer(
	FNA3D_Device *device,
	FNA3D_Renderbuffer *renderbuffer
);

/* Vertex Buffers */

/* Creates a vertex buffer to be used by Draw*Primitives.
 *
 * dynamic:		Set to 1 if this buffer will be updated frequently.
 * usage:		Set to WRITEONLY if you do not intend to call GetData.
 * sizeInBytes:		The length of the vertex buffer.
 *
 * Returns an allocated FNA3D_Buffer* object. Note that the contents of the
 * buffer are undefined, so you must call SetData at least once before drawing!
 */
FNA3DAPI FNA3D_Buffer* FNA3D_GenVertexBuffer(
	FNA3D_Device *device,
	uint8_t dynamic,
	FNA3D_BufferUsage usage,
	int32_t sizeInBytes
);

/* Sends a vertex buffer to be destroyed by the renderer. Note that we call it
 * "AddDispose" because it may not be immediately destroyed by the renderer if
 * this is not called from the main thread (for example, if a garbage collector
 * deletes the resource instead of the programmer).
 *
 * buffer: The FNA3D_Buffer to be destroyed.
 */
FNA3DAPI void FNA3D_AddDisposeVertexBuffer(
	FNA3D_Device *device,
	FNA3D_Buffer *buffer
);

/* Sets a region of the vertex buffer with client data.
 *
 * buffer:		The vertex buffer to be updated.
 * offsetInBytes:	The starting offset of the buffer to write into.
 * data:		The client data to write into the buffer.
 * elementCount:	The number of elements from the client buffer to write.
 * elementSizeInBytes:	The size of each element in the client buffer.
 * vertexStride:	Try to set this to the same value as elementSizeInBytes.
 *			XNA has this ridiculous thing where if vertexStride is
 *			greater than elementSizeInBytes, it tries to do partial
 *			updates of each vertex with the client data's smaller
 *			elements. It's... just, really bad. Don't try to use it.
 *			You probably just want '1' for both parameters, so that
 *			elementCount can just be the buffer length in bytes.
 * options:		Try not to call NONE if this is a dynamic buffer!
 */
FNA3DAPI void FNA3D_SetVertexBufferData(
	FNA3D_Device *device,
	FNA3D_Buffer *buffer,
	int32_t offsetInBytes,
	void* data,
	int32_t elementCount,
	int32_t elementSizeInBytes,
	int32_t vertexStride,
	FNA3D_SetDataOptions options
);

/* Pulls data from a region of the vertex buffer into a client pointer.
 *
 * buffer:		The vertex buffer to be read from.
 * offsetInBytes:	The starting offset of the buffer to write into.
 * data:		The client data to write into from the buffer.
 * elementCount:	The number of elements from the client buffer to read.
 * elementSizeInBytes:	The size of each element in the client buffer.
 * vertexStride:	Try to set this to the same value as elementSizeInBytes.
 *			XNA has this ridiculous thing where if vertexStride is
 *			greater than elementSizeInBytes, it tries to do partial
 *			updates of each vertex with the client data's smaller
 *			elements. It's... just, really bad. Don't try to use it.
 *			You probably just want '1' for both parameters, so that
 *			elementCount can just be the buffer length in bytes.
 */
FNA3DAPI void FNA3D_GetVertexBufferData(
	FNA3D_Device *device,
	FNA3D_Buffer *buffer,
	int32_t offsetInBytes,
	void* data,
	int32_t elementCount,
	int32_t elementSizeInBytes,
	int32_t vertexStride
);

/* Index Buffers */

/* Creates an index buffer to be used by Draw*Primitives.
 *
 * dynamic:		Set to 1 if this buffer will be updated frequently.
 * usage:		Set to WRITEONLY if you do not intend to call GetData.
 * sizeInBytes:		The length of the vertex buffer.
 *
 * Returns an allocated FNA3D_Buffer* object. Note that the contents of the
 * buffer are undefined, so you must call SetData at least once before drawing!
 */
FNA3DAPI FNA3D_Buffer* FNA3D_GenIndexBuffer(
	FNA3D_Device *device,
	uint8_t dynamic,
	FNA3D_BufferUsage usage,
	int32_t sizeInBytes
);

/* Sends an index buffer to be destroyed by the renderer. Note that we call it
 * "AddDispose" because it may not be immediately destroyed by the renderer if
 * this is not called from the main thread (for example, if a garbage collector
 * deletes the resource instead of the programmer).
 *
 * buffer: The FNA3D_Buffer to be destroyed.
 */
FNA3DAPI void FNA3D_AddDisposeIndexBuffer(
	FNA3D_Device *device,
	FNA3D_Buffer *buffer
);

/* Sets a region of the index buffer with client data.
 *
 * buffer:		The index buffer to be updated.
 * offsetInBytes:	The starting offset of the buffer to write into.
 * data:		The client data to write into the buffer.
 * dataLength:		The size (in bytes) of the client data.
 * options:		Try not to call NONE if this is a dynamic buffer!
 */
FNA3DAPI void FNA3D_SetIndexBufferData(
	FNA3D_Device *device,
	FNA3D_Buffer *buffer,
	int32_t offsetInBytes,
	void* data,
	int32_t dataLength,
	FNA3D_SetDataOptions options
);

/* Pulls data from a region of the index buffer into a client pointer.
 *
 * buffer:		The index buffer to be read from.
 * offsetInBytes:	The starting offset of the buffer to read from.
 * data:		The pointer to read buffer data into.
 * dataLength:		The size (in bytes) of the client data.
 */
FNA3DAPI void FNA3D_GetIndexBufferData(
	FNA3D_Device *device,
	FNA3D_Buffer *buffer,
	int32_t offsetInBytes,
	void* data,
	int32_t dataLength
);

/* Effects */

/* When using this API, be sure to include mojoshader.h! */
#ifndef _INCL_MOJOSHADER_H_
typedef struct MOJOSHADER_effect MOJOSHADER_effect;
typedef struct MOJOSHADER_effectTechnique MOJOSHADER_effectTechnique;
typedef struct MOJOSHADER_effectStateChanges MOJOSHADER_effectStateChanges;
#endif /* _INCL_MOJOSHADER_H_ */

/* Parses and compiles a Direct3D 9 Effects Framework binary.
 *
 * effectCode:		The D3D9 Effect binary blob.
 * effectCodeLength:	The size (in bytes) of the blob.
 * effect:		Filled with the compiled FNA3D_Effect*.
 * effectData:		Filled with the parsed Effect Framework data. This
 *			pointer is valid until the effect is disposed.
 */
FNA3DAPI void FNA3D_CreateEffect(
	FNA3D_Device *device,
	uint8_t *effectCode,
	uint32_t effectCodeLength,
	FNA3D_Effect **effect,
	MOJOSHADER_effect **effectData
);

/* Copies a compiled Effect, including its current technique/parameter data.
 *
 * cloneSource:	The FNA3D_Effect to copy.
 * effect:	Filled with the new compiled FNA3D_Effect*.
 * effectData:	Filled with the copied Effect Framework data.
 */
FNA3DAPI void FNA3D_CloneEffect(
	FNA3D_Device *device,
	FNA3D_Effect *cloneSource,
	FNA3D_Effect **effect,
	MOJOSHADER_effect **effectData
);

/* Sends an Effect to be destroyed by the renderer. Note that we call it
 * "AddDispose" because it may not be immediately destroyed by the renderer if
 * this is not called from the main thread (for example, if a garbage collector
 * deletes the resource instead of the programmer).
 *
 * effect: The FNA3D_Effect to be destroyed.
 */
FNA3DAPI void FNA3D_AddDisposeEffect(
	FNA3D_Device *device,
	FNA3D_Effect *effect
);

/* Sets the active technique on the Effect.
 *
 * effect:	The Effect to be modified.
 * technique:	The technique to be used by future ApplyEffect calls.
 */
FNA3DAPI void FNA3D_SetEffectTechnique(
	FNA3D_Device *device,
	FNA3D_Effect *effect,
	MOJOSHADER_effectTechnique *technique
);

/* Applies an effect pass from a given Effect, setting the active shader program
 * and committing any parameter data changes to be used by future draw calls.
 *
 * effect:		The Effect to be applied.
 * pass:		The current technique's pass index to be applied.
 * stateChanges:	Structure to be filled with any render state changes
 *			made by the Effect. This must be valid for the entire
 * 			duration that this Effect is being applied.
 */
FNA3DAPI void FNA3D_ApplyEffect(
	FNA3D_Device *device,
	FNA3D_Effect *effect,
	uint32_t pass,
	MOJOSHADER_effectStateChanges *stateChanges
);

/* Applies an effect pass from a given Effect, setting the active shader program
 * and committing and parameter data changes to be used by future draw calls,
 * while also caching the current program object to be stored once this Effect's
 * pass has been completed.
 *
 * effect:		The Effect to be applied.
 * stateChanges:	Structure to be filled with any render state changes
 *			made by the Effect. This must be valid for the entire
 * 			duration that this Effect is being applied.
 */
FNA3DAPI void FNA3D_BeginPassRestore(
	FNA3D_Device *device,
	FNA3D_Effect *effect,
	MOJOSHADER_effectStateChanges *stateChanges
);

/* Ends a pass started by BeginPassRestore, unsetting the current Effect and
 * restoring the previous shader state from before BeginPassRestore was called.
 *
 * effect: The Effect that was applied at BeginPassRestore.
 */
FNA3DAPI void FNA3D_EndPassRestore(
	FNA3D_Device *device,
	FNA3D_Effect *effect
);

/* Queries */

/* Creates an object used to run occlusion queries.
 *
 * Returns an FNA3D_Query object.
 */
FNA3DAPI FNA3D_Query* FNA3D_CreateQuery(FNA3D_Device *device);

/* Sends a query object to be destroyed by the renderer. Note that we call it
 * "AddDispose" because it may not be immediately destroyed by the renderer if
 * this is not called from the main thread (for example, if a garbage collector
 * deletes the resource instead of the programmer).
 *
 * query: The FNA3D_Query to be destroyed.
 */
FNA3DAPI void FNA3D_AddDisposeQuery(FNA3D_Device *device, FNA3D_Query *query);

/* Marks the start of when a query object should count pixels written.
 *
 * query: The FNA3D_Query to start.
 */
FNA3DAPI void FNA3D_QueryBegin(FNA3D_Device *device, FNA3D_Query *query);

/* Marks the end of when a query object should count pixels written. Note that
 * this does NOT mean the query has finished executing, you will need to poll
 * QueryComplete before checking the pixel count.
 *
 * query: The FNA3D_Query to stop.
 */
FNA3DAPI void FNA3D_QueryEnd(FNA3D_Device *device, FNA3D_Query *query);

/* Call this until the function returns 1 to safely query for pixel counts.
 *
 * query: The FNA3D_Query to sync with.
 *
 * Returns 1 when complete, 0 when still in execution.
 */
FNA3DAPI uint8_t FNA3D_QueryComplete(FNA3D_Device *device, FNA3D_Query *query);

/* Query the pixels counted between the begin/end markers set for the object.
 *
 * query: The FNA3D_Query to poll for pixel count
 *
 * Returns the pixels written during the begin/end period.
 */
FNA3DAPI int32_t FNA3D_QueryPixelCount(
	FNA3D_Device *device,
	FNA3D_Query *query
);

/* Feature Queries */

/* Returns 1 if the renderer natively supports DXT1 texture data. */
FNA3DAPI uint8_t FNA3D_SupportsDXT1(FNA3D_Device *device);

/* Returns 1 if the renderer natively supports S3TC texture data. */
FNA3DAPI uint8_t FNA3D_SupportsS3TC(FNA3D_Device *device);

/* Returns 1 if the renderer natively supports BC7 texture data. */
FNA3DAPI uint8_t FNA3D_SupportsBC7(FNA3D_Device *device);

/* Returns 1 if the renderer natively supports hardware instancing. */
FNA3DAPI uint8_t FNA3D_SupportsHardwareInstancing(FNA3D_Device *device);

/* Returns 1 if the renderer natively supports asynchronous buffer writing. */
FNA3DAPI uint8_t FNA3D_SupportsNoOverwrite(FNA3D_Device *device);

/* Returns 1 if the renderer natively supports SRGB render targets. */
FNA3DAPI uint8_t FNA3D_SupportsSRGBRenderTargets(FNA3D_Device *device);

/* Returns the number of sampler slots supported by the renderer. */
FNA3DAPI void FNA3D_GetMaxTextureSlots(
	FNA3D_Device *device,
	int32_t *textures,
	int32_t *vertexTextures
);

/* Returns the highest multisample count supported for anti-aliasing.
 *
 * format:		The pixel format to query for MSAA support.
 * multiSampleCount:	The max MSAA value requested for this format.
 *
 * Returns a hardware-specific version of min(preferred, possible).
 */
FNA3DAPI int32_t FNA3D_GetMaxMultiSampleCount(
	FNA3D_Device *device,
	FNA3D_SurfaceFormat format,
	int32_t multiSampleCount
);

/* Debugging */

/* Sets an arbitrary string constant to be stored in a rendering API trace,
 * useful for labeling call streams for debugging purposes.
 *
 * text: The string constant to mark in the API call stream.
 */
FNA3DAPI void FNA3D_SetStringMarker(FNA3D_Device *device, const char *text);

/* Sets an arbitrary string constant to be stored in a rendering API trace,
 * useful for labeling textures for debugging purposes.
 *
 * texture: The texture to attach the name to.
 * text: The string constant to mark as the name of the texture.
 */
FNA3DAPI void FNA3D_SetTextureName(FNA3D_Device *device, FNA3D_Texture *texture, const char *text);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* FNA3D_H */

/* vim: set noexpandtab shiftwidth=8 tabstop=8: */
