diff --git a/src/assets/map.cpp b/src/assets/map.cpp index 2856e06..e6757e6 100644 --- a/src/assets/map.cpp +++ b/src/assets/map.cpp @@ -26,10 +26,14 @@ std::shared_ptr assets::Map::LoadFromFile(const std::string& glm::vec3 angles; - iss >> obj.transform.position.x >> obj.transform.position.y >> obj.transform.position.z; + auto trans = &obj.node.local; + + iss >> trans->position.x >> trans->position.y >> trans->position.z; iss >> angles.x >> angles.y >> angles.z; - obj.transform.SetAngles(angles); - iss >> obj.transform.scale; + trans->SetAngles(angles); + iss >> trans->scale; + + obj.node.UpdateMatrix(); std::string flag; while (iss >> flag) @@ -62,5 +66,22 @@ void assets::Map::Draw(gfx::DrawList& dlist) const cmd.surface = &surface; dlist.AddSurface(cmd); } + + for (const auto& obj : static_objects_) + { + if (!obj.model || !obj.model->GetMesh()) + continue; + + const auto& surfaces = obj.model->GetMesh()->surfaces; + + for (const auto& surface : surfaces) + { + gfx::DrawSurfaceCmd cmd; + cmd.surface = &surface; + cmd.matrices = &obj.node.matrix; + // cmd.color_mod = glm::vec4(obj.color, 1.0f); + dlist.AddSurface(cmd); + } + } } #endif // CLIENT \ No newline at end of file diff --git a/src/assets/map.hpp b/src/assets/map.hpp index acc9307..02eadf9 100644 --- a/src/assets/map.hpp +++ b/src/assets/map.hpp @@ -4,7 +4,7 @@ #include #include "model.hpp" -#include "utils/transform.hpp" +#include "game/transform_node.hpp" #ifdef CLIENT #include "gfx/draw_list.hpp" @@ -15,7 +15,7 @@ namespace assets struct MapStaticObject { - Transform transform; + game::TransformNode node; std::shared_ptr model; glm::vec3 color = glm::vec3(1.0f); }; diff --git a/src/assets/model.cpp b/src/assets/model.cpp index abb124c..35b6769 100644 --- a/src/assets/model.cpp +++ b/src/assets/model.cpp @@ -76,14 +76,21 @@ std::shared_ptr assets::Model::LoadFromFile(const std::stri { CLIENT_ONLY(sflags |= gfx::SF_2SIDED;) } - else if (flag == "+transparent") - { - CLIENT_ONLY(sflags |= gfx::SF_TRANSPARENT;) - } else if (flag == "+ocolor") { CLIENT_ONLY(sflags |= gfx::SF_OBJECT_COLOR;) } + else if (flag == "+blend") + { + std::string blend_str; + iss >> blend_str; + + CLIENT_ONLY( + sflags |= gfx::SF_BLEND; + if (blend_str == "additive") + sflags |= gfx::SF_BLEND_ADDITIVE; + ) + } } CLIENT_ONLY( @@ -128,7 +135,8 @@ std::shared_ptr assets::Model::LoadFromFile(const std::stri // Optional but recommended auto shape_hull = std::make_unique(temp_hull.get()); - shape_hull->buildHull(temp_hull->getMargin()); + // shape_hull->buildHull(temp_hull->getMargin()); + shape_hull->buildHull(0.01f); model->cshape_ = std::make_unique((btScalar*)shape_hull->getVertexPointer(), shape_hull->numVertices(), sizeof(btVector3)); } diff --git a/src/client/app.cpp b/src/client/app.cpp index 63f4916..8d0e1a9 100644 --- a/src/client/app.cpp +++ b/src/client/app.cpp @@ -69,7 +69,7 @@ void App::Frame() float aspect = static_cast(viewport_size_.x) / static_cast(viewport_size_.y); renderer_.Begin(viewport_size_.x, viewport_size_.y); - renderer_.ClearColor(glm::vec3(0.3f, 0.9f, 1.0f)); + renderer_.ClearColor(glm::vec3(0.5f, 0.7f, 1.0f)); renderer_.ClearDepth(); dlist_.Clear(); diff --git a/src/client/main.cpp b/src/client/main.cpp index 88480bc..b6c4e06 100644 --- a/src/client/main.cpp +++ b/src/client/main.cpp @@ -15,7 +15,11 @@ #ifdef _WIN32 #define NOMINMAX #pragma comment(lib, "ws2_32") +#pragma comment(lib, "winmm.lib") #include +#include +#include +#include #endif #include "app.hpp" @@ -391,11 +395,26 @@ static void Main() { emscripten_set_main_loop(Frame, 0, true); #else +#ifdef _WIN32 + timeBeginPeriod(1); +#endif SDL_GL_SetSwapInterval(0); + auto frame_dur = std::chrono::milliseconds(5); + while (!s_quit) { + auto t_start = std::chrono::steady_clock::now(); + Frame(); + + auto t_next = t_start + frame_dur; + auto t_now = std::chrono::steady_clock::now(); + + if (t_now < t_next) + { + std::this_thread::sleep_for(t_next - t_now); + } } s_app.reset(); diff --git a/src/collision/dynamicsworld.cpp b/src/collision/dynamicsworld.cpp index b7112ac..326a57f 100644 --- a/src/collision/dynamicsworld.cpp +++ b/src/collision/dynamicsworld.cpp @@ -38,7 +38,7 @@ void collision::DynamicsWorld::AddMapCollision() // add static objects for (const auto& sobjs = map_->GetStaticObjects(); const auto& sobj : sobjs) { - AddModelInstance(*sobj.model, sobj.transform); + AddModelInstance(*sobj.model, sobj.node.local); } } diff --git a/src/game/openworld.cpp b/src/game/openworld.cpp index 7b3f937..f17b641 100644 --- a/src/game/openworld.cpp +++ b/src/game/openworld.cpp @@ -3,7 +3,10 @@ #include "player.hpp" #include "vehicle.hpp" -game::OpenWorld::OpenWorld() : World("openworld") {} +game::OpenWorld::OpenWorld() : World("openworld") +{ + srand(time(NULL)); +} void game::OpenWorld::PlayerJoined(Player& player) { @@ -69,7 +72,7 @@ void game::OpenWorld::SpawnVehicle(Player& player) // spawn him car // random model - const char* vehicles[] = {"pickup", "passat"}; + const char* vehicles[] = {"pickup_hd", "passat", "twingo", "polskifiat"}; auto vehicle_name = vehicles[rand() % (sizeof(vehicles) / sizeof(vehicles[0]))]; // ranodm color diff --git a/src/gameview/client_session.cpp b/src/gameview/client_session.cpp index aac3992..e805c97 100644 --- a/src/gameview/client_session.cpp +++ b/src/gameview/client_session.cpp @@ -67,7 +67,7 @@ void game::view::ClientSession::Update(const UpdateInfo& info) glm::mat4 game::view::ClientSession::GetViewMatrix() const { - glm::vec3 center(0, 0, 3); + glm::vec3 center(0.0f, 0.0f, 2.5f); if (world_ && follow_ent_) { @@ -82,7 +82,7 @@ glm::mat4 game::view::ClientSession::GetViewMatrix() const float pitch_sin = glm::sin(pitch_); glm::vec3 dir(yaw_sin * pitch_cos, yaw_cos * pitch_cos, pitch_sin); - float distance = 10.0f; + float distance = 8.0f; auto eye = center - dir * distance; diff --git a/src/gfx/renderer.cpp b/src/gfx/renderer.cpp index 87e97a4..b573d13 100644 --- a/src/gfx/renderer.cpp +++ b/src/gfx/renderer.cpp @@ -9,7 +9,8 @@ #include "client/gl.hpp" -#include "gfx/shader_sources.hpp" +#include "shader_sources.hpp" +#include "shader_defs.hpp" gfx::Renderer::Renderer() { @@ -81,15 +82,15 @@ void gfx::Renderer::DrawSurfaceList(std::span list, const DrawLi const Surface* sa = a.surface; const Surface* sb = b.surface; - const bool trans_a = sa->sflags & SF_TRANSPARENT; - const bool trans_b = sb->sflags & SF_TRANSPARENT; + const bool blend_a = sa->sflags & SF_BLEND; + const bool blend_b = sb->sflags & SF_BLEND; - if (trans_a != trans_b) - return trans_b; // opaque first + if (blend_a != blend_b) + return blend_b; // opaque first - if (trans_a) // both transparent + if (blend_a) // both blended { - return a.dist > b.dist; // do not optimize transparent, sort by distance instead + return a.dist > b.dist; // do not optimize blended, sort by distance instead } if (auto cmp = sa <=> sb; cmp != 0) @@ -103,24 +104,30 @@ void gfx::Renderer::DrawSurfaceList(std::span list, const DrawLi return false; }); - - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - - glDisable(GL_BLEND); - - InvalidateShaders(); + + glActiveTexture(GL_TEXTURE0); // for all future bindings // cache to eliminate fake state changes const gfx::Texture* last_texture = nullptr; const gfx::VertexArray* last_vao = nullptr; + InvalidateShaders(); + + // enable depth test + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + + // reset face culling + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); bool last_twosided = false; - glActiveTexture(GL_TEXTURE0); // for all future bindings - + // reset blending + glDisable(GL_BLEND); + glDepthMask(GL_TRUE); + bool last_blend = false; + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // set to opacity blending default + bool last_blend_additive = false; + for (const DrawSurfaceCmd& cmd : list) { const Surface* surface = cmd.surface; @@ -129,7 +136,7 @@ void gfx::Renderer::DrawSurfaceList(std::span list, const DrawLi const bool skeletal_flag = surface->mflags & MF_SKELETAL; // surface flags const bool twosided_flag = surface->sflags & SF_2SIDED; - const bool transparent_flag = surface->sflags & SF_TRANSPARENT; + const bool blend_flag = surface->sflags & SF_BLEND; const bool object_color_flag = surface->sflags & SF_OBJECT_COLOR; // sync 2sided @@ -159,21 +166,56 @@ void gfx::Renderer::DrawSurfaceList(std::span list, const DrawLi } // set color - bool cull_alpha = true; - glm::vec4 color = glm::vec4(1.0f); + int shflags = SHF_CULL_ALPHA; + glm::vec4 color = glm::vec4(1.0f); if (object_color_flag && cmd.color) { // use object color and disable alpha cull - cull_alpha = false; + shflags &= ~SHF_CULL_ALPHA; + shflags |= SHF_BACKGROUND; color = glm::vec4(*cmd.color); } + + // sync blending + if (blend_flag != last_blend) + { + if (blend_flag) + { + glEnable(GL_BLEND); + glDepthMask(GL_FALSE); + } + else + { + glDisable(GL_BLEND); + glDepthMask(GL_TRUE); + } + + last_blend = blend_flag; + } + + // sync blending type + if (blend_flag) + { + shflags &= ~SHF_CULL_ALPHA; + + const bool blend_additive = surface->sflags & SF_BLEND_ADDITIVE; + if (blend_additive != last_blend_additive) + { + if (blend_additive) + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + else + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + last_blend_additive = blend_additive; + } // sync cull_alpha - if (mshader.cull_alpha != cull_alpha) + if (mshader.flags != shflags) { - glUniform1i(mshader.shader->U(SU_CULL_ALPHA), cull_alpha ? 1 : 0); - mshader.cull_alpha = cull_alpha; + glUniform1i(mshader.shader->U(SU_FLAGS), shflags); + mshader.flags = shflags; } // sync color @@ -206,7 +248,8 @@ void gfx::Renderer::DrawSurfaceList(std::span list, const DrawLi (void*)(first_tri * 3U * sizeof(GLuint))); } - + // reset this as it is rare and other stuff might not reset this + glDepthMask(GL_TRUE); } diff --git a/src/gfx/renderer.hpp b/src/gfx/renderer.hpp index 536f631..c5ab835 100644 --- a/src/gfx/renderer.hpp +++ b/src/gfx/renderer.hpp @@ -22,7 +22,7 @@ namespace gfx // cached state to avoid redundant uniform updates which are expensive especially on WebGL bool global_setup = false; glm::vec4 color = glm::vec4(-1.0f); // invalid to force initial setup - bool cull_alpha = false; + int flags = 0; }; class Renderer diff --git a/src/gfx/shader.cpp b/src/gfx/shader.cpp index b8aba82..89a31eb 100644 --- a/src/gfx/shader.cpp +++ b/src/gfx/shader.cpp @@ -9,7 +9,7 @@ static const char* const s_uni_names[] = { "u_view_proj", // SU_VIEW_PROJ "u_tex", // SU_TEX "u_color", // SU_COLOR - "u_cull_alpha", // SU_COLOR + "u_flags", // SU_FLAGS }; // Vytvori shader z daneho zdroje diff --git a/src/gfx/shader.hpp b/src/gfx/shader.hpp index ff8514a..a3b5427 100644 --- a/src/gfx/shader.hpp +++ b/src/gfx/shader.hpp @@ -14,7 +14,7 @@ namespace gfx SU_VIEW_PROJ, SU_TEX, SU_COLOR, - SU_CULL_ALPHA, + SU_FLAGS, SU_COUNT }; diff --git a/src/gfx/shader_defs.hpp b/src/gfx/shader_defs.hpp index ea48079..23efe72 100644 --- a/src/gfx/shader_defs.hpp +++ b/src/gfx/shader_defs.hpp @@ -2,3 +2,6 @@ #define SD_MAX_LIGHTS 4 #define SD_MAX_BONES 256 + +#define SHF_CULL_ALPHA 1 +#define SHF_BACKGROUND 2 \ No newline at end of file diff --git a/src/gfx/shader_sources.cpp b/src/gfx/shader_sources.cpp index 1c64ad1..ba77b18 100644 --- a/src/gfx/shader_sources.cpp +++ b/src/gfx/shader_sources.cpp @@ -27,7 +27,7 @@ #define MESH_MATRICES_GLSL R"GLSL( uniform mat4 u_view_proj; - uniform mat4 u_model; // Transform matrix + uniform mat4 u_model; // Transform matrix )GLSL" #define LIGHT_MATRICES_GLSL R"GLSL( @@ -40,12 +40,12 @@ #define COMPUTE_LIGHTS_GLSL R"GLSL( // Example sun values (can later be uniforms) vec3 u_sun_direction = normalize(vec3(0.3, 0.5, -0.8)); // direction from which sunlight comes -vec3 u_sun_color = vec3(1.0, 0.95, 0.7); // warm sunlight color +vec3 u_sun_color = vec3(1.0, 0.95, 0.7) * 0.9; // warm sunlight color vec3 ComputeLights(in vec3 sector_pos, in vec3 sector_normal) { // Base ambient - vec3 color = vec3(0.5, 0.5, 0.5); // u_ambient_light + vec3 color = vec3(0.5, 0.5, 0.5) * 0.9; // u_ambient_light // Sunlight contribution float sun_dot = max(dot(sector_normal, -u_sun_direction), 0.0); @@ -107,21 +107,24 @@ R"GLSL( in vec2 v_uv; in vec3 v_color; +#define SHF_CULL_ALPHA 1 +#define SHF_BACKGROUND 2 + uniform sampler2D u_tex; uniform vec4 u_color; -uniform bool u_cull_alpha; +uniform int u_flags; layout (location = 0) out vec4 o_color; void main() { o_color = vec4(texture(u_tex, v_uv)); - if (u_cull_alpha) + if ((u_flags & SHF_CULL_ALPHA) > 0) { if (o_color.a < 0.5) - discard; + discard; } - else + else if ((u_flags & SHF_BACKGROUND) > 0) { // blend with bg o_color = mix(u_color, o_color, o_color.a); diff --git a/src/gfx/surface.hpp b/src/gfx/surface.hpp index b064f5d..8193f4d 100644 --- a/src/gfx/surface.hpp +++ b/src/gfx/surface.hpp @@ -20,9 +20,10 @@ using SurfaceFlags = uint8_t; enum SurfaceFlag : SurfaceFlags { SF_NONE = 0x00, - SF_2SIDED = 0x01, - SF_TRANSPARENT = 0x02, - SF_OBJECT_COLOR = 0x08, // use object level tint + SF_2SIDED = 0x01, // disable backface culling + SF_BLEND = 0x02, // enable blending, disable depth write + SF_BLEND_ADDITIVE = 0x04, // use additive blending instead of opacity + SF_OBJECT_COLOR = 0x08, // use object color for background instead of alpha culling }; struct Surface