Update vector

    When I started I wanted to do some experiment - not to use template classes. When I wrote this page I understood that this is not good for vectors and matrices. I needed to write a lot of code. I need to write template class for vector.

    Like this

    template<typename T>
    class slVec3_t
    {
    public:
    	slVec3_t() {}
    	
    	slVec3_t(T X, T Y, T Z) : 
    		x(X), 
    		y(Y), 
    		z(Z)
    	{}
    ...
    

    I need new type. User can choose what to use, float or double

    Add in slDefs.h

    using real_t = double;
    

    And add this for vector

    using slVec3 = slVec3_t<real_t>;
    using slVec3f = slVec3_t<float>;
    using slVec4 = slVec4_t<real_t>;
    using slVec4f = slVec4_t<float>;
    

    Matrix

    Matrix will be like this

    template<typename T>
    class slMatrix4_t
    {
    public:
    	slMatrix4_t() { identity(); }
    ...
    	slVec4_t<T> m_data[4];
    	T* data() { return &m_data[0].x; }
    };
    

    Short version for double

    using slMat4 = slMatrix4_t<real_t>;
    

    Quaternion

    For rotations I want to use quaternions. Only them. I used them only together with matrices. Quaternion multiplications are faster than matrix multiplication.

    I don't know how all this works...I think, I still need World matrix for drawing.

    class slQuaternion
    {
    public:
    	slQuaternion();
    	slQuaternion(const slQuaternion&);
    	slQuaternion(float x, float y, float z, float w);
    
    	void identity();
    
    	slQuaternion& operator=(const slQuaternion& o);
    	slQuaternion operator*(const slQuaternion& q)const;
    	slQuaternion operator*(float s) const;
    	void operator*=(const slQuaternion& q);
    	bool operator!=(const slQuaternion& q)const;
    	bool operator==(const slQuaternion& q)const;
    	slQuaternion operator+(const slQuaternion& o) const;
    	slQuaternion operator-(const slQuaternion& o) const;
    	slQuaternion operator-();
    	float operator[](uint32_t index) const;
    	float& operator[](uint32_t index);
    
    	float x, y, z, w;
    	float* data() { return &x; }
    };
    

    In slMath added this methods

    static float dot(const slQuaternion& v1, const slQuaternion& v2);
    static float length(const slQuaternion& v);
    static void lerp1(const slQuaternion& x, const slQuaternion& y, float t, slQuaternion& r);
    static void lerp2(const slQuaternion& x, const slQuaternion& y, float t, slQuaternion& r);
    static void set_rotation(slQuaternion&, float x, float y, float z);
    static void set_rotation(slQuaternion&, const slVec3& axis, const real_t& _angle);
    static void set_rotation(slQuaternion&, const slVec3f& axis, const float& _angle);
    static void set_rotation(slQuaternion&, const slVec4& axis, const real_t& _angle);
    static void set_rotation(slQuaternion&, const slVec4f& axis, const float& _angle);
    // from assimp?
    static void slerp(slQuaternion& q1, slQuaternion& q2, float time, float threshold, slQuaternion& r);
    

    Set angles

    void slMath::set_rotation(slQuaternion& q, float x, float y, float z)
    {
    	x *= 0.5f;
    	y *= 0.5f;
    	z *= 0.5f;
    	float c1 = ::cosf(x);
    	float c2 = ::cosf(y);
    	float c3 = ::cosf(z);
    	float s1 = ::sinf(x);
    	float s2 = ::sinf(y);
    	float s3 = ::sinf(z);
    	q.w = (c1 * c2 * c3) + (s1 * s2 * s3);
    	q.x = (s1 * c2 * c3) - (c1 * s2 * s3);
    	q.y = (c1 * s2 * c3) + (s1 * c2 * s3);
    	q.z = (c1 * c2 * s3) - (s1 * s2 * c3);
    }
    

    I need to add other methods for matrices and quaternions.

    Create matrix using quaternion

    void slMath::set_rotation(slMat4& m, const slQuaternion& q)
    {
    	real_t d = length(q);
    	real_t s = 2.0f / d;
    	real_t xs = q.x * s, ys = q.y * s, zs = q.z * s;
    	real_t wx = q.w * xs, wy = q.w * ys, wz = q.w * zs;
    	real_t xx = q.x * xs, xy = q.x * ys, xz = q.x * zs;
    	real_t yy = q.y * ys, yz = q.y * zs, zz = q.z * zs;
    	m.set(
    		1.0f - (yy + zz), xy - wz, xz + wy,
    		xy + wz, 1.0f - (xx + zz), yz - wx,
    		xz - wy, yz + wx, 1.0f - (xx + yy));
    }
    

    3D line

    Add new method in GS

    virtual void DrawLine3D(const slVec3& p1, const slVec3& p2, const slColor& c) = 0;
    

    Implementation

    below
    

    I need to write slFramework::GetMatrix, all matrices for rendering will be located inside framework.

    After this, I need to create shader for drawing lines.

    In slFramework.h I add

    enum class slMatrixType : uint32_t
    {
    	World,
    	View,
    	Projection,
    	ViewProjection, //For 3d line
    	WorldViewProjection,
    	ViewInvert,
    	//GUIProjection,
    	_count
    };
    

    And method for slFramework

    static slMat4* GetMatrix(slMatrixType);
    static void SetMatrix(slMatrixType, slMat4*);
    

    It working with pointers. Matrices MUST exists when I need to draw something

    There is will be a lot of matrices, and I DON"T want to copy them all the time.

    Implementation

    In slFrameworkImpl

    slMat4* m_matrixPtrs[(uint32_t)slMatrixType::_count];
    

    Methods

    slMat4* slFramework::GetMatrix(slMatrixType t)
    {
    	return g_framework->m_matrixPtrs[(uint32_t)t];
    }
    void slFramework::SetMatrix(slMatrixType t, slMat4* m)
    {
    	g_framework->m_matrixPtrs[(uint32_t)t] = m;
    }
    

    I need to create a shader.

    In d3d11 library I add new class - base class for all shaders.

    class slGSD3D11ShaderBase
    {
    public:
    	slGSD3D11ShaderBase() :
    		m_vShader(0),
    		m_pShader(0),
    		m_gShader(0),
    		m_vLayout(0)
    	{}
    
    	virtual ~slGSD3D11ShaderBase()
    	{
    		if (m_vLayout) m_vLayout->Release();
    		if (m_gShader) m_gShader->Release();
    		if (m_vShader) m_vShader->Release();
    		if (m_pShader) m_pShader->Release();
    	}
    
    	ID3D11VertexShader* m_vShader;
    	ID3D11PixelShader* m_pShader;
    	ID3D11GeometryShader* m_gShader;
    	ID3D11InputLayout* m_vLayout;
    
    	virtual void SetConstants(/*slMaterial* material*/) = 0;
    };
    

    Also I need functions for shader creation (in slGSD3D11)

    bool createShaders(
    		const char* vertexTarget,
    		const char* pixelTarget,
    		const char* vertexShader,
    		const char* pixelShader,
    		const char* vertexEntryPoint,
    		const char* pixelEntryPoint,
    		slMeshVertexType vertexType,
    		ID3D11VertexShader** vs,
    		ID3D11PixelShader** ps,
    		ID3D11InputLayout** il);
    bool createConstantBuffer(uint32_t byteSize, ID3D11Buffer**);
    bool createGeometryShaders(const char* target,
    	const char* shaderText,
    	const char* entryPoint,
    	ID3D11GeometryShader** gs);
    

    I need slMeshVertexType. Need to create new .h file for this. For future.

    Enum there.

    enum class slMeshVertexType : uint32_t
    {
    	Null, // 0
    };
    

    Shader creation

    bool createShaders(
    		const char* vertexTarget,
    		const char* pixelTarget,
    		const char* vertexShader,
    		const char* pixelShader,
    		const char* vertexEntryPoint,
    		const char* pixelEntryPoint,
    		slMeshVertexType vertexType,
    		ID3D11VertexShader** vs,
    		ID3D11PixelShader** ps,
    		ID3D11InputLayout** il);
    	bool createConstantBuffer(uint32_t byteSize, ID3D11Buffer**);
    	bool createGeometryShaders(const char* target,
    		const char* shaderText,
    		const char* entryPoint,
    		ID3D11GeometryShader** gs);
    

    Implementation

    bool slGSD3D11::createConstantBuffer(uint32_t byteSize, ID3D11Buffer** cb)
    {
    	D3D11_BUFFER_DESC mbd;
    	memset(&mbd, 0, sizeof(mbd));
    	mbd.Usage = D3D11_USAGE_DYNAMIC;
    	mbd.ByteWidth = byteSize;
    	mbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    	mbd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    	mbd.MiscFlags = 0;
    	mbd.StructureByteStride = 0;
    
    	HRESULT hr = m_d3d11Device->CreateBuffer(&mbd, 0, cb);
    	if (FAILED(hr))
    	{
    		slLog::PrintError("Can't create constant buffer. Error code [%u]\n", hr);
    		return false;
    	}
    	return true;
    }
    
    bool slGSD3D11::createGeometryShaders(const char* target,
    	const char* shaderText,
    	const char* entryPoint,
    	ID3D11GeometryShader** gs)
    {
    	ID3D10Blob* m_GsBlob = nullptr;
    	ID3D10Blob* m_errorBlob = nullptr;
    	HRESULT hr = D3DCompile(
    		shaderText,
    		strlen(shaderText),
    		0, 0, 0,
    		entryPoint,
    		target,
    		0,
    		0,
    		&m_GsBlob,
    		&m_errorBlob
    	);
    	if (FAILED(hr))
    	{
    		char* message = (char*)m_errorBlob->GetBufferPointer();
    		slLog::PrintError("Geometry shader compile error: %s\n", message);
    		return false;
    	}
    
    	hr = m_d3d11Device->CreateGeometryShader(
    		m_GsBlob->GetBufferPointer(),
    		m_GsBlob->GetBufferSize(),
    		0,
    		gs);
    	if (FAILED(hr))
    	{
    		slLog::PrintError("Can't create geometry shader. Error code [%u]\n", hr);
    		return false;
    	}
    
    	return true;
    }
    
    bool slGSD3D11::createShaders(
    	const char* vertexTarget,
    	const char* pixelTarget,
    	const char* vertexShader,
    	const char* pixelShader,
    	const char* vertexEntryPoint,
    	const char* pixelEntryPoint,
    	slMeshVertexType vertexType,
    	ID3D11VertexShader** vs,
    	ID3D11PixelShader** ps,
    	ID3D11InputLayout** il)
    {
    	ID3D10Blob* m_VsBlob = nullptr;
    	ID3D10Blob* m_PsBlob = nullptr;
    	ID3D10Blob* m_errorBlob = nullptr;
    
    	HRESULT hr = D3DCompile(
    		vertexShader,
    		strlen(vertexShader),
    		0, 0, 0,
    		vertexEntryPoint,
    		vertexTarget,
    		0,
    		0,
    		&m_VsBlob,
    		&m_errorBlob
    	);
    
    	if (FAILED(hr))
    	{
    		char* message = (char*)m_errorBlob->GetBufferPointer();
    		slLog::PrintError("Vertex shader compile error: %s\n", message);
    		return false;
    	}
    
    	hr = D3DCompile(
    		pixelShader,
    		strlen(pixelShader),
    		0, 0, 0,
    		pixelEntryPoint,
    		pixelTarget,
    		0,
    		0,
    		&m_PsBlob,
    		&m_errorBlob
    	);
    
    	if (FAILED(hr))
    	{
    		char* message = (char*)m_errorBlob->GetBufferPointer();
    		slLog::PrintError("Pixel shader compile error: %s\n", message);
    		return false;
    	}
    
    	hr = m_d3d11Device->CreateVertexShader(
    		m_VsBlob->GetBufferPointer(),
    		m_VsBlob->GetBufferSize(),
    		0,
    		vs);
    	if (FAILED(hr))
    	{
    		slLog::PrintError("Can't create vertex shader. Error code [%u]\n", hr);
    		return false;
    	}
    
    	hr = m_d3d11Device->CreatePixelShader(
    		m_PsBlob->GetBufferPointer(),
    		m_PsBlob->GetBufferSize(),
    		0,
    		ps);
    	if (FAILED(hr))
    	{
    		slLog::PrintError("Can't create pixel shader. Error code [%u]\n", hr);
    		return false;
    	}
    
    	if (vertexType != slMeshVertexType::Null)
    	{
    		D3D11_INPUT_ELEMENT_DESC vertexLayout[8];
    		uint32_t vertexLayoutSize = 0;
    		/*
    		LPCSTR SemanticName;
    		UINT SemanticIndex;
    		DXGI_FORMAT Format;
    		UINT InputSlot;
    		UINT AlignedByteOffset;
    		D3D11_INPUT_CLASSIFICATION InputSlotClass;
    		UINT InstanceDataStepRate;
    		*/
    
    		int ind = 0;
    		// for future
    		/*switch (vertexType)
    		{
    		default:
    			slLog::PrintError("Unsupportex vertex type\n");
    			return false;
    		}*/
    		vertexLayoutSize = ind + 1;
    
    		hr = m_d3d11Device->CreateInputLayout(
    			vertexLayout,
    			vertexLayoutSize,
    			m_VsBlob->GetBufferPointer(),
    			m_VsBlob->GetBufferSize(),
    			il);
    		if (FAILED(hr))
    		{
    			slLog::PrintError("Can't create input layout. Error code [%u]\n", hr);
    			return false;
    		}
    	}
    
    
    	if (m_VsBlob)    m_VsBlob->Release();
    	if (m_PsBlob)    m_PsBlob->Release();
    	if (m_errorBlob) m_errorBlob->Release();
    
    	return true;
    }
    

    For D3DCompile I need to include file and link .lib

    #include <d3dcompiler.h>
    #pragma comment(lib, "d3dcompiler.lib")
    

    Shader for line.

    class slD3D11ShaderLine3D : public slGSD3D11ShaderBase
    {
    public:
    	slD3D11ShaderLine3D(slGSD3D11* gs);
    	virtual ~slD3D11ShaderLine3D();
    
    	slGSD3D11* m_gs = 0;
    
    	ID3D11Buffer*		m_cb = 0;
    
    	struct cb
    	{
    		slMat4 VP;
    		slVec4  P1;
    		slVec4  P2;
    		slColor  Color;
    	}m_cbData;
    	virtual void SetConstants(/*slMaterial* material*/);
    
    	void SetData(const slVec3& p1, const slVec3& p2, const slColor& color, const slMat4& projMat);
    
    	bool init();
    };
    

    Implementation

    slD3D11ShaderLine3D::slD3D11ShaderLine3D(slGSD3D11* gs)	:	m_gs(gs){}
    slD3D11ShaderLine3D::~slD3D11ShaderLine3D() {}
    
    bool slD3D11ShaderLine3D::init(){
    	const char* text =
    		"struct VSIn{\n"
    		"	uint vertexID : SV_VertexID;\n"
    		"};\n"
    		"cbuffer cbVertex{\n"
    		"	double4x4 VP;\n"
    		"	double4 P1;\n"
    		"	double4 P2;\n"
    		"	float4 Color;\n"
    		"};\n"
    		"struct VSOut{\n"
    		"   float4 pos : SV_POSITION;\n"
    		"   float4 color : COLOR0;\n"
    		"};\n"
    		
    		"struct PSOut{\n"
    		"    float4 color : SV_Target;\n"
    		"};\n"
    
    		"VSOut VSMain(VSIn input){\n"
    			"double4 vertices[2] = {\n"
    			"double4( P1.xyz, 1.0),\n"
    			"double4( P2.xyz, 1.0)\n"
    			"};\n"
    		"   VSOut output;\n"
    		"	output.pos  = mul(VP, vertices[input.vertexID]);\n"
    		"	output.color = Color;\n"
    		"	return output;\n"
    		"}\n"
    		"PSOut PSMain(VSOut input){\n"
    		"    PSOut output;\n"
    		"    output.color = input.color;\n"
    		"    return output;\n"
    		"}\n";
    	if (!m_gs->createShaders(
    		"vs_5_0",
    		"ps_5_0",
    		text,
    		text,
    		"VSMain",
    		"PSMain",
    		slMeshVertexType::Null,
    		&this->m_vShader,
    		&this->m_pShader,
    		&this->m_vLayout))
    		return false;
    
    	if (!m_gs->createConstantBuffer(sizeof(cb), &m_cb))
    		return false;
    
    	return true;
    }
    
    void slD3D11ShaderLine3D::SetData(const slVec3& p1, const slVec3& p2, const slColor& color, const slMat4& projMat)
    {
    	m_cbData.P1 = p1;
    	m_cbData.P2 = p2;
    	m_cbData.P1.w = 1.f;
    	m_cbData.P2.w = 1.f;
    	m_cbData.Color = color;
    	m_cbData.VP = projMat;
    }
    
    void slD3D11ShaderLine3D::SetConstants(/*miMaterial* material*/){
    
    	m_gs->m_d3d11DevCon->VSSetConstantBuffers(0, 1, &m_cb);
    	D3D11_MAPPED_SUBRESOURCE mappedResource;
    	m_gs->m_d3d11DevCon->Map(m_cb, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
    	D3D11_BUFFER_DESC d;
    	m_cb->GetDesc(&d);
    	memcpy(mappedResource.pData, &m_cbData, d.ByteWidth);
    	m_gs->m_d3d11DevCon->Unmap(m_cb, 0);
    }
    

    Create this shader. In slGSD3D11

    slD3D11ShaderLine3D* m_shaderLine3D = 0;
    

    Add method

    bool CreateShaders();
    

    Implementation

    bool slGSD3D11::CreateShaders()
    {
    	m_shaderLine3D = slCreate<slD3D11ShaderLine3D>(this);
    	if (!m_shaderLine3D->init())
    		return false;
    
    	return true;
    }
    

    Call it in Init

    if (!CreateShaders())
    {
    	slLog::PrintError("Can't create Direct3D 11 shader\n");
    	return false;
    }
    

    Add SetActiveShader

    void slGSD3D11::SetActiveShader(slGSD3D11ShaderBase* shader)
    {
    	m_activeShader = shader;
    	m_d3d11DevCon->IASetInputLayout(shader->m_vLayout);
    	m_d3d11DevCon->VSSetShader(shader->m_vShader, 0, 0);
    	m_d3d11DevCon->GSSetShader(shader->m_gShader, 0, 0);
    	m_d3d11DevCon->PSSetShader(shader->m_pShader, 0, 0);
    }
    

    Now draw 3D line

    void slGSD3D11::DrawLine3D(const slVec3& p1, const slVec3& p2, const slColor& c)
    {
    	m_d3d11DevCon->IASetInputLayout(NULL);
    	m_d3d11DevCon->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_LINELIST);
    
    	SetActiveShader(m_shaderLine3D);
    	m_shaderLine3D->SetData(p1, p2, c, *slFramework::GetMatrix(slMatrixType::ViewProjection));
    	m_shaderLine3D->SetConstants(/*0*/);
    
    	m_d3d11DevCon->Draw(2, 0);
    }
    

    Camera

    Camera is a class for easy creation some matrices and some other data.

    For drawing you need view matrix, and projection matrix.

    View matrix is just a rotation matrix.

    Projection matrix it's like moving point from 3D world space into 2D screen, with range from -1 to +1.

    class slCamera
    {
    public:
    	slCamera();
    	~slCamera();
    
    	/*enum class Direction : uint32_t
    	{
    		North,
    		NorthEast,
    		East,
    		SouthEast,
    		South,
    		SouthWest,
    		West,
    		NorthWest
    	};*/
    
    	slMat4 m_projectionMatrix;
    
    	slMat4 m_viewMatrix;
    	slMat4 m_viewMatrixInvert;
    
    	slMat4 m_viewProjectionMatrix;
    	slMat4 m_viewProjectionInvertMatrix;
    
    	float m_near = 0.01f;
    	float m_far = 2500.f;
    	float m_fov = 0.683264f;
    	float m_aspect = 1.3333333f;
    
    	slCameraFrustum m_frust;
    
    	slVec3 m_position;
    	slVec3 m_target;
    	slVec3 m_up;
    
    	void Update();
    };
    

    First version. I add other things like slCameraFrustum later.

    Update()

    void slCamera::Update()
    {
    	slMath::perspectiveLH(m_projectionMatrix, m_fov, m_aspect, m_near, m_far);
    	slMath::lookAtLH(m_viewMatrix, m_position, m_target, m_up);
    	
    	slMath::mul(m_projectionMatrix, m_viewMatrix, m_viewProjectionMatrix);
    	
    	m_viewMatrixInvert = m_viewMatrix;
    	slMath::invert(m_viewMatrixInvert);
    
    	auto pi = m_projectionMatrix;
    	slMath::invert(pi);
    	slMath::mul(m_viewMatrixInvert, pi, m_viewProjectionInvertMatrix);
    
    	m_frust.CalculateFrustum(m_projectionMatrix, m_viewMatrix);
    }
    

    Drawing

    slVec3 globalPosition;
    globalPosition.set(99990000.f, 0.f, 0.f);
    
    slCamera* camera = slFramework::SummonCamera();
    camera->m_position = globalPosition + slVec3(10.f, 10.f, 10.f);
    camera->m_target = globalPosition;
    camera->Update();
    slFramework::SetMatrix(slMatrixType::ViewProjection, &camera->m_viewProjectionMatrix);
    
    float* dt = slFramework::GetDeltaTime();
    
    while (g_isRun)
    {
    	slFramework::Update();
    	camera->Update();
    ....
    if (gs)
    	{
    		gs->BeginDraw();
    		gs->ClearAll();
    
    		gs->DrawLine3D(slVec3(globalPosition.x + 1.f, globalPosition.y, 
    		globalPosition.z), slVec3(globalPosition.x -1.f, globalPosition.y, 
    		globalPosition.z), ColorRed);
    		gs->DrawLine3D(slVec3(globalPosition.x, globalPosition.y + 1.f, 
    		globalPosition.z), slVec3(globalPosition.x, globalPosition .y -1.f,
    		globalPosition.z), ColorYellow);
    		gs->DrawLine3D(slVec3(globalPosition.x, globalPosition.y, 
    		globalPosition.z + 1.f), slVec3(globalPosition.x, globalPosition.y,
    		globalPosition.z -1.f), ColorLime);
    
    		gs->EndDraw();
    		gs->SwapBuffers();
    	}
    }
    

    Using double in shader, I figured out that this is very easy thing for D3D11.

    Download