mirror of
https://github.com/mehah/otclient
synced 2026-08-15 16:29:06 -04:00
feat: Drawpool 3.0
This commit is contained in:
parent
674ad54275
commit
94fbbbc8a6
34 changed files with 561 additions and 505 deletions
2
init.lua
2
init.lua
|
|
@ -8,7 +8,7 @@ Services = {
|
|||
|
||||
g_app.setName("OTClient - Redemption");
|
||||
g_app.setCompactName("otclient");
|
||||
g_app.setOrganizationName("otbr");
|
||||
g_app.setOrganizationName("otcr");
|
||||
|
||||
g_app.hasUpdater = function()
|
||||
return (Services.updater and Services.updater ~= "" and g_modules.getModule("updater"))
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
-- Global Tables
|
||||
local binaryTree = {} -- BST
|
||||
local binaryTree = {} -- BST
|
||||
local battleButtons = {} -- map of creature id
|
||||
|
||||
-- Global variables that will inherit from init
|
||||
|
|
@ -64,7 +64,7 @@ end
|
|||
function init() -- Initiating the module (load)
|
||||
g_ui.importStyle('battlebutton')
|
||||
battleButton = modules.client_topmenu.addRightGameToggleButton('battleButton', tr('Battle') .. ' (Ctrl+B)',
|
||||
'/images/topbuttons/battle', toggle)
|
||||
'/images/topbuttons/battle', toggle)
|
||||
battleButton:setOn(true)
|
||||
battleWindow = g_ui.loadUI('battle')
|
||||
|
||||
|
|
@ -88,14 +88,14 @@ function init() -- Initiating the module (load)
|
|||
end
|
||||
|
||||
-- Adding Filter options
|
||||
local options = {'hidePlayers', 'hideNPCs', 'hideMonsters', 'hideSkulls', 'hideParty'}
|
||||
local options = { 'hidePlayers', 'hideNPCs', 'hideMonsters', 'hideSkulls', 'hideParty' }
|
||||
for i, v in ipairs(options) do
|
||||
hideButtons[v] = battleWindow:recursiveGetChildById(v)
|
||||
end
|
||||
|
||||
-- Adding SortType and SortOrder options
|
||||
local sortTypeOptions = {'Name', 'Distance', 'Age', 'Health'}
|
||||
local sortOrderOptions = {'Asc.', 'Desc.'}
|
||||
local sortTypeOptions = { 'Name', 'Distance', 'Age', 'Health' }
|
||||
local sortOrderOptions = { 'Asc.', 'Desc.' }
|
||||
|
||||
local sortTypeBox = battleWindow:recursiveGetChildById('sortTypeBox')
|
||||
for i, v in ipairs(sortTypeOptions) do
|
||||
|
|
@ -134,7 +134,6 @@ end
|
|||
|
||||
-- Binary Search, Insertion and Resort functions
|
||||
local function debugTables(sortType) -- Print both battlebutton and binarytree tables
|
||||
|
||||
local function getInfo(v, sortType)
|
||||
local returnedInfo = v.id
|
||||
if sortType then
|
||||
|
|
@ -464,10 +463,14 @@ end
|
|||
|
||||
local function canBeSeen(creature)
|
||||
return creature and creature:canBeSeen() and creature:getPosition() and
|
||||
modules.game_interface.getMapPanel():isInRange(creature:getPosition())
|
||||
modules.game_interface.getMapPanel():isInRange(creature:getPosition())
|
||||
end
|
||||
|
||||
local function getDistanceBetween(p1, p2) -- Calculate distance
|
||||
if p2 == nil then
|
||||
p2 = { x = 0, y = 0 }
|
||||
end
|
||||
|
||||
local xd = math.abs(p1.x - p2.x);
|
||||
local yd = math.abs(p1.y - p2.y);
|
||||
|
||||
|
|
@ -622,8 +625,8 @@ function removeCreature(creature, all) -- Remove a single creature or all
|
|||
msg = msg .. p
|
||||
end
|
||||
assert(index ~= nil,
|
||||
'Not able to remove creature: id ' .. creatureId .. ' not found in binary search using ' .. sortType ..
|
||||
' to find value ' .. msg .. '.')
|
||||
'Not able to remove creature: id ' .. creatureId .. ' not found in binary search using ' .. sortType ..
|
||||
' to find value ' .. msg .. '.')
|
||||
end
|
||||
end
|
||||
return false
|
||||
|
|
@ -688,10 +691,8 @@ function attackNext(previous)
|
|||
|
||||
if battleButton.isTarget then
|
||||
foundTarget = true
|
||||
|
||||
elseif foundTarget and not nextElement then
|
||||
nextElement = battleButton
|
||||
|
||||
elseif not foundTarget then
|
||||
prevElement = battleButton
|
||||
end
|
||||
|
|
@ -712,7 +713,6 @@ function attackNext(previous)
|
|||
g_game.attack(firstElement.creature)
|
||||
end
|
||||
end
|
||||
|
||||
elseif firstElement then
|
||||
g_game.attack(firstElement.creature)
|
||||
else
|
||||
|
|
@ -896,9 +896,9 @@ function onCreaturePositionChange(creature, newPos, oldPos) -- Update battleButt
|
|||
correctBattleButtons()
|
||||
else
|
||||
assert(index ~= nil,
|
||||
'Not able to update Position Change. Creature: ' .. creature:getName() .. ' id ' ..
|
||||
creatureId .. ' not found in binary search using ' .. sortType ..
|
||||
' to find value ' .. oldDistance .. '.\n')
|
||||
'Not able to update Position Change. Creature: ' .. creature:getName() .. ' id ' ..
|
||||
creatureId .. ' not found in binary search using ' .. sortType ..
|
||||
' to find value ' .. oldDistance .. '.\n')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -952,11 +952,10 @@ function onCreatureHealthPercentChange(creature, healthPercent, oldHealthPercent
|
|||
correctBattleButtons()
|
||||
else
|
||||
assert(index ~= nil,
|
||||
'Not able to update HealthPercent Change. Creature: id ' .. creatureId ..
|
||||
' not found in binary search using ' .. sortType .. ' to find value ' .. oldHealthPercent ..
|
||||
'.')
|
||||
'Not able to update HealthPercent Change. Creature: id ' .. creatureId ..
|
||||
' not found in binary search using ' .. sortType .. ' to find value ' .. oldHealthPercent ..
|
||||
'.')
|
||||
end
|
||||
|
||||
end
|
||||
battleButton:setLifeBarPercent(healthPercent)
|
||||
end
|
||||
|
|
@ -986,7 +985,7 @@ function onBattleButtonMouseRelease(self, mousePosition, mouseButton) -- Interac
|
|||
end
|
||||
|
||||
if ((g_mouse.isPressed(MouseLeftButton) and mouseButton == MouseRightButton) or
|
||||
(g_mouse.isPressed(MouseRightButton) and mouseButton == MouseLeftButton)) then
|
||||
(g_mouse.isPressed(MouseRightButton) and mouseButton == MouseLeftButton)) then
|
||||
mouseWidget.cancelNextRelease = true
|
||||
g_game.look(self.creature, true)
|
||||
return true
|
||||
|
|
@ -1080,5 +1079,4 @@ function terminate() -- Terminating the Module (unload)
|
|||
onGameStart = onGameStart
|
||||
})
|
||||
disconnecting()
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
controller = Controller:new()
|
||||
controller:registerEvents(g_game, {
|
||||
onClientVersionChange = function(version)
|
||||
g_game.enableFeature(GameFormatCreatureName);
|
||||
-- g_game.enableFeature(GameKeepUnawareTiles)
|
||||
g_game.enableFeature(GameFormatCreatureName)
|
||||
|
||||
if version >= 750 then
|
||||
g_game.enableFeature(GameSoul);
|
||||
|
|
|
|||
|
|
@ -34,26 +34,13 @@ LightView::LightView(const Size& size, const uint16_t tileSize) : m_pool(g_drawP
|
|||
m_texture = std::make_shared<Texture>(size);
|
||||
m_texture->setSmooth(true);
|
||||
});
|
||||
|
||||
g_drawPool.use(DrawPoolType::LIGHT);
|
||||
g_drawPool.addAction([this] {
|
||||
{
|
||||
std::scoped_lock l(m_pool->getMutex());
|
||||
m_texture->updatePixels(m_pixels.data());
|
||||
}
|
||||
g_painter->resetColor();
|
||||
g_painter->resetTransformMatrix();
|
||||
g_painter->setTexture(m_texture.get());
|
||||
g_painter->setCompositionMode(CompositionMode::MULTIPLY);
|
||||
g_painter->drawCoords(m_coords);
|
||||
});
|
||||
}
|
||||
|
||||
void LightView::resize(const Size& size, const uint16_t tileSize) {
|
||||
if (!m_texture || m_mapSize == size && m_tileSize == tileSize)
|
||||
return;
|
||||
|
||||
std::scoped_lock l(m_pool->getMutex());
|
||||
std::scoped_lock l(m_pool->getMutex(), m_pool->getMutexPreDraw());
|
||||
|
||||
m_mapSize = size;
|
||||
m_tileSize = tileSize;
|
||||
|
|
@ -71,10 +58,10 @@ void LightView::resize(const Size& size, const uint16_t tileSize) {
|
|||
|
||||
void LightView::addLightSource(const Point& pos, const Light& light, float brightness)
|
||||
{
|
||||
if (light.intensity == 0)
|
||||
if (!isDark() || light.intensity == 0)
|
||||
return;
|
||||
|
||||
auto& lightData = m_lightData[m_currentLightData];
|
||||
auto& lightData = m_lightData[0];
|
||||
|
||||
if (!lightData.lights.empty()) {
|
||||
auto& prevLight = lightData.lights.back();
|
||||
|
|
@ -95,7 +82,7 @@ void LightView::addLightSource(const Point& pos, const Light& light, float brigh
|
|||
|
||||
void LightView::resetShade(const Point& pos)
|
||||
{
|
||||
auto& lightData = m_lightData[m_currentLightData];
|
||||
auto& lightData = m_lightData[0];
|
||||
|
||||
size_t index = (pos.y / m_tileSize) * m_mapSize.width() + (pos.x / m_tileSize);
|
||||
if (index >= lightData.tiles.size()) return;
|
||||
|
|
@ -104,20 +91,34 @@ void LightView::resetShade(const Point& pos)
|
|||
|
||||
void LightView::draw(const Rect& dest, const Rect& src)
|
||||
{
|
||||
updateCoords(dest, src);
|
||||
|
||||
if (m_updatedHash != m_hash) {
|
||||
m_hash = m_updatedHash;
|
||||
m_updatedHash = 0;
|
||||
|
||||
std::scoped_lock l(m_pool->getMutex());
|
||||
if (++m_currentLightData > 1) m_currentLightData = 0;
|
||||
std::scoped_lock l(m_pool->getMutexPreDraw());
|
||||
std::swap(m_lightData[0], m_lightData[1]);
|
||||
g_asyncDispatcher.dispatch([this] {
|
||||
updatePixels();
|
||||
});
|
||||
}
|
||||
|
||||
auto& lightData = m_lightData[m_currentLightData];
|
||||
g_drawPool.preDraw(DrawPoolType::LIGHT, [this, &dest, &src] {
|
||||
g_drawPool.addAction([=, this] {
|
||||
{
|
||||
std::scoped_lock l(m_pool->getMutexPreDraw());
|
||||
m_texture->updatePixels(m_pixels.data());
|
||||
}
|
||||
|
||||
updateCoords(dest, src);
|
||||
g_painter->setCompositionMode(CompositionMode::MULTIPLY);
|
||||
g_painter->resetTransformMatrix();
|
||||
g_painter->resetColor();
|
||||
g_painter->setTexture(m_texture.get());
|
||||
g_painter->drawCoords(m_coords);
|
||||
});
|
||||
});
|
||||
|
||||
auto& lightData = m_lightData[0];
|
||||
lightData.lights.clear();
|
||||
lightData.tiles.assign(m_mapSize.area(), {});
|
||||
}
|
||||
|
|
@ -139,9 +140,9 @@ void LightView::updateCoords(const Rect& dest, const Rect& src) {
|
|||
}
|
||||
|
||||
void LightView::updatePixels() {
|
||||
std::scoped_lock l(m_pool->getMutex());
|
||||
std::scoped_lock l(m_pool->getMutexPreDraw());
|
||||
|
||||
const auto& lightData = m_lightData[m_currentLightData ? 0 : 1];
|
||||
const auto& lightData = m_lightData[1];
|
||||
|
||||
const size_t lightSize = lightData.lights.size();
|
||||
|
||||
|
|
|
|||
|
|
@ -82,6 +82,5 @@ private:
|
|||
CoordsBuffer m_coords;
|
||||
TexturePtr m_texture;
|
||||
LightData m_lightData[2];
|
||||
std::atomic_uint8_t m_currentLightData{ 0 };
|
||||
std::vector<uint8_t> m_pixels;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -152,51 +152,55 @@ void Map::addStaticText(const StaticTextPtr& txt, const Position& pos) {
|
|||
if (!g_app.isDrawingTexts())
|
||||
return;
|
||||
|
||||
for (const auto& other : m_staticTexts) {
|
||||
// try to combine messages
|
||||
if (other->getPosition() == pos && other->addMessage(txt->getName(), txt->getMessageMode(), txt->getFirstMessage())) {
|
||||
return;
|
||||
g_textDispatcher.addEvent([=, this] {
|
||||
for (const auto& other : m_staticTexts) {
|
||||
// try to combine messages
|
||||
if (other->getPosition() == pos && other->addMessage(txt->getName(), txt->getMessageMode(), txt->getFirstMessage())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
txt->setPosition(pos);
|
||||
m_staticTexts.emplace_back(txt);
|
||||
txt->setPosition(pos);
|
||||
m_staticTexts.emplace_back(txt);
|
||||
});
|
||||
}
|
||||
|
||||
void Map::addAnimatedText(const AnimatedTextPtr& txt, const Position& pos) {
|
||||
if (!g_app.isDrawingTexts())
|
||||
return;
|
||||
|
||||
// this code will stack animated texts of the same color
|
||||
AnimatedTextPtr prevAnimatedText;
|
||||
g_textDispatcher.addEvent([=, this] {
|
||||
// this code will stack animated texts of the same color
|
||||
AnimatedTextPtr prevAnimatedText;
|
||||
|
||||
bool merged = false;
|
||||
for (const auto& other : m_animatedTexts) {
|
||||
if (other->getPosition() == pos) {
|
||||
prevAnimatedText = other;
|
||||
if (other->merge(txt)) {
|
||||
merged = true;
|
||||
break;
|
||||
bool merged = false;
|
||||
for (const auto& other : m_animatedTexts) {
|
||||
if (other->getPosition() == pos) {
|
||||
prevAnimatedText = other;
|
||||
if (other->merge(txt)) {
|
||||
merged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!merged) {
|
||||
if (prevAnimatedText) {
|
||||
Point offset = prevAnimatedText->getOffset();
|
||||
if (const float t = prevAnimatedText->getTimer().ticksElapsed();
|
||||
t < g_gameConfig.getAnimatedTextDuration() / 4.0) { // didnt move 12 pixels
|
||||
const int32_t y = 12 - 48 * t / static_cast<float>(g_gameConfig.getAnimatedTextDuration());
|
||||
offset += Point(0, y);
|
||||
if (!merged) {
|
||||
if (prevAnimatedText) {
|
||||
Point offset = prevAnimatedText->getOffset();
|
||||
if (const float t = prevAnimatedText->getTimer().ticksElapsed();
|
||||
t < g_gameConfig.getAnimatedTextDuration() / 4.0) { // didnt move 12 pixels
|
||||
const int32_t y = 12 - 48 * t / static_cast<float>(g_gameConfig.getAnimatedTextDuration());
|
||||
offset += Point(0, y);
|
||||
}
|
||||
offset.y = std::min<int32_t>(offset.y, 12);
|
||||
txt->setOffset(offset);
|
||||
}
|
||||
offset.y = std::min<int32_t>(offset.y, 12);
|
||||
txt->setOffset(offset);
|
||||
m_animatedTexts.emplace_back(txt);
|
||||
}
|
||||
m_animatedTexts.emplace_back(txt);
|
||||
}
|
||||
|
||||
txt->setPosition(pos);
|
||||
txt->onAppear();
|
||||
txt->setPosition(pos);
|
||||
txt->onAppear();
|
||||
});
|
||||
}
|
||||
|
||||
ThingPtr Map::getThing(const Position& pos, int16_t stackPos)
|
||||
|
|
|
|||
|
|
@ -46,47 +46,6 @@ MapView::MapView() : m_pool(g_drawPool.get(DrawPoolType::MAP)), m_lightView(std:
|
|||
{
|
||||
m_floors.resize(g_gameConfig.getMapMaxZ() + 1);
|
||||
|
||||
m_pool->onBeforeDraw([this] {
|
||||
float fadeOpacity = 1.f;
|
||||
if (!m_shaderSwitchDone && m_fadeOutTime > 0) {
|
||||
fadeOpacity = 1.f - (m_fadeTimer.timeElapsed() / m_fadeOutTime);
|
||||
if (fadeOpacity < 0.f) {
|
||||
m_shader = m_nextShader;
|
||||
m_nextShader = nullptr;
|
||||
m_shaderSwitchDone = true;
|
||||
m_fadeTimer.restart();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_shaderSwitchDone && m_shader && m_fadeInTime > 0)
|
||||
fadeOpacity = std::min<float>(m_fadeTimer.timeElapsed() / m_fadeInTime, 1.f);
|
||||
|
||||
if (m_shader) {
|
||||
const auto& center = m_posInfo.srcRect.center();
|
||||
const auto& globalCoord = Point(m_posInfo.camera.x - m_drawDimension.width() / 2, -(m_posInfo.camera.y - m_drawDimension.height() / 2)) * m_tileSize;
|
||||
|
||||
m_shader->bind();
|
||||
m_shader->setUniformValue(ShaderManager::MAP_CENTER_COORD, center.x / static_cast<float>(m_rectDimension.width()), 1.f - center.y / static_cast<float>(m_rectDimension.height()));
|
||||
m_shader->setUniformValue(ShaderManager::MAP_GLOBAL_COORD, globalCoord.x / static_cast<float>(m_rectDimension.height()), globalCoord.y / static_cast<float>(m_rectDimension.height()));
|
||||
m_shader->setUniformValue(ShaderManager::MAP_ZOOM, m_pool->getScaleFactor());
|
||||
|
||||
Point last = transformPositionTo2D(m_posInfo.camera, m_shaderPosition);
|
||||
//Reverse vertical axis.
|
||||
last.y = -last.y;
|
||||
|
||||
m_shader->setUniformValue(ShaderManager::MAP_WALKOFFSET, last.x / static_cast<float>(m_rectDimension.width()), last.y / static_cast<float>(m_rectDimension.height()));
|
||||
|
||||
g_painter->setShaderProgram(m_shader);
|
||||
}
|
||||
|
||||
g_painter->setOpacity(fadeOpacity);
|
||||
});
|
||||
|
||||
m_pool->onAfterDraw([] {
|
||||
g_painter->resetShaderProgram();
|
||||
g_painter->resetOpacity();
|
||||
});
|
||||
|
||||
setVisibleDimension(Size(15, 11));
|
||||
}
|
||||
|
||||
|
|
@ -98,7 +57,52 @@ MapView::~MapView()
|
|||
m_lightView = nullptr;
|
||||
}
|
||||
|
||||
void MapView::draw()
|
||||
void MapView::registerEvents() {
|
||||
g_drawPool.addAction([this, camera = m_posInfo.camera, srcRect = m_posInfo.srcRect] {
|
||||
m_pool->onBeforeDraw([=, this] {
|
||||
float fadeOpacity = 1.f;
|
||||
if (!m_shaderSwitchDone && m_fadeOutTime > 0) {
|
||||
fadeOpacity = 1.f - (m_fadeTimer.timeElapsed() / m_fadeOutTime);
|
||||
if (fadeOpacity < 0.f) {
|
||||
m_shader = m_nextShader;
|
||||
m_nextShader = nullptr;
|
||||
m_shaderSwitchDone = true;
|
||||
m_fadeTimer.restart();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_shaderSwitchDone && m_shader && m_fadeInTime > 0)
|
||||
fadeOpacity = std::min<float>(m_fadeTimer.timeElapsed() / m_fadeInTime, 1.f);
|
||||
|
||||
if (m_shader) {
|
||||
const auto& center = srcRect.center();
|
||||
const auto& globalCoord = Point(camera.x - m_drawDimension.width() / 2, -(camera.y - m_drawDimension.height() / 2)) * m_tileSize;
|
||||
|
||||
m_shader->bind();
|
||||
m_shader->setUniformValue(ShaderManager::MAP_CENTER_COORD, center.x / static_cast<float>(m_rectDimension.width()), 1.f - center.y / static_cast<float>(m_rectDimension.height()));
|
||||
m_shader->setUniformValue(ShaderManager::MAP_GLOBAL_COORD, globalCoord.x / static_cast<float>(m_rectDimension.height()), globalCoord.y / static_cast<float>(m_rectDimension.height()));
|
||||
m_shader->setUniformValue(ShaderManager::MAP_ZOOM, m_pool->getScaleFactor());
|
||||
|
||||
Point last = transformPositionTo2D(camera, m_shaderPosition);
|
||||
//Reverse vertical axis.
|
||||
last.y = -last.y;
|
||||
|
||||
m_shader->setUniformValue(ShaderManager::MAP_WALKOFFSET, last.x / static_cast<float>(m_rectDimension.width()), last.y / static_cast<float>(m_rectDimension.height()));
|
||||
|
||||
g_painter->setShaderProgram(m_shader);
|
||||
}
|
||||
|
||||
g_painter->setOpacity(fadeOpacity);
|
||||
});
|
||||
|
||||
m_pool->onAfterDraw([] {
|
||||
g_painter->resetShaderProgram();
|
||||
g_painter->resetOpacity();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void MapView::draw(const Rect& rect)
|
||||
{
|
||||
// update visible tiles cache when needed
|
||||
if (m_updateVisibleTiles)
|
||||
|
|
@ -125,91 +129,92 @@ void MapView::draw()
|
|||
|
||||
void MapView::drawFloor()
|
||||
{
|
||||
g_drawPool.use(DrawPoolType::MAP, m_posInfo.rect, m_posInfo.srcRect, Color::black);
|
||||
{
|
||||
const auto& cameraPosition = m_posInfo.camera;
|
||||
const auto& lightView = isDrawingLights() ? m_lightView.get() : nullptr;
|
||||
const auto& cameraPosition = m_posInfo.camera;
|
||||
const auto& lightView = isDrawingLights() ? m_lightView.get() : nullptr;
|
||||
|
||||
uint32_t flags = Otc::DrawThings;
|
||||
if (lightView) flags |= Otc::DrawLights;
|
||||
if (m_drawNames) { flags |= Otc::DrawNames; }
|
||||
if (m_drawHealthBars) { flags |= Otc::DrawBars; }
|
||||
if (m_drawManaBar) { flags |= Otc::DrawManaBar; }
|
||||
uint32_t flags = Otc::DrawThings;
|
||||
if (lightView) flags |= Otc::DrawLights;
|
||||
if (m_drawNames) { flags |= Otc::DrawNames; }
|
||||
if (m_drawHealthBars) { flags |= Otc::DrawBars; }
|
||||
if (m_drawManaBar) { flags |= Otc::DrawManaBar; }
|
||||
|
||||
for (int_fast8_t z = m_floorMax; z >= m_floorMin; --z) {
|
||||
const float fadeLevel = getFadeLevel(z);
|
||||
if (fadeLevel == 0.f) break;
|
||||
if (fadeLevel < .99f)
|
||||
g_drawPool.setOpacity(fadeLevel);
|
||||
for (int_fast8_t z = m_floorMax; z >= m_floorMin; --z) {
|
||||
const float fadeLevel = getFadeLevel(z);
|
||||
if (fadeLevel == 0.f) break;
|
||||
if (fadeLevel < .99f)
|
||||
g_drawPool.setOpacity(fadeLevel);
|
||||
|
||||
Position _camera = cameraPosition;
|
||||
const bool alwaysTransparent = m_floorViewMode == ALWAYS_WITH_TRANSPARENCY && z < m_cachedFirstVisibleFloor && _camera.coveredUp(cameraPosition.z - z);
|
||||
Position _camera = cameraPosition;
|
||||
const bool alwaysTransparent = m_floorViewMode == ALWAYS_WITH_TRANSPARENCY && z < m_cachedFirstVisibleFloor && _camera.coveredUp(cameraPosition.z - z);
|
||||
|
||||
const auto& map = m_floors[z].cachedVisibleTiles;
|
||||
const auto& map = m_floors[z].cachedVisibleTiles;
|
||||
|
||||
if (m_fadeType != FadeType::OUT$ || fadeLevel == 1.f) {
|
||||
for (const auto& tile : map.shades) {
|
||||
if (alwaysTransparent && tile->getPosition().isInRange(_camera, g_gameConfig.getTileTransparentFloorViewRange(), g_gameConfig.getTileTransparentFloorViewRange(), true))
|
||||
continue;
|
||||
|
||||
m_lightView->resetShade(transformPositionTo2D(tile->getPosition(), cameraPosition));
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& tile : map.tiles) {
|
||||
uint32_t tileFlags = flags;
|
||||
|
||||
if (!m_drawViewportEdge && !tile->canRender(tileFlags, cameraPosition, m_viewport))
|
||||
if (m_fadeType != FadeType::OUT$ || fadeLevel == 1.f) {
|
||||
for (const auto& tile : map.shades) {
|
||||
if (alwaysTransparent && tile->getPosition().isInRange(_camera, g_gameConfig.getTileTransparentFloorViewRange(), g_gameConfig.getTileTransparentFloorViewRange(), true))
|
||||
continue;
|
||||
|
||||
bool isCovered = false;
|
||||
if (tile->hasCreature()) {
|
||||
isCovered = tile->isCovered(m_cachedFirstVisibleFloor);
|
||||
}
|
||||
m_lightView->resetShade(transformPositionTo2D(tile->getPosition(), cameraPosition));
|
||||
}
|
||||
}
|
||||
|
||||
if (alwaysTransparent) {
|
||||
const bool inRange = tile->getPosition().isInRange(_camera, g_gameConfig.getTileTransparentFloorViewRange(), g_gameConfig.getTileTransparentFloorViewRange(), true);
|
||||
isCovered = isCovered && !inRange;
|
||||
for (const auto& tile : map.tiles) {
|
||||
uint32_t tileFlags = flags;
|
||||
|
||||
g_drawPool.setOpacity(inRange ? .16 : .7);
|
||||
}
|
||||
if (!m_drawViewportEdge && !tile->canRender(tileFlags, cameraPosition, m_viewport))
|
||||
continue;
|
||||
|
||||
tile->draw(transformPositionTo2D(tile->getPosition(), cameraPosition), m_posInfo, tileFlags, isCovered, lightView);
|
||||
|
||||
if (alwaysTransparent)
|
||||
g_drawPool.resetOpacity();
|
||||
bool isCovered = false;
|
||||
if (tile->hasCreature()) {
|
||||
isCovered = tile->isCovered(m_cachedFirstVisibleFloor);
|
||||
}
|
||||
|
||||
for (const auto& missile : g_map.getFloorMissiles(z))
|
||||
missile->draw(transformPositionTo2D(missile->getPosition(), cameraPosition), true, lightView);
|
||||
if (alwaysTransparent) {
|
||||
const bool inRange = tile->getPosition().isInRange(_camera, g_gameConfig.getTileTransparentFloorViewRange(), g_gameConfig.getTileTransparentFloorViewRange(), true);
|
||||
isCovered = isCovered && !inRange;
|
||||
|
||||
if (m_shadowFloorIntensity > 0 && z == cameraPosition.z + 1) {
|
||||
g_drawPool.setOpacity(m_shadowFloorIntensity, true);
|
||||
g_drawPool.addFilledRect(m_rectDimension, Color::black, m_shadowConductor);
|
||||
g_drawPool.setOpacity(inRange ? .16 : .7);
|
||||
}
|
||||
|
||||
if (canFloorFade())
|
||||
tile->draw(transformPositionTo2D(tile->getPosition(), cameraPosition), m_posInfo, tileFlags, isCovered, lightView);
|
||||
|
||||
if (alwaysTransparent)
|
||||
g_drawPool.resetOpacity();
|
||||
|
||||
g_drawPool.flush();
|
||||
}
|
||||
|
||||
if (m_posInfo.rect.contains(g_window.getMousePosition())) {
|
||||
if (m_crosshairTexture && m_mousePosition.isValid()) {
|
||||
const auto& point = transformPositionTo2D(m_mousePosition, cameraPosition);
|
||||
const auto& crosshairRect = Rect(point, m_tileSize, m_tileSize);
|
||||
g_drawPool.addTexturedRect(crosshairRect, m_crosshairTexture);
|
||||
}
|
||||
} else if (m_lastHighlightTile) {
|
||||
m_mousePosition = {}; // Invalidate mousePosition
|
||||
destroyHighlightTile();
|
||||
for (const auto& missile : g_map.getFloorMissiles(z))
|
||||
missile->draw(transformPositionTo2D(missile->getPosition(), cameraPosition), true, lightView);
|
||||
|
||||
if (m_shadowFloorIntensity > 0 && z == cameraPosition.z + 1) {
|
||||
g_drawPool.setOpacity(m_shadowFloorIntensity, true);
|
||||
g_drawPool.addFilledRect(m_rectDimension, Color::black, m_shadowConductor);
|
||||
}
|
||||
|
||||
if (canFloorFade())
|
||||
g_drawPool.resetOpacity();
|
||||
|
||||
g_drawPool.flush();
|
||||
}
|
||||
|
||||
if (m_posInfo.rect.contains(g_window.getMousePosition())) {
|
||||
if (m_crosshairTexture && m_mousePosition.isValid()) {
|
||||
const auto& point = transformPositionTo2D(m_mousePosition, cameraPosition);
|
||||
const auto& crosshairRect = Rect(point, m_tileSize, m_tileSize);
|
||||
g_drawPool.addTexturedRect(crosshairRect, m_crosshairTexture);
|
||||
}
|
||||
} else if (m_lastHighlightTile) {
|
||||
m_mousePosition = {}; // Invalidate mousePosition
|
||||
destroyHighlightTile();
|
||||
}
|
||||
}
|
||||
|
||||
void MapView::drawText()
|
||||
void MapView::drawForeground(const Rect& rect)
|
||||
{
|
||||
g_drawPool.use(DrawPoolType::TEXT);
|
||||
const auto& camera = getCameraPosition();
|
||||
const auto& srcRect = calcFramebufferSource(rect.size());
|
||||
const auto& drawOffset = srcRect.topLeft();
|
||||
const auto& horizontalStretchFactor = rect.width() / static_cast<float>(srcRect.width());
|
||||
const auto& verticalStretchFactor = rect.height() / static_cast<float>(srcRect.height());
|
||||
|
||||
g_drawPool.scale(g_app.getStaticTextScale());
|
||||
for (const auto& staticText : g_map.getStaticTexts()) {
|
||||
|
|
@ -217,28 +222,43 @@ void MapView::drawText()
|
|||
continue;
|
||||
|
||||
const auto& pos = staticText->getPosition();
|
||||
if (pos.z != m_posInfo.camera.z && staticText->getMessageMode() == Otc::MessageNone)
|
||||
if (pos.z != camera.z && staticText->getMessageMode() == Otc::MessageNone)
|
||||
continue;
|
||||
|
||||
Point p = transformPositionTo2D(pos, m_posInfo.camera) - m_posInfo.drawOffset;
|
||||
p.x *= m_posInfo.horizontalStretchFactor;
|
||||
p.y *= m_posInfo.verticalStretchFactor;
|
||||
p += m_posInfo.rect.topLeft();
|
||||
staticText->drawText(p.scale(g_app.getStaticTextScale()), m_posInfo.rect);
|
||||
Point p = transformPositionTo2D(pos, camera) - drawOffset;
|
||||
p.x *= horizontalStretchFactor;
|
||||
p.y *= verticalStretchFactor;
|
||||
p += rect.topLeft();
|
||||
staticText->drawText(p.scale(g_app.getStaticTextScale()), rect);
|
||||
}
|
||||
|
||||
g_drawPool.scale(g_app.getAnimatedTextScale());
|
||||
for (const auto& animatedText : g_map.getAnimatedTexts()) {
|
||||
const auto& pos = animatedText->getPosition();
|
||||
|
||||
if (pos.z != m_posInfo.camera.z)
|
||||
if (pos.z != camera.z)
|
||||
continue;
|
||||
|
||||
auto p = transformPositionTo2D(pos, m_posInfo.camera) - m_posInfo.drawOffset;
|
||||
p.x *= m_posInfo.horizontalStretchFactor;
|
||||
p.y *= m_posInfo.verticalStretchFactor;
|
||||
p += m_posInfo.rect.topLeft();
|
||||
animatedText->drawText(p, m_posInfo.rect);
|
||||
auto p = transformPositionTo2D(pos, camera) - drawOffset;
|
||||
p.x *= horizontalStretchFactor;
|
||||
p.y *= verticalStretchFactor;
|
||||
p += rect.topLeft();
|
||||
animatedText->drawText(p, rect);
|
||||
}
|
||||
|
||||
g_drawPool.scale(1.f);
|
||||
for (const auto& tile : m_foregroundTiles) {
|
||||
const auto& dest = transformPositionTo2D(tile->getPosition(), camera);
|
||||
#ifndef BOT_PROTECTION
|
||||
Point p = dest - drawOffset;
|
||||
p.x *= horizontalStretchFactor;
|
||||
p.y *= verticalStretchFactor;
|
||||
p += rect.topLeft();
|
||||
p.y += 5;
|
||||
|
||||
tile->drawTexts(p);
|
||||
#endif
|
||||
tile->drawWidget(dest, rect);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -410,6 +430,7 @@ void MapView::updateGeometry(const Size& visibleDimension)
|
|||
|
||||
m_lightView->resize(lightSize, tileSize);
|
||||
}
|
||||
|
||||
g_mainDispatcher.addEvent([this, bufferSize]() {
|
||||
m_pool->getFrameBuffer()->resize(bufferSize);
|
||||
});
|
||||
|
|
@ -456,15 +477,15 @@ void MapView::updateLight()
|
|||
|
||||
void MapView::onTileUpdate(const Position& pos, const ThingPtr& thing, const Otc::Operation op)
|
||||
{
|
||||
if (m_lastHighlightTile && m_lastHighlightTile->getPosition() == pos && op == Otc::OPERATION_CLEAN)
|
||||
m_lastHighlightTile = nullptr;
|
||||
if (thing && thing->isOpaque() && op == Otc::OPERATION_REMOVE)
|
||||
m_resetCoveredCache = true;
|
||||
|
||||
if (thing) {
|
||||
if (thing->isOpaque() && op == Otc::OPERATION_REMOVE)
|
||||
m_resetCoveredCache = true;
|
||||
if (op == Otc::OPERATION_CLEAN) {
|
||||
if (m_lastHighlightTile && m_lastHighlightTile->getPosition() == pos)
|
||||
m_lastHighlightTile = nullptr;
|
||||
|
||||
requestUpdateVisibleTiles();
|
||||
}
|
||||
|
||||
requestUpdateVisibleTiles();
|
||||
}
|
||||
|
||||
void MapView::onFadeInFinished()
|
||||
|
|
@ -548,8 +569,7 @@ void MapView::setAntiAliasingMode(const AntialiasingMode mode)
|
|||
m_antiAliasingMode = mode;
|
||||
|
||||
g_mainDispatcher.addEvent([=, this]() {
|
||||
g_drawPool.get(DrawPoolType::MAP)->getFrameBuffer()
|
||||
->setSmooth(mode != ANTIALIASING_DISABLED);
|
||||
m_pool->getFrameBuffer()->setSmooth(mode != ANTIALIASING_DISABLED);
|
||||
});
|
||||
|
||||
updateGeometry(m_visibleDimension);
|
||||
|
|
@ -864,4 +884,19 @@ void MapView::destroyHighlightTile() {
|
|||
m_lastHighlightTile->unselect();
|
||||
m_lastHighlightTile = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void MapView::addForegroundTile(const TilePtr& tile) {
|
||||
std::scoped_lock l(g_drawPool.get(DrawPoolType::FOREGROUND_MAP)->getMutex());
|
||||
|
||||
if (std::find(m_foregroundTiles.begin(), m_foregroundTiles.end(), tile) == m_foregroundTiles.end())
|
||||
m_foregroundTiles.emplace_back(tile);
|
||||
}
|
||||
void MapView::removeForegroundTile(const TilePtr& tile) {
|
||||
std::scoped_lock l(g_drawPool.get(DrawPoolType::FOREGROUND_MAP)->getMutex());
|
||||
const auto it = std::find(m_foregroundTiles.begin(), m_foregroundTiles.end(), tile);
|
||||
if (it == m_foregroundTiles.end())
|
||||
return;
|
||||
|
||||
m_foregroundTiles.erase(it);
|
||||
}
|
||||
|
|
@ -88,8 +88,8 @@ public:
|
|||
|
||||
MapView();
|
||||
~MapView() override;
|
||||
void draw();
|
||||
void drawText();
|
||||
void draw(const Rect& rect);
|
||||
void drawForeground(const Rect& rect);
|
||||
|
||||
// floor visibility related
|
||||
uint8_t getLockedFirstVisibleFloor() const { return m_lockedFirstVisibleFloor; }
|
||||
|
|
@ -181,6 +181,9 @@ public:
|
|||
PainterShaderProgramPtr getNextShader() { return m_nextShader; }
|
||||
bool isSwitchingShader() { return !m_shaderSwitchDone; }
|
||||
|
||||
void addForegroundTile(const TilePtr& tile);
|
||||
void removeForegroundTile(const TilePtr& tile);
|
||||
|
||||
protected:
|
||||
void onGlobalLightChange(const Light& light);
|
||||
void onFloorChange(uint8_t floor, uint8_t previousFloor);
|
||||
|
|
@ -220,24 +223,25 @@ private:
|
|||
TexturePtr texture;
|
||||
};
|
||||
|
||||
void updateHighlightTile(const Position& mousePos);
|
||||
void destroyHighlightTile();
|
||||
|
||||
void updateLight();
|
||||
void updateViewportDirectionCache();
|
||||
void updateGeometry(const Size& visibleDimension);
|
||||
void updateVisibleTiles();
|
||||
void updateRect(const Rect& rect);
|
||||
void updateViewport(const Otc::Direction dir = Otc::InvalidDirection) { m_viewport = m_viewPortDirection[dir]; }
|
||||
void requestUpdateVisibleTiles() { m_updateVisibleTiles = true; }
|
||||
void requestUpdateMapPosInfo() { m_updateMapPosInfo = true; }
|
||||
|
||||
void registerEvents();
|
||||
|
||||
uint8_t calcFirstVisibleFloor(bool checkLimitsFloorsView) const;
|
||||
uint8_t calcLastVisibleFloor() const;
|
||||
|
||||
void updateLight();
|
||||
void updateViewportDirectionCache();
|
||||
void drawFloor();
|
||||
|
||||
void updateHighlightTile(const Position& mousePos);
|
||||
void destroyHighlightTile();
|
||||
|
||||
void updateViewport(const Otc::Direction dir = Otc::InvalidDirection) { m_viewport = m_viewPortDirection[dir]; }
|
||||
|
||||
bool canFloorFade() const { return m_floorViewMode == FADE && m_floorFading; }
|
||||
|
||||
float getFadeLevel(uint8_t z) const
|
||||
|
|
@ -314,6 +318,7 @@ private:
|
|||
AntialiasingMode m_antiAliasingMode{ AntialiasingMode::ANTIALIASING_DISABLED };
|
||||
|
||||
std::vector<FloorData> m_floors;
|
||||
std::vector<TilePtr> m_foregroundTiles;
|
||||
|
||||
PainterShaderProgramPtr m_shader;
|
||||
PainterShaderProgramPtr m_nextShader;
|
||||
|
|
|
|||
|
|
@ -146,12 +146,12 @@ void Tile::updateWidget(const Point& dest, const MapPosInfo& mapRect)
|
|||
m_widget->setRect(rect);
|
||||
}
|
||||
|
||||
void Tile::drawWidget(const Point& dest, const MapPosInfo& mapRect)
|
||||
void Tile::drawWidget(const Point& dest, const Rect& rect)
|
||||
{
|
||||
if (!m_widget)
|
||||
return;
|
||||
|
||||
m_widget->draw(mapRect.rect, DrawPoolType::FOREGROUND);
|
||||
m_widget->draw(rect, DrawPoolType::FOREGROUND);
|
||||
}
|
||||
|
||||
void Tile::setWidget(const UIWidgetPtr& widget) {
|
||||
|
|
@ -160,7 +160,7 @@ void Tile::setWidget(const UIWidgetPtr& widget) {
|
|||
m_widget = widget;
|
||||
m_widget->setClipping(true);
|
||||
g_dispatcher.scheduleEvent([tile = static_self_cast<Tile>()] {
|
||||
g_ui.getMapWidget()->addTile(tile);
|
||||
g_ui.getMapWidget()->getMapView()->addForegroundTile(tile);
|
||||
}, g_game.getServerBeat());
|
||||
}
|
||||
|
||||
|
|
@ -181,7 +181,7 @@ void Tile::clean()
|
|||
#endif
|
||||
)) {
|
||||
g_dispatcher.scheduleEvent([tile = static_self_cast<Tile>()] {
|
||||
g_ui.getMapWidget()->removeTile(tile);
|
||||
g_ui.getMapWidget()->getMapView()->removeForegroundTile(tile);
|
||||
}, g_game.getServerBeat());
|
||||
}
|
||||
|
||||
|
|
@ -849,24 +849,18 @@ bool Tile::canRender(uint32_t& flags, const Position& cameraPosition, const Awar
|
|||
}
|
||||
|
||||
#ifndef BOT_PROTECTION
|
||||
void Tile::drawTexts(const Point& dest, const MapPosInfo& mapRect)
|
||||
void Tile::drawTexts(Point dest)
|
||||
{
|
||||
Point p = dest - mapRect.drawOffset;
|
||||
p.x *= mapRect.horizontalStretchFactor;
|
||||
p.y *= mapRect.verticalStretchFactor;
|
||||
p += mapRect.rect.topLeft();
|
||||
p.y += 5;
|
||||
|
||||
if (m_timerText && g_clock.millis() < m_timer) {
|
||||
if (m_text && m_text->hasText())
|
||||
p.y -= 8;
|
||||
dest.y -= 8;
|
||||
m_timerText->setText(stdext::format("%.01f", (m_timer - g_clock.millis()) / 1000.));
|
||||
m_timerText->drawText(p, Rect(p.x - 64, p.y - 64, 128, 128));
|
||||
p.y += 16;
|
||||
m_timerText->drawText(dest, Rect(dest.x - 64, dest.y - 64, 128, 128));
|
||||
dest.y += 16;
|
||||
}
|
||||
|
||||
if (m_text && m_text->hasText()) {
|
||||
m_text->drawText(p, Rect(p.x - 64, p.y - 64, 128, 128));
|
||||
m_text->drawText(dest, Rect(dest.x - 64, dest.y - 64, 128, 128));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -875,7 +869,7 @@ void Tile::setText(const std::string& text, Color color)
|
|||
if (!m_text) {
|
||||
m_text = std::make_shared<StaticText>();
|
||||
g_dispatcher.scheduleEvent([tile = static_self_cast<Tile>()] {
|
||||
g_ui.getMapWidget()->addTile(tile);
|
||||
g_ui.getMapWidget()->getMapView()->addForegroundTile(tile);
|
||||
}, g_game.getServerBeat());
|
||||
}
|
||||
|
||||
|
|
@ -898,7 +892,7 @@ void Tile::setTimer(int time, Color color)
|
|||
if (!m_timerText) {
|
||||
m_timerText = std::make_shared<StaticText>();
|
||||
g_dispatcher.scheduleEvent([tile = static_self_cast<Tile>()] {
|
||||
g_ui.getMapWidget()->addTile(tile);
|
||||
g_ui.getMapWidget()->getMapView()->addForegroundTile(tile);
|
||||
}, g_game.getServerBeat());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ public:
|
|||
ThingPtr getTopMultiUseThing();
|
||||
|
||||
bool hasWidget() const { return m_widget != nullptr; }
|
||||
void drawWidget(const Point& dest, const MapPosInfo& mapRect);
|
||||
void drawWidget(const Point& dest, const Rect& rect);
|
||||
void setWidget(const UIWidgetPtr& widget);
|
||||
UIWidgetPtr getWidget() { return m_widget; }
|
||||
void removeWidget();
|
||||
|
|
@ -212,7 +212,7 @@ public:
|
|||
bool checkForDetachableThing();
|
||||
|
||||
#ifndef BOT_PROTECTION
|
||||
void drawTexts(const Point& dest, const MapPosInfo& mapRect);
|
||||
void drawTexts(Point dest);
|
||||
void setText(const std::string& text, Color color);
|
||||
std::string getText();
|
||||
void setTimer(int time, Color color);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
*/
|
||||
|
||||
#include "uimap.h"
|
||||
#include <framework/core/eventdispatcher.h>
|
||||
#include <framework/core/graphicalapplication.h>
|
||||
#include <framework/graphics/drawpoolmanager.h>
|
||||
#include <framework/graphics/graphics.h>
|
||||
|
|
@ -60,25 +61,19 @@ void UIMap::drawSelf(DrawPoolType drawPane)
|
|||
return;
|
||||
}
|
||||
|
||||
if (m_mapView && drawPane == DrawPoolType::FOREGROUND_TILE) {
|
||||
g_drawPool.use(DrawPoolType::FOREGROUND_TILE);
|
||||
for (const auto& tile : m_tiles) {
|
||||
const auto& dest = m_mapView->transformPositionTo2D(tile->getPosition(), m_mapView->getCameraPosition());
|
||||
#ifndef BOT_PROTECTION
|
||||
tile->drawTexts(dest, m_mapView->m_posInfo);
|
||||
#endif
|
||||
tile->drawWidget(dest, m_mapView->m_posInfo);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& mapSize = g_app.isScaled() ? Rect(0, 0, g_graphics.getViewportSize()) : m_mapRect;
|
||||
m_mapView->updateRect(mapSize);
|
||||
const auto& mapRect = g_app.isScaled() ? Rect(0, 0, g_graphics.getViewportSize()) : m_mapRect;
|
||||
|
||||
if (drawPane == DrawPoolType::MAP) {
|
||||
m_mapView->draw();
|
||||
} else if (drawPane == DrawPoolType::TEXT) {
|
||||
m_mapView->drawText();
|
||||
m_mapView->updateRect(mapRect);
|
||||
g_drawPool.preDraw(drawPane, [this, &mapRect] {
|
||||
m_mapView->registerEvents();
|
||||
m_mapView->draw(mapRect);
|
||||
}, m_mapView->m_posInfo.rect, m_mapView->m_posInfo.srcRect, Color::black);
|
||||
} else if (drawPane == DrawPoolType::FOREGROUND_MAP) {
|
||||
g_textDispatcher.poll();
|
||||
g_drawPool.preDraw(drawPane, [this, &mapRect] {
|
||||
m_mapView->drawForeground(mapRect);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -212,19 +207,4 @@ void UIMap::updateMapSize()
|
|||
updateVisibleDimension();
|
||||
}
|
||||
|
||||
void UIMap::addTile(const TilePtr& tile) {
|
||||
std::scoped_lock l(g_drawPool.get(DrawPoolType::FOREGROUND)->getMutex());
|
||||
|
||||
if (std::ranges::find(m_tiles, tile) == m_tiles.end())
|
||||
m_tiles.emplace_back(tile);
|
||||
}
|
||||
void UIMap::removeTile(const TilePtr& tile) {
|
||||
std::scoped_lock l(g_drawPool.get(DrawPoolType::FOREGROUND)->getMutex());
|
||||
const auto it = std::find(m_tiles.begin(), m_tiles.end(), tile);
|
||||
if (it == m_tiles.end())
|
||||
return;
|
||||
|
||||
m_tiles.erase(it);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et: */
|
||||
|
|
@ -93,11 +93,9 @@ public:
|
|||
void setDrawHighlightTarget(const bool enable) { m_mapView->setDrawHighlightTarget(enable); }
|
||||
void setAntiAliasingMode(const MapView::AntialiasingMode mode) { m_mapView->setAntiAliasingMode(mode); }
|
||||
void setFloorFading(const uint16_t v) { m_mapView->setFloorFading(v); }
|
||||
|
||||
void addTile(const TilePtr& tile);
|
||||
void removeTile(const TilePtr& tile);
|
||||
MapViewPtr getMapView() const { return m_mapView; }
|
||||
void clearTiles() {
|
||||
m_tiles.clear();
|
||||
m_mapView->m_foregroundTiles.clear();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
@ -109,7 +107,6 @@ private:
|
|||
void updateVisibleDimension();
|
||||
void updateMapSize();
|
||||
|
||||
std::vector<TilePtr> m_tiles;
|
||||
MapViewPtr m_mapView;
|
||||
Rect m_mapRect;
|
||||
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@
|
|||
#include <framework/core/eventdispatcher.h>
|
||||
#include <framework/platform/platformwindow.h>
|
||||
|
||||
void AdaptativeFrameCounter::update()
|
||||
bool AdaptativeFrameCounter::update()
|
||||
{
|
||||
const uint8_t maxFps = m_targetFps == 0 ? m_maxFps : std::clamp<uint8_t>(m_targetFps, 1, std::max<uint8_t>(m_maxFps, m_targetFps));
|
||||
const auto maxFps = m_targetFps == 0 ? m_maxFps : std::clamp<uint16_t>(m_targetFps, 1, std::max<uint16_t>(m_maxFps, m_targetFps));
|
||||
if (maxFps > 0) {
|
||||
const int32_t sleepPeriod = (getMaxPeriod(maxFps) - 1000) - m_timer.elapsed_micros();
|
||||
if (sleepPeriod > 0) stdext::microsleep(sleepPeriod);
|
||||
|
|
@ -37,15 +37,15 @@ void AdaptativeFrameCounter::update()
|
|||
++m_fpsCount;
|
||||
|
||||
if (m_fps == m_fpsCount)
|
||||
return;
|
||||
return false;
|
||||
|
||||
const uint32_t tickCount = stdext::millis();
|
||||
if (tickCount - m_interval <= 1000)
|
||||
return;
|
||||
return false;
|
||||
|
||||
m_fps = m_fpsCount;
|
||||
m_fpsCount = 0;
|
||||
m_interval = tickCount;
|
||||
|
||||
g_dispatcher.addEvent([this] { g_lua.callGlobalField("g_app", "onFps", getFps()); });
|
||||
return true;
|
||||
}
|
||||
|
|
@ -33,22 +33,31 @@ public:
|
|||
AdaptativeFrameCounter() : m_interval(stdext::millis()) { }
|
||||
|
||||
void init() { m_timer.restart(); }
|
||||
void update();
|
||||
bool update();
|
||||
|
||||
uint16_t getFps() const { return m_fps; }
|
||||
uint8_t getMaxFps() const { return m_maxFps; }
|
||||
uint8_t getTargetFps() const { return m_targetFps; }
|
||||
uint16_t getMaxFps() const { return m_maxFps; }
|
||||
uint16_t getTargetFps() const { return m_targetFps; }
|
||||
|
||||
void setMaxFps(const uint16_t max) { m_maxFps = max; }
|
||||
void setTargetFps(const uint16_t target) { m_targetFps = target; }
|
||||
void setTargetFps(const uint16_t target) { if (m_targetFps != target) m_targetFps = target; }
|
||||
|
||||
void resetTargetFps() { m_targetFps = 0; }
|
||||
|
||||
float getPercent() const {
|
||||
const float maxFps = std::clamp<uint16_t>(m_targetFps, 1, std::max<uint16_t>(m_maxFps, m_targetFps));
|
||||
return ((maxFps - m_fps) / maxFps) * 100.f;
|
||||
}
|
||||
|
||||
float getFpsPercent(float percent) const {
|
||||
return getFps() * (percent / 100);
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t getMaxPeriod(uint16_t fps) const { return 1000000u / fps; }
|
||||
|
||||
uint8_t m_maxFps{};
|
||||
uint8_t m_targetFps{ 60u };
|
||||
uint16_t m_maxFps{};
|
||||
uint16_t m_targetFps{ 60u };
|
||||
|
||||
uint16_t m_fps{};
|
||||
uint16_t m_fpsCount{};
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ protected:
|
|||
std::string m_charset{ "cp1252" };
|
||||
std::string m_organizationName{ "otbr" };
|
||||
std::string m_appName{ "OTClient - Redemption" };
|
||||
std::string m_appCompactName{ "otclient" };
|
||||
std::string m_appCompactName{ "otcr" };
|
||||
std::string m_startupOptions;
|
||||
|
||||
std::vector<std::string> m_startupArgs;
|
||||
|
|
|
|||
|
|
@ -26,11 +26,20 @@ AsyncDispatcher g_asyncDispatcher;
|
|||
|
||||
void AsyncDispatcher::init(uint8_t maxThreads)
|
||||
{
|
||||
/*
|
||||
* -1 = Graphic
|
||||
* 1 = Map and (Connection, Particle and Sound) Pool
|
||||
* 2 = Foreground UI
|
||||
* 3 = Foreground MAP
|
||||
* 4 = Extra, ex: pathfinder and lighting system
|
||||
*/
|
||||
const uint8_t minThreads = 4;
|
||||
|
||||
if (maxThreads == 0)
|
||||
maxThreads = 6;
|
||||
|
||||
// -2 = Main Thread and Map Thread
|
||||
int_fast8_t threads = std::clamp<int_fast8_t>(std::thread::hardware_concurrency() - 2, 1, maxThreads);
|
||||
// 2 = Min Threads
|
||||
int_fast8_t threads = std::clamp<int_fast8_t>(std::thread::hardware_concurrency() - 1, minThreads, maxThreads);
|
||||
while (--threads >= 0)
|
||||
m_threads.emplace_back([this] { m_ioService.run(); });
|
||||
}
|
||||
|
|
@ -45,9 +54,8 @@ void AsyncDispatcher::stop()
|
|||
|
||||
m_ioService.stop();
|
||||
|
||||
for (std::size_t i = 0; i < m_threads.size(); i++) {
|
||||
if (m_threads[i].joinable()) {
|
||||
m_threads[i].join();
|
||||
}
|
||||
for (auto& thread : m_threads) {
|
||||
if (thread.joinable())
|
||||
thread.join();
|
||||
}
|
||||
};
|
||||
|
|
@ -51,8 +51,8 @@ void EventDispatcher::shutdown()
|
|||
|
||||
void EventDispatcher::poll()
|
||||
{
|
||||
executeScheduledEvents();
|
||||
executeEvents();
|
||||
executeScheduledEvents();
|
||||
mergeEvents();
|
||||
}
|
||||
|
||||
|
|
@ -63,12 +63,9 @@ ScheduledEventPtr EventDispatcher::scheduleEvent(const std::function<void()>& ca
|
|||
|
||||
assert(delay >= 0);
|
||||
|
||||
const auto& scheduledEvent = std::make_shared<ScheduledEvent>(callback, delay, 1);
|
||||
const auto& thread = getThreadTask();
|
||||
std::scoped_lock lock(thread->mutex);
|
||||
|
||||
thread->scheduledEventList.emplace_back(scheduledEvent);
|
||||
return scheduledEvent;
|
||||
return thread->scheduledEventList.emplace_back(std::make_shared<ScheduledEvent>(callback, delay, 1));
|
||||
}
|
||||
|
||||
ScheduledEventPtr EventDispatcher::cycleEvent(const std::function<void()>& callback, int delay)
|
||||
|
|
@ -78,12 +75,9 @@ ScheduledEventPtr EventDispatcher::cycleEvent(const std::function<void()>& callb
|
|||
|
||||
assert(delay > 0);
|
||||
|
||||
const auto& scheduledEvent = std::make_shared<ScheduledEvent>(callback, delay, 0);
|
||||
const auto& thread = getThreadTask();
|
||||
std::scoped_lock lock(thread->mutex);
|
||||
|
||||
thread->scheduledEventList.emplace_back(scheduledEvent);
|
||||
return scheduledEvent;
|
||||
return thread->scheduledEventList.emplace_back(std::make_shared<ScheduledEvent>(callback, delay, 0));
|
||||
}
|
||||
|
||||
EventPtr EventDispatcher::addEvent(const std::function<void()>& callback)
|
||||
|
|
@ -96,13 +90,9 @@ EventPtr EventDispatcher::addEvent(const std::function<void()>& callback)
|
|||
return std::make_shared<Event>(nullptr);
|
||||
}
|
||||
|
||||
const auto& event = std::make_shared<Event>(callback);
|
||||
|
||||
const auto& thread = getThreadTask();
|
||||
std::scoped_lock lock(thread->mutex);
|
||||
thread->events.emplace_back(event);
|
||||
|
||||
return event;
|
||||
return thread->events.emplace_back(std::make_shared<Event>(callback));
|
||||
}
|
||||
|
||||
void EventDispatcher::executeEvents() {
|
||||
|
|
@ -113,7 +103,6 @@ void EventDispatcher::executeEvents() {
|
|||
for (const auto& event : m_eventList) {
|
||||
event->execute();
|
||||
}
|
||||
|
||||
m_eventList.clear();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -82,7 +82,8 @@ void GraphicalApplication::init(std::vector<std::string>& args, uint8_t asyncDis
|
|||
g_sounds.init();
|
||||
#endif
|
||||
|
||||
m_frameCounter.init();
|
||||
m_mapProcessFrameCounter.init();
|
||||
m_graphicFrameCounter.init();
|
||||
}
|
||||
|
||||
void GraphicalApplication::deinit()
|
||||
|
|
@ -134,13 +135,51 @@ void GraphicalApplication::run()
|
|||
|
||||
g_lua.callGlobalField("g_app", "onRun");
|
||||
|
||||
const auto& foreground = g_drawPool.get(DrawPoolType::FOREGROUND);
|
||||
const auto& foreground_tile = g_drawPool.get(DrawPoolType::FOREGROUND_TILE);
|
||||
const auto& txt = g_drawPool.get(DrawPoolType::TEXT);
|
||||
const auto& map = g_drawPool.get(DrawPoolType::MAP);
|
||||
std::condition_variable foregroundUICondition, foregroundMapCondition;
|
||||
|
||||
// clang c++20 dont support jthread
|
||||
std::thread t1([&]() {
|
||||
const auto& realFPS = [&] {
|
||||
m_mapProcessFrameCounter.setTargetFps(g_window.vsyncEnabled() || getMaxFps() || getTargetFps() ? 500u : 999u);
|
||||
return std::min<int>(m_graphicFrameCounter.getFps(), m_mapProcessFrameCounter.getFps());
|
||||
};
|
||||
|
||||
const auto& drawForeground = [&] {
|
||||
const auto& foregroundUI = g_drawPool.get(DrawPoolType::FOREGROUND);
|
||||
const auto& foregroundMap = g_drawPool.get(DrawPoolType::FOREGROUND_MAP);
|
||||
|
||||
if (foregroundUI->canRepaint()) {
|
||||
if (g_game.isOnline())
|
||||
foregroundUICondition.notify_one();
|
||||
else
|
||||
g_ui.render(DrawPoolType::FOREGROUND);
|
||||
}
|
||||
|
||||
if (g_game.isOnline() && foregroundMap->canRepaint())
|
||||
foregroundMapCondition.notify_one();
|
||||
};
|
||||
|
||||
// THREAD - FOREGROUND UI
|
||||
g_asyncDispatcher.dispatch([this, &condition = foregroundUICondition] {
|
||||
const auto& pool = g_drawPool.get(DrawPoolType::FOREGROUND);
|
||||
std::unique_lock lock(pool->getMutexPreDraw());
|
||||
condition.wait(lock, [this]() -> bool {
|
||||
g_ui.render(DrawPoolType::FOREGROUND);
|
||||
return m_stopping;
|
||||
});
|
||||
});
|
||||
|
||||
// THREAD - FOREGROUND MAP
|
||||
g_asyncDispatcher.dispatch([this, &condition = foregroundMapCondition] {
|
||||
const auto& pool = g_drawPool.get(DrawPoolType::FOREGROUND_MAP);
|
||||
std::unique_lock lock(pool->getMutexPreDraw());
|
||||
condition.wait(lock, [this]() -> bool {
|
||||
if (g_ui.m_mapWidget)
|
||||
g_ui.m_mapWidget->drawSelf(DrawPoolType::FOREGROUND_MAP);
|
||||
return m_stopping;
|
||||
});
|
||||
});
|
||||
|
||||
// THREAD - POOL & MAP
|
||||
g_asyncDispatcher.dispatch([&] {
|
||||
g_eventThreadId = std::this_thread::get_id();
|
||||
while (!m_stopping) {
|
||||
poll();
|
||||
|
|
@ -150,42 +189,20 @@ void GraphicalApplication::run()
|
|||
continue;
|
||||
}
|
||||
|
||||
/*if (g_drawPool.isDrawing()) {
|
||||
stdext::millisleep(1);
|
||||
continue;
|
||||
}*/
|
||||
|
||||
if (foreground->canRepaint()) {
|
||||
g_asyncDispatcher.dispatch([this, &foreground] {
|
||||
std::scoped_lock l(foreground->getMutex());
|
||||
g_ui.render(DrawPoolType::FOREGROUND);
|
||||
});
|
||||
}
|
||||
drawForeground();
|
||||
|
||||
if (g_game.isOnline()) {
|
||||
if (!g_ui.m_mapWidget)
|
||||
g_ui.m_mapWidget = g_ui.getRootWidget()->recursiveGetChildById("gameMapPanel")->static_self_cast<UIMap>();
|
||||
|
||||
if (txt->canRepaint() || foreground_tile->canRepaint()) {
|
||||
g_asyncDispatcher.dispatch([this, &txt] {
|
||||
std::scoped_lock l(txt->getMutex());
|
||||
g_textDispatcher.poll();
|
||||
|
||||
if (g_ui.m_mapWidget) {
|
||||
g_ui.m_mapWidget->drawSelf(DrawPoolType::TEXT);
|
||||
g_ui.m_mapWidget->drawSelf(DrawPoolType::FOREGROUND_TILE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
std::scoped_lock l(map->getMutex());
|
||||
g_ui.m_mapWidget->drawSelf(DrawPoolType::MAP);
|
||||
}
|
||||
g_ui.m_mapWidget->drawSelf(DrawPoolType::MAP);
|
||||
} else g_ui.m_mapWidget = nullptr;
|
||||
|
||||
stdext::millisleep(1);
|
||||
m_mapProcessFrameCounter.update();
|
||||
}
|
||||
|
||||
foregroundUICondition.notify_one();
|
||||
foregroundMapCondition.notify_one();
|
||||
});
|
||||
|
||||
m_running = true;
|
||||
|
|
@ -201,10 +218,13 @@ void GraphicalApplication::run()
|
|||
|
||||
// update screen pixels
|
||||
g_window.swapBuffers();
|
||||
m_frameCounter.update();
|
||||
}
|
||||
|
||||
t1.join();
|
||||
if (m_graphicFrameCounter.update()) {
|
||||
g_dispatcher.addEvent([this, fps = realFPS()] {
|
||||
g_lua.callGlobalField("g_app", "onFps", fps);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
m_stopping = false;
|
||||
m_running = false;
|
||||
|
|
@ -255,7 +275,7 @@ void GraphicalApplication::resize(const Size& size)
|
|||
|
||||
if (USE_FRAMEBUFFER) {
|
||||
g_drawPool.get(DrawPoolType::CREATURE_INFORMATION)->setFramebuffer(size);
|
||||
g_drawPool.get(DrawPoolType::TEXT)->setFramebuffer(size);
|
||||
g_drawPool.get(DrawPoolType::FOREGROUND_MAP)->setFramebuffer(size);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,14 +41,14 @@ public:
|
|||
void mainPoll();
|
||||
void close() override;
|
||||
|
||||
void setMaxFps(uint16_t maxFps) { m_frameCounter.setMaxFps(maxFps); }
|
||||
void setTargetFps(uint16_t targetFps) { m_frameCounter.setTargetFps(targetFps); }
|
||||
void setMaxFps(uint16_t maxFps) { m_graphicFrameCounter.setMaxFps(maxFps); }
|
||||
void setTargetFps(uint16_t targetFps) { m_graphicFrameCounter.setTargetFps(targetFps); }
|
||||
|
||||
uint16_t getFps() { return m_frameCounter.getFps(); }
|
||||
uint8_t getMaxFps() { return m_frameCounter.getMaxFps(); }
|
||||
uint8_t getTargetFps() { return m_frameCounter.getTargetFps(); }
|
||||
uint16_t getFps() { return m_graphicFrameCounter.getFps(); }
|
||||
uint8_t getMaxFps() { return m_graphicFrameCounter.getMaxFps(); }
|
||||
uint8_t getTargetFps() { return m_graphicFrameCounter.getTargetFps(); }
|
||||
|
||||
void resetTargetFps() { m_frameCounter.resetTargetFps(); }
|
||||
void resetTargetFps() { m_graphicFrameCounter.resetTargetFps(); }
|
||||
|
||||
bool isOnInputEvent() { return m_onInputEvent; }
|
||||
bool mustOptimize() {
|
||||
|
|
@ -112,7 +112,8 @@ private:
|
|||
float m_animatedTextScale{ PlatformWindow::DEFAULT_DISPLAY_DENSITY };
|
||||
float m_staticTextScale{ PlatformWindow::DEFAULT_DISPLAY_DENSITY };
|
||||
|
||||
AdaptativeFrameCounter m_frameCounter;
|
||||
AdaptativeFrameCounter m_mapProcessFrameCounter;
|
||||
AdaptativeFrameCounter m_graphicFrameCounter;
|
||||
};
|
||||
|
||||
extern GraphicalApplication g_app;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ DrawPool* DrawPool::create(const DrawPoolType type)
|
|||
} else {
|
||||
pool->m_alwaysGroupDrawings = true; // CREATURE_INFORMATION & TEXT
|
||||
|
||||
if (type == DrawPoolType::TEXT || type == DrawPoolType::FOREGROUND_TILE) {
|
||||
if (type == DrawPoolType::FOREGROUND_MAP) {
|
||||
pool->setFPS(FPS60);
|
||||
}
|
||||
}
|
||||
|
|
@ -49,7 +49,7 @@ DrawPool* DrawPool::create(const DrawPoolType type)
|
|||
return pool;
|
||||
}
|
||||
|
||||
void DrawPool::add(const Color& color, const TexturePtr& texture, DrawPool::DrawMethod& method,
|
||||
void DrawPool::add(const Color& color, const TexturePtr& texture, DrawPool::DrawMethod&& method,
|
||||
DrawMode drawMode, const DrawConductor& conductor, const CoordsBufferPtr& coordsBuffer)
|
||||
{
|
||||
updateHash(method, texture, color);
|
||||
|
|
@ -63,8 +63,8 @@ void DrawPool::add(const Color& color, const TexturePtr& texture, DrawPool::Draw
|
|||
if (m_alwaysGroupDrawings || conductor.agroup) {
|
||||
auto& coords = m_coords.try_emplace(m_state.hash, nullptr).first->second;
|
||||
if (!coords) {
|
||||
auto state = getState(method, texture, color);
|
||||
coords = m_objects[m_depthLevel][order].emplace_back(state).coords.get();
|
||||
auto state = getState(texture, color);
|
||||
coords = m_objects[order].emplace_back(std::move(state)).coords.get();
|
||||
}
|
||||
|
||||
if (coordsBuffer)
|
||||
|
|
@ -74,12 +74,12 @@ void DrawPool::add(const Color& color, const TexturePtr& texture, DrawPool::Draw
|
|||
} else {
|
||||
bool addNewObj = true;
|
||||
|
||||
auto& list = m_objects[m_depthLevel][order];
|
||||
auto& list = m_objects[order];
|
||||
if (!list.empty()) {
|
||||
auto& prevObj = list.back();
|
||||
if (prevObj.state.hash == m_state.hash) {
|
||||
if (prevObj.state == m_state) {
|
||||
if (!prevObj.coords)
|
||||
prevObj.addMethod(method);
|
||||
prevObj.addMethod(std::move(method));
|
||||
else if (coordsBuffer)
|
||||
prevObj.coords->append(coordsBuffer.get());
|
||||
else
|
||||
|
|
@ -90,11 +90,11 @@ void DrawPool::add(const Color& color, const TexturePtr& texture, DrawPool::Draw
|
|||
}
|
||||
|
||||
if (addNewObj) {
|
||||
auto state = getState(method, texture, color);
|
||||
auto state = getState(texture, color);
|
||||
if (coordsBuffer) {
|
||||
list.emplace_back(state).coords->append(coordsBuffer.get());
|
||||
list.emplace_back(std::move(state)).coords->append(coordsBuffer.get());
|
||||
} else
|
||||
list.emplace_back(drawMode, state, method);
|
||||
list.emplace_back(drawMode, std::move(state), std::move(method));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -143,38 +143,38 @@ void DrawPool::updateHash(const DrawPool::DrawMethod& method, const TexturePtr&
|
|||
{ // State Hash
|
||||
m_state.hash = 0;
|
||||
|
||||
if (m_bindedFramebuffers)
|
||||
stdext::hash_combine(m_state.hash, m_lastFramebufferId);
|
||||
|
||||
if (m_state.blendEquation != BlendEquation::ADD)
|
||||
stdext::hash_combine(m_state.hash, m_state.blendEquation);
|
||||
|
||||
if (m_state.clipRect.isValid())
|
||||
stdext::hash_union(m_state.hash, m_state.clipRect.hash());
|
||||
|
||||
if (m_state.compositionMode != CompositionMode::NORMAL)
|
||||
stdext::hash_combine(m_state.hash, m_state.compositionMode);
|
||||
|
||||
if (m_state.opacity < 1.f)
|
||||
stdext::hash_combine(m_state.hash, m_state.opacity);
|
||||
|
||||
if (m_state.clipRect.isValid())
|
||||
stdext::hash_union(m_state.hash, m_state.clipRect.hash());
|
||||
|
||||
if (m_state.shaderProgram)
|
||||
stdext::hash_combine(m_state.hash, m_state.shaderProgram->getProgramId());
|
||||
stdext::hash_union(m_state.hash, m_state.shaderProgram->hash());
|
||||
|
||||
if (m_state.transformMatrix != DEFAULT_MATRIX3)
|
||||
stdext::hash_union(m_state.hash, m_state.transformMatrix.hash());
|
||||
|
||||
if (m_bindedFramebuffers)
|
||||
stdext::hash_combine(m_state.hash, m_lastFramebufferId);
|
||||
|
||||
if (color != Color::white)
|
||||
stdext::hash_union(m_state.hash, color.hash());
|
||||
|
||||
if (texture)
|
||||
stdext::hash_union(m_state.hash, texture->hash());
|
||||
|
||||
if (hasFrameBuffer())
|
||||
stdext::hash_union(m_status.second, m_state.hash);
|
||||
}
|
||||
|
||||
if (hasFrameBuffer()) { // Method Hash
|
||||
if (hasFrameBuffer()) { // Pool Hash
|
||||
if (m_state.hash)
|
||||
stdext::hash_union(m_status.second, m_state.hash);
|
||||
|
||||
if (method.type == DrawPool::DrawMethodType::TRIANGLE) {
|
||||
if (!method.a.isNull()) stdext::hash_union(m_status.second, method.a.hash());
|
||||
if (!method.b.isNull()) stdext::hash_union(m_status.second, method.b.hash());
|
||||
|
|
@ -188,7 +188,7 @@ void DrawPool::updateHash(const DrawPool::DrawMethod& method, const TexturePtr&
|
|||
}
|
||||
}
|
||||
|
||||
DrawPool::PoolState DrawPool::getState(const DrawPool::DrawMethod& method, const TexturePtr& texture, const Color& color)
|
||||
DrawPool::PoolState DrawPool::getState(const TexturePtr& texture, const Color& color)
|
||||
{
|
||||
return PoolState{
|
||||
std::move(m_state.transformMatrix), m_state.opacity,
|
||||
|
|
@ -243,14 +243,12 @@ void DrawPool::setShaderProgram(const PainterShaderProgramPtr& shaderProgram, bo
|
|||
|
||||
void DrawPool::resetState()
|
||||
{
|
||||
for (auto& objs : m_objects) {
|
||||
for (auto& order : objs)
|
||||
order.clear();
|
||||
}
|
||||
|
||||
for (auto& objs : m_objects)
|
||||
objs.clear();
|
||||
m_objectsFlushed.clear();
|
||||
m_coords.clear();
|
||||
|
||||
m_state = {};
|
||||
m_depthLevel = 0;
|
||||
m_status.second = 0;
|
||||
m_lastFramebufferId = 0;
|
||||
m_shaderRefreshDelay = 0;
|
||||
|
|
@ -259,6 +257,9 @@ void DrawPool::resetState()
|
|||
|
||||
bool DrawPool::canRepaint(const bool autoUpdateStatus)
|
||||
{
|
||||
if (!hasFrameBuffer())
|
||||
return true;
|
||||
|
||||
uint16_t refreshDelay = m_refreshDelay;
|
||||
if (m_shaderRefreshDelay > 0 && (m_refreshDelay == 0 || m_shaderRefreshDelay < m_refreshDelay))
|
||||
refreshDelay = m_shaderRefreshDelay;
|
||||
|
|
@ -364,7 +365,7 @@ void DrawPool::removeFramebuffer() {
|
|||
void DrawPool::addAction(const std::function<void()>& action)
|
||||
{
|
||||
const uint8_t order = m_type == DrawPoolType::MAP ? DrawOrder::THIRD : DrawOrder::FIRST;
|
||||
m_objects[m_depthLevel][order].emplace_back(action);
|
||||
m_objects[order].emplace_back(action);
|
||||
}
|
||||
|
||||
void DrawPool::bindFrameBuffer(const Size& size)
|
||||
|
|
|
|||
|
|
@ -29,20 +29,18 @@
|
|||
#include "texture.h"
|
||||
#include "framework/core/timer.h"
|
||||
#include <framework/platform/platformwindow.h>
|
||||
#include <framework/core/graphicalapplication.h>
|
||||
|
||||
#include "../stdext/storage.h"
|
||||
|
||||
#define MAX_DRAW_DEPTH 15
|
||||
|
||||
enum class DrawPoolType : uint8_t
|
||||
{
|
||||
MAP,
|
||||
CREATURE_INFORMATION,
|
||||
LIGHT,
|
||||
TEXT,
|
||||
FOREGROUND_TILE,
|
||||
FOREGROUND_MAP,
|
||||
FOREGROUND,
|
||||
UNKNOW
|
||||
LAST
|
||||
};
|
||||
|
||||
enum DrawOrder : uint8_t
|
||||
|
|
@ -99,7 +97,8 @@ public:
|
|||
void onBeforeDraw(std::function<void()> f) { m_beforeDraw = std::move(f); }
|
||||
void onAfterDraw(std::function<void()> f) { m_afterDraw = std::move(f); }
|
||||
|
||||
std::mutex& getMutex() { return m_mutex; }
|
||||
std::mutex& getMutex() { return m_mutexDraw; }
|
||||
std::mutex& getMutexPreDraw() { return m_mutexPreDraw; }
|
||||
|
||||
protected:
|
||||
|
||||
|
|
@ -140,11 +139,11 @@ protected:
|
|||
struct DrawObject
|
||||
{
|
||||
DrawObject(std::function<void()> action) : action(std::move(action)) {}
|
||||
DrawObject(PoolState& state) : state(std::move(state)), coords(std::make_unique<CoordsBuffer>()) {}
|
||||
DrawObject(const DrawMode drawMode, PoolState& state, DrawMethod& method) :
|
||||
DrawObject(PoolState&& state) : state(std::move(state)), coords(std::make_unique<CoordsBuffer>()) {}
|
||||
DrawObject(const DrawMode drawMode, PoolState&& state, DrawMethod&& method) :
|
||||
drawMode(drawMode), state(std::move(state)) { methods.emplace_back(std::move(method)); }
|
||||
|
||||
void addMethod(DrawMethod& method)
|
||||
void addMethod(DrawMethod&& method)
|
||||
{
|
||||
drawMode = DrawMode::TRIANGLES;
|
||||
methods.emplace_back(std::move(method));
|
||||
|
|
@ -180,7 +179,7 @@ private:
|
|||
STATE_BLEND_EQUATION = 1 << 4,
|
||||
};
|
||||
|
||||
void add(const Color& color, const TexturePtr& texture, DrawPool::DrawMethod& method,
|
||||
void add(const Color& color, const TexturePtr& texture, DrawPool::DrawMethod&& method,
|
||||
DrawMode drawMode = DrawMode::TRIANGLES, const DrawConductor& conductor = DEFAULT_DRAW_CONDUCTOR,
|
||||
const CoordsBufferPtr& coordsBuffer = nullptr);
|
||||
|
||||
|
|
@ -191,7 +190,7 @@ private:
|
|||
inline void setFPS(uint16_t fps) { m_refreshDelay = fps; }
|
||||
|
||||
void updateHash(const DrawPool::DrawMethod& method, const TexturePtr& texture, const Color& color);
|
||||
PoolState getState(const DrawPool::DrawMethod& method, const TexturePtr& texture, const Color& color);
|
||||
PoolState getState(const TexturePtr& texture, const Color& color);
|
||||
|
||||
float getOpacity() const { return m_state.opacity; }
|
||||
Rect getClipRect() { return m_state.clipRect; }
|
||||
|
|
@ -220,8 +219,25 @@ private:
|
|||
void flush()
|
||||
{
|
||||
m_coords.clear();
|
||||
if (m_depthLevel < MAX_DRAW_DEPTH)
|
||||
++m_depthLevel;
|
||||
for (auto& objs : m_objects) {
|
||||
m_objectsFlushed.insert(m_objectsFlushed.end(), make_move_iterator(objs.begin()), make_move_iterator(objs.end()));
|
||||
objs.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void release(bool draw = true) {
|
||||
m_objectsDraw.clear();
|
||||
if (draw) {
|
||||
if (!m_objectsFlushed.empty())
|
||||
m_objectsDraw.insert(m_objectsDraw.end(), make_move_iterator(m_objectsFlushed.begin()), make_move_iterator(m_objectsFlushed.end()));
|
||||
|
||||
for (auto& objs : m_objects) {
|
||||
m_objectsDraw.insert(m_objectsDraw.end(), make_move_iterator(objs.begin()), make_move_iterator(objs.end()));
|
||||
objs.clear();
|
||||
}
|
||||
}
|
||||
|
||||
m_objectsFlushed.clear();
|
||||
}
|
||||
|
||||
bool canRepaint(bool autoUpdateStatus);
|
||||
|
|
@ -232,7 +248,6 @@ private:
|
|||
bool m_alwaysGroupDrawings{ false };
|
||||
|
||||
int_fast8_t m_bindedFramebuffers{ -1 };
|
||||
uint8_t m_depthLevel{ 0 };
|
||||
|
||||
uint16_t m_refreshDelay{ 0 }, m_shaderRefreshDelay{ 0 };
|
||||
uint32_t m_onlyOnceStateFlag{ 0 };
|
||||
|
|
@ -240,7 +255,7 @@ private:
|
|||
|
||||
PoolState m_state, m_oldState;
|
||||
|
||||
DrawPoolType m_type{ DrawPoolType::UNKNOW };
|
||||
DrawPoolType m_type{ DrawPoolType::LAST };
|
||||
|
||||
Timer m_refreshTimer;
|
||||
|
||||
|
|
@ -248,7 +263,10 @@ private:
|
|||
|
||||
std::vector<Matrix3> m_transformMatrixStack;
|
||||
std::vector<FrameBufferPtr> m_temporaryFramebuffers;
|
||||
std::vector<DrawObject> m_objects[MAX_DRAW_DEPTH + 1][static_cast<uint8_t>(DrawOrder::LAST)];
|
||||
|
||||
std::vector<DrawObject> m_objects[static_cast<uint8_t>(DrawOrder::LAST)];
|
||||
std::vector<DrawObject> m_objectsFlushed;
|
||||
std::vector<DrawObject> m_objectsDraw;
|
||||
|
||||
stdext::map<size_t, CoordsBuffer*> m_coords;
|
||||
|
||||
|
|
@ -260,7 +278,9 @@ private:
|
|||
std::function<void()> m_beforeDraw;
|
||||
std::function<void()> m_afterDraw;
|
||||
|
||||
std::mutex m_mutex;
|
||||
std::atomic_bool m_repaint{ false };
|
||||
std::mutex m_mutexDraw;
|
||||
std::mutex m_mutexPreDraw;
|
||||
|
||||
friend class DrawPoolManager;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ void DrawPoolManager::init(uint16_t spriteSize)
|
|||
m_spriteSize = spriteSize;
|
||||
|
||||
// Create Pools
|
||||
for (int8_t i = -1; ++i <= static_cast<uint8_t>(DrawPoolType::UNKNOW);) {
|
||||
for (int8_t i = -1; ++i < static_cast<uint8_t>(DrawPoolType::LAST);) {
|
||||
m_pools[i] = DrawPool::create(static_cast<DrawPoolType>(i));
|
||||
}
|
||||
}
|
||||
|
|
@ -41,7 +41,7 @@ void DrawPoolManager::init(uint16_t spriteSize)
|
|||
void DrawPoolManager::terminate() const
|
||||
{
|
||||
// Destroy Pools
|
||||
for (int_fast8_t i = -1; ++i <= static_cast<uint8_t>(DrawPoolType::UNKNOW);) {
|
||||
for (int_fast8_t i = -1; ++i < static_cast<uint8_t>(DrawPoolType::LAST);) {
|
||||
delete m_pools[i];
|
||||
}
|
||||
}
|
||||
|
|
@ -57,62 +57,16 @@ void DrawPoolManager::draw()
|
|||
g_painter->setResolution(m_size, m_transformMatrix);
|
||||
}
|
||||
|
||||
// m_drawing = true;
|
||||
for (auto pool : m_pools) {
|
||||
if (pool->getType() == DrawPoolType::CREATURE_INFORMATION)
|
||||
continue;
|
||||
|
||||
const auto& map = get(DrawPoolType::MAP); {
|
||||
std::scoped_lock l(map->m_mutex);
|
||||
if (drawPool(map)) {
|
||||
std::scoped_lock l(pool->m_mutexDraw);
|
||||
drawPool(pool);
|
||||
|
||||
if (pool->getType() == DrawPoolType::MAP)
|
||||
drawPool(get(DrawPoolType::CREATURE_INFORMATION));
|
||||
drawPool(get(DrawPoolType::LIGHT));
|
||||
}
|
||||
}
|
||||
|
||||
const auto& text = get(DrawPoolType::TEXT); {
|
||||
std::scoped_lock l(text->m_mutex);
|
||||
drawPool(text);
|
||||
drawPool(get(DrawPoolType::FOREGROUND_TILE));
|
||||
}
|
||||
|
||||
const auto& foreground = get(DrawPoolType::FOREGROUND); {
|
||||
std::scoped_lock l(foreground->m_mutex);
|
||||
drawPool(foreground);
|
||||
}
|
||||
|
||||
// m_drawing = false;
|
||||
}
|
||||
|
||||
bool DrawPoolManager::drawPool(DrawPool* pool) {
|
||||
if (!pool->isEnabled())
|
||||
return false;
|
||||
|
||||
if (!pool->hasFrameBuffer()) {
|
||||
for (const auto& obj : pool->m_objects[0][DrawOrder::FIRST]) {
|
||||
drawObject(obj);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!pool->m_framebuffer->canDraw())
|
||||
return false;
|
||||
|
||||
if (pool->canRepaint(true)) {
|
||||
pool->m_framebuffer->bind();
|
||||
for (int_fast8_t i = -1; ++i <= pool->m_depthLevel;) {
|
||||
for (const auto& order : pool->m_objects[i])
|
||||
for (const auto& obj : order)
|
||||
drawObject(obj);
|
||||
}
|
||||
|
||||
pool->m_framebuffer->release();
|
||||
}
|
||||
|
||||
g_painter->resetState();
|
||||
|
||||
if (pool->m_beforeDraw) pool->m_beforeDraw();
|
||||
pool->m_framebuffer->draw();
|
||||
if (pool->m_afterDraw) pool->m_afterDraw();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DrawPoolManager::drawObject(const DrawPool::DrawObject& obj)
|
||||
|
|
@ -135,8 +89,7 @@ void DrawPoolManager::drawObject(const DrawPool::DrawObject& obj)
|
|||
|
||||
void DrawPoolManager::addTexturedCoordsBuffer(const TexturePtr& texture, const CoordsBufferPtr& coords, const Color& color) const
|
||||
{
|
||||
DrawPool::DrawMethod method;
|
||||
getCurrentPool()->add(color, texture, method, DrawMode::TRIANGLE_STRIP, DEFAULT_DRAW_CONDUCTOR, coords);
|
||||
getCurrentPool()->add(color, texture, DrawPool::DrawMethod{}, DrawMode::TRIANGLE_STRIP, DEFAULT_DRAW_CONDUCTOR, coords);
|
||||
}
|
||||
|
||||
void DrawPoolManager::addTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src, const Color& color, const DrawConductor& condutor) const
|
||||
|
|
@ -144,12 +97,10 @@ void DrawPoolManager::addTexturedRect(const Rect& dest, const TexturePtr& textur
|
|||
if (dest.isEmpty() || src.isEmpty())
|
||||
return;
|
||||
|
||||
DrawPool::DrawMethod method{
|
||||
getCurrentPool()->add(color, texture, DrawPool::DrawMethod{
|
||||
.type = DrawPool::DrawMethodType::RECT,
|
||||
.dest = dest, .src = src
|
||||
};
|
||||
|
||||
getCurrentPool()->add(color, texture, method, DrawMode::TRIANGLE_STRIP, condutor);
|
||||
}, DrawMode::TRIANGLE_STRIP, condutor);
|
||||
}
|
||||
|
||||
void DrawPoolManager::addUpsideDownTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src, const Color& color) const
|
||||
|
|
@ -157,9 +108,7 @@ void DrawPoolManager::addUpsideDownTexturedRect(const Rect& dest, const TextureP
|
|||
if (dest.isEmpty() || src.isEmpty())
|
||||
return;
|
||||
|
||||
DrawPool::DrawMethod method{ DrawPool::DrawMethodType::UPSIDEDOWN_RECT, dest, src };
|
||||
|
||||
getCurrentPool()->add(color, texture, method, DrawMode::TRIANGLE_STRIP);
|
||||
getCurrentPool()->add(color, texture, DrawPool::DrawMethod{ DrawPool::DrawMethodType::UPSIDEDOWN_RECT, dest, src }, DrawMode::TRIANGLE_STRIP);
|
||||
}
|
||||
|
||||
void DrawPoolManager::addTexturedRepeatedRect(const Rect& dest, const TexturePtr& texture, const Rect& src, const Color& color) const
|
||||
|
|
@ -167,9 +116,7 @@ void DrawPoolManager::addTexturedRepeatedRect(const Rect& dest, const TexturePtr
|
|||
if (dest.isEmpty() || src.isEmpty())
|
||||
return;
|
||||
|
||||
DrawPool::DrawMethod method{ DrawPool::DrawMethodType::REPEATED_RECT, dest, src };
|
||||
|
||||
getCurrentPool()->add(color, texture, method);
|
||||
getCurrentPool()->add(color, texture, DrawPool::DrawMethod{ DrawPool::DrawMethodType::REPEATED_RECT, dest, src });
|
||||
}
|
||||
|
||||
void DrawPoolManager::addFilledRect(const Rect& dest, const Color& color, const DrawConductor& condutor) const
|
||||
|
|
@ -177,9 +124,7 @@ void DrawPoolManager::addFilledRect(const Rect& dest, const Color& color, const
|
|||
if (dest.isEmpty())
|
||||
return;
|
||||
|
||||
DrawPool::DrawMethod method{ DrawPool::DrawMethodType::RECT, dest };
|
||||
|
||||
getCurrentPool()->add(color, nullptr, method, DrawMode::TRIANGLES, condutor);
|
||||
getCurrentPool()->add(color, nullptr, DrawPool::DrawMethod{ DrawPool::DrawMethodType::RECT, dest }, DrawMode::TRIANGLES, condutor);
|
||||
}
|
||||
|
||||
void DrawPoolManager::addFilledTriangle(const Point& a, const Point& b, const Point& c, const Color& color) const
|
||||
|
|
@ -187,9 +132,12 @@ void DrawPoolManager::addFilledTriangle(const Point& a, const Point& b, const Po
|
|||
if (a == b || a == c || b == c)
|
||||
return;
|
||||
|
||||
DrawPool::DrawMethod method{ .type = DrawPool::DrawMethodType::TRIANGLE, .a = a, .b = b, .c = c };
|
||||
|
||||
getCurrentPool()->add(color, nullptr, method);
|
||||
getCurrentPool()->add(color, nullptr, DrawPool::DrawMethod{
|
||||
.type = DrawPool::DrawMethodType::TRIANGLE,
|
||||
.a = a,
|
||||
.b = b,
|
||||
.c = c
|
||||
});
|
||||
}
|
||||
|
||||
void DrawPoolManager::addBoundingRect(const Rect& dest, const Color& color, uint16_t innerLineWidth) const
|
||||
|
|
@ -197,30 +145,69 @@ void DrawPoolManager::addBoundingRect(const Rect& dest, const Color& color, uint
|
|||
if (dest.isEmpty() || innerLineWidth == 0)
|
||||
return;
|
||||
|
||||
DrawPool::DrawMethod method{
|
||||
getCurrentPool()->add(color, nullptr, DrawPool::DrawMethod{
|
||||
.type = DrawPool::DrawMethodType::BOUNDING_RECT,
|
||||
.dest = dest,
|
||||
.intValue = innerLineWidth
|
||||
};
|
||||
|
||||
getCurrentPool()->add(color, nullptr, method);
|
||||
});
|
||||
}
|
||||
|
||||
void DrawPoolManager::use(const DrawPoolType type, const Rect& dest, const Rect& src, const Color& colorClear)
|
||||
void DrawPoolManager::preDraw(const DrawPoolType type, const std::function<void()>& f, const Rect& dest, const Rect& src, const Color& colorClear)
|
||||
{
|
||||
select(type);
|
||||
const auto pool = getCurrentPool();
|
||||
|
||||
auto* currentPoll = getCurrentPool();
|
||||
if (pool->hasFrameBuffer() && pool->m_repaint.load())
|
||||
return;
|
||||
|
||||
currentPoll->setEnable(true);
|
||||
currentPoll->resetState();
|
||||
pool->resetState();
|
||||
|
||||
if (currentPoll->hasFrameBuffer()) {
|
||||
currentPoll->m_framebuffer->prepare(dest, src, colorClear);
|
||||
|
||||
// when the selected pool is MAP, reset the creature information state.
|
||||
if (type == DrawPoolType::MAP) {
|
||||
get(DrawPoolType::CREATURE_INFORMATION)->resetState();
|
||||
}
|
||||
// when the selected pool is MAP, reset the creature information state.
|
||||
if (type == DrawPoolType::MAP) {
|
||||
get(DrawPoolType::CREATURE_INFORMATION)->resetState();
|
||||
}
|
||||
|
||||
if (f) f();
|
||||
|
||||
std::scoped_lock l(pool->m_mutexDraw);
|
||||
|
||||
pool->setEnable(true);
|
||||
if (pool->hasFrameBuffer())
|
||||
pool->m_framebuffer->prepare(dest, src, colorClear);
|
||||
|
||||
pool->release(pool->m_repaint = pool->canRepaint(true));
|
||||
|
||||
if (type == DrawPoolType::MAP) {
|
||||
get(DrawPoolType::CREATURE_INFORMATION)->release();
|
||||
}
|
||||
}
|
||||
|
||||
void DrawPoolManager::drawPool(DrawPool* pool) {
|
||||
if (!pool->isEnabled())
|
||||
return;
|
||||
|
||||
if (!pool->hasFrameBuffer()) {
|
||||
for (const auto& obj : pool->m_objectsDraw) {
|
||||
drawObject(obj);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pool->m_framebuffer->canDraw())
|
||||
return;
|
||||
|
||||
if (pool->m_repaint) {
|
||||
pool->m_repaint.store(false);
|
||||
|
||||
pool->m_framebuffer->bind();
|
||||
for (const auto& obj : pool->m_objectsDraw)
|
||||
drawObject(obj);
|
||||
pool->m_framebuffer->release();
|
||||
}
|
||||
|
||||
g_painter->resetState();
|
||||
|
||||
if (pool->m_beforeDraw) pool->m_beforeDraw();
|
||||
pool->m_framebuffer->draw();
|
||||
if (pool->m_afterDraw) pool->m_afterDraw();
|
||||
}
|
||||
|
|
@ -33,8 +33,8 @@ public:
|
|||
DrawPool* get(const DrawPoolType type) const { return m_pools[static_cast<uint8_t>(type)]; }
|
||||
|
||||
void select(DrawPoolType type);
|
||||
void use(const DrawPoolType type) { use(type, {}, {}); }
|
||||
void use(DrawPoolType type, const Rect& dest, const Rect& src, const Color& colorClear = Color::alpha);
|
||||
void preDraw(const DrawPoolType type, const std::function<void()>& f) { return preDraw(type, f, {}, {}); }
|
||||
void preDraw(DrawPoolType type, const std::function<void()>& f, const Rect& dest, const Rect& src, const Color& colorClear = Color::alpha);
|
||||
|
||||
void addTexturedPoint(const TexturePtr& texture, const Point& point, const Color& color = Color::white) const
|
||||
{ addTexturedRect(Rect(point, texture->getSize()), texture, color); }
|
||||
|
|
@ -93,8 +93,6 @@ public:
|
|||
|
||||
DrawPoolType getCurrentType() const { return getCurrentPool()->m_type; }
|
||||
|
||||
bool isDrawing() const { return m_drawing; }
|
||||
|
||||
private:
|
||||
DrawPool* getCurrentPool() const;
|
||||
|
||||
|
|
@ -103,12 +101,10 @@ private:
|
|||
void terminate() const;
|
||||
void drawObject(const DrawPool::DrawObject& obj);
|
||||
|
||||
bool drawPool(DrawPool* pool);
|
||||
|
||||
std::atomic_bool m_drawing{ false };
|
||||
void drawPool(DrawPool* pool);
|
||||
|
||||
CoordsBuffer m_coordsBuffer;
|
||||
std::array<DrawPool*, static_cast<uint8_t>(DrawPoolType::UNKNOW) + 1> m_pools{};
|
||||
std::array<DrawPool*, static_cast<uint8_t>(DrawPoolType::LAST)> m_pools{};
|
||||
|
||||
Size m_size;
|
||||
Matrix3 m_transformMatrix;
|
||||
|
|
|
|||
|
|
@ -41,7 +41,9 @@ public:
|
|||
|
||||
bool resize(const Size& size);
|
||||
bool isValid() const { return m_texture != nullptr; }
|
||||
bool canDraw() const { return m_coordsBuffer.getVertexCount() > 0; }
|
||||
bool canDraw() const {
|
||||
return m_texture && m_coordsBuffer.getVertexCount() > 0;
|
||||
}
|
||||
TexturePtr getTexture() const { return m_texture; }
|
||||
Size getSize() const { return m_texture->getSize(); }
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ void Graphics::init()
|
|||
|
||||
m_ok = true;
|
||||
|
||||
g_painter = new Painter;
|
||||
g_painter = std::make_unique<Painter>();
|
||||
|
||||
g_textures.init();
|
||||
}
|
||||
|
|
@ -87,9 +87,6 @@ void Graphics::terminate()
|
|||
g_fonts.terminate();
|
||||
g_textures.terminate();
|
||||
|
||||
delete g_painter;
|
||||
g_painter = nullptr;
|
||||
|
||||
m_ok = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
#include "shader/shadersources.h"
|
||||
|
||||
Painter* g_painter = nullptr;
|
||||
std::unique_ptr<Painter> g_painter = nullptr;
|
||||
|
||||
/**
|
||||
* Painter using OpenGL 2.0 programmable rendering pipeline,
|
||||
|
|
|
|||
|
|
@ -142,4 +142,4 @@ protected:
|
|||
PainterShaderProgramPtr m_drawReplaceColorProgram;
|
||||
};
|
||||
|
||||
extern Painter* g_painter;
|
||||
extern std::unique_ptr<Painter> g_painter;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "graphics.h"
|
||||
|
||||
#include <framework/core/application.h>
|
||||
#include <framework/stdext/hash.h>
|
||||
|
||||
uint32_t ShaderProgram::m_currentProgram = 0;
|
||||
|
||||
|
|
@ -48,6 +49,7 @@ bool ShaderProgram::addShader(const ShaderPtr& shader)
|
|||
glAttachShader(m_programId, shader->getShaderId());
|
||||
m_linked = false;
|
||||
m_shaders.emplace_back(shader);
|
||||
m_hash = stdext::hash_int(m_programId);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -80,6 +82,7 @@ void ShaderProgram::removeShader(const ShaderPtr& shader)
|
|||
glDetachShader(m_programId, shader->getShaderId());
|
||||
m_shaders.erase(it);
|
||||
m_linked = false;
|
||||
m_hash = 0;
|
||||
}
|
||||
|
||||
void ShaderProgram::removeAllShaders()
|
||||
|
|
|
|||
|
|
@ -109,11 +109,13 @@ public:
|
|||
|
||||
bool isLinked() const { return m_linked; }
|
||||
uint32_t getProgramId() const { return m_programId; }
|
||||
size_t hash() const { return m_hash; }
|
||||
ShaderList getShaders() { return m_shaders; }
|
||||
|
||||
private:
|
||||
bool m_linked{ false };
|
||||
uint32_t m_programId;
|
||||
size_t m_hash{ 0 };
|
||||
static uint32_t m_currentProgram;
|
||||
ShaderList m_shaders;
|
||||
std::array<int, MAX_UNIFORM_LOCATIONS> m_uniformLocations{ };
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "win32window.h"
|
||||
#include <client/map.h>
|
||||
#include <framework/core/application.h>
|
||||
#include <framework/core/graphicalapplication.h>
|
||||
#include <framework/core/eventdispatcher.h>
|
||||
#include <framework/core/resourcemanager.h>
|
||||
#include <framework/graphics/image.h>
|
||||
|
|
@ -936,8 +937,9 @@ void WIN32Window::setFullscreen(bool fullscreen)
|
|||
|
||||
void WIN32Window::setVerticalSync(bool enable)
|
||||
{
|
||||
g_mainDispatcher.addEvent([&, enable] {
|
||||
m_vsync = enable;
|
||||
m_vsync = enable;
|
||||
|
||||
g_mainDispatcher.addEvent([this, enable] {
|
||||
#ifdef OPENGL_ES
|
||||
eglSwapInterval(m_eglDisplay, enable);
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -59,8 +59,12 @@ void UIManager::terminate()
|
|||
|
||||
void UIManager::render(DrawPoolType drawPane) const
|
||||
{
|
||||
if (drawPane == DrawPoolType::FOREGROUND)
|
||||
g_drawPool.use(DrawPoolType::FOREGROUND, { 0,0, g_graphics.getViewportSize() }, {});
|
||||
if (drawPane == DrawPoolType::FOREGROUND) {
|
||||
g_drawPool.preDraw(DrawPoolType::FOREGROUND, [this, drawPane] {
|
||||
m_rootWidget->draw(m_rootWidget->getRect(), drawPane);
|
||||
}, { 0,0, g_graphics.getViewportSize() }, {});
|
||||
return;
|
||||
}
|
||||
|
||||
m_rootWidget->draw(m_rootWidget->getRect(), drawPane);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1918,7 +1918,7 @@ void UIWidget::move(int x, int y) {
|
|||
self->m_rect = {}; // force update
|
||||
self->setRect(rect);
|
||||
self->setProp(PropUpdatingMove, false);
|
||||
}, 13);
|
||||
}, 8);
|
||||
}
|
||||
|
||||
m_rect = { x, y, getSize() };
|
||||
|
|
@ -1935,4 +1935,4 @@ void UIWidget::setShader(const std::string_view name) {
|
|||
});
|
||||
}
|
||||
|
||||
void UIWidget::repaint() { g_app.repaint(); }
|
||||
void UIWidget::repaint() { g_app.repaint(); }
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
#define GIT_BRANCH desenv
|
||||
#define GIT_VERSION 1.0
|
||||
#define GIT_VERSION 3.x
|
||||
#define GIT_COMMITS 0
|
||||
|
|
|
|||
|
|
@ -29,13 +29,13 @@
|
|||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<EnableUnitySupport>false</EnableUnitySupport>
|
||||
<EnableUnitySupport>true</EnableUnitySupport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<EnableUnitySupport>false</EnableUnitySupport>
|
||||
<EnableUnitySupport>true</EnableUnitySupport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
|
|
@ -142,6 +142,7 @@ cmd /c "start ../vcpkg_installed\$(VcpkgTriplet)\$(VcpkgTriplet)\tools\protobuf\
|
|||
<AdditionalIncludeDirectories>$(VcpkgRoot)\installed\$(VcpkgTriplet)\include\luajit;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
<DisableSpecificWarnings>4244;4251;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<CombineFilesOnlyFromTheSameFolder>true</CombineFilesOnlyFromTheSameFolder>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue