Fix memory leaks
* Fix recursive reference memory leak in UIWidget * Make Event/ScheduledEvent memory-leak safe * Fix exit crashs by freeing graphics resources before destroying GL context * Add many asserts to avoid any leak regression
This commit is contained in:
parent
f650b0e5bb
commit
1c7bbaea89
|
@ -213,9 +213,12 @@ SET(framework_SOURCES ${framework_SOURCES}
|
|||
${CMAKE_CURRENT_LIST_DIR}/graphics/fontmanager.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/graphics/framebuffer.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/graphics/framebuffer.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/graphics/framebuffermanager.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/graphics/framebuffermanager.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/graphics/glutil.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/graphics/graphics.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/graphics/graphics.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/graphics/hardwarebuffer.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/graphics/hardwarebuffer.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/graphics/image.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/graphics/image.h
|
||||
|
|
|
@ -116,11 +116,8 @@ void Application::init(const std::vector<std::string>& args)
|
|||
m_initialized = true;
|
||||
}
|
||||
|
||||
void Application::terminate()
|
||||
void Application::deinit()
|
||||
{
|
||||
if(!m_initialized)
|
||||
return;
|
||||
|
||||
g_lua.callGlobalField("g_app", "onTerminate");
|
||||
|
||||
// hide the window because there is no render anymore
|
||||
|
@ -128,6 +125,7 @@ void Application::terminate()
|
|||
|
||||
// run modules unload events
|
||||
g_modules.unloadModules();
|
||||
g_modules.clear();
|
||||
|
||||
// release remaining lua object references
|
||||
g_lua.collectGarbage();
|
||||
|
@ -135,19 +133,20 @@ void Application::terminate()
|
|||
// poll remaining events
|
||||
poll();
|
||||
|
||||
// destroy any remaining widget
|
||||
g_ui.terminate();
|
||||
}
|
||||
|
||||
void Application::terminate()
|
||||
{
|
||||
assert(m_initialized);
|
||||
|
||||
// terminate network
|
||||
Connection::terminate();
|
||||
|
||||
// terminate graphics
|
||||
g_ui.terminate();
|
||||
g_window.terminate();
|
||||
|
||||
// terminate sound
|
||||
g_sounds.terminate();
|
||||
|
||||
// flush remaining dispatcher events
|
||||
g_eventDispatcher.flush();
|
||||
|
||||
// save configurations
|
||||
g_configs.save();
|
||||
|
||||
|
@ -157,15 +156,22 @@ void Application::terminate()
|
|||
// terminate script environment
|
||||
g_lua.terminate();
|
||||
|
||||
// flush remaining dispatcher events
|
||||
g_eventDispatcher.flush();
|
||||
|
||||
// terminate graphics
|
||||
m_foreground = nullptr;
|
||||
g_graphics.terminate();
|
||||
g_window.terminate();
|
||||
|
||||
g_logger.info("Application ended successfully.");
|
||||
|
||||
m_terminated = true;
|
||||
}
|
||||
|
||||
void Application::run()
|
||||
{
|
||||
if(!m_initialized)
|
||||
return;
|
||||
assert(m_initialized);
|
||||
|
||||
m_stopping = false;
|
||||
m_running = true;
|
||||
|
|
|
@ -39,6 +39,7 @@ public:
|
|||
|
||||
virtual void init(const std::vector<std::string>& args);
|
||||
virtual void registerLuaFunctions();
|
||||
virtual void deinit();
|
||||
virtual void terminate();
|
||||
virtual void run();
|
||||
virtual void exit();
|
||||
|
@ -53,6 +54,7 @@ public:
|
|||
|
||||
bool isRunning() { return m_running; }
|
||||
bool isStopping() { return m_stopping; }
|
||||
bool isTermianted() { return m_terminated; }
|
||||
bool isOnInputEvent() { return m_onInputEvent; }
|
||||
const std::string& getName() { return m_appName; }
|
||||
const std::string& getVersion() { return m_appVersion; }
|
||||
|
@ -76,6 +78,7 @@ protected:
|
|||
Boolean<false> m_initialized;
|
||||
Boolean<false> m_running;
|
||||
Boolean<false> m_stopping;
|
||||
Boolean<false> m_terminated;
|
||||
Boolean<false> m_onInputEvent;
|
||||
Boolean<false> m_mustRepaint;
|
||||
AdaptativeFrameCounter m_backgroundFrameCounter;
|
||||
|
|
|
@ -57,6 +57,11 @@ bool ConfigManager::save()
|
|||
return m_confsDoc->save(m_fileName);
|
||||
}
|
||||
|
||||
void ConfigManager::clear()
|
||||
{
|
||||
m_confsDoc->clear();
|
||||
}
|
||||
|
||||
void ConfigManager::set(const std::string& key, const std::string& value)
|
||||
{
|
||||
if(key == "") {
|
||||
|
|
|
@ -32,6 +32,7 @@ public:
|
|||
ConfigManager();
|
||||
bool load(const std::string& file);
|
||||
bool save();
|
||||
void clear();
|
||||
|
||||
void set(const std::string& key, const std::string& value);
|
||||
void setList(const std::string& key, const std::vector<std::string>& list);
|
||||
|
|
|
@ -32,8 +32,12 @@ void EventDispatcher::flush()
|
|||
while(!m_eventList.empty())
|
||||
poll();
|
||||
|
||||
while(!m_scheduledEventList.empty())
|
||||
while(!m_scheduledEventList.empty()) {
|
||||
ScheduledEventPtr scheduledEvent = m_scheduledEventList.top();
|
||||
scheduledEvent->cancel();
|
||||
m_scheduledEventList.pop();
|
||||
}
|
||||
m_disabled = true;
|
||||
}
|
||||
|
||||
void EventDispatcher::poll()
|
||||
|
@ -77,6 +81,9 @@ void EventDispatcher::poll()
|
|||
|
||||
ScheduledEventPtr EventDispatcher::scheduleEvent(const std::function<void()>& callback, int delay)
|
||||
{
|
||||
if(m_disabled)
|
||||
return ScheduledEventPtr(new ScheduledEvent(nullptr, delay, 1));
|
||||
|
||||
assert(delay >= 0);
|
||||
ScheduledEventPtr scheduledEvent(new ScheduledEvent(callback, delay, 1));
|
||||
m_scheduledEventList.push(scheduledEvent);
|
||||
|
@ -85,6 +92,9 @@ ScheduledEventPtr EventDispatcher::scheduleEvent(const std::function<void()>& ca
|
|||
|
||||
ScheduledEventPtr EventDispatcher::cycleEvent(const std::function<void()>& callback, int delay)
|
||||
{
|
||||
if(m_disabled)
|
||||
return ScheduledEventPtr(new ScheduledEvent(nullptr, delay, 0));
|
||||
|
||||
assert(delay > 0);
|
||||
ScheduledEventPtr scheduledEvent(new ScheduledEvent(callback, delay, 0));
|
||||
m_scheduledEventList.push(scheduledEvent);
|
||||
|
@ -93,6 +103,9 @@ ScheduledEventPtr EventDispatcher::cycleEvent(const std::function<void()>& callb
|
|||
|
||||
EventPtr EventDispatcher::addEvent(const std::function<void()>& callback, bool pushFront)
|
||||
{
|
||||
if(m_disabled)
|
||||
return EventPtr(new Event(nullptr));
|
||||
|
||||
EventPtr event(new Event(callback));
|
||||
// front pushing is a way to execute an event before others
|
||||
if(pushFront) {
|
||||
|
|
|
@ -31,14 +31,24 @@ class Event : public LuaObject
|
|||
{
|
||||
public:
|
||||
Event(const std::function<void()>& callback) : m_callback(callback), m_canceled(false), m_executed(false) { }
|
||||
virtual ~Event() {
|
||||
// assure that we lost callback refs
|
||||
assert(m_callback == nullptr);
|
||||
}
|
||||
|
||||
virtual void execute() {
|
||||
if(!m_canceled && !m_executed && m_callback) {
|
||||
m_callback();
|
||||
m_executed = true;
|
||||
}
|
||||
|
||||
// reset callback to free object refs
|
||||
m_callback = nullptr;
|
||||
}
|
||||
void cancel() {
|
||||
m_canceled = true;
|
||||
m_callback = nullptr;
|
||||
}
|
||||
void cancel() { m_canceled = true; }
|
||||
|
||||
bool isCanceled() { return m_canceled; }
|
||||
bool isExecuted() { return m_executed; }
|
||||
|
@ -63,17 +73,21 @@ public:
|
|||
if(!m_canceled && m_callback && (m_maxCycles == 0 || m_cyclesExecuted < m_maxCycles)) {
|
||||
m_callback();
|
||||
m_executed = true;
|
||||
// callback may be used in the next cycle
|
||||
} else {
|
||||
// reset callback to free object refs
|
||||
m_callback = nullptr;
|
||||
}
|
||||
m_cyclesExecuted++;
|
||||
}
|
||||
|
||||
bool nextCycle() {
|
||||
if(m_canceled)
|
||||
return false;
|
||||
if(m_maxCycles == 0 || m_cyclesExecuted < m_maxCycles) {
|
||||
if(m_callback && !m_canceled && (m_maxCycles == 0 || m_cyclesExecuted < m_maxCycles)) {
|
||||
m_ticks += m_delay;
|
||||
return true;
|
||||
}
|
||||
// reset callback to free object refs
|
||||
m_callback = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -109,6 +123,7 @@ public:
|
|||
private:
|
||||
std::list<EventPtr> m_eventList;
|
||||
int m_pollEventsSize;
|
||||
Boolean<false> m_disabled;
|
||||
std::priority_queue<ScheduledEventPtr, std::vector<ScheduledEventPtr>, lessScheduledEvent> m_scheduledEventList;
|
||||
};
|
||||
|
||||
|
|
|
@ -28,6 +28,12 @@
|
|||
|
||||
ModuleManager g_modules;
|
||||
|
||||
void ModuleManager::clear()
|
||||
{
|
||||
m_modules.clear();
|
||||
m_autoLoadModules.clear();
|
||||
}
|
||||
|
||||
void ModuleManager::discoverModules()
|
||||
{
|
||||
// remove modules that are not loaded
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
class ModuleManager
|
||||
{
|
||||
public:
|
||||
void clear();
|
||||
|
||||
void discoverModulesPath();
|
||||
void discoverModules();
|
||||
void autoLoadModules(int maxPriority);
|
||||
|
|
|
@ -27,11 +27,13 @@
|
|||
#include "glutil.h"
|
||||
|
||||
class Texture;
|
||||
class TextureManager;
|
||||
class Image;
|
||||
class AnimatedTexture;
|
||||
class BitmapFont;
|
||||
class CachedText;
|
||||
class FrameBuffer;
|
||||
class FrameBufferManager;
|
||||
class Shader;
|
||||
class ShaderProgram;
|
||||
class PainterShaderProgram;
|
||||
|
|
|
@ -32,10 +32,10 @@ FontManager::FontManager()
|
|||
m_defaultFont = BitmapFontPtr(new BitmapFont("emptyfont"));
|
||||
}
|
||||
|
||||
void FontManager::releaseFonts()
|
||||
void FontManager::terminate()
|
||||
{
|
||||
m_defaultFont.reset();
|
||||
m_fonts.clear();
|
||||
m_defaultFont = nullptr;
|
||||
}
|
||||
|
||||
bool FontManager::importFont(std::string fontFile)
|
||||
|
|
|
@ -30,10 +30,8 @@ class FontManager
|
|||
public:
|
||||
FontManager();
|
||||
|
||||
/// Release fonts references, thus making possible to destruct them
|
||||
void releaseFonts();
|
||||
void terminate();
|
||||
|
||||
/// Import a font from .otfont file
|
||||
bool importFont(std::string fontFile);
|
||||
|
||||
bool fontExists(const std::string& fontName);
|
||||
|
|
|
@ -23,7 +23,9 @@
|
|||
#include "framebuffer.h"
|
||||
#include "graphics.h"
|
||||
#include "texture.h"
|
||||
|
||||
#include <framework/platform/platformwindow.h>
|
||||
#include <framework/application.h>
|
||||
|
||||
uint FrameBuffer::boundFbo = 0;
|
||||
|
||||
|
@ -32,12 +34,6 @@ FrameBuffer::FrameBuffer()
|
|||
internalCreate();
|
||||
}
|
||||
|
||||
FrameBuffer::FrameBuffer(const Size& size)
|
||||
{
|
||||
internalCreate();
|
||||
resize(size);
|
||||
}
|
||||
|
||||
void FrameBuffer::internalCreate()
|
||||
{
|
||||
m_prevBoundFbo = 0;
|
||||
|
@ -51,14 +47,14 @@ void FrameBuffer::internalCreate()
|
|||
|
||||
FrameBuffer::~FrameBuffer()
|
||||
{
|
||||
if(m_fbo != 0)
|
||||
assert(!g_app->isTermianted());
|
||||
if(g_graphics.ok() && m_fbo != 0)
|
||||
glDeleteFramebuffers(1, &m_fbo);
|
||||
}
|
||||
|
||||
void FrameBuffer::resize(const Size& size)
|
||||
{
|
||||
if(!size.isValid())
|
||||
return;
|
||||
assert(size.isValid());
|
||||
|
||||
if(m_texture && m_texture->getSize() == size)
|
||||
return;
|
||||
|
|
|
@ -28,9 +28,12 @@
|
|||
|
||||
class FrameBuffer
|
||||
{
|
||||
public:
|
||||
protected:
|
||||
FrameBuffer();
|
||||
FrameBuffer(const Size& size);
|
||||
|
||||
friend class FrameBufferManager;
|
||||
|
||||
public:
|
||||
virtual ~FrameBuffer();
|
||||
|
||||
void resize(const Size& size);
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/otclient>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#include "framebuffermanager.h"
|
||||
|
||||
FrameBufferManager g_framebuffers;
|
||||
|
||||
void FrameBufferManager::init()
|
||||
{
|
||||
m_temporaryFramebuffer = FrameBufferPtr(new FrameBuffer());
|
||||
}
|
||||
|
||||
void FrameBufferManager::terminate()
|
||||
{
|
||||
m_framebuffers.clear();
|
||||
m_temporaryFramebuffer = nullptr;
|
||||
}
|
||||
|
||||
FrameBufferPtr FrameBufferManager::createFrameBuffer()
|
||||
{
|
||||
FrameBufferPtr fbo = FrameBufferPtr(new FrameBuffer());
|
||||
m_framebuffers.push_back(fbo);
|
||||
return fbo;
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/otclient>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef FRAMEBUFFERMANAGER_H
|
||||
#define FRAMEBUFFERMANAGER_H
|
||||
|
||||
#include "framebuffer.h"
|
||||
|
||||
class FrameBufferManager
|
||||
{
|
||||
public:
|
||||
void init();
|
||||
void terminate();
|
||||
void clear();
|
||||
|
||||
FrameBufferPtr createFrameBuffer();
|
||||
const FrameBufferPtr& getTemporaryFrameBuffer() { return m_temporaryFramebuffer; }
|
||||
|
||||
protected:
|
||||
FrameBufferPtr m_temporaryFramebuffer;
|
||||
std::vector<FrameBufferPtr> m_framebuffers;
|
||||
};
|
||||
|
||||
extern FrameBufferManager g_framebuffers;
|
||||
|
||||
#endif
|
|
@ -33,6 +33,8 @@
|
|||
|
||||
#include <framework/graphics/graphics.h>
|
||||
#include <framework/graphics/texture.h>
|
||||
#include "texturemanager.h"
|
||||
#include "framebuffermanager.h"
|
||||
#include <framework/platform/platformwindow.h>
|
||||
|
||||
Graphics g_graphics;
|
||||
|
@ -88,13 +90,19 @@ void Graphics::init()
|
|||
m_alphaBits = 0;
|
||||
glGetIntegerv(GL_ALPHA_BITS, &m_alphaBits);
|
||||
|
||||
m_ok = true;
|
||||
|
||||
selectPainterEngine(m_prefferedPainterEngine);
|
||||
m_emptyTexture = TexturePtr(new Texture);
|
||||
|
||||
g_textures.init();
|
||||
g_framebuffers.init();
|
||||
}
|
||||
|
||||
void Graphics::terminate()
|
||||
{
|
||||
g_fonts.releaseFonts();
|
||||
g_fonts.terminate();
|
||||
g_framebuffers.terminate();
|
||||
g_textures.terminate();
|
||||
|
||||
#ifdef PAINTER_OGL2
|
||||
if(g_painterOGL2) {
|
||||
|
@ -112,7 +120,7 @@ void Graphics::terminate()
|
|||
|
||||
g_painter = nullptr;
|
||||
|
||||
m_emptyTexture.reset();
|
||||
m_ok = false;
|
||||
}
|
||||
|
||||
bool Graphics::parseOption(const std::string& option)
|
||||
|
|
|
@ -51,13 +51,13 @@ public:
|
|||
|
||||
int getMaxTextureSize() { return m_maxTextureSize; }
|
||||
const Size& getViewportSize() { return m_viewportSize; }
|
||||
TexturePtr& getEmptyTexture() { return m_emptyTexture; }
|
||||
|
||||
std::string getVendor() { return (const char*)glGetString(GL_VENDOR); }
|
||||
std::string getRenderer() { return (const char*)glGetString(GL_RENDERER); }
|
||||
std::string getVersion() { return (const char*)glGetString(GL_VERSION); }
|
||||
std::string getExtensions() { return (const char*)glGetString(GL_EXTENSIONS); }
|
||||
|
||||
bool ok() { return m_ok; }
|
||||
bool canUseDrawArrays();
|
||||
bool canUseShaders();
|
||||
bool canUseFBO();
|
||||
|
@ -72,10 +72,10 @@ public:
|
|||
|
||||
private:
|
||||
Size m_viewportSize;
|
||||
TexturePtr m_emptyTexture;
|
||||
|
||||
int m_maxTextureSize;
|
||||
int m_alphaBits;
|
||||
Boolean<false> m_ok;
|
||||
Boolean<true> m_useDrawArrays;
|
||||
Boolean<true> m_useFBO;
|
||||
Boolean<false> m_useHardwareBuffers;
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/otclient>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "hardwarebuffer.h"
|
||||
#include "graphics.h"
|
||||
|
||||
#include <framework/application.h>
|
||||
#include <framework/core/logger.h>
|
||||
|
||||
HardwareBuffer::HardwareBuffer(Type type)
|
||||
{
|
||||
m_type = type;
|
||||
m_id = 0;
|
||||
glGenBuffers(1, &m_id);
|
||||
if(!m_id)
|
||||
g_logger.fatal("Unable to create hardware buffer.");
|
||||
}
|
||||
|
||||
HardwareBuffer::~HardwareBuffer()
|
||||
{
|
||||
assert(!g_app->isTermianted());
|
||||
if(g_graphics.ok())
|
||||
glDeleteBuffers(1, &m_id);
|
||||
}
|
|
@ -40,15 +40,8 @@ public:
|
|||
DynamicDraw = GL_DYNAMIC_DRAW
|
||||
};
|
||||
|
||||
HardwareBuffer(Type type) {
|
||||
m_type = type;
|
||||
m_id = 0;
|
||||
glGenBuffers(1, &m_id);
|
||||
assert(m_id != 0);
|
||||
}
|
||||
~HardwareBuffer() {
|
||||
glDeleteBuffers(1, &m_id);
|
||||
}
|
||||
HardwareBuffer(Type type);
|
||||
~HardwareBuffer();
|
||||
|
||||
void bind() { glBindBuffer(m_type, m_id); }
|
||||
static void unbind(Type type) { glBindBuffer(type, 0); }
|
||||
|
|
|
@ -48,12 +48,6 @@ PainterOGL2::PainterOGL2()
|
|||
PainterShaderProgram::release();
|
||||
}
|
||||
|
||||
PainterOGL2::~PainterOGL2()
|
||||
{
|
||||
m_drawTexturedProgram = nullptr;
|
||||
m_drawSolidColorProgram = nullptr;
|
||||
}
|
||||
|
||||
void PainterOGL2::bind()
|
||||
{
|
||||
Painter::bind();
|
||||
|
|
|
@ -36,7 +36,6 @@ class PainterOGL2 : public Painter
|
|||
{
|
||||
public:
|
||||
PainterOGL2();
|
||||
~PainterOGL2();
|
||||
|
||||
void bind();
|
||||
void unbind();
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
*/
|
||||
|
||||
#include "shader.h"
|
||||
#include "graphics.h"
|
||||
|
||||
#include <framework/application.h>
|
||||
#include <framework/core/resourcemanager.h>
|
||||
|
||||
Shader::Shader(Shader::ShaderType shaderType)
|
||||
|
@ -41,7 +44,9 @@ Shader::Shader(Shader::ShaderType shaderType)
|
|||
|
||||
Shader::~Shader()
|
||||
{
|
||||
glDeleteShader(m_shaderId);
|
||||
assert(!g_app->isTermianted());
|
||||
if(g_graphics.ok())
|
||||
glDeleteShader(m_shaderId);
|
||||
}
|
||||
|
||||
bool Shader::compileSourceCode(const std::string& sourceCode)
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
*/
|
||||
|
||||
#include "shaderprogram.h"
|
||||
#include "graphics.h"
|
||||
|
||||
#include <framework/application.h>
|
||||
|
||||
GLuint ShaderProgram::m_currentProgram = 0;
|
||||
|
||||
|
@ -35,7 +38,9 @@ ShaderProgram::ShaderProgram()
|
|||
|
||||
ShaderProgram::~ShaderProgram()
|
||||
{
|
||||
glDeleteProgram(m_programId);
|
||||
assert(!g_app->isTermianted());
|
||||
if(g_graphics.ok())
|
||||
glDeleteProgram(m_programId);
|
||||
}
|
||||
|
||||
bool ShaderProgram::addShader(const ShaderPtr& shader) {
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#include "framebuffer.h"
|
||||
#include "image.h"
|
||||
|
||||
#include <framework/application.h>
|
||||
|
||||
Texture::Texture()
|
||||
{
|
||||
m_id = 0;
|
||||
|
@ -77,8 +79,9 @@ Texture::Texture(const ImagePtr& image, bool buildMipmaps)
|
|||
|
||||
Texture::~Texture()
|
||||
{
|
||||
assert(!g_app->isTermianted());
|
||||
// free texture from gl memory
|
||||
if(m_id > 0)
|
||||
if(g_graphics.ok() && m_id != 0)
|
||||
glDeleteTextures(1, &m_id);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,26 @@
|
|||
|
||||
TextureManager g_textures;
|
||||
|
||||
void TextureManager::init()
|
||||
{
|
||||
m_emptyTexture = TexturePtr(new Texture);
|
||||
}
|
||||
|
||||
void TextureManager::terminate()
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
// check for leaks
|
||||
int refs = 0;
|
||||
for(const auto& it : m_textures)
|
||||
if(it.second.use_count() > 1)
|
||||
refs++;
|
||||
if(refs > 0)
|
||||
g_logger.debug(stdext::format("%d textures references left", refs));
|
||||
#endif
|
||||
m_textures.clear();
|
||||
m_emptyTexture = nullptr;
|
||||
}
|
||||
|
||||
TexturePtr TextureManager::getTexture(const std::string& fileName)
|
||||
{
|
||||
TexturePtr texture;
|
||||
|
@ -59,7 +79,7 @@ TexturePtr TextureManager::getTexture(const std::string& fileName)
|
|||
texture = loadPNG(fin);
|
||||
} catch(stdext::exception& e) {
|
||||
g_logger.error(stdext::format("unable to load texture '%s': %s", fileName, e.what()));
|
||||
texture = g_graphics.getEmptyTexture();
|
||||
texture = g_textures.getEmptyTexture();
|
||||
}
|
||||
|
||||
if(texture)
|
||||
|
|
|
@ -28,12 +28,17 @@
|
|||
class TextureManager
|
||||
{
|
||||
public:
|
||||
TexturePtr getTexture(const std::string& fileName);
|
||||
void init();
|
||||
void terminate();
|
||||
|
||||
static TexturePtr loadPNG(std::stringstream& file);
|
||||
TexturePtr getTexture(const std::string& fileName);
|
||||
const TexturePtr& getEmptyTexture() { return m_emptyTexture; }
|
||||
|
||||
private:
|
||||
TexturePtr loadPNG(std::stringstream& file);
|
||||
|
||||
std::unordered_map<std::string, TextureWeakPtr> m_textures;
|
||||
TexturePtr m_emptyTexture;
|
||||
};
|
||||
|
||||
extern TextureManager g_textures;
|
||||
|
|
|
@ -35,6 +35,8 @@ LuaInterface::LuaInterface()
|
|||
L = nullptr;
|
||||
m_cppCallbackDepth = 0;
|
||||
m_weakTableRef = 0;
|
||||
m_totalObjRefs = 0;
|
||||
m_totalFuncRefs = 0;
|
||||
}
|
||||
|
||||
LuaInterface::~LuaInterface()
|
||||
|
@ -64,6 +66,8 @@ void LuaInterface::terminate()
|
|||
{
|
||||
// close lua state, it will release all objects
|
||||
closeLuaState();
|
||||
assert(m_totalFuncRefs == 0);
|
||||
assert(m_totalObjRefs == 0);
|
||||
}
|
||||
|
||||
void LuaInterface::registerSingletonClass(const std::string& className)
|
||||
|
@ -280,6 +284,7 @@ int LuaInterface::luaObjectCollectEvent(LuaInterface* lua)
|
|||
|
||||
// resets pointer to decrease object use count
|
||||
objPtr->reset();
|
||||
g_lua.m_totalObjRefs--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -603,6 +608,7 @@ int LuaInterface::luaCollectCppFunction(lua_State* L)
|
|||
auto funcPtr = static_cast<LuaCppFunctionPtr*>(g_lua.popUserdata());
|
||||
assert(funcPtr);
|
||||
funcPtr->reset();
|
||||
g_lua.m_totalFuncRefs--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1033,6 +1039,7 @@ void LuaInterface::pushObject(const LuaObjectPtr& obj)
|
|||
{
|
||||
// fills a new userdata with a new LuaObjectPtr pointer
|
||||
new(newUserdata(sizeof(LuaObjectPtr))) LuaObjectPtr(obj);
|
||||
m_totalObjRefs++;
|
||||
|
||||
// set the userdata metatable
|
||||
getGlobal(stdext::format("%s_mt", obj->getClassName()));
|
||||
|
@ -1050,6 +1057,7 @@ void LuaInterface::pushCppFunction(const LuaCppFunction& func)
|
|||
{
|
||||
// create a pointer to func (this pointer will hold the function existence)
|
||||
new(newUserdata(sizeof(LuaCppFunctionPtr))) LuaCppFunctionPtr(new LuaCppFunction(func));
|
||||
m_totalFuncRefs++;
|
||||
|
||||
// sets the userdata __gc metamethod, needed to free the function pointer when it gets collected
|
||||
newTable();
|
||||
|
|
|
@ -329,6 +329,8 @@ private:
|
|||
lua_State* L;
|
||||
int m_weakTableRef;
|
||||
int m_cppCallbackDepth;
|
||||
int m_totalObjRefs;
|
||||
int m_totalFuncRefs;
|
||||
};
|
||||
|
||||
extern LuaInterface g_lua;
|
||||
|
|
|
@ -23,12 +23,15 @@
|
|||
#include "luaobject.h"
|
||||
#include "luainterface.h"
|
||||
|
||||
#include <framework/application.h>
|
||||
|
||||
LuaObject::LuaObject() : m_fieldsTableRef(-1)
|
||||
{
|
||||
}
|
||||
|
||||
LuaObject::~LuaObject()
|
||||
{
|
||||
assert(!g_app->isTermianted());
|
||||
releaseLuaFieldsTable();
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "connection.h"
|
||||
|
||||
#include <framework/application.h>
|
||||
#include <framework/core/eventdispatcher.h>
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
|
@ -40,6 +41,7 @@ Connection::Connection() :
|
|||
|
||||
Connection::~Connection()
|
||||
{
|
||||
assert(!g_app->isTermianted());
|
||||
close();
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,9 @@ void UIManager::terminate()
|
|||
m_draggingWidget = nullptr;
|
||||
m_hoveredWidget = nullptr;
|
||||
m_pressedWidget = nullptr;
|
||||
m_styles.clear();
|
||||
m_destroyedWidgets.clear();
|
||||
m_checkEvent = nullptr;
|
||||
}
|
||||
|
||||
void UIManager::render(Fw::DrawPane drawPane)
|
||||
|
@ -266,22 +269,19 @@ void UIManager::onWidgetDestroy(const UIWidgetPtr& widget)
|
|||
if(m_draggingWidget == widget)
|
||||
updateDraggingWidget(nullptr);
|
||||
|
||||
#ifdef DEBUG
|
||||
static UIWidgetList destroyedWidgets;
|
||||
static ScheduledEventPtr checkEvent;
|
||||
|
||||
if(widget == m_rootWidget)
|
||||
#ifndef DEBUG
|
||||
if(widget == m_rootWidget || !m_rootWidget)
|
||||
return;
|
||||
|
||||
destroyedWidgets.push_back(widget);
|
||||
m_destroyedWidgets.push_back(widget);
|
||||
|
||||
if(checkEvent && !checkEvent->isExecuted())
|
||||
if(m_checkEvent && !m_checkEvent->isExecuted())
|
||||
return;
|
||||
|
||||
checkEvent = g_eventDispatcher.scheduleEvent([] {
|
||||
m_checkEvent = g_eventDispatcher.scheduleEvent([] {
|
||||
g_lua.collectGarbage();
|
||||
UIWidgetList backupList = destroyedWidgets;
|
||||
destroyedWidgets.clear();
|
||||
UIWidgetList backupList = m_destroyedWidgets;
|
||||
m_destroyedWidgets.clear();
|
||||
g_eventDispatcher.scheduleEvent([backupList] {
|
||||
g_lua.collectGarbage();
|
||||
for(const UIWidgetPtr& widget : backupList) {
|
||||
|
|
|
@ -82,6 +82,8 @@ private:
|
|||
Boolean<false> m_hoverUpdateScheduled;
|
||||
Boolean<false> m_drawDebugBoxes;
|
||||
std::unordered_map<std::string, OTMLNodePtr> m_styles;
|
||||
UIWidgetList m_destroyedWidgets;
|
||||
ScheduledEventPtr m_checkEvent;
|
||||
};
|
||||
|
||||
extern UIManager g_ui;
|
||||
|
|
|
@ -46,6 +46,7 @@ UIWidget::UIWidget()
|
|||
|
||||
UIWidget::~UIWidget()
|
||||
{
|
||||
assert(!g_app->isTermianted());
|
||||
#ifdef DEBUG
|
||||
if(!m_destroyed)
|
||||
g_logger.warning(stdext::format("widget '%s' was not explicitly destroyed", m_id));
|
||||
|
|
|
@ -28,6 +28,7 @@ int main(int argc, const char* argv[])
|
|||
OTClient app;
|
||||
app.init(args);
|
||||
app.run();
|
||||
app.deinit();
|
||||
app.terminate();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
#include <framework/graphics/paintershaderprogram.h>
|
||||
#include <framework/graphics/painterogl2_shadersources.h>
|
||||
#include <framework/graphics/texturemanager.h>
|
||||
#include <framework/graphics/framebuffer.h>
|
||||
#include <framework/graphics/framebuffermanager.h>
|
||||
#include "spritemanager.h"
|
||||
|
||||
Creature::Creature() : Thing()
|
||||
|
@ -161,10 +161,8 @@ void Creature::internalDrawOutfit(const Point& dest, float scaleFactor, bool ani
|
|||
void Creature::drawOutfit(const Rect& destRect, bool resize)
|
||||
{
|
||||
if(g_graphics.canUseFBO()) {
|
||||
static FrameBufferPtr outfitBuffer;
|
||||
if(!outfitBuffer)
|
||||
outfitBuffer = FrameBufferPtr(new FrameBuffer(Size(2*Otc::TILE_PIXELS, 2*Otc::TILE_PIXELS)));
|
||||
|
||||
const FrameBufferPtr& outfitBuffer = g_framebuffers.getTemporaryFrameBuffer();
|
||||
outfitBuffer->resize(Size(2*Otc::TILE_PIXELS, 2*Otc::TILE_PIXELS));
|
||||
outfitBuffer->bind();
|
||||
g_painter->setAlphaWriting(true);
|
||||
g_painter->clear(Color::alpha);
|
||||
|
|
|
@ -62,5 +62,6 @@ typedef std::shared_ptr<StaticText> StaticTextPtr;
|
|||
typedef std::shared_ptr<ItemShader> ItemShaderPtr;
|
||||
|
||||
typedef std::vector<ThingPtr> ThingList;
|
||||
typedef std::vector<ThingType> ThingTypeList;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -22,8 +22,6 @@
|
|||
|
||||
#include "mapview.h"
|
||||
|
||||
#include <framework/graphics/graphics.h>
|
||||
#include <framework/graphics/framebuffer.h>
|
||||
#include "creature.h"
|
||||
#include "map.h"
|
||||
#include "tile.h"
|
||||
|
@ -31,7 +29,11 @@
|
|||
#include "animatedtext.h"
|
||||
#include "missile.h"
|
||||
#include "shadermanager.h"
|
||||
|
||||
#include <framework/graphics/graphics.h>
|
||||
#include <framework/graphics/framebuffermanager.h>
|
||||
#include <framework/core/eventdispatcher.h>
|
||||
#include <framework/application.h>
|
||||
|
||||
MapView::MapView()
|
||||
{
|
||||
|
@ -41,12 +43,17 @@ MapView::MapView()
|
|||
m_cachedLastVisibleFloor = 7;
|
||||
m_optimizedSize = Size(Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES) * Otc::TILE_PIXELS;
|
||||
|
||||
m_framebuffer = FrameBufferPtr(new FrameBuffer());
|
||||
m_framebuffer = g_framebuffers.createFrameBuffer();
|
||||
setVisibleDimension(Size(15, 11));
|
||||
|
||||
m_shader = g_shaders.getDefaultMapShader();
|
||||
}
|
||||
|
||||
MapView::~MapView()
|
||||
{
|
||||
assert(!g_app->isTermianted());
|
||||
}
|
||||
|
||||
void MapView::draw(const Rect& rect)
|
||||
{
|
||||
// update visible tiles cache when needed
|
||||
|
|
|
@ -50,6 +50,7 @@ public:
|
|||
};
|
||||
|
||||
MapView();
|
||||
~MapView();
|
||||
void draw(const Rect& rect);
|
||||
|
||||
private:
|
||||
|
|
|
@ -44,6 +44,7 @@ void ShaderManager::terminate()
|
|||
{
|
||||
m_defaultItemShader = nullptr;
|
||||
m_defaultMapShader = nullptr;
|
||||
m_shaders.clear();
|
||||
}
|
||||
|
||||
PainterShaderProgramPtr ShaderManager::createShader(const std::string& name)
|
||||
|
|
|
@ -156,6 +156,4 @@ private:
|
|||
friend class ThingsType;
|
||||
};
|
||||
|
||||
typedef std::vector<ThingType> ThingTypeList;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -117,5 +117,7 @@ void OTClient::init(const std::vector<std::string>& args)
|
|||
void OTClient::terminate()
|
||||
{
|
||||
g_shaders.terminate();
|
||||
g_map.clean();
|
||||
g_thingsType.unload();
|
||||
Application::terminate();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue