mirror of
https://github.com/edubart/otclient.git
synced 2025-10-14 11:34:54 +02:00
merge total remake
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
#ifndef CONST_H
|
||||
#define CONST_H
|
||||
|
||||
//namespace Fw {
|
||||
|
||||
enum AlignmentFlag {
|
||||
AlignLeft = 1,
|
||||
AlignRight = 2,
|
||||
@@ -19,4 +21,42 @@ enum AlignmentFlag {
|
||||
AlignCenter = AlignVerticalCenter | AlignHorizontalCenter
|
||||
};
|
||||
|
||||
#endif // CONST_H
|
||||
enum AnchorPoint {
|
||||
AnchorNone = 0,
|
||||
AnchorTop,
|
||||
AnchorBottom,
|
||||
AnchorLeft,
|
||||
AnchorRight,
|
||||
AnchorVerticalCenter,
|
||||
AnchorHorizontalCenter,
|
||||
};
|
||||
|
||||
enum MouseButton {
|
||||
MouseNoButton = 0,
|
||||
MouseLeftButton,
|
||||
MouseRightButton,
|
||||
MouseMidButton
|
||||
};
|
||||
|
||||
enum MouseWheelDirection {
|
||||
MouseNoWheel = 0,
|
||||
MouseWheelUp,
|
||||
MouseWheelDown
|
||||
};
|
||||
|
||||
enum KeyboardModifier {
|
||||
KeyboardNoModifier = 0,
|
||||
KeyboardCtrlModifier = 1,
|
||||
KeyboardAltModifier = 2,
|
||||
KeyboardShiftModifier = 4
|
||||
};
|
||||
|
||||
enum ButtonState {
|
||||
ButtonUp = 0,
|
||||
ButtonDown,
|
||||
ButtonHover
|
||||
};
|
||||
|
||||
//}
|
||||
|
||||
#endif
|
||||
|
35
src/framework/core/configmanager.cpp
Normal file
35
src/framework/core/configmanager.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#include "configmanager.h"
|
||||
#include "resourcemanager.h"
|
||||
|
||||
#include <otml/otml.h>
|
||||
|
||||
ConfigManager g_configs;
|
||||
|
||||
bool ConfigManager::load(const std::string& fileName)
|
||||
{
|
||||
m_fileName = fileName;
|
||||
|
||||
if(!g_resources.fileExists(fileName))
|
||||
return false;
|
||||
|
||||
try {
|
||||
OTMLDocumentPtr doc = OTMLDocument::parse(fileName);
|
||||
for(const OTMLNodePtr& child : doc->childNodes())
|
||||
m_confsMap[child->tag()] = child->value();
|
||||
} catch(std::exception& e) {
|
||||
logError("ERROR: could not load configurations: ", e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConfigManager::save()
|
||||
{
|
||||
if(!m_fileName.empty()) {
|
||||
OTMLDocumentPtr doc = OTMLDocument::create();
|
||||
doc->write(m_confsMap);
|
||||
return doc->save(m_fileName);
|
||||
}
|
||||
return false;
|
||||
}
|
@@ -1,25 +1,25 @@
|
||||
#ifndef CONFIGS_H
|
||||
#define CONFIGS_H
|
||||
#ifndef CONFIGMANAGER_H
|
||||
#define CONFIGMANAGER_H
|
||||
|
||||
#include <global.h>
|
||||
|
||||
struct ConfigValueProxy {
|
||||
ConfigValueProxy(const std::string& v) : value(v) { }
|
||||
operator std::string() const { return convert<std::string>(value); }
|
||||
operator float() const { return convert<float>(value); }
|
||||
operator int() const { return convert<int>(value); }
|
||||
operator bool() const { return convert<bool>(value); }
|
||||
operator std::string() const { return aux::unsafe_cast<std::string>(value); }
|
||||
operator float() const { return aux::unsafe_cast<float>(value); }
|
||||
operator int() const { return aux::unsafe_cast<int>(value); }
|
||||
operator bool() const { return aux::unsafe_cast<bool>(value); }
|
||||
std::string value;
|
||||
};
|
||||
|
||||
class Configs
|
||||
class ConfigManager
|
||||
{
|
||||
public:
|
||||
bool load(const std::string& fileName);
|
||||
void save();
|
||||
bool save();
|
||||
|
||||
template<class T>
|
||||
void set(const std::string& key, const T& value) { m_confsMap[key] = convert<std::string>(value); }
|
||||
void set(const std::string& key, const T& value) { m_confsMap[key] = aux::unsafe_cast<std::string>(value); }
|
||||
|
||||
ConfigValueProxy get(const std::string& key) { return ConfigValueProxy(m_confsMap[key]); }
|
||||
|
||||
@@ -28,6 +28,6 @@ private:
|
||||
std::map<std::string, std::string> m_confsMap;
|
||||
};
|
||||
|
||||
extern Configs g_configs;
|
||||
extern ConfigManager g_configs;
|
||||
|
||||
#endif // CONFIGS_H
|
||||
#endif
|
@@ -1,37 +0,0 @@
|
||||
#include "configs.h"
|
||||
#include "resources.h"
|
||||
|
||||
#include <otml/otml.h>
|
||||
|
||||
Configs g_configs;
|
||||
|
||||
bool Configs::load(const std::string& fileName)
|
||||
{
|
||||
m_fileName = fileName;
|
||||
|
||||
if(!g_resources.fileExists(fileName))
|
||||
return false;
|
||||
|
||||
std::stringstream fin;
|
||||
if(!g_resources.loadFile(fileName, fin))
|
||||
return false;
|
||||
|
||||
try {
|
||||
OTMLParser parser(fin, fileName);
|
||||
parser.getDocument()->read(&m_confsMap);
|
||||
} catch(OTMLException e) {
|
||||
logError("ERROR: Malformed config file: ", e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Configs::save()
|
||||
{
|
||||
if(!m_fileName.empty()) {
|
||||
OTMLEmitter emitter;
|
||||
emitter.createDocument()->write(m_confsMap);
|
||||
g_resources.saveFile(m_fileName, emitter.emitDocument());
|
||||
}
|
||||
}
|
@@ -1,43 +0,0 @@
|
||||
#include "dispatcher.h"
|
||||
#include "engine.h"
|
||||
|
||||
Dispatcher g_dispatcher;
|
||||
|
||||
void Dispatcher::cleanup()
|
||||
{
|
||||
while(!m_scheduledTaskList.empty()) {
|
||||
ScheduledTask *task = m_scheduledTaskList.top();
|
||||
m_scheduledTaskList.pop();
|
||||
delete task;
|
||||
}
|
||||
}
|
||||
|
||||
void Dispatcher::poll()
|
||||
{
|
||||
while(!m_taskList.empty()) {
|
||||
m_taskList.front()();
|
||||
m_taskList.pop_front();
|
||||
}
|
||||
|
||||
while(!m_scheduledTaskList.empty()) {
|
||||
ScheduledTask *task = m_scheduledTaskList.top();
|
||||
if(g_engine.getCurrentFrameTicks() < task->ticks)
|
||||
break;
|
||||
m_scheduledTaskList.pop();
|
||||
task->callback();
|
||||
delete task;
|
||||
}
|
||||
}
|
||||
|
||||
void Dispatcher::scheduleTask(const std::function<void()>& callback, int delay)
|
||||
{
|
||||
m_scheduledTaskList.push(new ScheduledTask(g_engine.getCurrentFrameTicks() + delay, callback));
|
||||
}
|
||||
|
||||
void Dispatcher::addTask(const std::function<void()>& callback, bool pushFront)
|
||||
{
|
||||
if(pushFront)
|
||||
m_taskList.push_front(callback);
|
||||
else
|
||||
m_taskList.push_back(callback);
|
||||
}
|
@@ -1,43 +0,0 @@
|
||||
#ifndef DISPATCHER_H
|
||||
#define DISPATCHER_H
|
||||
|
||||
#include <global.h>
|
||||
#include <queue>
|
||||
|
||||
struct ScheduledTask {
|
||||
ScheduledTask(const std::function<void()>& _callback) : ticks(0), callback(_callback) { }
|
||||
ScheduledTask(int _ticks, const std::function<void()>& _callback) : ticks(_ticks), callback(_callback) { }
|
||||
bool operator<(const ScheduledTask& other) const { return ticks > other.ticks; }
|
||||
int ticks;
|
||||
std::function<void()> callback;
|
||||
};
|
||||
|
||||
struct lessScheduledTask : public std::binary_function<ScheduledTask*&, ScheduledTask*&, bool> {
|
||||
bool operator()(ScheduledTask*& t1,ScheduledTask*& t2) { return (*t1) < (*t2); }
|
||||
};
|
||||
|
||||
class Dispatcher
|
||||
{
|
||||
public:
|
||||
Dispatcher() { }
|
||||
|
||||
/// Cleanup scheduled events
|
||||
void cleanup();
|
||||
|
||||
/// Execute scheduled events
|
||||
void poll();
|
||||
|
||||
/// Add an event
|
||||
void addTask(const std::function<void()>& callback, bool pushFront = false);
|
||||
|
||||
/// Schedula an event
|
||||
void scheduleTask(const std::function<void()>& callback, int delay);
|
||||
|
||||
private:
|
||||
std::list<std::function<void()>> m_taskList;
|
||||
std::priority_queue<ScheduledTask*, std::vector<ScheduledTask*>, lessScheduledTask> m_scheduledTaskList;
|
||||
};
|
||||
|
||||
extern Dispatcher g_dispatcher;
|
||||
|
||||
#endif // DISPATCHER_H
|
@@ -1,155 +0,0 @@
|
||||
#include "engine.h"
|
||||
#include "platform.h"
|
||||
#include "dispatcher.h"
|
||||
#include <graphics/graphics.h>
|
||||
#include <graphics/fonts.h>
|
||||
#include <graphics/textures.h>
|
||||
#include <ui/uicontainer.h>
|
||||
#include <ui/uiskins.h>
|
||||
#include <script/luainterface.h>
|
||||
#include <net/connection.h>
|
||||
#include <../game.h>
|
||||
#include <../item.h>
|
||||
|
||||
Engine g_engine;
|
||||
|
||||
void Engine::init()
|
||||
{
|
||||
// initialize stuff
|
||||
g_graphics.init();
|
||||
g_fonts.init();
|
||||
g_lua.init();
|
||||
}
|
||||
|
||||
void Engine::terminate()
|
||||
{
|
||||
// destroy root ui
|
||||
UIContainer::getRoot()->destroy();
|
||||
|
||||
// cleanup script stuff
|
||||
g_lua.terminate();
|
||||
|
||||
// poll remaning events
|
||||
g_engine.poll();
|
||||
|
||||
// terminate stuff
|
||||
g_fonts.terminate();
|
||||
g_graphics.terminate();
|
||||
g_dispatcher.cleanup();
|
||||
}
|
||||
|
||||
void Engine::poll()
|
||||
{
|
||||
// poll platform events
|
||||
Platform::poll();
|
||||
|
||||
// poll diaptcher tasks
|
||||
g_dispatcher.poll();
|
||||
|
||||
// poll network events
|
||||
Connection::poll();
|
||||
}
|
||||
|
||||
void Engine::run()
|
||||
{
|
||||
// check if root container has elements
|
||||
const UIContainerPtr& rootContainer = UIContainer::getRoot();
|
||||
if(rootContainer->getChildCount() == 0)
|
||||
logFatal("FATAL ERROR: no ui loaded at all, no reason to continue running");
|
||||
|
||||
std::string fpsText;
|
||||
Size fpsTextSize;
|
||||
FontPtr defaultFont = g_uiSkins.getDefaultFont();
|
||||
|
||||
m_lastFrameTicks = Platform::getTicks();
|
||||
int lastFpsTicks = m_lastFrameTicks;
|
||||
int frameCount = 0;
|
||||
int fps = 0;
|
||||
m_running = true;
|
||||
|
||||
while(!m_stopping) {
|
||||
m_lastFrameTicks = Platform::getTicks();
|
||||
|
||||
poll();
|
||||
|
||||
// render only when visible
|
||||
if(Platform::isWindowVisible()) {
|
||||
// calculate fps
|
||||
if(m_calculateFps) {
|
||||
frameCount++;
|
||||
if(m_lastFrameTicks - lastFpsTicks >= 1000) {
|
||||
lastFpsTicks = m_lastFrameTicks;
|
||||
fps = frameCount;
|
||||
frameCount = 0;
|
||||
|
||||
// update fps text
|
||||
fpsText = make_string("FPS: ", fps);
|
||||
fpsTextSize = defaultFont->calculateTextRectSize(fpsText);
|
||||
}
|
||||
}
|
||||
|
||||
// render
|
||||
g_graphics.beginRender();
|
||||
|
||||
rootContainer->render();
|
||||
|
||||
// todo remove. render map
|
||||
g_game.getMap()->draw(0, 0);
|
||||
|
||||
// todo remove. view items
|
||||
static Item *item = NULL;
|
||||
if(!item) {
|
||||
item = new Item();
|
||||
item->setId(8377);
|
||||
}
|
||||
//item->draw(1, 1, 7);
|
||||
|
||||
// render fps
|
||||
if(m_calculateFps)
|
||||
defaultFont->renderText(fpsText, Point(g_graphics.getScreenSize().width() - fpsTextSize.width() - 10, 10));
|
||||
|
||||
g_graphics.endRender();
|
||||
|
||||
// swap buffers
|
||||
Platform::swapBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
m_stopping = false;
|
||||
m_running = false;
|
||||
}
|
||||
|
||||
void Engine::stop()
|
||||
{
|
||||
m_stopping = true;
|
||||
}
|
||||
|
||||
void Engine::onClose()
|
||||
{
|
||||
g_lua.getGlobal("onClose")->call("onClose");
|
||||
}
|
||||
|
||||
void Engine::onResize(const Size& size)
|
||||
{
|
||||
g_graphics.resize(size);
|
||||
UIContainer::getRoot()->setSize(size);
|
||||
}
|
||||
|
||||
void Engine::onInputEvent(const InputEvent& event)
|
||||
{
|
||||
UIContainer::getRoot()->onInputEvent(event);
|
||||
|
||||
ProtocolGame *protocol = g_game.getProtocol();
|
||||
if(protocol) {
|
||||
if(event.type == EV_KEY_DOWN) {
|
||||
if(event.keycode == KC_UP)
|
||||
protocol->sendWalkNorth();
|
||||
if(event.keycode == KC_RIGHT)
|
||||
protocol->sendWalkEast();
|
||||
if(event.keycode == KC_DOWN)
|
||||
protocol->sendWalkSouth();
|
||||
if(event.keycode == KC_LEFT)
|
||||
protocol->sendWalkWest();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,53 +0,0 @@
|
||||
#ifndef ENGINE_H
|
||||
#define ENGINE_H
|
||||
|
||||
#include <global.h>
|
||||
#include "input.h"
|
||||
|
||||
class Engine
|
||||
{
|
||||
public:
|
||||
Engine() : m_stopping(false),
|
||||
m_running(false),
|
||||
m_calculateFps(false) { }
|
||||
|
||||
void init();
|
||||
void terminate();
|
||||
|
||||
/// Poll events
|
||||
void poll();
|
||||
/// Main loop
|
||||
void run();
|
||||
|
||||
/// Stops main loop
|
||||
void stop();
|
||||
|
||||
/// Change current game state
|
||||
bool isRunning() const { return m_running; }
|
||||
bool isStopping() const { return m_stopping; }
|
||||
|
||||
/// Fired by platform on window close
|
||||
void onClose();
|
||||
/// Fired by platform on window resize
|
||||
void onResize(const Size& size);
|
||||
/// Fired by platform on mouse/keyboard input
|
||||
void onInputEvent(const InputEvent& event);
|
||||
|
||||
/// Enable FPS counter on screen
|
||||
void enableFpsCounter(bool enable = true) { m_calculateFps = enable; };
|
||||
|
||||
/// Return the current ticks on this frame
|
||||
int getCurrentFrameTicks() const { return m_lastFrameTicks; }
|
||||
|
||||
private:
|
||||
bool m_stopping;
|
||||
bool m_running;
|
||||
bool m_calculateFps;
|
||||
|
||||
int m_lastFrameTicks;
|
||||
};
|
||||
|
||||
extern Engine g_engine;
|
||||
|
||||
#endif // ENGINE_H
|
||||
|
45
src/framework/core/eventdispatcher.cpp
Normal file
45
src/framework/core/eventdispatcher.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
#include "eventdispatcher.h"
|
||||
#include <core/platform.h>
|
||||
|
||||
EventDispatcher g_dispatcher;
|
||||
|
||||
void EventDispatcher::init()
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
void EventDispatcher::terminate()
|
||||
{
|
||||
// clean scheduled events
|
||||
while(!m_scheduledEventList.empty())
|
||||
m_scheduledEventList.pop();
|
||||
}
|
||||
|
||||
void EventDispatcher::poll()
|
||||
{
|
||||
while(!m_eventList.empty()) {
|
||||
m_eventList.front()();
|
||||
m_eventList.pop_front();
|
||||
}
|
||||
|
||||
while(!m_scheduledEventList.empty()) {
|
||||
if(g_platform.getTicks() < m_scheduledEventList.top().ticks)
|
||||
break;
|
||||
SimpleCallback callback = std::move(m_scheduledEventList.top().callback);
|
||||
m_scheduledEventList.pop();
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
void EventDispatcher::scheduleEvent(const SimpleCallback& callback, int delay)
|
||||
{
|
||||
m_scheduledEventList.push(ScheduledEvent(g_platform.getTicks() + delay, callback));
|
||||
}
|
||||
|
||||
void EventDispatcher::addEvent(const SimpleCallback& callback, bool pushFront)
|
||||
{
|
||||
if(pushFront)
|
||||
m_eventList.push_front(callback);
|
||||
else
|
||||
m_eventList.push_back(callback);
|
||||
}
|
38
src/framework/core/eventdispatcher.h
Normal file
38
src/framework/core/eventdispatcher.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef EVENTDISPATCHER_H
|
||||
#define EVENTDISPATCHER_H
|
||||
|
||||
#include <global.h>
|
||||
|
||||
struct ScheduledEvent {
|
||||
ScheduledEvent(int ticks, const SimpleCallback& callback) : ticks(ticks), callback(callback) { }
|
||||
bool operator<(const ScheduledEvent& other) const { return ticks > other.ticks; }
|
||||
int ticks;
|
||||
SimpleCallback callback;
|
||||
};
|
||||
|
||||
class EventDispatcher
|
||||
{
|
||||
public:
|
||||
/// Initialize dispatcher
|
||||
void init();
|
||||
|
||||
/// Cleanup scheduled events
|
||||
void terminate();
|
||||
|
||||
/// Execute scheduled events
|
||||
void poll();
|
||||
|
||||
/// Add an event
|
||||
void addEvent(const SimpleCallback& callback, bool pushFront = false);
|
||||
|
||||
/// Schedule an event
|
||||
void scheduleEvent(const SimpleCallback& callback, int delay);
|
||||
|
||||
private:
|
||||
std::list<SimpleCallback> m_eventList;
|
||||
std::priority_queue<ScheduledEvent> m_scheduledEventList;
|
||||
};
|
||||
|
||||
extern EventDispatcher g_dispatcher;
|
||||
|
||||
#endif
|
@@ -1,10 +1,9 @@
|
||||
#ifndef INPUT_H
|
||||
#define INPUT_H
|
||||
#ifndef INPUTEVENT_H
|
||||
#define INPUTEVENT_H
|
||||
|
||||
#include <util/types.h>
|
||||
#include <util/point.h>
|
||||
#include <global.h>
|
||||
|
||||
enum EKeyCode {
|
||||
enum InputKeyCode {
|
||||
KC_UNKNOWN = 0x00,
|
||||
KC_ESCAPE = 0x01,
|
||||
KC_1 = 0x02,
|
||||
@@ -152,28 +151,28 @@ enum EKeyCode {
|
||||
KC_MEDIASELECT = 0xED // Media Select
|
||||
};
|
||||
|
||||
enum EEvent {
|
||||
EV_MOUSE = 1,
|
||||
EV_KEYBOARD = 2,
|
||||
EV_DOWN = 4,
|
||||
EV_UP = 8,
|
||||
EV_MOUSE_WHEEL = 16,
|
||||
EV_MOUSE_LEFT = 32,
|
||||
EV_MOUSE_RIGHT = 64,
|
||||
EV_MOUSE_MIDDLE = 128,
|
||||
|
||||
EV_TEXT_ENTER = EV_KEYBOARD | 256,
|
||||
EV_KEY_DOWN = EV_KEYBOARD | EV_DOWN,
|
||||
EV_KEY_UP = EV_KEYBOARD | EV_UP,
|
||||
EV_MOUSE_MOVE = EV_MOUSE | 512,
|
||||
EV_MOUSE_LDOWN = EV_MOUSE | EV_MOUSE_LEFT | EV_DOWN,
|
||||
EV_MOUSE_LUP = EV_MOUSE | EV_MOUSE_LEFT | EV_UP,
|
||||
EV_MOUSE_MDOWN = EV_MOUSE | EV_MOUSE_MIDDLE | EV_DOWN,
|
||||
EV_MOUSE_MUP = EV_MOUSE | EV_MOUSE_MIDDLE | EV_UP,
|
||||
EV_MOUSE_RDOWN = EV_MOUSE | EV_MOUSE_RIGHT | EV_DOWN,
|
||||
EV_MOUSE_RUP = EV_MOUSE | EV_MOUSE_RIGHT | EV_UP,
|
||||
EV_MOUSE_WHEEL_UP = EV_MOUSE | EV_MOUSE_WHEEL | EV_UP,
|
||||
EV_MOUSE_WHEEL_DOWN = EV_MOUSE | EV_MOUSE_WHEEL | EV_DOWN
|
||||
enum InputEventType {
|
||||
EventNone = 0,
|
||||
EventMouseAction = 1,
|
||||
EventKeyboardAction = 2,
|
||||
EventDown = 4,
|
||||
EventUp = 8,
|
||||
EventMouseWheel = 16,
|
||||
EventMouseLeftButton = 32,
|
||||
EventMouseRightButton = 64,
|
||||
EventMouseMidButton = 128,
|
||||
EventTextEnter = 256,
|
||||
EventKeyDown = EventKeyboardAction | EventDown,
|
||||
EventKeyUp = EventKeyboardAction | EventUp,
|
||||
EventMouseMove = EventMouseAction | 512,
|
||||
EventMouseLeftButtonDown = EventMouseAction | EventMouseLeftButton | EventDown,
|
||||
EventMouseLeftButtonUp = EventMouseAction | EventMouseLeftButton | EventUp,
|
||||
EventMouseMiddleButtonDown = EventMouseAction | EventMouseMidButton | EventDown,
|
||||
EventMouseMiddleButtonUp = EventMouseAction | EventMouseMidButton | EventUp,
|
||||
EventMouseRightButtonDown = EventMouseAction | EventMouseRightButton | EventDown,
|
||||
EventMouseRightButtonUp = EventMouseAction | EventMouseRightButton | EventUp,
|
||||
EventMouseWheelUp = EventMouseAction | EventMouseWheel | EventUp,
|
||||
EventMouseWheelDown = EventMouseAction | EventMouseWheel | EventDown
|
||||
};
|
||||
|
||||
struct InputEvent {
|
||||
@@ -187,4 +186,4 @@ struct InputEvent {
|
||||
bool alt;
|
||||
};
|
||||
|
||||
#endif // INPUT_H
|
||||
#endif
|
73
src/framework/core/module.cpp
Normal file
73
src/framework/core/module.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
#include "module.h"
|
||||
|
||||
#include <otml/otml.h>
|
||||
#include <luascript/luainterface.h>
|
||||
#include "modulemanager.h"
|
||||
|
||||
void Module::discover(const OTMLNodePtr& moduleNode)
|
||||
{
|
||||
m_description = moduleNode->readAt<std::string>("description");
|
||||
m_author = moduleNode->readAt<std::string>("author");
|
||||
m_website = moduleNode->readAt<std::string>("website");
|
||||
m_version = moduleNode->readAt<std::string>("version");
|
||||
|
||||
if(OTMLNodePtr node = moduleNode->get("dependencies")) {
|
||||
for(const OTMLNodePtr& tmp : node->childNodes())
|
||||
m_dependencies.push_back(tmp->value());
|
||||
}
|
||||
|
||||
// set onLoad callback
|
||||
if(OTMLNodePtr node = moduleNode->get("onLoad")) {
|
||||
g_lua.loadFunction(node->read<std::string>(), "@" + node->source() + "[" + node->tag() + "]");
|
||||
g_lua.useValue();
|
||||
m_loadCallback = g_lua.polymorphicPop<BooleanCallback>();
|
||||
}
|
||||
|
||||
// set onUnload callback
|
||||
if(OTMLNodePtr node = moduleNode->get("onUnload")) {
|
||||
g_lua.loadFunction(node->read<std::string>(), "@" + node->source() + "[" + node->tag() + "]");
|
||||
g_lua.useValue();
|
||||
m_unloadCallback = g_lua.polymorphicPop<SimpleCallback>();
|
||||
}
|
||||
|
||||
// load if autoLoad is set
|
||||
m_autoLoad = moduleNode->readAt<bool>("autoLoad", false);
|
||||
}
|
||||
|
||||
bool Module::load()
|
||||
{
|
||||
for(const std::string& depName : m_dependencies) {
|
||||
ModulePtr dep = g_modules.getModule(depName);
|
||||
if(!dep) {
|
||||
logError("ERROR: failed to load module '",m_name,"': could not find module dependency '",depName,"'");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!dep->isLoaded()) {
|
||||
if(!dep->load()) {
|
||||
logError("ERROR: failed to load module '",m_name,"': a dependency has failed to load");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(m_loadCallback) {
|
||||
m_loaded = m_loadCallback();
|
||||
if(!m_loaded) {
|
||||
logError("ERROR: failed to load module '",m_name, "': onLoad returned false");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
logInfo("Loaded module '", m_name, "'");
|
||||
return true;
|
||||
}
|
||||
|
||||
void Module::unload()
|
||||
{
|
||||
if(m_loaded) {
|
||||
if(m_unloadCallback)
|
||||
m_unloadCallback();
|
||||
m_loaded = false;
|
||||
}
|
||||
}
|
40
src/framework/core/module.h
Normal file
40
src/framework/core/module.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef MODULE_H
|
||||
#define MODULE_H
|
||||
|
||||
#include <otml/otmldeclarations.h>
|
||||
|
||||
class Module;
|
||||
typedef std::shared_ptr<Module> ModulePtr;
|
||||
|
||||
class Module
|
||||
{
|
||||
public:
|
||||
Module(const std::string& name) : m_loaded(false), m_autoLoad(false), m_name(name) { }
|
||||
void discover(const OTMLNodePtr& moduleNode);
|
||||
|
||||
bool load();
|
||||
void unload();
|
||||
|
||||
bool isLoaded() const { return m_loaded; }
|
||||
|
||||
std::string getDescription() const { return m_description; }
|
||||
std::string getName() const { return m_name; }
|
||||
std::string getAuthor() const { return m_author; }
|
||||
std::string getWebsite() const { return m_website; }
|
||||
std::string getVersion() const { return m_version; }
|
||||
bool autoLoad() const { return m_autoLoad; }
|
||||
|
||||
private:
|
||||
bool m_loaded;
|
||||
bool m_autoLoad;
|
||||
std::string m_name;
|
||||
std::string m_description;
|
||||
std::string m_author;
|
||||
std::string m_website;
|
||||
std::string m_version;
|
||||
BooleanCallback m_loadCallback;
|
||||
SimpleCallback m_unloadCallback;
|
||||
std::list<std::string> m_dependencies;
|
||||
};
|
||||
|
||||
#endif
|
58
src/framework/core/modulemanager.cpp
Normal file
58
src/framework/core/modulemanager.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
#include "modulemanager.h"
|
||||
#include "resourcemanager.h"
|
||||
#include <otml/otml.h>
|
||||
|
||||
ModuleManager g_modules;
|
||||
|
||||
void ModuleManager::discoverAndLoadModules()
|
||||
{
|
||||
auto moduleDirs = g_resources.listDirectoryFiles("/");
|
||||
for(const std::string& moduleDir : moduleDirs) {
|
||||
auto moduleFiles = g_resources.listDirectoryFiles("/" + moduleDir);
|
||||
for(const std::string& file : moduleFiles) {
|
||||
if(boost::ends_with(file, ".otmod"))
|
||||
discoverModule("/" + moduleDir + "/" + file);
|
||||
}
|
||||
}
|
||||
|
||||
// auto load modules
|
||||
for(const ModulePtr& module : m_modules) {
|
||||
if(!module->isLoaded() && module->autoLoad())
|
||||
module->load();
|
||||
}
|
||||
}
|
||||
|
||||
bool ModuleManager::discoverModule(const std::string& file)
|
||||
{
|
||||
ModulePtr module;
|
||||
try {
|
||||
OTMLDocumentPtr doc = OTMLDocument::parse(file);
|
||||
OTMLNodePtr moduleNode = doc->at("Module");
|
||||
|
||||
std::string name = moduleNode->readAt<std::string>("name");
|
||||
if(getModule(name))
|
||||
throw OTMLException(moduleNode, "a module with the same name is already discovered, did you duplicate module names?");
|
||||
|
||||
module = ModulePtr(new Module(name));
|
||||
module->discover(moduleNode);
|
||||
m_modules.push_back(module);
|
||||
} catch(std::exception& e) {
|
||||
logError("ERROR: failed to load module from '", file, "':\n", e.what());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ModuleManager::unloadModules()
|
||||
{
|
||||
for(const ModulePtr& module : m_modules)
|
||||
module->unload();
|
||||
}
|
||||
|
||||
ModulePtr ModuleManager::getModule(const std::string& moduleName)
|
||||
{
|
||||
for(const ModulePtr& module : m_modules)
|
||||
if(module->getName() == moduleName)
|
||||
return module;
|
||||
return nullptr;
|
||||
}
|
21
src/framework/core/modulemanager.h
Normal file
21
src/framework/core/modulemanager.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef MODULEMANAGER_H
|
||||
#define MODULEMANAGER_H
|
||||
|
||||
#include "module.h"
|
||||
|
||||
class ModuleManager
|
||||
{
|
||||
public:
|
||||
void discoverAndLoadModules();
|
||||
bool discoverModule(const std::string& file);
|
||||
void unloadModules();
|
||||
|
||||
ModulePtr getModule(const std::string& moduleName);
|
||||
|
||||
private:
|
||||
std::vector<ModulePtr> m_modules;
|
||||
};
|
||||
|
||||
extern ModuleManager g_modules;
|
||||
|
||||
#endif
|
@@ -1,29 +0,0 @@
|
||||
#include "packages.h"
|
||||
|
||||
#include <core/resources.h>
|
||||
#include <script/luainterface.h>
|
||||
|
||||
Packages g_packages;
|
||||
|
||||
void Packages::loadPackages()
|
||||
{
|
||||
std::list<std::string> packages = g_resources.listDirectoryFiles("modules");
|
||||
foreach(const std::string& package, packages) {
|
||||
std::string dir = make_string("modules/", package);
|
||||
g_resources.pushCurrentPath(dir);
|
||||
|
||||
std::list<std::string> packagesFiles = g_resources.listDirectoryFiles();
|
||||
foreach(const std::string& packageFile, packagesFiles) {
|
||||
if(boost::ends_with(packageFile, ".lua")) {
|
||||
g_lua.runScript(packageFile);
|
||||
}
|
||||
}
|
||||
|
||||
g_resources.popCurrentPath();
|
||||
}
|
||||
}
|
||||
|
||||
void Packages::terminate()
|
||||
{
|
||||
|
||||
}
|
@@ -1,15 +0,0 @@
|
||||
#ifndef PACKAGES_H
|
||||
#define PACKAGES_H
|
||||
|
||||
#include <global.h>
|
||||
|
||||
class Packages
|
||||
{
|
||||
public:
|
||||
void loadPackages();
|
||||
void terminate();
|
||||
};
|
||||
|
||||
extern Packages g_packages;
|
||||
|
||||
#endif // MODULES_H
|
@@ -3,53 +3,63 @@
|
||||
|
||||
#include <global.h>
|
||||
|
||||
class PlatformListener;
|
||||
|
||||
class Platform
|
||||
{
|
||||
public:
|
||||
static void init(const char *appName);
|
||||
static void terminate();
|
||||
void init(PlatformListener* platformListener, const char* appName);
|
||||
void terminate();
|
||||
|
||||
/// Poll platform input/window events
|
||||
static void poll();
|
||||
void poll();
|
||||
|
||||
/// Get current time in milliseconds since init
|
||||
static int getTicks();
|
||||
int getTicks();
|
||||
/// Sleep in current thread
|
||||
static void sleep(ulong miliseconds);
|
||||
void sleep(ulong ms);
|
||||
|
||||
static bool createWindow(int x, int y, int width, int height, int minWidth, int minHeight, bool maximized);
|
||||
static void destroyWindow();
|
||||
static void showWindow();
|
||||
static void setWindowTitle(const char *title);
|
||||
static bool isWindowFocused();
|
||||
static bool isWindowVisible();
|
||||
static int getWindowX();
|
||||
static int getWindowY();
|
||||
static int getWindowWidth();
|
||||
static int getWindowHeight();
|
||||
static bool isWindowMaximized();
|
||||
bool createWindow(int x, int y, int width, int height, int minWidth, int minHeight, bool maximized);
|
||||
void destroyWindow();
|
||||
void showWindow();
|
||||
void hideWindow();
|
||||
void setWindowTitle(const char* title);
|
||||
bool isWindowFocused();
|
||||
bool isWindowVisible();
|
||||
int getWindowX();
|
||||
int getWindowY();
|
||||
int getWindowWidth();
|
||||
int getWindowHeight();
|
||||
bool isWindowMaximized();
|
||||
|
||||
static int getDisplayHeight();
|
||||
static int getDisplayWidth();
|
||||
int getDisplayHeight();
|
||||
int getDisplayWidth();
|
||||
|
||||
/// Get GL extension function address
|
||||
static void *getExtensionProcAddress(const char *ext);
|
||||
/// Check if GL extension is supported
|
||||
static bool isExtensionSupported(const char *ext);
|
||||
void* getExtensionProcAddress(const char* ext);
|
||||
/// Check if GLX/WGL extension is supported
|
||||
bool isExtensionSupported(const char* ext);
|
||||
|
||||
static const char *getClipboardText();
|
||||
static void setClipboardText(const char *text);
|
||||
/// Get text from Ctrl+c
|
||||
const char* getClipboardText();
|
||||
/// Set text for Ctrl+v
|
||||
void setClipboardText(const char* text);
|
||||
|
||||
static void hideMouseCursor();
|
||||
static void showMouseCursor();
|
||||
void hideMouseCursor();
|
||||
void showMouseCursor();
|
||||
|
||||
/// Enable/disable vertical synchronization
|
||||
static void setVsync(bool enable = true);
|
||||
/// Enable or disable vertical synchronization
|
||||
void setVerticalSync(bool enable);
|
||||
/// Swap GL buffers
|
||||
static void swapBuffers();
|
||||
void swapBuffers();
|
||||
|
||||
/// Get the app user directory, the place to save files configurations files
|
||||
static std::string getAppUserDir();
|
||||
std::string getAppUserDir();
|
||||
|
||||
private:
|
||||
PlatformListener* m_listener;
|
||||
};
|
||||
|
||||
#endif // PLATFORM_H
|
||||
extern Platform g_platform;
|
||||
|
||||
#endif
|
||||
|
17
src/framework/core/platformlistener.h
Normal file
17
src/framework/core/platformlistener.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef PLATFORMLISTENER_H
|
||||
#define PLATFORMLISTENER_H
|
||||
|
||||
#include "inputevent.h"
|
||||
|
||||
class PlatformListener
|
||||
{
|
||||
public:
|
||||
/// Fired when user tries to close the window
|
||||
virtual void onClose() = 0;
|
||||
/// Fired when user resize the window
|
||||
virtual void onResize(const Size& size) = 0;
|
||||
/// Fired when user press a key or move the mouse
|
||||
virtual void onInputEvent(const InputEvent& event) = 0;
|
||||
};
|
||||
|
||||
#endif
|
170
src/framework/core/resourcemanager.cpp
Normal file
170
src/framework/core/resourcemanager.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
#include "resourcemanager.h"
|
||||
|
||||
#include <core/platform.h>
|
||||
#include <luascript/luainterface.h>
|
||||
|
||||
#include <physfs.h>
|
||||
|
||||
ResourceManager g_resources;
|
||||
|
||||
void ResourceManager::init(const char* argv0)
|
||||
{
|
||||
PHYSFS_init(argv0);
|
||||
|
||||
// try to find modules directory, all data lives there
|
||||
std::string baseDir = PHYSFS_getBaseDir();
|
||||
|
||||
std::string possibleDirs[] = { "modules",
|
||||
baseDir + "modules",
|
||||
baseDir + "../modules",
|
||||
baseDir + "../share/otclient/modules",
|
||||
"" };
|
||||
|
||||
bool found = false;
|
||||
for(const std::string& dir : possibleDirs) {
|
||||
if(g_resources.addToSearchPath(dir)) {
|
||||
logInfo("Using modules directory '", dir.c_str(), "'");
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found)
|
||||
throw std::runtime_error("could not find modules directory");
|
||||
|
||||
// setup write directory
|
||||
std::string dir = g_platform.getAppUserDir();
|
||||
if(g_resources.setWriteDir(dir))
|
||||
g_resources.addToSearchPath(dir);
|
||||
else
|
||||
throw std::runtime_error("could not setup write directory");
|
||||
}
|
||||
|
||||
void ResourceManager::terminate()
|
||||
{
|
||||
PHYSFS_deinit();
|
||||
}
|
||||
|
||||
bool ResourceManager::setWriteDir(const std::string& path)
|
||||
{
|
||||
if(!PHYSFS_setWriteDir(path.c_str()))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResourceManager::addToSearchPath(const std::string& path, bool insertInFront)
|
||||
{
|
||||
if(!PHYSFS_addToSearchPath(path.c_str(), insertInFront ? 0 : 1))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ResourceManager::searchAndAddPackages(const std::string& packagesDir, const std::string& packageExt, bool append)
|
||||
{
|
||||
auto files = listDirectoryFiles(resolvePath(packagesDir));
|
||||
for(const std::string& file : files) {
|
||||
if(boost::ends_with(file, packageExt))
|
||||
addToSearchPath(packagesDir + "/" + file, !append);
|
||||
}
|
||||
}
|
||||
|
||||
bool ResourceManager::fileExists(const std::string& fileName)
|
||||
{
|
||||
return (PHYSFS_exists(resolvePath(fileName).c_str()) && !PHYSFS_isDirectory(resolvePath(fileName).c_str()));
|
||||
}
|
||||
|
||||
bool ResourceManager::directoryExists(const std::string& directoryName)
|
||||
{
|
||||
return (PHYSFS_exists(resolvePath(directoryName).c_str()) && PHYSFS_isDirectory(resolvePath(directoryName).c_str()));
|
||||
}
|
||||
|
||||
void ResourceManager::loadFile(const std::string& fileName, std::iostream& out)
|
||||
{
|
||||
std::string fullPath = resolvePath(fileName);
|
||||
out.clear(std::ios::goodbit);
|
||||
PHYSFS_file* file = PHYSFS_openRead(fullPath.c_str());
|
||||
if(!file) {
|
||||
out.clear(std::ios::failbit);
|
||||
throw std::runtime_error(aux::make_string("failed to load file '", fullPath.c_str(), "': ", PHYSFS_getLastError()));
|
||||
} else {
|
||||
int fileSize = PHYSFS_fileLength(file);
|
||||
if(fileSize > 0) {
|
||||
char* buffer = new char[fileSize];
|
||||
PHYSFS_read(file, (void*)buffer, 1, fileSize);
|
||||
out.write(buffer, fileSize);
|
||||
delete[] buffer;
|
||||
} else
|
||||
out.clear(std::ios::eofbit);
|
||||
PHYSFS_close(file);
|
||||
out.seekg(0, std::ios::beg);
|
||||
}
|
||||
}
|
||||
|
||||
std::string ResourceManager::loadFile(const std::string& fileName)
|
||||
{
|
||||
std::stringstream fin;
|
||||
loadFile(fileName, fin);
|
||||
return fin.str();
|
||||
}
|
||||
|
||||
bool ResourceManager::saveFile(const std::string& fileName, const uchar* data, uint size)
|
||||
{
|
||||
PHYSFS_file* file = PHYSFS_openWrite(resolvePath(fileName).c_str());
|
||||
if(!file)
|
||||
return false;
|
||||
|
||||
PHYSFS_write(file, (void*)data, size, 1);
|
||||
PHYSFS_close(file);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResourceManager::saveFile(const std::string& fileName, std::istream& in)
|
||||
{
|
||||
std::streampos oldPos = in.tellg();
|
||||
in.seekg(0, std::ios::end);
|
||||
std::streampos size = in.tellg();
|
||||
in.seekg(0, std::ios::beg);
|
||||
char* buffer = new char[size];
|
||||
in.read(buffer, size);
|
||||
bool ret = saveFile(fileName, (const uchar*)buffer, size);
|
||||
delete[] buffer;
|
||||
in.seekg(oldPos, std::ios::beg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ResourceManager::saveFile(const std::string& fileName, const std::string& data)
|
||||
{
|
||||
return saveFile(fileName, (const uchar*)data.c_str(), data.size());
|
||||
}
|
||||
|
||||
bool ResourceManager::deleteFile(const std::string& fileName)
|
||||
{
|
||||
return PHYSFS_delete(resolvePath(fileName).c_str()) != 0;
|
||||
}
|
||||
|
||||
std::list<std::string> ResourceManager::listDirectoryFiles(const std::string& directoryPath)
|
||||
{
|
||||
std::list<std::string> files;
|
||||
char** rc = PHYSFS_enumerateFiles(resolvePath(directoryPath).c_str());
|
||||
|
||||
for(char** i = rc; *i != NULL; i++)
|
||||
files.push_back(*i);
|
||||
|
||||
PHYSFS_freeList(rc);
|
||||
return files;
|
||||
}
|
||||
|
||||
std::string ResourceManager::resolvePath(const std::string& path)
|
||||
{
|
||||
std::string fullPath;
|
||||
if(boost::starts_with(path, "/"))
|
||||
fullPath = path.substr(1);
|
||||
else {
|
||||
std::string scriptPath = g_lua.currentSourcePath();
|
||||
if(!scriptPath.empty()) {
|
||||
fullPath += scriptPath + "/";
|
||||
}
|
||||
fullPath += path;
|
||||
}
|
||||
return fullPath;
|
||||
}
|
40
src/framework/core/resourcemanager.h
Normal file
40
src/framework/core/resourcemanager.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef RESOURCES_H
|
||||
#define RESOURCES_H
|
||||
|
||||
#include <global.h>
|
||||
|
||||
class ResourceManager
|
||||
{
|
||||
public:
|
||||
void init(const char* argv0);
|
||||
void terminate();
|
||||
|
||||
/// Set output files directory
|
||||
bool setWriteDir(const std::string& path);
|
||||
|
||||
/// Add an package or directory to the search path
|
||||
bool addToSearchPath(const std::string& path, bool insertInFront = true);
|
||||
|
||||
/// Search and packages from a directory to the search path
|
||||
void searchAndAddPackages(const std::string& packagesDir, const std::string& packagesExt, bool append);
|
||||
|
||||
bool fileExists(const std::string& fileName);
|
||||
bool directoryExists(const std::string& directoryName);
|
||||
|
||||
void loadFile(const std::string& fileName, std::iostream& out);
|
||||
std::string loadFile(const std::string& fileName);
|
||||
|
||||
bool saveFile(const std::string& fileName, const uchar* data, uint size);
|
||||
bool saveFile(const std::string& fileName, const std::string& data);
|
||||
bool saveFile(const std::string& fileName, std::istream& in);
|
||||
|
||||
bool deleteFile(const std::string& fileName);
|
||||
|
||||
std::list<std::string> listDirectoryFiles(const std::string& directoryPath = "");
|
||||
|
||||
std::string resolvePath(const std::string& path);
|
||||
};
|
||||
|
||||
extern ResourceManager g_resources;
|
||||
|
||||
#endif
|
@@ -1,176 +0,0 @@
|
||||
#include <global.h>
|
||||
#include "resources.h"
|
||||
#include "platform.h"
|
||||
|
||||
#include <physfs.h>
|
||||
|
||||
Resources g_resources;
|
||||
|
||||
void Resources::init(const char *argv0)
|
||||
{
|
||||
PHYSFS_init(argv0);
|
||||
|
||||
// try to find data directory
|
||||
std::string dir;
|
||||
std::string baseDir = PHYSFS_getBaseDir();
|
||||
|
||||
std::string possibleDirs[] = { "data",
|
||||
baseDir + "data",
|
||||
baseDir + "../data",
|
||||
baseDir + "../share/otclient/data",
|
||||
"" };
|
||||
|
||||
bool found = false;
|
||||
foreach(dir, possibleDirs) {
|
||||
if(g_resources.addToSearchPath(dir)) {
|
||||
logInfo("Using data directory: ", dir.c_str());
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found)
|
||||
logFatal("ERROR: could not find data directory");
|
||||
|
||||
// setup write directory
|
||||
dir = Platform::getAppUserDir();
|
||||
if(g_resources.setWriteDir(dir))
|
||||
g_resources.addToSearchPath(dir);
|
||||
else
|
||||
logError("ERROR: could not setup write directory");
|
||||
}
|
||||
|
||||
void Resources::terminate()
|
||||
{
|
||||
PHYSFS_deinit();
|
||||
}
|
||||
|
||||
bool Resources::setWriteDir(const std::string& path)
|
||||
{
|
||||
if(!PHYSFS_setWriteDir(path.c_str()))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Resources::addToSearchPath(const std::string& path, bool insertInFront /*= true*/)
|
||||
{
|
||||
if(!PHYSFS_addToSearchPath(path.c_str(), insertInFront ? 0 : 1))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Resources::addPackagesToSearchPath(const std::string &packagesDirectory, const std::string &packageExtension, bool append)
|
||||
{
|
||||
auto files = listDirectoryFiles(resolvePath(packagesDirectory));
|
||||
foreach(const std::string& file, files) {
|
||||
if(boost::ends_with(file, packageExtension))
|
||||
addToSearchPath(packagesDirectory + "/" + file, !append);
|
||||
}
|
||||
}
|
||||
|
||||
bool Resources::fileExists(const std::string& fileName)
|
||||
{
|
||||
return (PHYSFS_exists(resolvePath(fileName).c_str()) && !PHYSFS_isDirectory(resolvePath(fileName).c_str()));
|
||||
}
|
||||
|
||||
bool Resources::directoryExists(const std::string& directoryName)
|
||||
{
|
||||
return (PHYSFS_exists(resolvePath(directoryName).c_str()) && PHYSFS_isDirectory(resolvePath(directoryName).c_str()));
|
||||
}
|
||||
|
||||
bool Resources::loadFile(const std::string& fileName, std::iostream& out)
|
||||
{
|
||||
std::string fullPath = resolvePath(fileName);
|
||||
out.clear(std::ios::goodbit);
|
||||
PHYSFS_file *file = PHYSFS_openRead(fullPath.c_str());
|
||||
if(!file) {
|
||||
logError("ERROR: Failed to load file '", fullPath.c_str(), "': ", PHYSFS_getLastError());
|
||||
out.clear(std::ios::failbit);
|
||||
return false;
|
||||
} else {
|
||||
int fileSize = PHYSFS_fileLength(file);
|
||||
if(fileSize > 0) {
|
||||
char *buffer = new char[fileSize];
|
||||
PHYSFS_read(file, (void*)buffer, 1, fileSize);
|
||||
out.write(buffer, fileSize);
|
||||
delete[] buffer;
|
||||
} else
|
||||
out.clear(std::ios::eofbit);
|
||||
PHYSFS_close(file);
|
||||
out.seekg(0, std::ios::beg);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool Resources::saveFile(const std::string &fileName, const uchar *data, uint size)
|
||||
{
|
||||
PHYSFS_file *file = PHYSFS_openWrite(resolvePath(fileName).c_str());
|
||||
if(!file) {
|
||||
logError("ERROR: Failed to save file '",fileName,"': ",PHYSFS_getLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
PHYSFS_write(file, (void*)data, size, 1);
|
||||
PHYSFS_close(file);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Resources::saveFile(const std::string &fileName, std::istream& in)
|
||||
{
|
||||
std::streampos oldPos = in.tellg();
|
||||
in.seekg(0, std::ios::end);
|
||||
std::streampos size = in.tellg();
|
||||
in.seekg(0, std::ios::beg);
|
||||
char *buffer = new char[size];
|
||||
in.read(buffer, size);
|
||||
bool ret = saveFile(fileName, (const uchar*)buffer, size);
|
||||
delete[] buffer;
|
||||
in.seekg(oldPos, std::ios::beg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Resources::deleteFile(const std::string& fileName)
|
||||
{
|
||||
return PHYSFS_delete(resolvePath(fileName).c_str()) != 0;
|
||||
}
|
||||
|
||||
std::list<std::string> Resources::listDirectoryFiles(const std::string& directoryPath)
|
||||
{
|
||||
std::list<std::string> files;
|
||||
char **rc = PHYSFS_enumerateFiles(resolvePath(directoryPath).c_str());
|
||||
|
||||
for(char **i = rc; *i != NULL; i++)
|
||||
files.push_back(*i);
|
||||
|
||||
PHYSFS_freeList(rc);
|
||||
return files;
|
||||
}
|
||||
|
||||
void Resources::pushCurrentPath(const std::string ¤tPath)
|
||||
{
|
||||
//logTraceDebug(currentPath);
|
||||
m_currentPaths.push(currentPath);
|
||||
}
|
||||
|
||||
void Resources::popCurrentPath()
|
||||
{
|
||||
m_currentPaths.pop();
|
||||
//if(!m_currentPaths.empty())
|
||||
// logTraceDebug(m_currentPaths.top());
|
||||
}
|
||||
|
||||
std::string Resources::resolvePath(const std::string& path)
|
||||
{
|
||||
std::string fullPath;
|
||||
if(boost::starts_with(path, "/"))
|
||||
fullPath = path.substr(1);
|
||||
else {
|
||||
if(m_currentPaths.size() > 0) {
|
||||
std::string currentPath = m_currentPaths.top();
|
||||
if(currentPath.length() > 0)
|
||||
fullPath += currentPath + "/";
|
||||
}
|
||||
fullPath += path;
|
||||
}
|
||||
return fullPath;
|
||||
}
|
||||
|
@@ -1,46 +0,0 @@
|
||||
#ifndef RESOURCES_H
|
||||
#define RESOURCES_H
|
||||
|
||||
#include <global.h>
|
||||
#include <stack>
|
||||
|
||||
class Resources
|
||||
{
|
||||
public:
|
||||
Resources() { }
|
||||
|
||||
void init(const char *argv0);
|
||||
void terminate();
|
||||
|
||||
/// Set output files dir
|
||||
bool setWriteDir(const std::string &path);
|
||||
|
||||
/// Add an package or directory to the search path
|
||||
bool addToSearchPath(const std::string& path, bool insertInFront = true);
|
||||
/// Add all packages from a directory
|
||||
void addPackagesToSearchPath(const std::string &packagesDirectory, const std::string &packageExtension, bool append);
|
||||
|
||||
bool fileExists(const std::string& fileName);
|
||||
bool directoryExists(const std::string& directoryName);
|
||||
|
||||
bool loadFile(const std::string& fileName, std::iostream& out);
|
||||
|
||||
bool saveFile(const std::string& fileName, const uchar *data, uint size);
|
||||
bool saveFile(const std::string& fileName, const std::string& data) { return saveFile(fileName, (const uchar*)data.c_str(), data.size()); }
|
||||
bool saveFile(const std::string& fileName, std::istream& in);
|
||||
|
||||
bool deleteFile(const std::string& fileName);
|
||||
|
||||
std::list<std::string> listDirectoryFiles(const std::string& directoryPath = "");
|
||||
|
||||
void pushCurrentPath(const std::string ¤tPath);
|
||||
void popCurrentPath();
|
||||
std::string resolvePath(const std::string& path);
|
||||
|
||||
private:
|
||||
std::stack<std::string> m_currentPaths;
|
||||
};
|
||||
|
||||
extern Resources g_resources;
|
||||
|
||||
#endif // RESOURCES_H
|
0
src/framework/core/win32platform.cpp
Normal file
0
src/framework/core/win32platform.cpp
Normal file
@@ -1,6 +1,5 @@
|
||||
#include <global.h>
|
||||
#include <core/platform.h>
|
||||
#include <core/engine.h>
|
||||
#include "platform.h"
|
||||
#include "platformlistener.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -41,12 +40,15 @@ struct X11PlatformPrivate {
|
||||
int y;
|
||||
std::string clipboardText;
|
||||
std::map<int, uchar> keyMap;
|
||||
PlatformListener* listener;
|
||||
} x11;
|
||||
|
||||
void Platform::init(const char *appName)
|
||||
Platform g_platform;
|
||||
|
||||
void Platform::init(PlatformListener* platformListener, const char *appName)
|
||||
{
|
||||
// seend random numbers
|
||||
std::srand(std::time(NULL));
|
||||
srand(time(NULL));
|
||||
|
||||
x11.appName = appName;
|
||||
x11.display = NULL;
|
||||
@@ -62,6 +64,7 @@ void Platform::init(const char *appName)
|
||||
x11.width = 0;
|
||||
x11.height = 0;
|
||||
x11.maximizeOnFirstShow = false;
|
||||
m_listener = platformListener;
|
||||
|
||||
// setup keymap
|
||||
x11.keyMap[XK_1] = KC_1;
|
||||
@@ -280,7 +283,7 @@ void Platform::poll()
|
||||
static int oldWidth = -1;
|
||||
static int oldHeight = -1;
|
||||
if(oldWidth != event.xconfigure.width || oldHeight != event.xconfigure.height) {
|
||||
g_engine.onResize(Size(event.xconfigure.width, event.xconfigure.height));
|
||||
m_listener->onResize(Size(event.xconfigure.width, event.xconfigure.height));
|
||||
oldWidth = event.xconfigure.width;
|
||||
oldHeight = event.xconfigure.height;
|
||||
}
|
||||
@@ -329,10 +332,10 @@ void Platform::poll()
|
||||
(uchar)(buf[0]) >= 32
|
||||
) {
|
||||
//logDebug("char: ", buf[0], " code: ", (uint)buf[0]);
|
||||
inputEvent.type = EV_TEXT_ENTER;
|
||||
inputEvent.type = EventTextEnter;
|
||||
inputEvent.keychar = buf[0];
|
||||
inputEvent.keycode = KC_UNKNOWN;
|
||||
g_engine.onInputEvent(inputEvent);
|
||||
m_listener->onInputEvent(inputEvent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,9 +346,9 @@ void Platform::poll()
|
||||
// fire key up/down event
|
||||
if(x11.keyMap.find(keysym) != x11.keyMap.end()) {
|
||||
inputEvent.keycode = x11.keyMap[keysym];
|
||||
inputEvent.type = (event.type == KeyPress) ? EV_KEY_DOWN : EV_KEY_UP;
|
||||
inputEvent.type = (event.type == KeyPress) ? EventKeyDown : EventKeyUp;
|
||||
inputEvent.keychar = (len > 0) ? buf[0] : 0;
|
||||
g_engine.onInputEvent(inputEvent);
|
||||
m_listener->onInputEvent(inputEvent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -353,31 +356,31 @@ void Platform::poll()
|
||||
case ButtonRelease:
|
||||
switch(event.xbutton.button) {
|
||||
case Button1:
|
||||
inputEvent.type = (event.type == ButtonPress) ? EV_MOUSE_LDOWN : EV_MOUSE_LUP;
|
||||
inputEvent.type = (event.type == ButtonPress) ? EventMouseLeftButtonDown : EventMouseLeftButtonUp;
|
||||
break;
|
||||
case Button3:
|
||||
inputEvent.type = (event.type == ButtonPress) ? EV_MOUSE_RDOWN : EV_MOUSE_RUP;
|
||||
inputEvent.type = (event.type == ButtonPress) ? EventMouseRightButtonDown : EventMouseRightButtonUp;
|
||||
break;
|
||||
case Button2:
|
||||
inputEvent.type = (event.type == ButtonPress) ? EV_MOUSE_MDOWN : EV_MOUSE_MUP;
|
||||
inputEvent.type = (event.type == ButtonPress) ? EventMouseMiddleButtonDown : EventMouseMiddleButtonUp;
|
||||
break;
|
||||
case Button4:
|
||||
inputEvent.type = EV_MOUSE_WHEEL_UP;
|
||||
inputEvent.type = EventMouseWheelUp;
|
||||
break;
|
||||
case Button5:
|
||||
inputEvent.type = EV_MOUSE_WHEEL_DOWN;
|
||||
inputEvent.type = EventMouseWheelDown;
|
||||
break;
|
||||
}
|
||||
g_engine.onInputEvent(inputEvent);
|
||||
m_listener->onInputEvent(inputEvent);
|
||||
break;
|
||||
|
||||
case MotionNotify:
|
||||
{
|
||||
inputEvent.type = EV_MOUSE_MOVE;
|
||||
inputEvent.type = EventMouseMove;
|
||||
Point newMousePos(event.xbutton.x, event.xbutton.y);
|
||||
inputEvent.mouseMoved = newMousePos - inputEvent.mousePos;
|
||||
inputEvent.mousePos = newMousePos;
|
||||
g_engine.onInputEvent(inputEvent);
|
||||
m_listener->onInputEvent(inputEvent);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -437,7 +440,7 @@ void Platform::poll()
|
||||
case ClientMessage:
|
||||
{
|
||||
if((Atom)event.xclient.data.l[0] == x11.atomDeleteWindow)
|
||||
g_engine.onClose();
|
||||
m_listener->onClose();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -555,7 +558,7 @@ bool Platform::createWindow(int x, int y, int width, int height, int minWidth, i
|
||||
x11.maximizeOnFirstShow = maximized;
|
||||
|
||||
// call first onResize
|
||||
g_engine.onResize(Size(width, height));
|
||||
m_listener->onResize(Size(width, height));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -579,7 +582,6 @@ void Platform::destroyWindow()
|
||||
}
|
||||
|
||||
if(x11.window != None) {
|
||||
XUnmapWindow(x11.display, x11.window);
|
||||
XDestroyWindow(x11.display, x11.window);
|
||||
x11.window = None;
|
||||
}
|
||||
@@ -607,7 +609,7 @@ void Platform::showWindow()
|
||||
// set window maximized if needed
|
||||
if(x11.maximizeOnFirstShow) {
|
||||
XEvent e;
|
||||
bzero(&e, sizeof(XEvent));
|
||||
memset(&e, 0, sizeof(XEvent));
|
||||
e.xany.type = ClientMessage;
|
||||
e.xclient.message_type = x11.atomWindowState;
|
||||
e.xclient.format = 32;
|
||||
@@ -624,6 +626,11 @@ void Platform::showWindow()
|
||||
}
|
||||
}
|
||||
|
||||
void Platform::hideWindow()
|
||||
{
|
||||
XUnmapWindow(x11.display, x11.window);
|
||||
}
|
||||
|
||||
void Platform::setWindowTitle(const char *title)
|
||||
{
|
||||
XStoreName(x11.display, x11.window, title);
|
||||
@@ -722,7 +729,7 @@ void Platform::showMouseCursor()
|
||||
}
|
||||
}
|
||||
|
||||
void Platform::setVsync(bool enable)
|
||||
void Platform::setVerticalSync(bool enable)
|
||||
{
|
||||
typedef GLint (*glSwapIntervalProc)(GLint);
|
||||
glSwapIntervalProc glSwapInterval = NULL;
|
||||
@@ -817,4 +824,4 @@ std::string Platform::getAppUserDir()
|
||||
if((mkdir(sdir.str().c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) && (errno != EEXIST))
|
||||
logError("ERROR: Couldn't create directory for saving configuration file. (",sdir.str(),")");
|
||||
return sdir.str();
|
||||
}
|
||||
}
|
@@ -16,24 +16,30 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <queue>
|
||||
#include <deque>
|
||||
#include <stack>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <tuple>
|
||||
#include <functional>
|
||||
#include <regex>
|
||||
#include <unordered_map>
|
||||
#include <typeinfo>
|
||||
#include <array>
|
||||
|
||||
// string algorithms
|
||||
// boost utilities
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
// constants
|
||||
#include <const.h>
|
||||
|
||||
// easy types
|
||||
// additional utilities
|
||||
#include <util/types.h>
|
||||
#include <util/auxiliary.h>
|
||||
#include <util/logger.h>
|
||||
#include <util/translator.h>
|
||||
|
||||
// custom types
|
||||
#include <util/point.h>
|
||||
@@ -41,11 +47,4 @@
|
||||
#include <util/rect.h>
|
||||
#include <util/size.h>
|
||||
|
||||
// additional utilities
|
||||
#include <util/convert.h>
|
||||
#include <util/foreach.h>
|
||||
#include <util/makestring.h>
|
||||
#include <util/logger.h>
|
||||
#include <util/algorithms.h>
|
||||
|
||||
#endif // GLOBAL_H
|
||||
#endif
|
||||
|
@@ -1,30 +1,9 @@
|
||||
/* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 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 "animatedtexture.h"
|
||||
#include "graphics.h"
|
||||
#include <core/platform.h>
|
||||
#include <core/eventdispatcher.h>
|
||||
|
||||
|
||||
#include <graphics/animatedtexture.h>
|
||||
#include <core/engine.h>
|
||||
#include <core/dispatcher.h>
|
||||
#include <GL/gl.h>
|
||||
|
||||
AnimatedTexture::AnimatedTexture(int width, int height, int channels, int numFrames, uchar *framesPixels, int *framesDelay) :
|
||||
Texture(),
|
||||
@@ -44,11 +23,13 @@ AnimatedTexture::AnimatedTexture(int width, int height, int channels, int numFra
|
||||
}
|
||||
|
||||
m_currentFrame = -1;
|
||||
g_dispatcher.scheduleTask(std::bind(&AnimatedTexture::processAnimation, this), 0);
|
||||
g_dispatcher.scheduleEvent(std::bind(&AnimatedTexture::processAnimation, this), 0);
|
||||
}
|
||||
|
||||
AnimatedTexture::~AnimatedTexture()
|
||||
{
|
||||
g_graphics.disableDrawing();
|
||||
|
||||
glDeleteTextures(m_numFrames, m_framesTextureId);
|
||||
delete[] m_framesTextureId;
|
||||
delete[] m_framesDelay;
|
||||
@@ -57,6 +38,8 @@ AnimatedTexture::~AnimatedTexture()
|
||||
|
||||
void AnimatedTexture::enableBilinearFilter()
|
||||
{
|
||||
g_graphics.disableDrawing();
|
||||
|
||||
for(int i=0;i<m_numFrames;++i) {
|
||||
glBindTexture(GL_TEXTURE_2D, m_framesTextureId[i]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
@@ -72,5 +55,5 @@ void AnimatedTexture::processAnimation()
|
||||
m_textureId = m_framesTextureId[m_currentFrame];
|
||||
AnimatedTexturePtr me = std::static_pointer_cast<AnimatedTexture>(shared_from_this());
|
||||
if(me.use_count() > 1)
|
||||
g_dispatcher.scheduleTask(std::bind(&AnimatedTexture::processAnimation, me), m_framesDelay[m_currentFrame]);
|
||||
g_dispatcher.addEvent(std::bind(&AnimatedTexture::processAnimation, me), m_framesDelay[m_currentFrame]);
|
||||
}
|
||||
|
@@ -1,32 +1,7 @@
|
||||
/* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 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 ANIMATEDTEXTURE_H
|
||||
#define ANIMATEDTEXTURE_H
|
||||
|
||||
#include <global.h>
|
||||
#include <graphics/graphics.h>
|
||||
#include "texture.h"
|
||||
|
||||
class AnimatedTexture : public Texture
|
||||
{
|
||||
@@ -48,4 +23,4 @@ private:
|
||||
typedef std::shared_ptr<AnimatedTexture> AnimatedTexturePtr;
|
||||
typedef std::weak_ptr<AnimatedTexture> AnimatedTextureWeakPtr;
|
||||
|
||||
#endif // ANIMATEDTEXTURE_H
|
||||
#endif
|
||||
|
@@ -1,73 +0,0 @@
|
||||
/* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 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 BORDEREDIMAGE_H
|
||||
#define BORDEREDIMAGE_H
|
||||
|
||||
#include <global.h>
|
||||
#include <graphics/image.h>
|
||||
#include <graphics/texture.h>
|
||||
#include <otml/otmlnode.h>
|
||||
|
||||
class BorderedImage;
|
||||
typedef std::shared_ptr<BorderedImage> BorderedImagePtr;
|
||||
|
||||
class BorderedImage : public Image
|
||||
{
|
||||
public:
|
||||
BorderedImage(TexturePtr texture,
|
||||
const Rect& left,
|
||||
const Rect& right,
|
||||
const Rect& top,
|
||||
const Rect& bottom,
|
||||
const Rect& topLeft,
|
||||
const Rect& topRight,
|
||||
const Rect& bottomLeft,
|
||||
const Rect& bottomRight,
|
||||
const Rect& center);
|
||||
|
||||
void draw(const Rect& screenCoords);
|
||||
|
||||
Size getDefaultSize() const { return m_defaultSize; }
|
||||
|
||||
static BorderedImagePtr loadFromOTMLNode(OTMLNode *node, TexturePtr defaultTexture = TexturePtr());
|
||||
|
||||
private:
|
||||
Rect m_leftBorderTexCoords;
|
||||
Rect m_rightBorderTexCoords;
|
||||
Rect m_topBorderTexCoords;
|
||||
Rect m_bottomBorderTexCoords;
|
||||
|
||||
Rect m_topLeftCornerTexCoords;
|
||||
Rect m_topRightCornerTexCoords;
|
||||
Rect m_bottomLeftCornerTexCoords;
|
||||
Rect m_bottomRightCornerTexCoords;
|
||||
|
||||
Rect m_centerTexCoords;
|
||||
|
||||
Size m_bordersSize;
|
||||
Size m_defaultSize;
|
||||
};
|
||||
|
||||
#endif // BORDEREDIMAGE_H
|
@@ -1,33 +1,11 @@
|
||||
/* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 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 "borderimage.h"
|
||||
#include "graphics.h"
|
||||
#include "texture.h"
|
||||
#include "texturemanager.h"
|
||||
|
||||
#include <otml/otml.h>
|
||||
|
||||
#include <global.h>
|
||||
#include <graphics/borderedimage.h>
|
||||
#include <graphics/graphics.h>
|
||||
#include <graphics/textures.h>
|
||||
|
||||
BorderedImage::BorderedImage(TexturePtr texture,
|
||||
BorderImage::BorderImage(TexturePtr texture,
|
||||
const Rect& left,
|
||||
const Rect& right,
|
||||
const Rect& top,
|
||||
@@ -59,7 +37,7 @@ BorderedImage::BorderedImage(TexturePtr texture,
|
||||
center.height());
|
||||
}
|
||||
|
||||
BorderedImagePtr BorderedImage::loadFromOTMLNode(OTMLNode* node, TexturePtr defaultTexture)
|
||||
BorderImagePtr BorderImage::loadFromOTML(const OTMLNodePtr& borderImageNode)
|
||||
{
|
||||
Rect leftBorder;
|
||||
Rect rightBorder;
|
||||
@@ -75,26 +53,27 @@ BorderedImagePtr BorderedImage::loadFromOTMLNode(OTMLNode* node, TexturePtr defa
|
||||
Size size;
|
||||
Point offset;
|
||||
|
||||
TexturePtr texture;
|
||||
std::string textureSource = node->readAt("source", std::string());
|
||||
if(!textureSource.empty())
|
||||
texture = g_textures.get(textureSource);
|
||||
else
|
||||
texture = defaultTexture;
|
||||
|
||||
// load texture
|
||||
std::string source = borderImageNode->at("source")->value();
|
||||
TexturePtr texture = g_textures.getTexture(source);
|
||||
if(!texture)
|
||||
return BorderedImagePtr();
|
||||
throw OTMLException(borderImageNode, "could not load border-image texture");
|
||||
|
||||
// load basic border confs
|
||||
size = texture->getSize();
|
||||
size = node->readAt("size", size);
|
||||
offset = node->readAt("offset", offset);
|
||||
size = borderImageNode->readAt("size", size);
|
||||
offset = borderImageNode->readAt("offset", offset);
|
||||
border = borderImageNode->readAt("border", 0);
|
||||
subRect = Rect(offset, size);
|
||||
border = node->readAt("border", 0);
|
||||
|
||||
// load border margins
|
||||
top = bottom = left = right = border;
|
||||
top = node->readAt("top", top);
|
||||
bottom = node->readAt("bottom", bottom);
|
||||
left = node->readAt("left", left);
|
||||
right = node->readAt("right", right);
|
||||
top = borderImageNode->readAt("border.top", top);
|
||||
bottom = borderImageNode->readAt("border.bottom", bottom);
|
||||
left = borderImageNode->readAt("border.left", left);
|
||||
right = borderImageNode->readAt("border.right", right);
|
||||
|
||||
// calculates border coords
|
||||
leftBorder = Rect(subRect.left(), subRect.top() + top, left, subRect.height() - top - bottom);
|
||||
rightBorder = Rect(subRect.right() - right + 1, subRect.top() + top, right, subRect.height() - top - bottom);
|
||||
topBorder = Rect(subRect.left() + left, subRect.top(), subRect.width() - right - left, top);
|
||||
@@ -104,17 +83,21 @@ BorderedImagePtr BorderedImage::loadFromOTMLNode(OTMLNode* node, TexturePtr defa
|
||||
bottomLeftCorner = Rect(subRect.left(), subRect.bottom() - bottom, left, bottom);
|
||||
bottomRightCorner = Rect(subRect.right() - right + 1, subRect.bottom() - bottom + 1, right, bottom);
|
||||
center = Rect(subRect.left() + left, subRect.top() + top, subRect.width() - right - left, subRect.height() - top - bottom);
|
||||
leftBorder = node->readAt("left border", leftBorder);
|
||||
rightBorder = node->readAt("right border", rightBorder);
|
||||
topBorder = node->readAt("top border", topBorder);
|
||||
bottomBorder = node->readAt("bottom border", bottomBorder);
|
||||
topLeftCorner = node->readAt("top left corner", topLeftCorner);
|
||||
topRightCorner = node->readAt("top right corner", topRightCorner);
|
||||
bottomLeftCorner = node->readAt("bottom left corner", bottomLeftCorner);
|
||||
bottomRightCorner = node->readAt("bottom right corner", bottomRightCorner);
|
||||
center = node->readAt("center", center);
|
||||
|
||||
return BorderedImagePtr(new BorderedImage(texture,
|
||||
// load individual border conf if supplied
|
||||
/*
|
||||
leftBorder = borderImageNode->readAt("left border", leftBorder);
|
||||
rightBorder = borderImageNode->readAt("right border", rightBorder);
|
||||
topBorder = borderImageNode->readAt("top border", topBorder);
|
||||
bottomBorder = borderImageNode->readAt("bottom border", bottomBorder);
|
||||
topLeftCorner = borderImageNode->readAt("top left corner", topLeftCorner);
|
||||
topRightCorner = borderImageNode->readAt("top right corner", topRightCorner);
|
||||
bottomLeftCorner = borderImageNode->readAt("bottom left corner", bottomLeftCorner);
|
||||
bottomRightCorner = borderImageNode->readAt("bottom right corner", bottomRightCorner);
|
||||
center = borderImageNode->readAt("center", center);
|
||||
*/
|
||||
|
||||
return BorderImagePtr(new BorderImage(texture,
|
||||
leftBorder,
|
||||
rightBorder,
|
||||
topBorder,
|
||||
@@ -126,8 +109,10 @@ BorderedImagePtr BorderedImage::loadFromOTMLNode(OTMLNode* node, TexturePtr defa
|
||||
center));
|
||||
}
|
||||
|
||||
void BorderedImage::draw(const Rect& screenCoords)
|
||||
void BorderImage::draw(const Rect& screenCoords)
|
||||
{
|
||||
//TODO: borderimage drawing could be optimized by caching the render into a texture
|
||||
|
||||
Rect rectCoords;
|
||||
Size centerSize = screenCoords.size() - m_bordersSize;
|
||||
|
||||
@@ -190,5 +175,4 @@ void BorderedImage::draw(const Rect& screenCoords)
|
||||
screenCoords.top() + m_topRightCornerTexCoords.height() + centerSize.height(),
|
||||
m_bottomRightCornerTexCoords.size());
|
||||
g_graphics.drawTexturedRect(rectCoords, m_texture, m_bottomRightCornerTexCoords);
|
||||
}
|
||||
|
||||
}
|
43
src/framework/graphics/borderimage.h
Normal file
43
src/framework/graphics/borderimage.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef BORDERIMAGE_H
|
||||
#define BORDERIMAGE_H
|
||||
|
||||
#include "image.h"
|
||||
|
||||
class BorderImage : public Image
|
||||
{
|
||||
public:
|
||||
BorderImage(TexturePtr texture,
|
||||
const Rect& left,
|
||||
const Rect& right,
|
||||
const Rect& top,
|
||||
const Rect& bottom,
|
||||
const Rect& topLeft,
|
||||
const Rect& topRight,
|
||||
const Rect& bottomLeft,
|
||||
const Rect& bottomRight,
|
||||
const Rect& center);
|
||||
|
||||
static BorderImagePtr loadFromOTML(const OTMLNodePtr& borderImageNode);
|
||||
|
||||
void draw(const Rect& screenCoords);
|
||||
|
||||
Size getDefaultSize() const { return m_defaultSize; }
|
||||
|
||||
private:
|
||||
Rect m_leftBorderTexCoords;
|
||||
Rect m_rightBorderTexCoords;
|
||||
Rect m_topBorderTexCoords;
|
||||
Rect m_bottomBorderTexCoords;
|
||||
|
||||
Rect m_topLeftCornerTexCoords;
|
||||
Rect m_topRightCornerTexCoords;
|
||||
Rect m_bottomLeftCornerTexCoords;
|
||||
Rect m_bottomRightCornerTexCoords;
|
||||
|
||||
Rect m_centerTexCoords;
|
||||
|
||||
Size m_bordersSize;
|
||||
Size m_defaultSize;
|
||||
};
|
||||
|
||||
#endif
|
@@ -1,104 +1,40 @@
|
||||
#include <global.h>
|
||||
#include <core/resources.h>
|
||||
#include <graphics/font.h>
|
||||
#include <graphics/textures.h>
|
||||
#include <graphics/graphics.h>
|
||||
#include "font.h"
|
||||
#include "texturemanager.h"
|
||||
#include "graphics.h"
|
||||
|
||||
#include <otml/otml.h>
|
||||
|
||||
void Font::calculateGlyphsWidthsAutomatically(const Size& glyphSize)
|
||||
void Font::load(const OTMLNodePtr& fontNode)
|
||||
{
|
||||
std::string textureName = fontNode->readAt<std::string>("texture");
|
||||
Size glyphSize = fontNode->readAt<Size>("glyph size");
|
||||
m_glyphHeight = fontNode->readAt<int>("height");
|
||||
m_topMargin = fontNode->readAt("top margin", 0);
|
||||
m_firstGlyph = fontNode->readAt("first glyph", 32);
|
||||
m_glyphSpacing = fontNode->readAt("spacing", Size(0,0));
|
||||
|
||||
// load font texture
|
||||
m_texture = g_textures.getTexture(textureName);
|
||||
if(!m_texture)
|
||||
throw OTMLException(fontNode, "failed to load texture for font");
|
||||
|
||||
// auto calculate widths
|
||||
calculateGlyphsWidthsAutomatically(glyphSize);
|
||||
|
||||
// read custom widths
|
||||
if(OTMLNodePtr node = fontNode->get("glyph widths")) {
|
||||
for(const OTMLNodePtr& child : node->childNodes())
|
||||
m_glyphsSize[aux::safe_cast<int>(child->tag())].setWidth(child->read<int>());
|
||||
}
|
||||
|
||||
// calculate glyphs texture coords
|
||||
int numHorizontalGlyphs = m_texture->getSize().width() / glyphSize.width();
|
||||
uchar *texturePixels = m_texture->getPixels();
|
||||
|
||||
// small AI to auto calculate pixels widths
|
||||
for(int glyph = m_firstGlyph; glyph< 256; ++glyph) {
|
||||
Rect glyphCoords(((glyph - m_firstGlyph) % numHorizontalGlyphs) * glyphSize.width(),
|
||||
((glyph - m_firstGlyph) / numHorizontalGlyphs) * glyphSize.height(),
|
||||
glyphSize.width(),
|
||||
m_glyphHeight);
|
||||
int width = glyphSize.width();
|
||||
int lastColumnFilledPixels = 0;
|
||||
for(int x = glyphCoords.left() + 1; x <= glyphCoords.right(); ++x) {
|
||||
int columnFilledPixels = 0;
|
||||
|
||||
// check if all vertical pixels are alpha
|
||||
for(int y = glyphCoords.top(); y <= glyphCoords.bottom(); ++y) {
|
||||
if(texturePixels[(y * m_texture->getSize().width() * 4) + (x*4) + 3] != 0)
|
||||
columnFilledPixels++;
|
||||
}
|
||||
|
||||
// if all pixels were alpha we found the width
|
||||
if(columnFilledPixels == 0) {
|
||||
width = x - glyphCoords.left();
|
||||
width += m_glyphSpacing.width();
|
||||
if(m_glyphHeight >= 16 && lastColumnFilledPixels >= m_glyphHeight/3)
|
||||
width += 1;
|
||||
break;
|
||||
}
|
||||
lastColumnFilledPixels = columnFilledPixels;
|
||||
}
|
||||
// store glyph size
|
||||
m_glyphsSize[glyph].setSize(width, m_glyphHeight);
|
||||
for(int glyph = m_firstGlyph; glyph < 256; ++glyph) {
|
||||
m_glyphsTextureCoords[glyph].setRect(((glyph - m_firstGlyph) % numHorizontalGlyphs) * glyphSize.width(),
|
||||
((glyph - m_firstGlyph) / numHorizontalGlyphs) * glyphSize.height(),
|
||||
m_glyphsSize[glyph].width(),
|
||||
m_glyphHeight);
|
||||
}
|
||||
|
||||
delete[] texturePixels;
|
||||
}
|
||||
|
||||
bool Font::load(const std::string& file)
|
||||
{
|
||||
std::stringstream fin;
|
||||
if(!g_resources.loadFile(file, fin)) {
|
||||
logError("ERROR: Coult not load font file '",file,"'");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string textureName;
|
||||
Size glyphSize;
|
||||
|
||||
try {
|
||||
OTMLParser parser(fin, file);
|
||||
OTMLNode* doc = parser.getDocument();
|
||||
|
||||
// required values
|
||||
textureName = doc->valueAt("image");
|
||||
glyphSize = doc->readAt("image-glyph-size", Size(16, 16));
|
||||
m_glyphHeight = doc->readAt("glyph-height", 11);
|
||||
m_firstGlyph = doc->readAt("first-glyph", 32);
|
||||
m_topMargin = doc->readAt("top-margin", 0);
|
||||
m_glyphSpacing = doc->readAt("glyph-spacing", Size(0,0));
|
||||
|
||||
// load texture
|
||||
m_texture = g_textures.get(textureName);
|
||||
if(!m_texture) {
|
||||
logError("ERROR: Failed to load image for font file '",file,"'");
|
||||
return false;
|
||||
}
|
||||
|
||||
// auto calculate widths
|
||||
calculateGlyphsWidthsAutomatically(glyphSize);
|
||||
|
||||
// read custom widths
|
||||
if(doc->hasChild("glyph-widths")) {
|
||||
std::map<int, int> glyphWidths;
|
||||
doc->readAt("glyph-widths", &glyphWidths);
|
||||
foreach(const auto& pair, glyphWidths)
|
||||
m_glyphsSize[pair.first].setWidth(pair.second);
|
||||
}
|
||||
|
||||
// calculate glyphs texture coords
|
||||
int numHorizontalGlyphs = m_texture->getSize().width() / glyphSize.width();
|
||||
for(int glyph = m_firstGlyph; glyph < 256; ++glyph) {
|
||||
m_glyphsTextureCoords[glyph].setRect(((glyph - m_firstGlyph) % numHorizontalGlyphs) * glyphSize.width(),
|
||||
((glyph - m_firstGlyph) / numHorizontalGlyphs) * glyphSize.height(),
|
||||
m_glyphsSize[glyph].width(),
|
||||
m_glyphHeight);
|
||||
}
|
||||
} catch(OTMLException e) {
|
||||
logError("ERROR: Malformed font file \"", file.c_str(), "\":\n ", e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Font::renderText(const std::string& text,
|
||||
@@ -112,9 +48,9 @@ void Font::renderText(const std::string& text,
|
||||
|
||||
|
||||
void Font::renderText(const std::string& text,
|
||||
const Rect& screenCoords,
|
||||
AlignmentFlag align,
|
||||
const Color& color)
|
||||
const Rect& screenCoords,
|
||||
AlignmentFlag align,
|
||||
const Color& color)
|
||||
{
|
||||
// prevent glitches from invalid rects
|
||||
if(!screenCoords.isValid())
|
||||
@@ -190,7 +126,9 @@ void Font::renderText(const std::string& text,
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<Point>& Font::calculateGlyphsPositions(const std::string& text, AlignmentFlag align, Size *textBoxSize) const
|
||||
const std::vector<Point>& Font::calculateGlyphsPositions(const std::string& text,
|
||||
AlignmentFlag align,
|
||||
Size *textBoxSize) const
|
||||
{
|
||||
// for performance reasons we use statics vectors that are allocated on demand
|
||||
static std::vector<Point> glyphsPositions(1);
|
||||
@@ -277,3 +215,41 @@ Size Font::calculateTextRectSize(const std::string& text)
|
||||
return size;
|
||||
}
|
||||
|
||||
void Font::calculateGlyphsWidthsAutomatically(const Size& glyphSize)
|
||||
{
|
||||
int numHorizontalGlyphs = m_texture->getSize().width() / glyphSize.width();
|
||||
uchar *texturePixels = m_texture->getPixels();
|
||||
|
||||
// small AI to auto calculate pixels widths
|
||||
for(int glyph = m_firstGlyph; glyph< 256; ++glyph) {
|
||||
Rect glyphCoords(((glyph - m_firstGlyph) % numHorizontalGlyphs) * glyphSize.width(),
|
||||
((glyph - m_firstGlyph) / numHorizontalGlyphs) * glyphSize.height(),
|
||||
glyphSize.width(),
|
||||
m_glyphHeight);
|
||||
int width = glyphSize.width();
|
||||
int lastColumnFilledPixels = 0;
|
||||
for(int x = glyphCoords.left() + 1; x <= glyphCoords.right(); ++x) {
|
||||
int columnFilledPixels = 0;
|
||||
|
||||
// check if all vertical pixels are alpha
|
||||
for(int y = glyphCoords.top(); y <= glyphCoords.bottom(); ++y) {
|
||||
if(texturePixels[(y * m_texture->getSize().width() * 4) + (x*4) + 3] != 0)
|
||||
columnFilledPixels++;
|
||||
}
|
||||
|
||||
// if all pixels were alpha we found the width
|
||||
if(columnFilledPixels == 0) {
|
||||
width = x - glyphCoords.left();
|
||||
width += m_glyphSpacing.width();
|
||||
if(m_glyphHeight >= 16 && lastColumnFilledPixels >= m_glyphHeight/3)
|
||||
width += 1;
|
||||
break;
|
||||
}
|
||||
lastColumnFilledPixels = columnFilledPixels;
|
||||
}
|
||||
// store glyph size
|
||||
m_glyphsSize[glyph].setSize(width, m_glyphHeight);
|
||||
}
|
||||
|
||||
delete[] texturePixels;
|
||||
}
|
||||
|
@@ -1,68 +1,46 @@
|
||||
/* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 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 FONT_H
|
||||
#define FONT_H
|
||||
|
||||
#include <global.h>
|
||||
#include <graphics/graphics.h>
|
||||
#include "graphicsdeclarations.h"
|
||||
#include <otml/otmldeclarations.h>
|
||||
|
||||
class Font
|
||||
{
|
||||
public:
|
||||
Font(const std::string& name) :
|
||||
m_name(name) { }
|
||||
Font(const std::string& name) : m_name(name) { }
|
||||
|
||||
/// Load font from file
|
||||
bool load(const std::string &file);
|
||||
/// Load font from otml node
|
||||
void load(const OTMLNodePtr& fontNode);
|
||||
|
||||
/// Simple text render starting at startPos
|
||||
void renderText(const std::string& text,
|
||||
const Point& startPos,
|
||||
const Color& color = Color::white);
|
||||
|
||||
/// Advanced text render
|
||||
/// Advanced text render delimited by a screen region and alignment
|
||||
void renderText(const std::string& text,
|
||||
const Rect& screenCoords,
|
||||
AlignmentFlag align = AlignTopLeft,
|
||||
const Color& color = Color::white);
|
||||
|
||||
/// Calculate glyphs positions to use on render, also calculates textBoxSize if wanted
|
||||
const std::vector<Point>& calculateGlyphsPositions(const std::string& text, AlignmentFlag align = AlignTopLeft, Size *textBoxSize = NULL) const;
|
||||
const std::vector<Point>& calculateGlyphsPositions(const std::string& text,
|
||||
AlignmentFlag align = AlignTopLeft,
|
||||
Size* textBoxSize = NULL) const;
|
||||
|
||||
/// Simulate render and calculate text size
|
||||
Size calculateTextRectSize(const std::string& text);
|
||||
|
||||
std::string getName() const { return m_name; }
|
||||
int getGlyphHeight() const { return m_glyphHeight; }
|
||||
const Rect *getGlyphsTextureCoords() const { return m_glyphsTextureCoords; }
|
||||
const Size *getGlyphsSize() const { return m_glyphsSize; }
|
||||
const Rect* getGlyphsTextureCoords() const { return m_glyphsTextureCoords; }
|
||||
const Size* getGlyphsSize() const { return m_glyphsSize; }
|
||||
const TexturePtr& getTexture() const { return m_texture; }
|
||||
int getTopMargin() const { return m_topMargin; }
|
||||
Size getGlyphSpacing() const { return m_glyphSpacing; }
|
||||
|
||||
private:
|
||||
/// Calculates each font character by inspecting font bitmap
|
||||
void calculateGlyphsWidthsAutomatically(const Size& glyphSize);
|
||||
|
||||
std::string m_name;
|
||||
@@ -75,6 +53,6 @@ private:
|
||||
Size m_glyphsSize[256];
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<Font> FontPtr;
|
||||
|
||||
#endif // FONT_H
|
||||
#endif
|
||||
|
||||
|
69
src/framework/graphics/fontmanager.cpp
Normal file
69
src/framework/graphics/fontmanager.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
#include "fontmanager.h"
|
||||
|
||||
#include <core/resourcemanager.h>
|
||||
#include <otml/otml.h>
|
||||
|
||||
FontManager g_fonts;
|
||||
|
||||
void FontManager::releaseFonts()
|
||||
{
|
||||
m_defaultFont.reset();
|
||||
m_fonts.clear();
|
||||
}
|
||||
|
||||
bool FontManager::importFont(std::string fontFile)
|
||||
{
|
||||
try {
|
||||
if(!boost::ends_with(fontFile, ".otfont"))
|
||||
fontFile += ".otfont";
|
||||
|
||||
OTMLDocumentPtr doc = OTMLDocument::parse(fontFile);
|
||||
OTMLNodePtr fontNode = doc->at("Font");
|
||||
|
||||
std::string name = fontNode->readAt<std::string>("name");
|
||||
if(fontExists(name))
|
||||
throw OTMLException(fontNode, "a font with the same name is already imported, did you duplicate font names?");
|
||||
|
||||
FontPtr font(new Font(name));
|
||||
font->load(fontNode);
|
||||
m_fonts.push_back(font);
|
||||
|
||||
// set as default if needed
|
||||
if(!m_defaultFont)
|
||||
m_defaultFont = font;
|
||||
|
||||
return true;
|
||||
} catch(std::exception& e) {
|
||||
logError("ERROR: could not load font '", fontFile, "': ", e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool FontManager::fontExists(const std::string& fontName)
|
||||
{
|
||||
for(const FontPtr& font : m_fonts) {
|
||||
if(font->getName() == fontName)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FontPtr FontManager::getFont(const std::string& fontName)
|
||||
{
|
||||
// find font by name
|
||||
for(const FontPtr& font : m_fonts) {
|
||||
if(font->getName() == fontName)
|
||||
return font;
|
||||
}
|
||||
|
||||
// when not found, fallback to default font
|
||||
return getDefaultFont();
|
||||
}
|
||||
|
||||
FontPtr FontManager::getDefaultFont()
|
||||
{
|
||||
// default font should always exists, otherwise the app may crash
|
||||
if(!m_defaultFont)
|
||||
throw std::runtime_error("no default font to display, cannot continue to run");
|
||||
return m_defaultFont;
|
||||
}
|
27
src/framework/graphics/fontmanager.h
Normal file
27
src/framework/graphics/fontmanager.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef FONTMANAGER_H
|
||||
#define FONTMANAGER_H
|
||||
|
||||
#include "font.h"
|
||||
|
||||
class FontManager
|
||||
{
|
||||
public:
|
||||
// Release fonts references, thus making possible to destruct them
|
||||
void releaseFonts();
|
||||
|
||||
bool importFont(std::string fontFile);
|
||||
|
||||
bool fontExists(const std::string& fontName);
|
||||
FontPtr getFont(const std::string& fontName);
|
||||
FontPtr getDefaultFont();
|
||||
|
||||
void setDefaultFont(const std::string& fontName) { m_defaultFont = getFont(fontName); }
|
||||
|
||||
private:
|
||||
std::vector<FontPtr> m_fonts;
|
||||
FontPtr m_defaultFont;
|
||||
};
|
||||
|
||||
extern FontManager g_fonts;
|
||||
|
||||
#endif
|
@@ -1,38 +0,0 @@
|
||||
#include <global.h>
|
||||
#include <core/resources.h>
|
||||
#include <graphics/fonts.h>
|
||||
|
||||
|
||||
Fonts g_fonts;
|
||||
|
||||
void Fonts::init()
|
||||
{
|
||||
g_resources.pushCurrentPath("fonts");
|
||||
|
||||
// load all fonts
|
||||
std::list<std::string> files = g_resources.listDirectoryFiles();
|
||||
foreach(const std::string& file, files) {
|
||||
if(boost::ends_with(file, ".otml")) {
|
||||
std::string name = file;
|
||||
boost::erase_first(name, ".otml");
|
||||
FontPtr font(new Font(name));
|
||||
if(font->load(file))
|
||||
m_fonts.push_back(font);
|
||||
}
|
||||
}
|
||||
|
||||
g_resources.popCurrentPath();
|
||||
}
|
||||
|
||||
FontPtr Fonts::get(const std::string& fontName)
|
||||
{
|
||||
// find font by name
|
||||
foreach(const FontPtr& font, m_fonts) {
|
||||
if(font->getName() == fontName)
|
||||
return font;
|
||||
}
|
||||
|
||||
logFatal("ERROR: Font '",fontName,"' not found");
|
||||
return FontPtr();
|
||||
}
|
||||
|
@@ -1,51 +0,0 @@
|
||||
/* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 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 FONTS_H
|
||||
#define FONTS_H
|
||||
|
||||
#include <global.h>
|
||||
#include <graphics/font.h>
|
||||
|
||||
class Fonts
|
||||
{
|
||||
public:
|
||||
Fonts() { }
|
||||
|
||||
/// Initialize all fonts
|
||||
void init();
|
||||
|
||||
/// Terminate all fonts
|
||||
void terminate() { }
|
||||
|
||||
/// Get a font by name
|
||||
FontPtr get(const std::string& fontName);
|
||||
|
||||
private:
|
||||
std::vector<FontPtr> m_fonts;
|
||||
};
|
||||
|
||||
extern Fonts g_fonts;
|
||||
|
||||
#endif // FONTS_H
|
@@ -1,30 +1,9 @@
|
||||
/* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 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 <global.h>
|
||||
#include "framebuffer.h"
|
||||
#include "graphics.h"
|
||||
#include <core/platform.h>
|
||||
#include <graphics/framebuffer.h>
|
||||
#include <graphics/graphics.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#include <GL/glext.h>
|
||||
|
||||
PFNGLGENFRAMEBUFFERSPROC oglGenFramebuffers = 0;
|
||||
PFNGLBINDFRAMEBUFFERPROC oglBindFramebuffer = 0;
|
||||
@@ -55,11 +34,11 @@ FrameBuffer::FrameBuffer(int width, int height)
|
||||
if(g_graphics.isExtensionSupported("GL_ARB_framebuffer_object")) {
|
||||
m_fallbackOldImp = false;
|
||||
if(!oglGenFramebuffers) {
|
||||
oglGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)Platform::getExtensionProcAddress("glGenFramebuffers");
|
||||
oglBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)Platform::getExtensionProcAddress("glBindFramebuffer");
|
||||
oglFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)Platform::getExtensionProcAddress("glFramebufferTexture2D");
|
||||
oglDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)Platform::getExtensionProcAddress("glDeleteFramebuffers");
|
||||
oglCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)Platform::getExtensionProcAddress("glCheckFramebufferStatus");
|
||||
oglGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)g_platform.getExtensionProcAddress("glGenFramebuffers");
|
||||
oglBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)g_platform.getExtensionProcAddress("glBindFramebuffer");
|
||||
oglFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)g_platform.getExtensionProcAddress("glFramebufferTexture2D");
|
||||
oglDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)g_platform.getExtensionProcAddress("glDeleteFramebuffers");
|
||||
oglCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)g_platform.getExtensionProcAddress("glCheckFramebufferStatus");
|
||||
}
|
||||
|
||||
// generate FBO
|
||||
|
@@ -1,34 +1,7 @@
|
||||
/* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 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 FRAMEBUFFER_H
|
||||
#define FRAMEBUFFER_H
|
||||
|
||||
#include <global.h>
|
||||
|
||||
class FrameBuffer;
|
||||
typedef std::shared_ptr<FrameBuffer> FrameBufferPtr;
|
||||
#include "graphicsdeclarations.h"
|
||||
|
||||
class FrameBuffer
|
||||
{
|
||||
@@ -53,4 +26,4 @@ private:
|
||||
int m_height;
|
||||
};
|
||||
|
||||
#endif // FRAMEBUFFER_H
|
||||
#endif
|
||||
|
@@ -1,38 +1,22 @@
|
||||
/* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 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 <global.h>
|
||||
#include <graphics/graphics.h>
|
||||
#include <graphics/texture.h>
|
||||
#include "fontmanager.h"
|
||||
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#include <GL/glext.h>
|
||||
|
||||
Graphics g_graphics;
|
||||
|
||||
void Graphics::init()
|
||||
{
|
||||
m_drawMode = DRAW_NONE;
|
||||
|
||||
// setup opengl
|
||||
glEnable(GL_ALPHA_TEST); // enable alpha by default
|
||||
glAlphaFunc(GL_GREATER, 0.0f); // default alpha mode
|
||||
glDisable(GL_DEPTH_TEST); // we are rendering 2D only, we don't need it
|
||||
glAlphaFunc(GL_GREATER, 0.0f); // default alpha func
|
||||
glDisable(GL_DEPTH_TEST); // we are rendering 2D only, we don't need depth buffer
|
||||
//glEnable(GL_TEXTURE_2D); // enable textures by default
|
||||
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
|
||||
glShadeModel(GL_SMOOTH);
|
||||
glEnable(GL_BLEND);
|
||||
@@ -45,7 +29,7 @@ void Graphics::init()
|
||||
|
||||
void Graphics::terminate()
|
||||
{
|
||||
m_bindedTexture.reset();
|
||||
g_fonts.releaseFonts();
|
||||
}
|
||||
|
||||
bool Graphics::isExtensionSupported(const char *extension)
|
||||
@@ -114,11 +98,18 @@ void Graphics::beginRender()
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glLoadIdentity();
|
||||
|
||||
// bind white color by default
|
||||
glColor4ubv(Color::white.rgbaPtr());
|
||||
m_boundColor = Color::white;
|
||||
}
|
||||
|
||||
void Graphics::endRender()
|
||||
{
|
||||
disableDrawing();
|
||||
|
||||
// clear any bound texture
|
||||
m_boundTexture.reset();
|
||||
}
|
||||
|
||||
void Graphics::disableDrawing()
|
||||
@@ -127,12 +118,15 @@ void Graphics::disableDrawing()
|
||||
glEnd();
|
||||
m_drawMode = DRAW_NONE;
|
||||
|
||||
m_bindedTexture.reset();
|
||||
m_boundTexture.reset();
|
||||
glColor4ubv(Color::white.rgbaPtr());
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::drawTexturedRect(const Rect& screenCoords, const TexturePtr& texture, const Rect& textureCoords, const Color& color)
|
||||
void Graphics::drawTexturedRect(const Rect& screenCoords,
|
||||
const TexturePtr& texture,
|
||||
const Rect& textureCoords,
|
||||
const Color& color)
|
||||
{
|
||||
if(screenCoords.isEmpty() || textureCoords.isEmpty())
|
||||
return;
|
||||
@@ -163,7 +157,10 @@ void Graphics::drawTexturedRect(const Rect& screenCoords, const TexturePtr& text
|
||||
glTexCoord2f(textureRight, textureTop); glVertex2i(right, top);
|
||||
}
|
||||
|
||||
void Graphics::drawRepeatedTexturedRect(const Rect& screenCoords, const TexturePtr& texture, const Rect& textureCoords, const Color& color)
|
||||
void Graphics::drawRepeatedTexturedRect(const Rect& screenCoords,
|
||||
const TexturePtr& texture,
|
||||
const Rect& textureCoords,
|
||||
const Color& color)
|
||||
{
|
||||
if(screenCoords.isEmpty() || textureCoords.isEmpty())
|
||||
return;
|
||||
@@ -177,11 +174,13 @@ void Graphics::drawRepeatedTexturedRect(const Rect& screenCoords, const TextureP
|
||||
|
||||
// partialCoords to screenCoords bottomRight
|
||||
if(partialCoords.bottom() > virtualScreenCoords.bottom()) {
|
||||
partialTextureCoords.setBottom(partialTextureCoords.bottom() + (virtualScreenCoords.bottom() - partialCoords.bottom()));
|
||||
partialTextureCoords.setBottom(partialTextureCoords.bottom() +
|
||||
(virtualScreenCoords.bottom() - partialCoords.bottom()));
|
||||
partialCoords.setBottom(virtualScreenCoords.bottom());
|
||||
}
|
||||
if(partialCoords.right() > virtualScreenCoords.right()) {
|
||||
partialTextureCoords.setRight(partialTextureCoords.right() + (virtualScreenCoords.right() - partialCoords.right()));
|
||||
partialTextureCoords.setRight(partialTextureCoords.right() +
|
||||
(virtualScreenCoords.right() - partialCoords.right()));
|
||||
partialCoords.setRight(virtualScreenCoords.right());
|
||||
}
|
||||
|
||||
@@ -191,7 +190,8 @@ void Graphics::drawRepeatedTexturedRect(const Rect& screenCoords, const TextureP
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::drawFilledRect(const Rect& screenCoords, const Color& color)
|
||||
void Graphics::drawFilledRect(const Rect& screenCoords,
|
||||
const Color& color)
|
||||
{
|
||||
if(screenCoords.isEmpty())
|
||||
return;
|
||||
@@ -210,7 +210,9 @@ void Graphics::drawFilledRect(const Rect& screenCoords, const Color& color)
|
||||
}
|
||||
|
||||
|
||||
void Graphics::drawBoundingRect(const Rect& screenCoords, const Color& color, int innerLineWidth)
|
||||
void Graphics::drawBoundingRect(const Rect& screenCoords,
|
||||
const Color& color,
|
||||
int innerLineWidth)
|
||||
{
|
||||
if(2 * innerLineWidth > screenCoords.height() || screenCoords.isEmpty())
|
||||
return;
|
||||
@@ -251,13 +253,13 @@ void Graphics::drawBoundingRect(const Rect& screenCoords, const Color& color, in
|
||||
void Graphics::bindColor(const Color& color)
|
||||
{
|
||||
// switch drawing to colored quads
|
||||
if(m_drawMode != DRAW_COLOR_QUADS || m_bindedColor != color) {
|
||||
if(m_drawMode != DRAW_COLOR_QUADS || m_boundColor != color) {
|
||||
if(m_drawMode != DRAW_NONE)
|
||||
glEnd();
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
if(m_bindedColor != color) {
|
||||
if(m_boundColor != color) {
|
||||
glColor4ubv(color.rgbaPtr());
|
||||
m_bindedColor = color;
|
||||
m_boundColor = color;
|
||||
}
|
||||
glBegin(GL_QUADS);
|
||||
m_drawMode = DRAW_COLOR_QUADS;
|
||||
@@ -267,17 +269,17 @@ void Graphics::bindColor(const Color& color)
|
||||
void Graphics::bindTexture(const TexturePtr& texture, const Color& color)
|
||||
{
|
||||
// switch drawing to textured quads
|
||||
if(m_drawMode != DRAW_TEXTURE_QUADS || m_bindedTexture != texture || m_bindedColor != color) {
|
||||
if(m_drawMode != DRAW_TEXTURE_QUADS || m_boundTexture != texture || m_boundColor != color) {
|
||||
if(m_drawMode != DRAW_NONE)
|
||||
glEnd();
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
if(m_bindedTexture != texture) {
|
||||
if(m_boundTexture != texture) {
|
||||
glBindTexture(GL_TEXTURE_2D, texture->getTextureId());
|
||||
m_bindedTexture = texture;
|
||||
m_boundTexture = texture;
|
||||
}
|
||||
if(m_bindedColor != color) {
|
||||
if(m_boundColor != color) {
|
||||
glColor4ubv(color.rgbaPtr());
|
||||
m_bindedColor = color;
|
||||
m_boundColor = color;
|
||||
}
|
||||
glBegin(GL_QUADS);
|
||||
m_drawMode = DRAW_TEXTURE_QUADS;
|
||||
|
@@ -1,36 +1,7 @@
|
||||
/* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 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 GRAPHICS_H
|
||||
#define GRAPHICS_H
|
||||
|
||||
#include <global.h>
|
||||
#include <graphics/textures.h>
|
||||
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#include <GL/glext.h>
|
||||
#include "graphicsdeclarations.h"
|
||||
|
||||
class Graphics
|
||||
{
|
||||
@@ -44,9 +15,7 @@ class Graphics
|
||||
};
|
||||
|
||||
public:
|
||||
Graphics() : m_drawMode(DRAW_NONE) { }
|
||||
|
||||
/// Initialize graphics
|
||||
/// Initialize default OpenGL states
|
||||
void init();
|
||||
|
||||
/// Termiante graphics
|
||||
@@ -55,7 +24,7 @@ public:
|
||||
/// Check if a GL extension is supported
|
||||
bool isExtensionSupported(const char *extension);
|
||||
|
||||
/// Called after every window resize
|
||||
/// Resizes OpenGL viewport
|
||||
void resize(const Size& size);
|
||||
|
||||
/// Restore original viewport
|
||||
@@ -66,27 +35,38 @@ public:
|
||||
|
||||
/// Called after every render
|
||||
void endRender();
|
||||
void disableDrawing();
|
||||
|
||||
// drawing API
|
||||
void drawTexturedRect(const Rect& screenCoords,
|
||||
const TexturePtr& texture,
|
||||
const Rect& textureCoords = Rect(),
|
||||
const Color& color = Color::white);
|
||||
|
||||
void drawRepeatedTexturedRect(const Rect& screenCoords,
|
||||
const TexturePtr& texture,
|
||||
const Rect& textureCoords,
|
||||
const Color& color = Color::white);
|
||||
|
||||
void drawFilledRect(const Rect& screenCoords,
|
||||
const Color& color);
|
||||
|
||||
void drawBoundingRect(const Rect& screenCoords,
|
||||
const Color& color = Color::green,
|
||||
int innerLineWidth = 1);
|
||||
|
||||
const Size& getScreenSize() const { return m_screenSize; }
|
||||
|
||||
void disableDrawing();
|
||||
void enableDrawing();
|
||||
|
||||
void drawTexturedRect(const Rect& screenCoords, const TexturePtr& texture, const Rect& textureCoords = Rect(), const Color& color = Color::white);
|
||||
void drawRepeatedTexturedRect(const Rect& screenCoords, const TexturePtr& texture, const Rect& textureCoords, const Color& color = Color::white);
|
||||
void drawFilledRect(const Rect& screenCoords, const Color& color);
|
||||
void drawBoundingRect(const Rect& screenCoords, const Color& color = Color::green, int innerLineWidth = 1);
|
||||
|
||||
private:
|
||||
void bindTexture(const TexturePtr& texture, const Color& color = Color::white);
|
||||
void bindColor(const Color& color);
|
||||
|
||||
TexturePtr m_bindedTexture;
|
||||
Color m_bindedColor;
|
||||
TexturePtr m_boundTexture;
|
||||
Color m_boundColor;
|
||||
Size m_screenSize;
|
||||
DrawMode m_drawMode;
|
||||
};
|
||||
|
||||
extern Graphics g_graphics;
|
||||
|
||||
#endif // GRAPHICS_H
|
||||
#endif
|
||||
|
22
src/framework/graphics/graphicsdeclarations.h
Normal file
22
src/framework/graphics/graphicsdeclarations.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef GRAPHICSDECLARATIONS_H
|
||||
#define GRAPHICSDECLARATIONS_H
|
||||
|
||||
#include <global.h>
|
||||
|
||||
class Texture;
|
||||
class Font;
|
||||
class Image;
|
||||
class BorderImage;
|
||||
class TextArea;
|
||||
class FrameBuffer;
|
||||
|
||||
typedef std::weak_ptr<Texture> TextureWeakPtr;
|
||||
|
||||
typedef std::shared_ptr<Texture> TexturePtr;
|
||||
typedef std::shared_ptr<Font> FontPtr;
|
||||
typedef std::shared_ptr<Image> ImagePtr;
|
||||
typedef std::shared_ptr<BorderImage> BorderImagePtr;
|
||||
typedef std::shared_ptr<TextArea> TextAreaPtr;
|
||||
typedef std::shared_ptr<FrameBuffer> FrameBufferPtr;
|
||||
|
||||
#endif
|
@@ -1,48 +1,37 @@
|
||||
/* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 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 "image.h"
|
||||
#include "texture.h"
|
||||
#include "graphics.h"
|
||||
#include "texturemanager.h"
|
||||
|
||||
#include <otml/otml.h>
|
||||
|
||||
#include <global.h>
|
||||
#include <graphics/image.h>
|
||||
#include <graphics/graphics.h>
|
||||
#include <graphics/textures.h>
|
||||
|
||||
Image::Image(TexturePtr texture)
|
||||
: m_texture(texture)
|
||||
Image::Image(TexturePtr texture, Rect textureCoords)
|
||||
{
|
||||
m_textureCoords = Rect(0, 0, m_texture->getSize());
|
||||
m_texture = texture;
|
||||
if(!textureCoords.isValid())
|
||||
m_textureCoords = Rect(0, 0, m_texture->getSize());
|
||||
else
|
||||
m_textureCoords = textureCoords;
|
||||
}
|
||||
|
||||
Image::Image(const std::string& texture)
|
||||
ImagePtr Image::loadFromOTML(const OTMLNodePtr& imageNode)
|
||||
{
|
||||
m_texture = g_textures.get(texture);
|
||||
m_textureCoords = Rect(0, 0, m_texture->getSize());
|
||||
}
|
||||
// load configs from otml node
|
||||
std::string source = imageNode->hasValue() ? imageNode->read<std::string>() : imageNode->readAt<std::string>("source");
|
||||
bool smooth = imageNode->readAt("smooth", false);
|
||||
Rect textureCoords = imageNode->readAt("coords", Rect());
|
||||
|
||||
Image::Image(const std::string& texture, Rect textureCoords) :
|
||||
m_textureCoords(textureCoords)
|
||||
{
|
||||
m_texture = g_textures.get(texture);
|
||||
// load texture
|
||||
TexturePtr texture = g_textures.getTexture(source);
|
||||
if(!texture)
|
||||
throw OTMLException(imageNode, "could not load image texture");
|
||||
|
||||
// enable texture bilinear filter
|
||||
if(smooth)
|
||||
texture->enableBilinearFilter();
|
||||
|
||||
// create image
|
||||
return ImagePtr(new Image(texture, textureCoords));
|
||||
}
|
||||
|
||||
void Image::draw(const Rect& screenCoords)
|
||||
@@ -50,5 +39,3 @@ void Image::draw(const Rect& screenCoords)
|
||||
if(m_texture)
|
||||
g_graphics.drawTexturedRect(screenCoords, m_texture, m_textureCoords);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,42 +1,16 @@
|
||||
/* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 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 IMAGE_H
|
||||
#define IMAGE_H
|
||||
|
||||
#include <global.h>
|
||||
#include <graphics/texture.h>
|
||||
#include "graphicsdeclarations.h"
|
||||
#include <otml/otmldeclarations.h>
|
||||
|
||||
class Image
|
||||
{
|
||||
public:
|
||||
Image(TexturePtr texture);
|
||||
Image(TexturePtr texture, Rect textureCoords) : m_texture(texture), m_textureCoords(textureCoords) { }
|
||||
Image(const std::string& texture);
|
||||
Image(const std::string& texture, Rect textureCoords);
|
||||
Image(TexturePtr texture, Rect textureCoords = Rect());
|
||||
|
||||
static ImagePtr loadFromOTML(const OTMLNodePtr& imageNode);
|
||||
|
||||
/// Draw image on screen
|
||||
virtual void draw(const Rect& screenCoords);
|
||||
|
||||
protected:
|
||||
@@ -44,6 +18,4 @@ protected:
|
||||
Rect m_textureCoords;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<Image> ImagePtr;
|
||||
|
||||
#endif // IMAGE_H
|
||||
#endif
|
||||
|
@@ -1,31 +1,8 @@
|
||||
/* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 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 "textarea.h"
|
||||
#include "font.h"
|
||||
#include "graphics.h"
|
||||
|
||||
|
||||
#include <global.h>
|
||||
#include <core/engine.h>
|
||||
#include <graphics/textarea.h>
|
||||
#include <graphics/graphics.h>
|
||||
#include <core/platform.h>
|
||||
|
||||
TextArea::TextArea() :
|
||||
m_align(AlignLeftCenter),
|
||||
@@ -55,6 +32,8 @@ TextArea::TextArea(FontPtr font,
|
||||
|
||||
void TextArea::draw()
|
||||
{
|
||||
//TODO: text rendering could be much optimized by using vertex buffer or caching the render into a texture
|
||||
|
||||
int textLength = m_text.length();
|
||||
const TexturePtr& texture = m_font->getTexture();
|
||||
for(int i=0;i<textLength;++i) {
|
||||
@@ -65,7 +44,7 @@ void TextArea::draw()
|
||||
if(m_cursorVisible && m_cursorPos >= 0) {
|
||||
assert(m_cursorPos <= textLength);
|
||||
const int delay = 500;
|
||||
int ticks = g_engine.getCurrentFrameTicks();
|
||||
int ticks = g_platform.getTicks();
|
||||
// draw every 500ms
|
||||
if(ticks - m_cursorTicks <= delay) {
|
||||
Rect cursorRect;
|
||||
@@ -76,7 +55,7 @@ void TextArea::draw()
|
||||
cursorRect = Rect(m_glyphsCoords[m_cursorPos-1].right(), m_glyphsCoords[m_cursorPos-1].top(), 1, m_font->getGlyphHeight());
|
||||
g_graphics.drawFilledRect(cursorRect, m_color);
|
||||
} else if(ticks - m_cursorTicks >= 2*delay) {
|
||||
m_cursorTicks = g_engine.getCurrentFrameTicks();
|
||||
m_cursorTicks = ticks;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,12 +92,12 @@ void TextArea::recalculate()
|
||||
} else if(m_cursorPos > m_startRenderPos || // cursor is after the previuos first rendered glyph
|
||||
(m_cursorPos == m_startRenderPos && textLength == m_cursorPos)) // cursor is at the previuos rendered element, and is the last text element
|
||||
{
|
||||
Rect virtualRect(m_startInternalPos, m_screenCoords.size()); // previus rendered virtual rect
|
||||
Rect virtualRect(m_startInternalPos, m_screenCoords.size()); // previous rendered virtual rect
|
||||
int pos = m_cursorPos - 1; // element before cursor
|
||||
glyph = (uchar)m_text[pos]; // glyph of the element before cursor
|
||||
Rect glyphRect(glyphsPositions[pos], glyphsSize[glyph]);
|
||||
|
||||
// if the cursor is not on the previus rendered virtual rect we need to update it
|
||||
// if the cursor is not on the previous rendered virtual rect we need to update it
|
||||
if(!virtualRect.contains(glyphRect.topLeft()) || !virtualRect.contains(glyphRect.bottomRight())) {
|
||||
// calculate where is the first glyph visible
|
||||
Point startGlyphPos;
|
||||
@@ -246,7 +225,7 @@ void TextArea::setText(const std::string& text)
|
||||
m_text = text;
|
||||
if(m_cursorPos >= 0) {
|
||||
m_cursorPos = 0;
|
||||
m_cursorTicks = g_engine.getCurrentFrameTicks();
|
||||
m_cursorTicks = g_platform.getTicks();
|
||||
}
|
||||
recalculate();
|
||||
}
|
||||
@@ -285,7 +264,7 @@ void TextArea::enableCursor(bool enable)
|
||||
{
|
||||
if(enable) {
|
||||
m_cursorPos = 0;
|
||||
m_cursorTicks = g_engine.getCurrentFrameTicks();
|
||||
m_cursorTicks = g_platform.getTicks();
|
||||
} else
|
||||
m_cursorPos = -1;
|
||||
recalculate();
|
||||
@@ -298,7 +277,7 @@ void TextArea::appendCharacter(char c)
|
||||
tmp = c;
|
||||
m_text.insert(m_cursorPos, tmp);
|
||||
m_cursorPos++;
|
||||
m_cursorTicks = g_engine.getCurrentFrameTicks();
|
||||
m_cursorTicks = g_platform.getTicks();
|
||||
recalculate();
|
||||
}
|
||||
}
|
||||
@@ -310,7 +289,7 @@ void TextArea::removeCharacter(bool right)
|
||||
m_text.erase(m_text.begin() + m_cursorPos);
|
||||
else if((uint)m_cursorPos == m_text.length()) {
|
||||
m_text.erase(m_text.begin() + (--m_cursorPos));
|
||||
m_cursorTicks = g_engine.getCurrentFrameTicks();
|
||||
m_cursorTicks = g_platform.getTicks();
|
||||
}
|
||||
recalculate();
|
||||
}
|
||||
@@ -321,12 +300,12 @@ void TextArea::moveCursor(bool right)
|
||||
if(right) {
|
||||
if((uint)m_cursorPos+1 <= m_text.length()) {
|
||||
m_cursorPos++;
|
||||
m_cursorTicks = g_engine.getCurrentFrameTicks();
|
||||
m_cursorTicks = g_platform.getTicks();
|
||||
}
|
||||
} else {
|
||||
if(m_cursorPos-1 >= 0) {
|
||||
m_cursorPos--;
|
||||
m_cursorTicks = g_engine.getCurrentFrameTicks();
|
||||
m_cursorTicks = g_platform.getTicks();
|
||||
}
|
||||
}
|
||||
recalculate();
|
||||
|
@@ -1,32 +1,7 @@
|
||||
/* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 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 TEXTAREA_H
|
||||
#define TEXTAREA_H
|
||||
|
||||
#include <global.h>
|
||||
#include "font.h"
|
||||
#include "graphicsdeclarations.h"
|
||||
|
||||
class TextArea
|
||||
{
|
||||
@@ -77,4 +52,4 @@ private:
|
||||
std::vector<Rect> m_glyphsTexCoords;
|
||||
};
|
||||
|
||||
#endif // TEXTAREA_H
|
||||
#endif
|
||||
|
@@ -1,34 +1,11 @@
|
||||
/* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 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 <global.h>
|
||||
#include <graphics/texture.h>
|
||||
#include "texture.h"
|
||||
#include "graphics.h"
|
||||
|
||||
#include <GL/gl.h>
|
||||
|
||||
Texture::Texture(int width, int height, int channels, uchar *pixels)
|
||||
{
|
||||
// generate opengl texture
|
||||
// generate opengl texture
|
||||
m_textureId = internalLoadGLTexture(pixels, channels, width, height);
|
||||
}
|
||||
|
||||
@@ -36,10 +13,16 @@ uint Texture::internalLoadGLTexture(uchar *pixels, int channels, int width, int
|
||||
{
|
||||
g_graphics.disableDrawing();
|
||||
|
||||
GLint texSize = 0;
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texSize);
|
||||
if(width > texSize || height > texSize) {
|
||||
logError("loading texture with size ",width,"x",height," failed, the maximum size is ",texSize,"x",texSize);
|
||||
// get smax texture size supported by the driver
|
||||
static GLint maxTexSize = -1;
|
||||
if(maxTexSize == -1)
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
|
||||
|
||||
// checks texture max size
|
||||
if(width > maxTexSize || height > maxTexSize) {
|
||||
logError("ERROR: loading texture with size ", width, "x", height, " failed, "
|
||||
"the maximum size allowed by the graphics card is ", maxTexSize, "x", maxTexSize, ",",
|
||||
"to prevent crashes the texture will be displayed as a blank texture");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -50,6 +33,7 @@ uint Texture::internalLoadGLTexture(uchar *pixels, int channels, int width, int
|
||||
m_size.setSize(width, height);
|
||||
bool mustFree = false;
|
||||
|
||||
// old opengl drivers only accept power of two dimensions
|
||||
if(!g_graphics.isExtensionSupported("GL_ARB_texture_non_power_of_two") && pixels) {
|
||||
int glWidth = 1;
|
||||
while(glWidth < width)
|
||||
@@ -63,9 +47,9 @@ uint Texture::internalLoadGLTexture(uchar *pixels, int channels, int width, int
|
||||
uchar *tmp = new uchar[glHeight*glWidth*channels];
|
||||
memset(tmp, 0, glHeight*glWidth*channels);
|
||||
if(pixels)
|
||||
for(int y=0;y<height;++y)
|
||||
for(int x=0;x<width;++x)
|
||||
for(int i=0;i<channels;++i)
|
||||
for(int y=0; y<height; ++y)
|
||||
for(int x=0; x<width; ++x)
|
||||
for(int i=0; i<channels; ++i)
|
||||
tmp[y*glWidth*channels+x*channels+i] = pixels[y*width*channels+x*channels+i];
|
||||
pixels = tmp;
|
||||
mustFree = true;
|
||||
@@ -99,11 +83,10 @@ uint Texture::internalLoadGLTexture(uchar *pixels, int channels, int width, int
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
// nearest filtering
|
||||
// nearest filtering (non smooth)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
// free if needed
|
||||
if(mustFree)
|
||||
delete[] pixels;
|
||||
|
||||
@@ -112,30 +95,37 @@ uint Texture::internalLoadGLTexture(uchar *pixels, int channels, int width, int
|
||||
|
||||
Texture::~Texture()
|
||||
{
|
||||
g_graphics.disableDrawing();
|
||||
|
||||
// free texture from gl memory
|
||||
if(m_textureId)
|
||||
glDeleteTextures(1, &m_textureId);
|
||||
}
|
||||
|
||||
void Texture::enableBilinearFilter()
|
||||
{
|
||||
g_graphics.disableDrawing();
|
||||
|
||||
// enable smooth texture
|
||||
glBindTexture(GL_TEXTURE_2D, m_textureId);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
}
|
||||
|
||||
uchar *Texture::getPixels()
|
||||
uchar* Texture::getPixels()
|
||||
{
|
||||
g_graphics.disableDrawing();
|
||||
|
||||
// copy pixels from opengl memory
|
||||
uchar *pixels = new uchar[m_glSize.area()*4];
|
||||
uchar* pixels = new uchar[m_glSize.area()*4];
|
||||
glBindTexture(GL_TEXTURE_2D, m_textureId);
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
// convert pixels to the real texture size
|
||||
if(m_size != m_glSize)
|
||||
for(int y=0;y<m_size.height();++y)
|
||||
for(int x=0;x<m_size.width();++x)
|
||||
for(int i=0;i<4;++i)
|
||||
for(int y=0; y<m_size.height(); ++y)
|
||||
for(int x=0; x<m_size.width(); ++x)
|
||||
for(int i=0; i<4; ++i)
|
||||
pixels[y*m_size.width()*4+x*4+i] = pixels[y*m_glSize.width()*4+x*4+i];
|
||||
return pixels;
|
||||
}
|
||||
|
||||
|
@@ -1,37 +1,13 @@
|
||||
/* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 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 TEXTURE_H
|
||||
#define TEXTURE_H
|
||||
|
||||
#include <global.h>
|
||||
#include "graphicsdeclarations.h"
|
||||
|
||||
class Texture : public std::enable_shared_from_this<Texture>
|
||||
{
|
||||
public:
|
||||
/// Create a texture, width and height must be a multiple of 2
|
||||
Texture(int width, int height, int channels, uchar *pixels = NULL);
|
||||
Texture(int width, int height, int channels, uchar* pixels = NULL);
|
||||
virtual ~Texture();
|
||||
|
||||
/// Enable texture bilinear filter (smooth scaled textures)
|
||||
@@ -41,21 +17,18 @@ public:
|
||||
virtual uint getTextureId() const { return m_textureId; }
|
||||
|
||||
/// Copy pixels from OpenGL texture
|
||||
uchar *getPixels();
|
||||
uchar* getPixels();
|
||||
|
||||
const Size& getSize() const { return m_size; }
|
||||
const Size& getGlSize() const { return m_glSize; }
|
||||
|
||||
protected:
|
||||
Texture() { }
|
||||
uint internalLoadGLTexture(uchar *pixels, int channels, int w, int h);
|
||||
uint internalLoadGLTexture(uchar* pixels, int channels, int w, int h);
|
||||
|
||||
uint m_textureId;
|
||||
Size m_size;
|
||||
Size m_glSize;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<Texture> TexturePtr;
|
||||
typedef std::weak_ptr<Texture> TextureWeakPtr;
|
||||
|
||||
#endif // TEXTURE_H
|
||||
#endif
|
||||
|
@@ -1,46 +0,0 @@
|
||||
/* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 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 <global.h>
|
||||
#include <graphics/textureloader.h>
|
||||
#include <graphics/texture.h>
|
||||
#include <util/apngloader.h>
|
||||
#include "animatedtexture.h"
|
||||
|
||||
TexturePtr TextureLoader::loadPNG(std::stringstream& file)
|
||||
{
|
||||
TexturePtr texture;
|
||||
|
||||
apng_data apng;
|
||||
if(load_apng(file, &apng) == 0) {
|
||||
if(apng.num_frames > 1) { // animated texture
|
||||
uchar *framesdata = apng.pdata + (apng.first_frame * apng.width * apng.height * apng.bpp);
|
||||
texture = TexturePtr(new AnimatedTexture(apng.width, apng.height, apng.bpp, apng.num_frames, framesdata, (int*)apng.frames_delay));
|
||||
} else
|
||||
texture = TexturePtr(new Texture(apng.width, apng.height, apng.bpp, apng.pdata));
|
||||
free_apng(&apng);
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
/* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 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 TEXTURELOADER_H
|
||||
#define TEXTURELOADER_H
|
||||
|
||||
#include <global.h>
|
||||
#include <graphics/texture.h>
|
||||
|
||||
class TextureLoader
|
||||
{
|
||||
public:
|
||||
/// Load a png textures
|
||||
static TexturePtr loadPNG(std::stringstream& file);
|
||||
};
|
||||
|
||||
#endif // TEXTURELOADER_H
|
55
src/framework/graphics/texturemanager.cpp
Normal file
55
src/framework/graphics/texturemanager.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#include "texturemanager.h"
|
||||
#include "animatedtexture.h"
|
||||
#include <core/resourcemanager.h>
|
||||
#include <thirdparty/apngloader.h>
|
||||
|
||||
TextureManager g_textures;
|
||||
|
||||
TexturePtr TextureManager::getTexture(const std::string& textureFile)
|
||||
{
|
||||
TexturePtr texture;
|
||||
|
||||
// check if the texture is already loaded
|
||||
auto it = m_textures.find(textureFile);
|
||||
if(it != m_textures.end()) {
|
||||
if(it->second.expired())
|
||||
m_textures.erase(it);
|
||||
else
|
||||
texture = it->second.lock();
|
||||
}
|
||||
|
||||
// texture not found, load it
|
||||
if(!texture) {
|
||||
try {
|
||||
// currently only png textures are supported
|
||||
if(!boost::ends_with(textureFile, ".png"))
|
||||
throw std::logic_error("texture file format no supported");
|
||||
|
||||
// load texture file data
|
||||
std::stringstream fin;
|
||||
g_resources.loadFile(textureFile, fin);
|
||||
texture = loadPNG(fin);
|
||||
} catch(std::exception& e) {
|
||||
logError("ERROR: unable to load texture '",textureFile,"': ", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
TexturePtr TextureManager::loadPNG(std::stringstream& file)
|
||||
{
|
||||
TexturePtr texture;
|
||||
|
||||
apng_data apng;
|
||||
if(load_apng(file, &apng) == 0) {
|
||||
if(apng.num_frames > 1) { // animated texture
|
||||
uchar *framesdata = apng.pdata + (apng.first_frame * apng.width * apng.height * apng.bpp);
|
||||
texture = TexturePtr(new AnimatedTexture(apng.width, apng.height, apng.bpp, apng.num_frames, framesdata, (int*)apng.frames_delay));
|
||||
} else
|
||||
texture = TexturePtr(new Texture(apng.width, apng.height, apng.bpp, apng.pdata));
|
||||
free_apng(&apng);
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
21
src/framework/graphics/texturemanager.h
Normal file
21
src/framework/graphics/texturemanager.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef TEXTUREMANAGER_H
|
||||
#define TEXTUREMANAGER_H
|
||||
|
||||
#include "texture.h"
|
||||
|
||||
class TextureManager
|
||||
{
|
||||
public:
|
||||
/// Load a texture from file, if is already loaded, it will be retrieved from cache
|
||||
TexturePtr getTexture(const std::string& textureFile);
|
||||
|
||||
/// Load a png textures
|
||||
static TexturePtr loadPNG(std::stringstream& file);
|
||||
|
||||
private:
|
||||
std::map<std::string, TextureWeakPtr> m_textures;
|
||||
};
|
||||
|
||||
extern TextureManager g_textures;
|
||||
|
||||
#endif
|
@@ -1,68 +0,0 @@
|
||||
/* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 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 <global.h>
|
||||
#include <core/resources.h>
|
||||
#include <graphics/textures.h>
|
||||
#include <graphics/textureloader.h>
|
||||
#include <core/dispatcher.h>
|
||||
|
||||
Textures g_textures;
|
||||
|
||||
TexturePtr Textures::get(const std::string& textureFile)
|
||||
{
|
||||
TexturePtr texture;
|
||||
|
||||
// check if the texture is already loaded
|
||||
auto it = m_textures.find(textureFile);
|
||||
if(it != m_textures.end()) {
|
||||
if(it->second.expired())
|
||||
m_textures.erase(it);
|
||||
else
|
||||
texture = it->second.lock();
|
||||
}
|
||||
|
||||
// texture not found, load it
|
||||
if(!texture) {
|
||||
// currently only png textures are supported
|
||||
if(!boost::ends_with(textureFile, ".png")) {
|
||||
logError("ERROR: Unable to load texture '",textureFile,"', file format no supported.");
|
||||
return texture;
|
||||
}
|
||||
|
||||
// load texture file data
|
||||
std::stringstream fin;
|
||||
if(!g_resources.loadFile(textureFile, fin)) {
|
||||
logError("ERROR: Unable to load texture '",textureFile,"', file could not be read.");
|
||||
return texture;
|
||||
}
|
||||
|
||||
|
||||
// load the texture
|
||||
texture = TexturePtr(TextureLoader::loadPNG(fin));
|
||||
if(!texture)
|
||||
logError("ERROR: Unable to load texture '",textureFile,"'");
|
||||
}
|
||||
return texture;
|
||||
}
|
@@ -1,45 +0,0 @@
|
||||
/* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 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 TEXTURES_H
|
||||
#define TEXTURES_H
|
||||
|
||||
#include <global.h>
|
||||
#include <graphics/texture.h>
|
||||
|
||||
class Textures
|
||||
{
|
||||
public:
|
||||
Textures() { }
|
||||
|
||||
/// Load a texture from file, if it was already loaded it will be retrieved from cache
|
||||
TexturePtr get(const std::string& textureFile);
|
||||
|
||||
private:
|
||||
std::map<std::string, TextureWeakPtr> m_textures;
|
||||
};
|
||||
|
||||
extern Textures g_textures;
|
||||
|
||||
#endif // TEXTURES_H
|
@@ -1,71 +1,79 @@
|
||||
#ifndef LUABINDER_H
|
||||
#define LUABINDER_H
|
||||
|
||||
#include "luavalue.h"
|
||||
#include "luastate.h"
|
||||
// this file is and must be included only from luainterface.h
|
||||
#include "luainterface.h"
|
||||
#include "luaexception.h"
|
||||
|
||||
/// This namespace contains some dirty metaprogamming with C++0x features
|
||||
/// The purpose here is to create templates that can bind any function from C++
|
||||
/// and expose in lua environment. This is done combining variadic templates,
|
||||
/// lambdas, tuples and some type traits features from the new C++0x standard to create
|
||||
/// templates that can detect functions arguments to generate a lambdas. These lambdas
|
||||
/// pops arguments from lua stack, call the bound C++ function and then
|
||||
/// pushes the result to lua.
|
||||
namespace luabinder
|
||||
{
|
||||
// transform const T& -> T
|
||||
/// Removes const references, transforming 'const T&' into 'T'
|
||||
template<typename T>
|
||||
struct remove_const_ref {
|
||||
typedef typename std::remove_const<typename std::remove_reference<T>::type>::type type;
|
||||
};
|
||||
|
||||
// pack an value into tuple recursively
|
||||
/// Pack arguments from lua stack into a tuple recursively
|
||||
template<int N>
|
||||
struct pack_values_into_tuple {
|
||||
template<typename Tuple>
|
||||
static void call(Tuple& tuple, LuaState* lua) {
|
||||
static void call(Tuple& tuple, LuaInterface* lua) {
|
||||
typedef typename std::tuple_element<N-1, Tuple>::type ValueType;
|
||||
std::get<N-1>(tuple) = safe_luavalue_cast<ValueType>(lua->popValue());
|
||||
std::get<N-1>(tuple) = lua->polymorphicPop<ValueType>();
|
||||
pack_values_into_tuple<N-1>::call(tuple, lua);
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct pack_values_into_tuple<0> {
|
||||
template<typename Tuple>
|
||||
static void call(Tuple &tuple, LuaState* lua) { }
|
||||
static void call(Tuple &tuple, LuaInterface* lua) { }
|
||||
};
|
||||
|
||||
// call function
|
||||
/// C++ function caller that can push results to lua
|
||||
template<typename Ret, typename F, typename... Args>
|
||||
typename std::enable_if<!std::is_void<Ret>::value, int>::type
|
||||
call_fun_and_push_result(const F& f, LuaState* lua, Args... args) {
|
||||
call_fun_and_push_result(const F& f, LuaInterface* lua, Args... args) {
|
||||
Ret ret = f(args...);
|
||||
lua->pushValue(safe_to_luavalue(ret));
|
||||
lua->polymorphicPush(ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// call function with no return
|
||||
/// C++ void function caller
|
||||
template<typename Ret, typename F, typename... Args>
|
||||
typename std::enable_if<std::is_void<Ret>::value, int>::type
|
||||
call_fun_and_push_result(const F& f, LuaState* lua, Args... args) {
|
||||
call_fun_and_push_result(const F& f, LuaInterface* lua, Args... args) {
|
||||
f(args...);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// expand function arguments for calling
|
||||
/// Expand arguments from tuple for later calling the C++ function
|
||||
template<int N, typename Ret>
|
||||
struct expand_fun_arguments {
|
||||
template<typename Tuple, typename F, typename... Args>
|
||||
static int call(const Tuple& tuple, const F& f, LuaState* lua, Args... args) {
|
||||
static int call(const Tuple& tuple, const F& f, LuaInterface* lua, Args... args) {
|
||||
return expand_fun_arguments<N-1,Ret>::call(tuple, f, lua, std::cref(std::get<N-1>(tuple)), args...);
|
||||
}
|
||||
};
|
||||
template<typename Ret>
|
||||
struct expand_fun_arguments<0,Ret> {
|
||||
template<typename Tuple, typename F, typename... Args>
|
||||
static int call(const Tuple& tuple, const F& f, LuaState* lua, Args... args) {
|
||||
static int call(const Tuple& tuple, const F& f, LuaInterface* lua, Args... args) {
|
||||
return call_fun_and_push_result<Ret>(f, lua, args...);
|
||||
}
|
||||
};
|
||||
|
||||
// bind different types of functions
|
||||
/// Bind different types of functions generating a lambda
|
||||
template<typename Ret, typename F, typename Tuple>
|
||||
LuaCppFunction bind_fun_specializer(const F& f) {
|
||||
enum { N = std::tuple_size<Tuple>::value };
|
||||
return [=](LuaState* lua) {
|
||||
return [=](LuaInterface* lua) {
|
||||
if(lua->stackSize() != N)
|
||||
throw LuaBadNumberOfArgumentsException(N, lua->stackSize());
|
||||
Tuple tuple;
|
||||
@@ -74,7 +82,7 @@ namespace luabinder
|
||||
};
|
||||
}
|
||||
|
||||
// bind a std::function
|
||||
/// Bind a std::function
|
||||
template<typename Ret, typename... Args>
|
||||
LuaCppFunction bind_fun(const std::function<Ret(Args...)>& f) {
|
||||
typedef typename std::tuple<typename remove_const_ref<Args>::type...> Tuple;
|
||||
@@ -83,13 +91,14 @@ namespace luabinder
|
||||
Tuple>(f);
|
||||
}
|
||||
|
||||
// bind a custumized function
|
||||
/// Bind a customized functions
|
||||
template<>
|
||||
inline
|
||||
LuaCppFunction bind_fun(const std::function<int(LuaState*)>& f) {
|
||||
LuaCppFunction bind_fun(const std::function<int(LuaInterface*)>& f) {
|
||||
return f;
|
||||
}
|
||||
|
||||
// convert to std::function then bind
|
||||
/// Convert to C++ functions pointers to std::function then bind
|
||||
template<typename Ret, typename... Args>
|
||||
LuaCppFunction bind_fun(Ret (*f)(Args...)) {
|
||||
return bind_fun(std::function<Ret(Args...)>(f));
|
||||
@@ -108,12 +117,17 @@ namespace luabinder
|
||||
template<std::size_t __i>
|
||||
struct tuple_element<__i,std::tuple<>> { typedef void type; };
|
||||
|
||||
// rebind functions already binded by std::bind that have placeholders
|
||||
template<typename Enable, int N, typename ArgsTuple, typename HoldersTuple, typename... Args>
|
||||
struct get_holded_tuple;
|
||||
|
||||
// some dirty stuff to extract arguments from std::bind holders
|
||||
template<int N, typename ArgsTuple, typename HoldersTuple, typename... Args>
|
||||
struct get_holded_tuple<typename std::enable_if<(N > 0 && std::is_placeholder<typename tuple_element<N-1, HoldersTuple>::type>::value > 0), void>::type, N, ArgsTuple, HoldersTuple, Args...> {
|
||||
struct get_holded_tuple<
|
||||
typename std::enable_if<
|
||||
(N > 0 && std::is_placeholder<
|
||||
typename tuple_element<N-1, HoldersTuple>::type
|
||||
>::value > 0), void
|
||||
>::type, N, ArgsTuple, HoldersTuple, Args...> {
|
||||
typedef typename std::tuple_element<N-1, HoldersTuple>::type holder_type;
|
||||
typedef typename tuple_element<std::is_placeholder<holder_type>::value-1, ArgsTuple>::type _arg_type;
|
||||
typedef typename remove_const_ref<_arg_type>::type arg_type;
|
||||
@@ -128,6 +142,7 @@ namespace luabinder
|
||||
typedef typename std::tuple<Args...> type;
|
||||
};
|
||||
|
||||
/// Rebind functions already bound by std::bind handling it's placeholders
|
||||
template<typename Ret, typename... Args, typename... Holders>
|
||||
LuaCppFunction bind_fun(const std::_Bind<Ret (*(Holders...))(Args...)>& f) {
|
||||
typedef typename std::tuple<Args...> ArgsTuple;
|
||||
@@ -138,6 +153,7 @@ namespace luabinder
|
||||
Tuple>(f);
|
||||
}
|
||||
|
||||
/// Rebind member functions already bound by std::bind handling it's placeholders
|
||||
template<typename Obj, typename Ret, typename... Args, typename... Holders>
|
||||
LuaCppFunction bind_fun(const std::_Bind<std::_Mem_fn<Ret (Obj::*)(Args...)>(Obj*, Holders...)>& f) {
|
||||
typedef typename std::tuple<Args...> ArgsTuple;
|
||||
@@ -148,17 +164,17 @@ namespace luabinder
|
||||
Tuple>(f);
|
||||
}
|
||||
|
||||
// custumized functions already binded by std::bind doesn't need to be bind again
|
||||
/// Bind customized functions already bound by std::bind
|
||||
template<typename Obj>
|
||||
LuaCppFunction bind_fun(const std::_Bind<std::_Mem_fn<int (Obj::*)(LuaState*)>(Obj*, std::_Placeholder<1>)>& f) {
|
||||
LuaCppFunction bind_fun(const std::_Bind<std::_Mem_fn<int (Obj::*)(LuaInterface*)>(Obj*, std::_Placeholder<1>)>& f) {
|
||||
return f;
|
||||
}
|
||||
inline
|
||||
LuaCppFunction bind_fun(const std::_Bind<int (*(std::_Placeholder<1>))(LuaState*)>& f) {
|
||||
LuaCppFunction bind_fun(const std::_Bind<int (*(std::_Placeholder<1>))(LuaInterface*)>& f) {
|
||||
return f;
|
||||
}
|
||||
|
||||
// bind member function
|
||||
/// Bind member functions
|
||||
template<typename Ret, typename Obj, typename... Args>
|
||||
LuaCppFunction bind_mem_fun(Ret (Obj::*f)(Args...)) {
|
||||
auto mf = std::mem_fn(f);
|
||||
@@ -176,16 +192,16 @@ namespace luabinder
|
||||
Tuple>(mf);
|
||||
}
|
||||
|
||||
// bind custumized member function
|
||||
/// Bind customized member functions
|
||||
template<typename Obj>
|
||||
LuaCppFunction bind_mem_fun(int (Obj::*f)(LuaState*)) {
|
||||
LuaCppFunction bind_mem_fun(int (Obj::*f)(LuaInterface*)) {
|
||||
auto mf = std::mem_fn(f);
|
||||
return [=](LuaState* lua) {
|
||||
lua->insert(1);
|
||||
auto obj = safe_luavalue_cast<Obj*>(lua->popValue());
|
||||
return [=](LuaInterface* lua) {
|
||||
auto obj = lua->castValue<Obj*>(1);
|
||||
lua->remove(1);
|
||||
return mf(obj, lua);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // LUABINDER_H
|
||||
#endif
|
12
src/framework/luascript/luadeclarations.h
Normal file
12
src/framework/luascript/luadeclarations.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef LUADECLARATIONS_H
|
||||
#define LUADECLARATIONS_H
|
||||
|
||||
#include <global.h>
|
||||
|
||||
class LuaInterface;
|
||||
class LuaObject;
|
||||
typedef std::function<int(LuaInterface*)> LuaCppFunction;
|
||||
typedef std::unique_ptr<LuaCppFunction> LuaCppFunctionPtr;
|
||||
typedef std::shared_ptr<LuaObject> LuaObjectPtr;
|
||||
|
||||
#endif
|
31
src/framework/luascript/luaexception.cpp
Normal file
31
src/framework/luascript/luaexception.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "luaexception.h"
|
||||
#include "luainterface.h"
|
||||
|
||||
LuaException::LuaException(const std::string& error, int traceLevel)
|
||||
{
|
||||
g_lua.clearStack(); // on every exception, clear lua stack
|
||||
generateLuaErrorMessage(error, traceLevel);
|
||||
}
|
||||
|
||||
void LuaException::generateLuaErrorMessage(const std::string& error, int traceLevel)
|
||||
{
|
||||
// append trace level to error message
|
||||
if(traceLevel >= 0)
|
||||
m_what = aux::make_string("LUA ERROR: ", g_lua.traceback(error, traceLevel));
|
||||
else
|
||||
m_what = aux::make_string("LUA ERROR: ", error);
|
||||
}
|
||||
|
||||
LuaBadNumberOfArgumentsException::LuaBadNumberOfArgumentsException(int expected, int got)
|
||||
{
|
||||
std::string error = "attempt to call a function with wrong number of arguments";
|
||||
if(expected >= 0 && got >= 0)
|
||||
error = aux::make_string(error, " (expected ", expected, ", but got ", got, ")");
|
||||
generateLuaErrorMessage(error, 1);
|
||||
}
|
||||
|
||||
LuaBadValueCastException::LuaBadValueCastException(const std::string& luaTypeName, const std::string& cppTypeName)
|
||||
{
|
||||
std::string error = aux::make_string("attempt to cast a '", luaTypeName, "' lua value to '", cppTypeName, "'");
|
||||
generateLuaErrorMessage(error, 0);
|
||||
}
|
@@ -3,12 +3,11 @@
|
||||
|
||||
#include "luadeclarations.h"
|
||||
|
||||
/// LuaException, all lua errors are throwed by it
|
||||
class LuaException : public std::exception
|
||||
{
|
||||
public:
|
||||
LuaException(const std::string& error, int traceLevel = -1);
|
||||
virtual ~LuaException() throw() { };
|
||||
virtual ~LuaException() throw() { }
|
||||
|
||||
void generateLuaErrorMessage(const std::string& error, int traceLevel);
|
||||
|
||||
@@ -20,19 +19,16 @@ protected:
|
||||
std::string m_what;
|
||||
};
|
||||
|
||||
class LuaBadNumberOfArgumentsException : public LuaException {
|
||||
class LuaBadNumberOfArgumentsException : public LuaException
|
||||
{
|
||||
public:
|
||||
LuaBadNumberOfArgumentsException(int expected = -1, int got = -1);
|
||||
};
|
||||
|
||||
class LuaBadTypeConversinException : public LuaException {
|
||||
class LuaBadValueCastException : public LuaException
|
||||
{
|
||||
public:
|
||||
LuaBadTypeConversinException(const std::string& typeName = "an incompatible lua type");
|
||||
};
|
||||
|
||||
class LuaBadValueCastException : public LuaException {
|
||||
public:
|
||||
LuaBadValueCastException(const LuaValuePtr& value, const std::string& typeName = "an incompatible lua type");
|
||||
LuaBadValueCastException(const std::string& luaTypeName, const std::string& cppTypeName);
|
||||
};
|
||||
|
||||
#endif
|
63
src/framework/luascript/luafunctions.cpp
Normal file
63
src/framework/luascript/luafunctions.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#include "luainterface.h"
|
||||
#include <graphics/fontmanager.h>
|
||||
#include <ui/ui.h>
|
||||
#include <net/protocol.h>
|
||||
|
||||
void LuaInterface::registerFunctions()
|
||||
{
|
||||
// easy typing _1, _2, ...
|
||||
using namespace std::placeholders;
|
||||
|
||||
// UIWidget
|
||||
g_lua.registerClass<UIWidget>();
|
||||
g_lua.bindClassStaticFunction<UIWidget>("create", &UIWidget::create);
|
||||
|
||||
g_lua.bindClassMemberFunction("destroy", &UIWidget::destroy);
|
||||
g_lua.bindClassMemberFunction("addChild", &UIWidget::addChild);
|
||||
|
||||
g_lua.bindClassMemberField<UIWidget>("id", &UIWidget::getId, &UIWidget::setId);
|
||||
g_lua.bindClassMemberField<UIWidget>("enabled", &UIWidget::isEnabled, &UIWidget::setEnabled);
|
||||
g_lua.bindClassMemberField<UIWidget>("visible", &UIWidget::isVisible, &UIWidget::setVisible);
|
||||
g_lua.bindClassMemberField<UIWidget>("width", &UIWidget::getWidth, &UIWidget::setWidth);
|
||||
g_lua.bindClassMemberField<UIWidget>("height", &UIWidget::getHeight, &UIWidget::setHeight);
|
||||
g_lua.bindClassMemberField<UIWidget>("parent", &UIWidget::getParent, &UIWidget::setParent);
|
||||
g_lua.bindClassMemberField<UIWidget>("marginTop", &UIWidget::getMarginTop, &UIWidget::setMarginTop);
|
||||
g_lua.bindClassMemberField<UIWidget>("marginBottom", &UIWidget::getMarginBottom, &UIWidget::setMarginBottom);
|
||||
g_lua.bindClassMemberField<UIWidget>("marginLeft", &UIWidget::getMarginLeft, &UIWidget::setMarginLeft);
|
||||
g_lua.bindClassMemberField<UIWidget>("marginRight", &UIWidget::getMarginRight, &UIWidget::setMarginRight);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("centerIn", &UIWidget::centerIn);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("addAnchor", &UIWidget::addAnchor);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("getChild", &UIWidget::getChildById);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("addChild", &UIWidget::addChild);
|
||||
|
||||
// UILabel
|
||||
g_lua.registerClass<UILabel, UIWidget>();
|
||||
g_lua.bindClassStaticFunction<UILabel>("create", &UILabel::create);
|
||||
g_lua.bindClassMemberField("text", &UILabel::getText, &UILabel::setText);
|
||||
g_lua.bindClassMemberFunction("resizeToText", &UILabel::resizeToText);
|
||||
|
||||
// UIButton
|
||||
g_lua.registerClass<UIButton, UIWidget>();
|
||||
g_lua.bindClassStaticFunction<UIButton>("create", &UIButton::create);
|
||||
g_lua.bindClassMemberField("text", &UIButton::getText, &UIButton::setText);
|
||||
|
||||
// UILineEdit
|
||||
g_lua.registerClass<UILineEdit, UIWidget>();
|
||||
g_lua.bindClassStaticFunction<UILineEdit>("create", &UILineEdit::create);
|
||||
g_lua.bindClassMemberField("text", &UILineEdit::getText, &UILineEdit::setText);
|
||||
|
||||
// UIWindow
|
||||
g_lua.registerClass<UIWindow, UIWidget>();
|
||||
g_lua.bindClassStaticFunction<UIWindow>("create", &UIWindow::create);
|
||||
g_lua.bindClassMemberField("title", &UIWindow::getTitle, &UIWindow::setTitle);
|
||||
|
||||
// Protocol
|
||||
g_lua.registerClass<Protocol>();
|
||||
|
||||
// global functions
|
||||
g_lua.bindGlobalFunction("importFont", std::bind(&FontManager::importFont, &g_fonts, _1));
|
||||
g_lua.bindGlobalFunction("setDefaultFont", std::bind(&FontManager::setDefaultFont, &g_fonts, _1));
|
||||
g_lua.bindGlobalFunction("importStyles", std::bind(&UIManager::importStyles, &g_ui, _1));
|
||||
g_lua.bindGlobalFunction("loadUI", std::bind(&UIManager::loadUI, &g_ui, _1));
|
||||
g_lua.bindGlobalFunction("getRootWidget", std::bind(&UIManager::getRootWidget, &g_ui));
|
||||
}
|
1035
src/framework/luascript/luainterface.cpp
Normal file
1035
src/framework/luascript/luainterface.cpp
Normal file
File diff suppressed because it is too large
Load Diff
329
src/framework/luascript/luainterface.h
Normal file
329
src/framework/luascript/luainterface.h
Normal file
@@ -0,0 +1,329 @@
|
||||
#ifndef LUAINTERFACE_H
|
||||
#define LUAINTERFACE_H
|
||||
|
||||
#include "luadeclarations.h"
|
||||
|
||||
struct lua_State;
|
||||
typedef int (*LuaCFunction) (lua_State *L);
|
||||
|
||||
/// Class that manages LUA stuff
|
||||
class LuaInterface
|
||||
{
|
||||
public:
|
||||
LuaInterface();
|
||||
~LuaInterface();
|
||||
|
||||
void init();
|
||||
void terminate();
|
||||
|
||||
/// Register core script functions
|
||||
void registerFunctions();
|
||||
|
||||
// functions that will register all script stuff in lua global environment
|
||||
void registerClass(const std::string& className, const std::string& baseClass = "LuaObject");
|
||||
|
||||
void registerClassStaticFunction(const std::string& className,
|
||||
const std::string& functionName,
|
||||
const LuaCppFunction& function);
|
||||
|
||||
void registerClassMemberFunction(const std::string& className,
|
||||
const std::string& functionName,
|
||||
const LuaCppFunction& function);
|
||||
|
||||
void registerClassMemberField(const std::string& className,
|
||||
const std::string& field,
|
||||
const LuaCppFunction& getFunction,
|
||||
const LuaCppFunction& setFunction);
|
||||
|
||||
void registerGlobalFunction(const std::string& functionName,
|
||||
const LuaCppFunction& function);
|
||||
|
||||
// register shortcuts using templates
|
||||
template<class C, class B = LuaObject>
|
||||
void registerClass() {
|
||||
registerClass(aux::demangle_type<C>(), aux::demangle_type<B>());
|
||||
}
|
||||
|
||||
template<class C>
|
||||
void registerClassStaticFunction(const std::string& functionName, const LuaCppFunction& function) {
|
||||
registerClassStaticFunction(aux::demangle_type<C>(), functionName, function);
|
||||
}
|
||||
|
||||
template<class C>
|
||||
void registerClassMemberFunction(const std::string& functionName, const LuaCppFunction& function) {
|
||||
registerClassMemberFunction(aux::demangle_type<C>(), functionName, function);
|
||||
}
|
||||
|
||||
template<class C>
|
||||
void registerClassMemberField(const std::string& field,
|
||||
const LuaCppFunction& getFunction,
|
||||
const LuaCppFunction& setFunction) {
|
||||
registerClassMemberField(aux::demangle_type<C>(), field, getFunction, setFunction);
|
||||
}
|
||||
|
||||
// methods for binding functions
|
||||
template<class C, typename F>
|
||||
void bindClassStaticFunction(const std::string& functionName, const F& function);
|
||||
|
||||
template<class C, typename F>
|
||||
void bindClassMemberFunction(const std::string& functionName, F C::*function);
|
||||
|
||||
template<class C, typename F1, typename F2>
|
||||
void bindClassMemberField(const std::string& fieldName, F1 C::*getFunction, F2 C::*setFunction);
|
||||
|
||||
template<class C, typename F>
|
||||
void bindClassMemberGetField(const std::string& fieldName, F C::*getFunction);
|
||||
|
||||
template<class C, typename F>
|
||||
void bindClassMemberSetField(const std::string& fieldName, F C::*setFunction);
|
||||
|
||||
template<typename F>
|
||||
void bindGlobalFunction(const std::string& functionName, const F& function);
|
||||
|
||||
private:
|
||||
/// Metamethod that will retrieve fields values (that include functions) from the object when using '.' or ':'
|
||||
static int luaObjectGetEvent(LuaInterface* lua);
|
||||
/// Metamethod that is called when setting a field of the object by using the keyword '='
|
||||
static int luaObjectSetEvent(LuaInterface* lua);
|
||||
/// Metamethod that will check equality of objects by using the keyword '=='
|
||||
static int luaObjectEqualEvent(LuaInterface* lua);
|
||||
/// Metamethod that is called every two lua garbage collections
|
||||
/// for any LuaObject that have no references left in lua environment
|
||||
/// anymore, thus this creates the possibility of holding an object
|
||||
/// existence by lua until it got no references left
|
||||
static int luaObjectCollectEvent(LuaInterface* lua);
|
||||
|
||||
public:
|
||||
/// Loads and runs a script
|
||||
/// @exception LuaException is thrown on any lua error
|
||||
void runScript(const std::string& fileName);
|
||||
|
||||
/// Loads and runs the script from buffer
|
||||
/// @exception LuaException is thrown on any lua error
|
||||
void runBuffer(const std::string& buffer, const std::string& source);
|
||||
|
||||
/// Loads a script file and pushes it's main function onto stack,
|
||||
/// @exception LuaException is thrown on any lua error
|
||||
void loadScript(const std::string& fileName);
|
||||
|
||||
/// Loads a function from buffer and pushes it onto stack,
|
||||
/// @exception LuaException is thrown on any lua error
|
||||
void loadFunction(const std::string& buffer, const std::string& source = "lua function buffer");
|
||||
|
||||
/// Evaluates a lua expression and pushes the result value onto the stack
|
||||
/// @exception LuaException is thrown on any lua error
|
||||
void evaluateExpression(const std::string& expression, const std::string& source = "lua expression");
|
||||
|
||||
/// Generates a traceback message for the current call stack
|
||||
/// @param errorMessage is an additional error message
|
||||
/// @param level is the level of the traceback, 0 means trace from calling function
|
||||
/// @return the generated traceback message
|
||||
std::string traceback(const std::string& errorMessage = "", int level = 0);
|
||||
|
||||
/// Searches for the source of the current running function
|
||||
std::string currentSourcePath();
|
||||
|
||||
/// @brief Calls a function
|
||||
/// The function and arguments must be on top of the stack in order,
|
||||
/// results are pushed onto the stack.
|
||||
/// @exception LuaException is thrown on any lua error
|
||||
/// @return number of results
|
||||
int safeCall(int numArgs = 0);
|
||||
|
||||
/// Same as safeCall but catches exceptions and can also calls a table of functions,
|
||||
/// if any error occurs it will be reported to stdout and returns 0 results
|
||||
/// @param requestedResults is the number of results requested to pushes onto the stack,
|
||||
/// if supplied, the call will always pushes that number of results, even if it fails
|
||||
int protectedCall(int numArgs = 0, int requestedResults = -1);
|
||||
|
||||
/// @brief Creates a new environment table
|
||||
/// The new environment table is redirected to the global environment (aka _G),
|
||||
/// this allows to access global variables from _G in the new environment and
|
||||
/// prevents new variables in this new environment to be set on the global environment
|
||||
void newEnvironment();
|
||||
|
||||
private:
|
||||
/// Load scripts requested by lua 'require'
|
||||
static int luaScriptLoader(lua_State* L);
|
||||
/// Handle lua errors from safeCall
|
||||
static int luaErrorHandler(lua_State* L);
|
||||
/// Handle bound cpp functions callbacks
|
||||
static int luaCppFunctionCallback(lua_State* L);
|
||||
/// Collect bound cpp function pointers
|
||||
static int luaCollectCppFunction(lua_State* L);
|
||||
|
||||
public:
|
||||
void createLuaState();
|
||||
void closeLuaState();
|
||||
|
||||
void collectGarbage();
|
||||
|
||||
void loadBuffer(const std::string& buffer, const std::string& source);
|
||||
|
||||
int pcall(int numArgs = 0, int numRets = 0, int errorFuncIndex = 0);
|
||||
void call(int numArgs = 0, int numRets = 0);
|
||||
void throwError();
|
||||
|
||||
int ref();
|
||||
int weakRef();
|
||||
void unref(int ref);
|
||||
void useValue() { pushValue(); ref(); }
|
||||
|
||||
const char* typeName(int index = -1);
|
||||
std::string functionSourcePath();
|
||||
|
||||
void insert(int index);
|
||||
void remove(int index);
|
||||
bool next(int index = -2);
|
||||
void copy(int index = -1);
|
||||
|
||||
void getStackFunction(int level = 0);
|
||||
|
||||
void getRef(int ref);
|
||||
void getWeakRef(int weakRef);
|
||||
|
||||
void getGlobalEnvironment();
|
||||
void setGlobalEnvironment();
|
||||
|
||||
void setMetatable(int index = -2);
|
||||
void getMetatable(int index = -1);
|
||||
|
||||
void getField(const char* key, int index = -1);
|
||||
void getField(const std::string& key, int index = -1) { return getField(key.c_str(), index); }
|
||||
void setField(const char* key, int index = -2);
|
||||
void setField(const std::string& key, int index = -2) { return setField(key.c_str(), index); }
|
||||
|
||||
void getTable(int index = -2);
|
||||
void setTable(int index = -3);
|
||||
|
||||
void getEnv(int index = -1);
|
||||
void setEnv(int index = -2);
|
||||
|
||||
void getGlobal(const std::string& key);
|
||||
void setGlobal(const std::string& key);
|
||||
|
||||
void rawGet(int index = -1);
|
||||
void rawGeti(int n, int index = -1);
|
||||
void rawSet(int index = -3);
|
||||
void rawSeti(int n, int index = -2);
|
||||
|
||||
void newTable();
|
||||
void* newUserdata(int size);
|
||||
|
||||
void pop(int n = 1);
|
||||
int popInteger();
|
||||
double popNumber();
|
||||
bool popBoolean();
|
||||
std::string popString();
|
||||
void* popUserdata();
|
||||
void* popUpvalueUserdata();
|
||||
LuaObjectPtr popObject();
|
||||
|
||||
void pushNil();
|
||||
void pushInteger(int v);
|
||||
void pushNumber(double v);
|
||||
void pushBoolean(bool v);
|
||||
void pushCString(const char* v);
|
||||
void pushString(const std::string& v) { pushCString(v.c_str()); }
|
||||
void pushLightUserdata(void* p);
|
||||
void pushThread();
|
||||
void pushValue(int index = -1);
|
||||
void pushObject(const LuaObjectPtr& obj);
|
||||
void pushCFunction(LuaCFunction func, int n = 0);
|
||||
void pushCppFunction(const LuaCppFunction& func);
|
||||
|
||||
bool isNil(int index = -1);
|
||||
bool isBoolean(int index = -1);
|
||||
bool isNumber(int index = -1);
|
||||
bool isString(int index = -1);
|
||||
bool isTable(int index = -1);
|
||||
bool isFunction(int index = -1);
|
||||
bool isCFunction(int index = -1);
|
||||
bool isLuaFunction(int index = -1) { return (isFunction() && !isCFunction()); }
|
||||
bool isUserdata(int index = -1);
|
||||
|
||||
bool toBoolean(int index = -1);
|
||||
int toInteger(int index = -1);
|
||||
double toNumber(int index = -1);
|
||||
const char* toCString(int index = -1);
|
||||
std::string toString(int index = -1);
|
||||
void* toUserdata(int index = -1);
|
||||
LuaObjectPtr toObject(int index = -1);
|
||||
|
||||
int getTop();
|
||||
int stackSize() { return getTop(); }
|
||||
void clearStack() { pop(stackSize()); }
|
||||
bool hasIndex(int index) { return (stackSize() >= (index < 0 ? -index : index) && index != 0); }
|
||||
|
||||
/// Pushes any type onto the stack
|
||||
template<typename T, typename... Args>
|
||||
void polymorphicPush(T v, Args... args) { push_luavalue(v); polymorphicPush(args...); }
|
||||
void polymorphicPush() { }
|
||||
|
||||
/// Casts a value from stack to any type
|
||||
/// @exception LuaBadValueCastException thrown if the cast fails
|
||||
template<class T>
|
||||
T castValue(int index = -1);
|
||||
|
||||
/// Same as castValue but also pops
|
||||
template<class T>
|
||||
T polymorphicPop() { T v = castValue<T>(); pop(1); return v; }
|
||||
|
||||
private:
|
||||
lua_State* L;
|
||||
int m_weakTableRef;
|
||||
};
|
||||
|
||||
extern LuaInterface g_lua;
|
||||
|
||||
// must be included after, because they need LuaInterface fully declared
|
||||
#include "luaexception.h"
|
||||
#include "luabinder.h"
|
||||
#include "luavaluecasts.h"
|
||||
|
||||
// next templates must be defined after above includes
|
||||
template<class C, typename F>
|
||||
void LuaInterface::bindClassStaticFunction(const std::string& functionName, const F& function) {
|
||||
registerClassStaticFunction<C>(functionName, luabinder::bind_fun(function));
|
||||
}
|
||||
|
||||
template<class C, typename F>
|
||||
void LuaInterface::bindClassMemberFunction(const std::string& functionName, F C::*function) {
|
||||
registerClassMemberFunction<C>(functionName, luabinder::bind_mem_fun(function));
|
||||
}
|
||||
|
||||
template<class C, typename F1, typename F2>
|
||||
void LuaInterface::bindClassMemberField(const std::string& fieldName, F1 C::*getFunction, F2 C::*setFunction) {
|
||||
registerClassMemberField<C>(fieldName,
|
||||
luabinder::bind_mem_fun(getFunction),
|
||||
luabinder::bind_mem_fun(setFunction));
|
||||
}
|
||||
|
||||
template<class C, typename F>
|
||||
void LuaInterface::bindClassMemberGetField(const std::string& fieldName, F C::*getFunction) {
|
||||
registerClassMemberField<C>(fieldName,
|
||||
luabinder::bind_mem_fun(getFunction),
|
||||
LuaCppFunction());
|
||||
}
|
||||
|
||||
template<class C, typename F>
|
||||
void LuaInterface::bindClassMemberSetField(const std::string& fieldName, F C::*setFunction) {
|
||||
registerClassMemberField<C>(fieldName,
|
||||
LuaCppFunction(),
|
||||
luabinder::bind_mem_fun(setFunction));
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void LuaInterface::bindGlobalFunction(const std::string& functionName, const F& function) {
|
||||
registerGlobalFunction(functionName, luabinder::bind_fun(function));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T LuaInterface::castValue(int index) {
|
||||
T o;
|
||||
if(!luavalue_cast(index, o))
|
||||
throw LuaBadValueCastException(typeName(index), aux::demangle_type<T>());
|
||||
return o;
|
||||
}
|
||||
|
||||
#endif
|
47
src/framework/luascript/luaobject.cpp
Normal file
47
src/framework/luascript/luaobject.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
#include "luaobject.h"
|
||||
#include "luainterface.h"
|
||||
|
||||
LuaObject::LuaObject() : m_fieldsTableRef(-1)
|
||||
{
|
||||
}
|
||||
|
||||
LuaObject::~LuaObject()
|
||||
{
|
||||
luaReleaseFieldsTable();
|
||||
}
|
||||
|
||||
void LuaObject::luaReleaseFieldsTable()
|
||||
{
|
||||
if(m_fieldsTableRef != -1)
|
||||
g_lua.unref(m_fieldsTableRef);
|
||||
}
|
||||
|
||||
void LuaObject::luaSetField(const std::string& key)
|
||||
{
|
||||
// create fields table on the fly
|
||||
if(m_fieldsTableRef == -1) {
|
||||
g_lua.newTable(); // create fields table
|
||||
m_fieldsTableRef = g_lua.ref(); // save a reference for it
|
||||
}
|
||||
|
||||
g_lua.getRef(m_fieldsTableRef); // push the table
|
||||
g_lua.insert(-2); // move the value to the top
|
||||
g_lua.setField(key); // set the field
|
||||
g_lua.pop(); // pop the fields table
|
||||
}
|
||||
|
||||
void LuaObject::luaGetField(const std::string& key)
|
||||
{
|
||||
if(m_fieldsTableRef != -1) {
|
||||
g_lua.getRef(m_fieldsTableRef); // push the obj's fields table
|
||||
g_lua.getField(key); // push the field value
|
||||
g_lua.remove(-2); // remove the table
|
||||
} else {
|
||||
g_lua.pushNil();
|
||||
}
|
||||
}
|
||||
|
||||
int LuaObject::getUseCount()
|
||||
{
|
||||
return shared_from_this().use_count() - 1;
|
||||
}
|
81
src/framework/luascript/luaobject.h
Normal file
81
src/framework/luascript/luaobject.h
Normal file
@@ -0,0 +1,81 @@
|
||||
#ifndef LUAOBJECT_H
|
||||
#define LUAOBJECT_H
|
||||
|
||||
#include "luadeclarations.h"
|
||||
|
||||
/// LuaObject, all script-able classes have it as base
|
||||
class LuaObject : public std::enable_shared_from_this<LuaObject>
|
||||
{
|
||||
public:
|
||||
LuaObject();
|
||||
virtual ~LuaObject() ;
|
||||
|
||||
/// Calls a function or table of functions stored in a lua field, results are pushed onto the stack,
|
||||
/// if any lua error occurs, it will be reported to stdout and return 0 results
|
||||
/// @return the number of results
|
||||
template<typename... T>
|
||||
int callLuaField(const std::string& field, const T&... args);
|
||||
|
||||
/// Sets a field in this lua object
|
||||
template<typename T>
|
||||
void setLuaField(const std::string& key, const T& value);
|
||||
|
||||
/// Gets a field from this lua object
|
||||
template<typename T>
|
||||
T getLuaField(const std::string& key);
|
||||
|
||||
/// Release fields table reference
|
||||
void luaReleaseFieldsTable();
|
||||
|
||||
/// Sets a field from this lua object, the value must be on the stack
|
||||
void luaSetField(const std::string& key);
|
||||
|
||||
/// Gets a field from this lua object, the result is pushed onto the stack
|
||||
void luaGetField(const std::string& key);
|
||||
|
||||
/// Returns the number of references of this object
|
||||
/// @note each userdata of this object on lua counts as a reference
|
||||
int getUseCount();
|
||||
|
||||
/// Returns the class name used in Lua
|
||||
virtual std::string getLuaObjectName() const {
|
||||
// this could later be cached for more performance
|
||||
return aux::demangle_name(typeid(*this).name());
|
||||
}
|
||||
|
||||
LuaObjectPtr asLuaObject() { return shared_from_this(); }
|
||||
|
||||
private:
|
||||
int m_fieldsTableRef;
|
||||
};
|
||||
|
||||
#include "luainterface.h"
|
||||
|
||||
template<typename... T>
|
||||
int LuaObject::callLuaField(const std::string& field, const T&... args) {
|
||||
// note that the field must be retrieved from this object lua value
|
||||
// to force using the __index metamethod of it's metatable
|
||||
// so cannot use LuaObject::getField here
|
||||
// push field
|
||||
g_lua.pushObject(asLuaObject());
|
||||
g_lua.getField(field);
|
||||
|
||||
// the first argument is always this object (self)
|
||||
g_lua.insert(-2);
|
||||
g_lua.polymorphicPush(args...);
|
||||
return g_lua.protectedCall(1 + sizeof...(args));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void LuaObject::setLuaField(const std::string& key, const T& value) {
|
||||
g_lua.polymorphicPush(value);
|
||||
luaSetField(key);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T LuaObject::getLuaField(const std::string& key) {
|
||||
luaGetField(key);
|
||||
return g_lua.polymorphicPop<T>();
|
||||
}
|
||||
|
||||
#endif
|
195
src/framework/luascript/luavaluecasts.h
Normal file
195
src/framework/luascript/luavaluecasts.h
Normal file
@@ -0,0 +1,195 @@
|
||||
#ifndef LUAVALUECASTS_H
|
||||
#define LUAVALUECASTS_H
|
||||
|
||||
// this file is and must be included only from luainterface.h
|
||||
#include "luainterface.h"
|
||||
#include "luaexception.h"
|
||||
|
||||
/// Pushes bool
|
||||
inline void push_luavalue(bool v) {
|
||||
g_lua.pushBoolean(v);
|
||||
}
|
||||
|
||||
/// Pushes int
|
||||
inline void push_luavalue(int v) {
|
||||
g_lua.pushInteger(v);
|
||||
}
|
||||
|
||||
/// Pushes double
|
||||
inline void push_luavalue(double v) {
|
||||
g_lua.pushNumber(v);
|
||||
}
|
||||
|
||||
/// Pushes std::string
|
||||
inline void push_luavalue(const std::string& v) {
|
||||
g_lua.pushString(v);
|
||||
}
|
||||
|
||||
/// Pushes const char*
|
||||
inline void push_luavalue(const char* v) {
|
||||
g_lua.pushCString(v);
|
||||
}
|
||||
|
||||
/// Pushes LuaCppFunction
|
||||
inline void push_luavalue(const LuaCppFunction& v) {
|
||||
g_lua.pushCppFunction(v);
|
||||
}
|
||||
|
||||
/// Pushes LuaObjectPtr
|
||||
template<class T>
|
||||
typename std::enable_if<std::is_base_of<LuaObject, typename T::element_type>::value, void>::type
|
||||
push_luavalue(const T& v) {
|
||||
if(v)
|
||||
return g_lua.pushObject(v);
|
||||
return g_lua.pushNil();
|
||||
}
|
||||
|
||||
/// Push std::function types
|
||||
template<typename Ret, typename... Args>
|
||||
void push_luavalue(const std::function<Ret(Args...)>& v) {
|
||||
if(v) {
|
||||
LuaCppFunction f = luabinder::bind_fun(v);
|
||||
g_lua.pushCppFunction(f);
|
||||
} else
|
||||
g_lua.pushNil();
|
||||
}
|
||||
|
||||
/// Casts lua value to bool
|
||||
inline bool luavalue_cast(int index, bool& o) {
|
||||
o = g_lua.toBoolean(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Casts lua value to int
|
||||
inline bool luavalue_cast(int index, int& o) {
|
||||
o = g_lua.toInteger(index);
|
||||
if(o == 0 && !g_lua.isNumber(index))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Casts lua value to double
|
||||
inline bool luavalue_cast(int index, double& o) {
|
||||
o = g_lua.toNumber(index);
|
||||
if(o == 0 && !g_lua.isNumber(index))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Casts lua value to std::string
|
||||
inline bool luavalue_cast(int index, std::string& o) {
|
||||
o = g_lua.toString(index);
|
||||
if(o.empty() && !g_lua.isString(index))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Casts lua value to LuaObjectPtr
|
||||
inline bool luavalue_cast(int index, LuaObjectPtr& o) {
|
||||
if(g_lua.isUserdata(index)) {
|
||||
o = g_lua.toObject(index);
|
||||
return true;
|
||||
} else if(g_lua.isNil(index)) {
|
||||
o = nullptr;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Casts lua value to enum
|
||||
template<class T>
|
||||
typename std::enable_if<std::is_enum<T>::value, bool>::type
|
||||
luavalue_cast(int index, T& o) {
|
||||
return luavalue_cast(index, (int&)o);
|
||||
}
|
||||
|
||||
/// Cast lua userdata to a class pointer
|
||||
template<class T>
|
||||
typename std::enable_if<std::is_base_of<LuaObject, T>::value, bool>::type
|
||||
luavalue_cast(int index, T*& o) {
|
||||
LuaObjectPtr obj;
|
||||
if(!luavalue_cast(index, obj))
|
||||
return false;
|
||||
o = std::dynamic_pointer_cast<T>(obj).get();
|
||||
return !!o;
|
||||
}
|
||||
|
||||
/// Cast lua userdata to a class shared pointer
|
||||
template<class T>
|
||||
bool luavalue_cast(int index, std::shared_ptr<T>& o) {
|
||||
LuaObjectPtr obj;
|
||||
if(!luavalue_cast(index, obj))
|
||||
return false;
|
||||
o = std::dynamic_pointer_cast<T>(obj);
|
||||
return !!o;
|
||||
}
|
||||
|
||||
/// Cast a lua function to a std::function
|
||||
template<typename... Args>
|
||||
bool luavalue_cast(int index, std::function<void(Args...)>& o) {
|
||||
if(g_lua.isFunction(index)) {
|
||||
g_lua.pushValue(index);
|
||||
// weak references are used here, this means that the script must hold another reference
|
||||
// to this function, otherwise it will expire
|
||||
int funcWeakRef = g_lua.weakRef();
|
||||
o = [=](Args... args...) {
|
||||
// note that we must catch exceptions, because this lambda can be called from anywhere
|
||||
// and most of them won't catch exceptions (e.g. dispatcher)
|
||||
g_lua.getWeakRef(funcWeakRef);
|
||||
try {
|
||||
if(g_lua.isFunction()) {
|
||||
g_lua.polymorphicPush(args...);
|
||||
assert(g_lua.safeCall(sizeof...(Args)) == 0);
|
||||
} else {
|
||||
throw LuaException("attempt to call an expired lua function from C++,"
|
||||
"did you forget to hold a reference for that function?", 0);
|
||||
}
|
||||
} catch(std::exception& e) {
|
||||
logError(e.what());
|
||||
}
|
||||
};
|
||||
return true;
|
||||
} else if(g_lua.isNil(index)) {
|
||||
o = std::function<void(Args...)>();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Cast a lua function to a std::function that can return
|
||||
template<typename Ret, typename... Args>
|
||||
typename std::enable_if<!std::is_void<Ret>::value, bool>::type
|
||||
luavalue_cast(int index, std::function<Ret(Args...)>& o) {
|
||||
if(g_lua.isFunction(index)) {
|
||||
g_lua.pushValue(index);
|
||||
// weak references are used here, this means that the script must hold another reference
|
||||
// to this function, otherwise it will expire
|
||||
int funcWeakRef = g_lua.weakRef();
|
||||
o = [=](Args... args...) -> Ret {
|
||||
// note that we must catch exceptions, because this lambda can be called from anywhere
|
||||
// and most of them won't catch exceptions (e.g. dispatcher)
|
||||
try {
|
||||
g_lua.getWeakRef(funcWeakRef);
|
||||
if(g_lua.isFunction()) {
|
||||
g_lua.polymorphicPush(args...);
|
||||
if(g_lua.safeCall(sizeof...(Args)) != 1)
|
||||
throw LuaException("a function from lua didn't retrieve the expected number of results", 0);
|
||||
return g_lua.polymorphicPop<Ret>();
|
||||
} else {
|
||||
throw LuaException("attempt to call an expired lua function from C++,"
|
||||
"did you forget to hold a reference for that function?", 0);
|
||||
}
|
||||
} catch(std::exception& e) {
|
||||
logError(e.what());
|
||||
}
|
||||
return Ret();
|
||||
};
|
||||
return true;
|
||||
} else if(g_lua.isNil(index)) {
|
||||
o = std::function<Ret(Args...)>();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
@@ -1,6 +1,6 @@
|
||||
#include "connection.h"
|
||||
|
||||
#include <core/dispatcher.h>
|
||||
#include <core/eventdispatcher.h>
|
||||
|
||||
static asio::io_service ioService;
|
||||
|
||||
@@ -21,7 +21,7 @@ void Connection::connect(const std::string& host, uint16 port, const ConnectCall
|
||||
{
|
||||
m_connectCallback = connectCallback;
|
||||
|
||||
asio::ip::tcp::resolver::query query(host, convert<std::string>(port));
|
||||
asio::ip::tcp::resolver::query query(host, aux::unsafe_cast<std::string>(port));
|
||||
m_resolver.async_resolve(query, std::bind(&Connection::onResolve, shared_from_this(), std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
m_timer.expires_from_now(boost::posix_time::seconds(2));
|
||||
@@ -56,7 +56,7 @@ void Connection::recv(uint16 bytes, uint32 timeout, const RecvCallback& callback
|
||||
void Connection::onTimeout(const boost::system::error_code& error)
|
||||
{
|
||||
if(error != asio::error::operation_aborted)
|
||||
g_dispatcher.addTask(std::bind(m_errorCallback, error));
|
||||
g_dispatcher.addEvent(std::bind(m_errorCallback, error));
|
||||
}
|
||||
|
||||
void Connection::onResolve(const boost::system::error_code& error, asio::ip::tcp::resolver::iterator endpointIterator)
|
||||
@@ -65,7 +65,7 @@ void Connection::onResolve(const boost::system::error_code& error, asio::ip::tcp
|
||||
|
||||
if(error) {
|
||||
if(m_errorCallback)
|
||||
g_dispatcher.addTask(std::bind(m_errorCallback, error));
|
||||
g_dispatcher.addEvent(std::bind(m_errorCallback, error));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -81,12 +81,12 @@ void Connection::onConnect(const boost::system::error_code& error)
|
||||
|
||||
if(error) {
|
||||
if(m_errorCallback)
|
||||
g_dispatcher.addTask(std::bind(m_errorCallback, error));
|
||||
g_dispatcher.addEvent(std::bind(m_errorCallback, error));
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_connectCallback)
|
||||
g_dispatcher.addTask(m_connectCallback);
|
||||
g_dispatcher.addEvent(m_connectCallback);
|
||||
}
|
||||
|
||||
void Connection::onSend(const boost::system::error_code& error, size_t)
|
||||
@@ -95,7 +95,7 @@ void Connection::onSend(const boost::system::error_code& error, size_t)
|
||||
|
||||
if(error) {
|
||||
if(m_errorCallback)
|
||||
g_dispatcher.addTask(std::bind(m_errorCallback, error));
|
||||
g_dispatcher.addEvent(std::bind(m_errorCallback, error));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -106,10 +106,10 @@ void Connection::onRecv(const boost::system::error_code& error)
|
||||
|
||||
if(error) {
|
||||
if(m_errorCallback)
|
||||
g_dispatcher.addTask(std::bind(m_errorCallback, error));
|
||||
g_dispatcher.addEvent(std::bind(m_errorCallback, error));
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_recvCallback)
|
||||
g_dispatcher.addTask(std::bind(m_recvCallback, m_recvBuffer, m_recvSize));
|
||||
g_dispatcher.addEvent(std::bind(m_recvCallback, m_recvBuffer, m_recvSize));
|
||||
}
|
||||
|
@@ -82,7 +82,7 @@ void Protocol::onError(const boost::system::error_code& err)
|
||||
|
||||
// displays a dialog, finish protocol
|
||||
|
||||
callField("onError", message.str());
|
||||
callLuaField("onError", message.str());
|
||||
}
|
||||
|
||||
bool Protocol::xteaDecrypt(InputMessage& inputMessage)
|
||||
|
@@ -5,7 +5,7 @@
|
||||
#include "inputmessage.h"
|
||||
#include "outputmessage.h"
|
||||
|
||||
#include <script/luaobject.h>
|
||||
#include <luascript/luaobject.h>
|
||||
|
||||
class Protocol : public LuaObject
|
||||
{
|
||||
@@ -24,8 +24,6 @@ public:
|
||||
|
||||
ProtocolPtr asProtocol() { return std::static_pointer_cast<Protocol>(shared_from_this()); }
|
||||
|
||||
virtual const char* getLuaTypeName() const { return "Protocol"; }
|
||||
|
||||
protected:
|
||||
uint32 m_xteaKey[4];
|
||||
bool m_checksumEnabled, m_xteaEncryptionEnabled;
|
||||
|
@@ -1,8 +1,8 @@
|
||||
#ifndef OTML_H
|
||||
#define OTML_H
|
||||
|
||||
#include "otmldocument.h"
|
||||
#include "otmlnode.h"
|
||||
#include "otmlemitter.h"
|
||||
#include "otmlparser.h"
|
||||
#include "otmlnodeext.h"
|
||||
|
||||
#endif // OTML_H
|
||||
#endif
|
||||
|
16
src/framework/otml/otmldeclarations.h
Normal file
16
src/framework/otml/otmldeclarations.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef OTMLDECLARATIONS_H
|
||||
#define OTMLDECLARATIONS_H
|
||||
|
||||
#include <global.h>
|
||||
|
||||
class OTMLNode;
|
||||
class OTMLDocument;
|
||||
class OTMLParser;
|
||||
class OTMLEmitter;
|
||||
|
||||
typedef std::shared_ptr<OTMLNode> OTMLNodePtr;
|
||||
typedef std::shared_ptr<OTMLDocument> OTMLDocumentPtr;
|
||||
typedef std::weak_ptr<OTMLNode> OTMLNodeWeakPtr;
|
||||
typedef std::vector<OTMLNodePtr> OTMLNodeList;
|
||||
|
||||
#endif
|
41
src/framework/otml/otmldocument.cpp
Normal file
41
src/framework/otml/otmldocument.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#include "otmldocument.h"
|
||||
#include "otmlparser.h"
|
||||
#include "otmlemitter.h"
|
||||
|
||||
#include <core/resourcemanager.h>
|
||||
|
||||
OTMLDocumentPtr OTMLDocument::create()
|
||||
{
|
||||
OTMLDocumentPtr doc(new OTMLDocument);
|
||||
doc->setTag("doc");
|
||||
return doc;
|
||||
}
|
||||
|
||||
OTMLDocumentPtr OTMLDocument::parse(const std::string& fileName)
|
||||
{
|
||||
std::stringstream fin;
|
||||
g_resources.loadFile(fileName, fin);
|
||||
return parse(fin, fileName);
|
||||
}
|
||||
|
||||
OTMLDocumentPtr OTMLDocument::parse(std::istream& in, const std::string& source)
|
||||
{
|
||||
OTMLDocumentPtr doc(new OTMLDocument);
|
||||
doc->setSource(source);
|
||||
OTMLParser parser(doc, in);
|
||||
parser.parse();
|
||||
return doc;
|
||||
}
|
||||
|
||||
std::string OTMLDocument::emit()
|
||||
{
|
||||
return OTMLEmitter::emitNode(shared_from_this());
|
||||
}
|
||||
|
||||
bool OTMLDocument::save(const std::string& fileName)
|
||||
{
|
||||
setSource(fileName);
|
||||
|
||||
return g_resources.saveFile(fileName, emit());
|
||||
}
|
||||
|
29
src/framework/otml/otmldocument.h
Normal file
29
src/framework/otml/otmldocument.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef OTMLDOCUMENT_H
|
||||
#define OTMLDOCUMENT_H
|
||||
|
||||
#include "otmlnode.h"
|
||||
|
||||
class OTMLDocument : public OTMLNode
|
||||
{
|
||||
public:
|
||||
OTMLDocument() { }
|
||||
virtual ~OTMLDocument() { }
|
||||
|
||||
/// Create a new OTML document for filling it with nodes
|
||||
static OTMLDocumentPtr create();
|
||||
|
||||
/// Parse OTML from a file
|
||||
static OTMLDocumentPtr parse(const std::string& fileName);
|
||||
|
||||
/// Parse OTML from input stream
|
||||
/// @param source is the file name that will be used to show errors messages
|
||||
static OTMLDocumentPtr parse(std::istream& in, const std::string& source);
|
||||
|
||||
/// Emits this document and all it's children to a std::string
|
||||
std::string emit();
|
||||
|
||||
/// Save this document to a file
|
||||
bool save(const std::string& fileName);
|
||||
};
|
||||
|
||||
#endif
|
@@ -1,63 +1,68 @@
|
||||
#include "otmlemitter.h"
|
||||
#include "otmlnode.h"
|
||||
#include "otmldocument.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
OTMLEmitter::OTMLEmitter() :
|
||||
m_rootNode(0)
|
||||
{
|
||||
}
|
||||
|
||||
OTMLEmitter::~OTMLEmitter()
|
||||
{
|
||||
if(m_rootNode)
|
||||
delete m_rootNode;
|
||||
}
|
||||
|
||||
OTMLNode* OTMLEmitter::createDocument()
|
||||
{
|
||||
m_rootNode = new OTMLNode;
|
||||
return m_rootNode;
|
||||
}
|
||||
|
||||
std::string OTMLEmitter::emitDocument()
|
||||
{
|
||||
if(m_rootNode)
|
||||
return emitNode(m_rootNode, 0);
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string OTMLEmitter::emitNodeValue(OTMLNode* node)
|
||||
{
|
||||
std::string value = node->value();
|
||||
if(!value.empty() && (value[0] == '"' || *value.rbegin() == '"'||
|
||||
value[0] == ' ' || *value.rbegin() == ' '||
|
||||
value[0] == '-' || value[0] == '{' || value[0] == '[' || value[0] == '|' ||
|
||||
value.find("\n") != std::string::npos)) {
|
||||
boost::replace_all(value, "\\", "\\\\");
|
||||
boost::replace_all(value, "\"", "\\\"");
|
||||
boost::replace_all(value, "\n", "\\n");
|
||||
value.append("\"");
|
||||
value.insert(0, "\"");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
std::string OTMLEmitter::emitNode(OTMLNode* node, int currentDepth)
|
||||
std::string OTMLEmitter::emitNode(const OTMLNodePtr& node, int currentDepth)
|
||||
{
|
||||
std::stringstream ss;
|
||||
for(int i=1;i<currentDepth;++i)
|
||||
ss << " ";
|
||||
if(currentDepth > 0) {
|
||||
if(node->hasTag())
|
||||
|
||||
// emit nodes
|
||||
if(currentDepth >= 0) {
|
||||
// fill spaces for current depth
|
||||
for(int i=0;i<currentDepth;++i)
|
||||
ss << " ";
|
||||
|
||||
// emit node tag
|
||||
if(node->hasTag()) {
|
||||
ss << node->tag();
|
||||
if(node->hasValue())
|
||||
ss << (node->hasTag() ? ": " : "- ") << emitNodeValue(node);
|
||||
if(!node->hasTag() && !node->hasValue())
|
||||
|
||||
// add ':' to if the node is unique or has value
|
||||
if(node->hasValue() || node->isUnique())
|
||||
ss << ":";
|
||||
} else
|
||||
ss << "-";
|
||||
ss << std::endl;
|
||||
|
||||
// emit node value
|
||||
if(node->hasValue()) {
|
||||
ss << " ";
|
||||
|
||||
std::string value = node->value();
|
||||
|
||||
// emit multiline values
|
||||
if(value.find("\n") != std::string::npos) {
|
||||
if(value[value.length()-1] == '\n' && value[value.length()-2] == '\n')
|
||||
ss << "|+";
|
||||
else if(value[value.length()-1] == '\n')
|
||||
ss << "|";
|
||||
else
|
||||
ss << "|-";
|
||||
|
||||
// multilines
|
||||
for(std::size_t pos = 0; pos < value.length(); ++pos) {
|
||||
ss << "\n";
|
||||
|
||||
// fill spaces for multiline depth
|
||||
for(int i=0;i<currentDepth+1;++i)
|
||||
ss << " ";
|
||||
|
||||
// fill until a new line
|
||||
while(pos < value.length()) {
|
||||
if(value[pos] == '\n')
|
||||
break;
|
||||
ss << value[pos++];
|
||||
}
|
||||
}
|
||||
// emit inline values
|
||||
} else
|
||||
ss << value;
|
||||
}
|
||||
}
|
||||
for(int i=0;i<node->size();++i)
|
||||
|
||||
// emit children
|
||||
for(int i=0;i<node->size();++i) {
|
||||
if(currentDepth >= 0 || i != 0)
|
||||
ss << "\n";
|
||||
ss << emitNode(node->at(i), currentDepth+1);
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
@@ -1,24 +1,13 @@
|
||||
#ifndef OTMLEMITTER_H
|
||||
#define OTMLEMITTER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
class OTMLNode;
|
||||
#include "otmldeclarations.h"
|
||||
|
||||
class OTMLEmitter
|
||||
{
|
||||
public:
|
||||
OTMLEmitter();
|
||||
~OTMLEmitter();
|
||||
|
||||
OTMLNode* createDocument();
|
||||
std::string emitDocument();
|
||||
|
||||
static std::string emitNodeValue(OTMLNode* node);
|
||||
static std::string emitNode(OTMLNode* node, int currentDepth = 0);
|
||||
|
||||
private:
|
||||
OTMLNode* m_rootNode;
|
||||
/// Emits a node and it's children to a std::string
|
||||
static std::string emitNode(const OTMLNodePtr& node, int currentDepth = -1);
|
||||
};
|
||||
|
||||
#endif // OTMLEMITTER_H
|
||||
#endif
|
||||
|
25
src/framework/otml/otmlexception.cpp
Normal file
25
src/framework/otml/otmlexception.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include "otmlexception.h"
|
||||
#include "otmldocument.h"
|
||||
|
||||
OTMLException::OTMLException(const OTMLNodePtr& node, const std::string& error)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "OTML error";
|
||||
if(!node->source().empty())
|
||||
ss << " in '" << node->source() << "'";
|
||||
ss << ": " << error;
|
||||
m_what = ss.str();
|
||||
}
|
||||
|
||||
OTMLException::OTMLException(const OTMLDocumentPtr& doc, const std::string& error, int line)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "OTML error";
|
||||
if(doc && !doc->source().empty()) {
|
||||
ss << " in '" << doc->source() << "'";
|
||||
if(line >= 0)
|
||||
ss << " at line " << line;
|
||||
}
|
||||
ss << ": " << error;
|
||||
m_what = ss.str();
|
||||
}
|
23
src/framework/otml/otmlexception.h
Normal file
23
src/framework/otml/otmlexception.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef OTMLEXCEPTION_H
|
||||
#define OTMLEXCEPTION_H
|
||||
|
||||
#include "otmldeclarations.h"
|
||||
|
||||
/// All OTML errors throw this exception
|
||||
class OTMLException : public std::exception
|
||||
{
|
||||
public:
|
||||
OTMLException(const OTMLNodePtr& node, const std::string& error);
|
||||
OTMLException(const OTMLDocumentPtr& doc, const std::string& error, int line = -1);
|
||||
virtual ~OTMLException() throw() { };
|
||||
|
||||
virtual const char* what() const throw() { return m_what.c_str(); }
|
||||
|
||||
protected:
|
||||
OTMLException() { }
|
||||
void generateErrorMessage(const OTMLDocumentPtr& doc, const std::string& error, int line);
|
||||
void generateErrorMessage(const OTMLNodePtr& node, const std::string& error);
|
||||
std::string m_what;
|
||||
};
|
||||
|
||||
#endif
|
@@ -1,93 +1,225 @@
|
||||
#include "otmlnode.h"
|
||||
#include "otmlemitter.h"
|
||||
#include "otmldocument.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
OTMLNode::OTMLNode(std::string what) :
|
||||
m_parent(0), m_line(0), m_what(what)
|
||||
OTMLNode::OTMLNode()
|
||||
{
|
||||
m_unique = false;
|
||||
}
|
||||
|
||||
OTMLNode::~OTMLNode()
|
||||
std::string OTMLNode::tag() const
|
||||
{
|
||||
for(int i=0;i<size();++i)
|
||||
delete at(i);
|
||||
return m_tag;
|
||||
}
|
||||
|
||||
OTMLNode* OTMLNode::at(const std::string& childTag) const {
|
||||
int i=0;
|
||||
while(i<size() && at(i)->tag()!=childTag)
|
||||
++i;
|
||||
return at(i);
|
||||
std::string OTMLNode::value() const
|
||||
{
|
||||
// ~ is an alias for no value
|
||||
if(m_value == "~")
|
||||
return aux::empty_string;
|
||||
return m_value;
|
||||
}
|
||||
|
||||
OTMLNode* OTMLNode::at(int pos) const
|
||||
int OTMLNode::size() const
|
||||
{
|
||||
if(pos < (int)m_children.size() && pos >= 0)
|
||||
return m_children[pos];
|
||||
return 0;
|
||||
return m_childNodes.size();
|
||||
}
|
||||
|
||||
OTMLNode* OTMLNode::atPath(const std::string& path) const
|
||||
OTMLNodePtr OTMLNode::parent() const
|
||||
{
|
||||
std::vector<std::string> nodeTags;
|
||||
OTMLNode* node = const_cast<OTMLNode*>(this);
|
||||
std::string shortcutKey;
|
||||
return m_parent.lock();
|
||||
}
|
||||
|
||||
boost::split(nodeTags, path, boost::is_any_of(std::string("/")));
|
||||
foreach(std::string& stag, nodeTags) {
|
||||
if(!shortcutKey.empty())
|
||||
shortcutKey += '.';
|
||||
shortcutKey += stag;
|
||||
if(node)
|
||||
node = node->at(stag);
|
||||
const OTMLNodeList& OTMLNode::childNodes() const
|
||||
{
|
||||
return m_childNodes;
|
||||
}
|
||||
|
||||
std::string OTMLNode::source() const
|
||||
{
|
||||
return m_source;
|
||||
}
|
||||
|
||||
bool OTMLNode::hasTag() const
|
||||
{
|
||||
return !m_tag.empty();
|
||||
}
|
||||
|
||||
bool OTMLNode::hasValue() const
|
||||
{
|
||||
return (!m_value.empty() && m_value != "~");
|
||||
}
|
||||
|
||||
bool OTMLNode::hasChildNodes() const
|
||||
{
|
||||
return size() > 0;
|
||||
}
|
||||
|
||||
bool OTMLNode::hasChild(const std::string& childTag) const
|
||||
{
|
||||
return !!get(childTag);
|
||||
}
|
||||
|
||||
bool OTMLNode::hasChild(int index) const
|
||||
{
|
||||
return !!get(index);
|
||||
}
|
||||
|
||||
bool OTMLNode::isUnique() const
|
||||
{
|
||||
return m_unique;
|
||||
}
|
||||
|
||||
void OTMLNode::setTag(std::string tag)
|
||||
{
|
||||
m_tag = tag;
|
||||
|
||||
// valued nodes that has tags are always unique
|
||||
if(!m_value.empty() && hasTag())
|
||||
setUnique();
|
||||
}
|
||||
|
||||
void OTMLNode::setValue(const std::string& value)
|
||||
{
|
||||
m_value = value;
|
||||
|
||||
// valued nodes that has tags are always unique
|
||||
if(!m_value.empty() && hasTag())
|
||||
setUnique();
|
||||
}
|
||||
|
||||
void OTMLNode::setParent(const OTMLNodePtr& parent)
|
||||
{
|
||||
m_parent = parent;
|
||||
}
|
||||
|
||||
void OTMLNode::setUnique(bool unique)
|
||||
{
|
||||
m_unique = unique;
|
||||
}
|
||||
|
||||
void OTMLNode::setSource(const std::string& source)
|
||||
{
|
||||
m_source = source;
|
||||
}
|
||||
|
||||
OTMLNodePtr OTMLNode::at(const std::string& childTag)
|
||||
{
|
||||
for(const OTMLNodePtr& child : m_childNodes) {
|
||||
if(child->tag() == childTag)
|
||||
return child;
|
||||
}
|
||||
throw OTMLException(shared_from_this(), aux::make_string("child node with tag '", childTag, "' not found"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OTMLNodePtr OTMLNode::at(int childIndex)
|
||||
{
|
||||
if(childIndex < size() && childIndex >= 0)
|
||||
return m_childNodes[childIndex];
|
||||
throw OTMLException(shared_from_this(), aux::make_string("child node at index '", childIndex, "' not found"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OTMLNodePtr OTMLNode::get(const std::string& childTag) const
|
||||
{
|
||||
for(const OTMLNodePtr& child : m_childNodes) {
|
||||
if(child->tag() == childTag)
|
||||
return child;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OTMLNodePtr OTMLNode::get(int childIndex) const
|
||||
{
|
||||
if(childIndex < size() && childIndex >= 0)
|
||||
return m_childNodes[childIndex];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void OTMLNode::addChild(const OTMLNodePtr& newChild)
|
||||
{
|
||||
// replace is needed when the tag is marked as unique
|
||||
if(newChild->hasTag()) {
|
||||
for(OTMLNodePtr node : m_childNodes) {
|
||||
if(node->tag() == newChild->tag() && (node->isUnique() || newChild->isUnique())) {
|
||||
newChild->setUnique();
|
||||
replaceChild(node, newChild);
|
||||
|
||||
// remove any other child with the same tag
|
||||
auto it = m_childNodes.begin();
|
||||
while(it != m_childNodes.end()) {
|
||||
OTMLNodePtr node = (*it);
|
||||
if(node != newChild && node->tag() == newChild->tag()) {
|
||||
node->setParent(nullptr);
|
||||
it = m_childNodes.erase(it);
|
||||
} else
|
||||
++it;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(node)
|
||||
return node;
|
||||
else
|
||||
return at(shortcutKey);
|
||||
m_childNodes.push_back(newChild);
|
||||
newChild->setParent(shared_from_this());
|
||||
}
|
||||
|
||||
OTMLNode* OTMLNode::createNode(std::string tag)
|
||||
bool OTMLNode::removeChild(const OTMLNodePtr& oldChild)
|
||||
{
|
||||
OTMLNode* node = new OTMLNode;
|
||||
node->setTag(tag);
|
||||
addNode(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
void OTMLNode::addNode(OTMLNode* node) {
|
||||
if(node->hasTag() && node->hasValue())
|
||||
if(OTMLNode* other = at(node->tag()))
|
||||
removeNode(other);
|
||||
m_children.push_back(node);
|
||||
node->setParent(this);
|
||||
}
|
||||
|
||||
bool OTMLNode::removeNode(OTMLNode* node) {
|
||||
for(NodeList::iterator it = m_children.begin(); it != m_children.end(); ++it) {
|
||||
if((*it) == node) {
|
||||
m_children.erase(it);
|
||||
for(auto it = m_childNodes.begin(); it != m_childNodes.end(); ++it) {
|
||||
if((*it) == oldChild) {
|
||||
m_childNodes.erase(it);
|
||||
oldChild->setParent(nullptr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string OTMLNode::generateErrorMessage(const std::string& message) const {
|
||||
std::stringstream ss;
|
||||
ss << "OTML error";
|
||||
if(!what().empty())
|
||||
ss << " in '" << what() << "'";
|
||||
if(m_line > 0)
|
||||
ss << " at line " << m_line;
|
||||
if(m_line > 0 && hasTag())
|
||||
ss << ", in node '" << tag() << "'";
|
||||
ss << ": " << message;
|
||||
return ss.str();
|
||||
bool OTMLNode::replaceChild(const OTMLNodePtr& oldChild, const OTMLNodePtr& newChild)
|
||||
{
|
||||
for(auto it = m_childNodes.begin(); it != m_childNodes.end(); ++it) {
|
||||
if((*it) == oldChild) {
|
||||
oldChild->setParent(nullptr);
|
||||
newChild->setParent(shared_from_this());
|
||||
it = m_childNodes.erase(it);
|
||||
m_childNodes.insert(it, newChild);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void OTMLNode::throwError(const std::string& message) const
|
||||
void OTMLNode::clear()
|
||||
{
|
||||
throw OTMLException(generateErrorMessage(message));
|
||||
m_childNodes.clear();
|
||||
}
|
||||
|
||||
void OTMLNode::merge(const OTMLNodePtr& node)
|
||||
{
|
||||
for(const OTMLNodePtr& child : node->childNodes()) {
|
||||
OTMLNodePtr newNode(new OTMLNode);
|
||||
newNode->setUnique(child->isUnique());
|
||||
newNode->setTag(child->tag());
|
||||
newNode->setValue(child->value());
|
||||
addChild(newNode);
|
||||
newNode->merge(child);
|
||||
}
|
||||
}
|
||||
|
||||
OTMLNodePtr OTMLNode::clone() const
|
||||
{
|
||||
OTMLNodePtr myClone(new OTMLNode);
|
||||
myClone->setTag(tag());
|
||||
myClone->setValue(value());
|
||||
myClone->setUnique(isUnique());
|
||||
for(OTMLNodePtr child : childNodes())
|
||||
myClone->addChild(child->clone());
|
||||
return myClone;
|
||||
}
|
||||
|
||||
std::string OTMLNode::emit()
|
||||
{
|
||||
return OTMLEmitter::emitNode(shared_from_this(), 0);
|
||||
}
|
||||
|
@@ -1,260 +1,215 @@
|
||||
#ifndef OTMLNODE_H
|
||||
#define OTMLNODE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <typeinfo>
|
||||
#include "otmldeclarations.h"
|
||||
#include "otmlexception.h"
|
||||
|
||||
#include <util/foreach.h>
|
||||
#include <util/makestring.h>
|
||||
#include <util/convert.h>
|
||||
|
||||
class OTMLException : public std::runtime_error {
|
||||
public:
|
||||
OTMLException(const std::string& what) : std::runtime_error(what) {}
|
||||
};
|
||||
|
||||
class OTMLNode
|
||||
class OTMLNode : public std::enable_shared_from_this<OTMLNode>
|
||||
{
|
||||
public:
|
||||
typedef std::vector<OTMLNode*> NodeList;
|
||||
typedef NodeList::iterator iterator;
|
||||
typedef NodeList::const_iterator const_iterator;
|
||||
OTMLNode();
|
||||
virtual ~OTMLNode() { }
|
||||
|
||||
OTMLNode(std::string what = "");
|
||||
~OTMLNode();
|
||||
std::string value() const;
|
||||
std::string tag() const;
|
||||
int size() const;
|
||||
OTMLNodePtr parent() const;
|
||||
const OTMLNodeList& childNodes() const;
|
||||
std::string source() const;
|
||||
|
||||
bool hasTag() const { return !m_tag.empty(); }
|
||||
bool hasChildren() const { return size() > 0; }
|
||||
bool hasValue() const { return !m_value.empty(); }
|
||||
bool hasChild(const std::string ctag) const { return at(ctag) != 0; }
|
||||
bool hasTag() const;
|
||||
bool hasValue() const;
|
||||
bool hasChildNodes() const;
|
||||
bool hasChild(const std::string& childTag) const;
|
||||
bool hasChild(int index) const;
|
||||
bool isUnique() const;
|
||||
|
||||
void setTag(std::string tag) { m_tag = tag; }
|
||||
void setLine(int line) { m_line = line; }
|
||||
void setValue(const std::string& value) { m_value = value; }
|
||||
void setParent(OTMLNode* parent) { m_parent = parent; }
|
||||
void setTag(std::string tag);
|
||||
void setValue(const std::string& value);
|
||||
void setParent(const OTMLNodePtr& parent);
|
||||
void setUnique(bool unique = true);
|
||||
void setSource(const std::string& source);
|
||||
|
||||
std::string tag() const { return m_tag; }
|
||||
int line() const { return m_line; }
|
||||
int size() const { return m_children.size(); }
|
||||
OTMLNode* parent() { return m_parent; }
|
||||
std::string what() const { return (m_parent ? m_parent->what() : m_what); }
|
||||
/// Same as get but if the child node doesn't exist throws an OTMLException
|
||||
OTMLNodePtr at(const std::string& childTag);
|
||||
OTMLNodePtr at(int childIndex);
|
||||
|
||||
iterator begin() { return m_children.begin(); }
|
||||
iterator end() { return m_children.end(); }
|
||||
const_iterator begin() const { return m_children.begin(); }
|
||||
const_iterator end() const { return m_children.end(); }
|
||||
/// Get a child node, if doesn't exists returns nullptr
|
||||
OTMLNodePtr get(const std::string& childTag) const;
|
||||
OTMLNodePtr get(int childIndex) const;
|
||||
|
||||
OTMLNode* front() const { return at(0); }
|
||||
OTMLNode* back() const { return at(size()-1); }
|
||||
void addChild(const OTMLNodePtr& newChild);
|
||||
bool removeChild(const OTMLNodePtr& oldChild);
|
||||
bool replaceChild(const OTMLNodePtr& oldChild, const OTMLNodePtr& newChild);
|
||||
|
||||
OTMLNode* at(const std::string& ctag) const;
|
||||
OTMLNode* at(int pos) const;
|
||||
OTMLNode *atPath(const std::string& path) const;
|
||||
/// Remove all children
|
||||
void clear();
|
||||
|
||||
OTMLNode* createNode(std::string tag = "");
|
||||
void addNode(OTMLNode* node);
|
||||
bool removeNode(OTMLNode* node);
|
||||
/// Recursively copy children from another node to this node
|
||||
void merge(const OTMLNodePtr& node);
|
||||
|
||||
std::string generateErrorMessage(const std::string& message) const;
|
||||
void throwError(const std::string& message) const;
|
||||
/// Recursively clone this node into a new one
|
||||
OTMLNodePtr clone() const;
|
||||
|
||||
std::string value(const std::string& def = "") const { return (m_value.empty() ? def : m_value); }
|
||||
std::string valueAt(const std::string ctag, const std::string& def = "") const {
|
||||
OTMLNode* c = at(ctag);
|
||||
return (c ? c->value() : def);
|
||||
}
|
||||
std::string valueAt(int pos, const std::string& def = "") const {
|
||||
OTMLNode* n = at(pos);
|
||||
return (n ? n->value() : def);
|
||||
}
|
||||
std::string valueAtPath(const std::string path, const std::string& def = "") const {
|
||||
OTMLNode* c = atPath(path);
|
||||
return (c ? c->value() : def);
|
||||
}
|
||||
/// Emits this node to a std::string
|
||||
virtual std::string emit();
|
||||
|
||||
// read into memory
|
||||
template <typename T>
|
||||
void read(T* v) const {
|
||||
if(!(*this >> *v))
|
||||
throwError(make_string("failed to cast node value to type ", std::string(typeid(T).name())));
|
||||
}
|
||||
template<typename T>
|
||||
T read();
|
||||
|
||||
template <typename T>
|
||||
bool readAt(const std::string& ctag, T* v) const {
|
||||
if(OTMLNode* node = at(ctag)) {
|
||||
node->read<T>(v);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
template<typename T>
|
||||
T read(const T& def);
|
||||
|
||||
template <typename T>
|
||||
bool readAt(int pos, T* v) const {
|
||||
if(OTMLNode* node = at(pos)) {
|
||||
node->read<T>(v);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
template<typename T, typename U>
|
||||
T readAt(const U& childIdentifier);
|
||||
|
||||
template <typename T>
|
||||
bool readAtPath(const std::string& ctag, T* v) const {
|
||||
if(OTMLNode* node = atPath(ctag)) {
|
||||
node->read<T>(v);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
template<typename T, typename U>
|
||||
T readAt(const U& childIdentifier, const T& def);
|
||||
|
||||
// read returning the result
|
||||
template <typename T>
|
||||
T read() const { T v; read<T>(&v); return v;}
|
||||
template<typename T>
|
||||
void write(const T& v);
|
||||
|
||||
template <typename T>
|
||||
T readAt(const std::string& ctag) const {
|
||||
T v;
|
||||
if(!readAt(ctag, &v))
|
||||
throwError(make_string("child node \'", ctag, "\' not found"));
|
||||
return v;
|
||||
}
|
||||
template<typename T>
|
||||
void writeAt(const std::string& childTag, const T& v);
|
||||
|
||||
template <typename T>
|
||||
T readAt(int pos) const {
|
||||
T v;
|
||||
if(!readAt(pos, &v))
|
||||
throwError(make_string("child node at pos ", pos, " not found"));
|
||||
return v;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T readAtPath(const std::string& ctag) const {
|
||||
T v;
|
||||
if(!readAtPath(ctag, &v))
|
||||
throwError(make_string("child node in path \'", ctag, "\' not found"));
|
||||
return v;
|
||||
}
|
||||
|
||||
// read with default supplied
|
||||
template <typename T>
|
||||
T readAt(const std::string& ctag, const T& def) const {
|
||||
OTMLNode* c = at(ctag);
|
||||
return (c ? c->read<T>() : def);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T readAt(int pos, const T& def) const {
|
||||
OTMLNode* c = at(pos);
|
||||
return (c ? c->read<T>() : def);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T readAtPath(const std::string& path, const T& def) const {
|
||||
OTMLNode* c = atPath(path);
|
||||
return (c ? c->read<T>() : def);
|
||||
}
|
||||
|
||||
// writing
|
||||
template <typename T>
|
||||
void write(T v) {
|
||||
if(!(*this << v))
|
||||
throwError(make_string("failed to cast to string node value of type ", typeid(T).name()));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void writeIn(int pos, T v) {
|
||||
OTMLNode* c;
|
||||
while(!at(pos))
|
||||
c = createNode();
|
||||
c->write<T>(v);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void writeIn(const std::string& ctag, T v) {
|
||||
OTMLNode* c = at(ctag);
|
||||
if(!c)
|
||||
c = createNode(ctag);
|
||||
c->write<T>(v);
|
||||
}
|
||||
template<typename T>
|
||||
void writeIn(const T& v);
|
||||
|
||||
private:
|
||||
OTMLNode* m_parent;
|
||||
int m_line;
|
||||
std::string m_what;
|
||||
NodeList m_children;
|
||||
std::string m_tag;
|
||||
std::string m_value;
|
||||
std::string m_source;
|
||||
bool m_unique;
|
||||
OTMLNodeList m_childNodes;
|
||||
OTMLNodeWeakPtr m_parent;
|
||||
};
|
||||
|
||||
// read operators
|
||||
template <typename T>
|
||||
bool operator >> (const OTMLNode& node, T& v) { return safe_convert(node.value(), v); }
|
||||
// templates for reading values
|
||||
template<typename T>
|
||||
T OTMLNode::read() {
|
||||
T v;
|
||||
if(!from_otmlnode(shared_from_this(), v))
|
||||
throw OTMLException(shared_from_this(),
|
||||
aux::make_string("failed to cast node value to type '", aux::demangle_type<T>(), "'"));
|
||||
return v;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator >> (const OTMLNode& node, std::vector<T>& v) {
|
||||
v.resize(node.size());
|
||||
for(unsigned i=0;i<node.size();++i)
|
||||
v[i] = node.readAt<T>(i);
|
||||
template<typename T>
|
||||
T OTMLNode::read(const T& def) {
|
||||
if(hasValue())
|
||||
return read<T>();
|
||||
return def;
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
T OTMLNode::readAt(const U& childIdentifier) {
|
||||
OTMLNodePtr child = at(childIdentifier);
|
||||
return child->read<T>();
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
T OTMLNode::readAt(const U& childIdentifier, const T& def) {
|
||||
OTMLNodePtr child = get(childIdentifier);
|
||||
if(!child)
|
||||
return def;
|
||||
return child->read<T>(def);
|
||||
}
|
||||
|
||||
|
||||
// templates for writing values
|
||||
template<typename T>
|
||||
void OTMLNode::write(const T& v) {
|
||||
to_otmlnode(shared_from_this(), v);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void OTMLNode::writeAt(const std::string& childTag, const T& v) {
|
||||
OTMLNodePtr child = get(childTag);
|
||||
bool created = false;
|
||||
if(!child) {
|
||||
child = OTMLNodePtr(new OTMLNode);
|
||||
child->setTag(childTag);
|
||||
child->setUnique();
|
||||
created = true;
|
||||
}
|
||||
child->write<T>(v);
|
||||
if(created)
|
||||
addChild(child);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void OTMLNode::writeIn(const T& v) {
|
||||
OTMLNodePtr child = OTMLNodePtr(new OTMLNode);
|
||||
child->write<T>(v);
|
||||
addChild(child);
|
||||
}
|
||||
|
||||
// templates for casting a node to another type
|
||||
template<typename T>
|
||||
bool from_otmlnode(OTMLNodePtr node, T& v) {
|
||||
return aux::cast(node->value(), v);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool from_otmlnode(OTMLNodePtr node, std::vector<T>& v) {
|
||||
v.resize(node->size());
|
||||
for(unsigned i=0;i<node->size();++i)
|
||||
v[i] = node->readAt<T>(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator >> (const OTMLNode& node, std::list<T>& v) {
|
||||
for(unsigned i=0;i<node.size();++i)
|
||||
v.push_back(node.readAt<T>(i));
|
||||
template<typename T>
|
||||
bool from_otmlnode(OTMLNodePtr node, std::list<T>& v) {
|
||||
for(unsigned i=0;i<node->size();++i)
|
||||
v.push_back(node->readAt<T>(i));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename K, typename T>
|
||||
bool operator >> (const OTMLNode& node, std::map<K, T>& m) {
|
||||
for(int i=0;i<node.size();++i) {
|
||||
bool from_otmlnode(OTMLNodePtr node, std::map<K, T>& m) {
|
||||
for(int i=0;i<node->size();++i) {
|
||||
K k;
|
||||
if(!safe_convert(node.at(i)->tag(), k))
|
||||
if(!aux::cast(node->at(i)->tag(), k))
|
||||
return false;
|
||||
m[k] = node.at(i)->read<T>();
|
||||
m[k] = node->at(i)->read<T>();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// write operators
|
||||
template <typename T>
|
||||
bool operator << (OTMLNode& node, const T& v) {
|
||||
std::string out;
|
||||
if(!safe_convert(v, out))
|
||||
return false;
|
||||
node.setValue(out);
|
||||
return true;
|
||||
// templates for casting a type to a node
|
||||
template<typename T>
|
||||
void to_otmlnode(OTMLNodePtr node, const T& v) {
|
||||
node->setValue(aux::unsafe_cast<std::string>(v));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator << (OTMLNode& node, const std::vector<T>& v) {
|
||||
for(unsigned i=0;i<v.size();++i)
|
||||
node.createNode()->write(v[i]);
|
||||
return true;
|
||||
template<typename T>
|
||||
void to_otmlnode(OTMLNodePtr node, const std::vector<T>& v) {
|
||||
for(unsigned i=0;i<v.size();++i) {
|
||||
OTMLNodePtr newNode(new OTMLNode);
|
||||
newNode->write(v[i]);
|
||||
node->addChild(newNode);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator << (OTMLNode& node, const std::list<T>& v) {
|
||||
for(unsigned i=0;i<v.size();++i)
|
||||
node.createNode()->write(v[i]);
|
||||
return true;
|
||||
template<typename T>
|
||||
void to_otmlnode(OTMLNodePtr node, const std::list<T>& v) {
|
||||
for(unsigned i=0;i<v.size();++i) {
|
||||
OTMLNodePtr newNode(new OTMLNode);
|
||||
newNode->write(v[i]);
|
||||
node->addChild(newNode);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename K, typename T>
|
||||
bool operator << (OTMLNode& node, const std::map<K, T>& m) {
|
||||
typename std::map<K, T>::const_iterator it;
|
||||
for(it = m.begin(); it != m.end(); ++it) {
|
||||
std::string k;
|
||||
if(!safe_convert(it->first, k))
|
||||
return false;
|
||||
node.createNode(k)->write(it->second);
|
||||
void to_otmlnode(OTMLNodePtr node, const std::map<K, T>& m) {
|
||||
for(auto it = m.begin(); it != m.end(); ++it) {
|
||||
std::string k = aux::unsafe_cast<std::string>(it->first);
|
||||
OTMLNodePtr newNode(new OTMLNode);
|
||||
newNode->setTag(k);
|
||||
newNode->setUnique();
|
||||
newNode->write(it->second);
|
||||
node->addChild(newNode);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#include "otmlnodeext.h"
|
||||
|
||||
#endif // OTMLNODE_H
|
||||
#endif
|
||||
|
@@ -1,27 +1,3 @@
|
||||
/* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 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 OTMLNODEEXT_H
|
||||
#define OTMLNODEEXT_H
|
||||
|
||||
@@ -30,55 +6,41 @@
|
||||
#include <util/rect.h>
|
||||
#include <util/size.h>
|
||||
|
||||
inline bool operator>>(const OTMLNode& node, Color& color)
|
||||
{
|
||||
int r, g, b, a;
|
||||
if(node.readAt(0, &r) &&
|
||||
node.readAt(1, &g) &&
|
||||
node.readAt(2, &b)) {
|
||||
a = 255;
|
||||
node.readAt(3, &a);
|
||||
color.setRGBA(r,g,b,a);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//inline bool from_otmlnode(const OTMLNodePtr& node, Color& color)
|
||||
//{
|
||||
//int r, g, b, a;
|
||||
//r = node->readAt<int>(0);
|
||||
//g = node->readAt<int>(1);
|
||||
//b = node->readAt<int>(2);
|
||||
//a = 255;
|
||||
//if(node->hasChild(3))
|
||||
//a = node->readAt<int>(3);
|
||||
//return true;
|
||||
//}
|
||||
|
||||
template <class T>
|
||||
inline bool operator>>(const OTMLNode& node, TPoint<T>& point)
|
||||
{
|
||||
T x, y;
|
||||
if(node.readAt(0, &x) && node.readAt(1, &y)) {
|
||||
point.x = x;
|
||||
point.y = y;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//template <class T>
|
||||
//bool from_otmlnode(const OTMLNodePtr& node, TPoint<T>& point)
|
||||
//{
|
||||
//point.x = node->readAt<T>(0);
|
||||
//point.y = node->readAt<T>(1);
|
||||
//return true;
|
||||
//}
|
||||
|
||||
template <class T>
|
||||
inline bool operator>>(const OTMLNode& node, TSize<T>& size)
|
||||
{
|
||||
T w, h;
|
||||
if(node.readAt(0, &w) && node.readAt(1, &h)) {
|
||||
size.setSize(w, h);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//template <class T>
|
||||
//bool from_otmlnode(const OTMLNodePtr& node, TSize<T>& size)
|
||||
//{
|
||||
//size.setSize(node->readAt<T>(0), node->readAt<T>(1));
|
||||
//return true;
|
||||
//}
|
||||
|
||||
template <class T>
|
||||
inline bool operator>>(const OTMLNode& node, TRect<T>& rect)
|
||||
{
|
||||
T x, y, width, height;
|
||||
if(node.readAt(0, &x) &&
|
||||
node.readAt(1, &y) &&
|
||||
node.readAt(2, &width) &&
|
||||
node.readAt(3, &height)) {
|
||||
rect.setRect(x, y, width, height);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//template <class T>
|
||||
//bool from_otmlnode(const OTMLNodePtr& node, TRect<T>& rect)
|
||||
//{
|
||||
//rect.setRect(node->readAt<int>(0),
|
||||
//node->readAt<int>(1),
|
||||
//node->readAt<int>(2),
|
||||
//node->readAt<int>(3));
|
||||
//return true;
|
||||
//}
|
||||
|
||||
#endif // OTMLNODEEXT_H
|
||||
#endif
|
||||
|
@@ -1,259 +1,160 @@
|
||||
#include "otmlparser.h"
|
||||
#include "otmlnode.h"
|
||||
#include "otmldocument.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
OTMLParser::OTMLParser(std::istream& in, std::string what) :
|
||||
m_currentDepth(0), m_currentLine(0),
|
||||
m_rootNode(new OTMLNode(what)), m_currentParent(m_rootNode), m_previousNode(0),
|
||||
m_in(in)
|
||||
OTMLParser::OTMLParser(OTMLDocumentPtr doc, std::istream& in) :
|
||||
currentDepth(0), currentLine(0),
|
||||
doc(doc), currentParent(doc), previousNode(0),
|
||||
in(in)
|
||||
{
|
||||
parse();
|
||||
}
|
||||
|
||||
OTMLParser::~OTMLParser()
|
||||
{
|
||||
delete m_rootNode;
|
||||
}
|
||||
|
||||
void OTMLParser::throwError(const std::string& message, int line)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "OTML syntax error";
|
||||
if(!what().empty())
|
||||
ss << " in '" << what() << "'";
|
||||
if(line > 0)
|
||||
ss << " at line " << line;
|
||||
ss << ": " << message;
|
||||
throw OTMLException(ss.str());
|
||||
}
|
||||
|
||||
void OTMLParser::parse()
|
||||
{
|
||||
m_rootNode->setTag("document");
|
||||
if(!in.good())
|
||||
throw OTMLException(doc, "cannot read from input stream");
|
||||
|
||||
while(m_in.good() && !m_in.eof()) {
|
||||
m_currentLine++;
|
||||
std::string line;
|
||||
std::getline(m_in, line);
|
||||
parseLine(line);
|
||||
while(!in.eof())
|
||||
parseLine(getNextLine());
|
||||
}
|
||||
|
||||
std::string OTMLParser::getNextLine()
|
||||
{
|
||||
currentLine++;
|
||||
std::string line;
|
||||
std::getline(in, line);
|
||||
return line;
|
||||
}
|
||||
|
||||
int OTMLParser::getLineDepth(const std::string& line, bool multilining)
|
||||
{
|
||||
// count number of spaces at the line beginning
|
||||
std::size_t spaces = 0;
|
||||
while(line[spaces] == ' ')
|
||||
spaces++;
|
||||
|
||||
// pre calculate depth
|
||||
int depth = spaces / 2;
|
||||
|
||||
if(!multilining || depth <= currentDepth) {
|
||||
// check the next character is a tab
|
||||
if(line[spaces] == '\t')
|
||||
throw OTMLException(doc, "indentation with tabs are not allowed", currentLine);
|
||||
|
||||
// must indent every 2 spaces
|
||||
if(spaces % 2 != 0)
|
||||
throw OTMLException(doc, "must indent every 2 spaces", currentLine);
|
||||
}
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
void OTMLParser::parseLine(std::string line)
|
||||
{
|
||||
// calculate depth
|
||||
std::size_t numSpaces = line.find_first_not_of(' ');
|
||||
int depth = getLineDepth(line);
|
||||
|
||||
// trim left whitespaces
|
||||
boost::trim_left(line);
|
||||
// remove line sides spaces
|
||||
boost::trim(line);
|
||||
|
||||
// skip comment or empty lines
|
||||
if(line[0] == '#' || line.empty())
|
||||
// skip empty lines
|
||||
if(line.empty())
|
||||
return;
|
||||
|
||||
// calculate depth
|
||||
int depth = 0;
|
||||
if(numSpaces != std::string::npos)
|
||||
depth = numSpaces / 2;
|
||||
|
||||
// check for syntax error
|
||||
if(numSpaces != std::string::npos && numSpaces % 2 != 0)
|
||||
throwError("file must be idented every 2 whitespaces", m_currentLine);
|
||||
// skip comments
|
||||
if(boost::starts_with(line, "//"))
|
||||
return;
|
||||
|
||||
// a depth above, change current parent to the previous added node
|
||||
if(depth == m_currentDepth+1) {
|
||||
m_currentParent = m_previousNode;
|
||||
// a depth below, change parent to previus parent
|
||||
} else if(depth < m_currentDepth) {
|
||||
for(int i=0;i<m_currentDepth-depth;++i)
|
||||
m_currentParent = m_currentParent->parent();
|
||||
// else if it isn't the current depth it's a syntax error
|
||||
} else if(depth != m_currentDepth) {
|
||||
throwError("invalid indentation level", m_currentLine);
|
||||
}
|
||||
if(depth == currentDepth+1) {
|
||||
currentParent = previousNode;
|
||||
// a depth below, change parent to previous parent
|
||||
} else if(depth < currentDepth) {
|
||||
for(int i=0;i<currentDepth-depth;++i)
|
||||
currentParent = currentParent->parent();
|
||||
// if it isn't the current depth, it's a syntax error
|
||||
} else if(depth != currentDepth)
|
||||
throw OTMLException(doc, "invalid indentation depth, are you indenting correctly?", currentLine);
|
||||
|
||||
// update current depth
|
||||
m_currentDepth = depth;
|
||||
// sets current depth
|
||||
currentDepth = depth;
|
||||
|
||||
// add node
|
||||
OTMLNode* node = m_currentParent->createNode();
|
||||
m_previousNode = node;
|
||||
parseNode(node, line);
|
||||
// alright, new depth is set, the line is not empty and it isn't a comment
|
||||
// then it must be a node, so we parse it
|
||||
parseNode(line);
|
||||
}
|
||||
|
||||
void OTMLParser::parseNode(OTMLNode* node, std::string data)
|
||||
void OTMLParser::parseNode(const std::string& data)
|
||||
{
|
||||
std::string tag;
|
||||
std::string value;
|
||||
std::size_t dotsPos = data.find_first_of(':');
|
||||
|
||||
// its a node that has a value but no tag
|
||||
// node that has no tag and may have a value
|
||||
if(!data.empty() && data[0] == '-') {
|
||||
value = data.substr(1);
|
||||
boost::trim(value);
|
||||
|
||||
// check if it's value is shortcut for adding a child node
|
||||
if(dotsPos != std::string::npos && !value.empty() && value[0] != '"') {
|
||||
OTMLNode* child = node->createNode();
|
||||
parseNode(child, value);
|
||||
value.clear();
|
||||
}
|
||||
}
|
||||
// its a node that has tag and possible a value
|
||||
else if(dotsPos != std::string::npos) {
|
||||
// node that has tag and possible a value
|
||||
} else if(dotsPos != std::string::npos) {
|
||||
tag = data.substr(0, dotsPos);
|
||||
value = data.substr(dotsPos+1);
|
||||
}
|
||||
// its a node that has only a tag
|
||||
else {
|
||||
if(data.size() > dotsPos+1)
|
||||
value = data.substr(dotsPos+1);
|
||||
// node that has only a tag
|
||||
} else {
|
||||
tag = data;
|
||||
}
|
||||
|
||||
// set node tag
|
||||
boost::trim(tag);
|
||||
node->setTag(tag);
|
||||
|
||||
// set node line
|
||||
node->setLine(m_currentLine);
|
||||
|
||||
// process node value
|
||||
parseNodeValue(node, value);
|
||||
}
|
||||
|
||||
void OTMLParser::parseNodeValue(OTMLNode* node, std::string value)
|
||||
{
|
||||
boost::trim(value);
|
||||
if(value.empty())
|
||||
return;
|
||||
|
||||
// multiline text scalar
|
||||
if(value[0] == '|') {
|
||||
// process multitine values
|
||||
if(value == "|" || value == "|-" || value == "|+") {
|
||||
// reads next lines until we can a value below the same depth
|
||||
std::string multiLineData;
|
||||
do {
|
||||
std::string line;
|
||||
size_t lastPos = m_in.tellg();
|
||||
std::getline(m_in, line);
|
||||
|
||||
// calculate numspaces
|
||||
std::size_t numSpaces = line.find_first_not_of(' ');
|
||||
size_t lastPos = in.tellg();
|
||||
std::string line = getNextLine();
|
||||
int depth = getLineDepth(line, true);
|
||||
|
||||
// depth above current depth, add the text to the multiline
|
||||
if(numSpaces != std::string::npos && (int)numSpaces >= (m_currentDepth+1)*2) {
|
||||
if(depth > currentDepth) {
|
||||
multiLineData += line.substr((currentDepth+1)*2);
|
||||
// it has contents below the current depth
|
||||
} else {
|
||||
// if not empty, its a node
|
||||
boost::trim(line);
|
||||
parseTextValue(line);
|
||||
multiLineData += line + "\n";
|
||||
}
|
||||
// if has contents below the current depth, its a node
|
||||
else if(numSpaces != std::string::npos) {
|
||||
m_in.seekg(lastPos, std::ios::beg);
|
||||
break;
|
||||
}
|
||||
// else its just a new line
|
||||
else {
|
||||
multiLineData += "\n";
|
||||
}
|
||||
} while(!m_in.eof());
|
||||
|
||||
// determine how to treat last new lines
|
||||
if(value.length() == 1 || (value.length() == 2 && value[1] == '-')) {
|
||||
// remove all new lines at the end
|
||||
while(*multiLineData.rbegin() == '\n')
|
||||
multiLineData.erase(multiLineData.length()-1, 1);
|
||||
// keep just one extra line
|
||||
if(value[0] == '-')
|
||||
multiLineData.append("\n");
|
||||
} else if(value.length() > 2 || value[1] != '+')
|
||||
throwError("invalid multiline identifier", m_currentLine);
|
||||
|
||||
node->setValue(multiLineData);
|
||||
}
|
||||
// sequence
|
||||
else if(value[0] == '[') {
|
||||
std::vector<std::string> tokens;
|
||||
parseTokens(value.substr(1), tokens);
|
||||
foreach(std::string& token, tokens) {
|
||||
OTMLNode* child = node->createNode();
|
||||
child->setLine(m_currentLine);
|
||||
parseNodeValue(child, token);
|
||||
}
|
||||
}
|
||||
// inline map
|
||||
else if(value[0] == '{') {
|
||||
std::vector<std::string> tokens;
|
||||
parseTokens(value.substr(1), tokens);
|
||||
foreach(std::string& token, tokens) {
|
||||
OTMLNode* child = node->createNode();
|
||||
parseNode(child, token);
|
||||
}
|
||||
}
|
||||
// text scalar
|
||||
else {
|
||||
parseTextValue(value);
|
||||
node->setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
void OTMLParser::parseTextValue(std::string& value)
|
||||
{
|
||||
if(value[0] == '"' && value[value.length()-1] == '"') {
|
||||
value = value.substr(1, value.length()-2);
|
||||
// escape characters
|
||||
boost::replace_all(value, "\\\\", "\\");
|
||||
boost::replace_all(value, "\\\"", "\"");
|
||||
boost::replace_all(value, "\\n", "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void OTMLParser::parseTokens(std::string data, std::vector<std::string>& out)
|
||||
{
|
||||
bool inQuote = false;
|
||||
int brackets = 1;
|
||||
|
||||
std::string tmp;
|
||||
uint i = 0;
|
||||
do {
|
||||
if(i<data.length()) {
|
||||
char c = data[i];
|
||||
tmp += c;
|
||||
|
||||
if(c == '"') {
|
||||
if(!inQuote)
|
||||
inQuote = true;
|
||||
else if(data[i-1] != '\\')
|
||||
inQuote = false;
|
||||
} else if(!inQuote) {
|
||||
if(c == '{' || c == '[')
|
||||
brackets++;
|
||||
else if(c == '}' || c == ']')
|
||||
brackets--;
|
||||
else if(c == ',' && brackets == 1) {
|
||||
tmp.erase(tmp.length()-1);
|
||||
boost::trim(tmp);
|
||||
if(!tmp.empty())
|
||||
out.push_back(tmp);
|
||||
tmp.clear();
|
||||
if(!line.empty()) {
|
||||
// rewind and break
|
||||
in.seekg(lastPos, std::ios::beg);
|
||||
currentLine--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
multiLineData += "\n";
|
||||
} while(!in.eof());
|
||||
|
||||
if(brackets == 0) {
|
||||
tmp.erase(tmp.length()-1);
|
||||
boost::trim(tmp);
|
||||
if(!tmp.empty())
|
||||
out.push_back(tmp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(i+1 >= data.length() && !m_in.eof()) {
|
||||
std::string line;
|
||||
std::getline(m_in, line);
|
||||
boost::trim(line);
|
||||
data += " ";
|
||||
data += line;
|
||||
}
|
||||
++i;
|
||||
} while(i<data.length());
|
||||
/* determine how to treat new lines at the end
|
||||
* | strip all new lines at the end and add just a new one
|
||||
* |- strip all new lines at the end
|
||||
* |+ keep all the new lines at the end (the new lines until next node)
|
||||
*/
|
||||
if(value == "|" || value == "|-") {
|
||||
// remove all new lines at the end
|
||||
int lastPos = multiLineData.length();
|
||||
while(multiLineData[--lastPos] == '\n')
|
||||
multiLineData.erase(lastPos, 1);
|
||||
|
||||
if(brackets != 0)
|
||||
throwError("no matching bracket while parsing, did you forget to close one?", m_currentLine);
|
||||
if(value == "|")
|
||||
multiLineData.append("\n");
|
||||
} // else it's |+
|
||||
|
||||
value = multiLineData;
|
||||
}
|
||||
|
||||
// create the node
|
||||
OTMLNodePtr node(new OTMLNode);
|
||||
node->setUnique(dotsPos != std::string::npos);
|
||||
node->setTag(tag);
|
||||
node->setValue(value);
|
||||
node->setSource(doc->source() + ":" + aux::safe_cast<std::string>(currentLine));
|
||||
currentParent->addChild(node);
|
||||
previousNode = node;
|
||||
}
|
||||
|
@@ -1,37 +1,33 @@
|
||||
#ifndef OTMLPARSER_H
|
||||
#define OTMLPARSER_H
|
||||
|
||||
#include <otml/otmlnode.h>
|
||||
|
||||
#include <istream>
|
||||
#include "otmldeclarations.h"
|
||||
|
||||
class OTMLParser
|
||||
{
|
||||
public:
|
||||
OTMLParser(std::istream& in, std::string what = "");
|
||||
~OTMLParser();
|
||||
OTMLParser(OTMLDocumentPtr doc, std::istream& in);
|
||||
|
||||
OTMLNode* getDocument() const { return m_rootNode; }
|
||||
std::string what() { return m_rootNode->what(); }
|
||||
|
||||
void throwError(const std::string& message, int line);
|
||||
|
||||
protected:
|
||||
/// Parse the entire document
|
||||
void parse();
|
||||
void parseLine(std::string line);
|
||||
void parseNode(OTMLNode* node, std::string data);
|
||||
void parseNodeValue(OTMLNode* node, std::string value);
|
||||
void parseTextValue(std::string& value);
|
||||
|
||||
void parseTokens(std::string data, std::vector<std::string>& out);
|
||||
|
||||
private:
|
||||
int m_currentDepth;
|
||||
int m_currentLine;
|
||||
OTMLNode* m_rootNode;
|
||||
OTMLNode* m_currentParent;
|
||||
OTMLNode* m_previousNode;
|
||||
std::istream& m_in;
|
||||
/// Retrieve next line from the input stream
|
||||
std::string getNextLine();
|
||||
/// Counts depth of a line (every 2 spaces increments one depth)
|
||||
int getLineDepth(const std::string& line, bool multilining = false);
|
||||
|
||||
/// Parse each line of the input stream
|
||||
void parseLine(std::string line);
|
||||
/// Parse nodes tag and value
|
||||
void parseNode(const std::string& data);
|
||||
|
||||
int currentDepth;
|
||||
int currentLine;
|
||||
OTMLDocumentPtr doc;
|
||||
OTMLNodePtr currentParent;
|
||||
OTMLNodePtr previousNode;
|
||||
std::istream& in;
|
||||
};
|
||||
|
||||
#endif // OTMLPARSER_H
|
||||
#endif
|
||||
|
6
src/framework/pch.h
Normal file
6
src/framework/pch.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef PCH_H
|
||||
#define PCH_H
|
||||
|
||||
#include "global.h"
|
||||
|
||||
#endif
|
@@ -1,645 +0,0 @@
|
||||
/* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 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 <global.h>
|
||||
#include <core/platform.h>
|
||||
#include <core/engine.h>
|
||||
|
||||
#include <windows.h>
|
||||
#include <dir.h>
|
||||
|
||||
#include <physfs.h>
|
||||
|
||||
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
struct Win32PlatformPrivate {
|
||||
HWND window;
|
||||
HINSTANCE instance;
|
||||
HDC hdc;
|
||||
HGLRC hrc;
|
||||
|
||||
std::string appName;
|
||||
int x, y;
|
||||
int width, height;
|
||||
int minWidth, minHeight;
|
||||
bool focused, visible, maximized;
|
||||
|
||||
std::map<int, uchar> keyMap;
|
||||
} win32;
|
||||
|
||||
void Platform::init(const char *appName)
|
||||
{
|
||||
// seend random numbers
|
||||
std::srand(std::time(NULL));
|
||||
|
||||
win32.appName = appName;
|
||||
win32.instance = GetModuleHandle(NULL);
|
||||
|
||||
// setup keys
|
||||
win32.keyMap[0x30] = KC_1;
|
||||
win32.keyMap[0x31] = KC_2;
|
||||
win32.keyMap[0x32] = KC_3;
|
||||
win32.keyMap[0x33] = KC_4;
|
||||
win32.keyMap[0x34] = KC_5;
|
||||
win32.keyMap[0x35] = KC_6;
|
||||
win32.keyMap[0x36] = KC_7;
|
||||
win32.keyMap[0x37] = KC_8;
|
||||
win32.keyMap[0x38] = KC_9;
|
||||
win32.keyMap[0x39] = KC_0;
|
||||
|
||||
win32.keyMap[VK_BACK] = KC_BACK;
|
||||
|
||||
win32.keyMap[VK_OEM_MINUS] = KC_MINUS;
|
||||
win32.keyMap[VK_OEM_PLUS] = KC_EQUALS;
|
||||
win32.keyMap[VK_SPACE] = KC_SPACE;
|
||||
win32.keyMap[VK_OEM_COMMA] = KC_COMMA;
|
||||
win32.keyMap[VK_OEM_PERIOD] = KC_PERIOD;
|
||||
|
||||
//win32.keyMap[VK_OEM_102] = KC_BACKSLASH;
|
||||
//win32.keyMap[XK_slash] = KC_SLASH;
|
||||
//win32.keyMap[XK_bracketleft] = KC_LBRACKET;
|
||||
//win32.keyMap[XK_bracketright] = KC_RBRACKET;
|
||||
|
||||
win32.keyMap[VK_ESCAPE] = KC_ESCAPE;
|
||||
win32.keyMap[VK_CAPITAL] = KC_CAPITAL;
|
||||
|
||||
win32.keyMap[VK_TAB] = KC_TAB;
|
||||
win32.keyMap[VK_RETURN] = KC_RETURN;
|
||||
win32.keyMap[VK_LCONTROL] = KC_LCONTROL;
|
||||
win32.keyMap[VK_RCONTROL] = KC_RCONTROL;
|
||||
|
||||
//win32.keyMap[XK_colon] = KC_COLON;
|
||||
//win32.keyMap[XK_semicolon] = KC_SEMICOLON;
|
||||
//win32.keyMap[XK_apostrophe] = KC_APOSTROPHE;
|
||||
//win32.keyMap[XK_grave] = KC_GRAVE;
|
||||
|
||||
win32.keyMap[0x41] = KC_A;
|
||||
win32.keyMap[0x42] = KC_B;
|
||||
win32.keyMap[0x43] = KC_C;
|
||||
win32.keyMap[0x44] = KC_D;
|
||||
win32.keyMap[0x45] = KC_E;
|
||||
win32.keyMap[0x46] = KC_F;
|
||||
win32.keyMap[0x47] = KC_G;
|
||||
win32.keyMap[0x48] = KC_H;
|
||||
win32.keyMap[0x49] = KC_I;
|
||||
win32.keyMap[0x4A] = KC_J;
|
||||
win32.keyMap[0x4B] = KC_K;
|
||||
win32.keyMap[0x4C] = KC_L;
|
||||
win32.keyMap[0x4D] = KC_M;
|
||||
win32.keyMap[0x4E] = KC_N;
|
||||
win32.keyMap[0x4F] = KC_O;
|
||||
win32.keyMap[0x50] = KC_P;
|
||||
win32.keyMap[0x51] = KC_Q;
|
||||
win32.keyMap[0x52] = KC_R;
|
||||
win32.keyMap[0x53] = KC_S;
|
||||
win32.keyMap[0x54] = KC_T;
|
||||
win32.keyMap[0x55] = KC_U;
|
||||
win32.keyMap[0x56] = KC_V;
|
||||
win32.keyMap[0x57] = KC_W;
|
||||
win32.keyMap[0x58] = KC_X;
|
||||
win32.keyMap[0x59] = KC_Y;
|
||||
win32.keyMap[0x5A] = KC_Z;
|
||||
|
||||
win32.keyMap[VK_F1] = KC_F1;
|
||||
win32.keyMap[VK_F2] = KC_F2;
|
||||
win32.keyMap[VK_F3] = KC_F3;
|
||||
win32.keyMap[VK_F4] = KC_F4;
|
||||
win32.keyMap[VK_F5] = KC_F5;
|
||||
win32.keyMap[VK_F6] = KC_F6;
|
||||
win32.keyMap[VK_F7] = KC_F7;
|
||||
win32.keyMap[VK_F8] = KC_F8;
|
||||
win32.keyMap[VK_F9] = KC_F9;
|
||||
win32.keyMap[VK_F10] = KC_F10;
|
||||
win32.keyMap[VK_F11] = KC_F11;
|
||||
win32.keyMap[VK_F12] = KC_F12;
|
||||
win32.keyMap[VK_F13] = KC_F13;
|
||||
win32.keyMap[VK_F14] = KC_F14;
|
||||
win32.keyMap[VK_F15] = KC_F15;
|
||||
|
||||
// keypad
|
||||
win32.keyMap[VK_NUMPAD0] = KC_NUMPAD0;
|
||||
win32.keyMap[VK_NUMPAD1] = KC_NUMPAD1;
|
||||
win32.keyMap[VK_NUMPAD2] = KC_NUMPAD2;
|
||||
win32.keyMap[VK_NUMPAD3] = KC_NUMPAD3;
|
||||
win32.keyMap[VK_NUMPAD4] = KC_NUMPAD4;
|
||||
win32.keyMap[VK_NUMPAD5] = KC_NUMPAD5;
|
||||
win32.keyMap[VK_NUMPAD6] = KC_NUMPAD6;
|
||||
win32.keyMap[VK_NUMPAD7] = KC_NUMPAD7;
|
||||
win32.keyMap[VK_NUMPAD8] = KC_NUMPAD8;
|
||||
win32.keyMap[VK_NUMPAD9] = KC_NUMPAD9;
|
||||
win32.keyMap[VK_ADD] = KC_ADD;
|
||||
win32.keyMap[VK_SUBTRACT] = KC_SUBTRACT;
|
||||
win32.keyMap[VK_DECIMAL] = KC_DECIMAL;
|
||||
//win32.keyMap[XK_KP_Equal] = KC_NUMPADEQUALS;
|
||||
win32.keyMap[VK_DIVIDE] = KC_DIVIDE;
|
||||
win32.keyMap[VK_MULTIPLY] = KC_MULTIPLY;
|
||||
win32.keyMap[VK_SEPARATOR] = KC_NUMPADENTER;
|
||||
|
||||
// keypad with numlock off
|
||||
//win32.keyMap[XK_KP_Home] = KC_NUMPAD7;
|
||||
//win32.keyMap[XK_KP_Up] = KC_NUMPAD8;
|
||||
//win32.keyMap[XK_KP_Page_Up] = KC_NUMPAD9;
|
||||
//win32.keyMap[XK_KP_Left] = KC_NUMPAD4;
|
||||
//win32.keyMap[XK_KP_Begin] = KC_NUMPAD5;
|
||||
//win32.keyMap[XK_KP_Right] = KC_NUMPAD6;
|
||||
//win32.keyMap[XK_KP_End] = KC_NUMPAD1;
|
||||
//win32.keyMap[XK_KP_Down] = KC_NUMPAD2;
|
||||
//win32.keyMap[XK_KP_Page_Down] = KC_NUMPAD3;
|
||||
//win32.keyMap[XK_KP_Insert] = KC_NUMPAD0;
|
||||
//win32.keyMap[XK_KP_Delete] = KC_DECIMAL;
|
||||
|
||||
win32.keyMap[VK_UP] = KC_UP;
|
||||
win32.keyMap[VK_DOWN] = KC_DOWN;
|
||||
win32.keyMap[VK_LEFT] = KC_LEFT;
|
||||
win32.keyMap[VK_RIGHT] = KC_RIGHT;
|
||||
|
||||
win32.keyMap[VK_PRIOR] = KC_PGUP;
|
||||
win32.keyMap[VK_NEXT] = KC_PGDOWN;
|
||||
win32.keyMap[VK_HOME] = KC_HOME;
|
||||
win32.keyMap[VK_END] = KC_END;
|
||||
|
||||
win32.keyMap[VK_NUMLOCK] = KC_NUMLOCK;
|
||||
win32.keyMap[VK_SNAPSHOT] = KC_SYSRQ;
|
||||
win32.keyMap[VK_SCROLL] = KC_SCROLL;
|
||||
win32.keyMap[VK_PAUSE] = KC_PAUSE;
|
||||
|
||||
win32.keyMap[VK_RSHIFT] = KC_RSHIFT;
|
||||
win32.keyMap[VK_LSHIFT] = KC_LSHIFT;
|
||||
win32.keyMap[VK_RMENU] = KC_RALT;
|
||||
win32.keyMap[VK_LMENU] = KC_LALT;
|
||||
|
||||
win32.keyMap[VK_INSERT] = KC_INSERT;
|
||||
win32.keyMap[VK_DELETE] = KC_DELETE;
|
||||
|
||||
win32.keyMap[VK_LWIN] = KC_LWIN;
|
||||
win32.keyMap[VK_RWIN] = KC_RWIN;
|
||||
win32.keyMap[VK_APPS] = KC_APPS;
|
||||
|
||||
|
||||
// win class
|
||||
WNDCLASSA wc;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Redraw On Size, And Own DC For Window.
|
||||
wc.lpfnWndProc = (WNDPROC)WndProc; // WndProc Handles Messages
|
||||
wc.cbClsExtra = 0; // No Extra Window Data
|
||||
wc.cbWndExtra = 0; // No Extra Window Data
|
||||
wc.hInstance = win32.instance; // Set The Instance
|
||||
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // Load The Default Icon
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Load The Arrow Pointer
|
||||
wc.hbrBackground = NULL; // No Background Required For GL
|
||||
wc.lpszMenuName = NULL; // We Don't Want A Menu
|
||||
wc.lpszClassName = win32.appName.c_str(); // Set The Class Name
|
||||
|
||||
if(!RegisterClassA(&wc))
|
||||
logFatal("FATAL ERROR: Failed to register the window class.");
|
||||
|
||||
// force first tick
|
||||
Platform::getTicks();
|
||||
}
|
||||
|
||||
void Platform::terminate()
|
||||
{
|
||||
if(win32.window) {
|
||||
destroyWindow();
|
||||
win32.window = NULL;
|
||||
}
|
||||
|
||||
if(win32.instance) {
|
||||
if(!UnregisterClassA(win32.appName.c_str(), win32.instance))
|
||||
logError("ERROR: Unregister class failed.");
|
||||
|
||||
win32.instance = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void Platform::poll()
|
||||
{
|
||||
MSG msg;
|
||||
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
int Platform::getTicks()
|
||||
{
|
||||
static ulong firstTick = 0;
|
||||
if(!firstTick)
|
||||
firstTick = GetTickCount();
|
||||
|
||||
return (uint32_t)(GetTickCount() - firstTick);
|
||||
}
|
||||
|
||||
void Platform::sleep(ulong miliseconds)
|
||||
{
|
||||
Sleep(miliseconds);
|
||||
}
|
||||
|
||||
bool Platform::createWindow(int x, int y, int width, int height, int minWidth, int minHeight, bool maximized)
|
||||
{
|
||||
DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
|
||||
DWORD dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
|
||||
|
||||
win32.x = x;
|
||||
win32.y = y;
|
||||
win32.width = width;
|
||||
win32.height = height;
|
||||
win32.minWidth = minWidth;
|
||||
win32.minHeight = minHeight;
|
||||
win32.maximized = maximized;
|
||||
|
||||
RECT windowRect = {x, y, x + width, y + height};
|
||||
AdjustWindowRectEx(&windowRect, dwStyle, FALSE, dwExStyle);
|
||||
|
||||
win32.window = CreateWindowExA(dwExStyle, // Extended Style For The Window
|
||||
win32.appName.c_str(), // Class Name
|
||||
win32.appName.c_str(), // Window Title
|
||||
dwStyle, // Required Window Style
|
||||
windowRect.left, // Window X Position
|
||||
windowRect.top, // Window Y Position
|
||||
windowRect.right - windowRect.left, // Calculate Window Width
|
||||
windowRect.bottom - windowRect.top, // Calculate Window Height
|
||||
NULL, // No Parent Window
|
||||
NULL, // No Menu
|
||||
win32.instance, // Instance
|
||||
NULL);
|
||||
|
||||
if(!win32.window) {
|
||||
terminate();
|
||||
logFatal("FATAL ERROR: Window creation error.");
|
||||
return false;
|
||||
}
|
||||
|
||||
GLuint pixelFormat;
|
||||
static PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be
|
||||
{
|
||||
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
|
||||
1, // Version Number
|
||||
PFD_DRAW_TO_WINDOW | // Format Must Support Window
|
||||
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
|
||||
PFD_DOUBLEBUFFER, // Must Support Double Buffering
|
||||
PFD_TYPE_RGBA, // Request An RGBA Format
|
||||
32, // Select Our Color Depth
|
||||
0, 0, 0, 0, 0, 0, // Color Bits Ignored
|
||||
0, // No Alpha Buffer
|
||||
0, // Shift Bit Ignored
|
||||
0, // No Accumulation Buffer
|
||||
0, 0, 0, 0, // Accumulation Bits Ignored
|
||||
16, // 16Bit Z-Buffer (Depth Buffer)
|
||||
0, // No Stencil Buffer
|
||||
0, // No Auxiliary Buffer
|
||||
PFD_MAIN_PLANE, // Main Drawing Layer
|
||||
0, // Reserved
|
||||
0, 0, 0 // Layer Masks Ignored
|
||||
};
|
||||
|
||||
if(!(win32.hdc = GetDC(win32.window))) {
|
||||
terminate();
|
||||
logFatal("FATAL ERROR: Can't Create A GL Device Context.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!(pixelFormat = ChoosePixelFormat(win32.hdc, &pfd))) {
|
||||
terminate();
|
||||
logFatal("FATAL ERROR: Can't Find A Suitable PixelFormat.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!SetPixelFormat(win32.hdc, pixelFormat, &pfd)) {
|
||||
terminate();
|
||||
logFatal("FATAL ERROR: Can't Set The PixelFormat.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!(win32.hrc = wglCreateContext(win32.hdc))) {
|
||||
terminate();
|
||||
logFatal("FATAL ERROR: Can't Create A GL Rendering Context.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!wglMakeCurrent(win32.hdc, win32.hrc)) {
|
||||
terminate();
|
||||
logFatal("FATAL ERROR: Can't Activate The GL Rendering Context.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Platform::destroyWindow()
|
||||
{
|
||||
if(win32.hrc) {
|
||||
if(!wglMakeCurrent(NULL, NULL))
|
||||
logError("ERROR: Release Of DC And RC Failed.");
|
||||
|
||||
if(!wglDeleteContext(win32.hrc))
|
||||
logError("ERROR: Release Rendering Context Failed.");
|
||||
|
||||
win32.hrc = NULL;
|
||||
}
|
||||
|
||||
if(win32.hdc) {
|
||||
if(!ReleaseDC(win32.window, win32.hdc))
|
||||
logError("ERROR: Release Device Context Failed.");
|
||||
|
||||
win32.hdc = NULL;
|
||||
}
|
||||
|
||||
if(win32.window) {
|
||||
if(!DestroyWindow(win32.window))
|
||||
logError("ERROR: Destroy window failed.");
|
||||
|
||||
win32.window = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void Platform::showWindow()
|
||||
{
|
||||
if(win32.maximized)
|
||||
ShowWindow(win32.window, SW_MAXIMIZE);
|
||||
else
|
||||
ShowWindow(win32.window, SW_SHOW);
|
||||
}
|
||||
|
||||
void Platform::setWindowTitle(const char *title)
|
||||
{
|
||||
SetWindowTextA(win32.window, title);
|
||||
}
|
||||
|
||||
void *Platform::getExtensionProcAddress(const char *ext)
|
||||
{
|
||||
return (void*)wglGetProcAddress(ext);
|
||||
}
|
||||
|
||||
bool Platform::isExtensionSupported(const char *ext)
|
||||
{
|
||||
typedef const char* _wglGetExtensionsStringARB(HDC hdc);
|
||||
_wglGetExtensionsStringARB *wglGetExtensionsStringARB = (_wglGetExtensionsStringARB*)getExtensionProcAddress("wglGetExtensionsStringARB");
|
||||
|
||||
const char *exts = wglGetExtensionsStringARB(win32.hdc);
|
||||
if(strstr(exts, ext))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *Platform::getClipboardText()
|
||||
{
|
||||
const char *text = "";
|
||||
if(OpenClipboard(NULL)) {
|
||||
text = (const char*)GetClipboardData(CF_TEXT);
|
||||
CloseClipboard();
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
void Platform::setClipboardText(const char *text)
|
||||
{
|
||||
int textLenght = strlen(text);
|
||||
HANDLE hData = new HANDLE[textLenght + 1];
|
||||
memcpy(hData, text, textLenght + 1);
|
||||
|
||||
if(OpenClipboard(NULL)) {
|
||||
EmptyClipboard();
|
||||
SetClipboardData(CF_TEXT, hData);
|
||||
CloseClipboard();
|
||||
}
|
||||
}
|
||||
|
||||
void Platform::hideMouseCursor()
|
||||
{
|
||||
ShowCursor(false);
|
||||
}
|
||||
|
||||
void Platform::showMouseCursor()
|
||||
{
|
||||
ShowCursor(true);
|
||||
}
|
||||
|
||||
void Platform::setVsync(bool enable /*= true*/)
|
||||
{
|
||||
typedef GLint (*glSwapIntervalProc)(GLint);
|
||||
glSwapIntervalProc glSwapInterval = NULL;
|
||||
|
||||
if(isExtensionSupported("WGL_EXT_swap_control"))
|
||||
glSwapInterval = (glSwapIntervalProc)getExtensionProcAddress("wglSwapIntervalEXT");
|
||||
|
||||
if(glSwapInterval)
|
||||
glSwapInterval(enable ? 1 : 0);
|
||||
}
|
||||
|
||||
void Platform::swapBuffers()
|
||||
{
|
||||
SwapBuffers(win32.hdc);
|
||||
}
|
||||
|
||||
bool Platform::isWindowFocused()
|
||||
{
|
||||
return win32.focused;
|
||||
}
|
||||
|
||||
bool Platform::isWindowVisible()
|
||||
{
|
||||
return win32.visible;
|
||||
}
|
||||
|
||||
int Platform::getWindowX()
|
||||
{
|
||||
return win32.x;
|
||||
}
|
||||
|
||||
int Platform::getWindowY()
|
||||
{
|
||||
return win32.y;
|
||||
}
|
||||
|
||||
int Platform::getWindowWidth()
|
||||
{
|
||||
return win32.width;
|
||||
}
|
||||
|
||||
int Platform::getWindowHeight()
|
||||
{
|
||||
return win32.height;
|
||||
}
|
||||
|
||||
int Platform::getDisplayWidth()
|
||||
{
|
||||
return GetSystemMetrics(SM_CXSCREEN);
|
||||
}
|
||||
|
||||
int Platform::getDisplayHeight()
|
||||
{
|
||||
return GetSystemMetrics(SM_CYSCREEN);
|
||||
}
|
||||
|
||||
bool Platform::isWindowMaximized()
|
||||
{
|
||||
return win32.maximized;
|
||||
}
|
||||
|
||||
std::string Platform::getAppUserDir()
|
||||
{
|
||||
std::stringstream sdir;
|
||||
sdir << PHYSFS_getUserDir() << "/." << win32.appName << "/";
|
||||
if((mkdir(sdir.str().c_str()) != 0) && (errno != EEXIST))
|
||||
flogError("ERROR: Couldn't create directory for saving configuration file. (%s)", sdir.str().c_str());
|
||||
return sdir.str();
|
||||
}
|
||||
|
||||
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
static int lastX, lastY;
|
||||
static InputEvent inputEvent;
|
||||
|
||||
switch(uMsg)
|
||||
{
|
||||
case WM_ACTIVATE:
|
||||
{
|
||||
win32.focused = !(wParam == WA_INACTIVE);
|
||||
break;
|
||||
}
|
||||
case WM_CHAR:
|
||||
{
|
||||
if(wParam >= 32 && wParam <= 255) {
|
||||
inputEvent.type = EV_TEXT_ENTER;
|
||||
inputEvent.keychar = wParam;
|
||||
inputEvent.keycode = KC_UNKNOWN;
|
||||
g_engine.onInputEvent(inputEvent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_CLOSE:
|
||||
{
|
||||
g_engine.onClose();
|
||||
break;
|
||||
}
|
||||
case WM_GETMINMAXINFO:
|
||||
{
|
||||
MINMAXINFO *minMax = (MINMAXINFO*)lParam;
|
||||
minMax->ptMinTrackSize.x = win32.minWidth;
|
||||
minMax->ptMinTrackSize.y = win32.minHeight;
|
||||
break;
|
||||
}
|
||||
case WM_KEYDOWN:
|
||||
case WM_KEYUP:
|
||||
{
|
||||
if(win32.keyMap.find(wParam) != win32.keyMap.end()) {
|
||||
inputEvent.type = uMsg == WM_KEYDOWN ? EV_KEY_DOWN : EV_KEY_UP;
|
||||
inputEvent.ctrl = HIWORD(GetKeyState(VK_CONTROL)) == 0 ? false : true;
|
||||
inputEvent.alt = HIWORD(GetKeyState(VK_MENU)) == 0 ? false : true;
|
||||
inputEvent.shift = HIWORD(GetKeyState(VK_SHIFT)) == 0 ? false : true;
|
||||
inputEvent.keycode = win32.keyMap[wParam];
|
||||
}
|
||||
g_engine.onInputEvent(inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_LBUTTONDOWN:
|
||||
{
|
||||
inputEvent.type = EV_MOUSE_LDOWN;
|
||||
g_engine.onInputEvent(inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_LBUTTONUP:
|
||||
{
|
||||
inputEvent.type = EV_MOUSE_LUP;
|
||||
g_engine.onInputEvent(inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_MBUTTONDOWN:
|
||||
{
|
||||
inputEvent.type = EV_MOUSE_MDOWN;
|
||||
g_engine.onInputEvent(inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_MBUTTONUP:
|
||||
{
|
||||
inputEvent.type = EV_MOUSE_MUP;
|
||||
g_engine.onInputEvent(inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_RBUTTONDOWN:
|
||||
{
|
||||
inputEvent.type = EV_MOUSE_RDOWN;
|
||||
g_engine.onInputEvent(inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_RBUTTONUP:
|
||||
{
|
||||
inputEvent.type = EV_MOUSE_RUP;
|
||||
g_engine.onInputEvent(inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_MOUSEMOVE:
|
||||
{
|
||||
inputEvent.type = EV_MOUSE_MOVE;
|
||||
Point newMousePos(LOWORD(lParam), HIWORD(lParam));
|
||||
inputEvent.mouseMoved = newMousePos - inputEvent.mousePos;
|
||||
inputEvent.mousePos = newMousePos;
|
||||
g_engine.onInputEvent(inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_MOUSEWHEEL:
|
||||
{
|
||||
inputEvent.type = HIWORD(wParam) > 0 ? EV_MOUSE_WHEEL_UP : EV_MOUSE_WHEEL_DOWN;
|
||||
g_engine.onInputEvent(inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_MOVE:
|
||||
{
|
||||
lastX = win32.x;
|
||||
lastY = win32.y;
|
||||
win32.x = LOWORD(lParam);
|
||||
win32.y = HIWORD(lParam);
|
||||
break;
|
||||
}
|
||||
case WM_SIZE:
|
||||
{
|
||||
switch(wParam)
|
||||
{
|
||||
case SIZE_MAXIMIZED:
|
||||
win32.x = lastX;
|
||||
win32.y = lastY;
|
||||
win32.maximized = true;
|
||||
break;
|
||||
case SIZE_RESTORED:
|
||||
win32.maximized = false;
|
||||
break;
|
||||
}
|
||||
|
||||
win32.visible = !(wParam == SIZE_MINIMIZED);
|
||||
|
||||
if(!win32.maximized) {
|
||||
win32.width = LOWORD(lParam);
|
||||
win32.height = HIWORD(lParam);
|
||||
}
|
||||
|
||||
g_engine.onResize(Size(LOWORD(lParam), HIWORD(lParam)));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
#ifndef LUADECLARATIONS_H
|
||||
#define LUADECLARATIONS_H
|
||||
|
||||
#include <global.h>
|
||||
|
||||
class LuaInterface;
|
||||
class LuaState;
|
||||
class LuaValue;
|
||||
class LuaObject;
|
||||
|
||||
typedef std::function<int(LuaState*)> LuaCppFunction;
|
||||
|
||||
typedef std::shared_ptr<LuaCppFunction> LuaCppFunctionPtr;
|
||||
typedef std::shared_ptr<LuaValue> LuaValuePtr;
|
||||
typedef std::shared_ptr<LuaObject> LuaObjectPtr;
|
||||
|
||||
typedef std::vector<LuaValuePtr> LuaValueList;
|
||||
|
||||
#endif // LUADECLARATIONS_H
|
@@ -1,39 +0,0 @@
|
||||
#include "luaexception.h"
|
||||
#include "luainterface.h"
|
||||
|
||||
LuaException::LuaException(const std::string& error, int traceLevel)
|
||||
{
|
||||
generateLuaErrorMessage(error, traceLevel);
|
||||
}
|
||||
|
||||
void LuaException::generateLuaErrorMessage(const std::string& error, int traceLevel)
|
||||
{
|
||||
// clear stack, to prevent further errors
|
||||
g_lua.clearStack();
|
||||
|
||||
// append trace level to error message
|
||||
if(traceLevel >= 0)
|
||||
m_what = make_string("LUA ERROR: ", g_lua.getTraceback(error, traceLevel));
|
||||
else
|
||||
m_what = make_string("LUA ERROR: ", error);
|
||||
}
|
||||
|
||||
LuaBadNumberOfArgumentsException::LuaBadNumberOfArgumentsException(int expected, int got)
|
||||
{
|
||||
std::string error = "attempt to call a function with wrong number of arguments";
|
||||
if(expected >= 0 && got >= 0)
|
||||
error = make_string(error, " (expected ", expected, ", but got ", got, ")");
|
||||
generateLuaErrorMessage(error, 1);
|
||||
}
|
||||
|
||||
LuaBadTypeConversinException::LuaBadTypeConversinException(const std::string& typeName)
|
||||
{
|
||||
std::string error = make_string("attempt to convert ", typeName, " to a lua value");
|
||||
generateLuaErrorMessage(error, 0);
|
||||
}
|
||||
|
||||
LuaBadValueCastException::LuaBadValueCastException(const LuaValuePtr& value, const std::string& typeName)
|
||||
{
|
||||
std::string error = make_string("attempt to cast a ", value->getTypeName(), " lua value to ", typeName);
|
||||
generateLuaErrorMessage(error, 0);
|
||||
}
|
@@ -1,54 +0,0 @@
|
||||
#include "luainterface.h"
|
||||
#include <core/engine.h>
|
||||
#include <ui/ui.h>
|
||||
#include "../../protocollogin.h"
|
||||
|
||||
void LuaInterface::registerFunctions()
|
||||
{
|
||||
g_lua.bindGlobalFunction("exit", std::bind(&Engine::stop, &g_engine));
|
||||
g_lua.bindGlobalFunction("loadUI", std::bind(&UILoader::loadFromFile, &g_uiLoader, std::placeholders::_1, std::placeholders::_2));
|
||||
g_lua.setGlobal("rootUI", safe_to_luavalue(UIContainer::getRoot()));
|
||||
|
||||
g_lua.registerClass("UIElement");
|
||||
g_lua.bindClassStaticFunction("UIElement", "new", &UIElement::create);
|
||||
g_lua.bindClassMemberField("UIElement", "id", &UIElement::getId, &UIElement::setId);
|
||||
g_lua.bindClassMemberField("UIElement", "enabled", &UIElement::isEnabled, &UIElement::setEnabled);
|
||||
g_lua.bindClassMemberField("UIElement", "visible", &UIElement::isVisible, &UIElement::setVisible);
|
||||
g_lua.bindClassMemberField("UIElement", "focused", &UIElement::isFocused, &UIElement::setFocused);
|
||||
g_lua.bindClassMemberField("UIElement", "width", &UIElement::getWidth, &UIElement::setWidth);
|
||||
g_lua.bindClassMemberField("UIElement", "height", &UIElement::getHeight, &UIElement::setHeight);
|
||||
g_lua.bindClassMemberField("UIElement", "parent", &UIElement::getParent, &UIElement::setParent);
|
||||
g_lua.bindClassMemberFunction("UIElement", "setLocked", &UIElement::setLocked);
|
||||
//g_lua.bindClassMemberFunction("UIElement", "setMargin", &UIElement::luaSetMargin);
|
||||
g_lua.bindClassMemberFunction("UIElement", "destroy", &UIElement::destroyLater);
|
||||
g_lua.bindClassMemberFunction("UIElement", "centerIn", &UIElement::centerIn);
|
||||
g_lua.bindClassMemberFunction("UIElement", "addAnchor", &UIElement::addAnchor);
|
||||
|
||||
g_lua.registerClass("UIContainer", "UIElement");
|
||||
g_lua.bindClassStaticFunction("UIContainer", "create", &UIContainer::create);
|
||||
g_lua.bindClassMemberFunction("UIContainer", "getChild", &UIContainer::getChildById);
|
||||
//g_lua.bindClassMemberFunction("UIContainer", "children", &UIContainer::getChildren);
|
||||
g_lua.bindClassMemberFunction("UIContainer", "addChild", &UIContainer::addChild);
|
||||
|
||||
g_lua.registerClass("UILabel", "UIElement");
|
||||
g_lua.bindClassStaticFunction("UILabel", "create", &UILabel::create);
|
||||
g_lua.bindClassMemberField("UILabel", "text", &UILabel::getText, &UILabel::setText);
|
||||
|
||||
g_lua.registerClass("UIButton", "UIElement");
|
||||
g_lua.bindClassStaticFunction("UIButton", "create", &UIButton::create);
|
||||
g_lua.bindClassMemberField("UIButton", "text", &UIButton::getText, &UIButton::setText);
|
||||
|
||||
g_lua.registerClass("UITextEdit", "UIElement");
|
||||
g_lua.bindClassStaticFunction("UITextEdit", "create", &UITextEdit::create);
|
||||
g_lua.bindClassMemberField("UITextEdit", "text", &UITextEdit::getText, &UITextEdit::setText);
|
||||
|
||||
g_lua.registerClass("UIWindow", "UIContainer");
|
||||
g_lua.bindClassStaticFunction("UIWindow", "create", &UIWindow::create);
|
||||
g_lua.bindClassMemberField("UIWindow", "title", &UIWindow::getTitle, &UIWindow::setTitle);
|
||||
|
||||
g_lua.registerClass("Protocol");
|
||||
g_lua.registerClass("ProtocolLogin", "Protocol");
|
||||
g_lua.bindClassStaticFunction("ProtocolLogin", "create", &ProtocolLogin::create);
|
||||
g_lua.bindClassMemberFunction("ProtocolLogin", "login", &ProtocolLogin::login);
|
||||
g_lua.bindClassMemberFunction("ProtocolLogin", "cancel", &ProtocolLogin::cancel);
|
||||
}
|
@@ -1,235 +0,0 @@
|
||||
#include "luainterface.h"
|
||||
|
||||
LuaInterface g_lua;
|
||||
|
||||
void LuaInterface::init()
|
||||
{
|
||||
// installs a custom loader that will load scripts correctlyfrom lua require keyword
|
||||
auto loaders = getGlobal("package")->getField("loaders");
|
||||
loaders->setTable(loaders->getTableSize() + 1, createCppFunction(&LuaInterface::luaScriptLoader));
|
||||
|
||||
// register LuaObject, the class that all other classes will derive from
|
||||
registerClass("LuaObject");
|
||||
bindClassMemberGetField("LuaObject", "use_count", &LuaObject::getUseCount);
|
||||
|
||||
// register other custom classes and functions
|
||||
registerFunctions();
|
||||
}
|
||||
|
||||
void LuaInterface::terminate()
|
||||
{
|
||||
collectGarbage();
|
||||
}
|
||||
|
||||
LuaValuePtr LuaInterface::loadFunction(const std::string& buffer, const std::string& source)
|
||||
{
|
||||
LuaValuePtr func;
|
||||
// get the function contained the buffer
|
||||
if(boost::starts_with(buffer, "function")) {
|
||||
runBuffer(make_string("__func = ", buffer), source);
|
||||
func = getGlobal("__func");
|
||||
setGlobal("__func", createNil());
|
||||
// use the buffer as a function
|
||||
} else
|
||||
func = loadBuffer(buffer, source);
|
||||
return func;
|
||||
}
|
||||
|
||||
LuaValuePtr LuaInterface::evaluateExpression(const std::string& expression, const std::string& source)
|
||||
{
|
||||
// run the expression
|
||||
std::string buffer = make_string("__exp = (", expression, ")");
|
||||
runBuffer(buffer, source);
|
||||
|
||||
// get the expression result
|
||||
LuaValuePtr res = getGlobal("__exp");
|
||||
setGlobal("__exp", createNil());
|
||||
return res;
|
||||
}
|
||||
|
||||
LuaValuePtr LuaInterface::createEnvironment()
|
||||
{
|
||||
// creates a new environment table and
|
||||
// redirect the new environment to the current thread global environment (aka _G)
|
||||
// this allows to access global variables from _G in the new environment
|
||||
// and prevents new variables on the new environment to be set on the global environment
|
||||
auto env = createTable();
|
||||
auto mt = createTable();
|
||||
mt->setField("__index", getGlobalEnvironment());
|
||||
env->setMetatable(mt);
|
||||
return env;
|
||||
}
|
||||
|
||||
void LuaInterface::registerClass(const std::string& className, const std::string& baseClass)
|
||||
{
|
||||
// create the class table (that it is also the class methods table)
|
||||
auto klass = createTable(className);
|
||||
// create the class metatable
|
||||
auto klass_mt = createTable(className + "_mt");
|
||||
// create the class fieldmethods table
|
||||
auto klass_fieldmethods = createTable(className + "_fieldmethods");
|
||||
|
||||
// set metatable metamethods
|
||||
klass_mt->setField("__index", &LuaInterface::luaObjectGetEvent);
|
||||
klass_mt->setField("__newindex", &LuaInterface::luaObjectSetEvent);
|
||||
klass_mt->setField("__eq", &LuaInterface::luaObjectEqualEvent);
|
||||
klass_mt->setField("__gc", &LuaInterface::luaObjectCollectEvent);
|
||||
klass_mt->setField("methods", klass);
|
||||
klass_mt->setField("fieldmethods", klass_fieldmethods);
|
||||
|
||||
// redirect methods and fieldmethods to the base class ones
|
||||
if(!className.empty() && className != "LuaObject") {
|
||||
/* the following code what create classes hierarchy for lua, by reproducing the following:
|
||||
* DerivedClass = { __index = BaseClass }
|
||||
* DerivedClass_fieldmethods = { __index = BaseClass_methods }
|
||||
*/
|
||||
|
||||
// redirect the class methods to the base methods
|
||||
auto redirect = createTable();
|
||||
auto tmp = getGlobal(baseClass);
|
||||
redirect->setField("__index", tmp);
|
||||
klass->setMetatable(redirect);
|
||||
|
||||
// redirect the class fieldmethods to the base fieldmethods
|
||||
redirect = createTable();
|
||||
tmp = getGlobal(baseClass + "_fieldmethods");
|
||||
redirect->setField("__index", tmp);
|
||||
klass_fieldmethods->setMetatable(redirect);
|
||||
}
|
||||
}
|
||||
|
||||
void LuaInterface::registerClassStaticFunction(const std::string& className, const std::string& functionName, const LuaCppFunction& function)
|
||||
{
|
||||
registerClassMemberFunction(className, functionName, function);
|
||||
}
|
||||
|
||||
void LuaInterface::registerClassMemberFunction(const std::string& className, const std::string& functionName, const LuaCppFunction& function)
|
||||
{
|
||||
auto table = getGlobal(className);
|
||||
table->setField(functionName, function);
|
||||
}
|
||||
|
||||
void LuaInterface::registerClassMemberField(const std::string& className, const std::string& field, const LuaCppFunction& getFunction, const LuaCppFunction& setFunction)
|
||||
{
|
||||
auto fieldmethods = getGlobal(className + "_fieldmethods");
|
||||
auto methods = getGlobal(className);
|
||||
auto capitalized = field;
|
||||
capitalized[0] = std::toupper(field[0]);
|
||||
|
||||
if(getFunction) {
|
||||
auto func = createCppFunction(getFunction);
|
||||
fieldmethods->setField(make_string("get_", field), func);
|
||||
methods->setField(make_string("get", capitalized), func);
|
||||
}
|
||||
|
||||
if(setFunction) {
|
||||
auto func = createCppFunction(setFunction);
|
||||
fieldmethods->setField(make_string("set_", field), func);
|
||||
methods->setField(make_string("set", capitalized), func);
|
||||
}
|
||||
}
|
||||
|
||||
void LuaInterface::registerGlobalFunction(const std::string& functionName, const LuaCppFunction& function)
|
||||
{
|
||||
setGlobal(functionName, createCppFunction(function));
|
||||
}
|
||||
|
||||
int LuaInterface::luaScriptLoader(LuaState* lua)
|
||||
{
|
||||
// load the script as a function
|
||||
auto fileName = make_string(lua->popValue()->toString(), + ".lua");
|
||||
auto scriptMain = lua->loadScript(fileName);
|
||||
lua->pushValue(scriptMain);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaInterface::luaObjectGetEvent(LuaState* lua)
|
||||
{
|
||||
// metamethod that will retrive fields values (that include functions) from the object
|
||||
|
||||
auto key = lua->popValue()->toString();
|
||||
auto objRef = lua->popValue();
|
||||
auto obj = safe_luavalue_cast<LuaObjectPtr>(objRef);
|
||||
|
||||
// if a get method for this key exists, calls it
|
||||
auto get_method = objRef->getMetatable()->getField("fieldmethods")->getField("get_" + key);
|
||||
if(!get_method->isNil()) {
|
||||
LuaValueList rets = get_method->call(make_string(obj->getLuaTypeName(), " obj.", key), objRef);
|
||||
assert(rets.size() == 1);
|
||||
lua->pushValues(rets);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// if the field for this key exists, returns it
|
||||
auto field = obj->getField(key);
|
||||
if(!field->isNil()) {
|
||||
lua->pushValue(field);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// if a method for this key exists, returns it
|
||||
auto method = objRef->getMetatable()->getField("methods")->getField(key);
|
||||
lua->pushValue(method);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaInterface::luaObjectSetEvent(LuaState* lua)
|
||||
{
|
||||
// this metamethod is called when setting a field of the object by using the keyword '='
|
||||
|
||||
auto value = lua->popValue();
|
||||
auto key = lua->popValue()->toString();
|
||||
auto objRef = lua->popValue();
|
||||
auto obj = safe_luavalue_cast<LuaObjectPtr>(objRef);
|
||||
|
||||
// check if a set method for this field exists and call it
|
||||
auto set_method = objRef->getMetatable()->getField("fieldmethods")->getField("set_" + key);
|
||||
if(!set_method->isNil()) {
|
||||
set_method->call(make_string(obj->getLuaTypeName(), " obj.", key, "="), objRef, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// no set method exists, then sets the object table
|
||||
obj->setField(key, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LuaInterface::luaObjectEqualEvent(LuaState* lua)
|
||||
{
|
||||
// metamethod that will check equality of objects
|
||||
|
||||
auto objRef2 = lua->popValue();
|
||||
auto objRef1 = lua->popValue();
|
||||
bool ret = false;
|
||||
|
||||
// check if obj1 == obj2
|
||||
if(objRef1->isUserdata() && objRef2->isUserdata()) {
|
||||
LuaObjectPtr* objPtr1 = static_cast<LuaObjectPtr*>(objRef1->toUserdata());
|
||||
LuaObjectPtr* objPtr2 = static_cast<LuaObjectPtr*>(objRef2->toUserdata());
|
||||
assert(objPtr1 && objPtr2);
|
||||
if(*objPtr1 == *objPtr2)
|
||||
ret = true;
|
||||
}
|
||||
|
||||
lua->pushBoolean(ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaInterface::luaObjectCollectEvent(LuaState* lua)
|
||||
{
|
||||
/* this metamethod is called every two lua garbage collections
|
||||
* for any LuaObject that have no references left in lua environment
|
||||
* anymore, thus this creates the possibility of holding an object
|
||||
* existence by lua
|
||||
*/
|
||||
|
||||
// get object pointer
|
||||
auto objRef = lua->popValue();
|
||||
auto objPtr = static_cast<LuaObjectPtr*>(objRef->toUserdata());
|
||||
assert(objPtr);
|
||||
|
||||
// reset pointer to decrease object use count
|
||||
objPtr->reset();
|
||||
return 0;
|
||||
}
|
||||
|
@@ -1,73 +0,0 @@
|
||||
#ifndef LUAINTERFACE_H
|
||||
#define LUAINTERFACE_H
|
||||
|
||||
#include "luabinder.h"
|
||||
#include "luaobject.h"
|
||||
|
||||
class LuaInterface : public LuaState
|
||||
{
|
||||
public:
|
||||
void init();
|
||||
void terminate();
|
||||
|
||||
/// Load a function from buffef into a LuaValue
|
||||
LuaValuePtr loadFunction(const std::string& buffer, const std::string& source = "lua function buffer");
|
||||
|
||||
/// Evaluate a lua expression to a LuaValue
|
||||
LuaValuePtr evaluateExpression(const std::string& expression, const std::string& source = "lua expression");
|
||||
|
||||
LuaValuePtr createEnvironment();
|
||||
|
||||
/// Register core script functions
|
||||
void registerFunctions();
|
||||
|
||||
// methods for registring classes and functions
|
||||
void registerClass(const std::string& className, const std::string& baseClass = "LuaObject");
|
||||
void registerClassStaticFunction(const std::string& className, const std::string& functionName, const LuaCppFunction& function);
|
||||
void registerClassMemberFunction(const std::string& className, const std::string& functionName, const LuaCppFunction& function);
|
||||
void registerClassMemberField(const std::string& className, const std::string& field, const LuaCppFunction& getFunction, const LuaCppFunction& setFunction);
|
||||
void registerGlobalFunction(const std::string& functionName, const LuaCppFunction& function);
|
||||
|
||||
// methods for binding functions
|
||||
template<typename F>
|
||||
void bindClassStaticFunction(const std::string& className, const std::string& functionName, const F& function) {
|
||||
registerClassStaticFunction(className, functionName, luabinder::bind_fun(function));
|
||||
}
|
||||
|
||||
template<class C, typename F>
|
||||
void bindClassMemberFunction(const std::string& className, const std::string& functionName, F C::*function) {
|
||||
registerClassMemberFunction(className, functionName, luabinder::bind_mem_fun(function));
|
||||
}
|
||||
|
||||
template<class C, typename F1, typename F2>
|
||||
void bindClassMemberField(const std::string& className, const std::string& fieldName, F1 C::*getFunction, F2 C::*setFunction) {
|
||||
registerClassMemberField(className, fieldName, luabinder::bind_mem_fun(getFunction), luabinder::bind_mem_fun(setFunction));
|
||||
}
|
||||
|
||||
template<class C, typename F>
|
||||
void bindClassMemberGetField(const std::string& className, const std::string& fieldName, F C::*getFunction) {
|
||||
registerClassMemberField(className, fieldName, luabinder::bind_mem_fun(getFunction), LuaCppFunction());
|
||||
}
|
||||
|
||||
template<class C, typename F>
|
||||
void bindClassMemberSetField(const std::string& className, const std::string& fieldName, F C::*setFunction) {
|
||||
registerClassMemberField(className, fieldName, LuaCppFunction(), luabinder::bind_mem_fun(setFunction));
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void bindGlobalFunction(const std::string& functionName, const F& function) {
|
||||
registerGlobalFunction(functionName, luabinder::bind_fun(function));
|
||||
}
|
||||
|
||||
private:
|
||||
// installed lua callbacks by this interface
|
||||
static int luaScriptLoader(LuaState* lua);
|
||||
static int luaObjectGetEvent(LuaState* lua);
|
||||
static int luaObjectSetEvent(LuaState* lua);
|
||||
static int luaObjectEqualEvent(LuaState* lua);
|
||||
static int luaObjectCollectEvent(LuaState* lua);
|
||||
};
|
||||
|
||||
extern LuaInterface g_lua;
|
||||
|
||||
#endif // LUAINTERFACE_H
|
@@ -1,24 +0,0 @@
|
||||
#include "luaobject.h"
|
||||
#include "luainterface.h"
|
||||
|
||||
LuaObject::LuaObject()
|
||||
{
|
||||
// creates own table
|
||||
m_luaTable = g_lua.createTable();
|
||||
}
|
||||
|
||||
LuaObject::~LuaObject()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
LuaValuePtr LuaObject::toLuaValue()
|
||||
{
|
||||
// fills a new userdata with a new LuaObject pointer
|
||||
new(g_lua.newUserdata(sizeof(LuaObjectPtr))) LuaObjectPtr(shared_from_this());
|
||||
|
||||
// set the metatable for the userdata
|
||||
g_lua.setMetatable(make_string(getLuaTypeName(), "_mt"));
|
||||
|
||||
return g_lua.popValue();
|
||||
}
|
@@ -1,50 +0,0 @@
|
||||
#ifndef LUAOBJECT_H
|
||||
#define LUAOBJECT_H
|
||||
|
||||
#include "luavalue.h"
|
||||
|
||||
/// LuaObject, all bound classes must be derived from it
|
||||
class LuaObject : public std::enable_shared_from_this<LuaObject>
|
||||
{
|
||||
public:
|
||||
LuaObject();
|
||||
virtual ~LuaObject();
|
||||
|
||||
/// Call a field of this lua object
|
||||
template<typename... T>
|
||||
LuaValueList callField(const std::string& field, const T&... args) {
|
||||
// note that we must retrive the field from or lua value (to use the __index metamethod)
|
||||
// so we cannot use our getField here
|
||||
auto fieldFunc = toLuaValue()->getField(field);
|
||||
auto funcName = make_string(getLuaTypeName(), ":", field);
|
||||
return fieldFunc->call(funcName, shared_from_this(), args...);
|
||||
}
|
||||
|
||||
/// Set a field of this lua object
|
||||
template<typename T>
|
||||
void setField(const std::string& key, const T& value) {
|
||||
m_luaTable->setField(key, value);
|
||||
}
|
||||
|
||||
/// Get a field of this lua object
|
||||
LuaValuePtr getField(const std::string& key) {
|
||||
return m_luaTable->getField(key);
|
||||
}
|
||||
|
||||
/// Returns current use count by the shared_ptr
|
||||
int getUseCount() { return shared_from_this().use_count() - 1; }
|
||||
|
||||
/// Class name used in lua, must be overridden by derived classes
|
||||
virtual const char* getLuaTypeName() const = 0;
|
||||
|
||||
/** Convert to a lua value for pushing this object into lua stack.
|
||||
* Each call to this will create a new pointer, thus increasing the use count.*/
|
||||
LuaValuePtr toLuaValue();
|
||||
|
||||
LuaObjectPtr asLuaObject() { return shared_from_this(); }
|
||||
|
||||
private:
|
||||
LuaValuePtr m_luaTable;
|
||||
};
|
||||
|
||||
#endif // LUAOBJECT_H
|
@@ -1,604 +0,0 @@
|
||||
#include "luastate.h"
|
||||
#include "luavalue.h"
|
||||
|
||||
#include <lua.hpp>
|
||||
#include <core/resources.h>
|
||||
|
||||
/// Retrive LuaState from L
|
||||
LuaState* retriveLuaState(lua_State* L)
|
||||
{
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, "LuaStateInstance");
|
||||
auto lua = static_cast<LuaState*>(const_cast<void*>(lua_topointer(L, -1)));
|
||||
lua_pop(L, 1);
|
||||
return lua;
|
||||
}
|
||||
|
||||
/// Handle errors by protected lua calls (pcall)
|
||||
int luaErrorHandler(lua_State* L)
|
||||
{
|
||||
// pops the error message
|
||||
auto lua = retriveLuaState(L);
|
||||
auto error = lua->popString();
|
||||
|
||||
// prevents repeated tracebacks
|
||||
if(error.find("stack traceback:") != std::string::npos)
|
||||
error = lua->getTraceback(error, 1);
|
||||
|
||||
// pushes the new error message with traceback information
|
||||
lua->pushString(error);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// Handle bound cpp functions callbacks
|
||||
int luaCppFunctionCallback(lua_State* L)
|
||||
{
|
||||
auto lua = retriveLuaState(L);
|
||||
auto funcPtr = static_cast<LuaCppFunctionPtr*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
assert(funcPtr);
|
||||
|
||||
try {
|
||||
return (*(funcPtr->get()))(lua);
|
||||
} catch(LuaException &e) {
|
||||
logError(e.what());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Free cpp function pointer when it expires
|
||||
int luaCppFunctionCallbackPointerExpire(lua_State* L)
|
||||
{
|
||||
auto funcPtr = static_cast<LuaCppFunctionPtr*>(lua_touserdata(L, -1));
|
||||
assert(funcPtr);
|
||||
funcPtr->reset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
LuaState::LuaState() : m_collecting(false)
|
||||
{
|
||||
// create lua state
|
||||
L = luaL_newstate();
|
||||
if(!L)
|
||||
throw LuaException("failed to create lua state");
|
||||
|
||||
// load lua standard libraries
|
||||
luaL_openlibs(L);
|
||||
|
||||
// store this into lua
|
||||
pushLightUserdata(this);
|
||||
lua_setfield(L, LUA_REGISTRYINDEX, "LuaStateInstance");
|
||||
}
|
||||
|
||||
LuaState::~LuaState()
|
||||
{
|
||||
// close lua state
|
||||
m_collecting = true;
|
||||
lua_close(L);
|
||||
}
|
||||
|
||||
void LuaState::collectGarbage()
|
||||
{
|
||||
// prevents recursive collects
|
||||
if(!m_collecting) {
|
||||
m_collecting = true;
|
||||
|
||||
// we must collect two times for __gc metamethod be called on uservalues
|
||||
for(int i=0;i<2;++i)
|
||||
lua_gc(L, LUA_GCCOLLECT, 0);
|
||||
|
||||
m_collecting = false;
|
||||
}
|
||||
}
|
||||
|
||||
LuaValuePtr LuaState::loadBuffer(const std::string& buffer, const std::string& source)
|
||||
{
|
||||
// load buffer from lua, the "@" means that the source is a file path, thus lua will
|
||||
// print file paths in tracebacks
|
||||
int ret = luaL_loadbuffer(L, buffer.c_str(), buffer.length(), ("@" + source).c_str());
|
||||
if(ret != 0)
|
||||
throw LuaException(popString(), 0);
|
||||
return popValue();
|
||||
}
|
||||
|
||||
LuaValuePtr LuaState::loadScript(const std::string &fileName)
|
||||
{
|
||||
std::stringstream fin;
|
||||
if(!g_resources.loadFile(fileName, fin))
|
||||
throw LuaException(make_string("failed to open lua script ", g_resources.resolvePath(fileName)), 0);
|
||||
return loadBuffer(fin.str(), g_resources.resolvePath(fileName));
|
||||
}
|
||||
|
||||
void LuaState::runBuffer(const std::string& buffer, const std::string& source)
|
||||
{
|
||||
auto main = loadBuffer(buffer, source);
|
||||
main->call(source);
|
||||
}
|
||||
|
||||
void LuaState::runScript(const std::string& fileName)
|
||||
{
|
||||
auto main = loadScript(fileName);
|
||||
main->call(fileName);
|
||||
}
|
||||
|
||||
int LuaState::safeCall(const std::string& functionName, int numArgs)
|
||||
{
|
||||
assert(hasIndex(-numArgs-1));
|
||||
|
||||
int previousStackSize = stackSize();
|
||||
|
||||
// push error function
|
||||
int errorFuncIndex = previousStackSize - numArgs;
|
||||
lua_pushcfunction(L, luaErrorHandler);
|
||||
insert(errorFuncIndex);
|
||||
|
||||
m_callStack.push_front(functionName);
|
||||
|
||||
// call the func
|
||||
int ret = lua_pcall(L, numArgs, LUA_MULTRET, errorFuncIndex);
|
||||
|
||||
m_callStack.pop_front();
|
||||
|
||||
// pop error func
|
||||
remove(errorFuncIndex);
|
||||
|
||||
if(ret != 0)
|
||||
throw LuaException(popString(), 0);
|
||||
|
||||
// return the number of results
|
||||
return (stackSize() + numArgs + 1) - previousStackSize;
|
||||
}
|
||||
|
||||
LuaValuePtr LuaState::popValue()
|
||||
{
|
||||
assert(hasIndex(-1));
|
||||
|
||||
LuaValuePtr value;
|
||||
|
||||
int refId = ref();
|
||||
if(refId < 0) {
|
||||
// refs < 0 are considered as nil values
|
||||
value = LuaValuePtr(new LuaValue());
|
||||
} else {
|
||||
pushRef(refId);
|
||||
value = LuaValuePtr(new LuaValue(refId));
|
||||
pop();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
LuaValueList LuaState::popValues()
|
||||
{
|
||||
int numValues = stackSize();
|
||||
LuaValueList values(numValues);
|
||||
for(int i=numValues-1;i>=0;--i)
|
||||
values[i] = popValue();
|
||||
return values;
|
||||
}
|
||||
|
||||
void LuaState::pushCppFunction(const LuaCppFunction& func)
|
||||
{
|
||||
// create a pointer to func (this pointer will hold the function existence)
|
||||
new(newUserdata(sizeof(LuaCppFunctionPtr))) LuaCppFunctionPtr(new LuaCppFunction(func));
|
||||
|
||||
// set the userdata __gc metamethod
|
||||
newTable();
|
||||
lua_pushcfunction(L, luaCppFunctionCallbackPointerExpire);
|
||||
setField("__gc");
|
||||
setMetatable();
|
||||
|
||||
// pushes the func
|
||||
lua_pushcclosure(L, luaCppFunctionCallback, 1);
|
||||
}
|
||||
|
||||
void LuaState::pushValue(const LuaValuePtr& value)
|
||||
{
|
||||
if(value->isNil())
|
||||
pushNil();
|
||||
else
|
||||
pushRef(value->m_ref);
|
||||
}
|
||||
|
||||
void LuaState::pushValues(const LuaValueList& values)
|
||||
{
|
||||
foreach(const LuaValuePtr& value, values)
|
||||
pushValue(value);
|
||||
}
|
||||
|
||||
std::string LuaState::getTraceback(const std::string& errorMessage, int depth)
|
||||
{
|
||||
// get traceback from debug.traceback
|
||||
getGlobalField("debug");
|
||||
getField("traceback");
|
||||
remove(-2);
|
||||
pushString(errorMessage);
|
||||
pushInteger(depth);
|
||||
call(2,1);
|
||||
std::string luaTraceback = popString();
|
||||
boost::replace_first(luaTraceback, "stack traceback:", "lua stack traceback:");
|
||||
|
||||
std::stringstream ss;
|
||||
ss << luaTraceback;
|
||||
|
||||
// add application call traceback
|
||||
if(m_callStack.size() > 0) {
|
||||
ss << "\napplication call stack traceback:";
|
||||
foreach(const std::string& func, m_callStack)
|
||||
ss << "\n\t" << func;
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string LuaState::getCurrentSource()
|
||||
{
|
||||
std::string path;
|
||||
int level = 0;
|
||||
|
||||
// get the current running script path
|
||||
LuaValuePtr func;
|
||||
do {
|
||||
func = getStackFunction(level);
|
||||
if(func->isLuaFunction()) {
|
||||
path = getFunctionSource(func);
|
||||
break;
|
||||
}
|
||||
level++;
|
||||
} while(!func->isNil());
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string LuaState::getFunctionSource(LuaValuePtr func)
|
||||
{
|
||||
std::string path;
|
||||
|
||||
pushValue(func);
|
||||
|
||||
lua_Debug ar;
|
||||
lua_getinfo(L, ">Sn", &ar);
|
||||
if(ar.source) {
|
||||
path = ar.source;
|
||||
path = path.substr(1, std::string::npos);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
LuaValuePtr LuaState::getGlobalEnvironment()
|
||||
{
|
||||
lua_pushthread(L);
|
||||
getEnv();
|
||||
remove(-2);
|
||||
return popValue();
|
||||
}
|
||||
|
||||
void LuaState::setGlobalEnvironment(const LuaValuePtr& env)
|
||||
{
|
||||
lua_pushthread(L);
|
||||
pushValue(env);
|
||||
setEnv();
|
||||
pop();
|
||||
}
|
||||
|
||||
LuaValuePtr LuaState::getStackFunction(int level)
|
||||
{
|
||||
// get current stack func
|
||||
lua_Debug ar;
|
||||
if(lua_getstack(L, level, &ar) == 1) {
|
||||
lua_getinfo(L, "f", &ar);
|
||||
return popValue();
|
||||
}
|
||||
return createNil();
|
||||
}
|
||||
|
||||
std::string LuaState::typeName(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
int type = lua_type(L, index);
|
||||
std::string name = lua_typename(L, type);
|
||||
return name;
|
||||
}
|
||||
|
||||
int LuaState::ref()
|
||||
{
|
||||
return luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
}
|
||||
|
||||
void LuaState::unref(int ref)
|
||||
{
|
||||
if(ref > 0)
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, ref);
|
||||
}
|
||||
|
||||
void LuaState::call(int numArgs, int numRets)
|
||||
{
|
||||
assert(hasIndex(-numArgs - 1));
|
||||
lua_call(L, numArgs, numRets);
|
||||
}
|
||||
|
||||
void LuaState::insert(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
lua_insert(L, index);
|
||||
}
|
||||
|
||||
void LuaState::remove(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
lua_remove(L, index);
|
||||
}
|
||||
|
||||
bool LuaState::next(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
return lua_next(L, index);
|
||||
}
|
||||
|
||||
void LuaState::copy(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
lua_pushvalue(L, index);
|
||||
}
|
||||
|
||||
void LuaState::setMetatable(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
lua_setmetatable(L, index);
|
||||
}
|
||||
|
||||
void LuaState::setMetatable(const std::string& name)
|
||||
{
|
||||
assert(hasIndex(-1));
|
||||
getGlobalField(name);
|
||||
setMetatable();
|
||||
}
|
||||
|
||||
void LuaState::getMetatable(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
lua_getmetatable(L, index);
|
||||
}
|
||||
|
||||
void LuaState::getField(const std::string& key, int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
lua_getfield(L, index, key.c_str());
|
||||
}
|
||||
|
||||
void LuaState::setField(const std::string& key, int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
lua_setfield(L, index, key.c_str());
|
||||
}
|
||||
|
||||
void LuaState::getEnv(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
lua_getfenv(L, index);
|
||||
}
|
||||
|
||||
void LuaState::setEnv(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
assert(lua_setfenv(L, index) == 1);
|
||||
}
|
||||
|
||||
void LuaState::getTable(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
lua_gettable(L, index);
|
||||
}
|
||||
|
||||
void LuaState::setTable(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
lua_settable(L, index);
|
||||
}
|
||||
|
||||
void LuaState::getGlobalField(const std::string& key)
|
||||
{
|
||||
lua_getglobal(L, key.c_str());
|
||||
}
|
||||
|
||||
void LuaState::setGlobalField(const std::string& key)
|
||||
{
|
||||
assert(hasIndex(-1));
|
||||
lua_setglobal(L, key.c_str());
|
||||
}
|
||||
|
||||
void LuaState::rawGet(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
lua_rawget(L, index);
|
||||
}
|
||||
|
||||
void LuaState::rawGeti(int n, int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
lua_rawgeti(L, index, n);
|
||||
}
|
||||
|
||||
void LuaState::rawSet(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
lua_rawset(L, index);
|
||||
}
|
||||
|
||||
void LuaState::rawSeti(int n, int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
lua_rawseti(L, index, n);
|
||||
}
|
||||
|
||||
void LuaState::newTable()
|
||||
{
|
||||
lua_newtable(L);
|
||||
}
|
||||
|
||||
void* LuaState::newUserdata(int size)
|
||||
{
|
||||
return lua_newuserdata(L, size);
|
||||
}
|
||||
|
||||
void LuaState::pop(int n)
|
||||
{
|
||||
assert(hasIndex(-n));
|
||||
lua_pop(L, n);
|
||||
}
|
||||
|
||||
int LuaState::popInteger()
|
||||
{
|
||||
assert(hasIndex(-1));
|
||||
int v = toInteger(-1);
|
||||
pop();
|
||||
return v;
|
||||
}
|
||||
|
||||
double LuaState::popNumber()
|
||||
{
|
||||
assert(hasIndex(-1));
|
||||
double v = toNumber(-1);
|
||||
pop();
|
||||
return v;
|
||||
}
|
||||
|
||||
bool LuaState::popBoolean()
|
||||
{
|
||||
assert(hasIndex(-1));
|
||||
bool v = toBoolean(-1);
|
||||
pop();
|
||||
return v;
|
||||
}
|
||||
|
||||
std::string LuaState::popString()
|
||||
{
|
||||
assert(hasIndex(-1));
|
||||
std::string v = toString(-1);
|
||||
pop();
|
||||
return v;
|
||||
}
|
||||
|
||||
void* LuaState::popUserdata()
|
||||
{
|
||||
assert(hasIndex(-1));
|
||||
void* v = toUserdata(-1);
|
||||
pop();
|
||||
return v;
|
||||
}
|
||||
|
||||
void LuaState::pushNil()
|
||||
{
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
void LuaState::pushInteger(int v)
|
||||
{
|
||||
lua_pushinteger(L, v);
|
||||
}
|
||||
|
||||
void LuaState::pushNumber(double v)
|
||||
{
|
||||
lua_pushnumber(L, v);
|
||||
}
|
||||
|
||||
void LuaState::pushBoolean(bool v)
|
||||
{
|
||||
lua_pushboolean(L, v);
|
||||
}
|
||||
|
||||
void LuaState::pushString(const std::string& v)
|
||||
{
|
||||
lua_pushstring(L, v.c_str());
|
||||
}
|
||||
|
||||
void LuaState::pushRef(int ref)
|
||||
{
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||
}
|
||||
|
||||
void LuaState::pushLightUserdata(void* p)
|
||||
{
|
||||
lua_pushlightuserdata(L, p);
|
||||
}
|
||||
|
||||
bool LuaState::isNil(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
return lua_isnil(L, index);
|
||||
}
|
||||
|
||||
bool LuaState::isBoolean(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
return lua_isboolean(L, index);
|
||||
}
|
||||
|
||||
bool LuaState::isNumber(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
return lua_isnumber(L, index);
|
||||
}
|
||||
|
||||
bool LuaState::isString(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
return lua_isstring(L, index);
|
||||
}
|
||||
|
||||
bool LuaState::isTable(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
return lua_istable(L, index);
|
||||
}
|
||||
|
||||
bool LuaState::isFunction(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
return lua_isfunction(L, index);
|
||||
}
|
||||
|
||||
bool LuaState::isCFunction(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
return lua_iscfunction(L, index);
|
||||
}
|
||||
|
||||
bool LuaState::isUserdata(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
return lua_isuserdata(L, index);
|
||||
}
|
||||
|
||||
bool LuaState::toBoolean(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
return (bool)lua_toboolean(L, index);
|
||||
}
|
||||
|
||||
int LuaState::toInteger(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
return lua_tointeger(L, index);
|
||||
}
|
||||
|
||||
double LuaState::toNumber(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
return lua_tonumber(L, index);
|
||||
}
|
||||
|
||||
std::string LuaState::toString(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
return std::string(isString() ? lua_tostring(L, index) : "");
|
||||
}
|
||||
|
||||
void* LuaState::toUserdata(int index)
|
||||
{
|
||||
assert(hasIndex(index));
|
||||
return lua_touserdata(L, index);
|
||||
}
|
||||
|
||||
int LuaState::stackSize()
|
||||
{
|
||||
return lua_gettop(L);
|
||||
}
|
@@ -1,126 +0,0 @@
|
||||
#ifndef LUASTATE_H
|
||||
#define LUASTATE_H
|
||||
|
||||
#include "luadeclarations.h"
|
||||
|
||||
struct lua_State;
|
||||
|
||||
class LuaState
|
||||
{
|
||||
public:
|
||||
LuaState();
|
||||
virtual ~LuaState();
|
||||
|
||||
// high level functions
|
||||
void collectGarbage();
|
||||
|
||||
LuaValuePtr loadBuffer(const std::string& buffer, const std::string& source);
|
||||
LuaValuePtr loadScript(const std::string& fileName);
|
||||
void runBuffer(const std::string& buffer, const std::string& source);
|
||||
void runScript(const std::string& fileName);
|
||||
|
||||
LuaValuePtr getGlobal(const std::string& name) { getGlobalField(name); return popValue(); }
|
||||
void setGlobal(const std::string& name, const LuaValuePtr& value) { pushValue(value); setGlobalField(name); }
|
||||
|
||||
LuaValuePtr createTable() { newTable(); return popValue(); }
|
||||
LuaValuePtr createTable(const std::string& name) { newTable(); copy(); setGlobalField(name); return popValue(); }
|
||||
LuaValuePtr createCppFunction(const LuaCppFunction& v) { pushCppFunction(v); return popValue(); }
|
||||
LuaValuePtr createNil() { pushNil(); return popValue(); }
|
||||
LuaValuePtr createNumber(double v) { pushNumber(v); return popValue(); }
|
||||
LuaValuePtr createInteger(int v) { pushInteger(v); return popValue(); }
|
||||
LuaValuePtr createString(const std::string& v) { pushString(v); return popValue(); }
|
||||
LuaValuePtr createBoolean(bool v) { pushBoolean(v); return popValue(); }
|
||||
|
||||
std::string getTraceback(const std::string& errorMessage = "", int depth = 0);
|
||||
std::string getCurrentSource();
|
||||
std::string getFunctionSource(LuaValuePtr func);
|
||||
LuaValuePtr getStackFunction(int level);
|
||||
|
||||
LuaValuePtr getGlobalEnvironment();
|
||||
void setGlobalEnvironment(const LuaValuePtr& env);
|
||||
|
||||
// low level lua functions
|
||||
std::string typeName(int index = -1);
|
||||
|
||||
int ref();
|
||||
void unref(int ref);
|
||||
|
||||
void call(int numArgs = 0, int numRets = 0);
|
||||
int safeCall(const std::string& functionName, int numArgs = 0);
|
||||
|
||||
void insert(int index);
|
||||
void remove(int index);
|
||||
bool next(int index = -2);
|
||||
void copy(int index = -1);
|
||||
|
||||
void setMetatable(int index = -2);
|
||||
void setMetatable(const std::string& name);
|
||||
void getMetatable(int index = -1);
|
||||
|
||||
void getField(const std::string& key, int index = -1);
|
||||
void setField(const std::string& key, int index = -2);
|
||||
|
||||
void getTable(int index = -2);
|
||||
void setTable(int index = -3);
|
||||
|
||||
void getEnv(int index = -1);
|
||||
void setEnv(int index = -2);
|
||||
|
||||
void getGlobalField(const std::string& key);
|
||||
void setGlobalField(const std::string& key);
|
||||
|
||||
void rawGet(int index = -1);
|
||||
void rawGeti(int n, int index = -1);
|
||||
void rawSet(int index = -3);
|
||||
void rawSeti(int n, int index = -2);
|
||||
|
||||
void newTable();
|
||||
void* newUserdata(int size);
|
||||
|
||||
void pop(int n = 1);
|
||||
int popInteger();
|
||||
double popNumber();
|
||||
bool popBoolean();
|
||||
std::string popString();
|
||||
void* popUserdata();
|
||||
LuaValuePtr popValue();
|
||||
LuaValueList popValues();
|
||||
|
||||
void pushNil();
|
||||
void pushInteger(int v);
|
||||
void pushNumber(double v);
|
||||
void pushBoolean(bool v);
|
||||
void pushString(const std::string& v);
|
||||
void pushRef(int ref);
|
||||
void pushLightUserdata(void* p);
|
||||
void pushCppFunction(const LuaCppFunction& func);
|
||||
void pushValue(const LuaValuePtr& value);
|
||||
void pushValues(const LuaValueList& values);
|
||||
|
||||
bool isNil(int index = -1);
|
||||
bool isBoolean(int index = -1);
|
||||
bool isNumber(int index = -1);
|
||||
bool isString(int index = -1);
|
||||
bool isTable(int index = -1);
|
||||
bool isFunction(int index = -1);
|
||||
bool isCFunction(int index = -1);
|
||||
bool isLuaFunction(int index = -1) { return (isFunction() && !isCFunction()); }
|
||||
bool isUserdata(int index = -1);
|
||||
|
||||
bool toBoolean(int index = -1);
|
||||
int toInteger(int index = -1);
|
||||
double toNumber(int index = -1);
|
||||
std::string toString(int index = -1);
|
||||
void* toUserdata(int index = -1);
|
||||
|
||||
int stackSize();
|
||||
void clearStack() { pop(stackSize()); }
|
||||
bool hasIndex(int index) { return (stackSize() >= (index < 0 ? -index : index)); }
|
||||
|
||||
private:
|
||||
lua_State* L;
|
||||
bool m_collecting;
|
||||
std::deque<std::string> m_callStack;
|
||||
};
|
||||
|
||||
#endif // LUASTATE_H
|
@@ -1,234 +0,0 @@
|
||||
#include "luavalue.h"
|
||||
#include "luainterface.h"
|
||||
#include "luaobject.h"
|
||||
|
||||
#include <core/resources.h>
|
||||
|
||||
LuaValue::LuaValue(int ref) : m_ref(ref)
|
||||
{
|
||||
}
|
||||
|
||||
LuaValue::~LuaValue()
|
||||
{
|
||||
// releases the reference of this value from lua
|
||||
g_lua.unref(m_ref);
|
||||
}
|
||||
|
||||
LuaValueList LuaValue::call(const std::string& funcName, const LuaValueList& args)
|
||||
{
|
||||
LuaValueList rets;
|
||||
|
||||
// if is a function, calls it
|
||||
if(isFunction()) {
|
||||
g_resources.pushCurrentPath(getPathDirectory(g_lua.getFunctionSource(shared_from_this())));
|
||||
|
||||
try {
|
||||
push();
|
||||
g_lua.pushValues(args);
|
||||
int numRets = g_lua.safeCall(funcName, args.size());
|
||||
for(int i=0;i<numRets; ++i)
|
||||
rets.push_back(g_lua.popValue());
|
||||
} catch(LuaException &e) {
|
||||
logError(e.what());
|
||||
}
|
||||
|
||||
g_resources.popCurrentPath();
|
||||
}
|
||||
// also calls a table of functions
|
||||
else if(isTable()) {
|
||||
LuaValueList functions = getTableValues();
|
||||
foreach(const LuaValuePtr& function, functions) {
|
||||
if(function->isFunction())
|
||||
function->call(funcName, args);
|
||||
}
|
||||
};
|
||||
|
||||
return rets;
|
||||
}
|
||||
|
||||
int LuaValue::getTableSize()
|
||||
{
|
||||
int size = 0;
|
||||
push();
|
||||
assert(g_lua.isTable());
|
||||
g_lua.pushNil();
|
||||
while(g_lua.next()) {
|
||||
g_lua.pop();
|
||||
size++;
|
||||
}
|
||||
g_lua.pop();
|
||||
return size;
|
||||
}
|
||||
|
||||
LuaValueList LuaValue::getTableValues()
|
||||
{
|
||||
LuaValueList ret;
|
||||
push();
|
||||
assert(g_lua.isTable());
|
||||
g_lua.pushNil();
|
||||
while(g_lua.next())
|
||||
ret.push_back(g_lua.popValue());
|
||||
return ret;
|
||||
}
|
||||
|
||||
LuaValuePtr LuaValue::getField(const std::string& key)
|
||||
{
|
||||
push();
|
||||
assert(g_lua.isTable() || g_lua.isUserdata());
|
||||
g_lua.getField(key);
|
||||
g_lua.remove(-2);
|
||||
return g_lua.popValue();
|
||||
}
|
||||
|
||||
void LuaValue::setField(const std::string& key, const LuaValuePtr& value)
|
||||
{
|
||||
push();
|
||||
assert(g_lua.isTable() || g_lua.isUserdata());
|
||||
g_lua.pushValue(value);
|
||||
g_lua.setField(key);
|
||||
g_lua.pop();
|
||||
}
|
||||
|
||||
LuaValuePtr LuaValue::getMetatable()
|
||||
{
|
||||
push();
|
||||
assert(g_lua.isUserdata() || g_lua.isTable());
|
||||
g_lua.getMetatable();
|
||||
g_lua.remove(-2);
|
||||
return g_lua.popValue();
|
||||
}
|
||||
|
||||
void LuaValue::setMetatable(const LuaValuePtr& mt)
|
||||
{
|
||||
push();
|
||||
assert(g_lua.isUserdata() || g_lua.isTable());
|
||||
g_lua.pushValue(mt);
|
||||
g_lua.setMetatable();
|
||||
g_lua.pop();
|
||||
}
|
||||
|
||||
void LuaValue::setTable(int n, const LuaValuePtr& value)
|
||||
{
|
||||
push();
|
||||
assert(g_lua.isTable());
|
||||
g_lua.pushInteger(n);
|
||||
g_lua.pushValue(value);
|
||||
g_lua.setTable();
|
||||
g_lua.pop();
|
||||
}
|
||||
|
||||
void LuaValue::setEnvironment(LuaValuePtr env)
|
||||
{
|
||||
push();
|
||||
g_lua.pushValue(env);
|
||||
g_lua.setEnv();
|
||||
g_lua.pop();
|
||||
}
|
||||
|
||||
std::string LuaValue::getTypeName()
|
||||
{
|
||||
push();
|
||||
std::string typeName = g_lua.typeName();
|
||||
g_lua.pop();
|
||||
return typeName;
|
||||
}
|
||||
|
||||
bool LuaValue::isBoolean()
|
||||
{
|
||||
push();
|
||||
bool ret = g_lua.isBoolean();
|
||||
g_lua.pop();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool LuaValue::isString()
|
||||
{
|
||||
push();
|
||||
bool ret = g_lua.isString();
|
||||
g_lua.pop();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool LuaValue::isNumber()
|
||||
{
|
||||
push();
|
||||
bool ret = g_lua.isNumber();
|
||||
g_lua.pop();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool LuaValue::isTable()
|
||||
{
|
||||
push();
|
||||
bool ret = g_lua.isTable();
|
||||
g_lua.pop();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool LuaValue::isFunction()
|
||||
{
|
||||
push();
|
||||
bool ret = g_lua.isFunction();
|
||||
g_lua.pop();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool LuaValue::isCFunction()
|
||||
{
|
||||
push();
|
||||
bool ret = g_lua.isCFunction();
|
||||
g_lua.pop();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool LuaValue::isLuaFunction()
|
||||
{
|
||||
push();
|
||||
bool ret = g_lua.isLuaFunction();
|
||||
g_lua.pop();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool LuaValue::isUserdata()
|
||||
{
|
||||
push();
|
||||
bool ret = g_lua.isUserdata();
|
||||
g_lua.pop();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool LuaValue::toBoolean()
|
||||
{
|
||||
push();
|
||||
return g_lua.popBoolean();
|
||||
}
|
||||
|
||||
int LuaValue::toInteger()
|
||||
{
|
||||
push();
|
||||
return g_lua.popInteger();
|
||||
}
|
||||
|
||||
double LuaValue::toNumber()
|
||||
{
|
||||
push();
|
||||
return g_lua.popNumber();
|
||||
}
|
||||
|
||||
std::string LuaValue::toString()
|
||||
{
|
||||
push();
|
||||
return g_lua.popString();
|
||||
}
|
||||
|
||||
void* LuaValue::toUserdata()
|
||||
{
|
||||
push();
|
||||
return g_lua.popUserdata();
|
||||
}
|
||||
|
||||
void LuaValue::push()
|
||||
{
|
||||
g_lua.pushValue(shared_from_this());
|
||||
}
|
||||
|
@@ -1,78 +0,0 @@
|
||||
#ifndef LUAVALUE_H
|
||||
#define LUAVALUE_H
|
||||
|
||||
#include "luavaluecasts.h"
|
||||
|
||||
/// Utility used to fill a LuaValueList by args...
|
||||
inline void fillLuaValueList(LuaValueList& argsList) { }
|
||||
template<class T, class... Args>
|
||||
void fillLuaValueList(LuaValueList& argsList, const T& first, const Args&... rest) {
|
||||
argsList.push_back(safe_to_luavalue(first));
|
||||
fillLuaValueList(argsList, rest...);
|
||||
}
|
||||
|
||||
/// LuaValue, all values from and to lua can be represented by this type
|
||||
class LuaValue : public std::enable_shared_from_this<LuaValue>
|
||||
{
|
||||
public:
|
||||
LuaValue(int ref = -1);
|
||||
virtual ~LuaValue();
|
||||
|
||||
/** If this value is a function or a list of functions, calls it.
|
||||
* Otherwise, if is not a nil value, throws an LuaException */
|
||||
LuaValueList call(const std::string& funcName, const LuaValueList& args = LuaValueList());
|
||||
template<class... T>
|
||||
LuaValueList call(const std::string& funcName, const T&... args) {
|
||||
LuaValueList argsList;
|
||||
push();
|
||||
fillLuaValueList(argsList, args...);
|
||||
return call(funcName, argsList);
|
||||
}
|
||||
|
||||
int getTableSize();
|
||||
LuaValueList getTableValues();
|
||||
|
||||
LuaValuePtr getField(const std::string& key);
|
||||
void setField(const std::string& key, const LuaValuePtr& value);
|
||||
template<typename T>
|
||||
void setField(const std::string& key, const T& value) {
|
||||
setField(key, safe_to_luavalue<T>(value));
|
||||
}
|
||||
|
||||
LuaValuePtr getMetatable();
|
||||
void setMetatable(const LuaValuePtr& mt);
|
||||
|
||||
void setTable(int n, const LuaValuePtr& value);
|
||||
|
||||
void setEnvironment(LuaValuePtr env);
|
||||
|
||||
std::string getTypeName();
|
||||
|
||||
// check types
|
||||
bool isNil() { return m_ref < 0; }
|
||||
bool isBoolean();
|
||||
bool isString();
|
||||
bool isNumber();
|
||||
bool isTable();
|
||||
bool isFunction();
|
||||
bool isCFunction();
|
||||
bool isLuaFunction();
|
||||
bool isUserdata();
|
||||
|
||||
// convert types
|
||||
bool toBoolean();
|
||||
int toInteger();
|
||||
double toNumber();
|
||||
std::string toString();
|
||||
void* toUserdata();
|
||||
|
||||
private:
|
||||
/// Pushes this value into lua stack
|
||||
void push();
|
||||
|
||||
int m_ref;
|
||||
friend class LuaState;
|
||||
};
|
||||
|
||||
|
||||
#endif // LUAVALUE_H
|
@@ -1,76 +0,0 @@
|
||||
#include "luavaluecasts.h"
|
||||
#include "luainterface.h"
|
||||
|
||||
bool to_luavalue(const LuaValuePtr& v, LuaValuePtr& o) {
|
||||
o = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool to_luavalue(bool v, LuaValuePtr& o) {
|
||||
o = g_lua.createBoolean(v);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool to_luavalue(int v, LuaValuePtr& o) {
|
||||
o = g_lua.createInteger(v);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool to_luavalue(double v, LuaValuePtr& o) {
|
||||
o = g_lua.createNumber(v);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool to_luavalue(const std::string& v, LuaValuePtr& o) {
|
||||
o = g_lua.createString(v);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool to_luavalue(const char* v, LuaValuePtr& o) {
|
||||
o = g_lua.createString(v);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool to_luavalue(int (*v)(LuaState*), LuaValuePtr& o) {
|
||||
o = g_lua.createCppFunction(v);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool to_luavalue(const LuaCppFunction& v, LuaValuePtr& o) {
|
||||
o = g_lua.createCppFunction(v);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool luavalue_cast(const LuaValuePtr& v, bool& o) {
|
||||
o = v->toBoolean();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool luavalue_cast(const LuaValuePtr& v, int& o) {
|
||||
o = v->toInteger();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool luavalue_cast(const LuaValuePtr& v, double& o) {
|
||||
o = v->toNumber();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool luavalue_cast(const LuaValuePtr& v, std::string& o) {
|
||||
o = v->toString();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool luavalue_cast(const LuaValuePtr& v, LuaObjectPtr& o) {
|
||||
if(v->isUserdata()) {
|
||||
LuaObjectPtr* objRef = static_cast<LuaObjectPtr*>(v->toUserdata());
|
||||
if(objRef && *objRef) {
|
||||
o = *objRef;
|
||||
return true;
|
||||
}
|
||||
} else if(v->isNil()) {
|
||||
o = LuaObjectPtr();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
@@ -1,80 +0,0 @@
|
||||
#ifndef LUAVALUECASTS_H
|
||||
#define LUAVALUECASTS_H
|
||||
|
||||
#include "luadeclarations.h"
|
||||
#include "luaexception.h"
|
||||
|
||||
// convert from common types
|
||||
bool to_luavalue(const LuaValuePtr& v, LuaValuePtr& o);
|
||||
bool to_luavalue(bool v, LuaValuePtr& o);
|
||||
bool to_luavalue(int v, LuaValuePtr& o);
|
||||
bool to_luavalue(double v, LuaValuePtr& o);
|
||||
bool to_luavalue(const std::string& v, LuaValuePtr& o);
|
||||
bool to_luavalue(const char* v, LuaValuePtr& o);
|
||||
bool to_luavalue(int (*v)(LuaState*), LuaValuePtr& o);
|
||||
bool to_luavalue(const LuaCppFunction& v, LuaValuePtr& o);
|
||||
|
||||
// convert from LuaObject
|
||||
template<class T>
|
||||
typename std::enable_if<std::is_base_of<LuaObject, typename T::element_type>::value, bool>::type
|
||||
to_luavalue(const T& v, LuaValuePtr& o) {
|
||||
if(v) {
|
||||
o = v->toLuaValue();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Safe convert, if any errors occurs throws an LuaException
|
||||
template<class T>
|
||||
LuaValuePtr safe_to_luavalue(const T& v) {
|
||||
LuaValuePtr o;
|
||||
if(!to_luavalue(v, o))
|
||||
throw LuaBadTypeConversinException();
|
||||
return o;
|
||||
}
|
||||
|
||||
// common types casting
|
||||
bool luavalue_cast(const LuaValuePtr& v, bool& o);
|
||||
bool luavalue_cast(const LuaValuePtr& v, int& o);
|
||||
bool luavalue_cast(const LuaValuePtr& v, double& o);
|
||||
bool luavalue_cast(const LuaValuePtr& v, std::string& o);
|
||||
bool luavalue_cast(const LuaValuePtr& v, LuaObjectPtr& o);
|
||||
|
||||
// convert enums
|
||||
template<class T>
|
||||
typename std::enable_if<std::is_enum<T>::value, bool>::type
|
||||
luavalue_cast(const LuaValuePtr& v, T& o) {
|
||||
return luavalue_cast(v, (int&)o);
|
||||
}
|
||||
|
||||
// cast pointer
|
||||
template<class T>
|
||||
bool luavalue_cast(const LuaValuePtr& v, T*& o) {
|
||||
LuaObjectPtr obj;
|
||||
if(!luavalue_cast(v, obj))
|
||||
return false;
|
||||
o = std::dynamic_pointer_cast<T>(obj).get();
|
||||
return !!o;
|
||||
}
|
||||
|
||||
// cast shared pointers
|
||||
template<class T>
|
||||
bool luavalue_cast(const LuaValuePtr& v, std::shared_ptr<T>& o) {
|
||||
LuaObjectPtr obj;
|
||||
if(!luavalue_cast(v, obj))
|
||||
return false;
|
||||
o = std::dynamic_pointer_cast<T>(obj);
|
||||
return !!o;
|
||||
}
|
||||
|
||||
/// Safe casting, if any errors occurs throws an LuaException
|
||||
template<class T>
|
||||
T safe_luavalue_cast(const LuaValuePtr& v) {
|
||||
T o;
|
||||
if(!luavalue_cast(v, o))
|
||||
throw LuaBadValueCastException(v);
|
||||
return o;
|
||||
}
|
||||
|
||||
#endif // LUAVALUECASTS_H
|
@@ -1,285 +0,0 @@
|
||||
#include <global.h>
|
||||
#include <script/luafunctions.h>
|
||||
#include <script/luacontext.h>
|
||||
#include <core/engine.h>
|
||||
#include <core/resources.h>
|
||||
#include <ui/ui.h>
|
||||
#include <core/dispatcher.h>
|
||||
#include "../../protocollogin.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
int lua_App_exit() {
|
||||
g_engine.stop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_App_loadUI() {
|
||||
UIContainerPtr parent;
|
||||
if(g_lua.stackSize() > 1)
|
||||
parent = std::dynamic_pointer_cast<UIContainer>(g_lua.popLuaObjectInstance());
|
||||
else
|
||||
parent = UIContainer::getRoot();
|
||||
|
||||
std::string uiFile = g_lua.popString();
|
||||
|
||||
if(!boost::ends_with(uiFile, ".otml"))
|
||||
uiFile.append(".otml");
|
||||
|
||||
UIElementPtr element;
|
||||
if(parent) {
|
||||
element = g_uiLoader.loadFromFile(uiFile.c_str(), parent);
|
||||
if(!element) {
|
||||
g_lua.reportFuncErrorWithTraceback("failed to load UI");
|
||||
}
|
||||
} else
|
||||
g_lua.reportFuncErrorWithTraceback("invalid parent container");
|
||||
|
||||
g_lua.pushLuaObjectInstance(element);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_App_getRootContainer() {
|
||||
UIContainerPtr rootContainer = UIContainer::getRoot();
|
||||
g_lua.pushLuaObjectInstance(rootContainer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
UIElementPtr lua_createUIElement(UI::ElementType elementType)
|
||||
{
|
||||
std::string id;
|
||||
UIContainerPtr parent;
|
||||
|
||||
if(g_lua.stackSize() > 1)
|
||||
parent = std::dynamic_pointer_cast<UIContainer>(g_lua.popLuaObjectInstance());
|
||||
|
||||
if(g_lua.stackSize() > 0) {
|
||||
if(g_lua.isString())
|
||||
id = g_lua.popString();
|
||||
else
|
||||
parent = std::dynamic_pointer_cast<UIContainer>(g_lua.popLuaObjectInstance());
|
||||
}
|
||||
|
||||
UIElementPtr element;
|
||||
switch(elementType) {
|
||||
case UI::Element:
|
||||
element = UIElementPtr(new UIElement);
|
||||
break;
|
||||
case UI::Container:
|
||||
element = UIElementPtr(new UIContainer);
|
||||
break;
|
||||
case UI::Label:
|
||||
element = UIElementPtr(new UILabel);
|
||||
break;
|
||||
case UI::Button:
|
||||
element = UIElementPtr(new UIButton);
|
||||
break;
|
||||
case UI::TextEdit:
|
||||
element = UIElementPtr(new UITextEdit);
|
||||
break;
|
||||
case UI::Window:
|
||||
element = UIElementPtr(new UIWindow);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(element) {
|
||||
if(!id.empty())
|
||||
element->setId(id);
|
||||
|
||||
if(parent)
|
||||
parent->addChild(element);
|
||||
|
||||
element->applyDefaultSkin();
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
int lua_UIElement_setLocked() {
|
||||
bool locked = true;
|
||||
if(g_lua.stackSize() > 1)
|
||||
locked = g_lua.popBoolean();
|
||||
|
||||
if(UIElementPtr element = std::dynamic_pointer_cast<UIElement>(g_lua.popLuaObjectInstance())) {
|
||||
if(UIContainerPtr container = element->getParent()) {
|
||||
if(locked)
|
||||
container->lockElement(element);
|
||||
else
|
||||
container->unlockElement(element);
|
||||
} else
|
||||
g_lua.reportFuncErrorWithTraceback("locking failed, element has no parent");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_UIElement_setMargin() {
|
||||
int top = 0, right = 0, bottom = 0, left = 0;
|
||||
if(g_lua.stackSize() == 5) {
|
||||
left = g_lua.popInteger();
|
||||
bottom = g_lua.popInteger();
|
||||
right = g_lua.popInteger();
|
||||
top = g_lua.popInteger();
|
||||
} else if(g_lua.stackSize() == 3) {
|
||||
left = right = g_lua.popInteger();
|
||||
top = bottom = g_lua.popInteger();
|
||||
} else if(g_lua.stackSize() == 2) {
|
||||
top = right = bottom = left = g_lua.popInteger();
|
||||
} else {
|
||||
g_lua.reportFuncErrorWithTraceback("invalid number of arguments");
|
||||
}
|
||||
|
||||
if(UIElementPtr element = std::dynamic_pointer_cast<UIElement>(g_lua.popLuaObjectInstance()))
|
||||
element->setMargin(top, right, bottom, left);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int lua_UIElement_centerIn() {
|
||||
std::string targetId;
|
||||
if(g_lua.isString())
|
||||
targetId = g_lua.popString();
|
||||
else if(UIElementPtr target = std::dynamic_pointer_cast<UIElement>(g_lua.popLuaObjectInstance()))
|
||||
targetId = target->getId();
|
||||
|
||||
if(UIElementPtr element = std::dynamic_pointer_cast<UIElement>(g_lua.popLuaObjectInstance()))
|
||||
element->centerIn(targetId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_UIElement_addAnchor() {
|
||||
AnchorPoint targetEdge = (AnchorPoint)g_lua.popInteger();
|
||||
|
||||
std::string targetId;
|
||||
if(g_lua.isString())
|
||||
targetId = g_lua.popString();
|
||||
else if(UIElementPtr target = std::dynamic_pointer_cast<UIElement>(g_lua.popLuaObjectInstance()))
|
||||
targetId = target->getId();
|
||||
|
||||
AnchorPoint anchoredEdge = (AnchorPoint)g_lua.popInteger();
|
||||
|
||||
if(UIElementPtr element = std::dynamic_pointer_cast<UIElement>(g_lua.popLuaObjectInstance()))
|
||||
element->addAnchor(anchoredEdge, AnchorLine(targetId, targetEdge));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void registerScriptFunctions()
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// App
|
||||
g_lua.registerModule("App");
|
||||
// App.exit()
|
||||
g_lua.registerMemberFunction("exit", &lua_App_exit);
|
||||
// App.loadUI(file, [parent])
|
||||
g_lua.registerMemberFunction("loadUI", &lua_App_loadUI);
|
||||
// App.getRootContainer()
|
||||
g_lua.registerMemberFunction("getRootContainer", &lua_App_getRootContainer);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UIElement
|
||||
g_lua.registerClass("UIElement");
|
||||
// (UIElement) UIElement.new([UIContainer parent], [string id])
|
||||
g_lua.registerMemberFunction("new", &lua_UIElement_new);
|
||||
// (string) UIElement.id
|
||||
g_lua.registerMemberField("id", &lua_UIElement_getId, &lua_UIElement_setId);
|
||||
// (boolean) UIElement.enabled
|
||||
g_lua.registerMemberField("enabled", &lua_UIElement_isEnabled, &lua_UIElement_setEnabled);
|
||||
// (boolean UIElement.visible
|
||||
g_lua.registerMemberField("visible", &lua_UIElement_isVisible, &lua_UIElement_setVisible);
|
||||
// (boolean UIElement.focused
|
||||
g_lua.registerMemberField("focused", &lua_UIElement_isFocused, &lua_UIElement_setFocused);
|
||||
// (integer) UIElement.width
|
||||
g_lua.registerMemberField("width", &lua_UIElement_getWidth, &lua_UIElement_setWidth);
|
||||
// (integer) UIElement.height
|
||||
g_lua.registerMemberField("height", &lua_UIElement_getHeight, &lua_UIElement_setHeight);
|
||||
// (UIContainer UIElement.parent
|
||||
g_lua.registerMemberField("parent", &lua_UIElement_getParent, &lua_UIElement_setParent);
|
||||
// element:setLocked(boolean locked)
|
||||
g_lua.registerMemberFunction("setLocked", &lua_UIElement_setLocked);
|
||||
// element:setMargin(int all)
|
||||
// element:setMargin(int vertical, int horizontal)
|
||||
// element:setMargin(int top, right, bottom, left)
|
||||
g_lua.registerMemberFunction("setMargin", &lua_UIElement_setMargin);
|
||||
// element:destroy()
|
||||
g_lua.registerMemberFunction("destroy", &lua_UIElement_destroy);
|
||||
// element:centerIn(UIContainer target)
|
||||
g_lua.registerMemberFunction("centerIn", &lua_UIElement_centerIn);
|
||||
// element:addAnchor(AnchorPoint anchoredEdge, UIElement target, AnchorPoint targetEdge)
|
||||
// element:addAnchor(AnchorPoint anchoredEdge, string targetId, AnchorPoint targetEdge)
|
||||
g_lua.registerMemberFunction("addAnchor", &lua_UIElement_addAnchor);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UIContainer
|
||||
g_lua.registerClass("UIContainer", "UIElement");
|
||||
// UIContainer.new([UIContainer parent], [string id])
|
||||
g_lua.registerMemberFunction("new", &lua_UIContainer_new);
|
||||
// container:child(string id)
|
||||
g_lua.registerMemberFunction("child", &lua_UIContainer_child);
|
||||
// (table) container:children()
|
||||
g_lua.registerMemberFunction("children", &lua_UIContainer_getChildren);
|
||||
// container:addChild(UIElement child)
|
||||
g_lua.registerMemberFunction("addChild", &lua_UIContainer_addChild);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UILabel
|
||||
g_lua.registerClass("UILabel", "UIElement");
|
||||
// UILabel.new([UIContainer parent], [string id])
|
||||
g_lua.registerMemberFunction("new", &lua_UILabel_new);
|
||||
// label.text
|
||||
g_lua.registerMemberField("text", &lua_UILabel_getText, &lua_UILabel_setText);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UIButton
|
||||
g_lua.registerClass("UIButton", "UIElement");
|
||||
// UIButton.new([UIContainer parent], [string id])
|
||||
g_lua.registerMemberFunction("new", &lua_UIButton_new);
|
||||
// button.text
|
||||
g_lua.registerMemberField("text", &lua_UIButton_getText, &lua_UIButton_setText);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UITextEdit
|
||||
g_lua.registerClass("UITextEdit", "UIElement");
|
||||
// UITextEdit.new([UIContainer parent], [string id])
|
||||
g_lua.registerMemberFunction("new", &lua_UITextEdit_new);
|
||||
// textEdit.text
|
||||
g_lua.registerMemberField("text", &lua_UITextEdit_getText, &lua_UITextEdit_setText);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UIWindow
|
||||
g_lua.registerClass("UIWindow", "UIContainer");
|
||||
// UIWindow.new([UIContainer parent], [string id])
|
||||
g_lua.registerMemberFunction("new", &lua_UIWindow_new);
|
||||
// window.title
|
||||
g_lua.registerMemberField("title", &lua_UIWindow_getTitle, &lua_UIWindow_setTitle);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Protocol
|
||||
g_lua.registerClass("ProtocolLogin");
|
||||
g_lua.registerMemberFunction("new", []{
|
||||
g_lua.pushLuaObjectInstance(LuaObjectPtr(new ProtocolLogin));
|
||||
return 1;
|
||||
});
|
||||
g_lua.registerMemberFunction("login", []{
|
||||
std::string accountPassword = g_lua.popString();
|
||||
std::string accountName = g_lua.popString();
|
||||
if(ProtocolLoginPtr protocolLogin = std::dynamic_pointer_cast<ProtocolLogin>(g_lua.popLuaObjectInstance()))
|
||||
protocolLogin->login(accountName, accountPassword);
|
||||
return 0;
|
||||
});
|
||||
g_lua.registerMemberFunction("cancel", []{
|
||||
//TODO: this func
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
|
23
src/framework/thirdparty/apngloader.h
vendored
Normal file
23
src/framework/thirdparty/apngloader.h
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef APNGLOADER_H
|
||||
#define APNGLOADER_H
|
||||
|
||||
#include <sstream>
|
||||
|
||||
struct apng_data {
|
||||
unsigned char *pdata;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int first_frame;
|
||||
unsigned int last_frame;
|
||||
unsigned char bpp;
|
||||
unsigned char coltype;
|
||||
unsigned int num_frames;
|
||||
unsigned int num_plays;
|
||||
unsigned int *frames_delay; // each frame delay in ms
|
||||
};
|
||||
|
||||
// returns -1 on error, 0 on success
|
||||
int load_apng(std::stringstream& file, struct apng_data *apng);
|
||||
void free_apng(struct apng_data *apng);
|
||||
|
||||
#endif
|
@@ -1,17 +1,12 @@
|
||||
#ifndef UI_H
|
||||
#define UI_H
|
||||
|
||||
#include <global.h>
|
||||
#include "uimanager.h"
|
||||
#include "uiwidget.h"
|
||||
#include "uibutton.h"
|
||||
#include "uilabel.h"
|
||||
#include "uilayout.h"
|
||||
#include "uilineedit.h"
|
||||
#include "uiwindow.h"
|
||||
|
||||
#include <ui/uiskins.h>
|
||||
#include <ui/uiloader.h>
|
||||
#include <ui/uielement.h>
|
||||
#include <ui/uielementskin.h>
|
||||
#include <ui/uicontainer.h>
|
||||
#include <ui/uibutton.h>
|
||||
#include <ui/uilabel.h>
|
||||
#include <ui/uiwindow.h>
|
||||
#include <ui/uitextedit.h>
|
||||
#include <ui/uicheckbox.h>
|
||||
|
||||
#endif // UI_H
|
||||
#endif
|
||||
|
44
src/framework/ui/uianchor.cpp
Normal file
44
src/framework/ui/uianchor.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#include "uianchor.h"
|
||||
#include "uiwidget.h"
|
||||
|
||||
UIAnchor::UIAnchor(const UIWidgetPtr& anchoredWidget, AnchorPoint anchoredEdge, const AnchorLine& anchorLine)
|
||||
: m_anchoredWidget(anchoredWidget), m_anchoredEdge(anchoredEdge), m_anchorLine(anchorLine) {
|
||||
}
|
||||
|
||||
UIWidgetPtr UIAnchor::getAnchorLineWidget() const {
|
||||
if(!m_anchoredWidget.expired() && !m_anchoredWidget.lock()->isDestroyed())
|
||||
return m_anchoredWidget.lock()->backwardsGetWidgetById(m_anchorLine.widgetId);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
UIWidgetPtr UIAnchor::getAnchoredWidget() const {
|
||||
return m_anchoredWidget.lock();
|
||||
}
|
||||
|
||||
AnchorPoint UIAnchor::getAnchoredEdge() const {
|
||||
return m_anchoredEdge;
|
||||
}
|
||||
|
||||
int UIAnchor::getAnchorLinePoint() const {
|
||||
UIWidgetPtr anchorLineWidget = getAnchorLineWidget();
|
||||
if(anchorLineWidget) {
|
||||
switch(m_anchorLine.edge) {
|
||||
case AnchorLeft:
|
||||
return anchorLineWidget->getGeometry().left();
|
||||
case AnchorRight:
|
||||
return anchorLineWidget->getGeometry().right();
|
||||
case AnchorTop:
|
||||
return anchorLineWidget->getGeometry().top();
|
||||
case AnchorBottom:
|
||||
return anchorLineWidget->getGeometry().bottom();
|
||||
case AnchorHorizontalCenter:
|
||||
return anchorLineWidget->getGeometry().horizontalCenter();
|
||||
case AnchorVerticalCenter:
|
||||
return anchorLineWidget->getGeometry().verticalCenter();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return -9999;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user