diff --git a/data/scripts/actors/actor_player.lua b/data/scripts/actors/actor_player.lua index 28d2d64..db4c427 100644 --- a/data/scripts/actors/actor_player.lua +++ b/data/scripts/actors/actor_player.lua @@ -1,3 +1,15 @@ +local PLAYER_PHYS_MASS = 80.0 +local PLAYER_PHYS_RADIUS = 0.40 +local PLAYER_PHYS_HEIGHT = 1.79 +local PLAYER_PHYS_JUMPDIST = PLAYER_PHYS_RADIUS +local PLAYER_PHYS_JUMPHEIGHT = 2.0 +local PLAYER_PHYS_JUMPSPEEDY = 5.0 +local PLAYER_PHYS_WALK_SPEED = 5.5 +local PLAYER_PHYS_RUN_SPEED_MUL = 1.4 +local PLAYER_PHYS_MOVE_SPEED_EXP = 1.0 +local PLAYER_PHYS_FLY_SPEED_EXP = 4.0 +local AIR_CONTROL = 0.2 + -- игрок actor_player = inherit_table(actor_base) @@ -6,61 +18,162 @@ actor_player.m_camera_offset_y = 0.5 function actor_player:on_init() actor_base.on_init(self) - self:create_body() + g_player = self + + self:create_player_body(PLAYER_PHYS_RADIUS, PLAYER_PHYS_HEIGHT - PLAYER_PHYS_RADIUS * 2.0, 80.0, 0.0, 0.0) self:activate_camera() - local ent = engine.create_entity("test_object") + local ent = engine.create_entity("weapon_ump") engine.add_entity_to_world(ent) - self.m_weapon_entity_id = ent:get_id() - - self.m_in_reload = false - - --local ent2 = engine.get_entity_from_id(self.m_weapon_entity_id) - --console.print(ent2:get_classname()) end function actor_player:on_shutdown() actor_base.on_shutdown(self) + + g_player = nil end function actor_player:on_update(dt) actor_base.on_update(self, dt) - self:update_camera_look() - --self:update_camera_movement(dt) - self:update_body_movement(dt) + self:update_camera_look() -- C++ + --self:update_camera() Lua (for perfomance should call from C++) + + --self:update_camera_movement(dt) -- C++ flying mode + --self:update_body_movement(dt) -- C++ + + self:update_player_movement(dt) local ent = engine.get_entity_from_id(self.m_weapon_entity_id) ent:set_relative_position_to_camera(self) - if self:get_action() == ACTION_FIRE and self.m_in_reload == false then - ent:play_animation(ent:find_animation("shoot1"), ANIM_PLAYBACK_NONE) - engine.play_sound("data/sounds/weapons/ump45_shoot.wav") + self:action_update() +end + +function actor_player:action_update() + local action = self:get_action() + + local ent = engine.get_entity_from_id(self.m_weapon_entity_id) + if ent then + if action == ACTION_FIRE then + ent:set_state(WEAPON_FSM_STATE_ATTACK) + elseif action == ACTION_RELOAD then + ent:set_state(WEAPON_FSM_STATE_RELOAD) + end + end +end + +-- TODO: remove +function vec3_magnitude(_x, _y, _z) + return math.sqrt(_x * _x + _y * _y + _z * _z) +end + +function vec3_normalize(_x, _y, _z) + local mag = vec3_magnitude(_x, _y, _z) + if mag == 0 then return 0, 0, 0 end + return _x / mag, _y / mag, _z / mag +end + +function vec3_cross(_x1, _y1, _z1, _x2, _y2, _z2) + return _y1 * _z2 - _y2 * _z1, + _z1 * _x2 - _z2 * _x1, + _x1 * _y2 - _x2 * _y1 +end + +function actor_player:update_player_movement(dt) + local movement = self:get_movement() + local speed = 4.0 + + local up_x, up_y, up_z = camera.get_up() + local front_x, front_y, front_z = camera.get_front() + front_y = 0.0 + + local final_front_x, final_front_y, final_front_z = vec3_normalize(front_x, front_y, front_z) + local cross_x, cross_y, cross_z = vec3_cross(final_front_x, final_front_y, final_front_z, + up_x, up_y, up_z) + + local final_cross_x, final_cross_y, final_cross_z = vec3_normalize(cross_x, cross_y, cross_z) + + local dir_x, dir_y, dir_z = 0.0, 0.0, 0.0 + + if (movement & EMovementDir_Forward) ~= 0 then + dir_x = dir_x + final_front_x + dir_y = dir_y + final_front_y + dir_z = dir_z + final_front_z + end + + if (movement & EMovementDir_Backward) ~= 0 then + dir_x = dir_x - final_front_x + dir_y = dir_y - final_front_y + dir_z = dir_z - final_front_z + end + + if (movement & EMovementDir_Left) ~= 0 then + dir_x = dir_x - final_cross_x + dir_y = dir_y - final_cross_y + dir_z = dir_z - final_cross_z + end + + if (movement & EMovementDir_Right) ~= 0 then + dir_x = dir_x + final_cross_x + dir_y = dir_y + final_cross_y + dir_z = dir_z + final_cross_z + end + + local current_vel_x, current_vel_y, current_vel_z = self:get_velocity() + + local vel_x = dir_x * speed + local vel_y = dir_y * speed + local vel_z = dir_z * speed + + + if self:on_ground() then + self:set_velocity(vel_x, current_vel_y, vel_z) + + if (movement & EMovementDir_Jump) ~= 0 then + self:set_velocity(current_vel_x, PLAYER_PHYS_JUMPSPEEDY, current_vel_z) + --console.print("!!! JUMP") + end + else + local air_vel_x = current_vel_x + dir_x * speed * AIR_CONTROL * dt + local air_vel_y = current_vel_y + dir_y * speed * AIR_CONTROL * dt + local air_vel_z = current_vel_z + dir_z * speed * AIR_CONTROL * dt + self:set_velocity(air_vel_x, current_vel_y, air_vel_z) + end +end + +local g_yaw = 0.0 +local g_pitch = 0.0 + +function actor_player:update_camera() + if not input.get_lock_mouse() then + return end - if self:get_action() == ACTION_RELOAD and self.m_in_reload == false then - ent:play_animation(ent:find_animation("reload"), ANIM_PLAYBACK_NONE) - engine.play_sound("data/sounds/weapons/ump45_reload.wav") - self.m_in_reload = true - end - - if ent:get_current_animation() == ent:find_animation("shoot1") and - ent:get_current_animation_time() >= ent:get_animation_time(ent:find_animation("shoot1")) then - ent:play_animation(ent:find_animation("idle1"), ANIM_PLAYBACK_REPEAT) - end - - if self.m_in_reload == true and ent:get_current_animation_time() >= ent:get_animation_time(ent:find_animation("reload")) then - ent:play_animation(ent:find_animation("idle1"), ANIM_PLAYBACK_REPEAT) - self.m_in_reload = false - end - -- if ent:get_current_animation() == ent:find_animation("reload") and - -- ent:get_current_animation_time() >= ent:get_animation_time(ent:find_animation("reload")) then - -- ent:play_animation(ent:find_animation("idle1"), ANIM_PLAYBACK_NONE) - --end + local mousePosX, mousePosY = input.get_mouse_pos() + local sensitivity = 0.15 -- #TODO: input.get_mouse_sensitivity() + + g_yaw = g_yaw + (mousePosX * sensitivity) + g_pitch = g_pitch - (mousePosY * sensitivity) + + -- lock axis + if g_pitch > 89.0 then g_pitch = 89.0 end + if g_pitch < -89.0 then g_pitch = -89.0 end + + camera.set_yaw_pitch(g_yaw, g_pitch) end function actor_player:on_collide(other) - console.print(string.format("actor_player:on_collide: %s", other:get_classname())) + --console.print(string.format("actor_player:on_collide: %s", other:get_classname())) + +-- put_debug_string_to_screen(string.format("actor_player:on_collide: %s", other:get_classname()), 4) + + -- FOR TEST +-- other:mark_for_delete() +end + +function actor_player:get_health() + return 100.0 end diff --git a/data/scripts/game_hud.lua b/data/scripts/game_hud.lua new file mode 100644 index 0000000..f101ef3 --- /dev/null +++ b/data/scripts/game_hud.lua @@ -0,0 +1,70 @@ +local RED_COLOR = { 1.0, 0.0, 0.0, 1.0 } +local GREEN_COLOR = { 0.0, 1.0, 0.0, 1.0 } +local BLUE_COLOR = { 0.0, 0.0, 1.0, 1.0 } +local BLACK_COLOR = { 0.0, 0.0, 0.0, 1.0 } +local WHITE_COLOR = { 1.0, 1.0, 1.0, 1.0 } + +local draw_test_hud = true +local draw_debug_string = false +local debug_string_text = "" +local debug_string_time = 0.0 +local debug_string_max_time = 0.0 + +function game_hud_draw( ) + if not draw_test_hud then + return + end + + -- example of color + local color = { 0.5, 0.5, 0.1, 1.0 } + + -- example of drawing + ui.draw_rect(150.0, 150.0, 350.0, 350.0, BLUE_COLOR) + ui.draw_image("data/textures/koshka1.jpg", 160.0, 160.0, 340.0, 340.0, WHITE_COLOR) + ui.draw_text("Hello, world!", 200.0, 200.0, GREEN_COLOR) + + if g_player then + game_player_hud_draw() + end + + -- debug + if draw_debug_string then + game_debug_string_draw() + end +end + +function game_player_hud_draw() + local display_x, display_y = ui.get_display_size() + local color = { 0.0, 0.0, 0.0, 0.3 } + local text_color = { 0.0, 0.0, 0.0, 0.6 } + local hud_rect_size_x = 200 + local hud_rect_size_y = 100 + local offset_text = ui.calc_text_width("Health") + 5 + + ui.draw_rect(0.0, display_y, hud_rect_size_x, display_y - hud_rect_size_y, color) + + ui.draw_text("Health", 10.0, display_y - hud_rect_size_y + 20, WHITE_COLOR) + ui.draw_text(string.format("%.0f", g_player:get_health()), 10.0 + offset_text, display_y - hud_rect_size_y + 20, WHITE_COLOR) +end + +function put_debug_string_to_screen(text, text_time) + debug_string_max_time = text_time + debug_string_text = text + debug_string_time = 0.0 + draw_debug_string = true +end + +function game_debug_string_draw() + debug_string_time = debug_string_time + engine.get_delta() + + if debug_string_time >= debug_string_max_time then + debug_string_max_time = 0.0 + debug_string_time = 0.0 + draw_debug_string = false + end + + local offset = ui.calc_text_width(debug_string_text) + + ui.draw_rect(490, 500, 490 + offset + 20, 550, BLACK_COLOR) + ui.draw_text(debug_string_text, 500, 500, RED_COLOR) +end \ No newline at end of file diff --git a/data/scripts/game_init.lua b/data/scripts/game_init.lua index a78a7b7..28f0755 100644 --- a/data/scripts/game_init.lua +++ b/data/scripts/game_init.lua @@ -1,25 +1,39 @@ -- Game initialization script -console.print("--- Game initialization ---") - -- загружаем скрипты load_script("game_utils.lua") +load_script("game_hud.lua") load_script("game_object.lua") load_script("test_object.lua") load_script("weapons/weapon_base.lua") + +load_script("weapons/weapon_ump.lua") + load_script("actors/actor_base.lua") load_script("actors/actor_player.lua") +-- глобальные переменные +g_player = nil + -- глобальная таблица сущностей g_entity_table = { -- Lua class -- CPP class -- Description + -- Actors + { "actor_player", "ActorBase", "Player entity" }, + -- Weapons + { "weapon_ump", "WeaponBase", "Weapon UMP" }, + -- Simple entity { "test_object", "Entity", "Test entity" }, -} \ No newline at end of file +} + +function sv_game_init( ) + console.print("--- Game initialization ---") +end diff --git a/data/scripts/weapons/weapon_base.lua b/data/scripts/weapons/weapon_base.lua index be38909..a856c8a 100644 --- a/data/scripts/weapons/weapon_base.lua +++ b/data/scripts/weapons/weapon_base.lua @@ -1,11 +1,12 @@ ----------------------------------------------------------- --- weapon_base.lua, Базоавый скрипт оружия +-- weapon_base.lua, Базовый скрипт оружия -- Автор: Кирилл -- Изменяли: -- Дата: 05.03.2026 ----------------------------------------------------------- -- индификаторы состояний FSM +WEAPON_FSM_STATE_NONE = 0 WEAPON_FSM_STATE_IDLE = 1 WEAPON_FSM_STATE_ATTACK = 2 WEAPON_FSM_STATE_ATTACK2 = 3 @@ -17,32 +18,11 @@ weapon_base = inherit_table(game_object) -- инициализация FSM weapon_base.m_fsm = {} --- покой -weapon_base.m_fsm[WEAPON_FSM_STATE_IDLE] = { - anim = "idle", -- имя анимации - anim_playback = ANIM_PLAYBACK_REPEAT, -- бесконечно играть - anim_speed = 1.0 -- обычная скорость анимации -} - --- атака -weapon_base.m_fsm[WEAPON_FSM_STATE_ATTACK] = { - anim = "attack", -- имя анимации - anim_playback = ANIM_PLAYBACK_NONE, - anim_speed = 1.0 -- обычная скорость анимации -} - --- перезарядка -weapon_base.m_fsm[WEAPON_FSM_STATE_RELOAD] = { - anim = "reload", -- имя анимации - anim_playback = ANIM_PLAYBACK_NONE, - anim_speed = 1.0 -- обычная скорость анимации -} - function weapon_base:on_init() game_object.on_init(self) -- начальное состояние FSM - self.m_state = WEAPON_FSM_STATE_IDLE + self.m_state = WEAPON_FSM_STATE_NONE self.m_next_state = WEAPON_FSM_STATE_IDLE self.m_state_time = 0.0 self.m_end_state_time = 0.0 @@ -64,46 +44,96 @@ function weapon_base:on_fsm_state_update(dt) self.m_state_time = self.m_state_time + dt -- проверка на стрельбу - if (self.m_state == WEAPON_STATE_ATTACK or - self.m_state == WEAPON_STATE_ATTACK2) and + if (self.m_state == WEAPON_FSM_STATE_ATTACK or + self.m_state == WEAPON_FSM_STATE_ATTACK2) and self.m_state_time >= self.m_end_state_time then -- переходим в ожидание - self:set_state(WEAPON_STATE_IDLE) + self:set_state(WEAPON_FSM_STATE_IDLE) end -- костыль, нету анимаций бесконечных - if self.m_state == WEAPON_STATE_IDLE and self.m_state_time >= self.m_end_state_time then + if self.m_state == WEAPON_FSM_STATE_IDLE and self.m_state_time >= self.m_end_state_time then -- переходим в ожидание - self:set_state(WEAPON_STATE_IDLE) + self:set_state(WEAPON_FSM_STATE_IDLE) end self:fsm_update(dt) end function weapon_base:set_state(next_state) + if self.m_state == next_state or self.m_next_state == next_state then + return + end + + if (self.m_state == WEAPON_FSM_STATE_ATTACK or self.m_state == WEAPON_FSM_STATE_RELOAD) + and next_state ~= WEAPON_FSM_STATE_IDLE then + return + end + self.m_next_state = next_state + console.print(string.format("weapon_base:set_state: switich to '%d' ", next_state)) end function weapon_base:fsm_update(dt) + -- надо ли менять состояние if self.m_next_state ~= self.m_state then - if self.m_next_state == WEAPON_STATE_ATTACK then - self:set_anim("attack1") - elseif self.m_next_state == WEAPON_STATE_ATTACK2 then - self:set_anim("attack1") - end + self:on_state_switch(self.m_next_state) -- сброс времени и установка его на таймер анимации self.m_state_time = 0.0 - self.m_end_state_time = render.get_anim_time(self:get_anim()) + self.m_end_state_time = self:get_animation_time(self:get_current_animation()) - -- запускаем атаку - if self.m_next_state == WEAPON_STATE_ATTACK or self.m_next_state == WEAPON_STATE_ATTACK2 then - self:attack() - end + console.print(string.format("weapon_base:fsm_update: switched from '%d' to '%d', end time %f ", + self.m_state, self.m_next_state, self.m_end_state_time)) self.m_state = self.m_next_state end -end \ No newline at end of file +end + +function weapon_base:find_fsm_state(state) + for k, v in pairs(self.m_fsm) do + if k == state then + return v + end + end + + console.print(string.format("weapon_base:find_fsm_state: state '%d' not found or not registered", state)) + return nil +end + +function weapon_base:on_state_switch(state) + -- ищем стейт в таблице + local fsm_state = self:find_fsm_state(state) + if not fsm_state then + return + end + + local anim_id = self:find_animation(fsm_state.anim) + self:play_animation(anim_id, fsm_state.anim_playback) +end + +function weapon_base:set_relative_position_to_camera( ent ) + local camX, camY, camZ = camera.get_position() + local frontX, frontY, frontZ = camera.get_front() + local rightX, rightY, rightZ = camera.get_right() + local upX, upY, upZ = camera.get_up() + + self:set_rotation_from_vectors(frontX, frontY, frontZ, + rightX, rightY, rightZ, + upX, upY, upZ) + + local offsetx = 0.0 + local offsety = 0.0 + local offsetz = 0.0 + + local x = camX + (rightX * offsetx) + (upX * offsety) + (frontX * offsetz) + local y = camY + (rightY * offsetx) + (upY * offsety) + (frontY * offsetz) + local z = camZ + (rightZ * offsetx) + (upZ * offsety) + (frontZ * offsetz) + self:set_position(x, y, z) + + -- force update transform + self:update_transform() +end diff --git a/data/scripts/weapons/weapon_key.lua b/data/scripts/weapons/weapon_key.lua deleted file mode 100644 index 73ee916..0000000 --- a/data/scripts/weapons/weapon_key.lua +++ /dev/null @@ -1 +0,0 @@ -weapon_key = inherit_table(weapon_base) diff --git a/data/scripts/weapons/weapon_ump.lua b/data/scripts/weapons/weapon_ump.lua new file mode 100644 index 0000000..5c22485 --- /dev/null +++ b/data/scripts/weapons/weapon_ump.lua @@ -0,0 +1,33 @@ +----------------------------------------------------------- +-- weapon_base.lua, Базоавый скрипт оружия +-- Автор: Кирилл +-- Изменяли: +-- Дата: 06.03.2026 +----------------------------------------------------------- +weapon_ump = inherit_table(weapon_base) + +-- покой +weapon_ump.m_fsm[WEAPON_FSM_STATE_IDLE] = { + anim = "idle1", -- имя анимации + anim_playback = ANIM_PLAYBACK_REPEAT, -- бесконечно играть + anim_speed = 1.0 -- обычная скорость анимации +} + +-- атака +weapon_ump.m_fsm[WEAPON_FSM_STATE_ATTACK] = { + anim = "shoot1", -- имя анимации + anim_playback = ANIM_PLAYBACK_NONE, + anim_speed = 1.0 -- обычная скорость анимации +} + +-- перезарядка +weapon_ump.m_fsm[WEAPON_FSM_STATE_RELOAD] = { + anim = "reload", -- имя анимации + anim_playback = ANIM_PLAYBACK_NONE, + anim_speed = 1.0 -- обычная скорость анимации +} + +function weapon_ump:on_init() + weapon_base.on_init(self) + self:load_model("data/models/weapons/v_ump.iqm") +end diff --git a/data/textures/koshka1.jpg b/data/textures/koshka1.jpg new file mode 100644 index 0000000..d94d13c Binary files /dev/null and b/data/textures/koshka1.jpg differ diff --git a/data/scripts/help.lua b/docs/lua help.txt similarity index 88% rename from data/scripts/help.lua rename to docs/lua help.txt index ab26177..006b224 100644 --- a/data/scripts/help.lua +++ b/docs/lua help.txt @@ -27,6 +27,12 @@ string m_name integer m_id +Entity callbacks: +on_init() -- on entity creation +on_shutdown() -- on entity destroy +on_update(delta) -- on entity update +on_collide(other) -- on entity collide with another entity + Entity methods: load_model(string filename) @@ -40,12 +46,15 @@ get_position() -- return x, y, z set_rotation(float x, float y, float z) -- setting the euler rotation +get_rotation() -- return x, y, z + set_rotation_from_vectors(float frontx, float fronty, float frontz, float rightx, float righty, float rightz, float upx, float upy, float upz) -- rotate around axis get_classname() -- return the classname of the entity get_id() -- return the id of the entity +mark_for_delete() -- mark entity to delete find_animation(string name) -- find a animation in the model play_animation(integer id, integer mode) -- play a animation with specified mode (ANIM_PLAYBACK_NONE, ANIM_PLAYBACK_REPEAT) @@ -57,7 +66,6 @@ get_animation_time(integer id) -- return the time of a animation ActorBase methods: activate_camera() - update_camera_look() update_camera_movement(float nubmer) create_body() diff --git a/docs/экспорт оружия из goldsource.txt b/docs/экспорт оружия из goldsource.txt new file mode 100644 index 0000000..dd4c2b3 --- /dev/null +++ b/docs/экспорт оружия из goldsource.txt @@ -0,0 +1,4 @@ +1. импортировать smd с Y-up осью вверх +2. снова экспортировать как GoldSource с Y-up осью3\ +3. ввести команды для iqm.exe для сборки модели, пример команды: + iqm.exe -scale 0.0254 -rotate 0,90,0 v_m3.iqm v_m3-PV.smd after_reload.smd draw.smd idle.smd insert.smd shoot1.smd shoot2.smd start_reload.smd \ No newline at end of file diff --git a/docs/экспорт уровня или модели в obj.txt b/docs/экспорт уровня или модели в obj.txt new file mode 100644 index 0000000..2988511 --- /dev/null +++ b/docs/экспорт уровня или модели в obj.txt @@ -0,0 +1 @@ +1. ОБЯЗАТЕЛЬНО TRAINGULATE FACE !!! \ No newline at end of file diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 95a9478..cda07a3 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -15,6 +15,7 @@ #include "render.h" #include "renderdevice.h" #include "imguimanager.h" +#include "scenemanager.h" // game #include "game.h" @@ -77,6 +78,431 @@ void debug_overlay_render() { // ImGui::PopStyleVar(); } + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Debug Console / ShowExampleAppConsole() +//----------------------------------------------------------------------------- + +// Demonstrate creating a simple console window, with scrolling, filtering, completion and history. +// For the console example, we are using a more C++ like approach of declaring a class to hold both data and functions. +struct ExampleAppConsole +{ + char InputBuf[256]; + ImVector Items; + ImVector Commands; + ImVector History; + int HistoryPos; // -1: new line, 0..History.Size-1 browsing history. + ImGuiTextFilter Filter; + bool AutoScroll; + bool ScrollToBottom; + + ExampleAppConsole() + { + ClearLog(); + memset(InputBuf, 0, sizeof(InputBuf)); + HistoryPos = -1; + + // "CLASSIFY" is here to provide the test case where "C"+[tab] completes to "CL" and display multiple matches. + Commands.push_back("help"); + Commands.push_back("history"); + Commands.push_back("clear"); + Commands.push_back("classify"); + Commands.push_back("ph_debug_draw"); + Commands.push_back("r_scene_debug_draw"); + Commands.push_back("r_show_stats"); + Commands.push_back("r_entity_debug_draw"); + Commands.push_back("map"); + Commands.push_back("quit"); + AutoScroll = true; + ScrollToBottom = false; + + } + ~ExampleAppConsole() + { + ClearLog(); + for (int i = 0; i < History.Size; i++) + ImGui::MemFree(History[i]); + } + + // Portable helpers + static int Stricmp(const char* s1, const char* s2) { int d; while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; } return d; } + static int Strnicmp(const char* s1, const char* s2, int n) { int d = 0; while (n > 0 && (d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; n--; } return d; } + static char* Strdup(const char* s) { IM_ASSERT(s); size_t len = strlen(s) + 1; void* buf = ImGui::MemAlloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)s, len); } + static void Strtrim(char* s) { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; } + + void ClearLog() + { + for (int i = 0; i < Items.Size; i++) + ImGui::MemFree(Items[i]); + Items.clear(); + } + + void AddLog(const char* fmt, ...) IM_FMTARGS(2) + { + // FIXME-OPT + char buf[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args); + buf[IM_ARRAYSIZE(buf) - 1] = 0; + va_end(args); + Items.push_back(Strdup(buf)); + } + + void Draw(const char* title, bool* p_open) + { + ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); + if (!ImGui::Begin(title, p_open)) + { + ImGui::End(); + return; + } + + // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. + // So e.g. IsItemHovered() will return true when hovering the title bar. + // Here we create a context menu only available from the title bar. + if (ImGui::BeginPopupContextItem()) + { + if (ImGui::MenuItem("Close Console")) + *p_open = false; + ImGui::EndPopup(); + } + + + // TODO: display items starting from the bottom +#if 0 + if (ImGui::SmallButton("Add Debug Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); } + ImGui::SameLine(); + if (ImGui::SmallButton("Add Debug Error")) { AddLog("[error] something went wrong"); } + ImGui::SameLine(); + if (ImGui::SmallButton("Clear")) { ClearLog(); } + ImGui::SameLine(); + bool copy_to_clipboard = ImGui::SmallButton("Copy"); + //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); } + + ImGui::Separator(); + + // Options menu + if (ImGui::BeginPopup("Options")) + { + ImGui::Checkbox("Auto-scroll", &AutoScroll); + ImGui::EndPopup(); + } + + // Options, Filter + ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_O, ImGuiInputFlags_Tooltip); + if (ImGui::Button("Options")) + ImGui::OpenPopup("Options"); + ImGui::SameLine(); + Filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180); + ImGui::Separator(); +#endif + + // Reserve enough left-over height for 1 separator + 1 input text + const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); + if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_HorizontalScrollbar)) + { + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::Selectable("Clear")) ClearLog(); + ImGui::EndPopup(); + } + + // Display every line as a separate entry so we can change their color or add custom widgets. + // If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end()); + // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping + // to only process visible items. The clipper will automatically measure the height of your first item and then + // "seek" to display only items in the visible area. + // To use the clipper we can replace your standard loop: + // for (int i = 0; i < Items.Size; i++) + // With: + // ImGuiListClipper clipper; + // clipper.Begin(Items.Size); + // while (clipper.Step()) + // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + // - That your items are evenly spaced (same height) + // - That you have cheap random access to your elements (you can access them given their index, + // without processing all the ones before) + // You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property. + // We would need random-access on the post-filtered list. + // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices + // or offsets of items that passed the filtering test, recomputing this array when user changes the filter, + // and appending newly elements as they are inserted. This is left as a task to the user until we can manage + // to improve this example code! + // If your items are of variable height: + // - Split them into same height items would be simpler and facilitate random-seeking into your list. + // - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items. + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing + // if (copy_to_clipboard) + // ImGui::LogToClipboard(); + for (const char* item : Items) + { + if (!Filter.PassFilter(item)) + continue; + + // Normally you would store more information in your item than just a string. + // (e.g. make Items[] an array of structure, store color/type etc.) + ImVec4 color; + bool has_color = false; + if (strstr(item, "[error]")) { color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); has_color = true; } + else if (strncmp(item, "# ", 2) == 0) { color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); has_color = true; } + if (has_color) + ImGui::PushStyleColor(ImGuiCol_Text, color); + ImGui::TextUnformatted(item); + if (has_color) + ImGui::PopStyleColor(); + } + // if (copy_to_clipboard) + // ImGui::LogFinish(); + + // Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame. + // Using a scrollbar or mouse-wheel will take away from the bottom edge. + if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())) + ImGui::SetScrollHereY(1.0f); + ScrollToBottom = false; + + ImGui::PopStyleVar(); + } + ImGui::EndChild(); + ImGui::Separator(); + + // Command-line + bool reclaim_focus = false; + ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_EscapeClearsAll | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory; + if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), input_text_flags, &TextEditCallbackStub, (void*)this)) + { + char* s = InputBuf; + Strtrim(s); + if (s[0]) + ExecCommand(s); + strcpy(s, ""); + reclaim_focus = true; + } + + // Auto-focus on window apparition + ImGui::SetItemDefaultFocus(); + if (reclaim_focus) + ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget + + ImGui::End(); + } + + void ExecCommand(const char* command_line) + { + AddLog("# %s\n", command_line); + + const char* full_command_line = command_line; + if (const char* arg = strchr(command_line, ' ')) + { + + static char extracted[1024]; + strncpy(extracted, command_line, arg - command_line); + + command_line = extracted; + } + + // Insert into history. First find match and delete it so it can be pushed to the back. + // This isn't trying to be smart or optimal. + HistoryPos = -1; + for (int i = History.Size - 1; i >= 0; i--) + if (Stricmp(History[i], command_line) == 0) + { + ImGui::MemFree(History[i]); + History.erase(History.begin() + i); + break; + } + History.push_back(Strdup(command_line)); + + // Process command + if (Stricmp(command_line, "CLEAR") == 0) + { + ClearLog(); + } + else if (Stricmp(command_line, "HELP") == 0) + { + AddLog("Commands:"); + for (int i = 0; i < Commands.Size; i++) + AddLog("- %s", Commands[i]); + } + else if (Stricmp(command_line, "HISTORY") == 0) + { + int first = History.Size - 10; + for (int i = first > 0 ? first : 0; i < History.Size; i++) + AddLog("%3d: %s\n", i, History[i]); + } + else if (Stricmp(command_line, "PH_DEBUG_DRAW") == 0) + { + if (g_PhysicsWorld) + g_PhysicsWorld->ToggleDebugDraw(); + } + else if (Stricmp(command_line, "R_SCENE_DEBUG_DRAW") == 0) + { + g_sceneManager->toggleDebugRender(); + } + else if (Stricmp(command_line, "R_SHOW_STATS") == 0) + { + g_render->ToggleShowStats(); + } + else if (Stricmp(command_line, "R_ENTITY_DEBUG_DRAW") == 0) + { + extern bool g_debugEntityDraw; + g_debugEntityDraw = !g_debugEntityDraw; + } + else if (Stricmp(command_line, "MAP") == 0) + { + GetEngine()->NewGame(full_command_line + 4); + } + else if (Stricmp(command_line, "QUIT") == 0) + { + GetEngine()->RequestExit(); + } + else + { + AddLog("Unknown command: '%s'\n", command_line); + } + + // On command input, we scroll to bottom even if AutoScroll==false + ScrollToBottom = true; + } + + // In C++11 you'd be better off using lambdas for this sort of forwarding callbacks + static int TextEditCallbackStub(ImGuiInputTextCallbackData* data) + { + ExampleAppConsole* console = (ExampleAppConsole*)data->UserData; + return console->TextEditCallback(data); + } + + int TextEditCallback(ImGuiInputTextCallbackData* data) + { + //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd); + switch (data->EventFlag) + { + case ImGuiInputTextFlags_CallbackCompletion: + { + // Example of TEXT COMPLETION + + // Locate beginning of current word + const char* word_end = data->Buf + data->CursorPos; + const char* word_start = word_end; + while (word_start > data->Buf) + { + const char c = word_start[-1]; + if (c == ' ' || c == '\t' || c == ',' || c == ';') + break; + word_start--; + } + + // Build a list of candidates + ImVector candidates; + for (int i = 0; i < Commands.Size; i++) + if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0) + candidates.push_back(Commands[i]); + + if (candidates.Size == 0) + { + // No match + AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start); + } + else if (candidates.Size == 1) + { + // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing. + data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start)); + data->InsertChars(data->CursorPos, candidates[0]); + data->InsertChars(data->CursorPos, " "); + } + else + { + // Multiple matches. Complete as much as we can.. + // So inputting "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches. + int match_len = (int)(word_end - word_start); + for (;;) + { + int c = 0; + bool all_candidates_matches = true; + for (int i = 0; i < candidates.Size && all_candidates_matches; i++) + if (i == 0) + c = toupper(candidates[i][match_len]); + else if (c == 0 || c != toupper(candidates[i][match_len])) + all_candidates_matches = false; + if (!all_candidates_matches) + break; + match_len++; + } + + if (match_len > 0) + { + data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start)); + data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len); + } + + // List matches + AddLog("Possible matches:\n"); + for (int i = 0; i < candidates.Size; i++) + AddLog("- %s\n", candidates[i]); + } + + break; + } + case ImGuiInputTextFlags_CallbackHistory: + { + // Example of HISTORY + const int prev_history_pos = HistoryPos; + if (data->EventKey == ImGuiKey_UpArrow) + { + if (HistoryPos == -1) + HistoryPos = History.Size - 1; + else if (HistoryPos > 0) + HistoryPos--; + } + else if (data->EventKey == ImGuiKey_DownArrow) + { + if (HistoryPos != -1) + if (++HistoryPos >= History.Size) + HistoryPos = -1; + } + + // A better implementation would preserve the data on the current input line along with cursor position. + if (prev_history_pos != HistoryPos) + { + const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : ""; + data->DeleteChars(0, data->BufTextLen); + data->InsertChars(0, history_str); + } + } + } + return 0; + } +}; + +static ExampleAppConsole s_console; +static bool s_showConsole = false; +static bool s_lastLockedMouse = false; + +void PrintToConsole(const char* msg) +{ + s_console.AddLog(msg); +} + +static void OpenConsole() +{ + s_lastLockedMouse = g_inputManager.GetRelativeMouseMode(); + g_inputManager.SetRelativeMouseMode(false); + + s_showConsole = true; +} + +static void CloseConsole() +{ + g_inputManager.SetRelativeMouseMode(s_lastLockedMouse); + s_showConsole = false; +} + +static void UpdateConsole() +{ + s_console.Draw("Console", NULL); + // ShowExampleAppLog(NULL); +} + Engine::Engine() { } @@ -186,6 +612,17 @@ void Engine::Frame_SDL() } + if (event.type == SDL_EVENT_KEY_DOWN && event.key.key == SDLK_GRAVE) { + s_showConsole = !s_showConsole; + + if (s_showConsole) + OpenConsole(); + else + CloseConsole(); + } + + + // keyboard action if (event.key.key < kMaxKeyboardKeys) { if (event.type == SDL_EVENT_KEY_DOWN) { @@ -213,6 +650,11 @@ void Engine::Frame_SDL() } } +namespace +{ + float dt; +} + void Engine::Frame() { // *** updating @@ -224,11 +666,14 @@ void Engine::Frame() if (currentTime <= oldTime) currentTime = oldTime + 1; - float dt = oldTime > 0 ? (float)((double)(currentTime - oldTime) / frequency) : (float)(1.0f / 60.0f); + dt = oldTime > 0 ? (float)((double)(currentTime - oldTime) / frequency) : (float)(1.0f / 60.0f); // *** ImGui scope begin g_ImGuiManager.BeginFrame(); + if (s_showConsole) + UpdateConsole(); + // update physics if (g_PhysicsWorld) g_PhysicsWorld->Step(dt); @@ -281,6 +726,8 @@ void Engine::RenderFrame() if (g_world) g_world->Render(); + g_game->Render2D(); + g_render->RenderStats(); // ImGui scope end *** @@ -313,12 +760,14 @@ void Engine::NewGame(const char* mapname) Disconnect(); g_PhysicsWorld = new PhysicsWorld(); - g_PhysicsWorld->ToggleDebugDraw(); + //g_PhysicsWorld->ToggleDebugDraw(); g_world = new World(); g_render->LoadSceneXML(mapname); + CloseConsole(); + // after initializing client scene and collision system - we initialize the server game g_game->InitForNewMap(mapname); } @@ -345,6 +794,16 @@ SDL_Window* Engine::GetWindow() return m_window; } +void Engine::RequestExit() +{ + m_run = false; +} + +float Engine::GetDelta() +{ + return dt; +} + Engine g_engine; #ifdef WIN32 diff --git a/src/engine/engine.h b/src/engine/engine.h index 52e2ae3..6dd3974 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -26,6 +26,10 @@ public: SDL_Window* GetWindow(); + void RequestExit(); + + float GetDelta(); + private: SDL_Window* m_window = nullptr; bool m_run = true; diff --git a/src/engine/ientity.cpp b/src/engine/ientity.cpp index 9960aee..0b63d00 100644 --- a/src/engine/ientity.cpp +++ b/src/engine/ientity.cpp @@ -1,4 +1,5 @@ #include "ientity.h" +#include "world.h" #include @@ -10,7 +11,8 @@ IEntityBase::IEntityBase() : m_rotation(0.0f), m_scale(1.0f), m_classname(nullptr), - m_id(-1) + m_id(-1), + m_dirtyTransform(true) { m_id = s_entityId++; } @@ -43,13 +45,16 @@ const glm::mat4& IEntityBase::GetWorldTransform() void IEntityBase::UpdateTransform() { - glm::vec3 radiansRotation = glm::radians(m_rotation); + if (!m_dirtyTransform) + return; - glm::mat4 T = glm::translate(glm::mat4(1.0f), m_position); - glm::mat4 R = glm::toMat4(glm::quat(radiansRotation)); - glm::mat4 S = glm::scale(glm::mat4(1.0f), m_scale); + glm::vec3 radiansRotation = glm::vec3(glm::radians(m_rotation.x), glm::radians(m_rotation.y), glm::radians(m_rotation.z)); + glm::mat4 rotation = glm::toMat4(glm::quat(radiansRotation)); - m_worldTM = T * R * S; + m_worldTM = glm::mat4(1.0f); + m_worldTM = glm::translate(m_worldTM, m_position) * rotation * glm::scale(m_worldTM, m_scale); + + m_dirtyTransform = false; } uint32_t IEntityBase::GetID() @@ -61,3 +66,14 @@ void IEntityBase::ResetEntityID() { s_entityId = 0; } + +void IEntityBase::MarkForDelete() +{ + if (g_world) + g_world->MarkEntityToDelete(this); +} + +void IEntityBase::SetDirty() +{ + m_dirtyTransform = true; +} diff --git a/src/engine/ientity.h b/src/engine/ientity.h index adc4ab1..9ef90b4 100644 --- a/src/engine/ientity.h +++ b/src/engine/ientity.h @@ -27,6 +27,10 @@ public: static void ResetEntityID(); + void MarkForDelete(); + + void SetDirty(); + protected: glm::vec3 m_position; glm::vec3 m_rotation; @@ -39,6 +43,8 @@ protected: const char* m_classname; uint32_t m_id; + + bool m_dirtyTransform; }; // registration diff --git a/src/engine/inputmanager.h b/src/engine/inputmanager.h index eecf4d7..2c24fbc 100644 --- a/src/engine/inputmanager.h +++ b/src/engine/inputmanager.h @@ -46,6 +46,7 @@ public: glm::vec2& GetMouseDeltaPos() { return m_deltaMousePos; } void SetRelativeMouseMode(bool relativeMode); + bool GetRelativeMouseMode() { return m_relativeMouseMode; } void Frame(); diff --git a/src/engine/log.cpp b/src/engine/log.cpp index ca0a7a9..3c215e3 100644 --- a/src/engine/log.cpp +++ b/src/engine/log.cpp @@ -11,6 +11,8 @@ static int g_day_in_month[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 int build_id; FILE* g_logFile; +extern void PrintToConsole(const char* msg); + void CalculateBuildNumber() { static int start_day = 3; @@ -119,6 +121,8 @@ void Logger::MsgArg(const char* fmt, va_list args) //sprintf(buffer2, "[%s] %s", timestr, buffer); + PrintToConsole(buffer); + if (g_logFile) { fwrite(buffer, sizeof(char), len, g_logFile); diff --git a/src/engine/physics/physicsworld.cpp b/src/engine/physics/physicsworld.cpp index 7f66d1b..76002e3 100644 --- a/src/engine/physics/physicsworld.cpp +++ b/src/engine/physics/physicsworld.cpp @@ -136,6 +136,26 @@ void PhysicsWorld::Step(float delta) m_world->debugDrawWorld();*/ } +bool PhysicsWorld::TraceRay(TraceRayResult& _result, const glm::vec3& _rayBegin, const glm::vec3& _rayEnd, IEntityBase* _pIgnoreEntity) +{ + btVector3 rayStart = glmVectorToBt(_rayBegin); + btVector3 rayEnd = glmVectorToBt(_rayEnd); + + ClosestRayResultCallback RayResultCallback(rayStart, rayEnd, _pIgnoreEntity); + g_PhysicsWorld->GetWorld()->rayTest(rayStart, rayEnd, RayResultCallback); + + if (RayResultCallback.hasHit()) + { + _result.hit = true; + + _result.pEntity = (IEntityBase*)RayResultCallback.m_collisionObject->getUserPointer(); + _result.position = btVectorToGlm(RayResultCallback.m_hitPointWorld); + _result.normal = btVectorToGlm(RayResultCallback.m_hitNormalWorld); + } + + return _result.hit; +} + void PhysicsWorld::ToggleDebugDraw() { m_debugDraw = !m_debugDraw; diff --git a/src/engine/physics/physicsworld.h b/src/engine/physics/physicsworld.h index 6a335c0..3669a70 100644 --- a/src/engine/physics/physicsworld.h +++ b/src/engine/physics/physicsworld.h @@ -17,6 +17,14 @@ struct SceneCollisionModel btTriangleMesh* triangleMesh; }; +struct TraceRayResult +{ + glm::vec3 position; + glm::vec3 normal; + IEntityBase* pEntity; + bool hit; +}; + class PhysicsWorld { public: @@ -30,6 +38,8 @@ public: void Step(float delta); + bool TraceRay(TraceRayResult& _result, const glm::vec3& _rayBegin, const glm::vec3& _rayEnd, IEntityBase* _pIgnoreEntity); + btDynamicsWorld* GetWorld() { return m_world; } float GetFixedTimeStep() { return m_stepTime; } diff --git a/src/engine/physics/rigidbody.cpp b/src/engine/physics/rigidbody.cpp index 9f28836..3f9f149 100644 --- a/src/engine/physics/rigidbody.cpp +++ b/src/engine/physics/rigidbody.cpp @@ -76,7 +76,7 @@ RigidBody::~RigidBody() // } // } // -// CreatePlayerBody(); +// CreatePlayerBody_Old(); // UpdateBodyTranslationDirty(); // // if (changeFilterUsableHack) diff --git a/src/engine/world.cpp b/src/engine/world.cpp index 2ad2458..296eb58 100644 --- a/src/engine/world.cpp +++ b/src/engine/world.cpp @@ -43,6 +43,7 @@ void World::Update(float dt) // Update entities for (int i = 0; i < m_entities.size(); i++) { + m_entities[i]->SetDirty(); m_entities[i]->Update(dt); } diff --git a/src/game/actor_base.cpp b/src/game/actor_base.cpp new file mode 100644 index 0000000..7e99366 --- /dev/null +++ b/src/game/actor_base.cpp @@ -0,0 +1,380 @@ +#include "actor_base.h" +#include "inputmanager.h" + +#include + +REGISTER_ENTITY(ActorBase); + +ActorBase::ActorBase() +{ +} + +ActorBase::~ActorBase() +{ +} + +void ActorBase::Update(float dt) +{ + UpdateBodyDirty(); + + Entity::Update(dt); + + AfterEngineStep(); +} + +void ActorBase::AfterEngineStep() +{ + //btTransform xform = m_rigidBody->getWorldTransform(); + //m_position = btVectorToGlm(xform.getOrigin()); + + m_position = btVectorToGlm(m_ph_motion_state.m_transform.getOrigin()); + + glm::vec3 cameraPos = m_position; + + if (m_luaObject.IsTable()) + { + LuaPlus::LuaObject m_camera_offset_y = m_luaObject.GetByName("m_camera_offset_y"); + if (m_camera_offset_y.IsNumber()) + cameraPos.y += (float)m_camera_offset_y.ToNumber(); + } + + m_camera.SetPosition(cameraPos); +} + +void ActorBase::UpdateCameraMovement(float dt) +{ + // calculate player movement + float speed = 12.0f * dt; + + uint32_t movementDir = GenMovementDir(); + + if (movementDir & EMovementDir_Forward) + m_position += speed * m_camera.GetFront(); + if (movementDir & EMovementDir_Backward) + m_position -= speed * m_camera.GetFront(); + if (movementDir & EMovementDir_Left) + m_position -= glm::normalize(glm::cross(m_camera.GetFront(), m_camera.GetUp())) * speed; + if (movementDir & EMovementDir_Right) + m_position += glm::normalize(glm::cross(m_camera.GetFront(), m_camera.GetUp())) * speed; + + // set position back to camera for calculation view matrix + m_camera.SetPosition(m_position); +} + +void ActorBase::UpdateBodyMovement(float dt) +{ + + glm::vec3 dir = glm::vec3(0.0f); + + glm::vec3 camFront = m_camera.GetFront(); + camFront.y = 0.0f; + camFront = glm::normalize(camFront); + + // calculate player movement + float speed = 4.f; + + uint32_t movementDir = GenMovementDir(); + + if (movementDir & EMovementDir_Forward) + dir += camFront; + if (movementDir & EMovementDir_Backward) + dir -= camFront; + if (movementDir & EMovementDir_Left) + dir -= glm::normalize(glm::cross(camFront, m_camera.GetUp())); + if (movementDir & EMovementDir_Right) + dir += glm::normalize(glm::cross(camFront, m_camera.GetUp())); + + btVector3 currentvel = m_rigidBody->getLinearVelocity(); + glm::vec3 velocity = dir * speed; + + if (OnGround()) { + m_rigidBody->setLinearVelocity(btVector3(velocity.x, currentvel.y(), velocity.z)); + if (movementDir & EMovementDir_Jump) { + m_rigidBody->setLinearVelocity(btVector3(currentvel.x(), PLAYER_PHYS_JUMPSPEEDY, currentvel.z())); + } + } + else { + float airControl = 0.2f; + btVector3 airvel = currentvel + glmVectorToBt(dir * speed * airControl * dt); + m_rigidBody->setLinearVelocity(btVector3(airvel.x(), currentvel.y(), airvel.z())); + } + + /*if (glm::length(velocity) > 0.1f && OnGround() && !(movementDir & EMovementDir_Jump)) + m_rigidBody->setLinearVelocity(glmVectorToBt(velocity)); + + if ((movementDir & EMovementDir_Jump) && OnGround()) { + m_rigidBody->applyCentralImpulse(btVector3(0.0f, PLAYER_PHYS_JUMPSPEEDY, 0.0f)); + movementDir &= ~EMovementDir_Jump; + }*/ +} + +void ActorBase::UpdateCameraLook() +{ + if (!g_inputManager.GetRelativeMouseMode()) + return; + + glm::ivec2 mousePos = g_inputManager.GetMousePos(); + + // calculate yaw and pitch + static float yaw = 0.0f, pitch = 0.0f; + + int deltaX = mousePos.x; + int deltaY = mousePos.y; + + float sensitivity = 0.15f; + + yaw += deltaX * sensitivity; + pitch -= deltaY * sensitivity; + + if (pitch > 89.0f) pitch = 89.0f; + if (pitch < -89.0f) pitch = -89.0f; + + m_camera.SetYawPitch(yaw, pitch); +} + +void ActorBase::ActivateCamera() +{ + g_inputManager.SetRelativeMouseMode(true); + + g_cameraManager.SetActiveCamera(&m_camera); +} + +void ActorBase::CreatePlayerBody(float radius, float height, float mass, float friction, float damping) +{ + + m_shape = new btCapsuleShape(radius, height); + + m_mass = mass; + btVector3 local_inertia(0.0f, 0.0f, 0.0f); + if (m_mass > 0.f) { + m_shape->calculateLocalInertia(m_mass, local_inertia); + } + + btRigidBody::btRigidBodyConstructionInfo rigid_body_ci(m_mass, nullptr, m_shape, local_inertia); + + m_rigidBody = new btRigidBody(rigid_body_ci); + m_rigidBody->setUserPointer(this); + m_rigidBody->setMotionState(&m_ph_motion_state); + m_ph_motion_state.setBody(m_rigidBody); + + // I'm sure that position is valid + btTransform xform; + xform.setIdentity(); + xform.setOrigin(glmVectorToBt(m_position)); + m_rigidBody->setWorldTransform(xform); + + // ACTOR STUFF + m_rigidBody->setAngularFactor(btVector3(0.0f, 0.0f, 0.0f)); + + m_rigidBody->setFriction(friction); + m_rigidBody->setAnisotropicFriction(btVector3(0.0f, 0.0f, 0.0f)); + m_rigidBody->setDamping(damping, 0.0f); + + m_rigidBody->setActivationState(DISABLE_DEACTIVATION); + + // #TODO: body filter and mask + g_PhysicsWorld->GetWorld()->addRigidBody(m_rigidBody); + + m_bodyDirty = true; + +} + +void ActorBase::CreatePlayerBody_Old() +{ + + m_shape = new btCapsuleShape(PLAYER_PHYS_RADIUS, PLAYER_PHYS_HEIGHT - PLAYER_PHYS_RADIUS * 2.0); + + m_mass = 80.0f; + btVector3 local_inertia(0.0f, 0.0f, 0.0f); + if (m_mass > 0.f) { + m_shape->calculateLocalInertia(m_mass, local_inertia); + } + + btRigidBody::btRigidBodyConstructionInfo rigid_body_ci(m_mass, nullptr, m_shape, local_inertia); + + m_rigidBody = new btRigidBody(rigid_body_ci); + m_rigidBody->setUserPointer(this); + m_rigidBody->setMotionState(&m_ph_motion_state); + m_ph_motion_state.setBody(m_rigidBody); + + // I'm sure that position is valid + btTransform xform; + xform.setIdentity(); + xform.setOrigin(glmVectorToBt(m_position)); + m_rigidBody->setWorldTransform(xform); + + // ACTOR STUFF + m_rigidBody->setAngularFactor(btVector3(0.0f, 0.0f, 0.0f)); + + + //m_rigidBody->setFriction(2.5f); + + m_rigidBody->setFriction(0.0f); + m_rigidBody->setAnisotropicFriction(btVector3(0.0f, 0.0f, 0.0f)); + m_rigidBody->setDamping(0.0f, 0.0f); + + m_rigidBody->setActivationState(DISABLE_DEACTIVATION); + + // #TODO: body filter and mask + g_PhysicsWorld->GetWorld()->addRigidBody(m_rigidBody); + + m_bodyDirty = true; +} + +bool ActorBase::OnGround() +{ + float rayLength = (PLAYER_PHYS_HEIGHT / 2.0f) + 0.1f; + + btTransform xform = m_rigidBody->getWorldTransform(); + + btVector3 rayStart = xform.getOrigin(); + btVector3 rayEnd = rayStart - btVector3(0.0f, rayLength, 0.0f); + + ClosestRayResultCallback RayResultCallback(rayStart, rayEnd, this); + g_PhysicsWorld->GetWorld()->rayTest(rayStart, rayEnd, RayResultCallback); + if (RayResultCallback.hasHit()) { + btVector3 hitNormal = RayResultCallback.m_hitNormalWorld; + if (hitNormal.y() > 0.7f) { + return true; + } + } + + return false; +} + +void ActorBase::RegisterFunctions() +{ + m_luaObject.Register("activate_camera", *this, &ActorBase::Lua_ActivateCamera); + m_luaObject.Register("update_camera_look", *this, &ActorBase::Lua_UpdateCameraLook); + m_luaObject.Register("update_camera_movement", *this, &ActorBase::Lua_UpdateCameraMovement); + m_luaObject.Register("create_player_body", *this, &ActorBase::Lua_CreatePlayerBody); + m_luaObject.Register("create_player_body_old", *this, &ActorBase::Lua_CreatePlayerBodyOld); + m_luaObject.Register("update_body_movement", *this, &ActorBase::Lua_UpdateBodyMovement); + m_luaObject.Register("get_action", *this, &ActorBase::Lua_GetAction); + m_luaObject.Register("get_movement", *this, &ActorBase::Lua_GetMovement); + m_luaObject.Register("on_ground", *this, &ActorBase::Lua_OnGround); + + //m_luaObject.RegisterDirect("activate_camera", &ActorBase_ActivateCamera); + //m_luaObject.RegisterDirect("update_camera_look", &ActorBase_UpdateCameraLook); + //m_luaObject.RegisterDirect("update_camera_movement", &ActorBase_UpdateCameraMovement); +} + +int ActorBase::Lua_UpdateCameraMovement(LuaPlus::LuaState* state) +{ + LuaPlus::LuaStack stack(state); + + UpdateCameraMovement(stack[2].GetFloat()); + + return 0; +} + +int ActorBase::Lua_UpdateBodyMovement(LuaPlus::LuaState* state) +{ + LuaPlus::LuaStack stack(state); + + UpdateBodyMovement(stack[2].GetFloat()); + + return 0; +} + +int ActorBase::Lua_UpdateCameraLook(LuaPlus::LuaState* state) +{ + UpdateCameraLook(); + return 0; +} + +int ActorBase::Lua_ActivateCamera(LuaPlus::LuaState* state) +{ + ActivateCamera(); + return 0; +} + +int ActorBase::Lua_CreatePlayerBody(LuaPlus::LuaState* state) +{ + LuaPlus::LuaStack stack(state); + + float radius = (float)stack[2].GetNumber(); + float height = (float)stack[3].GetNumber(); + float mass = (float)stack[4].GetNumber(); + float friction = (float)stack[5].GetNumber(); + float damping = (float)stack[6].GetNumber(); + + CreatePlayerBody(radius, height, mass, friction, damping); + + return 0; +} + +int ActorBase::Lua_CreatePlayerBodyOld(LuaPlus::LuaState* state) +{ + CreatePlayerBody_Old(); + return 0; +} + +int ActorBase::Lua_GetAction(LuaPlus::LuaState* state) +{ + int action = GenAction(); + state->PushInteger(action); + + return 1; +} + +int ActorBase::Lua_GetMovement(LuaPlus::LuaState* state) +{ + uint32_t movement = GenMovementDir(); + state->PushInteger(movement); + + return 1; +} + +int ActorBase::Lua_OnGround(LuaPlus::LuaState* state) +{ + state->PushBoolean(OnGround()); + return 1; +} + +int ActorBase::GenAction() +{ + int action = -1; + + if (!g_inputManager.GetRelativeMouseMode()) + return action; + + if (g_inputManager.GetMouse().IsKeyDown(EMouseButton_Left)) + action = 0; + else if (g_inputManager.GetMouse().IsKeyDown(EMouseButton_Right)) + action = 1; + else if (g_inputManager.GetKeyboard().IsKeyDown(SDLK_R)) + action = 2; + + return action; +} + +uint32_t ActorBase::GenMovementDir() +{ + uint32_t movementDir = EMovementDir_None; + + if (!g_inputManager.GetRelativeMouseMode()) + return movementDir; + + if (g_inputManager.GetKeyboard().IsKeyDown(SDLK_W)) { + movementDir |= EMovementDir_Forward; + } + + if (g_inputManager.GetKeyboard().IsKeyDown(SDLK_S)) { + movementDir |= EMovementDir_Backward; + } + + if (g_inputManager.GetKeyboard().IsKeyDown(SDLK_A)) { + movementDir |= EMovementDir_Left; + } + + if (g_inputManager.GetKeyboard().IsKeyDown(SDLK_D)) { + movementDir |= EMovementDir_Right; + } + + if (g_inputManager.GetKeyboard().IsKeyDown(SDLK_SPACE)) { + movementDir |= EMovementDir_Jump; + } + + return movementDir; +} diff --git a/src/game/actor_base.h b/src/game/actor_base.h new file mode 100644 index 0000000..be5593a --- /dev/null +++ b/src/game/actor_base.h @@ -0,0 +1,65 @@ +#ifndef ACTOR_BASE_H +#define ACTOR_BASE_H + +#include "game_object.h" + +#define PLAYER_PHYS_MASS 80.0 +#define PLAYER_PHYS_RADIUS 0.40 +#define PLAYER_PHYS_HEIGHT 1.79 +#define PLAYER_PHYS_JUMPDIST PLAYER_PHYS_RADIUS +#define PLAYER_PHYS_JUMPHEIGHT 2.0 +#define PLAYER_PHYS_JUMPSPEEDY 5.0 +#define PLAYER_PHYS_WALK_SPEED ( 5.5 ) +#define PLAYER_PHYS_RUN_SPEED_MUL 1.4 +#define PLAYER_PHYS_MOVE_SPEED_EXP 1.0 +#define PLAYER_PHYS_FLY_SPEED_EXP 4.0 + +class ActorBase : public Entity +{ +public: + ActorBase(); + ~ActorBase(); + + virtual void Update(float dt); + + void AfterEngineStep(); + + void UpdateCameraMovement(float dt); + + void UpdateBodyMovement(float dt); + + void UpdateCameraLook(); + + void ActivateCamera(); + + void CreatePlayerBody(float radius, float height, float mass, float friction, float damping); + void CreatePlayerBody_Old(); + + bool OnGround(); + + // Lua bindings + + virtual void RegisterFunctions(); + + int Lua_UpdateCameraMovement(LuaPlus::LuaState* state); + int Lua_UpdateBodyMovement(LuaPlus::LuaState* state); + int Lua_UpdateCameraLook(LuaPlus::LuaState* state); + int Lua_ActivateCamera(LuaPlus::LuaState* state); + int Lua_CreatePlayerBody(LuaPlus::LuaState* state); + int Lua_CreatePlayerBodyOld(LuaPlus::LuaState* state); + int Lua_GetAction(LuaPlus::LuaState* state); + int Lua_GetMovement(LuaPlus::LuaState* state); + int Lua_OnGround(LuaPlus::LuaState* state); + +private: + int GenAction(); + uint32_t GenMovementDir(); + +private: + Camera m_camera; + + +}; + + +#endif // !ACTOR_BASE_H diff --git a/src/game/game.cpp b/src/game/game.cpp index 1f2fbe3..25e9e01 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -1,8 +1,11 @@ #include "ifilesystem.h" #include "core.h" #include "log.h" +#include "engine.h" #include "game.h" #include "game_lua_help.h" +#include "game_ui.h" +#include "inputmanager.h" #include "ientity.h" #include "entitymanager.h" #include "world.h" @@ -105,6 +108,129 @@ void engineAddEntityToWorld(LuaPlus::LuaObject& object) g_world->AddEntity(entity); } +LuaPlus::LuaObject engineTraceRay(float rayBeginX, float rayBeginY, float rayBeginZ, + float rayEndX, float rayEndY, float rayEndZ, const LuaPlus::LuaObject& ignoreTable) +{ + IEntityBase* pIgnoreEntity = nullptr; + if (ignoreTable.IsTable()) + { + LuaPlus::LuaObject ignoreEntityTable = ignoreTable.GetByName("__object"); + if (ignoreEntityTable.IsLightUserdata()) + pIgnoreEntity = (IEntityBase*)ignoreEntityTable.GetLightUserdata(); + } + + TraceRayResult result = {}; + glm::vec3 rayBegin = glm::vec3(rayBeginX, rayBeginY, rayBeginZ); + glm::vec3 rayEnd = glm::vec3(rayEndX, rayEndY, rayEndZ); + + if (g_PhysicsWorld) + g_PhysicsWorld->TraceRay(result, rayBegin, rayEnd, pIgnoreEntity); + else + Logger::Msg("engine.trace_ray(): no server started or game loaded!"); + + LuaPlus::LuaObject resultTable = GetLuaState().CreateTable(); + resultTable.SetNumber("pos_x", result.position.x); + resultTable.SetNumber("pos_y", result.position.y); + resultTable.SetNumber("pos_z", result.position.z); + resultTable.SetNumber("normal_x", result.normal.x); + resultTable.SetNumber("normal_y", result.normal.y); + resultTable.SetNumber("normal_z", result.normal.z); + resultTable.SetInteger("entity_id", result.pEntity ? result.pEntity->GetID() : -1); + resultTable.SetInteger("hit", result.hit); + return resultTable; +} + +float engineGetDelta() +{ + return GetEngine()->GetDelta(); +} + +void registerEngine() +{ + using namespace LuaPlus; + + // register engine functions + LuaObject engineTable = GetLuaState().GetGlobals().CreateTable("engine"); + engineTable.RegisterDirect("error", &engineError); + engineTable.RegisterDirect("warning", &engineWarning); + engineTable.RegisterDirect("create_entity", &engineCreateEntity); + engineTable.RegisterDirect("add_entity_to_world", &engineAddEntityToWorld); + engineTable.RegisterDirect("get_entity_from_id", &engineGetEntityFromID); + engineTable.RegisterDirect("play_sound", &enginePlaySound); + engineTable.RegisterDirect("get_delta", &engineGetDelta); + engineTable.RegisterDirect("trace_ray", &engineTraceRay); + + LuaObject consoleTable = GetLuaState().GetGlobals().CreateTable("console"); + consoleTable.RegisterDirect("print", &consoleMsg); + + registerCamera(); + + registerInput(); + + registerEngineUI(); + + // action globals + GetLuaState().DoString("ACTION_FIRE = 0"); + GetLuaState().DoString("ACTION_ALT_FIRE = 1"); + GetLuaState().DoString("ACTION_RELOAD = 2"); + GetLuaState().DoString("ACTION_USE = 3"); + + // animations globals + GetLuaState().DoString("ANIM_PLAYBACK_NONE = 0"); + GetLuaState().DoString("ANIM_PLAYBACK_REPEAT = 1"); + + + char buffer[64]; + +#define REGISTER_CONSTANT(constant) \ + snprintf(buffer, sizeof(buffer), #constant" = %d", constant); \ + GetLuaState().DoString(buffer) + + REGISTER_CONSTANT(EMovementDir_None); + REGISTER_CONSTANT(EMovementDir_Forward); + REGISTER_CONSTANT(EMovementDir_Backward); + REGISTER_CONSTANT(EMovementDir_Left); + REGISTER_CONSTANT(EMovementDir_Right); + REGISTER_CONSTANT(EMovementDir_Jump); + +#undef REGISTER_CONSTANT +} + +int inputGetMousePos(LuaPlus::LuaState* state) +{ + const glm::vec2& pos = g_inputManager.GetMousePos(); + state->PushNumber(pos.x); + state->PushNumber(pos.y); + return 2; +} + +int inputGetDeltaMousePos(LuaPlus::LuaState* state) +{ + const glm::vec2& pos = g_inputManager.GetMouseDeltaPos(); + state->PushNumber(pos.x); + state->PushNumber(pos.y); + return 2; +} + +void inputLock(bool value) +{ + g_inputManager.SetRelativeMouseMode(value); +} + +bool inputGetLock() +{ + return g_inputManager.GetRelativeMouseMode(); +} + +void registerInput() +{ + LuaPlus::LuaObject inputTable = GetLuaState().GetGlobals().CreateTable("input"); + inputTable.Register("get_mouse_pos", &inputGetMousePos); + inputTable.Register("get_delta_mouse_pos", &inputGetDeltaMousePos); + inputTable.RegisterDirect("lock_mouse", &inputLock); + inputTable.RegisterDirect("get_lock_mouse", &inputGetLock); +} + int cameraGetPos(LuaPlus::LuaState* state) { glm::vec3 v = glm::vec3(0.0f); @@ -191,39 +317,23 @@ int cameraGetPitch(LuaPlus::LuaState* state) return 1; } -void registerEngine() +void cameraSetYawPitch(float yaw, float pitch) { - using namespace LuaPlus; + Camera* camera = g_cameraManager.GetActiveCamera(); + if (camera) + camera->SetYawPitch(yaw, pitch); +} - // register engine functions - LuaObject engineTable = GetLuaState().GetGlobals().CreateTable("engine"); - engineTable.RegisterDirect("error", &engineError); - engineTable.RegisterDirect("warning", &engineWarning); - engineTable.RegisterDirect("create_entity", &engineCreateEntity); - engineTable.RegisterDirect("add_entity_to_world", &engineAddEntityToWorld); - engineTable.RegisterDirect("get_entity_from_id", &engineGetEntityFromID); - engineTable.RegisterDirect("play_sound", &enginePlaySound); - - LuaObject consoleTable = GetLuaState().GetGlobals().CreateTable("console"); - consoleTable.RegisterDirect("print", &consoleMsg); - - LuaObject cameraTable = GetLuaState().GetGlobals().CreateTable("camera"); +void registerCamera() +{ + LuaPlus::LuaObject cameraTable = GetLuaState().GetGlobals().CreateTable("camera"); cameraTable.Register("get_position", &cameraGetPos); cameraTable.Register("get_front", &cameraGetFront); cameraTable.Register("get_right", &cameraGetRight); cameraTable.Register("get_up", &cameraGetUp); cameraTable.Register("get_yaw", &cameraGetYaw); cameraTable.Register("get_pitch", &cameraGetPitch); - - // action globals - GetLuaState().DoString("ACTION_FIRE = 0"); - GetLuaState().DoString("ACTION_ALT_FIRE = 1"); - GetLuaState().DoString("ACTION_RELOAD = 2"); - - // animations globals - GetLuaState().DoString("ANIM_PLAYBACK_NONE = 0"); - GetLuaState().DoString("ANIM_PLAYBACK_REPEAT = 1"); - + cameraTable.RegisterDirect("set_yaw_pitch", &cameraSetYawPitch); } void registerClasses() @@ -477,6 +587,11 @@ void Game::Shutdown() { } +void Game::Render2D() +{ + gameRenderUI(); +} + //LuaPrototype* pluaprototype = Lua_FindPrototype(classname); // //if (pluaprototype) diff --git a/src/game/game.h b/src/game/game.h index f233175..749dcf9 100644 --- a/src/game/game.h +++ b/src/game/game.h @@ -18,8 +18,13 @@ public: void Shutdown(); + void Render2D(); }; extern Game* g_game; -#endif \ No newline at end of file +#endif + +void registerCamera(); + +void registerInput(); diff --git a/src/game/game_object.cpp b/src/game/game_object.cpp index 7363cb6..30a23fa 100644 --- a/src/game/game_object.cpp +++ b/src/game/game_object.cpp @@ -1,68 +1,9 @@ +#include "core.h" #include "inputmanager.h" #include "debugrender.h" #include "game_object.h" #include -#define PLAYER_PHYS_MASS 80.0 -#define PLAYER_PHYS_RADIUS 0.40 -#define PLAYER_PHYS_HEIGHT 1.79 -#define PLAYER_PHYS_JUMPDIST PLAYER_PHYS_RADIUS -#define PLAYER_PHYS_JUMPHEIGHT 2.0 -#define PLAYER_PHYS_JUMPSPEEDY 5.0 -#define PLAYER_PHYS_WALK_SPEED ( 5.5 ) -#define PLAYER_PHYS_RUN_SPEED_MUL 1.4 -#define PLAYER_PHYS_MOVE_SPEED_EXP 1.0 -#define PLAYER_PHYS_FLY_SPEED_EXP 4.0 - -// Lua wrappers -void Entity_LoadModel(LuaPlus::LuaState* state) -{ - LuaPlus::LuaStack stack(state); - - Entity* entity = (Entity*)stack[1].GetByName("__object").GetLightUserdata(); - entity->LoadModel(stack[2].GetString()); -} - -void Entity_SetVisible(LuaPlus::LuaState* state) -{ - LuaPlus::LuaStack stack(state); - - Entity* entity = (Entity*)stack[1].GetByName("__object").GetLightUserdata(); - entity->SetVisible(stack[2].GetBoolean()); -} - -bool Entity_GetVisible(LuaPlus::LuaState* state) -{ - LuaPlus::LuaStack stack(state); - - Entity* entity = (Entity*)stack[1].GetByName("__object").GetLightUserdata(); - return entity->GetVisible(); -} - -void ActorBase_UpdateCameraMovement(LuaPlus::LuaState* state) -{ - LuaPlus::LuaStack stack(state); - - ActorBase* entity = (ActorBase*)stack[1].GetByName("__object").GetLightUserdata(); - entity->UpdateCameraMovement(stack[2].GetFloat()); -} - -void ActorBase_UpdateCameraLook(LuaPlus::LuaState* state) -{ - LuaPlus::LuaStack stack(state); - - ActorBase* entity = (ActorBase*)stack[1].GetByName("__object").GetLightUserdata(); - entity->UpdateCameraLook(); -} - -void ActorBase_ActivateCamera(LuaPlus::LuaState* state) -{ - LuaPlus::LuaStack stack(state); - - ActorBase* entity = (ActorBase*)stack[1].GetByName("__object").GetLightUserdata(); - entity->ActivateCamera(); -} - REGISTER_ENTITY(Entity); Entity::Entity() : @@ -96,6 +37,20 @@ Entity::~Entity() m_luaObject.AssignNil(); } + + if (m_rigidBody) { + g_PhysicsWorld->GetWorld()->removeRigidBody(m_rigidBody); + + delete m_rigidBody; + m_rigidBody = nullptr; + + m_ph_motion_state.setBody(nullptr); + } + + if (m_shape) { + delete m_shape; + m_shape = nullptr; + } } void Entity::Update(float dt) @@ -113,16 +68,20 @@ void Entity::Update(float dt) } } +bool g_debugEntityDraw = false; + void Entity::Render() { if (m_model) - { m_model->Draw(GetWorldTransform(), m_skeleton); - - /*BoundingBox bbox = m_boundingBox; + + + if (g_debugEntityDraw) + { + BoundingBox bbox = m_boundingBox; bbox.TransformAABB(GetWorldTransform()); - g_debugRender->DrawBoundingBox(bbox, glm::vec3(1.0f, 0.0f, 0.0f));*/ + g_debugRender->DrawBoundingBox(bbox, glm::vec3(1.0f, 1.0f, 1.0f)); } } @@ -210,10 +169,7 @@ void Entity::InitFromTable(LuaPlus::LuaObject& _object) m_luaObject = _object; // find functions - m_onInitFunction = m_luaObject.GetByName("on_init"); - m_onShutdownFunction = m_luaObject.GetByName("on_shutdown"); - m_onUpdateFunction = m_luaObject.GetByName("on_update"); - m_onCollideFunction = m_luaObject.GetByName("on_collide"); + InitLuaCallbacks(); // check //SDL_assert_always(m_onInitFunction.IsFunction() || m_onShutdownFunction.IsFunction() || m_onUpdateFunction.IsFunction()); @@ -228,6 +184,14 @@ void Entity::InitFromTable(LuaPlus::LuaObject& _object) m_luaObject.SetLightUserdata("__object", this); } +void Entity::InitLuaCallbacks() +{ + m_onInitFunction = m_luaObject.GetByName("on_init"); + m_onShutdownFunction = m_luaObject.GetByName("on_shutdown"); + m_onUpdateFunction = m_luaObject.GetByName("on_update"); + m_onCollideFunction = m_luaObject.GetByName("on_collide"); +} + void Entity::RegisterBaseFunctions() { m_luaObject.Register("load_model", *this, &Entity::Lua_LoadModel); @@ -236,13 +200,21 @@ void Entity::RegisterBaseFunctions() m_luaObject.Register("set_position", *this, &Entity::Lua_SetPosition); m_luaObject.Register("get_position", *this, &Entity::Lua_GetPosition); m_luaObject.Register("set_rotation", *this, &Entity::Lua_SetRotation); + m_luaObject.Register("get_rotation", *this, &Entity::Lua_GetRotation); m_luaObject.Register("set_rotation_from_vectors", *this, &Entity::Lua_SetRotationFromVectors); m_luaObject.Register("get_classname", *this, &Entity::Lua_GetClassname); m_luaObject.Register("get_id", *this, &Entity::Lua_GetID); + m_luaObject.Register("mark_for_delete", *this, &Entity::Lua_MarkForDelete); + + // physics + m_luaObject.Register("set_velocity", *this, &Entity::Lua_SetVelocity); + m_luaObject.Register("get_velocity", *this, &Entity::Lua_GetVelocity); + m_luaObject.Register("has_rigid_body", *this, &Entity::Lua_HasRigidBody); // animation m_luaObject.Register("find_animation", *this, &Entity::Lua_FindAnimation); m_luaObject.Register("play_animation", *this, &Entity::Lua_PlayAnimation); + m_luaObject.Register("stop_animation", *this, &Entity::Lua_StopAnimation); m_luaObject.Register("get_current_animation", *this, &Entity::Lua_GetCurrentAnimation); m_luaObject.Register("get_current_animation_time", *this, &Entity::Lua_GetCurrentAnimationTime); m_luaObject.Register("get_animation_time", *this, &Entity::Lua_GetAnimationTime); @@ -299,6 +271,12 @@ void Entity::Help_SetRotationFromVectors(const glm::vec3& front, const glm::vec3 m_rotation = glm::degrees(glm::eulerAngles(q)); } +void Entity::Help_SetVelocity(float x, float y, float z) +{ + if (m_rigidBody) + m_rigidBody->setLinearVelocity(btVector3(x, y, z)); +} + int Entity::Lua_LoadModel(LuaPlus::LuaState* state) { LuaPlus::LuaStack stack(state); @@ -349,6 +327,14 @@ int Entity::Lua_GetPosition(LuaPlus::LuaState* state) return 3; } +int Entity::Lua_GetRotation(LuaPlus::LuaState* state) +{ + state->PushNumber(m_rotation.x); + state->PushNumber(m_rotation.y); + state->PushNumber(m_rotation.z); + return 3; +} + int Entity::Lua_SetRotation(LuaPlus::LuaState* state) { LuaPlus::LuaStack stack(state); @@ -405,11 +391,58 @@ int Entity::Lua_UpdateTransform(LuaPlus::LuaState* state) return 0; } +int Entity::Lua_MarkForDelete(LuaPlus::LuaState* state) +{ + MarkForDelete(); + + return 0; +} + +int Entity::Lua_SetVelocity(LuaPlus::LuaState* state) +{ + LuaPlus::LuaStack stack(state); + + float x = stack[2].GetNumber(); + float y = stack[3].GetNumber(); + float z = stack[4].GetNumber(); + + Help_SetVelocity(x, y, z); + + return 0; +} + +int Entity::Lua_GetVelocity(LuaPlus::LuaState* state) +{ + glm::vec3 velocity = glm::vec3(0.0f); + if (m_rigidBody) + { + velocity = btVectorToGlm(m_rigidBody->getLinearVelocity()); + } + + state->PushNumber(velocity.x); + state->PushNumber(velocity.y); + state->PushNumber(velocity.z); + + return 3; +} + +int Entity::Lua_HasRigidBody(LuaPlus::LuaState* state) +{ + state->PushBoolean(!!m_rigidBody); + return 1; +} + int Entity::Lua_FindAnimation(LuaPlus::LuaState* state) { LuaPlus::LuaStack stack(state); const char* name = stack[2].GetString(); + if (!stack[2].IsString()) + { + Core::Warning("load_model: first argument is not an string"); + return 0; + } + if (m_model) state->PushInteger(m_model->FindAnimation(name)); else @@ -421,6 +454,13 @@ int Entity::Lua_FindAnimation(LuaPlus::LuaState* state) int Entity::Lua_PlayAnimation(LuaPlus::LuaState* state) { LuaPlus::LuaStack stack(state); + + if (!stack[2].IsNumber()) + { + Core::Warning("play_animation: first argument is not an number"); + return 0; + } + AnimationId_t id = stack[2].GetInteger(); int mode = stack[3].GetInteger(); @@ -430,6 +470,14 @@ int Entity::Lua_PlayAnimation(LuaPlus::LuaState* state) return 0; } +int Entity::Lua_StopAnimation(LuaPlus::LuaState* state) +{ + if (m_skeleton) + m_skeleton->StopAnimation(); + + return 0; +} + int Entity::Lua_GetCurrentAnimation(LuaPlus::LuaState* state) { if (m_skeleton) @@ -517,336 +565,6 @@ void Entity::UpdateBodyDirty() } } -REGISTER_ENTITY(ActorBase); - -ActorBase::ActorBase() -{ -} - -ActorBase::~ActorBase() -{ - if (m_rigidBody) { - g_PhysicsWorld->GetWorld()->removeRigidBody(m_rigidBody); - - delete m_rigidBody; - m_rigidBody = nullptr; - - m_ph_motion_state.setBody(nullptr); - } - - if (m_shape) { - delete m_shape; - m_shape = nullptr; - } -} - -void ActorBase::Update(float dt) -{ - static bool s_test = true; - - if (s_test) { - UpdateBodyDirty(); - Entity::Update(dt); - AfterEngineStep(); - } else { - ActivateCamera(); - - UpdateCameraLook(); - - UpdateCameraMovement(dt); - - } - - return; -} - -void ActorBase::AfterEngineStep() -{ - //btTransform xform = m_rigidBody->getWorldTransform(); - //m_position = btVectorToGlm(xform.getOrigin()); - - m_position = btVectorToGlm(m_ph_motion_state.m_transform.getOrigin()); - - glm::vec3 cameraPos = m_position; - - if (m_luaObject.IsTable()) - { - LuaPlus::LuaObject m_camera_offset_y = m_luaObject.GetByName("m_camera_offset_y"); - if (m_camera_offset_y.IsNumber()) - cameraPos.y += m_camera_offset_y.ToNumber(); - } - - m_camera.SetPosition(cameraPos); -} - -void ActorBase::UpdateCameraMovement(float dt) -{ - // calculate player movement - float speed = 12.0f * dt; - - uint32_t movementDir = GenMovementDir(); - - if (movementDir & EMovementDir_Forward) - m_position += speed * m_camera.GetFront(); - if (movementDir & EMovementDir_Backward) - m_position -= speed * m_camera.GetFront(); - if (movementDir & EMovementDir_Left) - m_position -= glm::normalize(glm::cross(m_camera.GetFront(), m_camera.GetUp())) * speed; - if (movementDir & EMovementDir_Right) - m_position += glm::normalize(glm::cross(m_camera.GetFront(), m_camera.GetUp())) * speed; - - // set position back to camera for calculation view matrix - m_camera.SetPosition(m_position); -} - -void ActorBase::UpdateBodyMovement(float dt) -{ - - glm::vec3 dir = glm::vec3(0.0f); - - glm::vec3 camFront = m_camera.GetFront(); - camFront.y = 0.0f; - camFront = glm::normalize(camFront); - - // calculate player movement - float speed = 4.f; - - uint32_t movementDir = GenMovementDir(); - - if (movementDir & EMovementDir_Forward) - dir += camFront; - if (movementDir & EMovementDir_Backward) - dir -= camFront; - if (movementDir & EMovementDir_Left) - dir -= glm::normalize(glm::cross(camFront, m_camera.GetUp())); - if (movementDir & EMovementDir_Right) - dir += glm::normalize(glm::cross(camFront, m_camera.GetUp())); - - btVector3 currentvel = m_rigidBody->getLinearVelocity(); - glm::vec3 velocity = dir * speed; - - if (OnGround()) { - m_rigidBody->setLinearVelocity(btVector3(velocity.x, currentvel.y(), velocity.z)); - if (movementDir & EMovementDir_Jump) { - m_rigidBody->setLinearVelocity(btVector3(currentvel.x(), PLAYER_PHYS_JUMPSPEEDY, currentvel.z())); - } - } else { - float airControl = 0.2f; - btVector3 airvel = currentvel + glmVectorToBt(dir * speed * airControl * dt); - m_rigidBody->setLinearVelocity(btVector3(airvel.x(), currentvel.y(), airvel.z())); - } - - /*if (glm::length(velocity) > 0.1f && OnGround() && !(movementDir & EMovementDir_Jump)) - m_rigidBody->setLinearVelocity(glmVectorToBt(velocity)); - - if ((movementDir & EMovementDir_Jump) && OnGround()) { - m_rigidBody->applyCentralImpulse(btVector3(0.0f, PLAYER_PHYS_JUMPSPEEDY, 0.0f)); - movementDir &= ~EMovementDir_Jump; - }*/ -} - -void ActorBase::UpdateCameraLook() -{ - glm::ivec2 mousePos = g_inputManager.GetMousePos(); - - // calculate yaw and pitch - static float yaw = 0.0f, pitch = 0.0f; - - int deltaX = mousePos.x; - int deltaY = mousePos.y; - - float sensitivity = 0.15f; - - yaw += deltaX * sensitivity; - pitch -= deltaY * sensitivity; - - if (pitch > 89.0f) pitch = 89.0f; - if (pitch < -89.0f) pitch = -89.0f; - - m_camera.SetYawPitch(yaw, pitch); -} - -void ActorBase::ActivateCamera() -{ - g_inputManager.SetRelativeMouseMode(true); - - g_cameraManager.SetActiveCamera(&m_camera); -} - -void ActorBase::CreatePlayerBody() -{ - - m_shape = new btCapsuleShape(PLAYER_PHYS_RADIUS, PLAYER_PHYS_HEIGHT - PLAYER_PHYS_RADIUS * 2.0); - - m_mass = 80.0f; - btVector3 local_inertia(0.0f, 0.0f, 0.0f); - if (m_mass > 0.f) { - m_shape->calculateLocalInertia(m_mass, local_inertia); - } - - btRigidBody::btRigidBodyConstructionInfo rigid_body_ci(m_mass, nullptr, m_shape, local_inertia); - - m_rigidBody = new btRigidBody(rigid_body_ci); - m_rigidBody->setUserPointer(this); - m_rigidBody->setMotionState(&m_ph_motion_state); - m_ph_motion_state.setBody(m_rigidBody); - - // I'm sure that position is valid - btTransform xform; - xform.setIdentity(); - xform.setOrigin(glmVectorToBt(m_position)); - m_rigidBody->setWorldTransform(xform); - - // ACTOR STUFF - m_rigidBody->setAngularFactor(btVector3(0.0f, 0.0f, 0.0f)); - - - //m_rigidBody->setFriction(2.5f); - - m_rigidBody->setFriction(0.0f); - m_rigidBody->setAnisotropicFriction(btVector3(0.0f, 0.0f, 0.0f)); - m_rigidBody->setDamping(0.0f, 0.0f); - - m_rigidBody->setActivationState(DISABLE_DEACTIVATION); - - // #TODO: body filter and mask - g_PhysicsWorld->GetWorld()->addRigidBody(m_rigidBody); - - m_bodyDirty = true; -} - -bool ActorBase::OnGround() -{ - float rayLength = (PLAYER_PHYS_HEIGHT / 2.0f) + 0.1f; - - btTransform xform = m_rigidBody->getWorldTransform(); - - btVector3 rayStart = xform.getOrigin(); - btVector3 rayEnd = rayStart - btVector3(0.0f, rayLength, 0.0f); - - ClosestRayResultCallback RayResultCallback(rayStart, rayEnd, this); - g_PhysicsWorld->GetWorld()->rayTest(rayStart, rayEnd, RayResultCallback); - if (RayResultCallback.hasHit()) { - btVector3 hitNormal = RayResultCallback.m_hitNormalWorld; - if (hitNormal.y() > 0.7f) { - return true; - } - } - - return false; -} - -void ActorBase::RegisterFunctions() -{ - m_luaObject.Register("activate_camera", *this, &ActorBase::Lua_ActivateCamera); - m_luaObject.Register("update_camera_look", *this, &ActorBase::Lua_UpdateCameraLook); - m_luaObject.Register("update_camera_movement", *this, &ActorBase::Lua_UpdateCameraMovement); - m_luaObject.Register("create_body", *this, &ActorBase::Lua_CreateBody); - m_luaObject.Register("update_body_movement", *this, &ActorBase::Lua_UpdateBodyMovement); - m_luaObject.Register("get_action", *this, &ActorBase::Lua_GetAction); - - //m_luaObject.RegisterDirect("activate_camera", &ActorBase_ActivateCamera); - //m_luaObject.RegisterDirect("update_camera_look", &ActorBase_UpdateCameraLook); - //m_luaObject.RegisterDirect("update_camera_movement", &ActorBase_UpdateCameraMovement); -} - -int ActorBase::Lua_UpdateCameraMovement(LuaPlus::LuaState* state) -{ - LuaPlus::LuaStack stack(state); - - UpdateCameraMovement(stack[2].GetFloat()); - - return 0; -} - -int ActorBase::Lua_UpdateBodyMovement(LuaPlus::LuaState* state) -{ - LuaPlus::LuaStack stack(state); - - UpdateBodyMovement(stack[2].GetFloat()); - - return 0; -} - -int ActorBase::Lua_UpdateCameraLook(LuaPlus::LuaState* state) -{ - UpdateCameraLook(); - return 0; -} - -int ActorBase::Lua_ActivateCamera(LuaPlus::LuaState* state) -{ - ActivateCamera(); - return 0; -} - -int ActorBase::Lua_CreateBody(LuaPlus::LuaState* state) -{ - CreatePlayerBody(); - return 0; -} - -int ActorBase::Lua_GetAction(LuaPlus::LuaState* state) -{ -// uint32_t action = 0; - - //float x, y; - //SDL_MouseButtonFlags buttons = SDL_GetMouseState(&x, &y); - - //if (buttons & SDL_BUTTON_MASK(SDL_BUTTON_LEFT)) - // state->PushInteger(0); - //if (buttons & SDL_BUTTON_MASK(SDL_BUTTON_RIGHT)) - // state->PushInteger(1); - //else - // state->PushInteger(-1); - - int action = GenAction(); - state->PushInteger(action); - - return 1; -} - -int ActorBase::GenAction() -{ - int action = -1; - - if (g_inputManager.GetMouse().IsKeyDown(EMouseButton_Left)) - action = 0; - else if (g_inputManager.GetMouse().IsKeyDown(EMouseButton_Right)) - action = 1; - else if (g_inputManager.GetKeyboard().IsKeyDown(SDLK_R)) - action = 2; - - return action; -} - -uint32_t ActorBase::GenMovementDir() -{ - uint32_t movementDir = EMovementDir_None; - - if (g_inputManager.GetKeyboard().IsKeyDown(SDLK_W)) { - movementDir |= EMovementDir_Forward; - } - - if (g_inputManager.GetKeyboard().IsKeyDown(SDLK_S)) { - movementDir |= EMovementDir_Backward; - } - - if (g_inputManager.GetKeyboard().IsKeyDown(SDLK_A)) { - movementDir |= EMovementDir_Left; - } - - if (g_inputManager.GetKeyboard().IsKeyDown(SDLK_D)) { - movementDir |= EMovementDir_Right; - } - - if (g_inputManager.GetKeyboard().IsKeyDown(SDLK_SPACE)) { - movementDir |= EMovementDir_Jump; - } - - return movementDir; -} - REGISTER_ENTITY(WeaponBase); WeaponBase::WeaponBase() @@ -859,8 +577,58 @@ WeaponBase::~WeaponBase() void WeaponBase::Update(float dt) { + Entity::Update(dt); } void WeaponBase::Fire(const glm::vec3& direction, float damage) { } + +//// Lua wrappers +//void Entity_LoadModel(LuaPlus::LuaState* state) +//{ +// LuaPlus::LuaStack stack(state); +// +// Entity* entity = (Entity*)stack[1].GetByName("__object").GetLightUserdata(); +// entity->LoadModel(stack[2].GetString()); +//} +// +//void Entity_SetVisible(LuaPlus::LuaState* state) +//{ +// LuaPlus::LuaStack stack(state); +// +// Entity* entity = (Entity*)stack[1].GetByName("__object").GetLightUserdata(); +// entity->SetVisible(stack[2].GetBoolean()); +//} +// +//bool Entity_GetVisible(LuaPlus::LuaState* state) +//{ +// LuaPlus::LuaStack stack(state); +// +// Entity* entity = (Entity*)stack[1].GetByName("__object").GetLightUserdata(); +// return entity->GetVisible(); +//} +// +//void ActorBase_UpdateCameraMovement(LuaPlus::LuaState* state) +//{ +// LuaPlus::LuaStack stack(state); +// +// ActorBase* entity = (ActorBase*)stack[1].GetByName("__object").GetLightUserdata(); +// entity->UpdateCameraMovement(stack[2].GetFloat()); +//} +// +//void ActorBase_UpdateCameraLook(LuaPlus::LuaState* state) +//{ +// LuaPlus::LuaStack stack(state); +// +// ActorBase* entity = (ActorBase*)stack[1].GetByName("__object").GetLightUserdata(); +// entity->UpdateCameraLook(); +//} +// +//void ActorBase_ActivateCamera(LuaPlus::LuaState* state) +//{ +// LuaPlus::LuaStack stack(state); +// +// ActorBase* entity = (ActorBase*)stack[1].GetByName("__object").GetLightUserdata(); +// entity->ActivateCamera(); +//} diff --git a/src/game/game_object.h b/src/game/game_object.h index 254bb09..0d1f075 100644 --- a/src/game/game_object.h +++ b/src/game/game_object.h @@ -89,6 +89,7 @@ public: // Game entity lua bindings void InitFromTable(LuaPlus::LuaObject& _object); + void InitLuaCallbacks(); void RegisterBaseFunctions(); virtual void RegisterFunctions(); @@ -97,19 +98,27 @@ public: void Help_SetPosition(float x, float y, float z); void Help_SetRotation(float x, float y, float z); void Help_SetRotationFromVectors(const glm::vec3& front, const glm::vec3& right, const glm::vec3& up); + void Help_SetVelocity(float x, float y, float z); int Lua_LoadModel(LuaPlus::LuaState* state); int Lua_Translate(LuaPlus::LuaState* state); int Lua_SetPosition(LuaPlus::LuaState* state); int Lua_GetPosition(LuaPlus::LuaState* state); + int Lua_GetRotation(LuaPlus::LuaState* state); int Lua_SetRotation(LuaPlus::LuaState* state); int Lua_SetRotationFromVectors(LuaPlus::LuaState* state); int Lua_GetClassname(LuaPlus::LuaState* state); int Lua_GetID(LuaPlus::LuaState* state); int Lua_UpdateTransform(LuaPlus::LuaState* state); + int Lua_MarkForDelete(LuaPlus::LuaState* state); + + int Lua_SetVelocity(LuaPlus::LuaState* state); + int Lua_GetVelocity(LuaPlus::LuaState* state); + int Lua_HasRigidBody(LuaPlus::LuaState* state); int Lua_FindAnimation(LuaPlus::LuaState* state); int Lua_PlayAnimation(LuaPlus::LuaState* state); + int Lua_StopAnimation(LuaPlus::LuaState* state); int Lua_GetCurrentAnimation(LuaPlus::LuaState* state); int Lua_GetCurrentAnimationTime(LuaPlus::LuaState* state); int Lua_GetAnimationTime(LuaPlus::LuaState* state); @@ -136,49 +145,6 @@ protected: bool m_bodyDirty; }; -class ActorBase : public Entity -{ -public: - ActorBase(); - ~ActorBase(); - - virtual void Update(float dt); - - void AfterEngineStep(); - - void UpdateCameraMovement(float dt); - - void UpdateBodyMovement(float dt); - - void UpdateCameraLook(); - - void ActivateCamera(); - - void CreatePlayerBody(); - - bool OnGround(); - - // Lua bindings - - virtual void RegisterFunctions(); - - int Lua_UpdateCameraMovement(LuaPlus::LuaState* state); - int Lua_UpdateBodyMovement(LuaPlus::LuaState* state); - int Lua_UpdateCameraLook(LuaPlus::LuaState* state); - int Lua_ActivateCamera(LuaPlus::LuaState* state); - int Lua_CreateBody(LuaPlus::LuaState* state); - int Lua_GetAction(LuaPlus::LuaState* state); - -private: - int GenAction(); - uint32_t GenMovementDir(); - -private: - Camera m_camera; - - -}; - class WeaponBase : public Entity { public: diff --git a/src/game/game_ui.cpp b/src/game/game_ui.cpp new file mode 100644 index 0000000..c1d2cb1 --- /dev/null +++ b/src/game/game_ui.cpp @@ -0,0 +1,79 @@ +#include "core.h" +#include "game_ui.h" +#include "game_lua_help.h" +#include "texturesmanager.h" + +#include + +using namespace LuaPlus; + +uint32_t ColorFromLua(const LuaObject& color) +{ + SDL_assert_always(color.IsTable()); + + float r = color[1].ToNumber(); + float g = color[2].ToNumber(); + float b = color[3].ToNumber(); + float a = color[4].ToNumber(); + + return ImGui::ColorConvertFloat4ToU32(ImVec4(r, g, b, a)); +} + +void uiDrawText(const char* text, float x, float y, const LuaObject& color) +{ + ImGui::GetBackgroundDrawList()->AddText(ImVec2(x, y), ColorFromLua(color), text); +} + +void uiDrawRect(float x, float y, float w, float h, const LuaObject& color) +{ + ImGui::GetBackgroundDrawList()->AddRectFilled(ImVec2(x, y), ImVec2(w, h), ColorFromLua(color)); +} + +void uiDrawImage(const char* filename, float x, float y, float w, float h, const LuaObject& color) +{ + ImTextureID texture = (ImTextureID)g_texturesManager->LoadTexture2D(filename); + ImGui::GetBackgroundDrawList()->AddImage(texture, ImVec2(x, y), ImVec2(w, h), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), ColorFromLua(color)); +} + +int uiGetDisplaySize(LuaState* state) +{ + state->PushNumber(ImGui::GetIO().DisplaySize.x); + state->PushNumber(ImGui::GetIO().DisplaySize.y); + return 2; +} + +int uiGetMousePos(LuaState* state) +{ + state->PushNumber(ImGui::GetIO().MousePos.x); + state->PushNumber(ImGui::GetIO().MousePos.y); + return 2; +} + +int uiCalcTextWidth(LuaState* state) +{ + LuaStack stack(state); + SDL_assert_always(stack[1].IsString()); + + state->PushNumber(ImGui::CalcTextSize(stack[1].GetString()).x); + + return 1; +} + +void registerEngineUI() +{ + LuaObject uiTable = GetLuaState().GetGlobals().CreateTable("ui"); + uiTable.RegisterDirect("draw_text", &uiDrawText); + uiTable.RegisterDirect("draw_rect", &uiDrawRect); + uiTable.RegisterDirect("draw_image", &uiDrawImage); + uiTable.Register("get_display_size", &uiGetDisplaySize); + uiTable.Register("get_mouse_pos", &uiGetMousePos); + uiTable.Register("calc_text_width", &uiCalcTextWidth); +} + +void gameRenderUI() +{ + LuaObject renderFunction = GetLuaState().GetGlobal("game_hud_draw"); + + LuaFunctionVoid function = renderFunction; + function(); +} diff --git a/src/game/game_ui.h b/src/game/game_ui.h new file mode 100644 index 0000000..500b669 --- /dev/null +++ b/src/game/game_ui.h @@ -0,0 +1,8 @@ +#ifndef GAME_UI_H +#define GAME_UI_H + +void registerEngineUI(); + +void gameRenderUI(); + +#endif // !GAME_UI_H diff --git a/src/render/model.cpp b/src/render/model.cpp index f194a21..2842ddf 100644 --- a/src/render/model.cpp +++ b/src/render/model.cpp @@ -674,24 +674,24 @@ void Model::Draw(const glm::mat4& model, SkeletonInstance* instance /*= nullptr* } // debug draw - if (instance) - { - glm::mat4 worldMat; - glm::mat4 worldMatParent; - for (int i = 0; i < instance->m_jointMatrices.size(); i++) - { - worldMat = model * instance->m_jointMatrices[i]; - glm::vec3 worldPos = worldMat[3]; - // g_debugRender->DrawAxis(worldPos); + //if (instance) + //{ + // glm::mat4 worldMat; + // glm::mat4 worldMatParent; + // for (int i = 0; i < instance->m_jointMatrices.size(); i++) + // { + // worldMat = model * instance->m_jointMatrices[i]; + // glm::vec3 worldPos = worldMat[3]; + // // g_debugRender->DrawAxis(worldPos); - const Joint& joint = instance->m_joints[i]; - if (joint.parentId != -1) - { - worldMatParent = model * instance->m_jointMatrices[joint.parentId]; - g_debugRender->DrawLine(worldMat[3], worldMatParent[3], glm::vec3(1.0f, 1.0f, 1.0f)); - } - } - } + // const Joint& joint = instance->m_joints[i]; + // if (joint.parentId != -1) + // { + // worldMatParent = model * instance->m_jointMatrices[joint.parentId]; + // g_debugRender->DrawLine(worldMat[3], worldMatParent[3], glm::vec3(1.0f, 1.0f, 1.0f)); + // } + // } + //} } @@ -764,7 +764,7 @@ void Model::UpdateSkeletonInstance(SkeletonInstance* instance, float dt) instance->m_time += dt; float frameTime = 1.0f / animation.framerate; - float totalDuration = animation.numFrames * frameTime; + float totalDuration = (animation.numFrames - 1) * frameTime; if (instance->m_time >= totalDuration && instance->m_looped) instance->m_time = 0.0f; @@ -772,11 +772,17 @@ void Model::UpdateSkeletonInstance(SkeletonInstance* instance, float dt) float animationFrame = instance->m_time / frameTime; int frameA = (int)(floor(animationFrame)); int frameB = (frameA + 1) % animation.numFrames; + float t = animationFrame - frameA; if (!instance->m_looped && frameA >= animation.numFrames - 1) frameA = animation.numFrames - 1; - float t = animationFrame - frameA; + if (instance->m_time >= totalDuration) + { + frameA = animation.numFrames - 1; + frameB = animation.numFrames - 1; + t = 0.0f; + } for (int i = 0; i < instance->m_joints.size(); ++i) { diff --git a/src/render/render.cpp b/src/render/render.cpp index d77b191..0856eca 100644 --- a/src/render/render.cpp +++ b/src/render/render.cpp @@ -14,7 +14,7 @@ static GLuint g_VAO = 0; -static int g_NumModels = 0; +int g_NumModels = 0; // TEMP glm::vec3 g_viewOrigin; @@ -77,7 +77,8 @@ Render::Render() : m_pWindow(nullptr), m_pGLContext(nullptr), m_pStretchedPicVBuf(nullptr), - m_usingVAO(false) + m_usingVAO(false), + m_showStats(true) { m_viewMatrix = glm::identity(); m_projectionMatrix = glm::identity(); @@ -296,6 +297,9 @@ void Render::RenderScene() { void Render::RenderStats() { + if (!m_showStats) + return; + char buffer[256]; snprintf(buffer, sizeof(buffer), "FPS: %.1f", ImGui::GetIO().Framerate); @@ -343,6 +347,11 @@ void Render::LoadSceneXML(const char* filename) g_sceneManager->loadScene(filename); } +void Render::ToggleShowStats() +{ + m_showStats = !m_showStats; +} + //IRender* GetRender() //{ // return g_render; diff --git a/src/render/render.h b/src/render/render.h index 41448d5..cd9b2d0 100644 --- a/src/render/render.h +++ b/src/render/render.h @@ -36,6 +36,8 @@ public: SDL_GLContext GetGLContext() { return m_pGLContext; } + void ToggleShowStats(); + private: glm::mat4 m_viewMatrix; glm::mat4 m_projectionMatrix; @@ -46,6 +48,7 @@ private: GPUBuffer* m_pStretchedPicVBuf; bool m_usingVAO; + bool m_showStats; }; extern Render* g_render; diff --git a/src/render/scenemanager.cpp b/src/render/scenemanager.cpp index 95c00c3..41830f3 100644 --- a/src/render/scenemanager.cpp +++ b/src/render/scenemanager.cpp @@ -18,6 +18,9 @@ #include +extern int g_NumModels; +static bool g_debugRenderScene = false; + static std::string getFileExtension(const std::string& filename) { size_t whereIsDot = filename.find_last_of('.'); @@ -398,7 +401,8 @@ void SceneManager::renderScene(const glm::mat4& cameraTranslation) (*it)->RenderObjects(); - g_debugRender->DrawBoundingBox((*it)->GetBoundingBox(), glm::vec3(1.0f)); + if (g_debugRenderScene) + g_debugRender->DrawBoundingBox((*it)->GetBoundingBox(), glm::vec3(1.0f)); } } @@ -482,6 +486,11 @@ const char* SceneManager::getSceneName() return m_sceneName.c_str(); } +void SceneManager::toggleDebugRender() +{ + g_debugRenderScene = !g_debugRenderScene; +} + // SceneStaticMesh SceneStaticMesh::SceneStaticMesh() : @@ -818,7 +827,7 @@ void R_SceneStaticMesh_BindShader(const glm::mat4& worldMatrix, Texture2D* albed { glm::vec4 lightPos = glm::vec4(1.0f, 1.0f, 1.0f, 0.0f); - g_debugRender->DrawAxis(glm::vec3(lightPos)); + // g_debugRender->DrawAxis(glm::vec3(lightPos)); Camera* camera = g_cameraManager.GetActiveCamera(); if (camera) @@ -853,4 +862,6 @@ void SceneStaticMesh::RenderObjects() R_SceneStaticMesh_BindShader(s_identity, m_albedoTexture); g_renderDevice->DrawArrays(PT_TRIANGLES, 0, m_vbcount); + + g_NumModels++; } diff --git a/src/render/scenemanager.h b/src/render/scenemanager.h index fa05071..f8fb51f 100644 --- a/src/render/scenemanager.h +++ b/src/render/scenemanager.h @@ -43,6 +43,9 @@ public: // \brief Get current scene name. const char* getSceneName(); + // \brief Toggle an debug rendering. + void toggleDebugRender(); + private: void LoadSceneXML(const char* filename); void loadSkybox(const char*);