SDL2: Mouse is back ! With correct focus support SDL2: Added typing support with keyboard ShaderBuilder: Refactored and simplified Shader block creation Several warning removal Fixed Image::Copyundefined
@@ -39,12 +39,13 @@ public: | |||||
WorldEntity::TickGame(seconds); | WorldEntity::TickGame(seconds); | ||||
m_time += seconds; | m_time += seconds; | ||||
m_hotspot = 0.4f * vec3(lol::sin(m_time * 4.f) + lol::cos(m_time * 5.3f), | |||||
lol::sin(m_time * 5.7f) + lol::cos(m_time * 4.4f), | |||||
lol::sin(m_time * 5.f)); | |||||
m_color = 0.25f * vec3(1.1f + lol::sin(m_time * 2.5f + 1.f), | |||||
1.1f + lol::sin(m_time * 2.8f + 1.3f), | |||||
1.1f + lol::sin(m_time * 2.7f)); | |||||
m_hotspot = 0.4f * vec3( | |||||
lol::sin((float)m_time * 4.f) + lol::cos((float)m_time * 5.3f), | |||||
lol::sin((float)m_time * 5.7f) + lol::cos((float)m_time * 4.4f), | |||||
lol::sin((float)m_time * 5.f)); | |||||
m_color = 0.25f * vec3(1.1f + lol::sin((float)m_time * 2.5f + 1.f), | |||||
1.1f + lol::sin((float)m_time * 2.8f + 1.3f), | |||||
1.1f + lol::sin((float)m_time * 2.7f)); | |||||
/* Saturate dot color */ | /* Saturate dot color */ | ||||
float x = std::max(m_color.x, std::max(m_color.y, m_color.z)); | float x = std::max(m_color.x, std::max(m_color.y, m_color.z)); | ||||
m_color /= x; | m_color /= x; | ||||
@@ -45,58 +45,63 @@ public: | |||||
ShaderBlock green_pixel("GreenPixel"); | ShaderBlock green_pixel("GreenPixel"); | ||||
ShaderBlock blue_pixel("BluePixel"); | ShaderBlock blue_pixel("BluePixel"); | ||||
String vertex_out = Shader::GetProgramOutVariableLocal(ShaderProgram::Vertex); | |||||
String pixel_out = Shader::GetProgramOutVariableLocal(ShaderProgram::Pixel); | |||||
String in_position = Shader::GetVariablePrefix(ShaderVariable::Attribute) + "position"; | |||||
String in_color = Shader::GetVariablePrefix(ShaderVariable::Attribute) + "color"; | |||||
String pass_color = Shader::GetVariablePrefix(ShaderVariable::Varying) + "color"; | |||||
nothing_vertex.Add(ShaderVariable::Attribute, "vec3", "position"); | |||||
nothing_vertex.Add(ShaderVariable::Attribute, "vec4", "color"); | |||||
nothing_vertex.Add(ShaderVariable::Varying, "vec4", "color"); | |||||
nothing_vertex.Add(ShaderVariable::InOut, "vec4", vertex_out); | |||||
nothing_vertex.SetMainCode( | |||||
String(" ") + pass_color + " = " + in_color + ";\n" + | |||||
String(" ") + vertex_out + " = vec4(" + in_position + ", 0.f);\n" | |||||
ShaderVar out_vertex = ShaderVar::GetShaderOut(ShaderProgram::Vertex); | |||||
ShaderVar out_pixel = ShaderVar::GetShaderOut(ShaderProgram::Pixel); | |||||
ShaderVar in_position = ShaderVar(ShaderVariable::Attribute, ShaderVariableType::Vec3, "position"); | |||||
ShaderVar in_color = ShaderVar(ShaderVariable::Attribute, ShaderVariableType::Vec4, "color"); | |||||
ShaderVar pass_color = ShaderVar(ShaderVariable::Varying, ShaderVariableType::Vec4, "color"); | |||||
nothing_vertex << in_position | |||||
<< in_color | |||||
<< pass_color; | |||||
nothing_vertex.AddVar(out_vertex); | |||||
nothing_vertex.SetMainCode(String() + | |||||
Line(pass_color + " = " + in_color + ";") + | |||||
Line(out_vertex + " = vec4(" + in_position + ", 0.f);") | |||||
); | ); | ||||
red_pixel.Add(ShaderVariable::Varying, "vec4", "color"); | |||||
red_pixel.Add(ShaderVariable::InOut, "vec4", pixel_out); | |||||
red_pixel.Add(ShaderVariable::InOut, "vec4", "ambient"); | |||||
red_pixel.SetMainCode( | |||||
String(" ") + pixel_out + " = " + pass_color + ";\n" + | |||||
String(" ") + pixel_out + ".r = 1.0;\n" + | |||||
String(" ") + "ambient = vec4(1.0);\n" | |||||
ShaderVar ambient = ShaderVar(ShaderVariable::InOut, ShaderVariableType::Vec4, "ambient"); | |||||
red_pixel.AddVar(pass_color); | |||||
red_pixel.AddVar(out_pixel); | |||||
red_pixel.AddVar(ambient); | |||||
red_pixel.SetMainCode(String() + | |||||
out_pixel + " = " + pass_color + ";\n" + | |||||
out_pixel + ".r = 1.0;\n" + | |||||
"ambient = vec4(1.0);\n" | |||||
); | ); | ||||
green_pixel.Add(ShaderVariable::Varying, "vec4", "color"); | |||||
green_pixel.Add(ShaderVariable::InOut, "vec4", pixel_out); | |||||
green_pixel.Add(ShaderVariable::InOut, "vec4", "ambient"); | |||||
green_pixel.SetMainCode( | |||||
String(" ") + pixel_out + " = " + pass_color + ";\n" + | |||||
String(" ") + pixel_out + ".g = 1.0;\n" + | |||||
String(" ") + "ambient.r = 0.0;\n" | |||||
green_pixel.AddVar(pass_color); | |||||
green_pixel.AddVar(out_pixel); | |||||
green_pixel.AddVar(ambient); | |||||
green_pixel.SetMainCode(String() + | |||||
out_pixel + " = " + pass_color + ";\n" + | |||||
out_pixel + ".g = 1.0;\n" + | |||||
"ambient.r = 0.0;\n" | |||||
); | ); | ||||
blue_pixel.Add(ShaderVariable::Varying, "vec4", "color"); | |||||
blue_pixel.Add(ShaderVariable::InOut, "vec4", pixel_out); | |||||
blue_pixel.Add(ShaderVariable::InOut, "vec4", "ambient"); | |||||
blue_pixel.SetCustomCode( | |||||
String("void SetAmbient(inout vec4 ambient)\n{\n ambient = vec4(1.0, 1.0, 1.0, 1.0);\n}")); | |||||
blue_pixel.SetMainCode( | |||||
String(" ") + pixel_out + " = " + pass_color + ";\n" + | |||||
String(" ") + pixel_out + ".b = 1.0;\n" + | |||||
String(" ") + "SetAmbient(ambient);\n" + | |||||
String(" ") + pixel_out + " *= ambient;\n" | |||||
blue_pixel.AddVar(pass_color); | |||||
blue_pixel.AddVar(out_pixel); | |||||
blue_pixel.AddVar(ambient); | |||||
blue_pixel.SetCustomCode(String() + | |||||
"void SetAmbient(inout vec4 ambient)\n" + | |||||
"{\n" + | |||||
" ambient = vec4(1.0, 1.0, 1.0, 1.0);\n" + | |||||
"}\n"); | |||||
blue_pixel.SetMainCode(String() + | |||||
out_pixel + " = " + pass_color + ";\n" + | |||||
out_pixel + ".b = 1.0;\n" + | |||||
"SetAmbient(ambient);\n" + | |||||
out_pixel + " *= ambient;\n" | |||||
); | ); | ||||
builder << ShaderProgram::Vertex | builder << ShaderProgram::Vertex | ||||
<< ¬hing_vertex | |||||
<< nothing_vertex | |||||
<< ShaderProgram::Pixel | << ShaderProgram::Pixel | ||||
<< &red_pixel | |||||
<< &green_pixel | |||||
<< &blue_pixel; | |||||
<< red_pixel | |||||
<< green_pixel | |||||
<< blue_pixel; | |||||
builder.Build(code); | builder.Build(code); | ||||
@@ -442,7 +442,7 @@ Shader::Shader(String const &name, | |||||
int Shader::GetAttribCount() const | int Shader::GetAttribCount() const | ||||
{ | { | ||||
return data->attrib_locations.count(); | |||||
return (int)data->attrib_locations.count(); | |||||
} | } | ||||
ShaderAttrib Shader::GetAttribLocation(VertexUsage usage, int index) const | ShaderAttrib Shader::GetAttribLocation(VertexUsage usage, int index) const | ||||
@@ -469,6 +469,10 @@ ShaderAttrib Shader::GetAttribLocation(VertexUsage usage, int index) const | |||||
return ret; | return ret; | ||||
} | } | ||||
ShaderUniform Shader::GetUniformLocation(String const& uni) const | |||||
{ | |||||
return GetUniformLocation(uni.C()); | |||||
} | |||||
ShaderUniform Shader::GetUniformLocation(char const *uni) const | ShaderUniform Shader::GetUniformLocation(char const *uni) const | ||||
{ | { | ||||
ShaderUniform ret; | ShaderUniform ret; | ||||
@@ -514,7 +518,7 @@ void Shader::SetUniform(ShaderUniform const &uni, int i) | |||||
#if defined USE_D3D9 || defined _XBOX | #if defined USE_D3D9 || defined _XBOX | ||||
SetUniform(uni, ivec4(i, 0, 0, 0)); | SetUniform(uni, ivec4(i, 0, 0, 0)); | ||||
#else | #else | ||||
glUniform1i(uni.frag, i); | |||||
glUniform1i((GLint)uni.frag, i); | |||||
#endif | #endif | ||||
} | } | ||||
@@ -523,7 +527,7 @@ void Shader::SetUniform(ShaderUniform const &uni, ivec2 const &v) | |||||
#if defined USE_D3D9 || defined _XBOX | #if defined USE_D3D9 || defined _XBOX | ||||
SetUniform(uni, ivec4(v, 0, 0)); | SetUniform(uni, ivec4(v, 0, 0)); | ||||
#else | #else | ||||
glUniform2i(uni.frag, v.x, v.y); | |||||
glUniform2i((GLint)uni.frag, v.x, v.y); | |||||
#endif | #endif | ||||
} | } | ||||
@@ -532,7 +536,7 @@ void Shader::SetUniform(ShaderUniform const &uni, ivec3 const &v) | |||||
#if defined USE_D3D9 || defined _XBOX | #if defined USE_D3D9 || defined _XBOX | ||||
SetUniform(uni, ivec4(v, 0)); | SetUniform(uni, ivec4(v, 0)); | ||||
#else | #else | ||||
glUniform3i(uni.frag, v.x, v.y, v.z); | |||||
glUniform3i((GLint)uni.frag, v.x, v.y, v.z); | |||||
#endif | #endif | ||||
} | } | ||||
@@ -544,7 +548,7 @@ void Shader::SetUniform(ShaderUniform const &uni, ivec4 const &v) | |||||
if (uni.flags & 2) | if (uni.flags & 2) | ||||
data->m_dev->SetVertexShaderConstantI((UINT)uni.vert, &v[0], 1); | data->m_dev->SetVertexShaderConstantI((UINT)uni.vert, &v[0], 1); | ||||
#else | #else | ||||
glUniform4i(uni.frag, v.x, v.y, v.z, v.w); | |||||
glUniform4i((GLint)uni.frag, v.x, v.y, v.z, v.w); | |||||
#endif | #endif | ||||
} | } | ||||
@@ -553,7 +557,7 @@ void Shader::SetUniform(ShaderUniform const &uni, float f) | |||||
#if defined USE_D3D9 || defined _XBOX | #if defined USE_D3D9 || defined _XBOX | ||||
SetUniform(uni, vec4(f, 0, 0, 0)); | SetUniform(uni, vec4(f, 0, 0, 0)); | ||||
#else | #else | ||||
glUniform1f(uni.frag, f); | |||||
glUniform1f((GLint)uni.frag, f); | |||||
#endif | #endif | ||||
} | } | ||||
@@ -562,7 +566,7 @@ void Shader::SetUniform(ShaderUniform const &uni, vec2 const &v) | |||||
#if defined USE_D3D9 || defined _XBOX | #if defined USE_D3D9 || defined _XBOX | ||||
SetUniform(uni, vec4(v, 0, 0)); | SetUniform(uni, vec4(v, 0, 0)); | ||||
#else | #else | ||||
glUniform2fv(uni.frag, 1, &v[0]); | |||||
glUniform2fv((GLint)uni.frag, 1, &v[0]); | |||||
#endif | #endif | ||||
} | } | ||||
@@ -571,7 +575,7 @@ void Shader::SetUniform(ShaderUniform const &uni, vec3 const &v) | |||||
#if defined USE_D3D9 || defined _XBOX | #if defined USE_D3D9 || defined _XBOX | ||||
SetUniform(uni, vec4(v, 0)); | SetUniform(uni, vec4(v, 0)); | ||||
#else | #else | ||||
glUniform3fv(uni.frag, 1, &v[0]); | |||||
glUniform3fv((GLint)uni.frag, 1, &v[0]); | |||||
#endif | #endif | ||||
} | } | ||||
@@ -583,7 +587,7 @@ void Shader::SetUniform(ShaderUniform const &uni, vec4 const &v) | |||||
if (uni.flags & 2) | if (uni.flags & 2) | ||||
data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, &v[0], 1); | data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, &v[0], 1); | ||||
#else | #else | ||||
glUniform4fv(uni.frag, 1, &v[0]); | |||||
glUniform4fv((GLint)uni.frag, 1, &v[0]); | |||||
#endif | #endif | ||||
} | } | ||||
@@ -596,7 +600,7 @@ void Shader::SetUniform(ShaderUniform const &uni, mat2 const &m) | |||||
if (uni.flags & 2) | if (uni.flags & 2) | ||||
data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, &m[0][0], 1); | data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, &m[0][0], 1); | ||||
#else | #else | ||||
glUniformMatrix2fv(uni.frag, 1, GL_FALSE, &m[0][0]); | |||||
glUniformMatrix2fv((GLint)uni.frag, 1, GL_FALSE, &m[0][0]); | |||||
#endif | #endif | ||||
} | } | ||||
@@ -611,7 +615,7 @@ void Shader::SetUniform(ShaderUniform const &uni, mat3 const &m) | |||||
if (uni.flags & 2) | if (uni.flags & 2) | ||||
data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, &tmp[0][0], 3); | data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, &tmp[0][0], 3); | ||||
#else | #else | ||||
glUniformMatrix3fv(uni.frag, 1, GL_FALSE, &m[0][0]); | |||||
glUniformMatrix3fv((GLint)uni.frag, 1, GL_FALSE, &m[0][0]); | |||||
#endif | #endif | ||||
} | } | ||||
@@ -623,7 +627,7 @@ void Shader::SetUniform(ShaderUniform const &uni, mat4 const &m) | |||||
if (uni.flags & 2) | if (uni.flags & 2) | ||||
data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, &m[0][0], 4); | data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, &m[0][0], 4); | ||||
#else | #else | ||||
glUniformMatrix4fv(uni.frag, 1, GL_FALSE, &m[0][0]); | |||||
glUniformMatrix4fv((GLint)uni.frag, 1, GL_FALSE, &m[0][0]); | |||||
#endif | #endif | ||||
} | } | ||||
@@ -658,7 +662,7 @@ void Shader::SetUniform(ShaderUniform const &uni, array<float> const &v) | |||||
data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, | data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, | ||||
&v[0], v.Count() / 4); | &v[0], v.Count() / 4); | ||||
#else | #else | ||||
glUniform1fv(uni.frag, v.Count(), &v[0]); | |||||
glUniform1fv((GLint)uni.frag, (GLsizei)v.Count(), &v[0]); | |||||
#endif | #endif | ||||
} | } | ||||
@@ -674,7 +678,7 @@ void Shader::SetUniform(ShaderUniform const &uni, array<vec2> const &v) | |||||
data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, | data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, | ||||
&v[0][0], v.Count() / 2); | &v[0][0], v.Count() / 2); | ||||
#else | #else | ||||
glUniform2fv(uni.frag, v.Count(), &v[0][0]); | |||||
glUniform2fv((GLint)uni.frag, (GLsizei)v.Count(), &v[0][0]); | |||||
#endif | #endif | ||||
} | } | ||||
@@ -690,7 +694,7 @@ void Shader::SetUniform(ShaderUniform const &uni, array<vec3> const &v) | |||||
data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, | data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, | ||||
&v[0][0], v.Count()); | &v[0][0], v.Count()); | ||||
#else | #else | ||||
glUniform3fv(uni.frag, v.Count(), &v[0][0]); | |||||
glUniform3fv((GLint)uni.frag, (GLsizei)v.Count(), &v[0][0]); | |||||
#endif | #endif | ||||
} | } | ||||
@@ -704,7 +708,7 @@ void Shader::SetUniform(ShaderUniform const &uni, array<vec4> const &v) | |||||
data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, | data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, | ||||
&v[0][0], v.Count()); | &v[0][0], v.Count()); | ||||
#else | #else | ||||
glUniform4fv(uni.frag, v.Count(), &v[0][0]); | |||||
glUniform4fv((GLint)uni.frag, (GLsizei)v.Count(), &v[0][0]); | |||||
#endif | #endif | ||||
} | } | ||||
@@ -934,6 +938,9 @@ String ShaderData::Patch(String const &code, ShaderType type) | |||||
} | } | ||||
static const String g_ret = "\n"; | static const String g_ret = "\n"; | ||||
static const String g_eol = ";"; | |||||
static const String g_bop = "{"; | |||||
static const String g_bcl = "}"; | |||||
static const String g_tab = " "; | static const String g_tab = " "; | ||||
//---- | //---- | ||||
@@ -1008,7 +1015,7 @@ String Shader::GetProgramQualifier(const ShaderProgram program) | |||||
{ | { | ||||
switch (program.ToScalar()) | switch (program.ToScalar()) | ||||
{ | { | ||||
case ShaderProgram::Geometry: return String(); //TODO : L O L ---------------- | |||||
case ShaderProgram::Geometry: return String(); //TODO : L O L --------- | |||||
case ShaderProgram::Vertex: return String("[vert.glsl]"); | case ShaderProgram::Vertex: return String("[vert.glsl]"); | ||||
case ShaderProgram::Pixel: return String("[frag.glsl]"); | case ShaderProgram::Pixel: return String("[frag.glsl]"); | ||||
default: return String(); | default: return String(); | ||||
@@ -1020,7 +1027,7 @@ String Shader::GetProgramOutVariable(const ShaderProgram program) | |||||
{ | { | ||||
switch (program.ToScalar()) | switch (program.ToScalar()) | ||||
{ | { | ||||
case ShaderProgram::Geometry: return String(); //TODO : L O L ---------------- | |||||
case ShaderProgram::Geometry: return String(); //TODO : L O L --------- | |||||
case ShaderProgram::Vertex: return String("gl_Position"); | case ShaderProgram::Vertex: return String("gl_Position"); | ||||
case ShaderProgram::Pixel: return String("gl_FragColor"); | case ShaderProgram::Pixel: return String("gl_FragColor"); | ||||
default: return String(); | default: return String(); | ||||
@@ -1032,29 +1039,44 @@ String Shader::GetProgramOutVariableLocal(const ShaderProgram program) | |||||
{ | { | ||||
switch (program.ToScalar()) | switch (program.ToScalar()) | ||||
{ | { | ||||
case ShaderProgram::Geometry: return String(); //TODO : L O L ---------------- | |||||
case ShaderProgram::Geometry: return String(); //TODO : L O L --------- | |||||
case ShaderProgram::Vertex: return String("out_position"); | case ShaderProgram::Vertex: return String("out_position"); | ||||
case ShaderProgram::Pixel: return String("out_frag_color"); | case ShaderProgram::Pixel: return String("out_frag_color"); | ||||
default: return String(); | default: return String(); | ||||
} | } | ||||
} | } | ||||
//ShaderVar ------------------------------------------------------------------- | |||||
ShaderVar ShaderVar::GetShaderOut(ShaderProgram program) | |||||
{ | |||||
switch (program.ToScalar()) | |||||
{ | |||||
case ShaderProgram::Geometry: //TODO : L O L ------------------------------ | |||||
default: ASSERT(false); return ShaderVar(); | |||||
case ShaderProgram::Vertex: return ShaderVar(ShaderVariable::InOut, ShaderVariableType::Vec4, Shader::GetProgramOutVariableLocal(program)); | |||||
case ShaderProgram::Pixel: return ShaderVar(ShaderVariable::InOut, ShaderVariableType::Vec4, Shader::GetProgramOutVariableLocal(program)); | |||||
} | |||||
} | |||||
//Shader Block implementation class ------------------------------------------- | //Shader Block implementation class ------------------------------------------- | ||||
void ShaderBlock::Add(const ShaderVariable parameter, String const &type, String const &name) | |||||
void ShaderBlock::AddVar(ShaderVar const& var) | |||||
{ | { | ||||
ASSERT(!m_parameters[parameter.ToScalar()].has_key(name)); | |||||
m_parameters[parameter.ToScalar()][name] = type; | |||||
ShaderVariable qualifier = var.GetQualifier(); | |||||
String type = var.GetType(); | |||||
String name = Shader::GetVariablePrefix(qualifier) + var.m_name; | |||||
ASSERT(!m_parameters[qualifier.ToScalar()].has_key(name)); | |||||
m_parameters[qualifier.ToScalar()][name] = type; | |||||
} | } | ||||
//---- | //---- | ||||
void ShaderBlock::AddCallParameters(const ShaderVariable type, map<String, String> const& variables, String& result) | |||||
void ShaderBlock::AddCallParameters(map<String, String> const& variables, String& result) | |||||
{ | { | ||||
array<String> keys = variables.keys(); | array<String> keys = variables.keys(); | ||||
for (String key : keys) | for (String key : keys) | ||||
{ | { | ||||
if (result.Count() > 0) | if (result.Count() > 0) | ||||
result += ", "; | result += ", "; | ||||
result += Shader::GetVariablePrefix(type) + key; | |||||
result += key; | |||||
} | } | ||||
} | } | ||||
@@ -1069,7 +1091,6 @@ void ShaderBlock::AddDefinitionParameters(const ShaderVariable type, const Shade | |||||
result += Shader::GetFunctionQualifier(type, program) + " "; | result += Shader::GetFunctionQualifier(type, program) + " "; | ||||
result += variables[key]; | result += variables[key]; | ||||
result += String(" "); | result += String(" "); | ||||
result += Shader::GetVariablePrefix(type); | |||||
result += key; | result += key; | ||||
} | } | ||||
} | } | ||||
@@ -1085,7 +1106,7 @@ void ShaderBlock::Build(const ShaderProgram program, String& call, String& funct | |||||
call = call_name + "("; | call = call_name + "("; | ||||
String call_parameters; | String call_parameters; | ||||
for (int i = 0; i < ShaderVariable::MAX; i++) | for (int i = 0; i < ShaderVariable::MAX; i++) | ||||
AddCallParameters((ShaderVariable)i, m_parameters[i], call_parameters); | |||||
AddCallParameters(/*(ShaderVariable)i, */m_parameters[i], call_parameters); | |||||
call += call_parameters + ");"; | call += call_parameters + ");"; | ||||
//Build function declaration | //Build function declaration | ||||
@@ -1133,6 +1154,14 @@ ShaderBuilder& ShaderBuilder::operator<<(ShaderBlock* block) | |||||
return *this; | return *this; | ||||
} | } | ||||
//---- | |||||
ShaderBuilder& ShaderBuilder::operator<<(ShaderBlock const& block) | |||||
{ | |||||
ASSERT(m_current_program != ShaderProgram::MAX); | |||||
m_blocks[m_current_program.ToScalar()].PushUnique(new ShaderBlock(block)); | |||||
return *this; | |||||
} | |||||
//---- | //---- | ||||
String ShaderBuilder::AddSlotOutVariableLocal(const ShaderProgram program) | String ShaderBuilder::AddSlotOutVariableLocal(const ShaderProgram program) | ||||
{ | { | ||||
@@ -1170,8 +1199,11 @@ void ShaderBuilder::MergeParameters(map<String, String>& variables, map<String, | |||||
for (String key : keys) | for (String key : keys) | ||||
{ | { | ||||
bool has_key = merged.has_key(key); | bool has_key = merged.has_key(key); | ||||
//Key exists, check the type to make sure it's the same | //Key exists, check the type to make sure it's the same | ||||
ASSERT(!(has_key && merged[key] != variables[key])); | |||||
ASSERT(!has_key || (has_key && merged[key] == variables[key]), | |||||
"has_key=%d, key=%s merged[key]=%s, variables[key]=%s\n", | |||||
(int)has_key, key.C(), merged[key].C(), variables[key].C()); | |||||
//does not exist, had it | //does not exist, had it | ||||
if (!has_key) | if (!has_key) | ||||
@@ -1217,8 +1249,7 @@ void ShaderBuilder::Build(String& code) | |||||
for (String key : keys) | for (String key : keys) | ||||
{ | { | ||||
code += Shader::GetVariableQualifier((ShaderVariable)var) + " "; | code += Shader::GetVariableQualifier((ShaderVariable)var) + " "; | ||||
code += m_parameters[prog][var][key] + " " + | |||||
Shader::GetVariablePrefix((ShaderVariable)var) + key + ";" + g_ret; | |||||
code += m_parameters[prog][var][key] + " " + key + ";" + g_ret; | |||||
} | } | ||||
if (var + 1 < ShaderVariable::InOut) | if (var + 1 < ShaderVariable::InOut) | ||||
code += g_ret; | code += g_ret; | ||||
@@ -1254,8 +1285,7 @@ void ShaderBuilder::Build(String& code) | |||||
{ | { | ||||
if (keys.Count()) | if (keys.Count()) | ||||
{ | { | ||||
code += g_tab + m_parameters[prog][var][key] + " " + | |||||
Shader::GetVariablePrefix((ShaderVariable)var) + key + ";" + g_ret; | |||||
code += g_tab + m_parameters[prog][var][key] + " " + key + ";" + g_ret; | |||||
} | } | ||||
} | } | ||||
code += g_ret; | code += g_ret; | ||||
@@ -55,6 +55,55 @@ String Color::HexString8Bpp(vec4 c) | |||||
return String::Printf("%02x%2x%02x%02x", c2.r, c2.g, c2.b, c2.a); | return String::Printf("%02x%2x%02x%02x", c2.r, c2.g, c2.b, c2.a); | ||||
} | } | ||||
/* | |||||
* Convert uint color to vec4. | |||||
*/ | |||||
vec4 Color::FromRGBA32(uint32_t c) | |||||
{ | |||||
ivec4 v(c >> 24, (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff); | |||||
return vec4(v) * (1.f / 255.f); | |||||
} | |||||
vec4 Color::FromRGB32(uint32_t c) | |||||
{ | |||||
return Color::FromRGBA32((c << 8) | 0x000000ffu); | |||||
} | |||||
vec4 Color::FromRGBA16(uint16_t c) | |||||
{ | |||||
return Color::FromRGBA32 | |||||
( 0x11000000u * (c >> 12) | |||||
| 0x00110000u * ((c >> 8) & 0xf) | |||||
| 0x00001100u * ((c >> 4) & 0xf) | |||||
| 0x00000011u * (c & 0xf)); | |||||
} | |||||
vec4 Color::FromRGB16(uint16_t c) | |||||
{ | |||||
return Color::FromRGBA16((c << 4) | 0xfu); | |||||
} | |||||
/* | |||||
* Convert uint color to vec4. | |||||
*/ | |||||
uint32_t Color::ToRGBA32(vec4 c) | |||||
{ | |||||
ivec4 v(c * 0xff); | |||||
return (uint32_t)((v.r << 24) | (v.g << 16) | (v.b << 8) | v.a); | |||||
} | |||||
uint32_t Color::ToRGB32(vec4 c) | |||||
{ | |||||
ivec4 v(c * 0xff); | |||||
return (uint32_t)((v.r << 16) | (v.g << 8) | v.b); | |||||
} | |||||
uint16_t Color::ToRGBA16(vec4 c) | |||||
{ | |||||
ivec4 v(c * 0xf); | |||||
return (uint16_t)((v.r << 12) | (v.g << 8) | (v.b << 4) | v.a); | |||||
} | |||||
uint16_t Color::ToRGB16(vec4 c) | |||||
{ | |||||
ivec4 v(c * 0xf); | |||||
return (uint16_t)((v.r << 8) | (v.g << 4) | v.b); | |||||
} | |||||
/* | /* | ||||
* Conversion from colours to hexadecimal | * Conversion from colours to hexadecimal | ||||
*/ | */ | ||||
@@ -133,8 +133,8 @@ void Image::DummyFill() | |||||
void Image::Copy(uint8_t* pixels, ivec2 const& size, PixelFormat fmt) | void Image::Copy(uint8_t* pixels, ivec2 const& size, PixelFormat fmt) | ||||
{ | { | ||||
ASSERT(fmt != PixelFormat::Unknown); | ASSERT(fmt != PixelFormat::Unknown); | ||||
SetFormat(fmt); | |||||
SetSize(size); | SetSize(size); | ||||
SetFormat(fmt); | |||||
memcpy(m_data->m_pixels[(int)fmt]->data(), pixels, | memcpy(m_data->m_pixels[(int)fmt]->data(), pixels, | ||||
size.x * size.y * BytesPerPixel(fmt)); | size.x * size.y * BytesPerPixel(fmt)); | ||||
} | } | ||||
@@ -19,13 +19,77 @@ using namespace lol; | |||||
//----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||||
LolImGui::LolImGui() | LolImGui::LolImGui() | ||||
{ | { | ||||
m_gamegroup = GAMEGROUP_BEFORE; | |||||
m_drawgroup = DRAWGROUP_HUD; | m_drawgroup = DRAWGROUP_HUD; | ||||
//Build shader code ------------------------------------------------------- | |||||
ShaderVar out_vertex = ShaderVar::GetShaderOut(ShaderProgram::Vertex); | |||||
ShaderVar out_pixel = ShaderVar::GetShaderOut(ShaderProgram::Pixel); | |||||
ShaderVar pass_texcoord = ShaderVar(ShaderVariable::Varying, ShaderVariableType::Vec2, "texcoord"); | |||||
ShaderVar pass_color = ShaderVar(ShaderVariable::Varying, ShaderVariableType::Vec4, "color"); | |||||
ShaderVar in_position = ShaderVar(ShaderVariable::Attribute, ShaderVariableType::Vec2, "position"); | |||||
ShaderVar in_texcoord = ShaderVar(ShaderVariable::Attribute, ShaderVariableType::Vec2, "texcoord"); | |||||
ShaderVar in_color = ShaderVar(ShaderVariable::Attribute, ShaderVariableType::Vec4, "color"); | |||||
m_ortho.m_var = ShaderVar(ShaderVariable::Uniform, ShaderVariableType::Mat4, "ortho"); | |||||
m_texture.m_var = ShaderVar(ShaderVariable::Uniform, ShaderVariableType::sampler2D, "texture"); | |||||
ShaderBlock imgui_vertex("imgui_vertex"); | |||||
imgui_vertex | |||||
<< out_vertex << m_ortho << in_position | |||||
<< pass_texcoord << in_texcoord | |||||
<< pass_color << in_color; | |||||
imgui_vertex.SetMainCode(String() + | |||||
Line(out_vertex + " = .5 *" + m_ortho + " * vec4(" + in_position + ", -1.0, 1.0);") | |||||
+ Line(pass_texcoord + " = " + in_texcoord + ";") | |||||
+ Line(pass_color + " = " + in_color + ";") | |||||
); | |||||
ShaderBlock imgui_pixel("imgui_pixel"); | |||||
imgui_pixel << m_texture << pass_texcoord << pass_color << out_pixel; | |||||
imgui_pixel.SetMainCode(String() + | |||||
Line(String() | |||||
+ "vec4 col = " + pass_color + " * texture2D(" + m_texture + ", " + pass_texcoord + ");") | |||||
+ Line("if (col.a == 0.0) discard; ") | |||||
+ Line(out_pixel + " = col;") | |||||
); | |||||
m_builder | |||||
<< ShaderProgram::Vertex << imgui_vertex | |||||
<< ShaderProgram::Pixel << imgui_pixel; | |||||
//Input Setup ------------------------------------------------------------- | |||||
for (int i = LolImGuiKey::KEY_START; i < LolImGuiKey::KEY_END; ++i) | |||||
m_profile << InputProfile::Keyboard(i, LolImGuiKey(i).ToString()); | |||||
for (int i = LolImGuiKey::MOUSE_KEY_START; i < LolImGuiKey::MOUSE_KEY_END; ++i) | |||||
m_profile << InputProfile::MouseKey(i, LolImGuiKey(i).ToString()); | |||||
for (int i = LolImGuiAxis::MOUSE_AXIS_START; i < LolImGuiAxis::MOUSE_AXIS_END; ++i) | |||||
m_profile << InputProfile::MouseAxis(i, LolImGuiAxis(i).ToString()); | |||||
Ticker::Ref(m_controller = new Controller("ImGui_Controller")); | |||||
m_controller->Init(m_profile); | |||||
//InputDevice::CaptureMouse(true); | |||||
m_mouse = InputDevice::GetMouse(); | |||||
m_keyboard = InputDevice::GetKeyboard(); | |||||
//m_controller->Get | |||||
//# define KB InputProfile::Keyboard | |||||
// m_profile | |||||
// << InputProfile::Keyboard(idx, g_name_key_Left); | |||||
//# undef KB | |||||
} | } | ||||
LolImGui::~LolImGui() | LolImGui::~LolImGui() | ||||
{ | { | ||||
ImGui::GetIO().Fonts->TexID = nullptr; | ImGui::GetIO().Fonts->TexID = nullptr; | ||||
Ticker::Unref(m_font); | Ticker::Unref(m_font); | ||||
m_font = nullptr; | m_font = nullptr; | ||||
Shader::Destroy(m_shader); | |||||
delete m_vdecl; | |||||
} | } | ||||
//------------------------------------------------------------------------- | //------------------------------------------------------------------------- | ||||
@@ -35,69 +99,34 @@ void LolImGui::Init() | |||||
Ticker::Ref(g_lolimgui = new LolImGui()); | Ticker::Ref(g_lolimgui = new LolImGui()); | ||||
ImGuiIO& io = ImGui::GetIO(); | ImGuiIO& io = ImGui::GetIO(); | ||||
//io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. | |||||
//io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; | |||||
//io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; | |||||
//io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP; | |||||
//io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN; | |||||
//io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME; | |||||
//io.KeyMap[ImGuiKey_End] = GLFW_KEY_END; | |||||
//io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE; | |||||
//io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE; | |||||
//io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER; | |||||
//io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; | |||||
//io.KeyMap[ImGuiKey_A] = GLFW_KEY_A; | |||||
//io.KeyMap[ImGuiKey_C] = GLFW_KEY_C; | |||||
//io.KeyMap[ImGuiKey_V] = GLFW_KEY_V; | |||||
//io.KeyMap[ImGuiKey_X] = GLFW_KEY_X; | |||||
//io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y; | |||||
//io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z; | |||||
//ImFont* font0 = io.Fonts->AddFontDefault(); | |||||
// Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. | |||||
io.KeyMap[ImGuiKey_Tab] = LolImGuiKey::Tab; | |||||
io.KeyMap[ImGuiKey_LeftArrow] = LolImGuiKey::LeftArrow; | |||||
io.KeyMap[ImGuiKey_RightArrow] = LolImGuiKey::RightArrow; | |||||
io.KeyMap[ImGuiKey_UpArrow] = LolImGuiKey::UpArrow; | |||||
io.KeyMap[ImGuiKey_DownArrow] = LolImGuiKey::DownArrow; | |||||
io.KeyMap[ImGuiKey_Home] = LolImGuiKey::Home; | |||||
io.KeyMap[ImGuiKey_End] = LolImGuiKey::End; | |||||
io.KeyMap[ImGuiKey_Delete] = LolImGuiKey::Delete; | |||||
io.KeyMap[ImGuiKey_Backspace] = LolImGuiKey::Backspace; | |||||
io.KeyMap[ImGuiKey_Enter] = LolImGuiKey::Enter; | |||||
io.KeyMap[ImGuiKey_Escape] = LolImGuiKey::Escape; | |||||
io.KeyMap[ImGuiKey_A] = LolImGuiKey::A; | |||||
io.KeyMap[ImGuiKey_C] = LolImGuiKey::C; | |||||
io.KeyMap[ImGuiKey_V] = LolImGuiKey::V; | |||||
io.KeyMap[ImGuiKey_X] = LolImGuiKey::X; | |||||
io.KeyMap[ImGuiKey_Y] = LolImGuiKey::Y; | |||||
io.KeyMap[ImGuiKey_Z] = LolImGuiKey::Z; | |||||
//Func pointer | //Func pointer | ||||
io.RenderDrawListsFn = LolImGui::RenderDrawLists; | io.RenderDrawListsFn = LolImGui::RenderDrawLists; | ||||
io.SetClipboardTextFn = LolImGui::SetClipboard; | io.SetClipboardTextFn = LolImGui::SetClipboard; | ||||
io.GetClipboardTextFn = LolImGui::GetClipboard; | io.GetClipboardTextFn = LolImGui::GetClipboard; | ||||
/* nope | |||||
#ifdef _MSC_VER | |||||
io.ImeWindowHandle = glfwGetWin32Window(g_Window); | |||||
#endif | |||||
*/ | |||||
/* Callback not needed but look into these to send IO stuff | |||||
if (install_callbacks) | |||||
{ | |||||
glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback); | |||||
glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback); | |||||
glfwSetKeyCallback(window, ImGui_ImplGlFw_KeyCallback); | |||||
glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback); | |||||
} | |||||
*/ | |||||
} | } | ||||
/* CALLBACKS | /* CALLBACKS | ||||
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods) | |||||
{ | |||||
if (action == GLFW_PRESS && button >= 0 && button < 3) | |||||
g_MousePressed[button] = true; | |||||
} | |||||
void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset) | |||||
{ | |||||
g_MouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines. | |||||
} | |||||
void ImGui_ImplGlFw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) | |||||
{ | |||||
ImGuiIO& io = ImGui::GetIO(); | |||||
if (action == GLFW_PRESS) | |||||
io.KeysDown[key] = true; | |||||
if (action == GLFW_RELEASE) | |||||
io.KeysDown[key] = false; | |||||
io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0; | |||||
io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0; | |||||
} | |||||
void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c) | void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c) | ||||
{ | { | ||||
ImGuiIO& io = ImGui::GetIO(); | ImGuiIO& io = ImGui::GetIO(); | ||||
@@ -138,25 +167,12 @@ void LolImGui::TickGame(float seconds) | |||||
// Build texture | // Build texture | ||||
unsigned char* pixels; | unsigned char* pixels; | ||||
ivec2 size; | ivec2 size; | ||||
io.Fonts->GetTexDataAsAlpha8(&pixels, &size.x, &size.y); | |||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &size.x, &size.y); | |||||
Image* image = new Image(); | Image* image = new Image(); | ||||
image->Copy(pixels, size, PixelFormat::RGBA_8); | image->Copy(pixels, size, PixelFormat::RGBA_8); | ||||
image->SetSize(size); | |||||
Ticker::Ref(m_font = new TextureImage("", image)); | Ticker::Ref(m_font = new TextureImage("", image)); | ||||
//// Create texture | |||||
//glGenTextures(1, &g_FontTexture); | |||||
//glBindTexture(GL_TEXTURE_2D, g_FontTexture); | |||||
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |||||
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||||
//glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels); | |||||
//// Store our identifier | |||||
//io.Fonts->TexID = (void *)(intptr_t)g_FontTexture; | |||||
//return true; | |||||
} | } | ||||
//Texture has been created | //Texture has been created | ||||
if (m_font && m_font->GetTexture()) | if (m_font && m_font->GetTexture()) | ||||
@@ -169,40 +185,73 @@ void LolImGui::TickGame(float seconds) | |||||
video_size = vec2(Video::GetSize()); | video_size = vec2(Video::GetSize()); | ||||
io.DisplaySize = ImVec2(video_size.x, video_size.y); | io.DisplaySize = ImVec2(video_size.x, video_size.y); | ||||
// Setup time step | |||||
//Setup time step | |||||
io.DeltaTime = seconds; | io.DeltaTime = seconds; | ||||
io.MouseDrawCursor = true; | |||||
// Setup inputs | |||||
// (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents()) | |||||
//double mouse_x, mouse_y; | |||||
//glfwGetCursorPos(g_Window, &mouse_x, &mouse_y); | |||||
//mouse_x *= (float)display_w / w; // Convert mouse coordinates to pixels | |||||
//mouse_y *= (float)display_h / h; | |||||
//io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) | |||||
/* | |||||
for (int i = 0; i < 3; i++) | |||||
//Update Keyboard | |||||
io.KeyCtrl = false; | |||||
io.KeyShift = false; | |||||
for (int i = LolImGuiKey::KEY_START; i < LolImGuiKey::KEY_END; ++i) | |||||
{ | { | ||||
io.MouseDown[i] = g_MousePressed[i] || glfwGetMouseButton(g_Window, i) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. | |||||
g_MousePressed[i] = false; | |||||
switch (i) | |||||
{ | |||||
default: | |||||
io.KeysDown[i] = m_controller->GetKey(i).IsPressed(); | |||||
break; | |||||
case LolImGuiKey::LShift: | |||||
case LolImGuiKey::RShift: | |||||
io.KeyShift = (io.KeyShift || m_controller->GetKey(i).IsPressed()); | |||||
break; | |||||
case LolImGuiKey::LCtrl: | |||||
case LolImGuiKey::RCtrl: | |||||
io.KeyCtrl = (io.KeyCtrl || m_controller->GetKey(i).IsPressed()); | |||||
break; | |||||
} | |||||
} | } | ||||
io.MouseWheel = g_MouseWheel; | |||||
g_MouseWheel = 0.0f; | |||||
*/ | |||||
//Update text input | |||||
String text = m_keyboard->GetText(); | |||||
//text.case_change(io.KeyShift); | |||||
for (int i = 0; i < text.count(); ++i) | |||||
io.AddInputCharacter(text[i]); | |||||
//Update mouse | |||||
if (m_mouse) | |||||
{ | |||||
vec2 cursor = m_mouse->GetCursor(0); | |||||
cursor.y = 1.f - cursor.y; | |||||
cursor *= video_size; | |||||
io.MousePos = ImVec2(cursor.x, cursor.y); | |||||
io.MouseWheel = m_controller->GetAxis(LolImGuiAxis::Scroll).GetValue(); | |||||
for (int i = LolImGuiKey::MOUSE_KEY_START; i < LolImGuiKey::MOUSE_KEY_END; ++i) | |||||
{ | |||||
switch (i) | |||||
{ | |||||
default: | |||||
io.MouseDown[i - LolImGuiKey::MOUSE_KEY_START] = m_controller->GetKey(i).IsPressed(); | |||||
break; | |||||
case LolImGuiKey::Focus: | |||||
if (m_controller->GetKey(i).IsPressed()) | |||||
io.MousePos = ImVec2(-1.f, -1.f); | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
// Start the frame | // Start the frame | ||||
ImGui::NewFrame(); | ImGui::NewFrame(); | ||||
} | } | ||||
void LolImGui::TickDraw(float seconds, Scene &scene) | void LolImGui::TickDraw(float seconds, Scene &scene) | ||||
{ | { | ||||
super::TickDraw(seconds, scene); | super::TickDraw(seconds, scene); | ||||
ImGui::Render(); | |||||
} | |||||
ImGuiIO& io = ImGui::GetIO(); | |||||
if (io.Fonts->TexID) | |||||
ImGui::Render(); | |||||
} | |||||
@@ -219,74 +268,126 @@ void LolImGui::TickDraw(float seconds, Scene &scene) | |||||
// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) | // - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) | ||||
//------------------------------------------------------------------------- | //------------------------------------------------------------------------- | ||||
void LolImGui::RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) | void LolImGui::RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) | ||||
{ | |||||
g_lolimgui->RenderDrawListsMethod(cmd_lists, cmd_lists_count); | |||||
} | |||||
void LolImGui::RenderDrawListsMethod(ImDrawList** const cmd_lists, int cmd_lists_count) | |||||
{ | { | ||||
if (cmd_lists_count == 0) | if (cmd_lists_count == 0) | ||||
return; | return; | ||||
/* | |||||
// We are using the OpenGL fixed pipeline to make the example code simpler to read! | |||||
// A probable faster way to render would be to collate all vertices from all cmd_lists into a single vertex buffer. | |||||
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers. | |||||
glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT); | |||||
glEnable(GL_BLEND); | |||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||||
glDisable(GL_CULL_FACE); | |||||
glDisable(GL_DEPTH_TEST); | |||||
glEnable(GL_SCISSOR_TEST); | |||||
glEnableClientState(GL_VERTEX_ARRAY); | |||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY); | |||||
glEnableClientState(GL_COLOR_ARRAY); | |||||
glEnable(GL_TEXTURE_2D); | |||||
// Setup orthographic projection matrix | |||||
const float width = ImGui::GetIO().DisplaySize.x; | |||||
const float height = ImGui::GetIO().DisplaySize.y; | |||||
glMatrixMode(GL_PROJECTION); | |||||
glPushMatrix(); | |||||
glLoadIdentity(); | |||||
glOrtho(0.0f, width, height, 0.0f, -1.0f, +1.0f); | |||||
glMatrixMode(GL_MODELVIEW); | |||||
glPushMatrix(); | |||||
glLoadIdentity(); | |||||
// Render command lists | |||||
#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT)) | |||||
vec2 size = vec2(Video::GetSize()); | |||||
float alpha = 1.f; | |||||
mat4 ortho = mat4::ortho(size.x * alpha, size.y * alpha, -1000.f, 1000.f) | |||||
* mat4::lookat(vec3::axis_z, vec3::zero, vec3::axis_y) | |||||
* mat4::scale(vec3::axis_x - vec3::axis_y - vec3::axis_z) | |||||
* mat4::translate(-size.x * .5f * alpha, -size.y * .5f * alpha, 0.f); | |||||
//Create shader | |||||
if (!m_shader) | |||||
{ | |||||
String code; | |||||
m_builder.Build(code); | |||||
m_shader = Shader::Create(m_builder.GetName(), code); | |||||
ASSERT(m_shader); | |||||
m_ortho.m_uniform = m_shader->GetUniformLocation(m_ortho.m_var); | |||||
m_texture.m_uniform = m_shader->GetUniformLocation(m_texture.m_var); | |||||
m_attribs | |||||
<< m_shader->GetAttribLocation(VertexUsage::Position, 0) | |||||
<< m_shader->GetAttribLocation(VertexUsage::TexCoord, 0) | |||||
<< m_shader->GetAttribLocation(VertexUsage::Color, 0); | |||||
m_vdecl = new VertexDeclaration( | |||||
VertexStream<vec2, vec2, u8vec4>( | |||||
VertexUsage::Position, | |||||
VertexUsage::TexCoord, | |||||
VertexUsage::Color)); | |||||
} | |||||
//Do not render without shader | |||||
if (!m_shader) | |||||
return; | |||||
RenderContext rc; | |||||
rc.SetCullMode(CullMode::Disabled); | |||||
rc.SetDepthFunc(DepthFunc::Disabled); | |||||
m_shader->Bind(); | |||||
for (int n = 0; n < cmd_lists_count; n++) | for (int n = 0; n < cmd_lists_count; n++) | ||||
{ | { | ||||
const ImDrawList* cmd_list = cmd_lists[n]; | const ImDrawList* cmd_list = cmd_lists[n]; | ||||
const unsigned char* vtx_buffer = (const unsigned char*)&cmd_list->vtx_buffer.front(); | const unsigned char* vtx_buffer = (const unsigned char*)&cmd_list->vtx_buffer.front(); | ||||
glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, pos))); | |||||
glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, uv))); | |||||
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, col))); | |||||
//Register uniforms | |||||
m_shader->SetUniform(m_ortho, ortho); | |||||
m_shader->SetUniform(m_texture, m_font->GetTexture()->GetTextureUniform(), 0); | |||||
int vtx_offset = 0; | int vtx_offset = 0; | ||||
for (size_t cmd_i = 0; cmd_i < cmd_list->commands.size(); cmd_i++) | for (size_t cmd_i = 0; cmd_i < cmd_list->commands.size(); cmd_i++) | ||||
{ | { | ||||
const ImDrawCmd* pcmd = &cmd_list->commands[cmd_i]; | const ImDrawCmd* pcmd = &cmd_list->commands[cmd_i]; | ||||
if (pcmd->user_callback) | |||||
struct Vertex | |||||
{ | { | ||||
pcmd->user_callback(cmd_list, pcmd); | |||||
} | |||||
else | |||||
vec2 pos, tex; | |||||
u8vec4 color; | |||||
}; | |||||
VertexBuffer* vbo = new VertexBuffer(pcmd->vtx_count * sizeof(Vertex)); | |||||
Vertex *vert = (Vertex *)vbo->Lock(0, 0); | |||||
#ifdef SHOW_IMGUI_DEBUG | |||||
//----------------------------------------------------------------- | |||||
//<Debug render> -------------------------------------------------- | |||||
//----------------------------------------------------------------- | |||||
float mod = -200.f; | |||||
vec3 off = vec3(vec2(-size.x, -size.y), 0.f); | |||||
vec3 pos[4] = { | |||||
(1.f / mod) * (off + vec3(0.f)), | |||||
(1.f / mod) * (off + size.x * vec3::axis_x), | |||||
(1.f / mod) * (off + size.x * vec3::axis_x + size.y * vec3::axis_y), | |||||
(1.f / mod) * (off + size.y * vec3::axis_y) | |||||
}; | |||||
for (int i = 0; i < 4; ++i) | |||||
Debug::DrawLine(pos[i], pos[(i + 1) % 4], Color::white); | |||||
ImDrawVert* buf = (ImDrawVert*)(vtx_buffer + vtx_offset); | |||||
for (uint16_t i = 0; i < pcmd->vtx_count; i += 3) | |||||
{ | { | ||||
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->texture_id); | |||||
glScissor((int)pcmd->clip_rect.x, (int)(height - pcmd->clip_rect.w), (int)(pcmd->clip_rect.z - pcmd->clip_rect.x), (int)(pcmd->clip_rect.w - pcmd->clip_rect.y)); | |||||
glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count); | |||||
vec2 pos[3]; | |||||
pos[0] = vec2(buf[i + 0].pos.x, buf[i + 0].pos.y); | |||||
pos[1] = vec2(buf[i + 1].pos.x, buf[i + 1].pos.y); | |||||
pos[2] = vec2(buf[i + 2].pos.x, buf[i + 2].pos.y); | |||||
vec4 col[3]; | |||||
col[0] = vec4(Color::FromRGBA32(buf[i + 0].col).arg, 1.f); | |||||
col[1] = vec4(Color::FromRGBA32(buf[i + 1].col).arg, 1.f); | |||||
col[2] = vec4(Color::FromRGBA32(buf[i + 2].col).arg, 1.f); | |||||
Debug::DrawLine((off + vec3(pos[0], 0.f)) / mod, (off + vec3(pos[1], 0.f)) / mod, col[0]); | |||||
Debug::DrawLine((off + vec3(pos[1], 0.f)) / mod, (off + vec3(pos[2], 0.f)) / mod, col[1]); | |||||
Debug::DrawLine((off + vec3(pos[2], 0.f)) / mod, (off + vec3(pos[0], 0.f)) / mod, col[2]); | |||||
} | } | ||||
vtx_offset += pcmd->vtx_count; | |||||
//----------------------------------------------------------------- | |||||
//<\Debug render> ------------------------------------------------- | |||||
//----------------------------------------------------------------- | |||||
#endif //SHOW_IMGUI_DEBUG | |||||
memcpy(vert, vtx_buffer + vtx_offset, pcmd->vtx_count * sizeof(Vertex)); | |||||
vbo->Unlock(); | |||||
m_font->Bind(); | |||||
m_vdecl->Bind(); | |||||
m_vdecl->SetStream(vbo, m_attribs[0], m_attribs[1], m_attribs[2]); | |||||
m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, pcmd->vtx_count); | |||||
m_vdecl->Unbind(); | |||||
m_font->Unbind(); | |||||
vtx_offset += pcmd->vtx_count * sizeof(Vertex); | |||||
delete vbo; | |||||
} | } | ||||
} | } | ||||
#undef OFFSETOF | |||||
// Restore modified state | |||||
glDisableClientState(GL_COLOR_ARRAY); | |||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY); | |||||
glDisableClientState(GL_VERTEX_ARRAY); | |||||
glMatrixMode(GL_MODELVIEW); | |||||
glPopMatrix(); | |||||
glMatrixMode(GL_PROJECTION); | |||||
glPopMatrix(); | |||||
glPopAttrib(); | |||||
*/ | |||||
m_shader->Unbind(); | |||||
} | } | ||||
@@ -22,6 +22,112 @@ class LolImGui : public Entity | |||||
{ | { | ||||
typedef Entity super; | typedef Entity super; | ||||
//ImGuiKeyBase ------------------------------------------------------------ | |||||
struct LolImGuiKeyBase : public StructSafeEnum | |||||
{ | |||||
enum Type | |||||
{ | |||||
KEY_START, | |||||
Tab = KEY_START, | |||||
LeftArrow, | |||||
RightArrow, | |||||
UpArrow, | |||||
DownArrow, | |||||
Home, | |||||
End, | |||||
Delete, | |||||
Backspace, | |||||
Enter, | |||||
Escape, | |||||
A, | |||||
C, | |||||
V, | |||||
X, | |||||
Y, | |||||
Z, | |||||
LShift, | |||||
RShift, | |||||
LCtrl, | |||||
RCtrl, | |||||
KEY_END, | |||||
MOUSE_KEY_START = KEY_END, | |||||
LeftClick = MOUSE_KEY_START, | |||||
RightClick, | |||||
MiddleClick, | |||||
Focus, | |||||
MOUSE_KEY_END, | |||||
MAX = MOUSE_KEY_END, | |||||
}; | |||||
protected: | |||||
virtual bool BuildEnumMap(map<int64_t, String>& enum_map) | |||||
{ | |||||
enum_map[Tab] = g_name_key_Tab; | |||||
enum_map[LeftArrow] = g_name_key_Left; | |||||
enum_map[RightArrow] = g_name_key_Right; | |||||
enum_map[UpArrow] = g_name_key_Up; | |||||
enum_map[DownArrow] = g_name_key_Down; | |||||
enum_map[Home] = g_name_key_Home; | |||||
enum_map[End] = g_name_key_End; | |||||
enum_map[Delete] = g_name_key_Delete; | |||||
enum_map[Backspace] = g_name_key_Backspace; | |||||
enum_map[Enter] = g_name_key_Return; | |||||
enum_map[Escape] = g_name_key_Escape; | |||||
enum_map[A] = g_name_key_A; | |||||
enum_map[C] = g_name_key_C; | |||||
enum_map[V] = g_name_key_V; | |||||
enum_map[X] = g_name_key_X; | |||||
enum_map[Y] = g_name_key_Y; | |||||
enum_map[Z] = g_name_key_Z; | |||||
enum_map[LShift] = g_name_key_LShift; | |||||
enum_map[RShift] = g_name_key_RShift; | |||||
enum_map[LCtrl] = g_name_key_LCtrl; | |||||
enum_map[RCtrl] = g_name_key_RCtrl; | |||||
enum_map[LeftClick] = g_name_mouse_key_left; | |||||
enum_map[RightClick] = g_name_mouse_key_right; | |||||
enum_map[MiddleClick] = g_name_mouse_key_middle; | |||||
return true; | |||||
} | |||||
}; | |||||
typedef SafeEnum<LolImGuiKeyBase> LolImGuiKey; | |||||
//ImGuiKeyBase ------------------------------------------------------------ | |||||
struct LolImGuiAxisBase : public StructSafeEnum | |||||
{ | |||||
enum Type | |||||
{ | |||||
MOUSE_AXIS_START = 0, | |||||
Scroll = MOUSE_AXIS_START, | |||||
MOUSE_AXIS_END, | |||||
MAX = MOUSE_AXIS_END, | |||||
}; | |||||
protected: | |||||
virtual bool BuildEnumMap(map<int64_t, String>& enum_map) | |||||
{ | |||||
enum_map[Scroll] = g_name_mouse_axis_scroll; | |||||
return true; | |||||
} | |||||
}; | |||||
typedef SafeEnum<LolImGuiAxisBase> LolImGuiAxis; | |||||
public: | |||||
//------------------------------------------------------------------------- | //------------------------------------------------------------------------- | ||||
LolImGui(); | LolImGui(); | ||||
~LolImGui(); | ~LolImGui(); | ||||
@@ -40,8 +146,32 @@ protected: | |||||
virtual void TickDraw(float seconds, Scene &scene); | virtual void TickDraw(float seconds, Scene &scene); | ||||
static void RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count); | static void RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count); | ||||
void RenderDrawListsMethod(ImDrawList** const cmd_lists, int cmd_lists_count); | |||||
struct Uniform | |||||
{ | |||||
Uniform() { } | |||||
Uniform(ShaderVar var) { m_var = var; } | |||||
operator String() { return m_var; } | |||||
operator ShaderVar() { return m_var; } | |||||
operator ShaderUniform() { return m_uniform; } | |||||
//-- | |||||
ShaderVar m_var; | |||||
ShaderUniform m_uniform; | |||||
}; | |||||
//------------------------------------------------------------------------- | |||||
TextureImage* m_font = nullptr; | TextureImage* m_font = nullptr; | ||||
ShaderBuilder m_builder = ShaderBuilder("imgui_shader", "120"); | |||||
Shader* m_shader = nullptr; | |||||
Uniform m_ortho; | |||||
Uniform m_texture; | |||||
array<ShaderAttrib> m_attribs; | |||||
VertexDeclaration* m_vdecl = nullptr; | |||||
Controller* m_controller = nullptr; | |||||
InputDevice* m_mouse = nullptr; | |||||
InputDevice* m_keyboard = nullptr; | |||||
InputProfile m_profile; | |||||
//map<ImGuiKey_, LolImGuiKey> m_keys; | |||||
}; | }; | ||||
//bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks); | //bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks); | ||||
@@ -315,6 +315,7 @@ private: | |||||
}; | }; | ||||
//----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||||
//TODO: Add mask|layer system to prevent several controllers from interfering with another. (input overlay in menus) | |||||
class Controller : public Entity | class Controller : public Entity | ||||
{ | { | ||||
public: | public: | ||||
@@ -21,6 +21,9 @@ static String g_name_joystick(const uint64_t num) | |||||
return String::Printf("Joystick%d", (int)num); | return String::Printf("Joystick%d", (int)num); | ||||
} | } | ||||
# define _SC(id, str, name) const String g_name_key_##name(#name); | |||||
# include "input/keys.h" | |||||
//Mouse default buttons/axis | //Mouse default buttons/axis | ||||
const String g_name_mouse_key_left("Left"); | const String g_name_mouse_key_left("Left"); | ||||
const String g_name_mouse_key_middle("Middle"); | const String g_name_mouse_key_middle("Middle"); | ||||
@@ -16,7 +16,7 @@ namespace lol | |||||
/** Internal class (not public) that allows to construct an InputDevice | /** Internal class (not public) that allows to construct an InputDevice | ||||
* dynamically, when the keys, axis and cursors are not known at | * dynamically, when the keys, axis and cursors are not known at | ||||
* compile time. */ | * compile time. */ | ||||
class InputDeviceInternal : InputDevice | |||||
class InputDeviceInternal : public InputDevice | |||||
{ | { | ||||
public: | public: | ||||
inline InputDeviceInternal(char const * name) : InputDevice(name) { } | inline InputDeviceInternal(char const * name) : InputDevice(name) { } | ||||
@@ -283,5 +283,10 @@ _SC(282, "", Sleep) | |||||
_SC(283, "", App1) | _SC(283, "", App1) | ||||
_SC(284, "", App2) | _SC(284, "", App2) | ||||
//Custom Lock management | |||||
_SC(285, "", CapsLockStatus) | |||||
_SC(286, "", ScrollLockStatus) | |||||
_SC(287, "", NumLockClearStatus) | |||||
#undef _SC | #undef _SC | ||||
@@ -54,6 +54,7 @@ public: | |||||
/* Allow conversion from int and to the underlying type */ | /* Allow conversion from int and to the underlying type */ | ||||
inline explicit SafeEnum(int i) : m_value(T(i)) {} | inline explicit SafeEnum(int i) : m_value(T(i)) {} | ||||
inline Type ToScalar() const { return m_value; } | inline Type ToScalar() const { return m_value; } | ||||
//inline class String ToString() const { return ToString(); } | |||||
/* Convert to string stuff */ | /* Convert to string stuff */ | ||||
inline class String ToString() | inline class String ToString() | ||||
@@ -127,6 +127,11 @@ public: | |||||
return String(&(*this)[start], item_count); | return String(&(*this)[start], item_count); | ||||
} | } | ||||
bool contains(String const &s) const | |||||
{ | |||||
return index_of(s.C()) != INDEX_NONE; | |||||
} | |||||
ptrdiff_t index_of(char token) const | ptrdiff_t index_of(char token) const | ||||
{ | { | ||||
using namespace std; | using namespace std; | ||||
@@ -135,6 +140,7 @@ public: | |||||
return tmp ? (ptrdiff_t)(tmp - C()) : INDEX_NONE; | return tmp ? (ptrdiff_t)(tmp - C()) : INDEX_NONE; | ||||
} | } | ||||
ptrdiff_t index_of(String const& token) const { return index_of(token.C()); } | |||||
ptrdiff_t index_of(char const* token) const | ptrdiff_t index_of(char const* token) const | ||||
{ | { | ||||
using namespace std; | using namespace std; | ||||
@@ -143,11 +149,6 @@ public: | |||||
return tmp ? (ptrdiff_t)(tmp - C()) : INDEX_NONE; | return tmp ? (ptrdiff_t)(tmp - C()) : INDEX_NONE; | ||||
} | } | ||||
bool contains(String const &s) const | |||||
{ | |||||
return index_of(s.C()) != INDEX_NONE; | |||||
} | |||||
ptrdiff_t last_index_of(char token) const | ptrdiff_t last_index_of(char token) const | ||||
{ | { | ||||
using namespace std; | using namespace std; | ||||
@@ -156,6 +157,18 @@ public: | |||||
return tmp ? (ptrdiff_t)(tmp - C()) : INDEX_NONE; | return tmp ? (ptrdiff_t)(tmp - C()) : INDEX_NONE; | ||||
} | } | ||||
ptrdiff_t last_index_of(String const& token) const { return last_index_of(token.C()); } | |||||
ptrdiff_t last_index_of(char const* token) const | |||||
{ | |||||
using namespace std; | |||||
ptrdiff_t token_len = strlen(token); | |||||
for (ptrdiff_t i = count() - token_len; i >= 0; --i) | |||||
if (strstr(C() + i, token)) | |||||
return i; | |||||
return -1; | |||||
} | |||||
int replace(char const old_token, char const new_token, | int replace(char const old_token, char const new_token, | ||||
bool all_occurrences = false) | bool all_occurrences = false) | ||||
{ | { | ||||
@@ -173,34 +186,32 @@ public: | |||||
return res; | return res; | ||||
} | } | ||||
/* FIXME: it doesn't sound safe to apply this in place */ | |||||
inline String& to_lower() | inline String& to_lower() | ||||
{ | { | ||||
char* p = C(); | |||||
for (ptrdiff_t i = 0; i < count(); ++i) | |||||
if ('A' <= p[i] && p[i] <= 'Z') | |||||
p[i] += 'a' - 'A'; | |||||
String ret(*this); | |||||
for (ptrdiff_t i = 0; i < ret.count(); ++i) | |||||
{ | |||||
if ('A' <= ret[i] && ret[i] <= 'Z') | |||||
ret[i] += 'a' - 'A'; | |||||
} | |||||
*this = ret; | |||||
return *this; | return *this; | ||||
} | } | ||||
inline String& to_upper() | inline String& to_upper() | ||||
{ | { | ||||
char* p = C(); | |||||
for (ptrdiff_t i = 0; i < count(); ++i) | |||||
if ('a' <= p[i] && p[i] <= 'z') | |||||
p[i] += 'A' - 'a'; | |||||
String ret(*this); | |||||
for (ptrdiff_t i = 0; i < ret.count(); ++i) | |||||
{ | |||||
if ('a' <= ret[i] && ret[i] <= 'z') | |||||
ret[i] += 'A' - 'a'; | |||||
} | |||||
*this = ret; | |||||
return *this; | return *this; | ||||
} | } | ||||
ptrdiff_t last_index_of(char const* token) const | |||||
inline String& case_change(bool case_to_upper) | |||||
{ | { | ||||
using namespace std; | |||||
ptrdiff_t token_len = strlen(token); | |||||
for (ptrdiff_t i = count() - token_len; i >= 0; --i) | |||||
if (strstr(C() + i, token)) | |||||
return i; | |||||
return -1; | |||||
return case_to_upper ? to_upper() : to_lower(); | |||||
} | } | ||||
bool starts_with(String const &s) const | bool starts_with(String const &s) const | ||||
@@ -231,6 +242,12 @@ public: | |||||
return ret += s; | return ret += s; | ||||
} | } | ||||
inline String operator +(char c) const | |||||
{ | |||||
String ret(*this); | |||||
return ret += c; | |||||
} | |||||
inline String& operator +=(String const &s) | inline String& operator +=(String const &s) | ||||
{ | { | ||||
using namespace std; | using namespace std; | ||||
@@ -240,12 +257,6 @@ public: | |||||
return *this; | return *this; | ||||
} | } | ||||
inline String operator +(char c) const | |||||
{ | |||||
String ret(*this); | |||||
return ret += c; | |||||
} | |||||
inline String& operator +=(char c) | inline String& operator +=(char c) | ||||
{ | { | ||||
((super &)*this).last() = c; | ((super &)*this).last() = c; | ||||
@@ -306,6 +317,7 @@ public: | |||||
inline void Resize(ptrdiff_t item_count) { return resize(item_count); } | inline void Resize(ptrdiff_t item_count) { return resize(item_count); } | ||||
inline String& ToLower() { return to_lower(); } | inline String& ToLower() { return to_lower(); } | ||||
inline String& ToUpper() { return to_upper(); } | inline String& ToUpper() { return to_upper(); } | ||||
inline String& CaseChange(bool case_to_upper) { return case_to_upper ? ToUpper() : ToLower(); } | |||||
inline String Sub(ptrdiff_t start, ptrdiff_t item_count = -1) const { return sub(start, item_count); } | inline String Sub(ptrdiff_t start, ptrdiff_t item_count = -1) const { return sub(start, item_count); } | ||||
inline bool Contains(String const &s) const { return contains(s); } | inline bool Contains(String const &s) const { return contains(s); } | ||||
inline ptrdiff_t IndexOf(char token) const { return index_of(token); } | inline ptrdiff_t IndexOf(char token) const { return index_of(token); } | ||||
@@ -318,6 +330,26 @@ public: | |||||
inline ptrdiff_t Count() const { return count(); } | inline ptrdiff_t Count() const { return count(); } | ||||
}; | }; | ||||
class Line | |||||
{ | |||||
public: | |||||
Line(String const& s) | |||||
{ | |||||
m_line = s + "\n"; | |||||
} | |||||
inline operator String() | |||||
{ | |||||
return m_line; | |||||
} | |||||
inline operator const char*() | |||||
{ | |||||
return m_line.C(); | |||||
} | |||||
private: | |||||
String m_line; | |||||
}; | |||||
inline bool operator ==(char const* sz, String const &s) | inline bool operator ==(char const* sz, String const &s) | ||||
{ | { | ||||
return s == sz; | return s == sz; | ||||
@@ -134,6 +134,134 @@ protected: | |||||
}; | }; | ||||
typedef SafeEnum<ShaderProgramBase> ShaderProgram; | typedef SafeEnum<ShaderProgramBase> ShaderProgram; | ||||
//ShaderProgramBase ----------------------------------------------------------- | |||||
struct ShaderVariableTypeBase | |||||
{ | |||||
enum Type | |||||
{ | |||||
Bool, | |||||
Int, UInt, | |||||
Float, | |||||
Double, | |||||
Vec2, Vec3, Vec4, | |||||
DVec2, DVec3, DVec4, | |||||
BVec2, BVec3, BVec4, | |||||
IVec2, IVec3, IVec4, | |||||
UVec2, UVec3, UVec4, | |||||
Mat2, Mat3, Mat4, | |||||
sampler1D, | |||||
sampler2D, | |||||
sampler3D, | |||||
samplerCube, | |||||
sampler2DRect, | |||||
sampler1DArray, | |||||
sampler2DArray, | |||||
samplerCubeArray, | |||||
samplerBuffer, | |||||
sampler2DMS, | |||||
sampler2DMSArray, | |||||
isampler1D, | |||||
isampler2D, | |||||
isampler3D, | |||||
isamplerCube, | |||||
isampler2DRect, | |||||
isampler1DArray, | |||||
isampler2DArray, | |||||
isamplerCubeArray, | |||||
isamplerBuffer, | |||||
isampler2DMS, | |||||
isampler2DMSArray, | |||||
usampler1D, | |||||
usampler2D, | |||||
usampler3D, | |||||
usamplerCube, | |||||
usampler2DRect, | |||||
usampler1DArray, | |||||
usampler2DArray, | |||||
usamplerCubeArray, | |||||
usamplerBuffer, | |||||
usampler2DMS, | |||||
usampler2DMSArray, | |||||
sampler1DShadow, | |||||
sampler2DShadow, | |||||
samplerCubeShadow, | |||||
sampler2DRectShadow, | |||||
sampler1DArrayShadow, | |||||
sampler2DArrayShadow, | |||||
samplerCubeArrayShadow, | |||||
MAX | |||||
}; | |||||
protected: | |||||
virtual bool BuildEnumMap(map<int64_t, String>& enum_map) | |||||
{ | |||||
enum_map[Bool] = "bool"; | |||||
enum_map[Int] = "int"; enum_map[UInt] = "uint"; | |||||
enum_map[Float] = "float"; | |||||
enum_map[Double] = "double"; | |||||
enum_map[Vec2] = "vec2"; enum_map[Vec3] = "vec3"; enum_map[Vec4] = "vec4"; | |||||
enum_map[DVec2] = "dvec2"; enum_map[DVec3] = "dvec3"; enum_map[DVec4] = "dvec4"; | |||||
enum_map[BVec2] = "bvec2"; enum_map[BVec3] = "bvec3"; enum_map[BVec4] = "bvec4"; | |||||
enum_map[IVec2] = "ivec2"; enum_map[IVec3] = "ivec3"; enum_map[IVec4] = "ivec4"; | |||||
enum_map[UVec2] = "uvec2"; enum_map[UVec3] = "uvec3"; enum_map[UVec4] = "uvec4"; | |||||
enum_map[Mat2] = "mat2"; | |||||
enum_map[Mat3] = "mat3"; | |||||
enum_map[Mat4] = "mat4"; | |||||
enum_map[sampler1D] = "sampler1D"; | |||||
enum_map[sampler2D] = "sampler2D"; | |||||
enum_map[sampler3D] = "sampler3D"; | |||||
enum_map[samplerCube] = "samplerCube"; | |||||
enum_map[sampler2DRect] = "sampler2DRect"; | |||||
enum_map[sampler1DArray] = "sampler1DArray"; | |||||
enum_map[sampler2DArray] = "sampler2DArray"; | |||||
enum_map[samplerCubeArray] = "samplerCubeArray"; | |||||
enum_map[samplerBuffer] = "samplerBuffer"; | |||||
enum_map[sampler2DMS] = "sampler2DMS"; | |||||
enum_map[sampler2DMSArray] = "sampler2DMSArray"; | |||||
enum_map[isampler1D] = "isampler1D"; | |||||
enum_map[isampler2D] = "isampler2D"; | |||||
enum_map[isampler3D] = "isampler3D"; | |||||
enum_map[isamplerCube] = "isamplerCube"; | |||||
enum_map[isampler2DRect] = "isampler2DRect"; | |||||
enum_map[isampler1DArray] = "isampler1DArray"; | |||||
enum_map[isampler2DArray] = "isampler2DArray"; | |||||
enum_map[isamplerCubeArray] = "isamplerCubeArray"; | |||||
enum_map[isamplerBuffer] = "isamplerBuffer"; | |||||
enum_map[isampler2DMS] = "isampler2DMS"; | |||||
enum_map[isampler2DMSArray] = "isampler2DMSArray"; | |||||
enum_map[usampler1D] = "usampler1D"; | |||||
enum_map[usampler2D] = "usampler2D"; | |||||
enum_map[usampler3D] = "usampler3D"; | |||||
enum_map[usamplerCube] = "usamplerCube"; | |||||
enum_map[usampler2DRect] = "usampler2DRect"; | |||||
enum_map[usampler1DArray] = "usampler1DArray"; | |||||
enum_map[usampler2DArray] = "usampler2DArray"; | |||||
enum_map[usamplerCubeArray] = "usamplerCubeArray"; | |||||
enum_map[usamplerBuffer] = "usamplerBuffer"; | |||||
enum_map[usampler2DMS] = "usampler2DMS"; | |||||
enum_map[usampler2DMSArray] = "usampler2DMSArray"; | |||||
enum_map[sampler1DShadow] = "sampler1DShadow"; | |||||
enum_map[sampler2DShadow] = "sampler2DShadow"; | |||||
enum_map[samplerCubeShadow] = "samplerCubeShadow"; | |||||
enum_map[sampler2DRectShadow] = "sampler2DRectShadow"; | |||||
enum_map[sampler1DArrayShadow] = "sampler1DArrayShadow"; | |||||
enum_map[sampler2DArrayShadow] = "sampler2DArrayShadow"; | |||||
enum_map[samplerCubeArrayShadow] = "samplerCubeArrayShadow"; | |||||
return true; | |||||
} | |||||
}; | |||||
typedef SafeEnum<ShaderVariableTypeBase> ShaderVariableType; | |||||
//ShaderUniform --------------------------------------------------------------- | //ShaderUniform --------------------------------------------------------------- | ||||
struct ShaderUniform | struct ShaderUniform | ||||
{ | { | ||||
@@ -193,6 +321,7 @@ public: | |||||
int GetAttribCount() const; | int GetAttribCount() const; | ||||
ShaderAttrib GetAttribLocation(VertexUsage usage, int index) const; | ShaderAttrib GetAttribLocation(VertexUsage usage, int index) const; | ||||
ShaderUniform GetUniformLocation(String const& uni) const; | |||||
ShaderUniform GetUniformLocation(char const *uni) const; | ShaderUniform GetUniformLocation(char const *uni) const; | ||||
void SetUniform(ShaderUniform const &uni, int i); | void SetUniform(ShaderUniform const &uni, int i); | ||||
void SetUniform(ShaderUniform const &uni, ivec2 const &v); | void SetUniform(ShaderUniform const &uni, ivec2 const &v); | ||||
@@ -231,6 +360,39 @@ public: | |||||
static String GetProgramOutVariableLocal(const ShaderProgram program); | static String GetProgramOutVariableLocal(const ShaderProgram program); | ||||
}; | }; | ||||
//ShaderVar ------------------------------------------------------------------- | |||||
class ShaderVar | |||||
{ | |||||
friend class ShaderBuilder; | |||||
friend class ShaderBlock; | |||||
protected: | |||||
public: | |||||
ShaderVar() { } | |||||
ShaderVar(ShaderVariable const& qualifier, String const& type, String const& name) | |||||
{ | |||||
m_qualifier = qualifier; | |||||
m_type = type; | |||||
m_name = name; | |||||
} | |||||
ShaderVar(ShaderVariable const& qualifier, ShaderVariableType const& type, String const& name) | |||||
: ShaderVar(qualifier, ShaderVariableType(type).ToString(), name) | |||||
{ } | |||||
~ShaderVar() { } | |||||
inline operator String() const { return Shader::GetVariablePrefix(m_qualifier) + m_name; } | |||||
inline ShaderVariable GetQualifier() const { return m_qualifier; } | |||||
inline String GetType() const { return m_type; } | |||||
inline String operator+(String const& value) { return String() + *this + value; } | |||||
static ShaderVar GetShaderOut(ShaderProgram program); | |||||
protected: | |||||
ShaderVariable m_qualifier; | |||||
String m_type; | |||||
String m_name; | |||||
}; | |||||
//ShaderBlock ----------------------------------------------------------------- | //ShaderBlock ----------------------------------------------------------------- | ||||
class ShaderBlock | class ShaderBlock | ||||
{ | { | ||||
@@ -260,10 +422,15 @@ public: | |||||
//Sets custom code that will be put before the main -so functions- | //Sets custom code that will be put before the main -so functions- | ||||
void SetCustomCode(String const& code_custom) { m_code_custom = code_custom; } | void SetCustomCode(String const& code_custom) { m_code_custom = code_custom; } | ||||
//Add parameter to the block | //Add parameter to the block | ||||
void Add(const ShaderVariable variable, String const& type, String const& name); | |||||
void AddVar(ShaderVar const& var); | |||||
inline ShaderBlock& operator<<(ShaderVar const& var) | |||||
{ | |||||
AddVar(var); | |||||
return *this; | |||||
} | |||||
protected: | protected: | ||||
void AddCallParameters(const ShaderVariable variable, map<String, String> const& variables, String& result); | |||||
void AddCallParameters(map<String, String> const& variables, String& result); | |||||
void AddDefinitionParameters(const ShaderVariable variable, const ShaderProgram program, map<String, String>& variables, String& result); | void AddDefinitionParameters(const ShaderVariable variable, const ShaderProgram program, map<String, String>& variables, String& result); | ||||
void Build(const ShaderProgram program, String& call, String& function); | void Build(const ShaderProgram program, String& call, String& function); | ||||
}; | }; | ||||
@@ -289,6 +456,7 @@ public: | |||||
String const& GetName(); | String const& GetName(); | ||||
ShaderBuilder& operator<<(const ShaderProgram program); | ShaderBuilder& operator<<(const ShaderProgram program); | ||||
ShaderBuilder& operator<<(ShaderBlock* block); | ShaderBuilder& operator<<(ShaderBlock* block); | ||||
ShaderBuilder& operator<<(ShaderBlock const& block); | |||||
protected: | protected: | ||||
String AddSlotOutVariableLocal(const ShaderProgram program); | String AddSlotOutVariableLocal(const ShaderProgram program); | ||||
@@ -316,6 +316,22 @@ public: | |||||
*/ | */ | ||||
static vec3 WavelengthToCIExyY(float nm); | static vec3 WavelengthToCIExyY(float nm); | ||||
/* | |||||
* Convert uint color to vec4. | |||||
*/ | |||||
static vec4 FromRGBA32(uint32_t c); | |||||
static vec4 FromRGB32(uint32_t c); | |||||
static vec4 FromRGBA16(uint16_t c); | |||||
static vec4 FromRGB16(uint16_t c); | |||||
/* | |||||
* Convert uint color to vec4. | |||||
*/ | |||||
static uint32_t ToRGBA32(vec4 c); | |||||
static uint32_t ToRGB32(vec4 c); | |||||
static uint16_t ToRGBA16(vec4 c); | |||||
static uint16_t ToRGB16(vec4 c); | |||||
/* | /* | ||||
* Convert colors to hex strings. | * Convert colors to hex strings. | ||||
*/ | */ | ||||
@@ -107,6 +107,7 @@ public: | |||||
bool GetContent(array<Directory>& directories); | bool GetContent(array<Directory>& directories); | ||||
bool GetContent(array<String>& files); | bool GetContent(array<String>& files); | ||||
String GetName(); | String GetName(); | ||||
long int GetModificationTime(); | |||||
static String GetCurrent(); | static String GetCurrent(); | ||||
static bool SetCurrent(String directory); | static bool SetCurrent(String directory); | ||||
@@ -417,6 +417,9 @@ | |||||
<ProjectReference Include="bullet\lolbullet.vcxproj"> | <ProjectReference Include="bullet\lolbullet.vcxproj"> | ||||
<Project>{83d3b207-c601-4025-8f41-01dedc354661}</Project> | <Project>{83d3b207-c601-4025-8f41-01dedc354661}</Project> | ||||
</ProjectReference> | </ProjectReference> | ||||
<ProjectReference Include="imgui\lolimgui.vcxproj"> | |||||
<Project>{a7f6fdf8-937e-41ef-b44d-04cd1a48c179}</Project> | |||||
</ProjectReference> | |||||
<ProjectReference Include="lua\lollua.vcxproj"> | <ProjectReference Include="lua\lollua.vcxproj"> | ||||
<Project>{d84021ca-b233-4e0f-8a52-071b83bbccc4}</Project> | <Project>{d84021ca-b233-4e0f-8a52-071b83bbccc4}</Project> | ||||
</ProjectReference> | </ProjectReference> | ||||
@@ -49,6 +49,48 @@ static int sdl12_to_scancode(int ch, int sc) | |||||
return 0; | return 0; | ||||
} | } | ||||
#else | |||||
//------------------------------------------------------------------------- | |||||
# define _SC(id, str, name) static const uint16_t SDLOL_##name = id; | |||||
# include "input/keys.h" | |||||
//------------------------------------------------------------------------- | |||||
static bool ScanCodeIsValid(int sc) | |||||
{ | |||||
switch (sc) | |||||
{ | |||||
# define _SC(id, str, name) \ | |||||
case id: return true; | |||||
# include "input/keys.h" | |||||
default: return false; | |||||
} | |||||
return false; | |||||
} | |||||
//------------------------------------------------------------------------- | |||||
static String ScanCodeToText(int sc) | |||||
{ | |||||
switch (sc) | |||||
{ | |||||
# define _SC(id, str, name) \ | |||||
case id: return String(str); | |||||
# include "input/keys.h" | |||||
default: | |||||
Log::Error(Line("ScanCodeToText unknown scancode %0d."), sc); | |||||
} | |||||
return String(); | |||||
} | |||||
//------------------------------------------------------------------------- | |||||
static String ScanCodeToName(int sc) | |||||
{ | |||||
switch (sc) | |||||
{ | |||||
# define _SC(id, str, name) \ | |||||
case id: return String(#name); | |||||
# include "input/keys.h" | |||||
default: | |||||
Log::Error(Line("ScanCodeToText unknown scancode %0d."), sc); | |||||
} | |||||
return String(); | |||||
} | |||||
#endif | #endif | ||||
/* | /* | ||||
@@ -218,30 +260,102 @@ void SdlInputData::Tick(float seconds) | |||||
case SDL_KEYDOWN: | case SDL_KEYDOWN: | ||||
case SDL_KEYUP: | case SDL_KEYUP: | ||||
#if USE_OLD_SDL | |||||
if (int sc = sdl12_to_scancode(event.key.keysym.sym, | |||||
event.key.keysym.scancode)) | |||||
#else | |||||
if (int sc = event.key.keysym.scancode) | |||||
#endif | |||||
m_keyboard->SetKey(sc, event.type == SDL_KEYDOWN); | |||||
else | |||||
Log::Error("unknown keypress (sym 0x%02x, scancode %0d)\n", | |||||
event.key.keysym.sym, event.key.keysym.scancode); | |||||
# if USE_OLD_SDL | |||||
switch (int sc = sdl12_to_scancode(event.key.keysym.sym, | |||||
event.key.keysym.scancode)) | |||||
# else | |||||
switch (int sc = event.key.keysym.scancode) | |||||
# endif | |||||
{ | |||||
//Lock management | |||||
case SDLOL_CapsLock: | |||||
case SDLOL_ScrollLock: | |||||
case SDLOL_NumLockClear: | |||||
//Update status on key down only | |||||
if (event.type == SDL_KEYDOWN) | |||||
{ | |||||
int sc2 = sc; | |||||
switch (sc) | |||||
{ | |||||
case SDLOL_CapsLock: | |||||
sc2 = SDLOL_CapsLockStatus; | |||||
break; | |||||
case SDLOL_ScrollLock: | |||||
sc2 = SDLOL_ScrollLockStatus; | |||||
break; | |||||
case SDLOL_NumLockClear: | |||||
sc2 = SDLOL_NumLockClearStatus; | |||||
break; | |||||
} | |||||
m_keyboard->SetKey(sc2, !m_keyboard->GetKey(sc2)); | |||||
/* DEBUG STUFF | |||||
Log::Info(Line("Repeat: 0x%02x : %s/%s/%s/%i"), | |||||
(int)m_keyboard, ScanCodeToText(sc2).C(), ScanCodeToName(sc2).C(), | |||||
m_keyboard->GetKey(sc2) ? "up" : "down", event.key.repeat); | |||||
*/ | |||||
} | |||||
default: | |||||
if (ScanCodeIsValid(sc)) | |||||
{ | |||||
m_keyboard->SetKey(sc, event.type == SDL_KEYDOWN); | |||||
if (event.type == SDL_KEYDOWN | |||||
&& !m_keyboard->GetKey(SDLOL_RCtrl) | |||||
&& !m_keyboard->GetKey(SDLOL_LCtrl) | |||||
&& !m_keyboard->GetKey(SDLOL_RAlt) | |||||
&& !m_keyboard->GetKey(SDLOL_LAlt)) | |||||
{ | |||||
String str = ScanCodeToText(sc); | |||||
str.CaseChange(m_keyboard->GetKey(SDLOL_CapsLockStatus) | |||||
^ (m_keyboard->GetKey(SDLOL_RShift) | |||||
|| m_keyboard->GetKey(SDLOL_LShift))); | |||||
m_keyboard->AddText(str); | |||||
} | |||||
/* DEBUG STUFF | |||||
Log::Info(Line("Repeat: 0x%02x : %s/%s/%s/%i"), | |||||
(int)m_keyboard, ScanCodeToText(sc).C(), ScanCodeToName(sc).C(), | |||||
event.type == SDL_KEYDOWN ? "up" : "down", event.key.repeat); | |||||
*/ | |||||
} | |||||
/* DEBUG STUFF | |||||
else | |||||
Log::Error("unknown keypress (sym 0x%02x, scancode %0d)\n", | |||||
event.key.keysym.sym, event.key.keysym.scancode); | |||||
*/ | |||||
} | |||||
break; | break; | ||||
# if USE_OLD_SDL | |||||
case SDL_MOUSEBUTTONDOWN: | case SDL_MOUSEBUTTONDOWN: | ||||
case SDL_MOUSEBUTTONUP: | case SDL_MOUSEBUTTONUP: | ||||
{ | |||||
# if USE_OLD_SDL | |||||
if (event.button.button != SDL_BUTTON_WHEELUP && event.button.button != SDL_BUTTON_WHEELDOWN) | if (event.button.button != SDL_BUTTON_WHEELUP && event.button.button != SDL_BUTTON_WHEELDOWN) | ||||
m_mouse->SetKey(event.button.button - 1, event.type == SDL_MOUSEBUTTONDOWN); | m_mouse->SetKey(event.button.button - 1, event.type == SDL_MOUSEBUTTONDOWN); | ||||
else | else | ||||
m_mouse->SetAxis(4, (event.button.button != SDL_BUTTON_WHEELUP) ? (1) : (-1)); | m_mouse->SetAxis(4, (event.button.button != SDL_BUTTON_WHEELUP) ? (1) : (-1)); | ||||
# endif | |||||
// TODO: mouse wheel as axis | |||||
break; | |||||
# else | |||||
case SDL_MOUSEBUTTONDOWN: | |||||
case SDL_MOUSEBUTTONUP: | |||||
m_mouse->SetKey(event.button.button - 1, event.type == SDL_MOUSEBUTTONDOWN); | |||||
break; | |||||
case SDL_MOUSEWHEEL: | |||||
m_mouse->SetAxis(4, (float)event.button.y); | |||||
break; | |||||
case SDL_WINDOWEVENT: | |||||
{ | |||||
switch (event.window.event) | |||||
{ | |||||
case SDL_WINDOWEVENT_ENTER: | |||||
case SDL_WINDOWEVENT_FOCUS_GAINED: | |||||
m_mouse->SetKey(3, true); | |||||
break; | |||||
case SDL_WINDOWEVENT_LEAVE: | |||||
case SDL_WINDOWEVENT_FOCUS_LOST: | |||||
m_mouse->SetKey(3, false); | |||||
break; | |||||
} | |||||
break; | break; | ||||
} | } | ||||
# endif | |||||
# if !SDL_FORCE_POLL_JOYSTICK | # if !SDL_FORCE_POLL_JOYSTICK | ||||
case SDL_JOYAXISMOTION: | case SDL_JOYAXISMOTION: | ||||
@@ -292,9 +406,7 @@ void SdlInputData::Tick(float seconds) | |||||
# if !EMSCRIPTEN && USE_OLD_SDL | # if !EMSCRIPTEN && USE_OLD_SDL | ||||
m_mouse->SetKey(3, !!(SDL_GetAppState() & SDL_APPMOUSEFOCUS)); | m_mouse->SetKey(3, !!(SDL_GetAppState() & SDL_APPMOUSEFOCUS)); | ||||
# else | # else | ||||
// Emscripten doesn't seem to handle SDL_APPMOUSEFOCUS | |||||
// FIXME: SDL2 doesn't have SDL_APPMOUSEFOCUS either | |||||
m_mouse->SetKey(3, true); | |||||
//Handled in PollEvent | |||||
# endif | # endif | ||||
if (m_mousecapture) | if (m_mousecapture) | ||||
@@ -197,7 +197,7 @@ class FileData | |||||
#if __ANDROID__ | #if __ANDROID__ | ||||
return 0; | return 0; | ||||
#elif HAVE_STDIO_H | #elif HAVE_STDIO_H | ||||
return m_stat.st_mtime; | |||||
return (long int)m_stat.st_mtime; | |||||
#else | #else | ||||
return 0; | return 0; | ||||
#endif | #endif | ||||
@@ -358,8 +358,10 @@ class DirectoryData | |||||
filter.Replace('/', '\\', true); | filter.Replace('/', '\\', true); | ||||
WIN32_FIND_DATA FindFileData; | WIN32_FIND_DATA FindFileData; | ||||
m_handle = FindFirstFile(filter.C(), &FindFileData); | m_handle = FindFirstFile(filter.C(), &FindFileData); | ||||
stat(directory.C(), &m_stat); | |||||
#elif HAVE_STDIO_H | #elif HAVE_STDIO_H | ||||
m_dd = opendir(directory.C()); | m_dd = opendir(directory.C()); | ||||
stat(directory.C(), &m_stat); | |||||
#endif | #endif | ||||
} | } | ||||
@@ -440,6 +442,17 @@ class DirectoryData | |||||
#endif | #endif | ||||
} | } | ||||
long int GetModificationTime() | |||||
{ | |||||
#if __ANDROID__ | |||||
return 0; | |||||
#elif HAVE_STDIO_H | |||||
return (long int)m_stat.st_mtime; | |||||
#else | |||||
return 0; | |||||
#endif | |||||
} | |||||
#if __ANDROID__ | #if __ANDROID__ | ||||
/* FIXME: not implemented */ | /* FIXME: not implemented */ | ||||
#elif defined(_WIN32) | #elif defined(_WIN32) | ||||
@@ -450,6 +463,7 @@ class DirectoryData | |||||
#endif | #endif | ||||
std::atomic<int> m_refcount; | std::atomic<int> m_refcount; | ||||
StreamType m_type; | StreamType m_type; | ||||
struct stat m_stat; | |||||
}; | }; | ||||
//-- DIRECTORY -- | //-- DIRECTORY -- | ||||
@@ -559,6 +573,12 @@ String Directory::GetName() | |||||
return m_name; | return m_name; | ||||
} | } | ||||
//-- | |||||
long int Directory::GetModificationTime() | |||||
{ | |||||
return m_data->GetModificationTime(); | |||||
} | |||||
//-- | //-- | ||||
String Directory::GetCurrent() | String Directory::GetCurrent() | ||||
{ | { | ||||
@@ -54,7 +54,7 @@ bool BaseThreadManager::Stop() | |||||
return false; | return false; | ||||
//Stop all threads | //Stop all threads | ||||
StopThreads(m_threads.count()); | |||||
StopThreads((int)m_threads.count()); | |||||
return true; | return true; | ||||
} | } | ||||
@@ -173,9 +173,9 @@ void BaseThreadManager::TickGame(float seconds) | |||||
//Resize thread count if needed | //Resize thread count if needed | ||||
if (m_threads.count() > m_jobqueue.count() && m_threads.count() > m_thread_min) | if (m_threads.count() > m_jobqueue.count() && m_threads.count() > m_thread_min) | ||||
StopThreads(m_threads.Count() - m_thread_min); | |||||
StopThreads((int)(m_threads.Count() - m_thread_min)); | |||||
else if (m_threads.count() < m_jobqueue.count()) | else if (m_threads.count() < m_jobqueue.count()) | ||||
AddThreads(lol::min(m_jobqueue.count(), (ptrdiff_t)m_thread_count) - m_threads.count()); | |||||
AddThreads((int)(lol::min(m_jobqueue.count(), (ptrdiff_t)m_thread_count) - m_threads.count())); | |||||
} | } | ||||
} /* namespace lol */ | } /* namespace lol */ |