Normal mapping
|
@ -1,36 +1,37 @@
|
|||
#version 330 core
|
||||
|
||||
uniform vec3 u_campos;
|
||||
uniform sampler2D u_texture;
|
||||
uniform sampler2D u_normal_texture;
|
||||
|
||||
uniform vec3 u_campos;
|
||||
uniform vec3 u_highlight;
|
||||
uniform float u_time;
|
||||
|
||||
in vec3 v_position;
|
||||
in vec3 v_normal;
|
||||
in vec3 v_proj_normal;
|
||||
in vec2 v_texcoord;
|
||||
in vec3 v_tangent;
|
||||
in vec3 v_bitangent;
|
||||
|
||||
layout (location=0) out vec4 v_output;
|
||||
|
||||
uniform sampler2D u_texture;
|
||||
|
||||
float get_fog_factor(float d)
|
||||
float kpc(float d, float min, float max)
|
||||
{
|
||||
const float FogMax = 10.0;
|
||||
const float FogMin = 0.0;
|
||||
if (d >= max) return 1.0;
|
||||
if (d <= min) return 0.0;
|
||||
|
||||
if (d >= FogMax) return 1.0;
|
||||
if (d <= FogMin) return 0.0;
|
||||
|
||||
return 1 - (FogMax - d) / (FogMax - FogMin);
|
||||
return 1.0 - (max - d) / (max - min);
|
||||
}
|
||||
|
||||
struct Light
|
||||
{
|
||||
vec3 position;
|
||||
vec3 diffuse;
|
||||
float radius;
|
||||
};
|
||||
|
||||
float lambert(vec3 n, vec3 l)
|
||||
float Lambert(vec3 n, vec3 l)
|
||||
{
|
||||
vec3 nrmn = normalize(n);
|
||||
vec3 nrml = normalize(l);
|
||||
|
@ -38,55 +39,38 @@ float lambert(vec3 n, vec3 l)
|
|||
return max(res, 0.0);
|
||||
}
|
||||
|
||||
float dist(vec2 p0, vec2 pf){return sqrt((pf.x-p0.x)*(pf.x-p0.x)+(pf.y-p0.y)*(pf.y-p0.y));}
|
||||
vec4 MakeLight(vec3 norm, vec3 position, vec3 diffuse, float radius, float sharpness, float power)
|
||||
{
|
||||
Light light;
|
||||
light.position = position;
|
||||
light.diffuse = diffuse;
|
||||
light.radius = radius;
|
||||
vec4 res = vec4(light.diffuse * Lambert(norm, normalize(light.position)), 1.0);
|
||||
float alpha = kpc(distance(light.position, v_position), light.radius * sharpness, light.radius);
|
||||
res *= mix(vec4(light.diffuse, 1), vec4(0,0,0,1.0), alpha);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
Light light;
|
||||
light.position = vec3(5.0, 4.0, 5.0);
|
||||
light.diffuse = vec3(1.0, 1.0, 1.0);
|
||||
vec3 tangentNormal = texture(u_normal_texture, v_texcoord).xyz * 2.0 - 1.0;
|
||||
vec3 T = normalize(v_tangent);
|
||||
vec3 B = normalize(v_bitangent);
|
||||
vec3 N = normalize(v_normal);
|
||||
mat3 TBN = mat3(T, B, N);
|
||||
vec3 norm = normalize(TBN * tangentNormal);
|
||||
vec4 texv = texture(u_texture, v_texcoord);
|
||||
//norm = abs(norm);
|
||||
|
||||
vec4 ambient = vec4(0.1, 0.1, 0.1, 1.0) * 1.5, light = ambient;
|
||||
|
||||
vec4 tex = texture(u_texture, v_texcoord);
|
||||
vec3 norm = (v_normal);
|
||||
light += MakeLight(norm, u_campos, vec3(1.0, 1.0, 1.0), 5.0, 0.0, 1.0);
|
||||
light += MakeLight(norm, vec3(5.0, 2.0, -7.0 + cos(u_time/35.0) * 2.0), vec3(1.0, 0.6, 0.0), 5.0, 0.6, 1.0);
|
||||
light += MakeLight(norm, vec3(7, 2.0, -7.0 + -cos(u_time / 30.0) * 1.0), vec3(0.6, 0.9, 1.0), 5.0, 0.6, 1.0);
|
||||
|
||||
v_output = texv * light;
|
||||
|
||||
vec3 res = vec3(1.0, 1.0, 1.0) * lambert(norm, normalize(light.position));
|
||||
|
||||
float a = dist(v_position.xy, vec2(0.0, 0.0)) * 2.0f;
|
||||
|
||||
|
||||
// vec4 res2 = texture2D(u_texture, v_texcoord) * ((dot(-light.position, v_normal) * 0.5)+2.5);
|
||||
vec4 texv = texture2D(u_texture, v_texcoord);
|
||||
vec4 res2 = texv * (abs(dot(-light.position, v_normal) * 0.5));
|
||||
//res2.xyz *= 0.2;
|
||||
res2.a = texv.a;
|
||||
v_output = res2;//vec4(res2, 1.0);
|
||||
|
||||
v_output = mix(v_output, texv, 0.66);
|
||||
|
||||
// + editor highlighting
|
||||
v_output.rgb *= u_highlight;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
vec3 col;
|
||||
vec4 tex = texture(u_texture, v_texcoord);
|
||||
vec3 norm = normalize(v_normal);
|
||||
vec3 dir = normalize(vec3(5.0, 0.25, -5.0) - v_position);
|
||||
float diff = max(dot(norm, dir), 0.0);
|
||||
float alpha = get_fog_factor(distance(u_campos, v_position));
|
||||
|
||||
vec3 diffuse = diff * vec3(0.8, 0.75, 0.7);
|
||||
float ff = 1.75;
|
||||
if (diffuse.x > 0.0) diffuse.x *= ff;
|
||||
if (diffuse.y > 0.0) diffuse.y *= ff;
|
||||
if (diffuse.z > 0.0) diffuse.z *= ff;
|
||||
vec3 ambient = vec3(0.3, 0.3, 0.3);
|
||||
col = (ambient + diffuse) * tex.rgb;
|
||||
col *= mix(vec4(1.0), vec4(0.0f, 0.0, 0.0, 1.0), alpha-0.2).xyz;
|
||||
|
||||
*/
|
||||
// vec4 tex = texture(u_texture, v_texcoord);
|
||||
// v_output = tex * vec4(vec3(1.5), 1.0);
|
||||
}
|
||||
|
|
|
@ -5,11 +5,15 @@ uniform mat4 u_mvp;
|
|||
layout (location = 0) in vec3 position;
|
||||
layout (location = 1) in vec3 normal;
|
||||
layout (location = 2) in vec2 texcoord;
|
||||
layout (location = 3) in vec3 tangent;
|
||||
layout (location = 4) in vec3 bitangent;
|
||||
|
||||
out vec3 v_position;
|
||||
out vec3 v_normal;
|
||||
out vec3 v_proj_normal;
|
||||
out vec2 v_texcoord;
|
||||
out vec3 v_tangent;
|
||||
out vec3 v_bitangent;
|
||||
|
||||
out float v_id;
|
||||
|
||||
|
@ -19,6 +23,8 @@ void main()
|
|||
v_normal = normal;
|
||||
v_proj_normal = vec4(u_mvp * vec4(normal, 1.0)).xyz;
|
||||
v_texcoord = texcoord;
|
||||
v_tangent = tangent;
|
||||
v_bitangent = bitangent;
|
||||
|
||||
v_id = gl_VertexID;
|
||||
|
||||
|
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
BIN
Data/resources/textures/materials/FLAT5_7_n.png
Normal file
After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
BIN
Data/resources/textures/materials/GRASS2_n.png
Normal file
After Width: | Height: | Size: 158 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
BIN
Data/resources/textures/materials/block_n.png
Normal file
After Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
BIN
Data/resources/textures/materials/floor0_n.png
Normal file
After Width: | Height: | Size: 114 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
BIN
Data/resources/textures/materials/floor1_n.png
Normal file
After Width: | Height: | Size: 100 KiB |
|
@ -1,85 +0,0 @@
|
|||
[02:17:44 AM] Info: Starting...
|
||||
|
||||
KP3D version 2
|
||||
===============================
|
||||
Copyright (C) kpworld.xyz 2018-2024
|
||||
Contact me! @kp_cftsz
|
||||
|
||||
[02:17:44 AM] Info: Initializing SDL
|
||||
[02:17:44 AM] Info: Initializing OpenGL
|
||||
[02:17:44 AM] Info: OpenGL version: 4.6.0 NVIDIA 536.23
|
||||
[02:17:44 AM] Info: Initializing GLEW
|
||||
[02:17:44 AM] Info: Initializing SDL_mixer
|
||||
[02:17:44 AM] Info: Reticulating splines...
|
||||
[02:17:45 AM] Info: Ready!
|
||||
[02:17:45 AM] Info: Finalized mesh with 45 batches
|
||||
[02:17:53 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:53 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:53 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:53 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:53 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:53 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:53 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:53 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:53 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:54 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:54 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:54 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:54 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:54 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:54 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:54 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:54 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:54 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:54 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:54 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:54 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:54 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:54 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:58 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:58 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:58 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:58 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:58 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:58 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:58 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:58 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:17:59 AM] Info: Finalized mesh with 44 batches
|
||||
[02:18:00 AM] Info: Finalized mesh with 44 batches
|
||||
[02:18:00 AM] Info: Finalized mesh with 44 batches
|
||||
[02:18:00 AM] Info: Finalized mesh with 44 batches
|
||||
[02:18:00 AM] Info: Finalized mesh with 44 batches
|
||||
[02:18:00 AM] Info: Finalized mesh with 44 batches
|
||||
[02:18:00 AM] Info
|
|
@ -129,6 +129,23 @@ const int* Bitmap::GetData() const
|
|||
return m_data;
|
||||
}
|
||||
|
||||
const byte* Bitmap::GetTextureData() const
|
||||
{
|
||||
byte* data = new byte[m_width * m_height * 4];
|
||||
for (int i = 0; i < m_width; i++)
|
||||
{
|
||||
for (int j = 0; j < m_height; j++)
|
||||
{
|
||||
data[(i + j * m_width) * 4 + 0] = (m_data[i + j * m_width] >> 24) & 0xFF;
|
||||
data[(i + j * m_width) * 4 + 1] = (m_data[i + j * m_width] >> 16) & 0xFF;
|
||||
data[(i + j * m_width) * 4 + 2] = (m_data[i + j * m_width] >> 8) & 0xFF;
|
||||
data[(i + j * m_width) * 4 + 3] = (m_data[i + j * m_width]) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
const int& Bitmap::PixelAt(int x, int y) const
|
||||
{
|
||||
assert(x >= 0 && y >= 0 && x < m_width && y < m_height);
|
||||
|
|
|
@ -22,6 +22,7 @@ public:
|
|||
int GetWidth() const;
|
||||
int GetHeight() const;
|
||||
const int* GetData() const;
|
||||
const byte* GetTextureData() const;
|
||||
|
||||
const int& PixelAt(int x, int y) const;
|
||||
int& PixelAt(int x, int y);
|
||||
|
|
|
@ -91,8 +91,11 @@ void Render()
|
|||
return;
|
||||
}
|
||||
|
||||
if (!open)
|
||||
return;
|
||||
|
||||
ImGui::SetNextWindowSize({640, 480}, ImGuiCond_FirstUseEver);
|
||||
if (open && ImGui::Begin("KP3Dii Console", &open, ImGuiWindowFlags_NoCollapse))
|
||||
if (ImGui::Begin("KP3Dii Console", &open, ImGuiWindowFlags_NoCollapse))
|
||||
{
|
||||
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
||||
ImGui::BeginChild(
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "KP3D_Shader.h"
|
||||
#include "KP3D_Noise.h"
|
||||
#include "KP3D_Geometry.h"
|
||||
#include "KP3D_Resources.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -116,15 +117,15 @@ void Map::BuildFlat(Sector& sector, Flat& flat, bool invert)
|
|||
if (s->inverted)
|
||||
{
|
||||
if (FloatCmp(s->floor.base_height, sector.floor.base_height, e))
|
||||
s->floor.texture = nullptr;
|
||||
s->floor.material = nullptr;
|
||||
if (FloatCmp(s->ceiling.base_height, sector.ceiling.base_height, e))
|
||||
s->ceiling.texture = nullptr;
|
||||
s->ceiling.material = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(l.flags & Wall::FLAG_OPENING))
|
||||
{
|
||||
l.textures[TEX_FRONT] = nullptr;
|
||||
l.materials[TEX_FRONT] = nullptr;
|
||||
l.flags = Wall::FLAG_OPENING | Wall::FLAG_SUBSECTOR_OPENING;
|
||||
l.portal = §or;
|
||||
}
|
||||
|
@ -185,8 +186,8 @@ void Map::BuildFlat(Sector& sector, Flat& flat, bool invert)
|
|||
if (FloatCmp(max_height, -MAX)) max_height = flat.base_height;
|
||||
|
||||
// Fix up the UVs so they keep the right scale
|
||||
float tw = flat.texture ? texture_scale / flat.texture->GetWidth() : 0.0f;
|
||||
float th = flat.texture ? texture_scale / flat.texture->GetHeight() : 0.0f;
|
||||
float tw = flat.material ? texture_scale / flat.material->textures[MAT_TEX_DIFFUSE].GetWidth() : 0.0f;
|
||||
float th = flat.material ? texture_scale / flat.material->textures[MAT_TEX_DIFFUSE].GetHeight() : 0.0f;
|
||||
Vertex3D vtxa = Vertex3D(fva, Vec2(au * tw, av * th));
|
||||
Vertex3D vtxb = Vertex3D(fvb, Vec2(bu * tw, bv * th));
|
||||
Vertex3D vtxc = Vertex3D(fvc, Vec2(cu * tw, cv * th));
|
||||
|
@ -194,8 +195,14 @@ void Map::BuildFlat(Sector& sector, Flat& flat, bool invert)
|
|||
flat.triangulated_data.push_back(vtxb);
|
||||
flat.triangulated_data.push_back(vtxc);
|
||||
BatchSectorInfo info = {BatchSectorInfo::BATCH_FLAT, §or, &flat, nullptr};
|
||||
if (flat.texture)
|
||||
m_mesh.AddBatch(flat.texture, { vtxa, vtxb, vtxc }, !invert, std::make_any<BatchSectorInfo>(info));
|
||||
if (flat.material)
|
||||
m_mesh.AddBatch(
|
||||
&flat.material->textures[MAT_TEX_DIFFUSE],
|
||||
{vtxa, vtxb, vtxc},
|
||||
!invert,
|
||||
std::make_any<BatchSectorInfo>(info),
|
||||
&flat.material->textures[MAT_TEX_NORMAL]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,11 +212,11 @@ void Map::BuildFlat(Sector& sector, Flat& flat, bool invert)
|
|||
* To do this we perform a similar approach to BuildFlat, but because the walls aren't strictly along one axis we have to
|
||||
* "flatten" them to perform the math to triangulate them. This is done by projecting the 3D points to 2D.
|
||||
*/
|
||||
void Map::BuildQuad(Sector& sector, Wall& wall, Flat& flat_topr, Flat& flat_bottomr, const Texture* texture, Vec3 pos_a, Vec3 pos_b, bool flip, bool flip_u, bool flip_v, XYf uv_offset)
|
||||
void Map::BuildQuad(Sector& sector, Wall& wall, Flat& flat_topr, Flat& flat_bottomr, const Material* material, Vec3 pos_a, Vec3 pos_b, bool flip, bool flip_u, bool flip_v, XYf uv_offset)
|
||||
{
|
||||
const float E = 4.0f / 128.0f;
|
||||
|
||||
if (!texture)
|
||||
if (!material)
|
||||
return;
|
||||
|
||||
if (sector.inverted)
|
||||
|
@ -290,14 +297,14 @@ void Map::BuildQuad(Sector& sector, Wall& wall, Flat& flat_topr, Flat& flat_bott
|
|||
Vec3 fvc = Vec3(c.x, c.y, 0.0f).Rotated({0, 1, 0}, -ToDegrees(angle)); fvc.x += pos_a.x; fvc.z += pos_a.z;
|
||||
|
||||
// Fix up the UVs so they keep the right scale
|
||||
float tw = texture ? texture_scale / texture->GetWidth() : 0.0f;
|
||||
float th = texture ? texture_scale / texture->GetHeight() : 0.0f;
|
||||
float tw = material ? texture_scale / material->textures[MAT_TEX_DIFFUSE].GetWidth() : 0.0f;
|
||||
float th = material ? texture_scale / material->textures[MAT_TEX_DIFFUSE].GetHeight() : 0.0f;
|
||||
Vertex3D vtxa = Vertex3D(fva, Vec2(au * tw, av * th));
|
||||
Vertex3D vtxb = Vertex3D(fvb, Vec2(bu * tw, bv * th));
|
||||
Vertex3D vtxc = Vertex3D(fvc, Vec2(cu * tw, cv * th));
|
||||
BatchSectorInfo info = {BatchSectorInfo::BATCH_WALL, §or, nullptr, &wall};
|
||||
if (texture)
|
||||
m_mesh.AddBatch(texture, {vtxa, vtxb, vtxc}, flip, std::make_any<BatchSectorInfo>(info));
|
||||
if (material)
|
||||
m_mesh.AddBatch(&material->textures[MAT_TEX_DIFFUSE], {vtxa, vtxb, vtxc}, flip, std::make_any<BatchSectorInfo>(info), &material->textures[MAT_TEX_NORMAL]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -309,7 +316,7 @@ void Map::BuildWall(Sector& sector, Wall& wall)
|
|||
{
|
||||
Vec3 a = {wall.start.x, 0.0f, wall.start.y};
|
||||
Vec3 b = {wall.end.x, 0.0f, wall.end.y};
|
||||
BuildQuad(sector, wall, sector.floor, sector.ceiling, wall.textures[TEX_FRONT], a, b, false, false, false, wall.uv_offset[TEX_FRONT]);
|
||||
BuildQuad(sector, wall, sector.floor, sector.ceiling, wall.materials[TEX_FRONT], a, b, false, false, false, wall.uv_offset[TEX_FRONT]);
|
||||
|
||||
if (!(wall.flags & Wall::FLAG_SUBSECTOR_OPENING))
|
||||
{
|
||||
|
@ -318,10 +325,10 @@ void Map::BuildWall(Sector& sector, Wall& wall)
|
|||
// Build upper and lower walls for sectors connected to other sectors (or sectors within sectors)
|
||||
bool flip = wall.portal->floor.base_height < sector.floor.base_height;
|
||||
if (flip && !FloatCmp(wall.portal->floor.base_height, sector.floor.base_height))
|
||||
BuildQuad(sector, wall, sector.floor, wall.portal->floor, wall.textures[TEX_LOWER], a, b, flip, false, false, wall.uv_offset[TEX_LOWER]);
|
||||
BuildQuad(sector, wall, sector.floor, wall.portal->floor, wall.materials[TEX_LOWER], a, b, flip, false, false, wall.uv_offset[TEX_LOWER]);
|
||||
flip = wall.portal->ceiling.base_height < sector.ceiling.base_height;
|
||||
if (!flip && !FloatCmp(wall.portal->ceiling.base_height, sector.ceiling.base_height))
|
||||
BuildQuad(sector, wall, sector.ceiling, wall.portal->ceiling, wall.textures[TEX_UPPER], a, b, !flip, false, false, wall.uv_offset[TEX_UPPER]);
|
||||
BuildQuad(sector, wall, sector.ceiling, wall.portal->ceiling, wall.materials[TEX_UPPER], a, b, !flip, false, false, wall.uv_offset[TEX_UPPER]);
|
||||
|
||||
wall.flags |= Wall::FLAG_JOINED;
|
||||
}
|
||||
|
@ -331,9 +338,9 @@ void Map::BuildWall(Sector& sector, Wall& wall)
|
|||
if (!(wall.flags & Wall::FLAG_JOINED))
|
||||
{
|
||||
bool flip = wall.portal->floor.base_height < sector.floor.base_height;
|
||||
BuildQuad(sector, wall, sector.floor, wall.portal->floor, wall.textures[TEX_LOWER], a, b, flip, false, false, wall.uv_offset[TEX_LOWER]);
|
||||
BuildQuad(sector, wall, sector.floor, wall.portal->floor, wall.materials[TEX_LOWER], a, b, flip, false, false, wall.uv_offset[TEX_LOWER]);
|
||||
flip = wall.portal->ceiling.base_height < sector.ceiling.base_height;
|
||||
BuildQuad(sector, wall, sector.ceiling, wall.portal->ceiling, wall.textures[TEX_UPPER], a, b, !flip, false, false, wall.uv_offset[TEX_UPPER]);
|
||||
BuildQuad(sector, wall, sector.ceiling, wall.portal->ceiling, wall.materials[TEX_UPPER], a, b, !flip, false, false, wall.uv_offset[TEX_UPPER]);
|
||||
|
||||
wall.flags |= Wall::FLAG_JOINED;
|
||||
}
|
||||
|
@ -425,7 +432,7 @@ void Map::JoinSectors(Sector& sector)
|
|||
w1.start.y = ld.end.y;
|
||||
w1.end.x = l.start.x;
|
||||
w1.end.y = l.start.y;
|
||||
w1.textures[TEX_FRONT] = nullptr;
|
||||
w1.materials[TEX_FRONT] = nullptr;
|
||||
w1.portal = &s;
|
||||
w1.flags = Wall::FLAG_TOUCHED;
|
||||
InsertLine(sector.walls, i + 1, w1);
|
||||
|
@ -451,7 +458,7 @@ void Map::JoinSectors(Sector& sector)
|
|||
w1.start.y = ld.end.y;
|
||||
w1.end.x = l.start.x;
|
||||
w1.end.y = l.start.y;
|
||||
w1.textures[TEX_FRONT] = nullptr;
|
||||
w1.materials[TEX_FRONT] = nullptr;
|
||||
w1.flags = Wall::FLAG_OPENING | Wall::FLAG_TOUCHED;
|
||||
w1.portal = &s;
|
||||
InsertLine(sector.walls, i + 1, w1);
|
||||
|
@ -466,7 +473,7 @@ void Map::JoinSectors(Sector& sector)
|
|||
XYf old_end = ld.end;
|
||||
ld.end.x = l.start.x;
|
||||
ld.end.y = l.start.y;
|
||||
ld.textures[TEX_FRONT] = nullptr;
|
||||
ld.materials[TEX_FRONT] = nullptr;
|
||||
ld.flags = Wall::FLAG_OPENING | Wall::FLAG_TOUCHED;
|
||||
ld.portal = &s;
|
||||
w1.start.x = ld.end.x;
|
||||
|
@ -485,7 +492,7 @@ void Map::JoinSectors(Sector& sector)
|
|||
if (!sector.inverted) // not sure if we want to discount inverted sectors for just this case or all of
|
||||
// them; revisit me!
|
||||
{
|
||||
ld.textures[TEX_FRONT] = nullptr;
|
||||
ld.materials[TEX_FRONT] = nullptr;
|
||||
ld.flags = Wall::FLAG_OPENING | Wall::FLAG_TOUCHED;
|
||||
ld.portal = &s;
|
||||
}
|
||||
|
@ -496,7 +503,7 @@ void Map::JoinSectors(Sector& sector)
|
|||
// Mark the other one as an opening
|
||||
if (!(l.flags & Wall::FLAG_OPENING)) // <- do we want to check this? not sure...
|
||||
{
|
||||
l.textures[TEX_FRONT] = nullptr;
|
||||
l.materials[TEX_FRONT] = nullptr;
|
||||
l.flags = Wall::FLAG_OPENING | Wall::FLAG_TOUCHED;
|
||||
l.portal = §or;
|
||||
}
|
||||
|
@ -543,13 +550,25 @@ void Map::Init()
|
|||
BuildSkybox("skybox_16.jpg");
|
||||
BuildGrid();
|
||||
|
||||
static Texture tex, tex2, tex3, tex4;
|
||||
tex.Load("GRASS2.png", true);
|
||||
tex2.Load("floor0.png", true);
|
||||
tex3.Load("FLAT5_7.png", true);
|
||||
tex4.Load("block.png", true);
|
||||
//static Texture tex, tex2, tex3, tex4;
|
||||
//tex.Load("GRASS2.png", true);
|
||||
//tex2.Load("floor0.png", true);
|
||||
//tex3.Load("FLAT5_7.png", true);
|
||||
//tex4.Load("block.png", true);
|
||||
m_dot.Load("dot.png");
|
||||
|
||||
static Material* tex;
|
||||
static Material* tex2;
|
||||
static Material* tex3;
|
||||
static Material* tex4;
|
||||
|
||||
tex = res::material_cache["GRASS2.png"].get();
|
||||
tex2 = res::material_cache["floor1.png"].get();
|
||||
tex3 = res::material_cache["FLAT5_7.png"].get();
|
||||
tex4 = res::material_cache["block.png"].get();
|
||||
|
||||
|
||||
|
||||
// Build a stupid little test map
|
||||
// ------------------------------
|
||||
// Main sector
|
||||
|
@ -564,11 +583,11 @@ void Map::Init()
|
|||
XYf points5[] = {{11, 4}, {14, 4}, {14, 2}, {16, 2}, {16, 10}, {11, 10}};
|
||||
// Platform above main sector (room over room testing)
|
||||
XYf points6[] = {{1, 4}, {3, 4}, {3, 7}, {1, 7}};
|
||||
auto build_sector = [&](Texture* wall, Texture* lower, Texture* floor, Texture* ceil, float floor_height, float ceil_height, int id, XYf* points, size_t num_points, bool inverted = false)
|
||||
auto build_sector = [&](Material* wall, Material* lower, Material* floor, Material* ceil, float floor_height, float ceil_height, int id, XYf* points, size_t num_points, bool inverted = false)
|
||||
{
|
||||
std::shared_ptr<Sector> s = std::make_unique<Sector>();
|
||||
s->ceiling.texture = ceil;
|
||||
s->floor.texture = floor;
|
||||
s->ceiling.material = ceil;
|
||||
s->floor.material = floor;
|
||||
s->floor.floor = true;
|
||||
s->floor.base_height = floor_height;
|
||||
s->ceiling.base_height = ceil_height;
|
||||
|
@ -580,12 +599,12 @@ void Map::Init()
|
|||
s->walls.push_back(Wall{ {wall,wall,lower}, {{0, 0}}, points[i], points[(i + 1) % num_points], Wall::NO_FLAGS, Wall::NO_UFLAGS, (uint)i });
|
||||
sectors.push_back(s);
|
||||
};
|
||||
build_sector(&tex3, &tex3, &tex, &tex2, -1.0f, 5.0f, 1, points, std::size(points));
|
||||
build_sector(&tex4, &tex4, &tex2, &tex2, -1.5f, 4.0f, 2, points2, std::size(points2));
|
||||
build_sector(&tex4, &tex4, &tex, &tex2, -1.5f, 5.0f, 3, points3, std::size(points3), true);
|
||||
build_sector(&tex4, &tex4, &tex, &tex2, -1.5f, 4.0f, 4, points4, std::size(points4), true);
|
||||
build_sector(&tex3, &tex4, &tex, &tex2, 0.0f, 2.0f, 5, points5, std::size(points5), false);
|
||||
build_sector(&tex4, &tex4, &tex4, &tex4, 1.0f, 1.4f, 6, points6, std::size(points6), true);
|
||||
build_sector(tex3, tex3, tex, tex2, -1.0f, 5.0f, 1, points, std::size(points));
|
||||
build_sector(tex4, tex4, tex2, tex2, -1.5f, 4.0f, 2, points2, std::size(points2));
|
||||
build_sector(tex4, tex4, tex, tex2, -1.5f, 5.0f, 3, points3, std::size(points3), true);
|
||||
build_sector(tex4, tex4, tex, tex2, -1.5f, 4.0f, 4, points4, std::size(points4), true);
|
||||
build_sector(tex3, tex4, tex, tex2, 0.0f, 2.0f, 5, points5, std::size(points5), false);
|
||||
build_sector(tex4, tex4, tex4, tex4, 1.0f, 1.4f, 6, points6, std::size(points6), true);
|
||||
|
||||
Rebuild(GEN_NORMALS);
|
||||
}
|
||||
|
@ -701,12 +720,12 @@ void Map::Rebuild(NormalGenType gen_normals)
|
|||
continue;
|
||||
|
||||
//if (s.id == 1 || s.id == 5)
|
||||
{
|
||||
//{
|
||||
// float yv0 = PerlinNoise2D(steiner_point.x, steiner_point.y, 1.0, 10.0);
|
||||
// float yv1 = -PerlinNoise2D(steiner_point.x, steiner_point.y, 0.5, 9.0);
|
||||
// s.floor.steiner_points.push_back({ steiner_point.x, yv0, steiner_point.y });
|
||||
// s.ceiling.steiner_points.push_back({ steiner_point.x, yv1, steiner_point.y });
|
||||
}
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -737,7 +756,7 @@ void Map::Rebuild(NormalGenType gen_normals)
|
|||
|
||||
// Finalize the mesh
|
||||
m_mesh.Finalize(
|
||||
gen_normals,
|
||||
GEN_SMOOTH_NORMALS,
|
||||
[](const RenderBatch3D& a, const RenderBatch3D& b) -> bool
|
||||
{
|
||||
return /*a.texture->GetGLID() < b.texture->GetGLID() &&*/
|
||||
|
@ -763,10 +782,10 @@ void Map::Update()
|
|||
void Map::Render()
|
||||
{
|
||||
// Skybox
|
||||
RenderSkybox();
|
||||
// RenderSkybox();
|
||||
|
||||
// Map
|
||||
glDisable(GL_CULL_FACE); // <- we shouldn't count on this
|
||||
//glDisable(GL_CULL_FACE); // <- we shouldn't count on this
|
||||
kp3d::Renderer3D::PushShader(kp3d::Renderer3D::GetMapShader());
|
||||
kp3d::Renderer3D::DrawMesh(m_mesh, m_transform, true, ShouldHighlight);
|
||||
kp3d::Renderer3D::PopShader();
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "KP3D_StaticMesh.h"
|
||||
#include "KP3D_Transform.h"
|
||||
#include "KP3D_Shader.h"
|
||||
#include "KP3D_Material.h"
|
||||
|
||||
namespace kp3d {
|
||||
|
||||
|
@ -35,10 +36,11 @@ struct Wall
|
|||
enum UserFlags: byte
|
||||
{
|
||||
NO_UFLAGS,
|
||||
UFLAG_ALIGN_WITH_HEIGHTMAP = 1 << 0
|
||||
UFLAG_ALIGN_WITH_HEIGHTMAP = 1 << 0,
|
||||
UFLAG_DOUBLESIDED = 1 << 1
|
||||
};
|
||||
|
||||
const Texture* textures[3];
|
||||
const Material* materials[3];
|
||||
XYf uv_offset[3];
|
||||
|
||||
XYf start;
|
||||
|
@ -54,7 +56,7 @@ struct Wall
|
|||
|
||||
struct Flat
|
||||
{
|
||||
const Texture* texture;
|
||||
const Material* material;
|
||||
float base_height;
|
||||
float min_height;
|
||||
float max_height;
|
||||
|
@ -130,7 +132,7 @@ public:
|
|||
ErrCode SaveToFile(const std::string& path);
|
||||
|
||||
void BuildFlat(Sector& sector, Flat& flat, bool invert);
|
||||
void BuildQuad(Sector& sector, Wall& wall, Flat& flat_top, Flat& flat_bottom, const Texture* texture, Vec3 pos_a, Vec3 pos_b, bool flip, bool flip_u, bool flip_v, XYf uv_offset);
|
||||
void BuildQuad(Sector& sector, Wall& wall, Flat& flat_top, Flat& flat_bottom, const Material* material, Vec3 pos_a, Vec3 pos_b, bool flip, bool flip_u, bool flip_v, XYf uv_offset);
|
||||
void BuildWall(Sector& sector, Wall& wall);
|
||||
void JoinSectors(Sector& sector);
|
||||
void SanitizeSectors();
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
#include "KP3D_Material.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include "KP3D_StringUtils.h"
|
||||
#include "KP3D_SystemUtils.h"
|
||||
#include "KP3D_Log.h"
|
||||
#include "KP3D_Bitmap.h"
|
||||
|
||||
namespace kp3d {
|
||||
|
||||
static Bitmap placeholder_normal(128, 128);
|
||||
static bool built_placeholder_normal = false;
|
||||
|
||||
void LoadMaterial(Material& material, std::string path)
|
||||
{
|
||||
path = "materials/" + path;
|
||||
|
||||
if (str::EndsWith(path, "_n.png"))
|
||||
return;
|
||||
|
||||
// Diffuse texture is just gonna be the regular path we give it
|
||||
material.textures[MAT_TEX_DIFFUSE].Load(path, true, Texture::FILTER_LINEAR);
|
||||
|
||||
// Only gonna support .png and .jpg (not .jpeg) for now.
|
||||
// If you need something else, get bent loser
|
||||
std::string ext = ".png";
|
||||
if (str::EndsWith(path, ext))
|
||||
{
|
||||
str::ReplaceAll(path, ext, "");
|
||||
}
|
||||
else if (str::EndsWith(path, ".jpg"))
|
||||
{
|
||||
ext = ".jpg";
|
||||
str::ReplaceAll(path, ext, "");
|
||||
}
|
||||
else if (str::EndsWith(path, ".webp"))
|
||||
{
|
||||
KP3D_LOG_ERROR("FUCK WEBP!!! ALL MY HOMIES HATE WEBP!!!");
|
||||
exit(1337);
|
||||
}
|
||||
|
||||
// Now look for normal textures in the form of _n suffixes
|
||||
std::string normal_path = path + "_n" + ext;
|
||||
if (std::filesystem::exists(sys::GetTextureDir() + normal_path))
|
||||
{
|
||||
KP3D_LOG_INFO("Found normal map texture: {}", normal_path);
|
||||
material.textures[MAT_TEX_NORMAL].Load(normal_path, true, Texture::FILTER_LINEAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make a little placeholder normal texture (this could be done more efficiently but whatever)
|
||||
if (!built_placeholder_normal)
|
||||
{
|
||||
int w = placeholder_normal.GetWidth(), h = placeholder_normal.GetHeight();
|
||||
for (int i = 0; i < w * h; i++)
|
||||
placeholder_normal.PixelAt(i % w, i / w) = 0x7F7FFFFF;
|
||||
built_placeholder_normal = true;
|
||||
}
|
||||
const byte* data = placeholder_normal.GetTextureData();
|
||||
material.textures[MAT_TEX_NORMAL].Load(data, placeholder_normal.GetWidth(), placeholder_normal.GetHeight(), true, Texture::FILTER_LINEAR);
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
// & perhaps in the future we'll support roughness maps, metallic maps, heightmaps, etc. but for now, just this
|
||||
// ...
|
||||
}
|
||||
|
||||
} // namespace kp3d
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "KP3D_Common.h"
|
||||
#include "KP3D_Texture.h"
|
||||
|
||||
|
@ -17,4 +19,6 @@ struct Material
|
|||
Texture textures[NUM_MAT_TEX];
|
||||
};
|
||||
|
||||
void LoadMaterial(Material& material, std::string path);
|
||||
|
||||
} // namespace kp3d
|
||||
|
|
|
@ -201,17 +201,32 @@ void Renderer3D::DrawMesh(StaticMesh& mesh, const Mat4& m, bool bind_shader, uin
|
|||
bool skinned = !batch.bone_data.empty();
|
||||
|
||||
if (batch.texture)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
batch.texture->Bind();
|
||||
}
|
||||
if (batch.normal_texture)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
batch.normal_texture->Bind();
|
||||
r3d_state->shader->SetUniform("u_normal_texture", 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, batch.gl_vbo_id);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glEnableVertexAttribArray(2);
|
||||
glEnableVertexAttribArray(4);
|
||||
glEnableVertexAttribArray(5);
|
||||
if (skinned)
|
||||
{
|
||||
glEnableVertexAttribArray(3);
|
||||
glEnableVertexAttribArray(4);
|
||||
glEnableVertexAttribArray(5);
|
||||
glEnableVertexAttribArray(6);
|
||||
}
|
||||
|
||||
glVertexAttribPointer(
|
||||
|
@ -219,17 +234,19 @@ void Renderer3D::DrawMesh(StaticMesh& mesh, const Mat4& m, bool bind_shader, uin
|
|||
);
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex3D), reinterpret_cast<GLvoid*>(offsetof(Vertex3D, normal)));
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex3D), reinterpret_cast<GLvoid*>(offsetof(Vertex3D, uv)));
|
||||
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex3D), reinterpret_cast<GLvoid*>(offsetof(Vertex3D, atangent)));
|
||||
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex3D), reinterpret_cast<GLvoid*>(offsetof(Vertex3D, bitangent)));
|
||||
if (skinned)
|
||||
{
|
||||
glVertexAttribIPointer(
|
||||
3,
|
||||
5,
|
||||
MAX_NUM_BONES_PER_VERTEX,
|
||||
GL_UNSIGNED_INT,
|
||||
sizeof(Vertex3D),
|
||||
reinterpret_cast<GLvoid*>(offsetof(Vertex3D, bone_ids))
|
||||
);
|
||||
glVertexAttribPointer(
|
||||
4,
|
||||
6,
|
||||
MAX_NUM_BONES_PER_VERTEX,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
|
@ -250,9 +267,11 @@ void Renderer3D::DrawMesh(StaticMesh& mesh, const Mat4& m, bool bind_shader, uin
|
|||
|
||||
if (skinned)
|
||||
{
|
||||
glDisableVertexAttribArray(6);
|
||||
glDisableVertexAttribArray(5);
|
||||
}
|
||||
glDisableVertexAttribArray(4);
|
||||
glDisableVertexAttribArray(3);
|
||||
}
|
||||
glDisableVertexAttribArray(2);
|
||||
glDisableVertexAttribArray(1);
|
||||
glDisableVertexAttribArray(0);
|
||||
|
@ -437,6 +456,9 @@ void Renderer3D::ReloadShaders()
|
|||
void Renderer3D::Tick()
|
||||
{
|
||||
r3d_state->time += 1.0f;
|
||||
|
||||
if ((int)r3d_state->time % 60 == 0)
|
||||
ReloadShaders();
|
||||
}
|
||||
|
||||
const Shader& Renderer3D::GetShader()
|
||||
|
|
|
@ -5,15 +5,18 @@
|
|||
|
||||
#include "KP3D_StringUtils.h"
|
||||
#include "KP3D_SystemUtils.h"
|
||||
#include "KP3D_Log.h"
|
||||
|
||||
namespace kp3d::res {
|
||||
|
||||
std::unordered_map<std::string, std::shared_ptr<Material>> material_cache;
|
||||
|
||||
void LoadMaterials()
|
||||
{
|
||||
texture_cache.clear();
|
||||
material_cache.clear();
|
||||
|
||||
// Load every available texture
|
||||
for (const auto& entry: std::filesystem::recursive_directory_iterator(kp3d::sys::GetTextureDir()))
|
||||
for (const auto& entry: std::filesystem::recursive_directory_iterator(kp3d::sys::GetTextureDir() + "materials/"))
|
||||
{
|
||||
if (entry.is_directory())
|
||||
continue;
|
||||
|
@ -24,10 +27,16 @@ void LoadMaterials()
|
|||
if (!kp3d::str::EndsWith(path_str, ".png") && !kp3d::str::EndsWith(path_str, ".jpg"))
|
||||
continue;
|
||||
|
||||
std::string filename = std::filesystem::proximate(path_str, kp3d::sys::GetTextureDir()).string();
|
||||
std::string filename = std::filesystem::proximate(path_str, kp3d::sys::GetTextureDir() + "materials/").string();
|
||||
std::replace(filename.begin(), filename.end(), '\\', '/');
|
||||
|
||||
// texture_cache.emplace(filename, );
|
||||
if (kp3d::str::EndsWith(path_str, "_n.png"))
|
||||
continue;
|
||||
|
||||
KP3D_LOG_INFO("Loading material resource: {}", filename);
|
||||
|
||||
material_cache.emplace(filename, std::make_shared<Material>());
|
||||
LoadMaterial(*material_cache[filename], filename);
|
||||
|
||||
// new:
|
||||
// m_loaded_res_mutex.lock();
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
|
||||
#include "KP3D_Common.h"
|
||||
#include "KP3D_Texture.h"
|
||||
|
@ -9,7 +10,7 @@
|
|||
|
||||
namespace kp3d::res {
|
||||
|
||||
std::unordered_map<std::string, kp3d::Texture*> texture_cache;
|
||||
extern std::unordered_map<std::string, std::shared_ptr<Material>> material_cache;
|
||||
|
||||
void LoadMaterials();
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ StaticMesh::~StaticMesh()
|
|||
glDeleteVertexArrays(1, &m_gl_vao_id);
|
||||
}
|
||||
|
||||
void StaticMesh::AddBatch(const Texture* texture, const std::vector<Vertex3D>& vertex_data, bool flip, std::any user_data)
|
||||
void StaticMesh::AddBatch(const Texture* texture, const std::vector<Vertex3D>& vertex_data, bool flip, std::any user_data, const Texture* normal_texture)
|
||||
{
|
||||
// "flipping" the vertex data basically means changing the order of the vertices so it faces
|
||||
// a different direction than it did previously, useful for making sure stuff works with culling
|
||||
|
@ -93,11 +93,11 @@ void StaticMesh::AddBatch(const Texture* texture, const std::vector<Vertex3D>& v
|
|||
flipped_data[i + 2] = vertex_data[i + 1];
|
||||
}
|
||||
|
||||
m_batches.push_back({0, texture, flipped_data});
|
||||
m_batches.push_back({0, texture, normal_texture, flipped_data});
|
||||
}
|
||||
else
|
||||
{
|
||||
m_batches.push_back({0, texture, vertex_data});
|
||||
m_batches.push_back({0, texture, normal_texture, vertex_data});
|
||||
}
|
||||
|
||||
// Clean me/move me somewhere else
|
||||
|
@ -125,7 +125,8 @@ void StaticMesh::AddBatch(const Texture* texture, const std::vector<Vertex3D>& v
|
|||
void StaticMesh::AddIndexedBatch(
|
||||
const Texture* texture,
|
||||
const std::vector<Vertex3D>& vertex_data,
|
||||
const std::vector<uint>& index_data
|
||||
const std::vector<uint>& index_data,
|
||||
const Texture* normal_texture
|
||||
)
|
||||
{
|
||||
// Do we really need to do this flipping all the time?
|
||||
|
@ -138,7 +139,7 @@ void StaticMesh::AddIndexedBatch(
|
|||
flipped_data[i + 2] = index_data[i + 1];
|
||||
}
|
||||
|
||||
m_batches.push_back({0, texture, vertex_data, 0, flipped_data});
|
||||
m_batches.push_back({0, texture, normal_texture, vertex_data, 0, flipped_data});
|
||||
}
|
||||
|
||||
// Experimental feature for KP3D 0.2 -- skinned (skeletal animated) meshes using bones
|
||||
|
@ -147,7 +148,8 @@ void StaticMesh::AddSkinnedBatch(
|
|||
const std::vector<Vertex3D>& vertex_data,
|
||||
const std::vector<uint>& index_data,
|
||||
const std::vector<VertexBoneData>& bone_data,
|
||||
bool flipped
|
||||
bool flipped,
|
||||
const Texture* normal_texture
|
||||
)
|
||||
{
|
||||
skinnable = true;
|
||||
|
@ -170,7 +172,7 @@ void StaticMesh::AddSkinnedBatch(
|
|||
}
|
||||
}
|
||||
|
||||
m_batches.push_back({0, texture, vertex_data, 0, flipped_data, bone_data});
|
||||
m_batches.push_back({0, texture, normal_texture, vertex_data, 0, flipped_data, bone_data});
|
||||
}
|
||||
|
||||
// Take the batches, order them by texture ID, and have one draw call per texture use.
|
||||
|
@ -251,6 +253,19 @@ void StaticMesh::Finalize(NormalGenType gen_normals, BatchComparison sort, Batch
|
|||
v0.normal += n;
|
||||
v1.normal += n;
|
||||
v2.normal += n;
|
||||
|
||||
// While we're at it let's calculate the tangents and bitangents
|
||||
Vec2 delta_uv1 = v1.uv - v0.uv;
|
||||
Vec2 delta_uv2 = v2.uv - v0.uv;
|
||||
float f = 1.0f / (delta_uv1.x * delta_uv2.y - delta_uv2.x * delta_uv1.y);
|
||||
Vec3 tangent = f * (delta_uv2.y * vz1 - delta_uv1.y * vz2);
|
||||
Vec3 bitangent = f * (-delta_uv2.x * vz1 + delta_uv1.x * vz2);
|
||||
v0.atangent += tangent;
|
||||
v1.atangent += tangent;
|
||||
v2.atangent += tangent;
|
||||
v0.bitangent += bitangent;
|
||||
v1.bitangent += bitangent;
|
||||
v2.bitangent += bitangent;
|
||||
}
|
||||
for (size_t j = 0; j < current.vertex_data.size(); j++)
|
||||
{
|
||||
|
|
|
@ -25,6 +25,8 @@ public:
|
|||
Vec3 position;
|
||||
Vec3 normal;
|
||||
Vec2 uv;
|
||||
Vec3 atangent;
|
||||
Vec3 bitangent;
|
||||
uint bone_ids[MAX_NUM_BONES_PER_VERTEX] = {0};
|
||||
float weights[MAX_NUM_BONES_PER_VERTEX] = {0.0f};
|
||||
};
|
||||
|
@ -54,6 +56,7 @@ struct RenderBatch3D
|
|||
{
|
||||
GLuint gl_vbo_id = 0;
|
||||
const Texture* texture;
|
||||
const Texture* normal_texture;
|
||||
std::vector<Vertex3D> vertex_data;
|
||||
GLuint gl_ibo_id = 0;
|
||||
std::vector<uint> index_data;
|
||||
|
@ -77,14 +80,15 @@ public:
|
|||
StaticMesh();
|
||||
~StaticMesh();
|
||||
|
||||
void AddBatch(const Texture* texture, const std::vector<Vertex3D>& vertex_data, bool flip = false, std::any user_data = {});
|
||||
void AddIndexedBatch(const Texture* texture, const std::vector<Vertex3D>& vertex_data, const std::vector<uint>& index_data);
|
||||
void AddBatch(const Texture* texture, const std::vector<Vertex3D>& vertex_data, bool flip = false, std::any user_data = {}, const Texture* normal_texture = nullptr);
|
||||
void AddIndexedBatch(const Texture* texture, const std::vector<Vertex3D>& vertex_data, const std::vector<uint>& index_data, const Texture* normal_texture = nullptr);
|
||||
void AddSkinnedBatch(
|
||||
const Texture* texture,
|
||||
const std::vector<Vertex3D>& vertex_data,
|
||||
const std::vector<uint>& index_data,
|
||||
const std::vector<VertexBoneData>& bone_data,
|
||||
bool flip = true
|
||||
bool flip = true,
|
||||
const Texture* normal_texture = nullptr
|
||||
);
|
||||
void Finalize(NormalGenType gen_normals = GEN_NORMALS, BatchComparison sort = nullptr, BatchComparison criteria = nullptr);
|
||||
void Reset();
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
#include "KP3D_Geometry.h"
|
||||
#include "KP3D_Console.h"
|
||||
#include "KP3D_EventBus.h"
|
||||
#include "KP3D_StringUtils.h"
|
||||
#include "KP3D_SystemUtils.h"
|
||||
#include "KP3D_Resources.h"
|
||||
|
||||
#include "Sandbox.h"
|
||||
|
||||
|
@ -33,8 +36,8 @@ Editor::Editor()
|
|||
{
|
||||
m_banner.Load(".kp3d/banner.png");
|
||||
m_stem.Load("editor/stem.png");
|
||||
m_block.Load("block.png", true);
|
||||
m_mode = MODE_BUILD;
|
||||
// m_block.Load("block.png", true);
|
||||
m_mode = MODE_NORMAL;
|
||||
|
||||
kp3d::EventBus::Subscribe(this, &Editor::OnScrollWheel);
|
||||
kp3d::EventBus::Subscribe(this, &Editor::OnKeyPress);
|
||||
|
@ -163,8 +166,8 @@ void Editor::UpdateModeBuild()
|
|||
if (points.size() >= 3 && kp3d::PosCmp(points.back(), points.front(), 1.0f / 128.0f))// points.back() == points.front())
|
||||
{
|
||||
std::shared_ptr<kp3d::Sector> s = std::make_shared<kp3d::Sector>();
|
||||
s->ceiling.texture = &m_block;
|
||||
s->floor.texture = &m_block;
|
||||
s->ceiling.material = kp3d::res::material_cache["block.png"].get();
|
||||
s->floor.material = kp3d::res::material_cache["block.png"].get();
|
||||
s->floor.floor = true;
|
||||
s->floor.base_height = 0.0f;
|
||||
s->ceiling.base_height = 2.0f;
|
||||
|
@ -178,7 +181,7 @@ void Editor::UpdateModeBuild()
|
|||
wall.end = { points[i + 1].x, -points[i + 1].z };
|
||||
wall.uid = i;
|
||||
for (int j = 0; j < 3; j++)
|
||||
wall.textures[j] = &m_block;
|
||||
wall.materials[j] = kp3d::res::material_cache["block.png"].get();
|
||||
|
||||
s->walls.push_back(wall);
|
||||
}
|
||||
|
@ -213,8 +216,8 @@ void Editor::UpdateModeBuild()
|
|||
if (has_start_pos)
|
||||
{
|
||||
std::shared_ptr<kp3d::Sector> s = std::make_shared<kp3d::Sector>();
|
||||
s->ceiling.texture = &m_block;
|
||||
s->floor.texture = &m_block;
|
||||
s->ceiling.material = kp3d::res::material_cache["block.png"].get();
|
||||
s->floor.material = kp3d::res::material_cache["block.png"].get();
|
||||
s->floor.floor = true;
|
||||
s->floor.base_height = 0.0f;
|
||||
s->ceiling.base_height = 4.0f;
|
||||
|
@ -230,7 +233,7 @@ void Editor::UpdateModeBuild()
|
|||
wall.flags = kp3d::Wall::NO_FLAGS;
|
||||
wall.user_flags = kp3d::Wall::NO_UFLAGS;
|
||||
for (int j = 0; j < 3; j++)
|
||||
wall.textures[j] = &m_block;
|
||||
wall.materials[j] = kp3d::res::material_cache["block.png"].get();
|
||||
|
||||
s->walls.push_back(wall);
|
||||
}
|
||||
|
@ -260,8 +263,8 @@ void Editor::RenderUI()
|
|||
}
|
||||
if (ImGui::BeginMenu("View"))
|
||||
{
|
||||
ImGui::Checkbox("Info overlay", &show_info_overlay);
|
||||
ImGui::Checkbox("Selection information", &show_selection_info);
|
||||
ImGui::Checkbox("Info Overlay", &show_info_overlay);
|
||||
ImGui::Checkbox("Selection Info", &show_selection_info);
|
||||
ImGui::Checkbox("Console", &kp3d::console::open);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
@ -277,24 +280,40 @@ void Editor::RenderUI()
|
|||
RenderUIAbout();
|
||||
|
||||
// Sector window
|
||||
// ImGui::SetNextWindowSize({400, 500}, ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize({400, 500}, ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowPos({20, 200}, ImGuiCond_FirstUseEver);
|
||||
if (show_selection_info)
|
||||
{
|
||||
if (ImGui::Begin("Selection Information", &show_selection_info, ImGuiWindowFlags_AlwaysAutoResize))
|
||||
if (ImGui::Begin("Selection Info", &show_selection_info))
|
||||
{
|
||||
if (m_mode == MODE_BUILD)
|
||||
if (m_mode != MODE_NORMAL)
|
||||
{
|
||||
ImGui::Text("No selection");
|
||||
}
|
||||
else if (m_mode == MODE_NORMAL)
|
||||
else
|
||||
{
|
||||
if (kp3d::editor_hovered_batch)
|
||||
{
|
||||
try
|
||||
{
|
||||
const auto& info = std::any_cast<kp3d::BatchSectorInfo>(kp3d::editor_hovered_batch->userdata);
|
||||
if (info.sector)
|
||||
ImGui::SeparatorText("Type");
|
||||
ImGui::Text(info.wall ? "Wall" : "Flat/Sector");
|
||||
if (info.wall)
|
||||
{
|
||||
ImGui::SeparatorText("Hierarchy");
|
||||
ImGui::Text("Sector ID: %u\n", info.sector->id);
|
||||
|
||||
ImGui::SeparatorText("Properties");
|
||||
ImGui::CheckboxFlags("Align with heightmap", (unsigned*)&info.wall->user_flags, kp3d::Wall::UFLAG_ALIGN_WITH_HEIGHTMAP);
|
||||
ImGui::CheckboxFlags("Double-sided", (unsigned*)&info.wall->user_flags, kp3d::Wall::UFLAG_DOUBLESIDED);
|
||||
|
||||
ImGui::SeparatorText("Materials");
|
||||
RenderUIMaterialSelect("Middle", info.wall->materials[kp3d::TEX_FRONT]);
|
||||
RenderUIMaterialSelect("Upper", info.wall->materials[kp3d::TEX_UPPER]);
|
||||
RenderUIMaterialSelect("Lower", info.wall->materials[kp3d::TEX_LOWER]);
|
||||
}
|
||||
else if (info.sector)
|
||||
{
|
||||
ImGui::SeparatorText("Hierarchy");
|
||||
ImGui::Text("ID: %u\n", info.sector->id);
|
||||
|
@ -305,14 +324,15 @@ void Editor::RenderUI()
|
|||
ImGui::Text("- ID: %u", sc->id);
|
||||
ImGui::Unindent();
|
||||
ImGui::SeparatorText("Properties");
|
||||
ImGui::InputFloat("Floor height", &info.sector->floor.base_height);
|
||||
ImGui::InputFloat("Ceiling height", &info.sector->ceiling.base_height);
|
||||
ImGui::Checkbox("Inverted", &info.sector->inverted);
|
||||
int changed = 0;
|
||||
changed |= ImGui::InputFloat("Floor height", &info.sector->floor.base_height);
|
||||
changed |= ImGui::InputFloat("Ceiling height", &info.sector->ceiling.base_height);
|
||||
changed |= ImGui::Checkbox("Inverted", &info.sector->inverted);
|
||||
if (changed)
|
||||
sandbox->map.Rebuild(kp3d::GEN_NORMALS);
|
||||
ImGui::SeparatorText("Materials");
|
||||
ImGui::Text("Floor:");
|
||||
ImGui::ImageButton((ImTextureID) info.sector->floor.texture->GetGLID(), {128, 128});
|
||||
ImGui::Text("Ceiling:");
|
||||
ImGui::ImageButton((ImTextureID)info.sector->ceiling.texture->GetGLID(), { 128, 128 });
|
||||
RenderUIMaterialSelect("Floor", info.sector->floor.material);
|
||||
RenderUIMaterialSelect("Ceiling", info.sector->ceiling.material);
|
||||
}
|
||||
}
|
||||
catch (std::bad_any_cast& e)
|
||||
|
@ -380,6 +400,21 @@ void Editor::RenderUIAbout()
|
|||
}
|
||||
}
|
||||
|
||||
void Editor::RenderUIMaterialSelect(const char* name, const kp3d::Material* material)
|
||||
{
|
||||
ImGui::Text("%s:", name);
|
||||
if (material)
|
||||
{
|
||||
if (ImGui::ImageButton((ImTextureID)material->textures[kp3d::MAT_TEX_DIFFUSE].GetGLID(), {96, 96})) {}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string str = "Set " + kp3d::str::ToLower(name) + " material...";
|
||||
if (ImGui::Button(str.c_str())) {}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Editor::OnScrollWheel(const kp3d::ScrollWheelEvent* e)
|
||||
{
|
||||
using namespace kp3d;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "KP3D_Texture.h"
|
||||
#include "KP3D_Math.h"
|
||||
#include "KP3D_IOEvents.h"
|
||||
#include "KP3D_Material.h"
|
||||
|
||||
enum EditMode
|
||||
{
|
||||
|
@ -30,6 +31,7 @@ public:
|
|||
void RenderUI();
|
||||
void RenderUIInfo();
|
||||
void RenderUIAbout();
|
||||
void RenderUIMaterialSelect(const char* name, const kp3d::Material* material);
|
||||
|
||||
void OnScrollWheel(const kp3d::ScrollWheelEvent* e);
|
||||
void OnKeyPress(const kp3d::KeyPressEvent* e);
|
||||
|
@ -40,7 +42,6 @@ private:
|
|||
private:
|
||||
kp3d::Texture m_banner;
|
||||
kp3d::Texture m_stem;
|
||||
kp3d::Texture m_block;
|
||||
kp3d::Vec3 m_stem_pos;
|
||||
EditMode m_mode;
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <KP3D_Renderer3D.h>
|
||||
#include <KP3D_Console.h>
|
||||
#include <KP3D_StringUtils.h>
|
||||
#include <KP3D_Resources.h>
|
||||
|
||||
static kp3d::Texture tex;
|
||||
static std::vector<kp3d::XYf> points;
|
||||
|
@ -15,6 +16,8 @@ static std::vector<kp3d::XYf> points;
|
|||
Sandbox::Sandbox(const std::string& path):
|
||||
kp3d::Game(path, "sandbox-cfg.json", "sandbox-log.txt")
|
||||
{
|
||||
kp3d::res::LoadMaterials();
|
||||
|
||||
tex.Load("logo.png");
|
||||
crosshair.Load(".kp3d/crosshair.png");
|
||||
m_projection.InitPerspective(70.0f, (float) GetWidth() / (float) GetHeight());
|
||||
|
|