From d2b36e6c65ec8126c0ebc96adb7e011e78a5eacc Mon Sep 17 00:00:00 2001 From: Alexander Pickering Date: Tue, 1 Nov 2016 00:28:16 -0400 Subject: Initial commit --- src/client/callbackhandeler.cpp | 54 +++++ src/client/callbackhandeler.hpp | 22 ++ src/client/config.hpp | 1 + src/client/initdevice.cpp | 189 ++++++++++++++++ src/client/initdevice.hpp | 17 ++ src/client/lua_api/gameparts.hpp | 15 ++ src/client/lua_api/gui/iguibutton.cpp | 163 ++++++++++++++ src/client/lua_api/gui/iguibutton.hpp | 11 + src/client/lua_api/gui/iguielement.cpp | 93 ++++++++ src/client/lua_api/gui/iguielement.hpp | 15 ++ src/client/lua_api/gui/iguilabel.cpp | 128 +++++++++++ src/client/lua_api/gui/iguilabel.hpp | 11 + src/client/lua_api/guiparts.hpp | 29 +++ src/client/lua_api/load_core.cpp | 32 +++ src/client/lua_api/load_core.hpp | 14 ++ src/client/lua_api/load_game.cpp | 24 ++ src/client/lua_api/load_game.hpp | 14 ++ src/client/lua_api/load_gui.cpp | 69 ++++++ src/client/lua_api/load_gui.hpp | 14 ++ src/client/lua_api/scene/icamera.cpp | 124 ++++++++++ src/client/lua_api/scene/icamera.hpp | 11 + src/client/main.cpp | 93 ++++++++ src/client/menuhandeler.cpp | 31 +++ src/client/menuhandeler.hpp | 27 +++ src/client/util/hashmap.c | 397 +++++++++++++++++++++++++++++++++ src/client/util/hashmap.h | 81 +++++++ 26 files changed, 1679 insertions(+) create mode 100644 src/client/callbackhandeler.cpp create mode 100644 src/client/callbackhandeler.hpp create mode 100644 src/client/config.hpp create mode 100644 src/client/initdevice.cpp create mode 100644 src/client/initdevice.hpp create mode 100644 src/client/lua_api/gameparts.hpp create mode 100644 src/client/lua_api/gui/iguibutton.cpp create mode 100644 src/client/lua_api/gui/iguibutton.hpp create mode 100644 src/client/lua_api/gui/iguielement.cpp create mode 100644 src/client/lua_api/gui/iguielement.hpp create mode 100644 src/client/lua_api/gui/iguilabel.cpp create mode 100644 src/client/lua_api/gui/iguilabel.hpp create mode 100644 src/client/lua_api/guiparts.hpp create mode 100644 src/client/lua_api/load_core.cpp create mode 100644 src/client/lua_api/load_core.hpp create mode 100644 src/client/lua_api/load_game.cpp create mode 100644 src/client/lua_api/load_game.hpp create mode 100644 src/client/lua_api/load_gui.cpp create mode 100644 src/client/lua_api/load_gui.hpp create mode 100644 src/client/lua_api/scene/icamera.cpp create mode 100644 src/client/lua_api/scene/icamera.hpp create mode 100644 src/client/main.cpp create mode 100644 src/client/menuhandeler.cpp create mode 100644 src/client/menuhandeler.hpp create mode 100644 src/client/util/hashmap.c create mode 100644 src/client/util/hashmap.h (limited to 'src/client') diff --git a/src/client/callbackhandeler.cpp b/src/client/callbackhandeler.cpp new file mode 100644 index 0000000..f39f4ca --- /dev/null +++ b/src/client/callbackhandeler.cpp @@ -0,0 +1,54 @@ +#include +#include +#include +extern "C" { + #include + #include + #include +} +#include +#include + +#include "callbackhandeler.hpp" + +using namespace irr; +using namespace gui; +using namespace std; + +std::map > guifuncs; +//IrrlichtDevice* device; + +void registerguicallback(IGUIElement* element, EGUI_EVENT_TYPE event, void (*func)(irr::SEvent)){ + printf("Callback registered\n"); + guifuncs[element][event] = func; +} + + +GlobalEventReceiver::GlobalEventReceiver(IrrlichtDevice* d){ + //device = d; +} +bool GlobalEventReceiver::OnEvent(const SEvent& e){ + EEVENT_TYPE type = e.EventType; + switch (type){ + case EET_GUI_EVENT:{ + IGUIElement* caller = e.GUIEvent.Caller; + EGUI_EVENT_TYPE get = e.GUIEvent.EventType; + printf("detected gui event...\n"); + if ( + guifuncs.find(caller) != guifuncs.end() && + guifuncs[caller].find(get) != guifuncs[caller].end()){ + guifuncs[caller][get](e); + printf("sucessfully called a gui event\n"); + return true; + } + return false; + break; + } + case EET_MOUSE_INPUT_EVENT:{ + + } + default: + printf("Called an unknown event\n"); + return false; + } +} diff --git a/src/client/callbackhandeler.hpp b/src/client/callbackhandeler.hpp new file mode 100644 index 0000000..31c04f8 --- /dev/null +++ b/src/client/callbackhandeler.hpp @@ -0,0 +1,22 @@ +#include +#include +#include +extern "C" { + #include + #include + #include +} +#include + +using namespace irr; +using namespace gui; + +void registerguicallback(IGUIElement* element, EGUI_EVENT_TYPE event, void (*func)(irr::SEvent)); + + +class GlobalEventReceiver : public irr::IEventReceiver{ +public: + GlobalEventReceiver(IrrlichtDevice* d); + bool OnEvent(const irr::SEvent& e); +}; +//GlobalEventReceiver::GlobalEventReceiver(IrrlichtDevice* d); diff --git a/src/client/config.hpp b/src/client/config.hpp new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/client/config.hpp @@ -0,0 +1 @@ + diff --git a/src/client/initdevice.cpp b/src/client/initdevice.cpp new file mode 100644 index 0000000..814dd67 --- /dev/null +++ b/src/client/initdevice.cpp @@ -0,0 +1,189 @@ + +extern "C" { + #include + #include + #include +} +#include + +#include "initdevice.hpp" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +struct settings{ + u8 aa; + u8 bits; + E_DEVICE_TYPE dtype; + u32 adapter; + bool doublebuffer; + bool multithread; + E_DRIVER_TYPE driver; + bool fullscreen; + bool stencilbuffer; + bool stereobuffer; + bool performancetimers; + bool vsync; + dimension2d windowsize; + u8 zbuffer; +}; + +void parseSetting(const char* settingname, lua_State* L, settings* set){ + if(strcmp(settingname,"Anti Alias") == 0){ + if(lua_isnumber(L,-1)){ + set->aa = lua_tonumber(L,-1); + }else{ + printf("Setting \"Anti Alias\" must be a number.\n"); + } + }else if(strcmp(settingname,"Bits Per Pixel") == 0){ + if(lua_isnumber(L,-1)){ + set->bits = lua_tonumber(L,-1); + }else{ + printf("Setting \"Bits Per Pixel\" must be a number.\n"); + } + }else if(strcmp(settingname,"Device Type") == 0){ + if(lua_isstring(L,-1)){ + const char* dtn = lua_tostring(L,-1); + if(strcmp(dtn,"WIN32") == 0){ + set->dtype = irr::EIDT_WIN32; + }else if(strcmp(dtn,"WINCE") == 0){ + set->dtype = irr::EIDT_WINCE; + }else if(strcmp(dtn,"OSX") == 0){ + set->dtype = irr::EIDT_OSX; + }else if(strcmp(dtn,"X11") == 0){ + set->dtype = irr::EIDT_X11; + }else if(strcmp(dtn,"SDL") == 0){ + set->dtype = irr::EIDT_SDL; + }else if(strcmp(dtn,"CONSOLE") == 0){ + set->dtype = irr::EIDT_CONSOLE; + }else if(strcmp(dtn,"BEST") == 0){ + set->dtype = irr::EIDT_BEST; + } + }else{ + printf("Setting \"Device Type\" must be a string\n"); + } + }else if(strcmp(settingname,"Display Adapter") == 0){ + if(lua_isnumber(L,-1)){ + set->adapter = lua_tonumber(L,-1); + }else{ + printf("Setting \"Display Adapter\" must be a number\n"); + } + }else if(strcmp(settingname,"Double Buffer") == 0){ + if(lua_isboolean(L,-1)){ + set->doublebuffer = lua_toboolean(L,-1) == 1; + }else{ + printf("Setting \"Double Buffer\" must be a boolean\n"); + } + }else if(strcmp(settingname,"Multithreaded") == 0){ + if(lua_isboolean(L,-1)){ + set->multithread = lua_toboolean(L,-1) == 1; + }else{ + printf("Setting \"Multithreaded\" must be a boolean\n"); + } + }else if(strcmp(settingname,"Driver Type") == 0){ + if(lua_isstring(L,-1)){ + const char* dts = lua_tostring(L,-1); + if(strcmp(dts,"NULL") == 0){ + set->driver = EDT_NULL; + }else if(strcmp(dts,"SOFTWARE") == 0){ + set->driver = EDT_SOFTWARE; + }else if(strcmp(dts,"BURNINGS") == 0){ + set->driver = EDT_BURNINGSVIDEO; + }else if(strcmp(dts,"D3D8") == 0){ + set->driver = EDT_DIRECT3D8; + }else if(strcmp(dts,"D3D9") == 0){ + set->driver = EDT_DIRECT3D9; + }else if(strcmp(dts,"OPENGL") == 0){ + set->driver = EDT_OPENGL; + } + }else{ + printf("Setting \"Driver Type\" must be a string\n"); + } + }else if(strcmp(settingname,"Fullscreen") == 0){ + if(lua_isboolean(L,-1)){ + set->fullscreen = lua_toboolean(L,-1) == 1; + }else{ + printf("Setting \"Fullscreen\" must be a boolean\n"); + } + }else if(strcmp(settingname,"Stencil Buffer") == 0){ + if(lua_isboolean(L,-1)){ + set->stencilbuffer = lua_toboolean(L,-1) == 1; + }else{ + printf("Setting \"Stencil Buffer\" must be a boolean\n"); + } + }else if(strcmp(settingname,"Stereo Buffer") == 0){ + if(lua_isboolean(L,-1)){ + set->stereobuffer = lua_toboolean(L,-1) == 1; + }else{ + printf("Setting \"Stereo Buffer\" must be a boolean\n"); + } + }else if(strcmp(settingname,"VSync") == 0){ + if(lua_isboolean(L,-1)){ + set->vsync = lua_toboolean(L,-1) == 1; + }else{ + printf("Setting \"VSync\" must be a boolean\n"); + } + }else if(strcmp(settingname,"Window Width") == 0){ + if(lua_isnumber(L,-1)){ + set->windowsize.Width = lua_tonumber(L,-1); + }else{ + printf("Setting \"Window Width\" must be a number"); + } + }else if(strcmp(settingname,"Window Height") == 0){ + if(lua_isnumber(L,-1)){ + set->windowsize.Height = lua_tonumber(L,-1); + }else{ + printf("Setting \"Window Height\" must be a number"); + } + } +} + +void settingsFromTable(lua_State *L, SIrrlichtCreationParameters* p){ + lua_pushnil(L); + settings* set = (settings*)malloc(sizeof(settings)); + while(lua_next(L,-2) != 0){ + printf("%s - %s\n", + lua_typename(L, lua_type(L, -2)), + lua_typename(L, lua_type(L, -1))); + if(lua_isstring(L,-2)){ + const char* setstr = lua_tostring(L,-2); + printf("\tFound setting %s\n",setstr); + parseSetting(setstr,L,set); + }else{ + printf("\tFound a non-string setting key! Key is a %s\n",luaL_typename(L,-1)); + } + lua_pop(L,1); + } + p->AntiAlias = set->aa; + p->Bits = set->bits; + p->DeviceType = set->dtype; + p->DisplayAdapter = set->adapter; + p->DriverMultithreaded = set->multithread; + p->DriverType = set->driver; + p->Fullscreen = set->fullscreen; + p->Stencilbuffer = set->stencilbuffer; + p->Vsync = set->vsync; + p->WindowSize = set->windowsize; + p->ZBufferBits = set->zbuffer; + free(set); + printf("Settings loaded"); +} + +IrrlichtDevice* spawnIrrDevice(lua_State* L){ + printf("Attempting to load settings...\n"); + int iErr = luaL_dofile(L,"../data/deviceinit.lua"); + SIrrlichtCreationParameters p = SIrrlichtCreationParameters(); + settingsFromTable(L,&p); + if(iErr != 0){ + printf("Failed to open lua file:/data/deviceinit.lua\n"); + } + IrrlichtDevice* dev = createDeviceEx(p); + if(!dev) + exit(1); + dev->setWindowCaption(L"Borkengin"); + return dev; +} diff --git a/src/client/initdevice.hpp b/src/client/initdevice.hpp new file mode 100644 index 0000000..dd328f7 --- /dev/null +++ b/src/client/initdevice.hpp @@ -0,0 +1,17 @@ +#ifndef __H_BE_initdevice +#define __H_BE_initdevice +#include +extern "C" { + #include + #include + #include +} +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +IrrlichtDevice* spawnIrrDevice(lua_State* L); +#endif diff --git a/src/client/lua_api/gameparts.hpp b/src/client/lua_api/gameparts.hpp new file mode 100644 index 0000000..e6f02a1 --- /dev/null +++ b/src/client/lua_api/gameparts.hpp @@ -0,0 +1,15 @@ +extern "C" { + #include + #include + #include +} + +typedef struct LISceneNode { + irr::scene::ISceneNode* n; + map_t funcmap; + const char* type; +} LIGUIElement; + +extern lua_State* tL; +extern irr::IrrlichtDevice* gamedevice; +extern long nodenum; diff --git a/src/client/lua_api/gui/iguibutton.cpp b/src/client/lua_api/gui/iguibutton.cpp new file mode 100644 index 0000000..6c2fc5a --- /dev/null +++ b/src/client/lua_api/gui/iguibutton.cpp @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include +#include +#include +extern "C" { + #include + #include + #include +} +#include +#include "../guiparts.hpp" +#include "iguielement.hpp" +#include "../../callbackhandeler.hpp" +#include "../../util/hashmap.h" + +using namespace irr; +using namespace gui; + +IrrlichtDevice* device; +char lhashkey[20]; + +static LIGUIElement* checkiguibutton(lua_State* L, int index){ + void* ud = luaL_checkudata(L,index,"gui.iguibutton"); + luaL_argcheck(L,ud != NULL, index, "'gui.iguibutton' expected"); + return (LIGUIElement*) ud; +} + +static LIGUIElement* checkiguibutton(lua_State* L){ + return checkiguibutton(L,1); +} + +//The callback even for all gui buttons +static void iguibuttonevent(irr::SEvent e){ + IGUIElement* caller = (IGUIElement*)e.GUIEvent.Caller; + printf("Some gui something somewhere was pressed\n"); + if(iguielements.find(caller) != iguielements.end()){ + printf("I know what reference is linked to that button: %d!\n",iguielements[caller]); + int ref = iguielements[caller]; + EGUI_EVENT_TYPE etype = e.GUIEvent.EventType; + if(etype == EGET_BUTTON_CLICKED){ + lua_rawgeti(tL,LUA_REGISTRYINDEX,ref); + printf("getting raw, the thing on the top of stack is a %s\n",luaL_typename(tL,-1)); + LIGUIElement* tbut = checkiguibutton(tL,-1); + int hashmapresponse; + char* hashkey = (char*)"onpress"; + int terror = hashmap_get(tbut->funcmap,hashkey,(void**)&hashmapresponse); + if(terror == MAP_OK){ + lua_rawgeti(tL,LUA_REGISTRYINDEX,hashmapresponse); + lua_call(tL,0,0); + }else{ + printf("Tried to call onpress on something that dosen't have onpress\n"); + } + }else if(etype == EGET_ELEMENT_HOVERED){ + printf("Trying to call onhovered!\n"); + lua_rawgeti(tL,LUA_REGISTRYINDEX,ref); + LIGUIElement* tbut = (LIGUIElement*)lua_touserdata(tL,-1); + int hashmapresponse; + int terror = hashmap_get(tbut->funcmap,(char*)"onhovered",(void**)&hashmapresponse); + if(terror == MAP_OK){ + lua_rawgeti(tL,LUA_REGISTRYINDEX,hashmapresponse); + lua_call(tL,0,0); + } + } + } +} + +static int newiguibutton(lua_State* L){ + printf("Createing gui button!\n"); + //The position of the button + int startx = luaL_optint(L,1,0); + int starty = luaL_optint(L,2,0); + int endx = luaL_optint(L,3,startx+100); + int endy = luaL_optint(L,4,starty+100); + + //Label and tooltip + wchar_t* button_label; + wchar_t* button_tooltip; + const char* labelopt = luaL_optstring(L,5,"Button"); + const char* tooltipopt = luaL_optstring(L,6,"Tooltip"); + int bls = strlen(labelopt); + int bts = strlen(tooltipopt); + button_label = (wchar_t*)malloc(sizeof(wchar_t)*(bls)); + button_tooltip = (wchar_t*)malloc(sizeof(wchar_t)*(bts)); + mbstowcs(button_label,labelopt,bls+1); + mbstowcs(button_tooltip,tooltipopt,bts+1); + printf("Got the string options\n"); + + //If the element has a parrent + int parent = luaL_optint(L,7,0); + + //Create the button + IGUIEnvironment* env = device->getGUIEnvironment(); + IGUIButton* nbut = (IGUIButton*) env->addButton(core::rect(startx,starty,endx,endy), guielements[parent], gui_elenum++, button_label, button_tooltip); + + //Register it's callback + registerguicallback(nbut,EGET_BUTTON_CLICKED,iguibuttonevent); + printf("Finished registering callback\n"); + + //Create the lua representation of the button + LIGUIElement* lbut = (LIGUIElement*)lua_newuserdata(L, sizeof(LIGUIElement)); + + //Make it callbackable + int tref = luaL_ref(L,LUA_REGISTRYINDEX); + iguielements[nbut] = tref; + lua_rawgeti(L,LUA_REGISTRYINDEX,tref);//Put it back on the stack since luaL_ref pops the object. + + //Set it's metatable + luaL_getmetatable(L, "gui.iguibutton"); + lua_setmetatable(L, -2); + + //Create the struct + lbut->e = nbut; + lbut->funcmap = hashmap_new(); + lbut->type = "iguibutton"; + + //Free up anything made in the function + free(button_label); + free(button_tooltip); + + //Put it on top and return it + lua_rawgeti(L,LUA_REGISTRYINDEX,tref); + return 1; +} + +static const luaL_reg iguibutton_f[] = { + {"new", newiguibutton}, + {"gethandeler", guigethandeler}, + {"sethandeler", guisethandeler}, + {0,0}, +}; + +static const luaL_reg iguibutton_m[] = { + {"move", moveiguielement}, + {"settext", setiguitext}, + {"remove", removeiguielement}, + {0,0}, +}; + +int iguibutton_register(lua_State* L, IrrlichtDevice* d){ + device = d; + tL = L; + + luaL_newmetatable(L, "gui.iguibutton"); + + luaL_register(L,"iguibutton",iguibutton_f); + + lua_pushstring(L,"__index"); + lua_pushstring(L,"gethandeler"); + lua_gettable(L,-3); + lua_settable(L,-4); + + lua_pushstring(L,"__newindex"); + lua_pushstring(L,"sethandeler"); + lua_gettable(L,-3); + lua_settable(L,-4); + + luaL_register(L, NULL, iguibutton_m); + + return 1; +} diff --git a/src/client/lua_api/gui/iguibutton.hpp b/src/client/lua_api/gui/iguibutton.hpp new file mode 100644 index 0000000..4059767 --- /dev/null +++ b/src/client/lua_api/gui/iguibutton.hpp @@ -0,0 +1,11 @@ +#include +#include +#include +extern "C" { + #include + #include + #include +} +#include + +int iguibutton_register(lua_State* L, irr::IrrlichtDevice* d); diff --git a/src/client/lua_api/gui/iguielement.cpp b/src/client/lua_api/gui/iguielement.cpp new file mode 100644 index 0000000..cb395af --- /dev/null +++ b/src/client/lua_api/gui/iguielement.cpp @@ -0,0 +1,93 @@ +/*This file defines some things that all igui stuff can do*/ +extern "C" { + #include + #include + #include +} +#include +#include "../guiparts.hpp" + +using namespace irr; +using namespace core; + +static LIGUIElement* toiguielement(lua_State* L,int index){ + LIGUIElement* ret = (LIGUIElement*)lua_touserdata(L,index); + if(ret == NULL) + luaL_typerror(L,index,"LIGUIButton"); + return ret; +} + +static LIGUIElement* toiguielement(lua_State* L){ + return toiguielement(L,1); +} + +int moveiguielement(lua_State* L){ + LIGUIElement* ele = toiguielement(L,1); + int x = luaL_optint(L,2,0); + int y = luaL_optint(L,3,0); + ele->e->move(position2d(x,y)); + return 0; +} + +int setiguitext(lua_State* L){ + LIGUIElement* ele = toiguielement(L,1); + const char* str = luaL_optstring(L,2,""); + int size = strlen(str); + wchar_t* al = (wchar_t*)malloc(sizeof(wchar_t)*size); + mbstowcs(al,str,size); + ele->e->setText(al); + free(al); + return 0; +} + +int removeiguielement(lua_State* L){ + LIGUIElement* ele = toiguielement(L,1); + ele->e->remove(); + hashmap_free(ele->funcmap); + free(ele); + return 0; +} + +int guigethandeler(lua_State* L){ + printf("Called the get index handeler!\n"); + LIGUIElement* button = toiguielement(L); + if(!lua_isstring(L,2)){ + luaL_error(L,"index of iguibutton must be of type 'string'"); + } + const char* lstr = lua_tostring(L,2); + char* hashkey = (char*)malloc(sizeof(char)*strlen(lstr)); + strcpy(hashkey,lstr); + int ref; + if(hashmap_get(button->funcmap,hashkey,(void**)&ref) == MAP_OK){ + //We found the value in our hashmap! + lua_rawgeti(L,LUA_REGISTRYINDEX,ref); + return 1; + }else{ + //Could not find in hashmap, check parrent + lua_getglobal(L,button->type); + printf("Button's type is %s\n",button->type); + lua_getfield(L,-1,lstr); + return 1; + } +} + +int guisethandeler(lua_State* L){ + printf("Called the set index handeler\n"); + LIGUIElement* button = toiguielement(L); + if(!lua_isstring(L,2)){ + luaL_error(L,"index of iguibutton must be of type 'string'"); + } + const char* lstr = lua_tostring(L,2); + char* hashkey = (char*)malloc(sizeof(char)*strlen(lstr)); + strcpy(hashkey,lstr); + int oldref; + if(hashmap_get(button->funcmap,hashkey,(void**)&oldref) == MAP_OK){ + luaL_unref(L,LUA_REGISTRYINDEX,oldref); + hashmap_remove(button->funcmap,hashkey); + } + int ref = luaL_ref(L,LUA_REGISTRYINDEX); + if(hashmap_put(button->funcmap,hashkey,(void*)ref) != MAP_OK){ + luaL_error(L,"Error while setting the hashkey on iguibutton"); + } + return 0; +} diff --git a/src/client/lua_api/gui/iguielement.hpp b/src/client/lua_api/gui/iguielement.hpp new file mode 100644 index 0000000..5756a34 --- /dev/null +++ b/src/client/lua_api/gui/iguielement.hpp @@ -0,0 +1,15 @@ + +#include +#include +extern "C" { + #include + #include + #include +} +#include + +int moveiguielement(lua_State* L); +int setiguitext(lua_State* L); +int removeiguielement(lua_State* L); +int guigethandeler(lua_State* L); +int guisethandeler(lua_State* L); diff --git a/src/client/lua_api/gui/iguilabel.cpp b/src/client/lua_api/gui/iguilabel.cpp new file mode 100644 index 0000000..da720f9 --- /dev/null +++ b/src/client/lua_api/gui/iguilabel.cpp @@ -0,0 +1,128 @@ + +#include +#include +#include +#include +#include +#include +extern "C" { + #include + #include + #include +} +#include +#include "../guiparts.hpp" +#include "iguielement.hpp" +#include "../../callbackhandeler.hpp" + +using namespace irr; +using namespace gui; + +//IrrlichtDevice* guidevice; + +static LIGUIElement* checkiguilabel(lua_State* L, int index){ + void* ud = luaL_checkudata(L,index,"gui.iguilabel"); + luaL_argcheck(L,ud != NULL, index, "'gui.iguilabel' expected"); + return (LIGUIElement*) ud; +} + +static LIGUIElement* checkiguilabel(lua_State* L){ + return checkiguilabel(L,1); +} + +static void iguilabelevent(irr::SEvent e){ + printf("Oh no! an iguilabel generated an event!"); +} + +static int newiguilabel(lua_State* L){ + printf("Createing label!\n"); + int nargs = lua_gettop(L); + //The position of the text + int startx = luaL_optint(L,1,0); + int starty = luaL_optint(L,2,0); + int endx = luaL_optint(L,3,startx+100); + int endy = luaL_optint(L,4,starty+100); + + //Label and tooltip + wchar_t* label; + const char* labelopt = luaL_optstring(L,5,"Label"); + int bls = strlen(labelopt); + label = (wchar_t*)malloc(sizeof(wchar_t)*(bls)); + mbstowcs(label,labelopt,bls); + printf("Got the string option\n"); + + //If the element has a parrent + int parent = 0; + if(nargs >= 6){ + parent = luaL_optint(L,6,0); + printf("got the parrent\n"); + } + + + //Create the button + IGUIEnvironment* env = guidevice->getGUIEnvironment(); + //printf("Createing button with data %d %d %d %d, %p, %d, %s, %s\n", startx,starty,endx,endy,guielements[parent],gui_elenum,button_label,button_tooltip); + //Create the label + IGUIStaticText* llabel = (IGUIStaticText*) env->addStaticText(label,core::rect(startx,starty,endx,endy),false,false, guielements[parent], gui_elenum++, false); + printf("Created the button\n"); + + //Register it's callback + registerguicallback(llabel,EGET_ELEMENT_HOVERED,iguilabelevent); + + //Create it's lua representation + LIGUIElement* ltext = (LIGUIElement*)lua_newuserdata(L, sizeof(LIGUIElement)); + int tref = luaL_ref(L,LUA_REGISTRYINDEX); + iguielements[llabel] = tref; + lua_rawgeti(L,LUA_REGISTRYINDEX,tref);//Put it back on the stack since luaL_ref pops the object. + + //Set it's metatable + luaL_getmetatable(L, "gui.iguilabel"); + lua_setmetatable(L, -2); + + //Create the struct + ltext->e = llabel; + ltext->funcmap = hashmap_new(); + ltext->type = "iguilabel"; + + //Free up anything made in this function + free(label); + + //Put it on top and return it + lua_rawgeti(L,LUA_REGISTRYINDEX,tref); + return 1; +} + +static const luaL_reg iguilabel_f[] = { + {"new", newiguilabel}, + {"gethandeler", guigethandeler}, + {"sethandeler", guisethandeler}, + {0,0}, +}; + +static const luaL_reg iguilabel_m[] = { + {"move", moveiguielement}, + {"settext", setiguitext}, + {"remove", removeiguielement}, + {0, 0}, +}; + +int iguilabel_register(lua_State* L, IrrlichtDevice* d){ + + luaL_newmetatable(L, "gui.iguilabel"); + + luaL_register(L,"iguilabel",iguilabel_f); + + lua_pushstring(L,"__index"); + lua_pushstring(L,"gethandeler"); + lua_gettable(L,-3); + lua_settable(L,-4); + + lua_pushstring(L,"__newindex"); + lua_pushstring(L,"sethandeler"); + lua_gettable(L,-3); + lua_settable(L,-4); + + luaL_register(L, NULL, iguilabel_m); + + return 1; +} diff --git a/src/client/lua_api/gui/iguilabel.hpp b/src/client/lua_api/gui/iguilabel.hpp new file mode 100644 index 0000000..c779c70 --- /dev/null +++ b/src/client/lua_api/gui/iguilabel.hpp @@ -0,0 +1,11 @@ + +#include +#include +extern "C" { + #include + #include + #include +} +#include + +int iguilabel_register(lua_State* L, irr::IrrlichtDevice* d); diff --git a/src/client/lua_api/guiparts.hpp b/src/client/lua_api/guiparts.hpp new file mode 100644 index 0000000..fba3862 --- /dev/null +++ b/src/client/lua_api/guiparts.hpp @@ -0,0 +1,29 @@ +#ifndef __H_guiparts +#define __H_guiparts +#include +#include +#include +#include +#include +extern "C" { + #include + #include + #include +} +#include +#include "../util/hashmap.h" + + +typedef struct LIGUIElement { + irr::gui::IGUIElement* e; + map_t funcmap; + const char* type; +} LIGUIElement; + + +extern lua_State* tL; +extern irr::IrrlichtDevice* guidevice; +extern long gui_elenum; +extern std::vector guielements; +extern std::map iguielements; +#endif diff --git a/src/client/lua_api/load_core.cpp b/src/client/lua_api/load_core.cpp new file mode 100644 index 0000000..910115f --- /dev/null +++ b/src/client/lua_api/load_core.cpp @@ -0,0 +1,32 @@ +#include +#include +#include +#include +extern "C" { + #include + #include + #include +} +#include + +int makevector(lua_State* L){ + lua_newtable(L); + + lua_pushstring("x"); + lua_optint(L,1,0); + lua_settable(L,-2); + + lua_pushstring("y"); + lua_optint(L,2,0); + lua_settable(L,-2); + + lua_pushstring("z"); + lua_optint(L,3,0); + lua_settable(L,-2); + +} + +void load_corefuncs(lua_State* L, IrrlichtDevice* d){ + lua_newtable(L); + lua_setglobal(L,"GAME"); +} diff --git a/src/client/lua_api/load_core.hpp b/src/client/lua_api/load_core.hpp new file mode 100644 index 0000000..641ca08 --- /dev/null +++ b/src/client/lua_api/load_core.hpp @@ -0,0 +1,14 @@ +#ifndef __H_loadgame +#define __H_loadgame +#include +#include +#include +extern "C" { + #include + #include + #include +} +#include + +void load_corefuncs(lua_State* L, IrrlichtDevice* device); +#endif diff --git a/src/client/lua_api/load_game.cpp b/src/client/lua_api/load_game.cpp new file mode 100644 index 0000000..fb51595 --- /dev/null +++ b/src/client/lua_api/load_game.cpp @@ -0,0 +1,24 @@ +#include +#include +#include +#include +extern "C" { + #include + #include + #include +} +#include + +#include "gui/iguibutton.hpp" +#include "gui/iguilabel.hpp" +#include "../callbackhandeler.hpp" +#include "guiparts.hpp" + +using namespace irr; +using namespace gui; +using namespace core; + +void load_gamefuncs(lua_State* L, IrrlichtDevice* d){ + lua_newtable(L); + lua_setglobal(L,"GAME"); +} diff --git a/src/client/lua_api/load_game.hpp b/src/client/lua_api/load_game.hpp new file mode 100644 index 0000000..f20e0c6 --- /dev/null +++ b/src/client/lua_api/load_game.hpp @@ -0,0 +1,14 @@ +#ifndef __H_loadgame +#define __H_loadgame +#include +#include +#include +extern "C" { + #include + #include + #include +} +#include + +void load_gamefuncs(lua_State* L, IrrlichtDevice* device); +#endif diff --git a/src/client/lua_api/load_gui.cpp b/src/client/lua_api/load_gui.cpp new file mode 100644 index 0000000..ed7faac --- /dev/null +++ b/src/client/lua_api/load_gui.cpp @@ -0,0 +1,69 @@ +#include +#include +#include +#include +extern "C" { + #include + #include + #include +} +#include + +#include "gui/iguibutton.hpp" +#include "gui/iguilabel.hpp" +#include "../callbackhandeler.hpp" +#include "guiparts.hpp" + +using namespace irr; +using namespace gui; +using namespace core; + +//Things from guiparts.hpp +std::map iguielements; +IrrlichtDevice* guidevice; +long gui_elenum; +std::vector guielements(1); +lua_State* tL; + +int screenwidth(lua_State* L); +int screenheight(lua_State* L); + +void load_guifuncs(lua_State* L, IrrlichtDevice* d){ + tL = L; + guidevice = d; + gui_elenum = 0; + guielements[0] = NULL; + printf("About to initalize guielements vector\n"); + printf("Done initalizeing guilements vector\n"); + + iguibutton_register(L,d); + iguilabel_register(L,d); + lua_pop(L, 1); + + lua_newtable(L); + //lua_pushcfunction(L,createiguibutton); + //lua_setfield(L,-2,"createButton"); + lua_setglobal(L,"gui"); + + lua_pushcfunction(L,screenwidth); + lua_setglobal(L,"scrw"); + + lua_pushcfunction(L,screenheight); + lua_setglobal(L,"scrh"); + +} + + +int screenheight(lua_State* L){ + core::rect dim = guidevice->getGUIEnvironment()->getRootGUIElement()->getAbsoluteClippingRect(); + lua_pushnumber(L,dim.getHeight()); + printf("Got screen height:%d\n",dim.getWidth()); + return 1; +} + +int screenwidth(lua_State* L){ + core::rect dim = guidevice->getGUIEnvironment()->getRootGUIElement()->getAbsoluteClippingRect(); + lua_pushnumber(L,dim.getWidth()); + printf("Got screen width:%d\n",dim.getWidth()); + return 1; +} diff --git a/src/client/lua_api/load_gui.hpp b/src/client/lua_api/load_gui.hpp new file mode 100644 index 0000000..eb76634 --- /dev/null +++ b/src/client/lua_api/load_gui.hpp @@ -0,0 +1,14 @@ +#ifndef __H_loadgui +#define __H_loadgui +#include +#include +#include +extern "C" { + #include + #include + #include +} +#include + +void load_guifuncs(lua_State* L, IrrlichtDevice* device); +#endif diff --git a/src/client/lua_api/scene/icamera.cpp b/src/client/lua_api/scene/icamera.cpp new file mode 100644 index 0000000..2dd5a67 --- /dev/null +++ b/src/client/lua_api/scene/icamera.cpp @@ -0,0 +1,124 @@ + +#include +#include +#include +#include +#include +#include +extern "C" { + #include + #include + #include +} +#include +#include "../gameparts.hpp" +#include "icamera.hpp" + +using namespace irr; +using namespace scene; + +//IrrlichtDevice* guidevice; + +static LISceneNode* checkiscenecamera(lua_State* L, int index){ + void* ud = luaL_checkudata(L,index,"scene.icamera"); + luaL_argcheck(L,ud != NULL, index, "'scene.icamera' expected"); + return (LISceneNode*) ud; +} + +static LISceneNode* checkiscenecamera(lua_State* L){ + return checkiscenecamera(L,1); +} + +//iscenecamera.new(Vector position, Vector lookat, parrent) +static int newiscenecamera(lua_State* L){ + printf("Createing camera!\n"); + int nargs = lua_gettop(L); + //The position of the camera + int startx = luaL_optint(L,1,0); + int starty = luaL_optint(L,2,0); + int endx = luaL_optint(L,3,startx+100); + int endy = luaL_optint(L,4,starty+100); + + //Label and tooltip + wchar_t* label; + const char* labelopt = luaL_optstring(L,5,"Label"); + int bls = strlen(labelopt); + label = (wchar_t*)malloc(sizeof(wchar_t)*(bls)); + mbstowcs(label,labelopt,bls); + printf("Got the string option\n"); + + //If the element has a parrent + int parent = 0; + if(nargs >= 6){ + parent = luaL_optint(L,6,0); + printf("got the parrent\n"); + } + + + //Create the button + IGUIEnvironment* env = guidevice->getGUIEnvironment(); + //printf("Createing button with data %d %d %d %d, %p, %d, %s, %s\n", startx,starty,endx,endy,guielements[parent],gui_elenum,button_label,button_tooltip); + //Create the label + IGUIStaticText* llabel = (IGUIStaticText*) env->addStaticText(label,core::rect(startx,starty,endx,endy),false,false, guielements[parent], gui_elenum++, false); + printf("Created the button\n"); + + //Register it's callback + registerguicallback(llabel,EGET_ELEMENT_HOVERED,iguilabelevent); + + //Create it's lua representation + LIGUIElement* ltext = (LIGUIElement*)lua_newuserdata(L, sizeof(LIGUIElement)); + int tref = luaL_ref(L,LUA_REGISTRYINDEX); + iguielements[llabel] = tref; + lua_rawgeti(L,LUA_REGISTRYINDEX,tref);//Put it back on the stack since luaL_ref pops the object. + + //Set it's metatable + luaL_getmetatable(L, "gui.iguilabel"); + lua_setmetatable(L, -2); + + //Create the struct + ltext->e = llabel; + ltext->funcmap = hashmap_new(); + ltext->type = "iguilabel"; + + //Free up anything made in this function + free(label); + + //Put it on top and return it + lua_rawgeti(L,LUA_REGISTRYINDEX,tref); + return 1; +} + +static const luaL_reg iguilabel_f[] = { + {"new", newiguilabel}, + {"gethandeler", guigethandeler}, + {"sethandeler", guisethandeler}, + {0,0}, +}; + +static const luaL_reg iguilabel_m[] = { + {"move", moveiguielement}, + {"settext", setiguitext}, + {"remove", removeiguielement}, + {0, 0}, +}; + +int iguilabel_register(lua_State* L, IrrlichtDevice* d){ + + luaL_newmetatable(L, "gui.iguilabel"); + + luaL_register(L,"iguilabel",iguilabel_f); + + lua_pushstring(L,"__index"); + lua_pushstring(L,"gethandeler"); + lua_gettable(L,-3); + lua_settable(L,-4); + + lua_pushstring(L,"__newindex"); + lua_pushstring(L,"sethandeler"); + lua_gettable(L,-3); + lua_settable(L,-4); + + luaL_register(L, NULL, iguilabel_m); + + return 1; +} diff --git a/src/client/lua_api/scene/icamera.hpp b/src/client/lua_api/scene/icamera.hpp new file mode 100644 index 0000000..15525f8 --- /dev/null +++ b/src/client/lua_api/scene/icamera.hpp @@ -0,0 +1,11 @@ + +#include +#include +extern "C" { + #include + #include + #include +} +#include + +int icamera_register(lua_State* L, irr::IrrlichtDevice* d); diff --git a/src/client/main.cpp b/src/client/main.cpp new file mode 100644 index 0000000..4e284c5 --- /dev/null +++ b/src/client/main.cpp @@ -0,0 +1,93 @@ +#include +#include +extern "C" { + #include + #include + #include +} +#include + +#include +#include + +#include "initdevice.hpp" +#include "menuhandeler.hpp" +#include "lua_api/load_gui.hpp" +#include "lua_api/load_game.hpp" +#include "callbackhandeler.hpp" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +void loadLLibs(lua_State* L){ + luaopen_base(L); + luaopen_table(L); + luaopen_io(L); + luaopen_string(L); + luaopen_math(L); +} + +void loadIrrLibs(lua_State* L, IrrlichtDevice* device){ + printf("Loading guifuncs...\n"); + load_guifuncs(L,device); + load_gamefuncs(L,device); +} + +int main(int argc, char *argv[]){ + //Create a new lua state, this gets shared everywhere + lua_State *state = luaL_newstate(); + //Load the lua libraries + loadLLibs(state); + //Defined in initdevice.cpp, creates the irrlicht device + IrrlichtDevice *device = spawnIrrDevice(state); + if (!device) + return 1; + //Loads libraries for interfaceing with irrlicht + loadIrrLibs(state,device); + printf("Loadded irr libs...\n"); + //Sets the global event handeler + GlobalEventReceiver ger = GlobalEventReceiver(device); + device->setEventReceiver(&ger); + int iErr = luaL_dofile(state,"../data/guitest.lua"); + if(iErr != 0){ + lua_error(state); + printf("Failed to open lua file:../data/guitest.lua\n"); + } + + + + device->setWindowCaption(L"Bork[en]gine Demo"); + + //Load some menu + loadMenu("Some menu",device); + + IVideoDriver* driver = device->getVideoDriver(); + ISceneManager* smgr = device->getSceneManager(); + IGUIEnvironment* guienv = device->getGUIEnvironment(); + + guienv->addStaticText(L"Hello World! This is the Irrlicht Software renderer!", + rect(10,10,260,22), true); + + smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0)); + + printf("Everything registered, about to start running device!\n"); + + while(device->run()){ + driver->beginScene(true, true, SColor(255,100,101,140)); + + smgr->drawAll(); + guienv->drawAll(); + + driver->endScene(); + lua_getglobal(state,"GAME"); + lua_getfield(state,-1,"tick"); + if(!lua_isnil(state,-1)) + lua_call(state,0,0); + } + lua_close(state); + return 0; +} diff --git a/src/client/menuhandeler.cpp b/src/client/menuhandeler.cpp new file mode 100644 index 0000000..830c695 --- /dev/null +++ b/src/client/menuhandeler.cpp @@ -0,0 +1,31 @@ +extern "C" { + #include + #include + #include +} +#include + +#include "initdevice.hpp" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +void loadMenu(const char* name, IrrlichtDevice* device){ + +} + +void showMenu(const char* name, IrrlichtDevice* device){ + +} + +void hideMenu(const char* name, IrrlichtDevice* device){ + +} + +void dropMenu(const char* name, IrrlichtDevice* device){ + +} diff --git a/src/client/menuhandeler.hpp b/src/client/menuhandeler.hpp new file mode 100644 index 0000000..914335f --- /dev/null +++ b/src/client/menuhandeler.hpp @@ -0,0 +1,27 @@ +#ifndef __H_BE_menuhandeler +#define __H_BE_menuhandeler +extern "C" { + #include + #include + #include +} +#include + +#include "initdevice.hpp" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +void loadMenu(const char* name, IrrlichtDevice* device); + +void showMenu(const char* name, IrrlichtDevice* device); + +void hideMenu(const char* name, IrrlichtDevice* device); + +void dropMenu(const char* name, IrrlichtDevice* device); + +#endif diff --git a/src/client/util/hashmap.c b/src/client/util/hashmap.c new file mode 100644 index 0000000..f91e743 --- /dev/null +++ b/src/client/util/hashmap.c @@ -0,0 +1,397 @@ +/* + * Generic map implementation. + */ +#include "hashmap.h" + +#include +#include +#include + +#define INITIAL_SIZE (256) +#define MAX_CHAIN_LENGTH (8) + +/* We need to keep keys and values */ +typedef struct _hashmap_element{ + char* key; + int in_use; + any_t data; +} hashmap_element; + +/* A hashmap has some maximum size and current size, + * as well as the data to hold. */ +typedef struct _hashmap_map{ + int table_size; + int size; + hashmap_element *data; +} hashmap_map; + +/* + * Return an empty hashmap, or NULL on failure. + */ +map_t hashmap_new() { + hashmap_map* m = (hashmap_map*) malloc(sizeof(hashmap_map)); + if(!m) goto err; + + m->data = (hashmap_element*) calloc(INITIAL_SIZE, sizeof(hashmap_element)); + if(!m->data) goto err; + + m->table_size = INITIAL_SIZE; + m->size = 0; + + return m; + err: + if (m) + hashmap_free(m); + return NULL; +} + +/* The implementation here was originally done by Gary S. Brown. I have + borrowed the tables directly, and made some minor changes to the + crc32-function (including changing the interface). //ylo */ + + /* ============================================================= */ + /* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or */ + /* code or tables extracted from it, as desired without restriction. */ + /* */ + /* First, the polynomial itself and its table of feedback terms. The */ + /* polynomial is */ + /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ + /* */ + /* Note that we take it "backwards" and put the highest-order term in */ + /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ + /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ + /* the MSB being 1. */ + /* */ + /* Note that the usual hardware shift register implementation, which */ + /* is what we're using (we're merely optimizing it by doing eight-bit */ + /* chunks at a time) shifts bits into the lowest-order term. In our */ + /* implementation, that means shifting towards the right. Why do we */ + /* do it this way? Because the calculated CRC must be transmitted in */ + /* order from highest-order term to lowest-order term. UARTs transmit */ + /* characters in order from LSB to MSB. By storing the CRC this way, */ + /* we hand it to the UART in the order low-byte to high-byte; the UART */ + /* sends each low-bit to hight-bit; and the result is transmission bit */ + /* by bit from highest- to lowest-order term without requiring any bit */ + /* shuffling on our part. Reception works similarly. */ + /* */ + /* The feedback terms table consists of 256, 32-bit entries. Notes: */ + /* */ + /* The table can be generated at runtime if desired; code to do so */ + /* is shown later. It might not be obvious, but the feedback */ + /* terms simply represent the results of eight shift/xor opera- */ + /* tions for all combinations of data and CRC register values. */ + /* */ + /* The values must be right-shifted by eight bits by the "updcrc" */ + /* logic; the shift must be unsigned (bring in zeroes). On some */ + /* hardware you could probably optimize the shift in assembler by */ + /* using byte-swap instructions. */ + /* polynomial $edb88320 */ + /* */ + /* -------------------------------------------------------------------- */ + +static unsigned long crc32_tab[] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL + }; + +/* Return a 32-bit CRC of the contents of the buffer. */ + +unsigned long crc32(const unsigned char *s, unsigned int len) +{ + unsigned int i; + unsigned long crc32val; + + crc32val = 0; + for (i = 0; i < len; i ++) + { + crc32val = + crc32_tab[(crc32val ^ s[i]) & 0xff] ^ + (crc32val >> 8); + } + return crc32val; +} + +/* + * Hashing function for a string + */ +unsigned int hashmap_hash_int(hashmap_map * m, char* keystring){ + + unsigned long key = crc32((unsigned char*)(keystring), strlen(keystring)); + + /* Robert Jenkins' 32 bit Mix Function */ + key += (key << 12); + key ^= (key >> 22); + key += (key << 4); + key ^= (key >> 9); + key += (key << 10); + key ^= (key >> 2); + key += (key << 7); + key ^= (key >> 12); + + /* Knuth's Multiplicative Method */ + key = (key >> 3) * 2654435761; + + return key % m->table_size; +} + +/* + * Return the integer of the location in data + * to store the point to the item, or MAP_FULL. + */ +int hashmap_hash(map_t in, char* key){ + int curr; + int i; + + /* Cast the hashmap */ + hashmap_map* m = (hashmap_map *) in; + + /* If full, return immediately */ + if(m->size >= (m->table_size/2)) return MAP_FULL; + + /* Find the best index */ + curr = hashmap_hash_int(m, key); + + /* Linear probing */ + for(i = 0; i< MAX_CHAIN_LENGTH; i++){ + if(m->data[curr].in_use == 0) + return curr; + + if(m->data[curr].in_use == 1 && (strcmp(m->data[curr].key,key)==0)) + return curr; + + curr = (curr + 1) % m->table_size; + } + + return MAP_FULL; +} + +/* + * Doubles the size of the hashmap, and rehashes all the elements + */ +int hashmap_rehash(map_t in){ + int i; + int old_size; + hashmap_element* curr; + + /* Setup the new elements */ + hashmap_map *m = (hashmap_map *) in; + hashmap_element* temp = (hashmap_element *) + calloc(2 * m->table_size, sizeof(hashmap_element)); + if(!temp) return MAP_OMEM; + + /* Update the array */ + curr = m->data; + m->data = temp; + + /* Update the size */ + old_size = m->table_size; + m->table_size = 2 * m->table_size; + m->size = 0; + + /* Rehash the elements */ + for(i = 0; i < old_size; i++){ + int status; + + if (curr[i].in_use == 0) + continue; + + status = hashmap_put(m, curr[i].key, curr[i].data); + if (status != MAP_OK) + return status; + } + + free(curr); + + return MAP_OK; +} + +/* + * Add a pointer to the hashmap with some key + */ +int hashmap_put(map_t in, char* key, any_t value){ + int index; + hashmap_map* m; + + /* Cast the hashmap */ + m = (hashmap_map *) in; + + /* Find a place to put our value */ + index = hashmap_hash(in, key); + while(index == MAP_FULL){ + if (hashmap_rehash(in) == MAP_OMEM) { + return MAP_OMEM; + } + index = hashmap_hash(in, key); + } + + /* Set the data */ + m->data[index].data = value; + m->data[index].key = key; + m->data[index].in_use = 1; + m->size++; + + return MAP_OK; +} + +/* + * Get your pointer out of the hashmap with a key + */ +int hashmap_get(map_t in, char* key, any_t *arg){ + int curr; + int i; + hashmap_map* m; + + /* Cast the hashmap */ + m = (hashmap_map *) in; + + /* Find data location */ + curr = hashmap_hash_int(m, key); + + /* Linear probing, if necessary */ + for(i = 0; idata[curr].in_use; + if (in_use == 1){ + if (strcmp(m->data[curr].key,key)==0){ + *arg = (m->data[curr].data); + return MAP_OK; + } + } + + curr = (curr + 1) % m->table_size; + } + + *arg = NULL; + + /* Not found */ + return MAP_MISSING; +} + +/* + * Iterate the function parameter over each element in the hashmap. The + * additional any_t argument is passed to the function as its first + * argument and the hashmap element is the second. + */ +int hashmap_iterate(map_t in, PFany f, any_t item) { + int i; + + /* Cast the hashmap */ + hashmap_map* m = (hashmap_map*) in; + + /* On empty hashmap, return immediately */ + if (hashmap_length(m) <= 0) + return MAP_MISSING; + + /* Linear probing */ + for(i = 0; i< m->table_size; i++) + if(m->data[i].in_use != 0) { + any_t data = (any_t) (m->data[i].data); + int status = f(item, data); + if (status != MAP_OK) { + return status; + } + } + + return MAP_OK; +} + +/* + * Remove an element with that key from the map + */ +int hashmap_remove(map_t in, char* key){ + int i; + int curr; + hashmap_map* m; + + /* Cast the hashmap */ + m = (hashmap_map *) in; + + /* Find key */ + curr = hashmap_hash_int(m, key); + + /* Linear probing, if necessary */ + for(i = 0; idata[curr].in_use; + if (in_use == 1){ + if (strcmp(m->data[curr].key,key)==0){ + /* Blank out the fields */ + m->data[curr].in_use = 0; + m->data[curr].data = NULL; + m->data[curr].key = NULL; + + /* Reduce the size */ + m->size--; + return MAP_OK; + } + } + curr = (curr + 1) % m->table_size; + } + + /* Data not found */ + return MAP_MISSING; +} + +/* Deallocate the hashmap */ +void hashmap_free(map_t in){ + hashmap_map* m = (hashmap_map*) in; + free(m->data); + free(m); +} + +/* Return the length of the hashmap */ +int hashmap_length(map_t in){ + hashmap_map* m = (hashmap_map *) in; + if(m != NULL) return m->size; + else return 0; +} diff --git a/src/client/util/hashmap.h b/src/client/util/hashmap.h new file mode 100644 index 0000000..16c76dd --- /dev/null +++ b/src/client/util/hashmap.h @@ -0,0 +1,81 @@ +/* + * Generic hashmap manipulation functions + * + * Originally by Elliot C Back - http://elliottback.com/wp/hashmap-implementation-in-c/ + * + * Modified by Pete Warden to fix a serious performance problem, support strings as keys + * and removed thread synchronization - http://petewarden.typepad.com + */ +#ifndef __HASHMAP_H__ +#define __HASHMAP_H__ + +#define MAP_MISSING -3 /* No such element */ +#define MAP_FULL -2 /* Hashmap is full */ +#define MAP_OMEM -1 /* Out of Memory */ +#define MAP_OK 0 /* OK */ + +/* + * any_t is a pointer. This allows you to put arbitrary structures in + * the hashmap. + */ +typedef void *any_t; + +/* + * PFany is a pointer to a function that can take two any_t arguments + * and return an integer. Returns status code.. + */ +typedef int (*PFany)(any_t, any_t); + +/* + * map_t is a pointer to an internally maintained data structure. + * Clients of this package do not need to know how hashmaps are + * represented. They see and manipulate only map_t's. + */ +typedef any_t map_t; + +/* + * Return an empty hashmap. Returns NULL if empty. +*/ +extern map_t hashmap_new(); + +/* + * Iteratively call f with argument (item, data) for + * each element data in the hashmap. The function must + * return a map status code. If it returns anything other + * than MAP_OK the traversal is terminated. f must + * not reenter any hashmap functions, or deadlock may arise. + */ +extern int hashmap_iterate(map_t in, PFany f, any_t item); + +/* + * Add an element to the hashmap. Return MAP_OK or MAP_OMEM. + */ +extern int hashmap_put(map_t in, char* key, any_t value); + +/* + * Get an element from the hashmap. Return MAP_OK or MAP_MISSING. + */ +extern int hashmap_get(map_t in, char* key, any_t *arg); + +/* + * Remove an element from the hashmap. Return MAP_OK or MAP_MISSING. + */ +extern int hashmap_remove(map_t in, char* key); + +/* + * Get any element. Return MAP_OK or MAP_MISSING. + * remove - should the element be removed from the hashmap + */ +extern int hashmap_get_one(map_t in, any_t *arg, int remove); + +/* + * Free the hashmap + */ +extern void hashmap_free(map_t in); + +/* + * Get the current size of a hashmap + */ +extern int hashmap_length(map_t in); + +#endif //__HASHMAP_H__ -- cgit v1.2.3-70-g09d2