diff --git a/Content/Documentation/ScriptingAPI-Documentation.md b/Content/Documentation/ScriptingAPI-Documentation.md index d4f26eab6..2623c0912 100644 --- a/Content/Documentation/ScriptingAPI-Documentation.md +++ b/Content/Documentation/ScriptingAPI-Documentation.md @@ -350,6 +350,8 @@ Gives you the ability to render text with a custom font. - SetShadowBolden(float value) - SetShadowSoftness(float value) - SetShadowOffset(Vector value) +- SetHorizontalWrapping(float value) +- SetHidden(bool value) - GetText() : string result - GetSize() : int result - GetPos() : Vector result @@ -362,6 +364,17 @@ Gives you the ability to render text with a custom font. - GetShadowBolden() : float result - GetShadowSoftness() : float result - GetShadowOffset() : Vector result +- GetHorizontalWrapping() : float result +- IsHidden() : bool result +- TextSize() : Vector result -- returns text width and height in a Vector's X and Y components +- SetTypewriterTime(float value) -- time to fully type the text in seconds (0: disable) +- SetTypewriterLooped(bool value)) -- if true, typing starts over when finished +- SetTypewriterCharacterStart(int value) -- starting character for the animation +- SetTypewriterSound(Sound sound, SoundInstance soundinstance) -- sound effect when new letter appears +- ResetTypewriter() -- resets typewriter to first character +- TypewriterFinish() -- finished typewriter animation immediately +- IsTypewriterFinished() : bool -- returns tru if typewrites animation is finished, false otherwise + ### Texture Just holds texture information in VRAM. @@ -693,6 +706,7 @@ Describes an orientation in 3D space. - UpdateCamera() -- update the camera matrices - TransformCamera(TransformComponent transform) -- copies the transform's orientation to the camera, and sets the camera position, look direction and up direction. Camera matrices are not updated immediately. They will be updated by the Scene::Update() (if the camera is part of the scene), or by manually calling UpdateCamera() +- TransformCamera(Matrix matrix) - GetFOV() : float result - SetFOV(float value) -- Sets the vertical field of view for the camera (value is an angle in radians) - GetNearPlane() : float result @@ -985,7 +999,7 @@ Describes a Rigid Body Physics object. - LinearDamping : float - AngularDamping : float - BoxParams_HalfExtents : Vector -- SphereParams_Radius : floatd +- SphereParams_Radius : float - CapsuleParams_Radius : float - CapsuleParams_Height : float - TargetMeshLOD : int @@ -1072,6 +1086,13 @@ Describes a Collider object. - GetPresetWeight(ExpressionPreset preset) : float -- returns current weight of preset expression - SetForceTalkingEnabled(bool value) -- Force continuous talking animation, even if no voice is playing - IsForceTalkingEnabled() : bool +- SetPresetOverrideMouth(ExpressionPreset preset, ExpressionOverride override) +- SetPresetOverrideBlink(ExpressionPreset preset, ExpressionOverride override) +- SetPresetOverrideLook(ExpressionPreset preset, ExpressionOverride override) +- SetOverrideMouth(int id, ExpressionOverride override) +- SetOverrideBlink(int id, ExpressionOverride override) +- SetOverrideLook(int id, ExpressionOverride override) + [outer] ExpressionPreset = { Happy = 0, @@ -1094,6 +1115,12 @@ Describes a Collider object. Neutral = 17, } +[outer] ExpressionOverride = { + None = 0, + Block = 1, + Blend = 2, +} + #### HumanoidComponent - GetBoneEntity(HumanoidBone bone) : int -- Get the entity that is mapped to the specified humanoid bone. Use HumanoidBone table to get access to humanoid bone values diff --git a/Content/scripts/character_controller/assets/animations.wiscene b/Content/scripts/character_controller/assets/animations.wiscene index 61718c8e9..c9a0fd9d9 100644 Binary files a/Content/scripts/character_controller/assets/animations.wiscene and b/Content/scripts/character_controller/assets/animations.wiscene differ diff --git a/Content/scripts/character_controller/assets/level.wiscene b/Content/scripts/character_controller/assets/level.wiscene index 547a47f27..f81b9182c 100644 Binary files a/Content/scripts/character_controller/assets/level.wiscene and b/Content/scripts/character_controller/assets/level.wiscene differ diff --git a/Content/scripts/character_controller/assets/typewriter.wav b/Content/scripts/character_controller/assets/typewriter.wav new file mode 100644 index 000000000..070a45d26 Binary files /dev/null and b/Content/scripts/character_controller/assets/typewriter.wav differ diff --git a/Content/scripts/character_controller/assets/zone_angry.lua b/Content/scripts/character_controller/assets/zone_angry.lua deleted file mode 100644 index 76f4df871..000000000 --- a/Content/scripts/character_controller/assets/zone_angry.lua +++ /dev/null @@ -1,4 +0,0 @@ -if not Script_Initialized(script_pid()) then - dofile(script_dir() .. "zone_expression.lua") -end -zone_expression(GetEntity(), ExpressionPreset.Angry, "angry") \ No newline at end of file diff --git a/Content/scripts/character_controller/assets/zone_angry.wiscene b/Content/scripts/character_controller/assets/zone_angry.wiscene deleted file mode 100644 index e3cb6e87b..000000000 Binary files a/Content/scripts/character_controller/assets/zone_angry.wiscene and /dev/null differ diff --git a/Content/scripts/character_controller/assets/zone_expression.lua b/Content/scripts/character_controller/assets/zone_expression.lua deleted file mode 100644 index 9cf047227..000000000 --- a/Content/scripts/character_controller/assets/zone_expression.lua +++ /dev/null @@ -1,31 +0,0 @@ -function zone_expression(zone_entity, expression_preset, expression_string) - local distance = 1 - local scene = GetScene() - local zone_transform = scene.Component_GetTransform(zone_entity) - if zone_transform ~= nil then - local zone_pos = zone_transform.GetPosition() - local zone_active = false - - for i,entity in ipairs(scene.Entity_GetExpressionArray()) do - local transform = scene.Component_GetTransform(entity) - local expression = scene.Component_GetExpression(entity) - if expression ~= nil and transform ~= nil then - local expression_pos = transform.GetPosition() - if vector.Subtract(expression_pos, zone_pos).Length() < distance then - expression.SetPresetWeight(expression_preset, 1) - zone_active = true - else - expression.SetPresetWeight(expression_preset, 0) - end - end - end - - local str = "If character gets close to this, it will be " .. expression_string .. "\n" - if zone_active then - str = str .. "...and a character is currently " .. expression_string .. "!" - else - str = str .. "...but no one is " .. expression_string .. " currently." - end - DrawDebugText(str, vector.Add(zone_pos, Vector(0,1,0)), Vector(1,1,1,1), 0.1, DEBUG_TEXT_DEPTH_TEST | DEBUG_TEXT_CAMERA_FACING) - end -end diff --git a/Content/scripts/character_controller/assets/zone_happy.lua b/Content/scripts/character_controller/assets/zone_happy.lua deleted file mode 100644 index 9af0f1a4a..000000000 --- a/Content/scripts/character_controller/assets/zone_happy.lua +++ /dev/null @@ -1,4 +0,0 @@ -if not Script_Initialized(script_pid()) then - dofile(script_dir() .. "zone_expression.lua") -end -zone_expression(GetEntity(), ExpressionPreset.Happy, "happy") diff --git a/Content/scripts/character_controller/assets/zone_happy.wiscene b/Content/scripts/character_controller/assets/zone_happy.wiscene deleted file mode 100644 index 25c619815..000000000 Binary files a/Content/scripts/character_controller/assets/zone_happy.wiscene and /dev/null differ diff --git a/Content/scripts/character_controller/assets/zone_sad.lua b/Content/scripts/character_controller/assets/zone_sad.lua deleted file mode 100644 index a73399efd..000000000 --- a/Content/scripts/character_controller/assets/zone_sad.lua +++ /dev/null @@ -1,4 +0,0 @@ -if not Script_Initialized(script_pid()) then - dofile(script_dir() .. "zone_expression.lua") -end -zone_expression(GetEntity(), ExpressionPreset.Sad, "sad") \ No newline at end of file diff --git a/Content/scripts/character_controller/assets/zone_sad.wiscene b/Content/scripts/character_controller/assets/zone_sad.wiscene deleted file mode 100644 index aaccabe12..000000000 Binary files a/Content/scripts/character_controller/assets/zone_sad.wiscene and /dev/null differ diff --git a/Content/scripts/character_controller/character_controller.lua b/Content/scripts/character_controller/character_controller.lua index 2a2872e9f..3aecdb2d0 100644 --- a/Content/scripts/character_controller/character_controller.lua +++ b/Content/scripts/character_controller/character_controller.lua @@ -5,13 +5,14 @@ -- WASD/left thumbstick: walk -- SHIFT/right shoulder button: walk -> jog -- E/left shoulder button: jog -> run --- SPACE/gamepad X/gamepad button 2: jump +-- SPACE/gamepad X/gamepad button 3: jump -- Right Mouse Button/Right thumbstick: rotate camera -- Scoll middle mouse/Left-Right triggers: adjust camera distance -- H: toggle debug draw -- L: toggle framerate lock -- ESCAPE key: quit --- ENTER: reload script +-- R: reload script +-- ENTER: interaction -- Debug Draw Helper local DrawAxis = function(point,f) @@ -20,13 +21,230 @@ local DrawAxis = function(point,f) DrawLine(point,point:Add(Vector(0,0,f)),Vector(0,0,1,1)) end -local debug = true -- press H to toggle +local debug = false -- press H to toggle local allow_pushaway_NPC = true -- You can decide whether NPCs can be pushed away by player local framerate_lock = false local framerate_lock_target = 20 local slope_threshold = 0.2 -- How much slopeiness will cause character to slide down instead of standing on it local gravity = -30 +local ConversationState = { + Disabled = 0, + Talking = 1, + Waiting = 2, +} +local function Conversation() + local self = { + state = ConversationState.Disabled, + percent = 0, + character = nil, + font = SpriteFont(), + advance_font = SpriteFont(""), + choice_fonts = {}, + font_blink_timer = 0, + dialog = {}, + speed = 30, + choice = 1, + override_input = false, + + Update = function(self, path, scene, player) + + local crop_height = GetScreenHeight() * 0.18 + local text_offset = GetScreenWidth() * 0.2 + self.font.SetPos(Vector(text_offset, GetScreenHeight() - crop_height + 10)) + self.font.SetHorizontalWrapping(GetScreenWidth() - self.font.GetPos().GetX() * 2) + self.advance_font.SetPos(Vector(GetScreenWidth() - self.font.GetPos().GetX(), GetScreenHeight() - 50)) + + -- Update conversation percentage (fade in/out of conversation) + if self.state == ConversationState.Disabled then + self.percent = math.lerp(self.percent, 0, 0.05) + else + self.percent = math.lerp(self.percent, 1, 0.05) + end + path.SetCropTop(self.percent * crop_height) + path.SetCropBottom(self.percent * crop_height) + local cam = GetCamera() + cam.SetApertureSize(self.percent) + + if self.percent < 0.9 then + self.font.SetHidden(true) + self.font.ResetTypewriter() + else + self.font.SetHidden(false) + end + self.advance_font.SetColor(Vector()) + self.override_input = false + for i,choice_font in ipairs(self.choice_fonts) do + choice_font.SetColor(Vector()) + end + self.font_blink_timer = self.font_blink_timer + getDeltaTime() + + -- Focus on character: + if self.character ~= nil then + cam.SetFocalLength(vector.Subtract(scene.Component_GetTransform(self.character.head).GetPosition(), cam.GetPosition()).Length()) + end + + -- State flow: + if self.state == ConversationState.Disabled then + self.font.SetHidden(true) + elseif self.state == ConversationState.Talking then + + self.choice = 1 + self.override_input = true + self:CinematicCamera(self.character, player, scene, cam) + + -- End of talking: + if self.font.IsTypewriterFinished() then + self.state = ConversationState.Waiting + self.font_blink_timer = 0 + end + + -- Skip talking: + if input.Press(KEYBOARD_BUTTON_ENTER) or input.Press(KEYBOARD_BUTTON_SPACE) or input.Press(GAMEPAD_BUTTON_2) then + self.font.TypewriterFinish() + end + + -- Turn on talking animation: + if self.character.expression ~= INVALID_ENTITY and self.percent >= 0.9 then + scene.Component_GetExpression(self.character.expression).SetForceTalkingEnabled(true) + end + + elseif self.state == ConversationState.Waiting then + + -- End of talking, waiting for input: + + if self.dialog.choices ~= nil then + -- Dialog choices: + self.override_input = true + self:CinematicCamera(player, self.character, scene, cam) + + local pos = vector.Add(self.font.GetPos(), Vector(20, 10 + self.font.TextSize().GetY())) + for i,choice in ipairs(self.dialog.choices) do + if self.choice_fonts[i] == nil then + self.choice_fonts[i] = SpriteFont() + path.AddFont(self.choice_fonts[i]) + end + self.choice_fonts[i].SetPos(pos) + self.choice_fonts[i].SetSize(self.font.GetSize()) + self.choice_fonts[i].SetHorizontalWrapping(GetScreenWidth() - self.choice_fonts[i].GetPos().GetX() * 2) + if i == self.choice then + self.choice_fonts[i].SetText(" " .. choice[1]) + self.choice_fonts[i].SetColor(vector.Lerp(Vector(1,1,1,1), self.font.GetColor(), math.abs(math.sin(self.font_blink_timer * math.pi)))) + else + self.choice_fonts[i].SetText(" " .. choice[1]) + self.choice_fonts[i].SetColor(self.font.GetColor()) + end + pos = vector.Add(pos, Vector(0, self.choice_fonts[i].TextSize().GetY() + 5)) + end + + -- Dialog input: + if input.Press(KEYBOARD_BUTTON_UP) or input.Press(string.byte('W')) or input.Press(GAMEPAD_BUTTON_UP) then + self.choice = self.choice - 1 + self.font_blink_timer = 0 + end + if input.Press(KEYBOARD_BUTTON_DOWN) or input.Press(string.byte('S')) or input.Press(GAMEPAD_BUTTON_DOWN) then + self.choice = self.choice + 1 + self.font_blink_timer = 0 + end + if self.choice < 1 then + self.choice = #self.dialog.choices + end + if self.choice > #self.dialog.choices then + self.choice = 1 + end + if input.Press(KEYBOARD_BUTTON_ENTER) or input.Press(KEYBOARD_BUTTON_SPACE) or input.Press(GAMEPAD_BUTTON_2) then + if self.dialog.choices[self.choice].action ~= nil then + self.dialog.choices[self.choice].action() -- execute dialog choice action + end + self:Next() + end + else + -- No dialog choices: + self.override_input = true + self:CinematicCamera(self.character, player, scene, cam) + + if input.Press(KEYBOARD_BUTTON_ENTER) or input.Press(KEYBOARD_BUTTON_SPACE) or input.Press(GAMEPAD_BUTTON_2) then + if self.dialog.action_after ~= nil then + self.dialog.action_after() -- execute dialog action after ended + end + self:Next() + self.font.ResetTypewriter() + end + -- Blinking advance conversation icon: + self.advance_font.SetColor(vector.Lerp(Vector(0,0,0,0), self.font.GetColor(), math.abs(math.sin(self.font_blink_timer * math.pi)))) + end + + -- Turn off talking animation: + if self.character.expression ~= INVALID_ENTITY then + scene.Component_GetExpression(self.character.expression).SetForceTalkingEnabled(false) + end + end + + end, + + Enter = function(self, character) + backlog_post("Entering conversation") + self.state = ConversationState.Talking + self.character = character + if #self.character.dialogs < self.character.next_dialog then + self.character.next_dialog = 1 + end + self:Next() + end, + + Exit = function(self) + backlog_post("Exiting conversation") + self.state = ConversationState.Disabled + self.dialog = {} + self.override_input = false + self.font.ResetTypewriter() + end, + + Next = function(self) + if #self.character.dialogs < self.character.next_dialog then + self:Exit() + end + if self.state == ConversationState.Disabled then + return + end + self.dialog = self.character.dialogs[self.character.next_dialog] + self.character.next_dialog = self.character.next_dialog + 1 + self.state = ConversationState.Talking + self.font.SetText(self.dialog[1]) + self.font.SetTypewriterTime(string.len(self.dialog[1] or "") / self.speed) + self.font.ResetTypewriter() + if self.dialog.action ~= nil then + self.dialog.action() -- execute dialog action + end + end, + + CinematicCamera = function(self, character_foreground, character_background, scene, camera) + local head_pos = scene.Component_GetTransform(character_foreground.head).GetPosition() + local forward_dir = vector.Subtract(character_background.position, character_foreground.position).Normalize() + forward_dir = vector.TransformNormal(forward_dir, matrix.RotationY(math.pi * 0.1)) + local up_dir = Vector(0,1,0) + local right_dir = vector.Cross(up_dir, forward_dir).Normalize() + local cam_pos = vector.Add(head_pos, forward_dir) + local cam_target = vector.Add(vector.Add(head_pos, vector.Multiply(right_dir, -0.4)), Vector(0,-0.1)) + local lookat = matrix.Inverse(matrix.LookAt(cam_pos, cam_target)) + camera.TransformCamera(lookat) + camera.UpdateCamera() + camera.SetFocalLength(vector.Subtract(head_pos, camera.GetPosition()).Length()) + end + } + self.font.SetSize(20) + self.font.SetColor(Vector(0.6,0.8,1,1)) + self.advance_font.SetSize(24) + local sound = Sound() + local soundinstance = SoundInstance() + audio.CreateSound(script_dir() .. "assets/typewriter.wav", sound) + audio.CreateSoundInstance(sound, soundinstance) + audio.SetVolume(0.2, soundinstance) + self.font.SetTypewriterSound(sound, soundinstance) + return self +end +local conversation = Conversation() + local scene = GetScene() local Layers = { @@ -41,7 +259,17 @@ local States = { JUMP = "jump", SWIM_IDLE = "swim_idle", SWIM = "swim", - DANCE = "dance" + DANCE = "dance", + WAVE = "wave" +} + +local Mood = { + Neutral = ExpressionPreset.Neutral, + Happy = ExpressionPreset.Happy, + Angry = ExpressionPreset.Angry, + Sad = ExpressionPreset.Sad, + Relaxed = ExpressionPreset.Relaxed, + Surprised = ExpressionPreset.Surprised } local enable_footprints = true @@ -60,7 +288,8 @@ local function LoadAnimations(model_name) JUMP = anim_scene.Entity_FindByName("jump"), SWIM_IDLE = anim_scene.Entity_FindByName("swim_idle"), SWIM = anim_scene.Entity_FindByName("swim"), - DANCE = anim_scene.Entity_FindByName("dance") + DANCE = anim_scene.Entity_FindByName("dance"), + WAVE = anim_scene.Entity_FindByName("wave"), } scene.Merge(anim_scene) end @@ -73,16 +302,8 @@ local function Character(model_name, start_position, face, controllable) target_rot_horizontal = 0, target_rot_vertical = 0, target_height = 0, - current_anim = INVALID_ENTITY, - idle_anim = INVALID_ENTITY, - walk_anim = INVALID_ENTITY, - jog_anim = INVALID_ENTITY, - run_anim = INVALID_ENTITY, - jump_anim = INVALID_ENTITY, - swim_idle_anim = INVALID_ENTITY, - dance_anim = INVALID_ENTITY, - swim_anim = INVALID_ENTITY, - all_anims = {}, + anims = {}, + anim_amount = 1, neck = INVALID_ENTITY, head = INVALID_ENTITY, left_hand = INVALID_ENTITY, @@ -111,12 +332,16 @@ local function Character(model_name, start_position, face, controllable) root_bone_offset = 0, foot_placed_left = false, foot_placed_right = false, + mood = Mood.Neutral, + mood_amount = 1, patrol_waypoints = {}, patrol_next = 0, patrol_wait = 0, patrol_reached = false, hired = nil, + dialogs = {}, + next_dialog = 1, Create = function(self, model_name, start_position, face, controllable) self.start_position = start_position @@ -172,27 +397,26 @@ local function Character(model_name, start_position, face, controllable) for i,entity in ipairs(scene.Entity_GetExpressionArray()) do if scene.Entity_IsDescendant(entity, self.model) then self.expression = entity - self.happy = 0 - break + + -- Set up some overrides to avoid bad looking expression combinations: + local expression = scene.Component_GetExpression(self.expression) + expression.SetPresetOverrideBlink(ExpressionPreset.Happy, ExpressionOverride.Block) + expression.SetPresetOverrideMouth(ExpressionPreset.Happy, ExpressionOverride.Blend) + expression.SetPresetOverrideBlink(ExpressionPreset.Surprised, ExpressionOverride.Block) end end self.root = scene.Entity_FindByName("Root", self.model) - self.idle_anim = scene.RetargetAnimation(self.humanoid, animations.IDLE, false) - self.walk_anim = scene.RetargetAnimation(self.humanoid, animations.WALK, false) - self.jog_anim = scene.RetargetAnimation(self.humanoid, animations.JOG, false) - self.run_anim = scene.RetargetAnimation(self.humanoid, animations.RUN, false) - self.jump_anim = scene.RetargetAnimation(self.humanoid, animations.JUMP, false) - self.swim_idle_anim = scene.RetargetAnimation(self.humanoid, animations.SWIM_IDLE, false) - self.swim_anim = scene.RetargetAnimation(self.humanoid, animations.SWIM, false) - self.dance_anim = scene.RetargetAnimation(self.humanoid, animations.DANCE, false) - - for i,entity in ipairs(scene.Entity_GetAnimationArray()) do - if scene.Entity_IsDescendant(entity, self.model) then - table.insert(self.all_anims, entity) - end - end + self.anims[States.IDLE] = scene.RetargetAnimation(self.humanoid, animations.IDLE, false) + self.anims[States.WALK] = scene.RetargetAnimation(self.humanoid, animations.WALK, false) + self.anims[States.JOG] = scene.RetargetAnimation(self.humanoid, animations.JOG, false) + self.anims[States.RUN] = scene.RetargetAnimation(self.humanoid, animations.RUN, false) + self.anims[States.JUMP] = scene.RetargetAnimation(self.humanoid, animations.JUMP, false) + self.anims[States.SWIM_IDLE] = scene.RetargetAnimation(self.humanoid, animations.SWIM_IDLE, false) + self.anims[States.SWIM] = scene.RetargetAnimation(self.humanoid, animations.SWIM, false) + self.anims[States.DANCE] = scene.RetargetAnimation(self.humanoid, animations.DANCE, false) + self.anims[States.WAVE] = scene.RetargetAnimation(self.humanoid, animations.WAVE, false) local model_transform = scene.Component_GetTransform(self.model) model_transform.ClearTransform() @@ -250,7 +474,7 @@ local function Character(model_name, start_position, face, controllable) model_transform.Translate(savedPos) model_transform.UpdateTransform() - if controllable then + if self.controllable then -- Camera target control: -- read from gamepad analog stick: @@ -271,40 +495,22 @@ local function Character(model_name, start_position, face, controllable) self.target_rot_horizontal = self.target_rot_horizontal + diff.GetX() self.target_rot_vertical = math.clamp(self.target_rot_vertical + diff.GetY(), -math.pi * 0.3, math.pi * 0.4) -- vertical camers limits - - if self.dance_anim ~= INVALID_ENTITY and self.state == States.IDLE and input.Press(string.byte('C')) then - self.state = States.DANCE - end end - if self.state == States.DANCE then - self.happy = math.lerp(self.happy, 1, 0.1) - else - self.happy = math.lerp(self.happy, 0, 0.1) - end + -- Blend to current mood, blend out other moods: local expression = scene.Component_GetExpression(self.expression) - expression.SetPresetWeight(ExpressionPreset.Happy, self.happy) + for i,preset in pairs(Mood) do + local weight = expression.GetPresetWeight(preset) + if preset == self.mood then + weight = math.lerp(weight, self.mood_amount, 0.1) + else + weight = math.lerp(weight, 0, 0.1) + end + expression.SetPresetWeight(preset, weight) + end -- state and animation update - if(self.state == States.IDLE) then - self.current_anim = self.idle_anim - elseif(self.state == States.WALK) then - self.current_anim = self.walk_anim - elseif(self.state == States.JOG) then - self.current_anim = self.jog_anim - elseif(self.state == States.RUN) then - self.current_anim = self.run_anim - elseif(self.state == States.JUMP) then - self.current_anim = self.jump_anim - elseif(self.state == States.SWIM_IDLE) then - self.current_anim = self.swim_idle_anim - elseif(self.state == States.SWIM) then - self.current_anim = self.swim_anim - elseif(self.state == States.DANCE) then - self.current_anim = self.dance_anim - end - - local current_anim = scene.Component_GetAnimation(self.current_anim) + local current_anim = scene.Component_GetAnimation(self.anims[self.state]) if current_anim ~= nil then -- Play current anim: current_anim.Play() @@ -320,7 +526,7 @@ local function Character(model_name, start_position, face, controllable) self.state = States.IDLE end else - if self.velocity.Length() < 0.1 and self.state ~= States.SWIM_IDLE and self.state ~= States.SWIM and self.state ~= States.DANCE then + if self.velocity.Length() < 0.1 and self.state ~= States.SWIM_IDLE and self.state ~= States.SWIM and self.state ~= States.DANCE and self.state ~= States.WAVE then self.state = States.IDLE end end @@ -346,7 +552,7 @@ local function Character(model_name, start_position, face, controllable) end end - if controllable then + if self.controllable then if not backlog_isactive() then -- Movement input: local lookDir = Vector() @@ -388,7 +594,7 @@ local function Character(model_name, start_position, face, controllable) end end - if(input.Press(string.byte('J')) or input.Press(KEYBOARD_BUTTON_SPACE) or input.Press(GAMEPAD_BUTTON_2)) then + if(input.Press(string.byte('J')) or input.Press(KEYBOARD_BUTTON_SPACE) or input.Press(GAMEPAD_BUTTON_3)) then self:Jump(self.jump_speed) end elseif self.velocity.GetY() > 0 then @@ -493,7 +699,7 @@ local function Character(model_name, start_position, face, controllable) -- But the player can still collide with NPC and can be blocked collision_layer = collision_layer & ~Layers.Player end - local current_anim = scene.Component_GetAnimation(self.current_anim) + local current_anim = scene.Component_GetAnimation(self.anims[self.state]) local ground_intersect = false local platform_velocity_accumulation = Vector() local platform_velocity_count = 0 @@ -539,11 +745,11 @@ local function Character(model_name, start_position, face, controllable) -- Animation blending if current_anim ~= nil then -- Blend in current animation: - current_anim.SetAmount(math.lerp(current_anim.GetAmount(), 1, 0.1)) + current_anim.SetAmount(math.lerp(current_anim.GetAmount(), self.anim_amount, 0.1)) -- Ease out other animations: - for i,anim in ipairs(self.all_anims) do - if (anim ~= INVALID_ENTITY) and (anim ~= self.current_anim) then + for i,anim in pairs(self.anims) do + if (anim ~= INVALID_ENTITY) and (anim ~= self.anims[self.state]) then local prev_anim = scene.Component_GetAnimation(anim) prev_anim.SetAmount(math.lerp(prev_anim.GetAmount(), 0, 0.1)) if prev_anim.GetAmount() <= 0 then @@ -552,7 +758,7 @@ local function Character(model_name, start_position, face, controllable) end end end - + end if platform_velocity_count > 0 then @@ -715,6 +921,14 @@ local function Character(model_name, start_position, face, controllable) end end, + Follow = function(self, leader) + self.hired = leader + end, + Unfollow = function(self) + self.hired = nil + self.patrol_waypoints = {} + end, + } self:Create(model_name, start_position, face, controllable) @@ -735,16 +949,12 @@ local ResolveCharacters = function(characterA, characterB) humanoidA.SetLookAt(headB) humanoidB.SetLookAt(headA) - if characterB.controllable then - if input.Press(KEYBOARD_BUTTON_ENTER) then - characterA.hired = characterB - end - - if characterA.hired == nil then - DrawDebugText("Hello there!\nPress ENTER to hire me!", vector.Add(headA, Vector(0,0.4)), Vector(1,0.2,1,1), 0.1, DEBUG_TEXT_DEPTH_TEST | DEBUG_TEXT_CAMERA_FACING) - else - DrawDebugText("Where are we going?", vector.Add(headA, Vector(0,0.4)), Vector(0.2,1,0.2,1), 0.1, DEBUG_TEXT_DEPTH_TEST | DEBUG_TEXT_CAMERA_FACING) + local facing_amount = vector.Dot(characterB.face, vector.Subtract(characterA.position, characterB.position).Normalize()) + if #characterA.dialogs > 0 and conversation.state == ConversationState.Disabled and facing_amount > 0.8 then + if input.Press(KEYBOARD_BUTTON_ENTER) or input.Press(GAMEPAD_BUTTON_2) then + conversation:Enter(characterA) end + DrawDebugText("", vector.Add(headA, Vector(0,0.4)), Vector(1,1,1,1), 0.1, DEBUG_TEXT_DEPTH_TEST | DEBUG_TEXT_CAMERA_FACING) end end @@ -888,10 +1098,6 @@ local function ThirdPersonCamera(character) -- Feed back camera after collision: camera.TransformCamera(camera_transform) camera.UpdateCamera() - - camera.ApertureSize = self.character.happy - camera.FocalLength = vector.Subtract(scene.Component_GetTransform(self.character.head).GetPosition(), camera.GetPosition()).Length() - end, } @@ -943,11 +1149,14 @@ runProcess(function() --application.SetInfoDisplay(false) application.SetFPSDisplay(true) - --path.SetResolutionScale(0.5) + --path.SetResolutionScale(0.75) --path.SetFSR2Enabled(true) --path.SetFSR2Preset(FSR2_Preset.Performance) --SetProfilerEnabled(true) + path.AddFont(conversation.font) + path.AddFont(conversation.advance_font) + while true do player:Update() @@ -978,7 +1187,12 @@ runProcess(function() end end - camera:Update() + conversation:Update(path, scene, player) + player.controllable = not conversation.override_input + + if not conversation.override_input then + camera:Update() + end update() @@ -1021,10 +1235,11 @@ runProcess(function() help_text = help_text .. "WASD/arrows/left analog stick: walk\n" help_text = help_text .. "SHIFT/right shoulder button: walk -> jog\n" help_text = help_text .. "E/left shoulder button: jog -> run\n" - help_text = help_text .. "SPACE/gamepad X/gamepad button 2: Jump\n" + help_text = help_text .. "SPACE/gamepad X/gamepad button 3: Jump\n" help_text = help_text .. "Right Mouse Button/Right thumbstick: rotate camera\n" help_text = help_text .. "Scoll middle mouse/Left-Right triggers: adjust camera distance\n" help_text = help_text .. "ESCAPE key: quit\n" + help_text = help_text .. "ENTER key: interact\n" help_text = help_text .. "R: reload script\n" help_text = help_text .. "H: toggle debug draw\n" help_text = help_text .. "L: toggle framerate lock\n" @@ -1083,7 +1298,64 @@ runProcess(function() end end) +-- Conversation dialogs: +local dialogtree = { + -- Dialog starts here: + {"Hello! Today is a nice day for a walk, isn't it? The sun is shining, the wind blows lightly, and the temperature is just perfect! To be honest, I don't need anything else to be happy."}, + {"I just finished my morning routine and I'm ready for the day. What should I do now...?"}, + { + "Anything I can do for you?", + choices = { + { + "Follow me!", + action = function() + conversation.character:Follow(player) + conversation.character.next_dialog = 4 + end + }, + { + "Never mind.", + action = function() + conversation.character.next_dialog = 5 + end + } + } + }, + -- Dialog 4: When chosen [Follow me] or [Just keep following me] + {"Lead the way!", action_after = function() conversation:Exit() conversation.character.next_dialog = 6 end}, + + -- Dialog 5: When chosen [Never mind] - this also modifies mood (expression) and state (anim) while dialog is playing + { + "Have a nice day!", + action = function() + conversation.character.mood = Mood.Happy + conversation.character.state = States.WAVE + conversation.character.anim_amount = 0.1 + end, + action_after = function() + conversation.character.mood = Mood.Neutral + conversation.character.state = States.IDLE + conversation.character.anim_amount = 1 + conversation:Exit() + conversation.character.next_dialog = 1 + end + }, + + -- Dialog 6: After Dialog 4 finished, so character is following player + { + "Where are we going?", + choices = { + {"Just keep following me.", action = function() conversation.character.next_dialog = 4 end}, + {"Stay here!", action = function() conversation.character:Unfollow() end} + } + }, + {"Gotcha!"}, -- After chosen [Stay here] +} + +for i,npc in pairs(npcs) do + npc.dialogs = dialogtree +end -- Patrol waypoints: diff --git a/Editor/Editor.cpp b/Editor/Editor.cpp index 0cc54d5ca..572d45a08 100644 --- a/Editor/Editor.cpp +++ b/Editor/Editor.cpp @@ -3084,6 +3084,12 @@ void EditorComponent::SaveAs() void EditorComponent::CheckBonePickingEnabled() { + if (optionsWnd.generalWnd.skeletonsVisibleCheckBox.GetCheck()) + { + bone_picking = true; + return; + } + // Check if armature or bone is selected to allow bone picking: // (Don't want to always enable bone picking, because it can make the screen look very busy.) Scene& scene = GetCurrentScene(); diff --git a/Editor/GeneralWindow.cpp b/Editor/GeneralWindow.cpp index a4c563a81..7612b7b1e 100644 --- a/Editor/GeneralWindow.cpp +++ b/Editor/GeneralWindow.cpp @@ -251,6 +251,10 @@ void GeneralWindow::Create(EditorComponent* _editor) }); AddWidget(&bonePickerOpacitySlider); + skeletonsVisibleCheckBox.Create("Skeletons always visible: "); + skeletonsVisibleCheckBox.SetTooltip("Armature skeletons will be always visible, even when not selected."); + AddWidget(&skeletonsVisibleCheckBox); + localizationButton.Create(ICON_LANGUAGE " Create Localization Template"); localizationButton.SetTooltip("Generate a file that can be used to edit localization for the Editor.\nThe template will be created from the currently selected language."); @@ -659,6 +663,7 @@ void GeneralWindow::ResizeLayout() width -= padding * 6; add(transformToolOpacitySlider); add(bonePickerOpacitySlider); + add_right(skeletonsVisibleCheckBox); y += jump; width = prev_width; diff --git a/Editor/GeneralWindow.h b/Editor/GeneralWindow.h index 9311c63f2..cb3195a67 100644 --- a/Editor/GeneralWindow.h +++ b/Editor/GeneralWindow.h @@ -33,6 +33,7 @@ public: wi::gui::Slider transformToolOpacitySlider; wi::gui::Slider bonePickerOpacitySlider; + wi::gui::CheckBox skeletonsVisibleCheckBox; wi::gui::Button localizationButton; diff --git a/Editor/ModelImporter_GLTF.cpp b/Editor/ModelImporter_GLTF.cpp index d517be100..4f9adea3a 100644 --- a/Editor/ModelImporter_GLTF.cpp +++ b/Editor/ModelImporter_GLTF.cpp @@ -1987,6 +1987,14 @@ void Import_Extension_VRM(LoaderState& state) { expression.preset = ExpressionComponent::Preset::Neutral; } + else if (!presetName.compare("SURPRISED")) + { + expression.preset = ExpressionComponent::Preset::Surprised; + } + else if (!wi::helper::toUpper(expression.name).compare("SURPRISED")) // wtf vroid + { + expression.preset = ExpressionComponent::Preset::Surprised; + } const size_t preset_index = (size_t)expression.preset; if (preset_index < arraysize(component.presets)) diff --git a/WickedEngine/wiAudio.cpp b/WickedEngine/wiAudio.cpp index 42caedfa9..c18e22dde 100644 --- a/WickedEngine/wiAudio.cpp +++ b/WickedEngine/wiAudio.cpp @@ -189,7 +189,7 @@ namespace wi::audio WAVEFORMATEX wfx = {}; wi::vector audioData; }; - struct SoundInstanceInternal + struct SoundInstanceInternal : public IXAudio2VoiceCallback { std::shared_ptr audio; std::shared_ptr soundinternal; @@ -198,12 +198,56 @@ namespace wi::audio wi::vector outputMatrix; wi::vector channelAzimuths; XAUDIO2_BUFFER buffer = {}; + bool ended = true; ~SoundInstanceInternal() { sourceVoice->Stop(); sourceVoice->DestroyVoice(); } + + // Called just before this voice's processing pass begins. + STDMETHOD_(void, OnVoiceProcessingPassStart) (THIS_ UINT32 BytesRequired) + { + } + + // Called just after this voice's processing pass ends. + STDMETHOD_(void, OnVoiceProcessingPassEnd) (THIS) + { + } + + // Called when this voice has just finished playing a buffer stream + // (as marked with the XAUDIO2_END_OF_STREAM flag on the last buffer). + STDMETHOD_(void, OnStreamEnd) (THIS) + { + ended = true; + } + + // Called when this voice is about to start processing a new buffer. + STDMETHOD_(void, OnBufferStart) (THIS_ void* pBufferContext) + { + ended = false; + } + + // Called when this voice has just finished processing a buffer. + // The buffer can now be reused or destroyed. + STDMETHOD_(void, OnBufferEnd) (THIS_ void* pBufferContext) + { + } + + // Called when this voice has just reached the end position of a loop. + STDMETHOD_(void, OnLoopEnd) (THIS_ void* pBufferContext) + { + } + + // Called in the event of a critical error during voice processing, + // such as a failing xAPO or an error from the hardware XMA decoder. + // The voice may have to be destroyed and re-created to recover from + // the error. The callback arguments report which buffer was being + // processed when the error occurred, and its HRESULT code. + STDMETHOD_(void, OnVoiceError) (THIS_ void* pBufferContext, HRESULT Error) + { + } }; SoundInternal* to_internal(const Sound* param) { @@ -366,7 +410,7 @@ namespace wi::audio }; hr = instanceinternal->audio->audioEngine->CreateSourceVoice(&instanceinternal->sourceVoice, &soundinternal->wfx, - 0, XAUDIO2_DEFAULT_FREQ_RATIO, NULL, &SFXSendList, NULL); + 0, XAUDIO2_DEFAULT_FREQ_RATIO, instanceinternal.get(), &SFXSendList, NULL); if (FAILED(hr)) { assert(0); @@ -425,8 +469,11 @@ namespace wi::audio assert(SUCCEEDED(hr)); hr = instanceinternal->sourceVoice->FlushSourceBuffers(); // reset submitted audio buffer assert(SUCCEEDED(hr)); - hr = instanceinternal->sourceVoice->SubmitSourceBuffer(&audio_internal->termination_mark); // mark this as terminated, this resets XAUDIO2_VOICE_STATE::SamplesPlayed to zero - assert(SUCCEEDED(hr)); + if (!instanceinternal->ended) // if already ended, don't submit end again, it can cause high pitched jerky sound + { + hr = instanceinternal->sourceVoice->SubmitSourceBuffer(&audio_internal->termination_mark); // mark this as terminated, this resets XAUDIO2_VOICE_STATE::SamplesPlayed to zero + assert(SUCCEEDED(hr)); + } hr = instanceinternal->sourceVoice->SubmitSourceBuffer(&instanceinternal->buffer); // resubmit assert(SUCCEEDED(hr)); } @@ -468,6 +515,15 @@ namespace wi::audio assert(SUCCEEDED(hr)); } } + bool IsEnded(SoundInstance* instance) + { + if (instance != nullptr && instance->IsValid()) + { + auto instanceinternal = to_internal(instance); + return instanceinternal->ended; + } + return false; + } SampleInfo GetSampleInfo(const Sound* sound) { @@ -743,6 +799,7 @@ namespace wi::audio wi::vector outputMatrix; wi::vector channelAzimuths; FAudioBuffer buffer = {}; + bool ended = true; ~SoundInstanceInternal(){ FAudioSourceVoice_Stop(sourceVoice, 0, FAUDIO_COMMIT_NOW); @@ -995,6 +1052,15 @@ namespace wi::audio assert(res == 0); } } + bool IsEnded(SoundInstance* instance) + { + if (instance != nullptr && instance->IsValid()) + { + auto instanceinternal = to_internal(instance); + return instanceinternal->ended; + } + return false; + } SampleInfo GetSampleInfo(const Sound* sound) { diff --git a/WickedEngine/wiAudio.h b/WickedEngine/wiAudio.h index 6f0937262..a744101c8 100644 --- a/WickedEngine/wiAudio.h +++ b/WickedEngine/wiAudio.h @@ -64,6 +64,7 @@ namespace wi::audio void SetVolume(float volume, SoundInstance* instance = nullptr); float GetVolume(const SoundInstance* instance = nullptr); void ExitLoop(SoundInstance* instance); + bool IsEnded(SoundInstance* instance); struct SampleInfo { diff --git a/WickedEngine/wiGraphics.h b/WickedEngine/wiGraphics.h index a5d93ed0c..8fc5a0726 100644 --- a/WickedEngine/wiGraphics.h +++ b/WickedEngine/wiGraphics.h @@ -411,7 +411,7 @@ namespace wi::graphics DEPTH_RESOLVE_MIN_MAX = 1 << 18, STENCIL_RESOLVE_MIN_MAX = 1 << 19, CACHE_COHERENT_UMA = 1 << 20, // https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ns-d3d12-d3d12_feature_data_architecture - VIDEO_DECODE_H264, + VIDEO_DECODE_H264 = 1 << 21, }; enum class ResourceState diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index 94eda74f8..dbcc7fc1a 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -11890,8 +11890,38 @@ void Postprocess_SSR( BindCommonResources(cmd); + int temporal_output = device->GetFrameCount() % 2; + int temporal_history = 1 - temporal_output; + + { + GPUBarrier barriers[] = { + GPUBarrier::Image(&res.texture_tile_minmax_roughness_horizontal, res.texture_tile_minmax_roughness_horizontal.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&res.texture_tile_minmax_roughness, res.texture_tile_minmax_roughness.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Buffer(&res.buffer_tile_tracing_statistics, ResourceState::UNDEFINED, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Buffer(&res.buffer_tiles_tracing_earlyexit, ResourceState::UNDEFINED, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Buffer(&res.buffer_tiles_tracing_cheap, ResourceState::UNDEFINED, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Buffer(&res.buffer_tiles_tracing_expensive, ResourceState::UNDEFINED, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&res.texture_resolve, res.texture_resolve.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&res.texture_resolve_variance, res.texture_resolve_variance.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&res.texture_resolve_reprojectionDepth, res.texture_resolve_reprojectionDepth.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&res.texture_temporal[temporal_output], res.texture_temporal[temporal_output].desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&res.texture_temporal_variance[temporal_output], res.texture_temporal_variance[temporal_output].desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&res.texture_bilateral_temp, res.texture_bilateral_temp.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&output, output.desc.layout, ResourceState::UNORDERED_ACCESS), + }; + device->Barrier(barriers, arraysize(barriers), cmd); + } + + device->ClearUAV(&output, 0, cmd); device->ClearUAV(&res.buffer_tile_tracing_statistics, 0, cmd); + { + GPUBarrier barriers[] = { + GPUBarrier::Memory(), + }; + device->Barrier(barriers, arraysize(barriers), cmd); + } + PostProcess postprocess; ssr_roughness_cutoff = roughnessCutoff; ssr_frame = (float)res.frame; @@ -11906,13 +11936,6 @@ void Postprocess_SSR( }; device->BindUAVs(uavs, 0, arraysize(uavs), cmd); - { - GPUBarrier barriers[] = { - GPUBarrier::Image(&res.texture_tile_minmax_roughness_horizontal, res.texture_tile_minmax_roughness_horizontal.desc.layout, ResourceState::UNORDERED_ACCESS), - }; - device->Barrier(barriers, arraysize(barriers), cmd); - } - device->Dispatch( (res.texture_tile_minmax_roughness_horizontal.GetDesc().width + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, (res.texture_tile_minmax_roughness_horizontal.GetDesc().height + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, @@ -11922,7 +11945,6 @@ void Postprocess_SSR( { GPUBarrier barriers[] = { - GPUBarrier::Memory(), GPUBarrier::Image(&res.texture_tile_minmax_roughness_horizontal, ResourceState::UNORDERED_ACCESS, res.texture_tile_minmax_roughness_horizontal.desc.layout), }; device->Barrier(barriers, arraysize(barriers), cmd); @@ -11951,13 +11973,6 @@ void Postprocess_SSR( }; device->BindUAVs(uavs, 0, arraysize(uavs), cmd); - { - GPUBarrier barriers[] = { - GPUBarrier::Image(&res.texture_tile_minmax_roughness, res.texture_tile_minmax_roughness.desc.layout, ResourceState::UNORDERED_ACCESS), - }; - device->Barrier(barriers, arraysize(barriers), cmd); - } - device->Dispatch( (res.texture_tile_minmax_roughness.GetDesc().width + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, (res.texture_tile_minmax_roughness.GetDesc().height + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, @@ -11967,7 +11982,10 @@ void Postprocess_SSR( { GPUBarrier barriers[] = { - GPUBarrier::Memory(), + GPUBarrier::Memory(&res.buffer_tile_tracing_statistics), + GPUBarrier::Memory(&res.buffer_tiles_tracing_earlyexit), + GPUBarrier::Memory(&res.buffer_tiles_tracing_cheap), + GPUBarrier::Memory(&res.buffer_tiles_tracing_expensive), GPUBarrier::Image(&res.texture_tile_minmax_roughness, ResourceState::UNORDERED_ACCESS, res.texture_tile_minmax_roughness.desc.layout), }; device->Barrier(barriers, arraysize(barriers), cmd); @@ -11991,12 +12009,6 @@ void Postprocess_SSR( device->Dispatch(1, 1, 1, cmd); - GPUBarrier barriers[] = { - GPUBarrier::Memory(), - GPUBarrier::Buffer(&res.buffer_tile_tracing_statistics, ResourceState::UNORDERED_ACCESS, ResourceState::INDIRECT_ARGUMENT), - }; - device->Barrier(barriers, arraysize(barriers), cmd); - device->EventEnd(cmd); } @@ -12070,7 +12082,6 @@ void Postprocess_SSR( { GPUBarrier barriers[] = { - GPUBarrier::Memory(), GPUBarrier::Image(&res.texture_depth_hierarchy, ResourceState::UNORDERED_ACCESS, res.texture_depth_hierarchy.desc.layout, i), }; device->Barrier(barriers, arraysize(barriers), cmd); @@ -12118,6 +12129,7 @@ void Postprocess_SSR( { GPUBarrier barriers[] = { + GPUBarrier::Buffer(&res.buffer_tile_tracing_statistics, ResourceState::UNORDERED_ACCESS, ResourceState::INDIRECT_ARGUMENT), GPUBarrier::Buffer(&res.buffer_tiles_tracing_earlyexit, ResourceState::UNORDERED_ACCESS, ResourceState::SHADER_RESOURCE), GPUBarrier::Buffer(&res.buffer_tiles_tracing_cheap, ResourceState::UNORDERED_ACCESS, ResourceState::SHADER_RESOURCE), GPUBarrier::Buffer(&res.buffer_tiles_tracing_expensive, ResourceState::UNORDERED_ACCESS, ResourceState::SHADER_RESOURCE), @@ -12141,7 +12153,6 @@ void Postprocess_SSR( { GPUBarrier barriers[] = { - GPUBarrier::Memory(), GPUBarrier::Image(&res.texture_rayIndirectSpecular, ResourceState::UNORDERED_ACCESS, res.texture_rayIndirectSpecular.desc.layout), GPUBarrier::Image(&res.texture_rayDirectionPDF, ResourceState::UNORDERED_ACCESS, res.texture_rayDirectionPDF.desc.layout), GPUBarrier::Image(&res.texture_rayLengths, ResourceState::UNORDERED_ACCESS, res.texture_rayLengths.desc.layout), @@ -12178,15 +12189,6 @@ void Postprocess_SSR( }; device->BindUAVs(uavs, 0, arraysize(uavs), cmd); - { - GPUBarrier barriers[] = { - GPUBarrier::Image(&res.texture_resolve, res.texture_resolve.desc.layout, ResourceState::UNORDERED_ACCESS), - GPUBarrier::Image(&res.texture_resolve_variance, res.texture_resolve_variance.desc.layout, ResourceState::UNORDERED_ACCESS), - GPUBarrier::Image(&res.texture_resolve_reprojectionDepth, res.texture_resolve_reprojectionDepth.desc.layout, ResourceState::UNORDERED_ACCESS), - }; - device->Barrier(barriers, arraysize(barriers), cmd); - } - device->Dispatch( (res.texture_resolve.GetDesc().width + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, (res.texture_resolve.GetDesc().height + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, @@ -12207,9 +12209,6 @@ void Postprocess_SSR( device->EventEnd(cmd); } - int temporal_output = device->GetFrameCount() % 2; - int temporal_history = 1 - temporal_output; - // Temporal pass: { device->EventBegin("SSR Temporal pass", cmd); @@ -12231,14 +12230,6 @@ void Postprocess_SSR( }; device->BindUAVs(uavs, 0, arraysize(uavs), cmd); - { - GPUBarrier barriers[] = { - GPUBarrier::Image(&res.texture_temporal[temporal_output], res.texture_temporal[temporal_output].desc.layout, ResourceState::UNORDERED_ACCESS), - GPUBarrier::Image(&res.texture_temporal_variance[temporal_output], res.texture_temporal_variance[temporal_output].desc.layout, ResourceState::UNORDERED_ACCESS), - }; - device->Barrier(barriers, arraysize(barriers), cmd); - } - device->Dispatch( (res.texture_temporal[temporal_output].GetDesc().width + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, (res.texture_temporal[temporal_output].GetDesc().height + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, @@ -12248,7 +12239,6 @@ void Postprocess_SSR( { GPUBarrier barriers[] = { - GPUBarrier::Memory(), GPUBarrier::Image(&res.texture_temporal[temporal_output], ResourceState::UNORDERED_ACCESS, res.texture_temporal[temporal_output].desc.layout), GPUBarrier::Image(&res.texture_temporal_variance[temporal_output], ResourceState::UNORDERED_ACCESS, res.texture_temporal_variance[temporal_output].desc.layout), }; @@ -12280,13 +12270,6 @@ void Postprocess_SSR( }; device->BindUAVs(uavs, 0, arraysize(uavs), cmd); - { - GPUBarrier barriers[] = { - GPUBarrier::Image(&res.texture_bilateral_temp, res.texture_bilateral_temp.desc.layout, ResourceState::UNORDERED_ACCESS), - }; - device->Barrier(barriers, arraysize(barriers), cmd); - } - device->Dispatch( (res.texture_bilateral_temp.GetDesc().width + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, (res.texture_bilateral_temp.GetDesc().height + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, @@ -12296,7 +12279,6 @@ void Postprocess_SSR( { GPUBarrier barriers[] = { - GPUBarrier::Memory(), GPUBarrier::Image(&res.texture_bilateral_temp, ResourceState::UNORDERED_ACCESS, res.texture_bilateral_temp.desc.layout), }; device->Barrier(barriers, arraysize(barriers), cmd); @@ -12320,13 +12302,6 @@ void Postprocess_SSR( }; device->BindUAVs(uavs, 0, arraysize(uavs), cmd); - { - GPUBarrier barriers[] = { - GPUBarrier::Image(&output, output.desc.layout, ResourceState::UNORDERED_ACCESS), - }; - device->Barrier(barriers, arraysize(barriers), cmd); - } - device->Dispatch( (output.GetDesc().width + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, (output.GetDesc().height + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, @@ -12336,7 +12311,6 @@ void Postprocess_SSR( { GPUBarrier barriers[] = { - GPUBarrier::Memory(), GPUBarrier::Image(&output, ResourceState::UNORDERED_ACCESS, output.desc.layout), }; device->Barrier(barriers, arraysize(barriers), cmd); @@ -12989,8 +12963,49 @@ void Postprocess_DepthOfField( device->EventBegin("Postprocess_DepthOfField", cmd); auto range = wi::profiler::BeginRangeGPU("Depth of Field", cmd); + { + GPUBarrier barriers[] = { + GPUBarrier::Image(&res.texture_tilemax_horizontal, res.texture_tilemax_horizontal.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&res.texture_tilemin_horizontal, res.texture_tilemin_horizontal.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&res.texture_tilemax, res.texture_tilemax.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&res.texture_tilemin, res.texture_tilemin.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&res.texture_neighborhoodmax, res.texture_neighborhoodmax.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&res.texture_presort, res.texture_presort.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&res.texture_prefilter, res.texture_prefilter.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&res.texture_main, res.texture_main.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&res.texture_alpha1, res.texture_alpha1.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&res.texture_postfilter, res.texture_postfilter.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&res.texture_alpha2, res.texture_alpha2.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&output, output.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Buffer(&res.buffer_tile_statistics, ResourceState::UNDEFINED, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Buffer(&res.buffer_tiles_earlyexit, ResourceState::UNDEFINED, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Buffer(&res.buffer_tiles_cheap, ResourceState::UNDEFINED, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Buffer(&res.buffer_tiles_expensive, ResourceState::UNDEFINED, ResourceState::UNORDERED_ACCESS), + }; + device->Barrier(barriers, arraysize(barriers), cmd); + } + + device->ClearUAV(&res.texture_tilemax_horizontal, 0, cmd); + device->ClearUAV(&res.texture_tilemin_horizontal, 0, cmd); + device->ClearUAV(&res.texture_tilemax, 0, cmd); + device->ClearUAV(&res.texture_tilemin, 0, cmd); + device->ClearUAV(&res.texture_neighborhoodmax, 0, cmd); + device->ClearUAV(&res.texture_presort, 0, cmd); + device->ClearUAV(&res.texture_prefilter, 0, cmd); + device->ClearUAV(&res.texture_main, 0, cmd); + device->ClearUAV(&res.texture_alpha1, 0, cmd); + device->ClearUAV(&res.texture_postfilter, 0, cmd); + device->ClearUAV(&res.texture_alpha2, 0, cmd); + device->ClearUAV(&output, 0, cmd); device->ClearUAV(&res.buffer_tile_statistics, 0, cmd); + { + GPUBarrier barriers[] = { + GPUBarrier::Memory(), + }; + device->Barrier(barriers, arraysize(barriers), cmd); + } + const TextureDesc& desc = output.GetDesc(); PostProcess postprocess; @@ -13013,14 +13028,6 @@ void Postprocess_DepthOfField( }; device->BindUAVs(uavs, 0, arraysize(uavs), cmd); - { - GPUBarrier barriers[] = { - GPUBarrier::Image(&res.texture_tilemax_horizontal, res.texture_tilemax_horizontal.desc.layout, ResourceState::UNORDERED_ACCESS), - GPUBarrier::Image(&res.texture_tilemin_horizontal, res.texture_tilemin_horizontal.desc.layout, ResourceState::UNORDERED_ACCESS), - }; - device->Barrier(barriers, arraysize(barriers), cmd); - } - device->PushConstants(&postprocess, sizeof(postprocess), cmd); device->Dispatch( (res.texture_tilemax_horizontal.GetDesc().width + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, @@ -13031,7 +13038,6 @@ void Postprocess_DepthOfField( { GPUBarrier barriers[] = { - GPUBarrier::Memory(), GPUBarrier::Image(&res.texture_tilemax_horizontal, ResourceState::UNORDERED_ACCESS, res.texture_tilemax_horizontal.desc.layout), GPUBarrier::Image(&res.texture_tilemin_horizontal, ResourceState::UNORDERED_ACCESS, res.texture_tilemin_horizontal.desc.layout), }; @@ -13058,14 +13064,6 @@ void Postprocess_DepthOfField( }; device->BindUAVs(uavs, 0, arraysize(uavs), cmd); - { - GPUBarrier barriers[] = { - GPUBarrier::Image(&res.texture_tilemax, res.texture_tilemax.desc.layout, ResourceState::UNORDERED_ACCESS), - GPUBarrier::Image(&res.texture_tilemin, res.texture_tilemin.desc.layout, ResourceState::UNORDERED_ACCESS), - }; - device->Barrier(barriers, arraysize(barriers), cmd); - } - device->Dispatch( (res.texture_tilemax.GetDesc().width + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, (res.texture_tilemax.GetDesc().height + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, @@ -13075,7 +13073,6 @@ void Postprocess_DepthOfField( { GPUBarrier barriers[] = { - GPUBarrier::Memory(), GPUBarrier::Image(&res.texture_tilemax, ResourceState::UNORDERED_ACCESS, res.texture_tilemax.desc.layout), GPUBarrier::Image(&res.texture_tilemin, ResourceState::UNORDERED_ACCESS, res.texture_tilemin.desc.layout), }; @@ -13105,13 +13102,6 @@ void Postprocess_DepthOfField( }; device->BindUAVs(uavs, 0, arraysize(uavs), cmd); - { - GPUBarrier barriers[] = { - GPUBarrier::Image(&res.texture_neighborhoodmax, res.texture_neighborhoodmax.desc.layout, ResourceState::UNORDERED_ACCESS), - }; - device->Barrier(barriers, arraysize(barriers), cmd); - } - device->Dispatch( (res.texture_neighborhoodmax.GetDesc().width + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, (res.texture_neighborhoodmax.GetDesc().height + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, @@ -13121,7 +13111,10 @@ void Postprocess_DepthOfField( { GPUBarrier barriers[] = { - GPUBarrier::Memory(), + GPUBarrier::Memory(&res.buffer_tile_statistics), + GPUBarrier::Memory(&res.buffer_tiles_earlyexit), + GPUBarrier::Memory(&res.buffer_tiles_cheap), + GPUBarrier::Memory(&res.buffer_tiles_expensive), GPUBarrier::Image(&res.texture_neighborhoodmax, ResourceState::UNORDERED_ACCESS, res.texture_neighborhoodmax.desc.layout), }; device->Barrier(barriers, arraysize(barriers), cmd); @@ -13148,8 +13141,10 @@ void Postprocess_DepthOfField( device->Dispatch(1, 1, 1, cmd); GPUBarrier barriers[] = { - GPUBarrier::Memory(), GPUBarrier::Buffer(&res.buffer_tile_statistics, ResourceState::UNORDERED_ACCESS, ResourceState::INDIRECT_ARGUMENT), + GPUBarrier::Buffer(&res.buffer_tiles_earlyexit, ResourceState::UNORDERED_ACCESS, ResourceState::SHADER_RESOURCE), + GPUBarrier::Buffer(&res.buffer_tiles_cheap, ResourceState::UNORDERED_ACCESS, ResourceState::SHADER_RESOURCE), + GPUBarrier::Buffer(&res.buffer_tiles_expensive, ResourceState::UNORDERED_ACCESS, ResourceState::SHADER_RESOURCE), }; device->Barrier(barriers, arraysize(barriers), cmd); @@ -13178,17 +13173,6 @@ void Postprocess_DepthOfField( }; device->BindUAVs(uavs, 0, arraysize(uavs), cmd); - { - GPUBarrier barriers[] = { - GPUBarrier::Buffer(&res.buffer_tiles_earlyexit, ResourceState::UNORDERED_ACCESS, ResourceState::SHADER_RESOURCE), - GPUBarrier::Buffer(&res.buffer_tiles_cheap, ResourceState::UNORDERED_ACCESS, ResourceState::SHADER_RESOURCE), - GPUBarrier::Buffer(&res.buffer_tiles_expensive, ResourceState::UNORDERED_ACCESS, ResourceState::SHADER_RESOURCE), - GPUBarrier::Image(&res.texture_presort, res.texture_presort.desc.layout, ResourceState::UNORDERED_ACCESS), - GPUBarrier::Image(&res.texture_prefilter, res.texture_prefilter.desc.layout, ResourceState::UNORDERED_ACCESS), - }; - device->Barrier(barriers, arraysize(barriers), cmd); - } - device->BindResource(&res.buffer_tiles_earlyexit, 2, cmd); device->BindComputeShader(&shaders[CSTYPE_POSTPROCESS_DEPTHOFFIELD_PREPASS_EARLYEXIT], cmd); device->PushConstants(&postprocess, sizeof(postprocess), cmd); @@ -13206,7 +13190,6 @@ void Postprocess_DepthOfField( { GPUBarrier barriers[] = { - GPUBarrier::Memory(), GPUBarrier::Image(&res.texture_presort, ResourceState::UNORDERED_ACCESS, res.texture_presort.desc.layout), GPUBarrier::Image(&res.texture_prefilter, ResourceState::UNORDERED_ACCESS, res.texture_prefilter.desc.layout), }; @@ -13236,14 +13219,6 @@ void Postprocess_DepthOfField( }; device->BindUAVs(uavs, 0, arraysize(uavs), cmd); - { - GPUBarrier barriers[] = { - GPUBarrier::Image(&res.texture_main, res.texture_main.desc.layout, ResourceState::UNORDERED_ACCESS), - GPUBarrier::Image(&res.texture_alpha1, res.texture_alpha1.desc.layout, ResourceState::UNORDERED_ACCESS), - }; - device->Barrier(barriers, arraysize(barriers), cmd); - } - device->BindComputeShader(&shaders[CSTYPE_POSTPROCESS_DEPTHOFFIELD_MAIN_EARLYEXIT], cmd); device->DispatchIndirect(&res.buffer_tile_statistics, INDIRECT_OFFSET_EARLYEXIT, cmd); @@ -13257,7 +13232,6 @@ void Postprocess_DepthOfField( { GPUBarrier barriers[] = { - GPUBarrier::Memory(), GPUBarrier::Image(&res.texture_main, ResourceState::UNORDERED_ACCESS, res.texture_main.desc.layout), GPUBarrier::Image(&res.texture_alpha1, ResourceState::UNORDERED_ACCESS, res.texture_alpha1.desc.layout), }; @@ -13284,14 +13258,6 @@ void Postprocess_DepthOfField( }; device->BindUAVs(uavs, 0, arraysize(uavs), cmd); - { - GPUBarrier barriers[] = { - GPUBarrier::Image(&res.texture_postfilter, res.texture_postfilter.desc.layout, ResourceState::UNORDERED_ACCESS), - GPUBarrier::Image(&res.texture_alpha2, res.texture_alpha2.desc.layout, ResourceState::UNORDERED_ACCESS), - }; - device->Barrier(barriers, arraysize(barriers), cmd); - } - device->Dispatch( (res.texture_postfilter.GetDesc().width + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, (res.texture_postfilter.GetDesc().height + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, @@ -13301,7 +13267,6 @@ void Postprocess_DepthOfField( { GPUBarrier barriers[] = { - GPUBarrier::Memory(), GPUBarrier::Image(&res.texture_postfilter, ResourceState::UNORDERED_ACCESS, res.texture_postfilter.desc.layout), GPUBarrier::Image(&res.texture_alpha2, ResourceState::UNORDERED_ACCESS, res.texture_alpha2.desc.layout), }; @@ -13336,13 +13301,6 @@ void Postprocess_DepthOfField( }; device->BindUAVs(uavs, 0, arraysize(uavs), cmd); - { - GPUBarrier barriers[] = { - GPUBarrier::Image(&output, output.desc.layout, ResourceState::UNORDERED_ACCESS), - }; - device->Barrier(barriers, arraysize(barriers), cmd); - } - device->Dispatch( (desc.width + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, (desc.height + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, @@ -13352,7 +13310,6 @@ void Postprocess_DepthOfField( { GPUBarrier barriers[] = { - GPUBarrier::Memory(), GPUBarrier::Image(&output, ResourceState::UNORDERED_ACCESS, output.desc.layout), }; device->Barrier(barriers, arraysize(barriers), cmd); @@ -13441,8 +13398,37 @@ void Postprocess_MotionBlur( const TextureDesc& desc = output.GetDesc(); + { + GPUBarrier barriers[] = { + GPUBarrier::Image(&res.texture_tilemax_horizontal, res.texture_tilemax_horizontal.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&res.texture_tilemin_horizontal, res.texture_tilemin_horizontal.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&res.texture_tilemax, res.texture_tilemax.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&res.texture_tilemin, res.texture_tilemin.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&res.texture_neighborhoodmax, res.texture_neighborhoodmax.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&output, output.desc.layout, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Buffer(&res.buffer_tile_statistics, ResourceState::UNDEFINED, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Buffer(&res.buffer_tiles_earlyexit, ResourceState::UNDEFINED, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Buffer(&res.buffer_tiles_cheap, ResourceState::UNDEFINED, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Buffer(&res.buffer_tiles_expensive, ResourceState::UNDEFINED, ResourceState::UNORDERED_ACCESS), + }; + device->Barrier(barriers, arraysize(barriers), cmd); + } + + device->ClearUAV(&res.texture_tilemax_horizontal, 0, cmd); + device->ClearUAV(&res.texture_tilemin_horizontal, 0, cmd); + device->ClearUAV(&res.texture_tilemax, 0, cmd); + device->ClearUAV(&res.texture_tilemin, 0, cmd); + device->ClearUAV(&res.texture_neighborhoodmax, 0, cmd); + device->ClearUAV(&output, 0, cmd); device->ClearUAV(&res.buffer_tile_statistics, 0, cmd); + { + GPUBarrier barriers[] = { + GPUBarrier::Memory(), + }; + device->Barrier(barriers, arraysize(barriers), cmd); + } + PostProcess postprocess; postprocess.resolution.x = desc.width; postprocess.resolution.y = desc.height; @@ -13461,14 +13447,6 @@ void Postprocess_MotionBlur( }; device->BindUAVs(uavs, 0, arraysize(uavs), cmd); - { - GPUBarrier barriers[] = { - GPUBarrier::Image(&res.texture_tilemax_horizontal, res.texture_tilemax_horizontal.desc.layout, ResourceState::UNORDERED_ACCESS), - GPUBarrier::Image(&res.texture_tilemin_horizontal, res.texture_tilemin_horizontal.desc.layout, ResourceState::UNORDERED_ACCESS), - }; - device->Barrier(barriers, arraysize(barriers), cmd); - } - device->PushConstants(&postprocess, sizeof(postprocess), cmd); device->Dispatch( (res.texture_tilemax_horizontal.GetDesc().width + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, @@ -13479,7 +13457,6 @@ void Postprocess_MotionBlur( { GPUBarrier barriers[] = { - GPUBarrier::Memory(), GPUBarrier::Image(&res.texture_tilemax_horizontal, ResourceState::UNORDERED_ACCESS, res.texture_tilemax_horizontal.desc.layout), GPUBarrier::Image(&res.texture_tilemin_horizontal, ResourceState::UNORDERED_ACCESS, res.texture_tilemin_horizontal.desc.layout), }; @@ -13503,14 +13480,6 @@ void Postprocess_MotionBlur( }; device->BindUAVs(uavs, 0, arraysize(uavs), cmd); - { - GPUBarrier barriers[] = { - GPUBarrier::Image(&res.texture_tilemax, res.texture_tilemax.desc.layout, ResourceState::UNORDERED_ACCESS), - GPUBarrier::Image(&res.texture_tilemin, res.texture_tilemin.desc.layout, ResourceState::UNORDERED_ACCESS), - }; - device->Barrier(barriers, arraysize(barriers), cmd); - } - device->Dispatch( (res.texture_tilemax.GetDesc().width + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, (res.texture_tilemax.GetDesc().height + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, @@ -13520,7 +13489,6 @@ void Postprocess_MotionBlur( { GPUBarrier barriers[] = { - GPUBarrier::Memory(), GPUBarrier::Image(&res.texture_tilemax, ResourceState::UNORDERED_ACCESS, res.texture_tilemax.desc.layout), GPUBarrier::Image(&res.texture_tilemin, ResourceState::UNORDERED_ACCESS, res.texture_tilemin.desc.layout), }; @@ -13550,13 +13518,6 @@ void Postprocess_MotionBlur( }; device->BindUAVs(uavs, 0, arraysize(uavs), cmd); - { - GPUBarrier barriers[] = { - GPUBarrier::Image(&res.texture_neighborhoodmax, res.texture_neighborhoodmax.desc.layout, ResourceState::UNORDERED_ACCESS), - }; - device->Barrier(barriers, arraysize(barriers), cmd); - } - device->Dispatch( (res.texture_neighborhoodmax.GetDesc().width + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, (res.texture_neighborhoodmax.GetDesc().height + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, @@ -13566,7 +13527,10 @@ void Postprocess_MotionBlur( { GPUBarrier barriers[] = { - GPUBarrier::Memory(), + GPUBarrier::Memory(&res.buffer_tile_statistics), + GPUBarrier::Memory(&res.buffer_tiles_earlyexit), + GPUBarrier::Memory(&res.buffer_tiles_cheap), + GPUBarrier::Memory(&res.buffer_tiles_expensive), GPUBarrier::Image(&res.texture_neighborhoodmax, ResourceState::UNORDERED_ACCESS, res.texture_neighborhoodmax.desc.layout), }; device->Barrier(barriers, arraysize(barriers), cmd); @@ -13593,8 +13557,10 @@ void Postprocess_MotionBlur( device->Dispatch(1, 1, 1, cmd); GPUBarrier barriers[] = { - GPUBarrier::Memory(), GPUBarrier::Buffer(&res.buffer_tile_statistics, ResourceState::UNORDERED_ACCESS, ResourceState::INDIRECT_ARGUMENT), + GPUBarrier::Buffer(&res.buffer_tiles_earlyexit, ResourceState::UNORDERED_ACCESS, ResourceState::SHADER_RESOURCE), + GPUBarrier::Buffer(&res.buffer_tiles_cheap, ResourceState::UNORDERED_ACCESS, ResourceState::SHADER_RESOURCE), + GPUBarrier::Buffer(&res.buffer_tiles_expensive, ResourceState::UNORDERED_ACCESS, ResourceState::SHADER_RESOURCE), }; device->Barrier(barriers, arraysize(barriers), cmd); @@ -13619,16 +13585,6 @@ void Postprocess_MotionBlur( }; device->BindUAVs(uavs, 0, arraysize(uavs), cmd); - { - GPUBarrier barriers[] = { - GPUBarrier::Buffer(&res.buffer_tiles_earlyexit, ResourceState::UNORDERED_ACCESS, ResourceState::SHADER_RESOURCE), - GPUBarrier::Buffer(&res.buffer_tiles_cheap, ResourceState::UNORDERED_ACCESS, ResourceState::SHADER_RESOURCE), - GPUBarrier::Buffer(&res.buffer_tiles_expensive, ResourceState::UNORDERED_ACCESS, ResourceState::SHADER_RESOURCE), - GPUBarrier::Image(&output, output.desc.layout, ResourceState::UNORDERED_ACCESS), - }; - device->Barrier(barriers, arraysize(barriers), cmd); - } - device->BindComputeShader(&shaders[CSTYPE_POSTPROCESS_MOTIONBLUR_EARLYEXIT], cmd); device->DispatchIndirect(&res.buffer_tile_statistics, INDIRECT_OFFSET_EARLYEXIT, cmd); @@ -13642,7 +13598,6 @@ void Postprocess_MotionBlur( { GPUBarrier barriers[] = { - GPUBarrier::Memory(), GPUBarrier::Image(&output, ResourceState::UNORDERED_ACCESS, output.desc.layout), }; device->Barrier(barriers, arraysize(barriers), cmd); diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index 7cc017209..2f13e62c5 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -60,7 +60,7 @@ namespace wi::scene impostorInstanceOffset = uint32_t(instanceArraySize); instanceArraySize += 1; } - if (instanceBuffer.desc.size < (instanceArraySize * sizeof(ShaderMeshInstance))) + if (instanceUploadBuffer[0].desc.size < (instanceArraySize * sizeof(ShaderMeshInstance))) { GPUBufferDesc desc; desc.stride = sizeof(ShaderMeshInstance); @@ -93,7 +93,7 @@ namespace wi::scene impostorMaterialOffset = uint32_t(materialArraySize); materialArraySize += 1; } - if (materialBuffer.desc.size < (materialArraySize * sizeof(ShaderMaterial))) + if (materialUploadBuffer[0].desc.size < (materialArraySize * sizeof(ShaderMaterial))) { GPUBufferDesc desc; desc.stride = sizeof(ShaderMaterial); @@ -241,7 +241,7 @@ namespace wi::scene impostorGeometryOffset = uint32_t(geometryArraySize); geometryArraySize += 1; } - if (geometryBuffer.desc.size < (geometryArraySize * sizeof(ShaderGeometry))) + if (geometryUploadBuffer[0].desc.size < (geometryArraySize * sizeof(ShaderGeometry))) { GPUBufferDesc desc; desc.stride = sizeof(ShaderGeometry); diff --git a/WickedEngine/wiScene_BindLua.cpp b/WickedEngine/wiScene_BindLua.cpp index a23152118..b982b2efb 100644 --- a/WickedEngine/wiScene_BindLua.cpp +++ b/WickedEngine/wiScene_BindLua.cpp @@ -361,6 +361,12 @@ ExpressionPreset = { Neutral = 17, } +ExpressionOverride = { + None = 0, + Block = 1, + Blend = 2, +} + HumanoidBone = { Hips = 0, Spine = 1, @@ -3113,14 +3119,18 @@ int CameraComponent_BindLua::TransformCamera(lua_State* L) component->TransformCamera(*transform->component); return 0; } - else + Matrix_BindLua* matrix = Luna::lightcheck(L, 1); + if (matrix != nullptr) { - wi::lua::SError(L, "TransformCamera(TransformComponent transform) invalid argument!"); + component->TransformCamera(XMLoadFloat4x4(&matrix->data)); + return 0; } + + wi::lua::SError(L, "TransformCamera(TransformComponent | Matrix transform) invalid argument!"); } else { - wi::lua::SError(L, "TransformCamera(TransformComponent transform) not enough arguments!"); + wi::lua::SError(L, "TransformCamera(TransformComponent | Matrix transform) not enough arguments!"); } return 0; } @@ -5607,6 +5617,12 @@ Luna::FunctionType ExpressionComponent_BindLua::met lunamethod(ExpressionComponent_BindLua, GetPresetWeight), lunamethod(ExpressionComponent_BindLua, SetForceTalkingEnabled), lunamethod(ExpressionComponent_BindLua, IsForceTalkingEnabled), + lunamethod(ExpressionComponent_BindLua, SetPresetOverrideMouth), + lunamethod(ExpressionComponent_BindLua, SetPresetOverrideBlink), + lunamethod(ExpressionComponent_BindLua, SetPresetOverrideLook), + lunamethod(ExpressionComponent_BindLua, SetOverrideMouth), + lunamethod(ExpressionComponent_BindLua, SetOverrideBlink), + lunamethod(ExpressionComponent_BindLua, SetOverrideLook), { NULL, NULL } }; Luna::PropertyType ExpressionComponent_BindLua::properties[] = { @@ -5688,6 +5704,7 @@ int ExpressionComponent_BindLua::GetWeight(lua_State* L) if (id >= 0 && component->expressions.size() > id) { wi::lua::SSetFloat(L, component->expressions[id].weight); + return 1; } else { @@ -5710,6 +5727,7 @@ int ExpressionComponent_BindLua::GetPresetWeight(lua_State* L) if (id >= 0 && component->expressions.size() > id) { wi::lua::SSetFloat(L, component->expressions[id].weight); + return 1; } else { @@ -5741,6 +5759,142 @@ int ExpressionComponent_BindLua::IsForceTalkingEnabled(lua_State* L) return 1; } +int ExpressionComponent_BindLua::SetPresetOverrideMouth(lua_State* L) +{ + int argc = wi::lua::SGetArgCount(L); + if (argc > 1) + { + ExpressionComponent::Preset preset = (ExpressionComponent::Preset)wi::lua::SGetInt(L, 1); + ExpressionComponent::Override value = (ExpressionComponent::Override)wi::lua::SGetInt(L, 2); + int id = component->presets[size_t(preset)]; + if (id >= 0 && component->expressions.size() > id) + { + component->expressions[id].override_mouth = value; + } + else + { + wi::lua::SError(L, "SetPresetOverrideMouth(ExpressionPreset preset, ExpressionOverride override) preset doesn't exist!"); + } + } + else + { + wi::lua::SError(L, "SetPresetOverrideMouth(ExpressionPreset preset, ExpressionOverride override) not enough arguments!"); + } + return 0; +} +int ExpressionComponent_BindLua::SetPresetOverrideBlink(lua_State* L) +{ + int argc = wi::lua::SGetArgCount(L); + if (argc > 1) + { + ExpressionComponent::Preset preset = (ExpressionComponent::Preset)wi::lua::SGetInt(L, 1); + ExpressionComponent::Override value = (ExpressionComponent::Override)wi::lua::SGetInt(L, 2); + int id = component->presets[size_t(preset)]; + if (id >= 0 && component->expressions.size() > id) + { + component->expressions[id].override_blink = value; + } + else + { + wi::lua::SError(L, "SetPresetOverrideBlink(ExpressionPreset preset, ExpressionOverride override) preset doesn't exist!"); + } + } + else + { + wi::lua::SError(L, "SetPresetOverrideBlink(ExpressionPreset preset, ExpressionOverride override) not enough arguments!"); + } + return 0; +} +int ExpressionComponent_BindLua::SetPresetOverrideLook(lua_State* L) +{ + int argc = wi::lua::SGetArgCount(L); + if (argc > 1) + { + ExpressionComponent::Preset preset = (ExpressionComponent::Preset)wi::lua::SGetInt(L, 1); + ExpressionComponent::Override value = (ExpressionComponent::Override)wi::lua::SGetInt(L, 2); + int id = component->presets[size_t(preset)]; + if (id >= 0 && component->expressions.size() > id) + { + component->expressions[id].override_look = value; + } + else + { + wi::lua::SError(L, "SetPresetOverrideLook(ExpressionPreset preset, ExpressionOverride override) preset doesn't exist!"); + } + } + else + { + wi::lua::SError(L, "SetPresetOverrideLook(ExpressionPreset preset, ExpressionOverride override) not enough arguments!"); + } + return 0; +} +int ExpressionComponent_BindLua::SetOverrideMouth(lua_State* L) +{ + int argc = wi::lua::SGetArgCount(L); + if (argc > 1) + { + int id = wi::lua::SGetInt(L, 1); + ExpressionComponent::Override value = (ExpressionComponent::Override)wi::lua::SGetInt(L, 2); + if (id >= 0 && component->expressions.size() > id) + { + component->expressions[id].override_mouth = value; + } + else + { + wi::lua::SError(L, "SetOverrideMouth(int id, ExpressionOverride override) id is out of bounds!"); + } + } + else + { + wi::lua::SError(L, "SetOverrideMouth(int id, ExpressionOverride override) not enough arguments!"); + } + return 0; +} +int ExpressionComponent_BindLua::SetOverrideBlink(lua_State* L) +{ + int argc = wi::lua::SGetArgCount(L); + if (argc > 1) + { + int id = wi::lua::SGetInt(L, 1); + ExpressionComponent::Override value = (ExpressionComponent::Override)wi::lua::SGetInt(L, 2); + if (id >= 0 && component->expressions.size() > id) + { + component->expressions[id].override_blink = value; + } + else + { + wi::lua::SError(L, "SetOverrideBlink(int id, ExpressionOverride override) id is out of bounds!"); + } + } + else + { + wi::lua::SError(L, "SetOverrideBlink(int id, ExpressionOverride override) not enough arguments!"); + } + return 0; +} +int ExpressionComponent_BindLua::SetOverrideLook(lua_State* L) +{ + int argc = wi::lua::SGetArgCount(L); + if (argc > 1) + { + int id = wi::lua::SGetInt(L, 1); + ExpressionComponent::Override value = (ExpressionComponent::Override)wi::lua::SGetInt(L, 2); + if (id >= 0 && component->expressions.size() > id) + { + component->expressions[id].override_look = value; + } + else + { + wi::lua::SError(L, "SetOverrideLook(int id, ExpressionOverride override) id is out of bounds!"); + } + } + else + { + wi::lua::SError(L, "SetOverrideLook(int id, ExpressionOverride override) not enough arguments!"); + } + return 0; +} + diff --git a/WickedEngine/wiScene_BindLua.h b/WickedEngine/wiScene_BindLua.h index 62739e67f..4f1811977 100644 --- a/WickedEngine/wiScene_BindLua.h +++ b/WickedEngine/wiScene_BindLua.h @@ -1650,6 +1650,13 @@ namespace wi::lua::scene int GetPresetWeight(lua_State* L); int SetForceTalkingEnabled(lua_State* L); int IsForceTalkingEnabled(lua_State* L); + + int SetPresetOverrideMouth(lua_State* L); + int SetPresetOverrideBlink(lua_State* L); + int SetPresetOverrideLook(lua_State* L); + int SetOverrideMouth(lua_State* L); + int SetOverrideBlink(lua_State* L); + int SetOverrideLook(lua_State* L); }; class HumanoidComponent_BindLua diff --git a/WickedEngine/wiScene_Components.cpp b/WickedEngine/wiScene_Components.cpp index 74d7015d0..dd242a0e3 100644 --- a/WickedEngine/wiScene_Components.cpp +++ b/WickedEngine/wiScene_Components.cpp @@ -1600,10 +1600,8 @@ namespace wi::scene frustum.Create(_VP); } - void CameraComponent::TransformCamera(const TransformComponent& transform) + void CameraComponent::TransformCamera(const XMMATRIX& W) { - XMMATRIX W = XMLoadFloat4x4(&transform.world); - XMVECTOR _Eye = XMVector3Transform(XMVectorSet(0, 0, 0, 1), W); XMVECTOR _At = XMVector3Normalize(XMVector3TransformNormal(XMVectorSet(0, 0, 1, 0), W)); XMVECTOR _Up = XMVector3Normalize(XMVector3TransformNormal(XMVectorSet(0, 1, 0, 0), W)); diff --git a/WickedEngine/wiScene_Components.h b/WickedEngine/wiScene_Components.h index ac842c837..53722c947 100644 --- a/WickedEngine/wiScene_Components.h +++ b/WickedEngine/wiScene_Components.h @@ -968,7 +968,8 @@ namespace wi::scene void CreatePerspective(float newWidth, float newHeight, float newNear, float newFar, float newFOV = XM_PI / 3.0f); void UpdateCamera(); - void TransformCamera(const TransformComponent& transform); + void TransformCamera(const XMMATRIX& W); + void TransformCamera(const TransformComponent& transform) { TransformCamera(XMLoadFloat4x4(&transform.world)); } void Reflect(const XMFLOAT4& plane = XMFLOAT4(0, 1, 0, 0)); inline XMVECTOR GetEye() const { return XMLoadFloat3(&Eye); } diff --git a/WickedEngine/wiScene_Serializers.cpp b/WickedEngine/wiScene_Serializers.cpp index 7ffa98aef..204156663 100644 --- a/WickedEngine/wiScene_Serializers.cpp +++ b/WickedEngine/wiScene_Serializers.cpp @@ -1825,6 +1825,12 @@ namespace wi::scene { Expression& expression = expressions[expression_index]; archive >> expression.name; + if (expression.preset == ExpressionComponent::Preset::Count && expression.name.compare("Surprised") == 0) + { + // Vroid was not exporting Suprised expression properly and it was not handled at import for some models: + expression.preset = ExpressionComponent::Preset::Surprised; + presets[size_t(ExpressionComponent::Preset::Surprised)] = int(expression_index); + } archive >> expression.weight; uint32_t value = 0; diff --git a/WickedEngine/wiSpriteFont.cpp b/WickedEngine/wiSpriteFont.cpp index bd6bbc6e9..fc74e3a03 100644 --- a/WickedEngine/wiSpriteFont.cpp +++ b/WickedEngine/wiSpriteFont.cpp @@ -18,7 +18,24 @@ namespace wi if (anim.typewriter.time > 0) { + size_t text_length = text.length(); + size_t text_length_prev = std::min(text_length, size_t(wi::math::Lerp(float(std::min(text_length, anim.typewriter.character_start)), float(text_length + 1), anim.typewriter.elapsed / anim.typewriter.time))); anim.typewriter.elapsed += dt; + size_t text_length_next = std::min(text_length, size_t(wi::math::Lerp(float(std::min(text_length, anim.typewriter.character_start)), float(text_length + 1), anim.typewriter.elapsed / anim.typewriter.time))); + + if (anim.typewriter.soundinstance.IsValid()) + { + if (!anim.typewriter.IsFinished() && wi::audio::IsEnded(&anim.typewriter.soundinstance) && text_length_prev != text_length_next && text[text_length_next - 1] != ' ' && anim.typewriter.soundinstance.IsValid()) + { + wi::audio::Stop(&anim.typewriter.soundinstance); + if (!IsHidden()) + { + wi::audio::Play(&anim.typewriter.soundinstance); + } + } + wi::audio::ExitLoop(&anim.typewriter.soundinstance); + } + if (anim.typewriter.looped && anim.typewriter.elapsed > anim.typewriter.time) { anim.typewriter.reset(); diff --git a/WickedEngine/wiSpriteFont.h b/WickedEngine/wiSpriteFont.h index fe6433755..37441f701 100644 --- a/WickedEngine/wiSpriteFont.h +++ b/WickedEngine/wiSpriteFont.h @@ -1,5 +1,6 @@ #pragma once #include "wiFont.h" +#include "wiAudio.h" #include @@ -53,6 +54,8 @@ namespace wi float time = 0; // time to fully type the text in seconds (0: disable) bool looped = false; // if true, typing starts over when finished size_t character_start = 0; // starting character for the animation + wi::audio::Sound sound; + wi::audio::SoundInstance soundinstance; float elapsed = 0; // internal use; you don't need to initialize @@ -60,6 +63,14 @@ namespace wi { elapsed = 0; } + void Finish() + { + elapsed = time; + } + bool IsFinished() const + { + return time <= elapsed; + } } typewriter; } anim; }; diff --git a/WickedEngine/wiSpriteFont_BindLua.cpp b/WickedEngine/wiSpriteFont_BindLua.cpp index c48b42b32..adb9e161f 100644 --- a/WickedEngine/wiSpriteFont_BindLua.cpp +++ b/WickedEngine/wiSpriteFont_BindLua.cpp @@ -1,6 +1,7 @@ #include "wiSpriteFont_BindLua.h" #include "wiFont.h" #include "wiMath_BindLua.h" +#include "wiAudio_BindLua.h" namespace wi::lua { @@ -18,6 +19,8 @@ namespace wi::lua lunamethod(SpriteFont_BindLua, SetShadowBolden), lunamethod(SpriteFont_BindLua, SetShadowSoftness), lunamethod(SpriteFont_BindLua, SetShadowOffset), + lunamethod(SpriteFont_BindLua, SetHorizontalWrapping), + lunamethod(SpriteFont_BindLua, SetHidden), lunamethod(SpriteFont_BindLua, SetStyle), lunamethod(SpriteFont_BindLua, GetText), @@ -32,7 +35,17 @@ namespace wi::lua lunamethod(SpriteFont_BindLua, GetShadowBolden), lunamethod(SpriteFont_BindLua, GetShadowSoftness), lunamethod(SpriteFont_BindLua, GetShadowOffset), + lunamethod(SpriteFont_BindLua, GetHorizontalWrapping), + lunamethod(SpriteFont_BindLua, IsHidden), + lunamethod(SpriteFont_BindLua, TextSize), + lunamethod(SpriteFont_BindLua, SetTypewriterTime), + lunamethod(SpriteFont_BindLua, SetTypewriterLooped), + lunamethod(SpriteFont_BindLua, SetTypewriterCharacterStart), + lunamethod(SpriteFont_BindLua, SetTypewriterSound), + lunamethod(SpriteFont_BindLua, ResetTypewriter), + lunamethod(SpriteFont_BindLua, TypewriterFinish), + lunamethod(SpriteFont_BindLua, IsTypewriterFinished), { NULL, NULL } }; Luna::PropertyType SpriteFont_BindLua::properties[] = { @@ -256,6 +269,28 @@ namespace wi::lua wi::lua::SError(L, "SetShadowOffset(Vector pos) not enough arguments!"); return 0; } + int SpriteFont_BindLua::SetHorizontalWrapping(lua_State* L) + { + int argc = wi::lua::SGetArgCount(L); + if (argc > 0) + { + font.params.h_wrap = wi::lua::SGetFloat(L, 1); + } + else + wi::lua::SError(L, "SetHorizontalWrapping(float value) not enough arguments!"); + return 0; + } + int SpriteFont_BindLua::SetHidden(lua_State* L) + { + int argc = wi::lua::SGetArgCount(L); + if (argc > 0) + { + font.SetHidden(wi::lua::SGetBool(L, 1)); + } + else + wi::lua::SError(L, "SetHidden(bool value) not enough arguments!"); + return 0; + } int SpriteFont_BindLua::GetText(lua_State* L) { @@ -321,6 +356,93 @@ namespace wi::lua Luna::push(L, XMLoadFloat4(&C)); return 1; } + int SpriteFont_BindLua::GetHorizontalWrapping(lua_State* L) + { + wi::lua::SSetFloat(L, font.params.h_wrap); + return 1; + } + int SpriteFont_BindLua::IsHidden(lua_State* L) + { + wi::lua::SSetBool(L, font.IsHidden()); + return 1; + } + + int SpriteFont_BindLua::TextSize(lua_State* L) + { + XMFLOAT2 textsize = font.TextSize(); + Luna::push(L, XMLoadFloat2(&textsize)); + return 1; + } + + int SpriteFont_BindLua::SetTypewriterTime(lua_State* L) + { + int argc = wi::lua::SGetArgCount(L); + if (argc < 1) + { + wi::lua::SError(L, "SetTypewriterTime(float value) not enough arguments!"); + } + font.anim.typewriter.time = wi::lua::SGetFloat(L, 1); + return 0; + } + int SpriteFont_BindLua::SetTypewriterLooped(lua_State* L) + { + int argc = wi::lua::SGetArgCount(L); + if (argc < 1) + { + wi::lua::SError(L, "SetTypewriterLooped(bool value) not enough arguments!"); + } + font.anim.typewriter.looped = wi::lua::SGetBool(L, 1); + return 0; + } + int SpriteFont_BindLua::SetTypewriterCharacterStart(lua_State* L) + { + int argc = wi::lua::SGetArgCount(L); + if (argc < 1) + { + wi::lua::SError(L, "SetTypewriterCharacterStart(int value) not enough arguments!"); + } + font.anim.typewriter.character_start = (size_t)wi::lua::SGetLongLong(L, 1); + return 0; + } + int SpriteFont_BindLua::SetTypewriterSound(lua_State* L) + { + int argc = wi::lua::SGetArgCount(L); + if (argc < 2) + { + wi::lua::SError(L, "SetTypewriterSound(Sound sound, SoundInstance soundinstance) not enough arguments!"); + return 0; + } + Sound_BindLua* sound = Luna::lightcheck(L, 1); + if (sound == nullptr) + { + wi::lua::SError(L, "SetTypewriterSound(Sound sound, SoundInstance soundinstance) first argument is not a sound!"); + return 0; + } + SoundInstance_BindLua* soundinstance = Luna::lightcheck(L, 2); + if (soundinstance == nullptr) + { + wi::lua::SError(L, "SetTypewriterSound(Sound sound, SoundInstance soundinstance) second argument is not a sound instance!"); + return 0; + } + font.anim.typewriter.sound = sound->sound; + font.anim.typewriter.soundinstance = soundinstance->soundinstance; + return 0; + } + int SpriteFont_BindLua::ResetTypewriter(lua_State* L) + { + font.anim.typewriter.reset(); + return 0; + } + int SpriteFont_BindLua::TypewriterFinish(lua_State* L) + { + font.anim.typewriter.Finish(); + return 0; + } + int SpriteFont_BindLua::IsTypewriterFinished(lua_State* L) + { + wi::lua::SSetBool(L, font.anim.typewriter.IsFinished()); + return 1; + } void SpriteFont_BindLua::Bind() { diff --git a/WickedEngine/wiSpriteFont_BindLua.h b/WickedEngine/wiSpriteFont_BindLua.h index f39e14597..d8150acfd 100644 --- a/WickedEngine/wiSpriteFont_BindLua.h +++ b/WickedEngine/wiSpriteFont_BindLua.h @@ -30,6 +30,8 @@ namespace wi::lua int SetShadowBolden(lua_State* L); int SetShadowSoftness(lua_State* L); int SetShadowOffset(lua_State* L); + int SetHorizontalWrapping(lua_State* L); + int SetHidden(lua_State* L); int GetText(lua_State* L); int GetSize(lua_State* L); @@ -43,6 +45,18 @@ namespace wi::lua int GetShadowBolden(lua_State* L); int GetShadowSoftness(lua_State* L); int GetShadowOffset(lua_State* L); + int GetHorizontalWrapping(lua_State* L); + int IsHidden(lua_State* L); + + int TextSize(lua_State* L); + + int SetTypewriterTime(lua_State* L); + int SetTypewriterLooped(lua_State* L); + int SetTypewriterCharacterStart(lua_State* L); + int SetTypewriterSound(lua_State* L); + int ResetTypewriter(lua_State* L); + int TypewriterFinish(lua_State* L); + int IsTypewriterFinished(lua_State* L); static void Bind(); }; diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index f627056ac..a6e9e94ab 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wi::version // minor features, major updates, breaking compatibility changes const int minor = 71; // minor bug fixes, alterations, refactors, updates - const int revision = 199; + const int revision = 200; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);