feat: Drawpool 3.0

This commit is contained in:
Renato Machado 2023-11-27 14:40:05 -03:00 committed by GitHub
parent 674ad54275
commit 94fbbbc8a6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 561 additions and 505 deletions

View file

@ -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"))

View file

@ -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

View file

@ -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);

View file

@ -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();

View file

@ -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;
};

View file

@ -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)

View file

@ -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);
}

View file

@ -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;

View file

@ -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());
}

View file

@ -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);

View file

@ -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: */

View file

@ -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;

View file

@ -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;
}

View file

@ -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{};

View file

@ -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;

View file

@ -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();
}
};

View file

@ -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();
}

View file

@ -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);
}
});
}

View file

@ -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;

View file

@ -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)

View file

@ -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;
};

View file

@ -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();
}

View file

@ -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;

View file

@ -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(); }

View file

@ -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;
}

View file

@ -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,

View file

@ -142,4 +142,4 @@ protected:
PainterShaderProgramPtr m_drawReplaceColorProgram;
};
extern Painter* g_painter;
extern std::unique_ptr<Painter> g_painter;

View file

@ -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()

View file

@ -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{ };

View file

@ -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

View file

@ -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);
}

View file

@ -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(); }

View file

@ -1,3 +1,3 @@
#define GIT_BRANCH desenv
#define GIT_VERSION 1.0
#define GIT_VERSION 3.x
#define GIT_COMMITS 0

View file

@ -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>