//******************************************************************************
//
// OGL Utility / OGLPrimitive
//
// プリミティブ描画クラス
//
// Copyright (C) 2010-2022 WADA Masashi. All Rights Reserved.
//
//******************************************************************************

// MEMO:
// 頂点バッファとインデックスバッファの操作をラップするクラス。

#import "OGLTypes.h"
#import "OGLDevice.h"
#import "OGLTransMatrix.h"
#import "OGLTexture.h"


//******************************************************************************
// パラメータ定義
//******************************************************************************
//プリミティブ種別
#define OGL_POINTS				(0)		//点
#define OGL_LINES				(1)		//線
#define OGL_LINE_STRIP			(2)		//線ストリップ
#define OGL_TRIANGLES			(3)		//三角形
#define OGL_TRIANGLE_STRIP		(4)		//三角形ストリップ
#define OGL_TRIANGLE_FAN		(5)		//三角形ファン

//カリング
#define OGL_CULL_NONE			(0)		//カリングなし
#define OGL_CULL_FACE			(1)		//カリング表
#define OGL_CULL_BACK			(2)		//カリング裏


//******************************************************************************
// プリミティブ描画クラス
//******************************************************************************
class OGLPrimitive
{
public:
	
	//コンストラクタ／デストラクタ
	OGLPrimitive(void);
	virtual ~OGLPrimitive(void);
	
	//リソース解放
	void Release();
	
	//初期化
	//  指定可能な頂点データフォーマット
	//    OGLVERTEX_TYPE_V3N3C
	//    OGLVERTEX_TYPE_V3CT2
	//    OGLVERTEX_TYPE_V3N3CT2
	//  指定可能なプリミティブ種別
	//    OGL_POINTS
	//    OGL_LINES
	//    OGL_LINE_STRIP
	//    OGL_TRIANGLES
	//    OGL_TRIANGLE_STRIP
	//    OGL_TRIANGLE_FAN
	int Initialize(
			OGLDevice* pOGLDevice,					//描画デバイス
			OGLsizei vertexSize,					//頂点サイズ(byte)
			unsigned int vertexFormat,				//頂点フォーマット
			OGLenum primitiveType,					//プリミティブ種別
			bool isEnableDepthFunc = true,			//省略可：深度テスト
			bool isEnableAlphaBlending = true,		//省略可：アルファブレンディング
			unsigned int cullMode = OGL_CULL_NONE	//省略可：カリング
		);
	
	//頂点バッファ／インデックスバッファの生成
	int CreateVertexBuffer(OGLDevice* pOGLDevice, OGLsizei vertexNum);
	int CreateIndexBuffer(OGLDevice* pOGLDevice, OGLsizei indexNum);
	
	//頂点データ／インデックスデータ登録
	//  バッファのロック／アンロック制御は自動的に行われる
	//  本メソッドに指定したデータは利用者側が破棄する
	int SetAllVertex(OGLDevice* pOGLDevice, void* pVertex);
	int SetAllIndex(OGLDevice* pOGLDevice, unsigned int* pIndex);
	
	//マテリアル登録（省略可）
	void SetMaterial(OGLMATERIAL material);
	
	//ポイントサイズ登録（プリミティブ種別が点の場合のみ）
	void SetPointSize(float pointSize);
	
	//移動制御
	void Transform(OGLTransMatrix* pTransMatrix);
	
	//描画
	int Draw(
			OGLDevice* pOGLDevice,
			OGLTexture* pTexture = NULL,
			OGLsizei drawIndexNum = -1
		);
	
	//頂点バッファ／インデックスバッファのロック制御
	//  バッファの内容を書き換えるにはロックしてバッファのポインタを取得する
	//  バッファの内容を書き終えたらアンロックする
	int LockVertex(void** pPtrVertex, unsigned int offset = 0, unsigned int size = 0);
	int UnlockVertex();
	int LockIndex(unsigned int** pPtrIndex, unsigned int offset = 0, unsigned int size = 0);
	int UnlockIndex();
	
private:
	
	//頂点記述子
	MTLVertexDescriptor* m_pVertexDescriptor;
	
	//レンダーパイプライン記述子
	MTLRenderPipelineDescriptor* m_pRenderPipelineDescriptor;
	
	//レンダーパイプライン状態
	id <MTLRenderPipelineState> m_MTLRenderPipelineState;
	
	//深度ステンシル状態
	id <MTLDepthStencilState> m_MTLDepthStencilState;
	
	//制御情報バッファ
	id <MTLBuffer> m_MTLUniformsBuffer;
	
	//頂点バッファ
	id <MTLBuffer> m_MTLVertexBuffer;
	
	//インデックスバッファ
	id <MTLBuffer> m_MTLIndexBuffer;
	
	//頂点情報
	OGLsizei m_VertexSize;
	unsigned int m_VertexFormat;
	OGLenum m_PrimitiveType;
	float m_PointSize;
	
	//頂点バッファ情報
	OGLsizei m_VertexNum;
	bool m_IsVertexLocked;
	void* m_pVertexBuffer;
	unsigned int m_VertexBufferLockedOffset;
	unsigned int m_VertexBufferLockedSize;
	
	//インデックスバッファ情報
	OGLsizei m_IndexNum;
	bool m_IsIndexLocked;
	void* m_pIndexBuffer;
	unsigned int m_IndexBufferLockedOffset;
	unsigned int m_IndexBufferLockedSize;
	
	//描画情報
	OGLMATERIAL m_Material;
	OGLTransMatrix m_TransMatrix;
	bool m_isEnableDepthFunc;
	bool m_isEnableAlphaBlending;
	MTLCullMode m_CullMode;
	
	int _CreateRenderPipelineState(OGLDevice* pOGLDevice);
	int _CreateRenderPipelineState_V3N3C(OGLDevice* pOGLDevice);
	int _CreateRenderPipelineState_V3CT2(OGLDevice* pOGLDevice);
	int _CreateRenderPipelineState_V3N3CT2(OGLDevice* pOGLDevice);
	int _CreateVertexDescriptor_V3N3C();
	int _CreateVertexDescriptor_V3CT2();
	int _CreateVertexDescriptor_V3N3CT2();
	int _CreateRenderPipelineDescriptor(
				OGLDevice* pOGLDevice,
				NSString* pPiplineLabel,
				NSString* pVertexFunctionName,
				NSString* pFragmentFunctionName,
				MTLVertexDescriptor* pVertexDescriptor
			);
	int _CreateDepthStencilState(OGLDevice* pOGLDevice);
	int _CreateUniformsBuffer(OGLDevice* pOGLDevice);
	int _GetPrimitiveNum(unsigned int* pNum);
	MTLPrimitiveType _GetPrimitiveType(OGLenum primitiveType);
	void _GetDefaultMaterial(OGLMATERIAL* pMaterial);
	OGLMaterial _GetMaterialForShader();
	
private:
	
	//代入とコピーコンストラクタの禁止
	void operator=(const OGLPrimitive&);
	OGLPrimitive(const OGLPrimitive&);
	NSUInteger _AlignUp(NSUInteger n, NSUInteger alignment);
	
};

