class slMeshLoader
{
public:
slMeshLoader() {}
virtual ~slMeshLoader() {}
virtual uint32_t GetSupportedFilesCount() = 0;
virtual slString GetSupportedFileExtension(uint32_t) = 0;
virtual slString GetSupportedFileName(uint32_t) = 0;
virtual void Load(const char* path, slMeshLoaderCallback*) = 0;
};
OBJ can have many models. Each new model will be sent
into callback.
class slMeshLoaderCallback
{
public:
slMeshLoaderCallback() {}
virtual ~slMeshLoaderCallback() {}
virtual void OnMaterial(slMaterial* m, slString* name);
virtual void OnMesh(slMesh* newMesh, slString* name, slString* materialName);
};
3D files can have materials. I need new class.
This class is like in IrrLicht. I know this engine
so long time, and, almost all things I write in my own way,
but not materials, I can't imagine more easy way to set shader,
textures and other parameters.
enum class slShaderType
{
Solid,
BumpMap,
SphereMap,
User
};
// Graphics System
struct slMaterial
{
slShaderType m_shader = slShaderType::Solid;
float m_opacity = 1.f;
slColor m_colorDiffuse = ColorWhite;
slColor m_colorAmbient = ColorGray;
slColor m_colorSpecular = ColorWhite;
slVec3 m_sunPosition;
bool m_wireframe = false;
bool m_cullBackFace = false;
struct map{
slTexture* m_texture = 0;
}m_maps[16];
slString m_name;
};
Shader type. FIrst will be shader without any effects like bumpmap.
I just wrote next shaders that I want to write. User shader is that
shader that user can write, but in GS lib side. I don't want
to add ability to user to write shaders in app side.
In framework add new methods
static uint32_t GetMeshLoadersNum();
static slMeshLoader* GetMeshLoader(uint32_t);
static void LoadMesh(const char*, slMeshLoaderCallback*);
Same like with gs
uint32_t slFramework::GetMeshLoadersNum()
{
return (uint32_t)g_framework->m_meshLoaders.size();
}
slMeshLoader* slFramework::GetMeshLoader(uint32_t i)
{
SL_ASSERT_ST(i < g_framework->m_meshLoaders.size());
return g_framework->m_meshLoaders[i];
}
Load mesh
void slFramework::LoadMesh(const char* path, slMeshLoaderCallback* cb)
{
slStringA stra;
std::filesystem::path p = path;
auto e = p.extension();
uint32_t mln = GetMeshLoadersNum();
for (uint32_t i = 0; i < mln; ++i)
{
auto ml = GetMeshLoader(i);
auto sfc = ml->GetSupportedFilesCount();
for (uint32_t o = 0; o < sfc; ++o)
{
slString sfe = ml->GetSupportedFileExtension(o);
sfe.to_utf8(stra);
if (strcmp((const char*)stra.m_data, e.generic_string().c_str()) == 0)
{
ml->Load(path, cb);
return;
}
}
}
}
Now I need to add meshloader library into slowlib
extern "C"
{
slGS* SL_CDECL slGSD3D11_create();
slMeshLoader* SL_CDECL slMeshLoaderOBJ_create(); // new
}
SL_LINK_LIBRARY("slowlib.d3d11");
SL_LINK_LIBRARY("slowlib.meshloader");
OBJ loader library
I copy pasted d3d library and changed name.
Basic functions
#include "slowlib.h"
#include "slowlib.meshloaderimpl.h"
extern "C"
{
slMeshLoader* SL_CDECL slMeshLoaderOBJ_create()
{
slMeshLoaderImpl* ml = slCreate<slMeshLoaderImpl>();
return ml;
}
}
Mesh loader class
class slMeshLoaderImpl : public slMeshLoader
{
void ImportOBJ_MTL(slArray<OBJMaterial*>& materials, const char* obj_fileName, const char* mtl_fileName);
void LoadOBJ(const char* path, slMeshLoaderCallback*);
public:
slMeshLoaderImpl();
virtual ~slMeshLoaderImpl();
virtual uint32_t GetSupportedFilesCount() final;
virtual slString GetSupportedFileExtension(uint32_t) final;
virtual slString GetSupportedFileName(uint32_t) final;
virtual void Load(const char* path, slMeshLoaderCallback*) final;
};
Methods
slMeshLoaderImpl::slMeshLoaderImpl(){}
slMeshLoaderImpl::~slMeshLoaderImpl(){}
uint32_t slMeshLoaderImpl::GetSupportedFilesCount()
{
return 1;
}
slString slMeshLoaderImpl::GetSupportedFileExtension(uint32_t i)
{
switch (i)
{
case 0:
return "obj";
}
return "-";
}
slString slMeshLoaderImpl::GetSupportedFileName(uint32_t i)
{
switch (i)
{
case 0:
return "Wavefront OBJ";
}
return "-";
}
void slMeshLoaderImpl::Load(const char* path, slMeshLoaderCallback* cb)
{
size_t len = strlen(path);
if (len > 4)
{
// find last '.'
size_t last_dot = 0;
for (size_t i = 0; i < len; ++i)
{
if (path[i] == '.')
last_dot = i;
}
if (last_dot)
{
if (strcmp(".obj", &path[last_dot]) == 0)
LoadOBJ(path, cb);
}
}
}
LoadOBJ
Code is very large.
Old version is here OBJ Import Export
Interesting parts. I read whole text into buffer, and then read this buffer
using functions
unsigned char* OBJNextLine(unsigned char* ptr);
unsigned char* OBJSkipSpaces(unsigned char* ptr);
unsigned char* OBJReadVec2(unsigned char* ptr, slVec2f& vec2);
unsigned char* OBJReadFloat(unsigned char* ptr, float& value);
unsigned char* OBJReadVec3(unsigned char* ptr, slVec3f& vec3);
unsigned char* OBJReadFace(unsigned char* ptr, OBJFace& f, char* s);
unsigned char* OBJReadWord(unsigned char* ptr, slStringA& str);
unsigned char* OBJReadLastWord(unsigned char* ptr, slStringA& str);
For example
unsigned char* OBJReadVec2(unsigned char* ptr, slVec2f& vec2)
{
ptr = OBJSkipSpaces(ptr);
float x, y;
if (*ptr == '\n')
{
ptr++;
}
else
{
ptr = OBJReadFloat(ptr, x);
ptr = OBJSkipSpaces(ptr);
ptr = OBJReadFloat(ptr, y);
ptr = OBJNextLine(ptr);
vec2.x = x;
vec2.y = y;
}
return ptr;
}
Actually need to put this functions somewhere in library because they are usefull.
I have some helper structs
enum class OBJFaceType
{
p,
pu,
pun,
pn
};
struct OBJSimpleArr
{
OBJSimpleArr() {
sz = 0;
}
int data[0x100];
unsigned int sz;
void push_back(int v) { data[sz++] = v; }
unsigned int size() { return sz; }
void reset() { sz = 0; }
};
struct OBJFace
{
OBJFace() {
ft = OBJFaceType::pun;
}
OBJSimpleArr p, u, n;
OBJFaceType ft;
void reset()
{
ft = OBJFaceType::pun;
p.reset();
u.reset();
n.reset();
}
};
For MTL
struct OBJMaterial
{
OBJMaterial() {
m_specularExponent = 10.f;
m_opacity = 1.f;
m_transparency = 0.f;
m_refraction = 1.f;
}
slStringA m_name; // newmtl
slVec3f m_ambient; // Ka
slVec3f m_diffuse; // Kd
slVec3f m_specular; // Ks
float m_specularExponent; // Ns
float m_opacity; // d
float m_transparency; // Tr
float m_refraction; // Ni
slStringA m_map_diffuse; // map_Kd
slStringA m_map_ambient; // map_Ka
slStringA m_map_specular; // map_Ks
slStringA m_map_specularHighlight; // map_Ns
slStringA m_map_alpha; // map_d
slStringA m_map_bump; // map_bump bump
slStringA m_map_displacement; // disp
slStringA m_map_reflection; // refl
};
I show face step
case 'f':
{
isModel = true;
f.reset();
ptr = OBJReadFace(++ptr, f, s);
polygonCreator.Clear();
bool genNormals = true;
for (size_t sz2 = f.p.size(), i2 = 0; i2 < sz2; ++i2)
{
auto index = i2;
auto pos_index = f.p.data[index];
if (pos_index < 0)
{
// если индекс отрицательный то он указывает на позицию относительно последнего элемента
// -1 = последний элемент
// if index is negative then he points on position relative last element
// -1 = last element
pos_index = last_counter[0] + pos_index + 1;
}
auto v = position[pos_index];
slVec3f pcPos, pcNorm;
slVec2f pcUV;
pcPos = v;
if (f.ft == OBJFaceType::pu || f.ft == OBJFaceType::pun)
{
auto uv_index = f.u.data[index];
if (uv_index < 0)
{
uv_index = last_counter[1] + uv_index + 1;
}
auto u = uv[uv_index];
pcUV.x = u.x;
pcUV.y = 1.f - u.y;
}
if (f.ft == OBJFaceType::pn || f.ft == OBJFaceType::pun)
{
auto nor_index = f.n.data[index];
if (nor_index < 0)
{
nor_index = last_counter[2] + nor_index + 1;
}
auto n = normal[nor_index];
// geometry_creator->AddNormal(n.x, n.y, n.z);
pcNorm = n;
genNormals = false;
}
polygonCreator.SetPosition(pcPos);
polygonCreator.SetNormal(pcNorm);
polygonCreator.SetUV(pcUV);
polygonCreator.AddVertex();
}
if (!polygonMesh)
polygonMesh = slFramework::SummonPolygonMesh();
polygonMesh->AddPolygon(&polygonCreator, genNormals);
}break;
slMesh creation can be when 'o' or 'g', or without them.
if (polygonMesh)
{
if (polygonMesh->m_first_polygon)
{
slMaterial* m = 0;
if (currMaterial)
{
/*m = g_sdk->CreateMaterial(currMaterial->m_name.data());
if (currMaterial->m_map_diffuse.size())
m->m_maps[m->mapSlot_Diffuse].m_texturePath = currMaterial->m_map_diffuse;*/
}
cb->OnMesh(polygonMesh->CreateMesh(), &prev_word, 0);
slDestroy(polygonMesh);
polygonMesh = 0;
}
}
It works, now I need to add GPU mesh buffer and shader.
GPU mesh
class slGPUMesh
{
public:
slGPUMesh() {}
virtual ~slGPUMesh() {}
};
This is all what I need now.
Create D3D11 mesh buffer
class slGSD3D11Mesh : public slGPUMesh
{
public:
slGSD3D11Mesh();
virtual ~slGSD3D11Mesh();
ID3D11Buffer* m_vBuffer = 0;
ID3D11Buffer* m_iBuffer = 0;
DXGI_FORMAT m_indexType = DXGI_FORMAT_R16_UINT;
slMeshInfo m_meshInfo;
};
Implementation
slGSD3D11Mesh::slGSD3D11Mesh() {}
slGSD3D11Mesh::~slGSD3D11Mesh()
{
if (m_vBuffer)
{
m_vBuffer->Release();
m_vBuffer = 0;
}
if (m_iBuffer)
{
m_iBuffer->Release();
m_iBuffer = 0;
}
}
Creating GPU mesh will be in GS. Add method
virtual slGPUMesh* SummonMesh(slMesh*) = 0;
Implementation. Creating GPU mesh.
slGPUMesh* slGSD3D11::SummonMesh(slMesh* m)
{
SL_ASSERT_ST(m);
SL_ASSERT_ST(m->m_vertices);
SL_ASSERT_ST(m->m_indices);
SL_ASSERT_ST(m->m_info.m_iCount);
SL_ASSERT_ST(m->m_info.m_vCount);
slGSD3D11Mesh* newMesh = slCreate<slGSD3D11Mesh>();
newMesh->m_meshInfo = m->m_info;
slZeroDecl(D3D11_BUFFER_DESC, vbd);
slZeroDecl(D3D11_BUFFER_DESC, ibd);
vbd.Usage = D3D11_USAGE_DEFAULT;
vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_STREAM_OUTPUT;
ibd.Usage = D3D11_USAGE_DEFAULT;
ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
slZeroDecl(D3D11_SUBRESOURCE_DATA, vData);
slZeroDecl(D3D11_SUBRESOURCE_DATA, iData);
vbd.ByteWidth = m->m_info.m_stride * m->m_info.m_vCount;
vData.pSysMem = &m->m_vertices[0];
auto hr = m_d3d11Device->CreateBuffer(&vbd, &vData, &newMesh->m_vBuffer);
if (FAILED(hr))
{
slLog::PrintError("Can't create Direct3D 11 vertex buffer [%u]\n", hr);
return nullptr;
}
uint32_t index_sizeof = sizeof(uint16_t);
newMesh->m_indexType = DXGI_FORMAT_R16_UINT;
if (m->m_info.m_indexType == slMeshIndexType::u32)
{
newMesh->m_indexType = DXGI_FORMAT_R32_UINT;
index_sizeof = sizeof(uint32_t);
}
ibd.ByteWidth = index_sizeof * newMesh->m_meshInfo.m_iCount;
iData.pSysMem = &m->m_indices[0];
hr = m_d3d11Device->CreateBuffer(&ibd, &iData, &newMesh->m_iBuffer);
if (FAILED(hr))
{
slLog::PrintError("Can't create Direct3D 11 index buffer [%u]\n", hr);
return nullptr;
}
return newMesh;
}
Drawing. Add methods in GS
virtual void SetMesh(slGPUMesh*) = 0;
virtual void SetMaterial(slMaterial*) = 0;
virtual void Draw() = 0;
Implementation
void slGSD3D11::SetMesh(slGPUMesh* m)
{
m_currMesh = (slGSD3D11Mesh*)m;
}
void slGSD3D11::SetMaterial(slMaterial* m)
{
m_currMaterial = m;
}
void slGSD3D11::Draw()
{
SL_ASSERT_ST(m_currMesh);
SL_ASSERT_ST(m_currMaterial);
if (m_currMaterial->m_wireframe)
{
if (m_currMaterial->m_cullBackFace)
m_d3d11DevCon->RSSetState(m_RasterizerWireframe);
else
m_d3d11DevCon->RSSetState(m_RasterizerWireframeNoBackFaceCulling);
}
else
{
if (m_currMaterial->m_cullBackFace)
m_d3d11DevCon->RSSetState(m_RasterizerSolid);
else
m_d3d11DevCon->RSSetState(m_RasterizerSolidNoBackFaceCulling);
}
switch (m_currMesh->m_meshInfo.m_vertexType)
{
case slMeshVertexType::Triangle:
{
switch (m_currMaterial->m_shader)
{
case slShaderType::Solid:
SetActiveShader(m_shaderSolid);
m_shaderSolid->SetData(*slFramework::GetMatrix(slMatrixType::WorldViewProjection),
*slFramework::GetMatrix(slMatrixType::World));
m_shaderSolid->SetConstants(m_currMaterial);
break;
}
}break;
}
uint32_t offset = 0u;
m_d3d11DevCon->IASetVertexBuffers(0, 1, &m_currMesh->m_vBuffer, &m_currMesh->m_meshInfo.m_stride, &offset);
switch (m_currMesh->m_meshInfo.m_vertexType)
{
default:
case slMeshVertexType::Triangle:
m_d3d11DevCon->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_d3d11DevCon->IASetIndexBuffer(m_currMesh->m_iBuffer, m_currMesh->m_indexType, 0);
m_d3d11DevCon->DrawIndexed(m_currMesh->m_meshInfo.m_iCount, 0, 0);
break;
}
}
Write new shader
class slD3D11ShaderSolid : public slGSD3D11ShaderBase
{
public:
slD3D11ShaderSolid(slGSD3D11* gs);
virtual ~slD3D11ShaderSolid();
slGSD3D11* m_gs = 0;
ID3D11Buffer* m_cbV = 0;
ID3D11Buffer* m_cbP = 0;
struct cbV
{
slMat4 WVP;
slMat4 W;
}m_cbDataV;
struct cbP
{
slVec4 SunPosition;
slColor BaseColor;
}m_cbDataP;
virtual void SetConstants(slMaterial* material);
void SetData(const slMat4& WVP, const slMat4& W);
bool init();
};
Simple implementation
slD3D11ShaderSolid::slD3D11ShaderSolid(slGSD3D11* gs)
:
m_gs(gs)
{}
slD3D11ShaderSolid::~slD3D11ShaderSolid()
{
if (m_cbV)m_cbV->Release();
if (m_cbP)m_cbP->Release();
}
bool slD3D11ShaderSolid::init(){
const char* text =
"struct VSIn{\n"
" float3 position : POSITION;\n"
" float2 uv : TEXCOORD;\n"
" float3 normal : NORMAL;\n"
" float3 binormal : BINORMAL;\n"
" float3 tangent : TANGENT;\n"
" float4 color : COLOR;\n"
"};\n"
"cbuffer cbVertex{\n"
" double4x4 WVP;\n"
" double4x4 W;\n"
"};\n"
"cbuffer cbPixel{\n"
" double4 SunPosition;\n"
" float4 BaseColor;\n"
"};\n"
"struct VSOut{\n"
" float4 pos : SV_POSITION;\n"
" float2 uv : TEXCOORD0;\n"
" float4 vColor : COLOR0;\n"
" float3 normal : NORMAL0;\n"
" float4 fragPos : NORMAL1;\n"
"};\n"
"struct PSOut{\n"
" float4 color : SV_Target;\n"
"};\n"
"VSOut VSMain(VSIn input){\n"
" VSOut output;\n"
" output.pos = mul(WVP, double4(input.position.x, input.position.y, input.position.z, 1.0));\n"
" output.uv.x = input.uv.x;\n"
" output.uv.y = input.uv.y;\n"
" output.vColor = input.color;\n"
" output.normal = normalize(mul((double3x3)W, input.normal));\n"
" output.fragPos = mul(W, double4(input.position.x, input.position.y, input.position.z, 1.0));\n"
" return output;\n"
"}\n"
"PSOut PSMain(VSOut input){\n"
" float3 lightDir = normalize(-SunPosition.xyz);\n"
" float diff = max(dot(input.normal, -lightDir), 0.0);\n"
" PSOut output;\n"
//" output.color = tex2d_1.Sample(tex2D_sampler_1, input.uv) * BaseColor;\n"
" output.color = BaseColor;\n"
//" output.color.w += input.vColor.w;\n"
//" if(output.color.w>1.f) output.color.w = 1.f;\n"
//" output.color.xyz = lerp(output.color.xyz, input.vColor.xyz, input.vColor.www);\n"
" if(diff>1.f) diff = 1.f;\n"
" output.color.xyz *= diff;\n"
" output.color.w = 1.f;\n"
//" if(output.color.w == 0.f) if(input.vColor.w!=1.f)discard;\n"
" return output;\n"
"}\n";
if (!m_gs->createShaders(
"vs_5_0",
"ps_5_0",
text,
text,
"VSMain",
"PSMain",
slMeshVertexType::Triangle,
&this->m_vShader,
&this->m_pShader,
&this->m_vLayout))
return false;
if (!m_gs->createConstantBuffer(sizeof(cbV), &m_cbV))
return false;
if (!m_gs->createConstantBuffer(sizeof(cbP), &m_cbP))
return false;
return true;
}
void slD3D11ShaderSolid::SetData(const slMat4& WVP, const slMat4& W)
{
m_cbDataV.W = W;
m_cbDataV.WVP = WVP;
}
void slD3D11ShaderSolid::SetConstants(slMaterial* material){
{
D3D11_MAPPED_SUBRESOURCE mappedResource;
D3D11_BUFFER_DESC d;
m_gs->m_d3d11DevCon->Map(m_cbV, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
m_cbV->GetDesc(&d);
memcpy(mappedResource.pData, &m_cbDataV, d.ByteWidth);
m_gs->m_d3d11DevCon->Unmap(m_cbV, 0);
m_gs->m_d3d11DevCon->VSSetConstantBuffers(0, 1, &m_cbV);
}
m_cbDataP.BaseColor = material->m_colorDiffuse;
m_cbDataP.SunPosition = material->m_sunPosition;
{
D3D11_MAPPED_SUBRESOURCE mappedResource;
D3D11_BUFFER_DESC d;
m_gs->m_d3d11DevCon->Map(m_cbP, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
m_cbP->GetDesc(&d);
memcpy(mappedResource.pData, &m_cbDataP, d.ByteWidth);
m_gs->m_d3d11DevCon->Unmap(m_cbP, 0);
m_gs->m_d3d11DevCon->PSSetConstantBuffers(0, 1, &m_cbP);
}
}
Update slGSD3D11::createShaders
Need to create input layout. I don't know how it works,
I think every shader must have unique input layout.
And I think I can create static global arrays instead if this:
int ind = 0;
switch (vertexType)
{
case slMeshVertexType::Triangle:
ind = 0;
vertexLayout[ind].SemanticName = "POSITION";
vertexLayout[ind].SemanticIndex = 0;
vertexLayout[ind].Format = DXGI_FORMAT_R32G32B32_FLOAT;
vertexLayout[ind].InputSlot = 0;
vertexLayout[ind].AlignedByteOffset = 0;
vertexLayout[ind].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
vertexLayout[ind].InstanceDataStepRate = 0;
ind++;
vertexLayout[ind].SemanticName = "TEXCOORD";
vertexLayout[ind].SemanticIndex = 0;
vertexLayout[ind].Format = DXGI_FORMAT_R32G32_FLOAT;
vertexLayout[ind].InputSlot = 0;
vertexLayout[ind].AlignedByteOffset = 12;
vertexLayout[ind].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
vertexLayout[ind].InstanceDataStepRate = 0;
ind++;
vertexLayout[ind].SemanticName = "NORMAL";
vertexLayout[ind].SemanticIndex = 0;
vertexLayout[ind].Format = DXGI_FORMAT_R32G32B32_FLOAT;
vertexLayout[ind].InputSlot = 0;
vertexLayout[ind].AlignedByteOffset = 20;
vertexLayout[ind].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
vertexLayout[ind].InstanceDataStepRate = 0;
ind++;
vertexLayout[ind].SemanticName = "BINORMAL";
vertexLayout[ind].SemanticIndex = 0;
vertexLayout[ind].Format = DXGI_FORMAT_R32G32B32_FLOAT;
vertexLayout[ind].InputSlot = 0;
vertexLayout[ind].AlignedByteOffset = 32;
vertexLayout[ind].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
vertexLayout[ind].InstanceDataStepRate = 0;
ind++;
vertexLayout[ind].SemanticName = "TANGENT";
vertexLayout[ind].SemanticIndex = 0;
vertexLayout[ind].Format = DXGI_FORMAT_R32G32B32_FLOAT;
vertexLayout[ind].InputSlot = 0;
vertexLayout[ind].AlignedByteOffset = 44;
vertexLayout[ind].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
vertexLayout[ind].InstanceDataStepRate = 0;
ind++;
vertexLayout[ind].SemanticName = "COLOR";
vertexLayout[ind].SemanticIndex = 0;
vertexLayout[ind].Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
vertexLayout[ind].InputSlot = 0;
vertexLayout[ind].AlignedByteOffset = 56;
vertexLayout[ind].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
vertexLayout[ind].InstanceDataStepRate = 0;
break;
}
vertexLayoutSize = ind + 1;
How to use
This is not very simple way to load a model.
The Idea of this library is write simple layer,
then write anoter layer like above first layer.
For exmaple, model class in Demo
class MyModel {
slGS* m_gs = 0;
slArray<slGPUMesh*> m_meshBuffers;
slMaterial m_material;
slMat4 m_W;
slMat4 m_WVP;
public:
MyModel(slGS* gs):m_gs(gs) {}
~MyModel()
{
for (size_t i = 0; i < m_meshBuffers.m_size; ++i)
{
slDestroy(m_meshBuffers.m_data[i]);
}
}
class cb : public slMeshLoaderCallback
{
public:
cb(){}
virtual ~cb() {}
virtual void OnMaterial(slMaterial* m, slString* name) override{}
virtual void OnMesh(slMesh* newMesh, slString* name, slString* materialName) override{
if (newMesh)
{
slGPUMesh* gpumesh = m_model->m_gs->SummonMesh(newMesh);
if(gpumesh)
m_model->m_meshBuffers.push_back(gpumesh);
slDestroy(newMesh);
}
}
MyModel* m_model = 0;
}
m_cb;
bool Load(const char* p)
{
m_cb.m_model = this;
slFramework::LoadMesh(p, &m_cb);
return m_meshBuffers.m_size > 0;
}
void Draw(slCamera* camera)
{
m_WVP = camera->m_projectionMatrix * camera->m_viewMatrix * m_W;
m_material.m_sunPosition.set(0.f, 1.f, 0.f);
slFramework::SetMatrix(slMatrixType::World, &m_W);
slFramework::SetMatrix(slMatrixType::WorldViewProjection, &m_WVP);
for (size_t i = 0; i < m_meshBuffers.m_size; ++i)
{
m_gs->SetMesh(m_meshBuffers.m_data[i]);
m_gs->SetMaterial(&m_material);
m_gs->Draw();
}
}
void SetPosition(const slVec3& p)
{
m_W.m_data[3] = p;
m_W.m_data[3].w = 1.f;
}
};
...
MyModel* mm = slCreate<MyModel>(gs);
if (mm->Load(slFramework::GetPathA("..\\data\\4_objs.obj").c_str()))
{
printf("LOADED!\n");
}
mm->SetPosition(globalPosition);
...
// drawing
mm->Draw(camera);
4 models
Other things
Using this function I can open files even if program have other working directory
(for example if it launched from cmd)
slString slFramework::GetAppPath()
{
return g_framework->m_appPath;
}
slStringA slFramework::GetPathA(const slString& v)
{
slString p = g_framework->m_appPath;
p.append(v);
slStringA stra;
p.to_utf8(stra);
return stra;
}
Download
Please enable JavaScript to view the comments powered by Disqus.