mirror of
https://github.com/godotengine/godot.git
synced 2024-11-21 11:32:13 +00:00
GODOT IS OPEN SOURCE
This commit is contained in:
parent
0e49da1687
commit
0b806ee0fc
301
SConstruct
Normal file
301
SConstruct
Normal file
@ -0,0 +1,301 @@
|
||||
EnsureSConsVersion(0,14);
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import glob
|
||||
import sys
|
||||
import methods
|
||||
|
||||
methods.update_version()
|
||||
|
||||
# scan possible build platforms
|
||||
|
||||
platform_list = [] # list of platforms
|
||||
platform_opts = {} # options for each platform
|
||||
platform_flags = {} # flags for each platform
|
||||
|
||||
|
||||
active_platforms=[]
|
||||
active_platform_ids=[]
|
||||
platform_exporters=[]
|
||||
global_defaults=[]
|
||||
|
||||
for x in glob.glob("platform/*"):
|
||||
if (not os.path.isdir(x)):
|
||||
continue
|
||||
tmppath="./"+x
|
||||
|
||||
sys.path.append(tmppath)
|
||||
import detect
|
||||
|
||||
if (os.path.exists(x+"/export/export.cpp")):
|
||||
platform_exporters.append(x[9:])
|
||||
if (os.path.exists(x+"/globals/global_defaults.cpp")):
|
||||
global_defaults.append(x[9:])
|
||||
if (detect.is_active()):
|
||||
active_platforms.append( detect.get_name() )
|
||||
active_platform_ids.append(x);
|
||||
if (detect.can_build()):
|
||||
x=x.replace("platform/","") # rest of world
|
||||
x=x.replace("platform\\","") # win32
|
||||
platform_list+=[x]
|
||||
platform_opts[x]=detect.get_opts()
|
||||
platform_flags[x]=detect.get_flags()
|
||||
sys.path.remove(tmppath)
|
||||
sys.modules.pop('detect')
|
||||
|
||||
module_list=methods.detect_modules()
|
||||
|
||||
|
||||
print "Detected Platforms: "+str(platform_list)
|
||||
print("Detected Modules: "+str(module_list))
|
||||
|
||||
methods.save_active_platforms(active_platforms,active_platform_ids)
|
||||
|
||||
custom_tools=['default']
|
||||
|
||||
if (os.name=="posix"):
|
||||
pass
|
||||
elif (os.name=="nt"):
|
||||
if (os.getenv("VSINSTALLDIR")==None):
|
||||
custom_tools=['mingw']
|
||||
|
||||
env_base=Environment(tools=custom_tools,ENV = {'PATH' : os.environ['PATH']});
|
||||
#env_base=Environment(tools=custom_tools);
|
||||
env_base.global_defaults=global_defaults
|
||||
env_base.android_source_modules=[]
|
||||
env_base.android_source_files=[]
|
||||
env_base.android_module_libraries=[]
|
||||
env_base.android_manifest_chunk=""
|
||||
env_base.disabled_modules=[]
|
||||
|
||||
env_base.__class__.android_module_source = methods.android_module_source
|
||||
env_base.__class__.android_module_library = methods.android_module_library
|
||||
env_base.__class__.android_module_file = methods.android_module_file
|
||||
env_base.__class__.android_module_manifest = methods.android_module_manifest
|
||||
env_base.__class__.disable_module = methods.disable_module
|
||||
|
||||
env_base.__class__.add_source_files = methods.add_source_files
|
||||
|
||||
customs = ['custom.py']
|
||||
|
||||
profile = ARGUMENTS.get("profile", False)
|
||||
if profile:
|
||||
import os.path
|
||||
if os.path.isfile(profile):
|
||||
customs.append(profile)
|
||||
elif os.path.isfile(profile+".py"):
|
||||
customs.append(profile+".py")
|
||||
|
||||
opts=Options(customs, ARGUMENTS)
|
||||
opts.Add('target', 'Compile Target (debug/profile/release).', "debug")
|
||||
opts.Add('platform','Platform: '+str(platform_list)+'(sfml).',"")
|
||||
opts.Add('python','Build Python Support: (yes/no)','no')
|
||||
opts.Add('squirrel','Build Squirrel Support: (yes/no)','no')
|
||||
opts.Add('tools','Build Tools (Including Editor): (yes/no)','yes')
|
||||
opts.Add('lua','Build Lua Support: (yes/no)','no')
|
||||
opts.Add('rfd','Remote Filesystem Driver: (yes/no)','no')
|
||||
opts.Add('gdscript','Build GDSCript support: (yes/no)','yes')
|
||||
opts.Add('vorbis','Build Ogg Vorbis Support: (yes/no)','yes')
|
||||
opts.Add('minizip','Build Minizip Archive Support: (yes/no)','yes')
|
||||
opts.Add('opengl', 'Build OpenGL Support: (yes/no)', 'yes')
|
||||
opts.Add('game', 'Game (custom) Code Directory', "")
|
||||
opts.Add('squish','Squish BC Texture Compression (yes/no)','yes')
|
||||
opts.Add('theora','Theora Video (yes/no)','yes')
|
||||
opts.Add('freetype','Freetype support in editor','yes')
|
||||
opts.Add('speex','Speex Audio (yes/no)','yes')
|
||||
opts.Add('xml','XML Save/Load support (yes/no)','yes')
|
||||
opts.Add('png','PNG Image loader support (yes/no)','yes')
|
||||
opts.Add('jpg','JPG Image loader support (yes/no)','yes')
|
||||
opts.Add('webp','WEBP Image loader support (yes/no)','yes')
|
||||
opts.Add('dds','DDS Texture loader support (yes/no)','yes')
|
||||
opts.Add('pvr','PVR (PowerVR) Texture loader support (yes/no)','yes')
|
||||
opts.Add('builtin_zlib','Use built-in zlib (yes/no)','yes')
|
||||
opts.Add('musepack','Musepack Audio (yes/no)','yes')
|
||||
opts.Add('default_gui_theme','Default GUI theme (yes/no)','yes')
|
||||
opts.Add("CXX", "Compiler");
|
||||
opts.Add("nedmalloc", "Add nedmalloc support", 'yes');
|
||||
opts.Add("CCFLAGS", "Custom flags for the C++ compiler");
|
||||
opts.Add("CFLAGS", "Custom flags for the C compiler");
|
||||
opts.Add("LINKFLAGS", "Custom flags for the linker");
|
||||
opts.Add('disable_3d', 'Disable 3D nodes for smaller executable (yes/no)', "no")
|
||||
opts.Add('disable_advanced_gui', 'Disable advance 3D gui nodes and behaviors (yes/no)', "no")
|
||||
opts.Add('old_scenes', 'Compatibility with old-style scenes', "yes")
|
||||
|
||||
# add platform specific options
|
||||
|
||||
for k in platform_opts.keys():
|
||||
opt_list = platform_opts[k]
|
||||
for o in opt_list:
|
||||
opts.Add(o[0],o[1],o[2])
|
||||
|
||||
for x in module_list:
|
||||
opts.Add('module_'+x+'_enabled', "Enable module '"+x+"'.", "yes")
|
||||
|
||||
opts.Update(env_base) # update environment
|
||||
Help(opts.GenerateHelpText(env_base)) # generate help
|
||||
|
||||
# add default include paths
|
||||
|
||||
env_base.Append(CPPPATH=['#core','#core/math','#tools','#drivers','#'])
|
||||
|
||||
# configure ENV for platform
|
||||
env_base.detect_python=True
|
||||
env_base.platform_exporters=platform_exporters
|
||||
|
||||
"""
|
||||
sys.path.append("./platform/"+env_base["platform"])
|
||||
import detect
|
||||
detect.configure(env_base)
|
||||
sys.path.remove("./platform/"+env_base["platform"])
|
||||
sys.modules.pop('detect')
|
||||
"""
|
||||
|
||||
if (env_base['target']=='debug'):
|
||||
env_base.Append(CPPFLAGS=['-DDEBUG_MEMORY_ALLOC']);
|
||||
env_base.Append(CPPFLAGS=['-DSCI_NAMESPACE'])
|
||||
|
||||
env_base.platforms = {}
|
||||
|
||||
for p in platform_list:
|
||||
|
||||
sys.path.append("./platform/"+p)
|
||||
import detect
|
||||
if "create" in dir(detect):
|
||||
env = detect.create(env_base)
|
||||
else:
|
||||
env = env_base.Clone()
|
||||
detect.configure(env)
|
||||
env['platform'] = p
|
||||
sys.path.remove("./platform/"+p)
|
||||
sys.modules.pop('detect')
|
||||
|
||||
flag_list = platform_flags[p]
|
||||
for f in flag_list:
|
||||
env[f[0]] = f[1]
|
||||
|
||||
env.module_list=[]
|
||||
|
||||
for x in module_list:
|
||||
if env['module_'+x+'_enabled'] != "yes":
|
||||
continue
|
||||
tmppath="./modules/"+x
|
||||
sys.path.append(tmppath)
|
||||
env.current_module=x
|
||||
import config
|
||||
if (config.can_build(p)):
|
||||
config.configure(env)
|
||||
env.module_list.append(x)
|
||||
sys.path.remove(tmppath)
|
||||
sys.modules.pop('config')
|
||||
|
||||
|
||||
if (env['musepack']=='yes'):
|
||||
env.Append(CPPFLAGS=['-DMUSEPACK_ENABLED']);
|
||||
|
||||
if (env["old_scenes"]=='yes'):
|
||||
env.Append(CPPFLAGS=['-DOLD_SCENE_FORMAT_ENABLED'])
|
||||
if (env["rfd"]=='yes'):
|
||||
env.Append(CPPFLAGS=['-DRFD_ENABLED'])
|
||||
if (env["builtin_zlib"]=='yes'):
|
||||
env.Append(CPPPATH=['#drivers/builtin_zlib/zlib'])
|
||||
|
||||
if (env['squirrel']=='yes'):
|
||||
|
||||
env.Append(CPPFLAGS=['-DSQUIRREL_ENABLED'])
|
||||
env.Append(CPPPATH=['#script/squirrel/src'])
|
||||
|
||||
# to test 64 bits compiltion
|
||||
# env.Append(CPPFLAGS=['-m64'])
|
||||
|
||||
if (env['lua']=='yes'):
|
||||
|
||||
env.Append(CPPFLAGS=['-DLUA_ENABLED'])
|
||||
env.Append(CPPPATH=['#script/lua/src'])
|
||||
if (env_base['squish']=='yes'):
|
||||
env.Append(CPPFLAGS=['-DSQUISH_ENABLED']);
|
||||
|
||||
if (env['vorbis']=='yes'):
|
||||
env.Append(CPPFLAGS=['-DVORBIS_ENABLED']);
|
||||
|
||||
if (env['theora']=='yes'):
|
||||
env.Append(CPPFLAGS=['-DTHEORA_ENABLED']);
|
||||
|
||||
if (env['png']=='yes'):
|
||||
env.Append(CPPFLAGS=['-DPNG_ENABLED']);
|
||||
if (env['dds']=='yes'):
|
||||
env.Append(CPPFLAGS=['-DDDS_ENABLED']);
|
||||
if (env['pvr']=='yes'):
|
||||
env.Append(CPPFLAGS=['-DPVR_ENABLED']);
|
||||
if (env['jpg']=='yes'):
|
||||
env.Append(CPPFLAGS=['-DJPG_ENABLED']);
|
||||
if (env['webp']=='yes'):
|
||||
env.Append(CPPFLAGS=['-DWEBP_ENABLED']);
|
||||
|
||||
if (env['speex']=='yes'):
|
||||
env.Append(CPPFLAGS=['-DSPEEX_ENABLED']);
|
||||
|
||||
if (env['tools']=='yes'):
|
||||
env.Append(CPPFLAGS=['-DTOOLS_ENABLED'])
|
||||
if (env['disable_3d']=='yes'):
|
||||
env.Append(CPPFLAGS=['-D_3D_DISABLED'])
|
||||
if (env['gdscript']=='yes'):
|
||||
env.Append(CPPFLAGS=['-DGDSCRIPT_ENABLED'])
|
||||
if (env['disable_advanced_gui']=='yes'):
|
||||
env.Append(CPPFLAGS=['-DADVANCED_GUI_DISABLED'])
|
||||
|
||||
if (env['minizip'] == 'yes'):
|
||||
env.Append(CPPFLAGS=['-DMINIZIP_ENABLED'])
|
||||
|
||||
if (env['xml']=='yes'):
|
||||
env.Append(CPPFLAGS=['-DXML_ENABLED'])
|
||||
|
||||
if (env['default_gui_theme']=='no'):
|
||||
env.Append(CPPFLAGS=['-DDEFAULT_THEME_DISABLED'])
|
||||
|
||||
if (env["python"]=='yes'):
|
||||
detected=False;
|
||||
if (env.detect_python):
|
||||
print("Python 3.0 Prefix:");
|
||||
pycfg_exec="python3-config"
|
||||
errorval=os.system(pycfg_exec+" --prefix")
|
||||
prefix=""
|
||||
if (not errorval):
|
||||
#gah, why can't it get both at the same time like pkg-config, sdl-config, etc?
|
||||
env.ParseConfig(pycfg_exec+" --cflags")
|
||||
env.ParseConfig(pycfg_exec+" --libs")
|
||||
detected=True
|
||||
|
||||
if (detected):
|
||||
env.Append(CPPFLAGS=['-DPYTHON_ENABLED'])
|
||||
#remove annoying warnings
|
||||
if ('-Wstrict-prototypes' in env["CCFLAGS"]):
|
||||
env["CCFLAGS"].remove('-Wstrict-prototypes');
|
||||
if ('-fwrapv' in env["CCFLAGS"]):
|
||||
env["CCFLAGS"].remove('-fwrapv');
|
||||
else:
|
||||
print("Python 3.0 not detected ("+pycfg_exec+") support disabled.");
|
||||
|
||||
#if env['nedmalloc'] == 'yes':
|
||||
# env.Append(CPPFLAGS = ['-DNEDMALLOC_ENABLED'])
|
||||
|
||||
Export('env')
|
||||
|
||||
#build subdirs, the build order is dependent on link order.
|
||||
|
||||
SConscript("core/SCsub")
|
||||
SConscript("servers/SCsub")
|
||||
SConscript("scene/SCsub")
|
||||
SConscript("tools/SCsub")
|
||||
SConscript("script/SCsub");
|
||||
SConscript("drivers/SCsub")
|
||||
SConscript("bin/SCsub")
|
||||
|
||||
if env['game']:
|
||||
SConscript(env['game']+'/SCsub')
|
||||
|
||||
SConscript("modules/SCsub")
|
||||
SConscript("main/SCsub")
|
||||
|
||||
SConscript("platform/"+p+"/SCsub"); # build selected platform
|
||||
|
4
bin/SCsub
Normal file
4
bin/SCsub
Normal file
@ -0,0 +1,4 @@
|
||||
Import('env')
|
||||
Export('env')
|
||||
|
||||
SConscript('tests/SCsub');
|
14
bin/tests/SCsub
Normal file
14
bin/tests/SCsub
Normal file
@ -0,0 +1,14 @@
|
||||
Import('env')
|
||||
|
||||
env.tests_sources=[]
|
||||
env.add_source_files(env.tests_sources,"*.cpp")
|
||||
|
||||
Export('env')
|
||||
|
||||
#SConscript('math/SCsub');
|
||||
|
||||
lib = env.Library("tests",env.tests_sources)
|
||||
|
||||
env.Prepend(LIBS=[lib])
|
||||
|
||||
|
107
bin/tests/test_containers.cpp
Normal file
107
bin/tests/test_containers.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
/*************************************************************************/
|
||||
/* test_containers.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "test_containers.h"
|
||||
#include "dvector.h"
|
||||
#include "set.h"
|
||||
#include "print_string.h"
|
||||
#include "math_funcs.h"
|
||||
#include "servers/visual/default_mouse_cursor.xpm"
|
||||
|
||||
#include "variant.h"
|
||||
#include "list.h"
|
||||
#include "image.h"
|
||||
|
||||
namespace TestContainers {
|
||||
|
||||
MainLoop * test() {
|
||||
|
||||
|
||||
/*
|
||||
HashMap<int,int> int_map;
|
||||
|
||||
for (int i=0;i<68000;i++) {
|
||||
|
||||
int num=(int)Math::random(0,1024);
|
||||
int_map[i]=num;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
{
|
||||
|
||||
// static const int size = 16;
|
||||
Image img;
|
||||
img.create(default_mouse_cursor_xpm);
|
||||
|
||||
{
|
||||
for (int i=0; i<8; i++) {
|
||||
|
||||
Image mipmap;
|
||||
//img.make_mipmap(mipmap);
|
||||
img = mipmap;
|
||||
if (img.get_width() <= 4) break;
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#if 0
|
||||
Set<int> set;
|
||||
|
||||
print_line("Begin Insert");
|
||||
for (int i=0;i<1100;i++) {
|
||||
|
||||
int num=i;//(int)Math::random(0,1024);
|
||||
// print_line("inserting "+itos(num));
|
||||
set.insert( num );
|
||||
}
|
||||
|
||||
/*
|
||||
for (int i=0;i<400;i++) {
|
||||
|
||||
int num=(int)Math::random(0,1024);
|
||||
set.erase(num);
|
||||
}
|
||||
*/
|
||||
//set.print_tree();
|
||||
|
||||
for(Set<int>::Element *I=set.front();I;I=I->next()) {
|
||||
|
||||
print_line("inserted "+itos(I->get())+" prev is "+itos(I->prev()?I->prev()->get():-100));
|
||||
|
||||
}
|
||||
|
||||
print_line("depth is "+itos(set.calculate_depth()));
|
||||
print_line("Insert Success");
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
43
bin/tests/test_containers.h
Normal file
43
bin/tests/test_containers.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*************************************************************************/
|
||||
/* test_containers.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 TEST_CONTAINERS_H
|
||||
#define TEST_CONTAINERS_H
|
||||
|
||||
#include "os/main_loop.h"
|
||||
/**
|
||||
@author Juan Linietsky <reduzio@gmail.com>
|
||||
*/
|
||||
|
||||
namespace TestContainers {
|
||||
|
||||
MainLoop * test();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
217
bin/tests/test_detailer.cpp
Normal file
217
bin/tests/test_detailer.cpp
Normal file
@ -0,0 +1,217 @@
|
||||
/*************************************************************************/
|
||||
/* test_detailer.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "test_detailer.h"
|
||||
#include "servers/visual_server.h"
|
||||
#include "os/main_loop.h"
|
||||
#include "math_funcs.h"
|
||||
#include "print_string.h"
|
||||
#include "geometry.h"
|
||||
#include "quick_hull.h"
|
||||
namespace TestMultiMesh {
|
||||
|
||||
|
||||
class TestMainLoop : public MainLoop {
|
||||
|
||||
RID instance;
|
||||
RID camera;
|
||||
RID viewport;
|
||||
RID light;
|
||||
RID mesh;
|
||||
RID scenario;
|
||||
|
||||
#define MULTIMESH_COUNT 1500
|
||||
|
||||
float ofs_x,ofs_y;
|
||||
bool quit;
|
||||
public:
|
||||
|
||||
|
||||
virtual void _update_qh() {
|
||||
|
||||
VisualServer *vs=VisualServer::get_singleton();
|
||||
Vector<Vector3> vts;
|
||||
/*
|
||||
|
||||
static const int s = 20;
|
||||
for(int i=0;i<s;i++) {
|
||||
Matrix3 rot(Vector3(0,1,0),i*Math_PI/s);
|
||||
|
||||
for(int j=0;j<s;j++) {
|
||||
Vector3 v;
|
||||
v.x=Math::sin(j*Math_PI*2/s);
|
||||
v.y=Math::cos(j*Math_PI*2/s);
|
||||
|
||||
vts.push_back( rot.xform(v*2 ) );
|
||||
}
|
||||
}*/
|
||||
/*
|
||||
Math::seed(0);
|
||||
for(int i=0;i<50;i++) {
|
||||
|
||||
vts.push_back( Vector3(Math::randf()*2-1.0,Math::randf()*2-1.0,Math::randf()*2-1.0).normalized()*2);
|
||||
}*/
|
||||
/*
|
||||
vts.push_back(Vector3(0,0,1));
|
||||
vts.push_back(Vector3(0,0,-1));
|
||||
vts.push_back(Vector3(0,1,0));
|
||||
vts.push_back(Vector3(0,-1,0));
|
||||
vts.push_back(Vector3(1,0,0));
|
||||
vts.push_back(Vector3(-1,0,0));*/
|
||||
/*
|
||||
vts.push_back(Vector3(1,1,1));
|
||||
vts.push_back(Vector3(1,-1,1));
|
||||
vts.push_back(Vector3(-1,1,1));
|
||||
vts.push_back(Vector3(-1,-1,1));
|
||||
vts.push_back(Vector3(1,1,-1));
|
||||
vts.push_back(Vector3(1,-1,-1));
|
||||
vts.push_back(Vector3(-1,1,-1));
|
||||
vts.push_back(Vector3(-1,-1,-1));
|
||||
*/
|
||||
|
||||
|
||||
DVector<Plane> convex_planes = Geometry::build_cylinder_planes(0.5,0.7,4,Vector3::AXIS_Z);
|
||||
Geometry::MeshData convex_data = Geometry::build_convex_mesh(convex_planes);
|
||||
vts=convex_data.vertices;
|
||||
|
||||
Geometry::MeshData md;
|
||||
Error err = QuickHull::build(vts,md);
|
||||
print_line("ERR: "+itos(err));
|
||||
|
||||
vs->mesh_remove_surface(mesh,0);
|
||||
vs->mesh_add_surface_from_mesh_data(mesh,md);
|
||||
|
||||
|
||||
|
||||
//vs->scenario_set_debug(scenario,VS::SCENARIO_DEBUG_WIREFRAME);
|
||||
|
||||
/*
|
||||
RID sm = vs->shader_create();
|
||||
//vs->shader_set_fragment_code(sm,"OUT_ALPHA=mod(TIME,1);");
|
||||
//vs->shader_set_vertex_code(sm,"OUT_VERTEX=IN_VERTEX*mod(TIME,1);");
|
||||
vs->shader_set_fragment_code(sm,"OUT_DIFFUSE=vec3(1,0,1);OUT_GLOW=abs(sin(TIME));");
|
||||
RID tcmat = vs->mesh_surface_get_material(test_cube,0);
|
||||
vs->material_set_shader(tcmat,sm);
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
virtual void input_event(const InputEvent& p_event) {
|
||||
|
||||
if (p_event.type==InputEvent::MOUSE_MOTION && p_event.mouse_motion.button_mask&4) {
|
||||
|
||||
ofs_x+=p_event.mouse_motion.relative_y/200.0;
|
||||
ofs_y+=p_event.mouse_motion.relative_x/200.0;
|
||||
}
|
||||
if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.pressed && p_event.mouse_button.button_index==1) {
|
||||
|
||||
QuickHull::debug_stop_after++;
|
||||
_update_qh();
|
||||
}
|
||||
if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.pressed && p_event.mouse_button.button_index==2) {
|
||||
|
||||
if (QuickHull::debug_stop_after>0)
|
||||
QuickHull::debug_stop_after--;
|
||||
_update_qh();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
virtual void request_quit() {
|
||||
|
||||
quit=true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
virtual void init() {
|
||||
|
||||
VisualServer *vs=VisualServer::get_singleton();
|
||||
|
||||
|
||||
mesh = vs->mesh_create();
|
||||
|
||||
scenario = vs->scenario_create();
|
||||
|
||||
QuickHull::debug_stop_after=0;
|
||||
_update_qh();
|
||||
|
||||
instance = vs->instance_create2(mesh,scenario);
|
||||
|
||||
camera = vs->camera_create();
|
||||
|
||||
|
||||
vs->camera_set_perspective( camera, 60.0,0.1, 100.0 );
|
||||
viewport = vs->viewport_create();
|
||||
vs->viewport_attach_camera( viewport, camera );
|
||||
vs->viewport_attach_to_screen(viewport);
|
||||
vs->viewport_set_scenario( viewport, scenario );
|
||||
|
||||
vs->camera_set_transform(camera, Transform( Matrix3(), Vector3(0,0,2 ) ) );
|
||||
|
||||
RID lightaux = vs->light_create( VisualServer::LIGHT_DIRECTIONAL );
|
||||
vs->light_set_color( lightaux, VisualServer::LIGHT_COLOR_AMBIENT, Color(0.3,0.3,0.3) );
|
||||
light = vs->instance_create2( lightaux,scenario );
|
||||
vs->instance_set_transform(light,Transform(Matrix3(Vector3(0.1,0.4,0.7).normalized(),0.9)));
|
||||
|
||||
ofs_x=0;
|
||||
ofs_y=0;
|
||||
quit=false;
|
||||
}
|
||||
|
||||
virtual bool idle(float p_time) {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool iteration(float p_time) {
|
||||
|
||||
VisualServer *vs=VisualServer::get_singleton();
|
||||
|
||||
Transform tr_camera;
|
||||
tr_camera.rotate( Vector3(0,1,0), ofs_y );
|
||||
tr_camera.rotate( Vector3(1,0,0),ofs_x );
|
||||
tr_camera.translate(0,0,10);
|
||||
|
||||
vs->camera_set_transform( camera, tr_camera );
|
||||
|
||||
return quit;
|
||||
}
|
||||
virtual void finish() {
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
MainLoop* test() {
|
||||
|
||||
return memnew(TestMainLoop);
|
||||
|
||||
}
|
||||
|
||||
}
|
44
bin/tests/test_detailer.h
Normal file
44
bin/tests/test_detailer.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*************************************************************************/
|
||||
/* test_detailer.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 TEST_MULTIMESH_H
|
||||
#define TEST_MULTIMESH_H
|
||||
|
||||
/**
|
||||
@author Juan Linietsky <reduzio@gmail.com>
|
||||
*/
|
||||
#include "os/main_loop.h"
|
||||
|
||||
namespace TestMultiMesh {
|
||||
|
||||
MainLoop* test();
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
1003
bin/tests/test_gdscript.cpp
Normal file
1003
bin/tests/test_gdscript.cpp
Normal file
File diff suppressed because it is too large
Load Diff
46
bin/tests/test_gdscript.h
Normal file
46
bin/tests/test_gdscript.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*************************************************************************/
|
||||
/* test_gdscript.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 TEST_GDSCRIPT_H
|
||||
#define TEST_GDSCRIPT_H
|
||||
|
||||
#include "os/main_loop.h"
|
||||
|
||||
namespace TestGDScript {
|
||||
|
||||
enum TestType {
|
||||
TEST_TOKENIZER,
|
||||
TEST_PARSER,
|
||||
TEST_COMPILER
|
||||
};
|
||||
|
||||
MainLoop* test(TestType p_type);
|
||||
|
||||
}
|
||||
|
||||
#endif // TEST_GDSCRIPT_H
|
399
bin/tests/test_gui.cpp
Normal file
399
bin/tests/test_gui.cpp
Normal file
@ -0,0 +1,399 @@
|
||||
/*************************************************************************/
|
||||
/* test_gui.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 _3D_DISABLED
|
||||
|
||||
#include "test_gui.h"
|
||||
|
||||
#include "scene/main/scene_main_loop.h"
|
||||
#include "os/os.h"
|
||||
#include "scene/gui/control.h"
|
||||
#include "scene/gui/button.h"
|
||||
#include "scene/gui/label.h"
|
||||
#include "scene/gui/line_edit.h"
|
||||
#include "scene/gui/scroll_bar.h"
|
||||
#include "scene/gui/popup_menu.h"
|
||||
#include "scene/gui/option_button.h"
|
||||
#include "scene/gui/spin_box.h"
|
||||
#include "scene/gui/menu_button.h"
|
||||
#include "scene/gui/progress_bar.h"
|
||||
#include "scene/gui/panel.h"
|
||||
#include "scene/gui/tab_container.h"
|
||||
#include "scene/gui/tree.h"
|
||||
#include "scene/gui/rich_text_label.h"
|
||||
#include "scene/gui/texture_frame.h"
|
||||
#include "io/image_loader.h"
|
||||
#include "print_string.h"
|
||||
#include "scene/2d/sprite.h"
|
||||
|
||||
#include "scene/main/viewport.h"
|
||||
#include "scene/3d/camera.h"
|
||||
#include "scene/3d/test_cube.h"
|
||||
|
||||
namespace TestGUI {
|
||||
|
||||
|
||||
class TestMainLoop : public SceneMainLoop {
|
||||
|
||||
|
||||
Control *control;
|
||||
|
||||
public:
|
||||
|
||||
virtual void request_quit() {
|
||||
|
||||
quit();
|
||||
|
||||
}
|
||||
virtual void init() {
|
||||
|
||||
SceneMainLoop::init();
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
|
||||
Viewport *vp = memnew( Viewport );
|
||||
vp->set_world( Ref<World>( memnew( World )));
|
||||
get_root()->add_child(vp);
|
||||
|
||||
vp->set_rect(Rect2(0,0,256,256));
|
||||
vp->set_as_render_target(true);
|
||||
vp->set_render_target_update_mode(Viewport::RENDER_TARGET_UPDATE_ALWAYS);
|
||||
|
||||
|
||||
Camera *camera = memnew( Camera );
|
||||
vp->add_child(camera);
|
||||
camera->make_current();
|
||||
|
||||
TestCube *testcube = memnew( TestCube );
|
||||
vp->add_child(testcube);
|
||||
testcube->set_transform(Transform( Matrix3().rotated(Vector3(0,1,0),Math_PI*0.25), Vector3(0,0,-8)));
|
||||
|
||||
Sprite *sp = memnew( Sprite );
|
||||
sp->set_texture( vp->get_render_target_texture() );
|
||||
// sp->set_texture( ResourceLoader::load("res://ball.png") );
|
||||
sp->set_pos(Point2(300,300));
|
||||
get_root()->add_child(sp);
|
||||
|
||||
|
||||
return;
|
||||
#endif
|
||||
|
||||
Panel * frame = memnew( Panel );
|
||||
frame->set_anchor( MARGIN_RIGHT, Control::ANCHOR_END );
|
||||
frame->set_anchor( MARGIN_BOTTOM, Control::ANCHOR_END );
|
||||
frame->set_end( Point2(0,0) );
|
||||
|
||||
get_root()->add_child( frame );
|
||||
|
||||
Label *label = memnew( Label );
|
||||
|
||||
label->set_pos( Point2( 80,90 ) );
|
||||
label->set_size( Point2( 170,80 ) );
|
||||
label->set_align( Label::ALIGN_FILL );
|
||||
//label->set_text("There");
|
||||
label->set_text("There was once upon a time a beautiful unicorn that loved to play with little girls...");
|
||||
|
||||
frame->add_child(label);
|
||||
|
||||
Button *button = memnew( Button );
|
||||
|
||||
button->set_pos( Point2( 20,20 ) );
|
||||
button->set_size( Point2( 1,1 ) );
|
||||
button->set_text("This is a biggie button");
|
||||
|
||||
|
||||
frame->add_child( button );
|
||||
|
||||
|
||||
#if 0
|
||||
Sprite *tf = memnew( Sprite );
|
||||
frame->add_child(tf);
|
||||
Image img;
|
||||
ImageLoader::load_image("LarvoClub.png",&img);
|
||||
|
||||
img.resize(512,512);
|
||||
img.generate_mipmaps();
|
||||
img.compress();
|
||||
Ref<Texture> text = memnew( Texture );
|
||||
text->create_from_image(img);
|
||||
tf->set_texture(text);
|
||||
tf->set_pos(Point2(50,50));
|
||||
//tf->set_scale(Point2(0.3,0.3));
|
||||
|
||||
|
||||
return;
|
||||
#endif
|
||||
|
||||
Tree * tree = memnew( Tree );
|
||||
tree->set_columns(2);
|
||||
|
||||
tree->set_pos( Point2( 230,210 ) );
|
||||
tree->set_size( Point2( 150,250 ) );
|
||||
|
||||
|
||||
TreeItem *item = tree->create_item();
|
||||
item->set_editable(0,true);
|
||||
item->set_text(0,"root");
|
||||
item = tree->create_item( tree->get_root() );
|
||||
item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
|
||||
item->set_editable(0,true);
|
||||
item->set_text(0,"check");
|
||||
item->set_cell_mode(1, TreeItem::CELL_MODE_CHECK);
|
||||
item->set_editable(1,true);
|
||||
item->set_text(1,"check2");
|
||||
item = tree->create_item( tree->get_root() );
|
||||
item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE);
|
||||
item->set_editable(0,true);
|
||||
item->set_range_config(0,0,20,0.1);
|
||||
item->set_range(0,2);
|
||||
item->add_button(0,Theme::get_default()->get_icon("folder","FileDialog"));
|
||||
item->set_cell_mode(1, TreeItem::CELL_MODE_RANGE);
|
||||
item->set_editable(1,true);
|
||||
item->set_range_config(1,0,20,0.1);
|
||||
item->set_range(1,3);
|
||||
|
||||
item = tree->create_item( tree->get_root() );
|
||||
item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE);
|
||||
item->set_editable(0,true);
|
||||
item->set_text(0,"Have,Many,Several,Options!");
|
||||
item->set_range(0,2);
|
||||
|
||||
item = tree->create_item( item );
|
||||
item->set_editable(0,true);
|
||||
item->set_text(0,"Gershwin!");
|
||||
|
||||
frame->add_child(tree);
|
||||
|
||||
//control = memnew( Control );
|
||||
//root->add_child( control );
|
||||
|
||||
|
||||
|
||||
LineEdit *line_edit = memnew( LineEdit );
|
||||
|
||||
line_edit->set_pos( Point2( 30,190 ) );
|
||||
line_edit->set_size( Point2( 180,1 ) );
|
||||
|
||||
frame->add_child(line_edit);
|
||||
|
||||
HScrollBar *hscroll = memnew( HScrollBar );
|
||||
|
||||
hscroll->set_pos( Point2( 30,290 ) );
|
||||
hscroll->set_size( Point2( 180,1 ) );
|
||||
hscroll->set_max(10);
|
||||
hscroll->set_page(4);
|
||||
|
||||
frame->add_child(hscroll);
|
||||
|
||||
|
||||
|
||||
SpinBox *spin = memnew( SpinBox );
|
||||
|
||||
spin->set_pos( Point2( 30,260 ) );
|
||||
spin->set_size( Point2( 120,1 ) );
|
||||
|
||||
frame->add_child(spin);
|
||||
hscroll->share(spin);
|
||||
|
||||
ProgressBar *progress = memnew( ProgressBar );
|
||||
|
||||
progress->set_pos( Point2( 30,330 ) );
|
||||
progress->set_size( Point2( 120,1 ) );
|
||||
|
||||
frame->add_child(progress);
|
||||
hscroll->share(progress);
|
||||
|
||||
MenuButton *menu_button = memnew( MenuButton );
|
||||
|
||||
menu_button->set_text("I'm a menu!");
|
||||
menu_button->set_pos( Point2( 30,380 ) );
|
||||
menu_button->set_size( Point2( 1,1 ) );
|
||||
|
||||
frame->add_child(menu_button);
|
||||
|
||||
PopupMenu *popup = menu_button->get_popup();
|
||||
|
||||
popup->add_item("Hello, testing");
|
||||
popup->add_item("My Dearest");
|
||||
popup->add_separator();
|
||||
popup->add_item("Popup");
|
||||
popup->add_check_item("Check Popup");
|
||||
popup->set_item_checked(4,true);
|
||||
|
||||
OptionButton *options = memnew( OptionButton );
|
||||
|
||||
options->add_item("Hello, testing");
|
||||
options->add_item("My Dearest");
|
||||
|
||||
options->set_pos( Point2( 230,180 ) );
|
||||
options->set_size( Point2( 1,1 ) );
|
||||
|
||||
frame->add_child(options);
|
||||
|
||||
/*
|
||||
Tree * tree = memnew( Tree );
|
||||
tree->set_columns(2);
|
||||
|
||||
tree->set_pos( Point2( 230,210 ) );
|
||||
tree->set_size( Point2( 150,250 ) );
|
||||
|
||||
|
||||
TreeItem *item = tree->create_item();
|
||||
item->set_editable(0,true);
|
||||
item->set_text(0,"root");
|
||||
item = tree->create_item( tree->get_root() );
|
||||
item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
|
||||
item->set_editable(0,true);
|
||||
item->set_text(0,"check");
|
||||
item = tree->create_item( tree->get_root() );
|
||||
item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE);
|
||||
item->set_editable(0,true);
|
||||
item->set_range_config(0,0,20,0.1);
|
||||
item->set_range(0,2);
|
||||
item->add_button(0,Theme::get_default()->get_icon("folder","FileDialog"));
|
||||
item = tree->create_item( tree->get_root() );
|
||||
item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE);
|
||||
item->set_editable(0,true);
|
||||
item->set_text(0,"Have,Many,Several,Options!");
|
||||
item->set_range(0,2);
|
||||
|
||||
frame->add_child(tree);
|
||||
*/
|
||||
|
||||
|
||||
RichTextLabel *richtext = memnew( RichTextLabel );
|
||||
|
||||
richtext->set_pos( Point2( 600,210 ) );
|
||||
richtext->set_size( Point2( 180,250 ) );
|
||||
richtext->set_anchor_and_margin(MARGIN_RIGHT,Control::ANCHOR_END,20);
|
||||
|
||||
frame->add_child(richtext);
|
||||
|
||||
|
||||
richtext->add_text("Hello, My Friends!\n\nWelcome to the amazing world of ");
|
||||
|
||||
richtext->add_newline();
|
||||
richtext->add_newline();
|
||||
|
||||
richtext->push_color(Color(1,0.5,0.5));
|
||||
richtext->add_text("leprechauns");
|
||||
richtext->pop();
|
||||
#if 0
|
||||
richtext->add_text(" and ");
|
||||
richtext->push_color(Color(0,1.0,0.5));
|
||||
richtext->add_text("faeries.\n");
|
||||
richtext->pop();
|
||||
richtext->add_text("In this new episode, we will attemp to ");
|
||||
richtext->push_font(richtext->get_font("mono_font","Fonts"));
|
||||
richtext->push_color(Color(0.7,0.5,1.0));
|
||||
richtext->add_text("deliver something nice");
|
||||
richtext->pop();
|
||||
richtext->pop();
|
||||
richtext->add_text(" to all the viewers! Unfortunately, I need to ");
|
||||
richtext->push_underline();
|
||||
richtext->add_text("keep writing a lot of text");
|
||||
richtext->pop();
|
||||
richtext->add_text(" so the label control overflows and the scrollbar appears.\n");
|
||||
//richtext->push_indent(1);
|
||||
//richtext->add_text("By the way, testing indent levels! Yohohoho! Everything should appear to the right sightly here!\n");
|
||||
//richtext->pop();
|
||||
richtext->push_meta("http://www.scrollingcapabilities.xz");
|
||||
richtext->add_text("This allows to test for the scrolling capabilities ");
|
||||
richtext->pop();
|
||||
richtext->add_text("of the rich text label for huge text (not like this text will really be huge but, you know).\nAs long as it is so long that it will work nicely for a test/demo, then it's welcomed in my book...\nChanging subject, the day is cloudy today and I'm wondering if I'll get che chance to travel somewhere nice. Sometimes, watching the clouds from satellite images may give a nice insight about how pressure zones in our planet work, althogh it also makes it pretty obvious to see why most weather forecasts get it wrong so often.\nClouds are so difficult to predict!\nBut it's pretty cool how our civilization has adapted to having water falling from the sky each time it rains...");
|
||||
//richtext->add_text("Hello!\nGorgeous..");
|
||||
#endif
|
||||
|
||||
//richtext->push_meta("http://www.scrollingcapabilities.xz");
|
||||
///richtext->add_text("Hello!\n");
|
||||
//richtext->pop();
|
||||
|
||||
richtext->set_anchor(MARGIN_RIGHT,Control::ANCHOR_END);
|
||||
|
||||
|
||||
TabContainer * tabc = memnew( TabContainer );
|
||||
|
||||
Control *ctl= memnew( Control );
|
||||
ctl->set_name("tab 1");
|
||||
tabc->add_child(ctl);
|
||||
|
||||
ctl= memnew( Control );
|
||||
ctl->set_name("tab 2");
|
||||
tabc->add_child(ctl);
|
||||
label = memnew( Label );
|
||||
label->set_text("Some Label");
|
||||
label->set_pos( Point2(20,20) );
|
||||
ctl->add_child(label);;
|
||||
|
||||
ctl= memnew( Control );
|
||||
ctl->set_name("tab 3");
|
||||
button = memnew( Button );
|
||||
button->set_text("Some Button");
|
||||
button->set_pos( Point2(30,50) );
|
||||
ctl->add_child(button);;
|
||||
|
||||
tabc->add_child(ctl);
|
||||
|
||||
frame->add_child(tabc);
|
||||
|
||||
tabc->set_pos( Point2( 400,210 ) );
|
||||
tabc->set_size( Point2( 180,250 ) );
|
||||
|
||||
|
||||
Ref<ImageTexture> text = memnew( ImageTexture );
|
||||
text->load("test_data/concave.png");
|
||||
|
||||
Sprite* sprite = memnew(Sprite);
|
||||
sprite->set_texture(text);
|
||||
sprite->set_pos(Point2(300, 300));
|
||||
frame->add_child(sprite);
|
||||
sprite->show();
|
||||
|
||||
Sprite* sprite2 = memnew(Sprite);
|
||||
sprite->set_texture(text);
|
||||
sprite->add_child(sprite2);
|
||||
sprite2->set_pos(Point2(50, 50));
|
||||
sprite2->show();
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
MainLoop* test() {
|
||||
|
||||
|
||||
return memnew( TestMainLoop );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
44
bin/tests/test_gui.h
Normal file
44
bin/tests/test_gui.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*************************************************************************/
|
||||
/* test_gui.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 TEST_GUI_H
|
||||
#define TEST_GUI_H
|
||||
|
||||
#include "os/main_loop.h"
|
||||
|
||||
/**
|
||||
@author Juan Linietsky <reduzio@gmail.com>
|
||||
*/
|
||||
namespace TestGUI {
|
||||
|
||||
MainLoop* test();
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
77
bin/tests/test_image.cpp
Normal file
77
bin/tests/test_image.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
/*************************************************************************/
|
||||
/* test_image.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "test_image.h"
|
||||
#include "os/main_loop.h"
|
||||
#include "math_funcs.h"
|
||||
#include "print_string.h"
|
||||
#include "io/image_loader.h"
|
||||
namespace TestImage {
|
||||
|
||||
|
||||
class TestMainLoop : public MainLoop {
|
||||
|
||||
bool quit;
|
||||
public:
|
||||
virtual void input_event(const InputEvent& p_event) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
virtual void init() {
|
||||
|
||||
quit=false;
|
||||
}
|
||||
virtual bool iteration(float p_time) {
|
||||
|
||||
return quit;
|
||||
}
|
||||
|
||||
virtual bool idle(float p_time) {
|
||||
return quit;
|
||||
}
|
||||
|
||||
virtual void finish() {
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
MainLoop* test() {
|
||||
|
||||
Image img;
|
||||
ImageLoader::load_image("as1.png",&img);
|
||||
|
||||
img.resize(512,512);
|
||||
|
||||
return memnew( TestMainLoop );
|
||||
|
||||
}
|
||||
|
||||
}
|
44
bin/tests/test_image.h
Normal file
44
bin/tests/test_image.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*************************************************************************/
|
||||
/* test_image.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 TEST_IMAGE_H
|
||||
#define TEST_IMAGE_H
|
||||
|
||||
/**
|
||||
@author Juan Linietsky <reduzio@gmail.com>
|
||||
*/
|
||||
|
||||
#include "os/main_loop.h"
|
||||
|
||||
namespace TestImage {
|
||||
|
||||
MainLoop* test();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
208
bin/tests/test_io.cpp
Normal file
208
bin/tests/test_io.cpp
Normal file
@ -0,0 +1,208 @@
|
||||
/*************************************************************************/
|
||||
/* test_io.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "test_io.h"
|
||||
|
||||
#ifdef MINIZIP_ENABLED
|
||||
|
||||
|
||||
|
||||
#include "os/main_loop.h"
|
||||
#include "os/os.h"
|
||||
#include "scene/resources/texture.h"
|
||||
#include "print_string.h"
|
||||
#include "io/resource_loader.h"
|
||||
#include "io/resource_saver.h"
|
||||
#include "os/dir_access.h"
|
||||
#include "core/globals.h"
|
||||
|
||||
#include "io/file_access_memory.h"
|
||||
|
||||
namespace TestIO {
|
||||
|
||||
|
||||
class TestMainLoop : public MainLoop {
|
||||
|
||||
|
||||
bool quit;
|
||||
|
||||
public:
|
||||
virtual void input_event(const InputEvent& p_event) {
|
||||
|
||||
|
||||
}
|
||||
virtual bool idle(float p_time) {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void request_quit() {
|
||||
|
||||
quit=true;
|
||||
|
||||
}
|
||||
virtual void init() {
|
||||
|
||||
quit=true;
|
||||
}
|
||||
virtual bool iteration(float p_time) {
|
||||
|
||||
return quit;
|
||||
}
|
||||
virtual void finish() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
MainLoop* test() {
|
||||
|
||||
print_line("this is test io");
|
||||
DirAccess* da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
da->change_dir(".");
|
||||
print_line("Opening current dir "+ da->get_current_dir());
|
||||
String entry;
|
||||
da->list_dir_begin();
|
||||
while ( (entry = da->get_next()) != "") {
|
||||
|
||||
print_line("entry "+entry+" is dir: " + Variant(da->current_is_dir()));
|
||||
};
|
||||
da->list_dir_end();
|
||||
|
||||
RES texture = ResourceLoader::load("test_data/rock.png");
|
||||
ERR_FAIL_COND_V(texture.is_null(), NULL);
|
||||
|
||||
ResourceSaver::save("test_data/rock.xml",texture);
|
||||
|
||||
print_line("localize paths");
|
||||
print_line(Globals::get_singleton()->localize_path("algo.xml"));
|
||||
print_line(Globals::get_singleton()->localize_path("c:\\windows\\algo.xml"));
|
||||
print_line(Globals::get_singleton()->localize_path(Globals::get_singleton()->get_resource_path()+"/something/something.xml"));
|
||||
print_line(Globals::get_singleton()->localize_path("somedir/algo.xml"));
|
||||
|
||||
{
|
||||
|
||||
FileAccess* z = FileAccess::open("test_data/archive.zip", FileAccess::READ);
|
||||
int len = z->get_len();
|
||||
Vector<uint8_t> zip;
|
||||
zip.resize(len);
|
||||
z->get_buffer(&zip[0], len);
|
||||
z->close();
|
||||
memdelete(z);
|
||||
|
||||
FileAccessMemory::register_file("a_package", zip);
|
||||
FileAccess::make_default<FileAccessMemory>(FileAccess::ACCESS_RESOURCES);
|
||||
FileAccess::make_default<FileAccessMemory>(FileAccess::ACCESS_FILESYSTEM);
|
||||
FileAccess::make_default<FileAccessMemory>(FileAccess::ACCESS_USERDATA);
|
||||
|
||||
print_line("archive test");
|
||||
#if 0
|
||||
Archive arch;
|
||||
|
||||
Archive::get_singleton()->add_package("a_package");
|
||||
FileAccessArchive f;
|
||||
|
||||
print_line("opening for read");
|
||||
f._open("file.txt", FileAccess::READ);
|
||||
int pos = f.get_pos();
|
||||
printf("file has %i bytes, initial pos %i\n", (int)f.get_len(), pos);
|
||||
|
||||
do {
|
||||
printf("%c", f.get_8());
|
||||
|
||||
} while (!f.eof_reached());
|
||||
|
||||
print_line("opening for stored seek");
|
||||
f.open("seek.bin", FileAccess::READ);
|
||||
pos = f.get_pos();
|
||||
printf("byte at pos %i is %i\n", pos, (int)f.get_8());
|
||||
f.seek(128);
|
||||
pos = f.get_pos();
|
||||
printf("byte at pos %i is %i\n", pos, (int)f.get_8());
|
||||
|
||||
print_line("opening for deflated seek");
|
||||
f.open("seek_deflated.bin", FileAccess::READ);
|
||||
pos = f.get_pos();
|
||||
printf("byte at pos %i is %i\n", pos, (int)f.get_8());
|
||||
f.seek(128);
|
||||
pos = f.get_pos();
|
||||
printf("byte at pos %i is %i\n", pos, (int)f.get_8());
|
||||
pos = f.get_pos();
|
||||
printf("byte at pos %i is %i\n", pos, (int)f.get_8());
|
||||
pos = f.get_pos();
|
||||
printf("byte at pos %i is %i\n", pos, (int)f.get_8());
|
||||
f.seek(256);
|
||||
pos = f.get_pos();
|
||||
printf("byte at pos %i is %i\n", pos, (int)f.get_8());
|
||||
pos = f.get_pos();
|
||||
printf("byte at pos %i is %i\n", pos, (int)f.get_8());
|
||||
pos = f.get_pos();
|
||||
printf("byte at pos %i is %i\n", pos, (int)f.get_8());
|
||||
f.seek(4);
|
||||
pos = f.get_pos();
|
||||
printf("byte at pos %i is %i\n", pos, (int)f.get_8());
|
||||
pos = f.get_pos();
|
||||
printf("byte at pos %i is %i\n", pos, (int)f.get_8());
|
||||
pos = f.get_pos();
|
||||
printf("byte at pos %i is %i\n", pos, (int)f.get_8());
|
||||
|
||||
f.close();
|
||||
|
||||
DirAccessArchive d;
|
||||
String dir = "../blah1/blah2/blahask/../blah3/.//blah4/";
|
||||
printf("changing dir to %s\n", dir.utf8().get_data());
|
||||
d.change_dir(dir);
|
||||
printf("current dir is %s\n", d.get_current_dir().utf8().get_data());
|
||||
|
||||
FileAccessMemory::cleanup();
|
||||
#endif
|
||||
};
|
||||
|
||||
print_line("test done");
|
||||
|
||||
|
||||
return memnew( TestMainLoop );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
namespace TestIO {
|
||||
|
||||
|
||||
MainLoop* test() {
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
44
bin/tests/test_io.h
Normal file
44
bin/tests/test_io.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*************************************************************************/
|
||||
/* test_io.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 TEST_IO_H
|
||||
#define TEST_IO_H
|
||||
|
||||
/**
|
||||
@author Juan Linietsky <reduzio@gmail.com>
|
||||
*/
|
||||
|
||||
#include "os/main_loop.h"
|
||||
|
||||
namespace TestIO {
|
||||
|
||||
MainLoop* test();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
192
bin/tests/test_main.cpp
Normal file
192
bin/tests/test_main.cpp
Normal file
@ -0,0 +1,192 @@
|
||||
/*************************************************************************/
|
||||
/* test_main.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "list.h"
|
||||
#include "os/main_loop.h"
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
|
||||
#include "test_string.h"
|
||||
#include "test_containers.h"
|
||||
#include "test_math.h"
|
||||
#include "test_gui.h"
|
||||
#include "test_render.h"
|
||||
#include "test_sound.h"
|
||||
#include "test_misc.h"
|
||||
#include "test_physics.h"
|
||||
#include "test_physics_2d.h"
|
||||
#include "test_python.h"
|
||||
#include "test_io.h"
|
||||
#include "test_particles.h"
|
||||
#include "test_detailer.h"
|
||||
#include "test_shader_lang.h"
|
||||
#include "test_gdscript.h"
|
||||
#include "test_image.h"
|
||||
|
||||
|
||||
const char ** tests_get_names() {
|
||||
|
||||
static const char* test_names[]={
|
||||
"string",
|
||||
"containers",
|
||||
"math",
|
||||
"render",
|
||||
"particles",
|
||||
"multimesh",
|
||||
"gui",
|
||||
"io",
|
||||
"shaderlang",
|
||||
NULL
|
||||
};
|
||||
|
||||
return test_names;
|
||||
}
|
||||
|
||||
MainLoop* test_main(String p_test,const List<String>& p_args) {
|
||||
|
||||
|
||||
if (p_test=="string") {
|
||||
|
||||
return TestString::test();
|
||||
}
|
||||
|
||||
if (p_test=="containers") {
|
||||
|
||||
return TestContainers::test();
|
||||
}
|
||||
|
||||
if (p_test=="math") {
|
||||
|
||||
return TestMath::test();
|
||||
}
|
||||
|
||||
if (p_test=="physics") {
|
||||
|
||||
return TestPhysics::test();
|
||||
}
|
||||
|
||||
if (p_test=="physics_2d") {
|
||||
|
||||
return TestPhysics2D::test();
|
||||
}
|
||||
|
||||
if (p_test=="misc") {
|
||||
|
||||
return TestMisc::test();
|
||||
}
|
||||
|
||||
if (p_test=="render") {
|
||||
|
||||
return TestRender::test();
|
||||
}
|
||||
|
||||
#ifndef _3D_DISABLED
|
||||
if (p_test=="gui") {
|
||||
|
||||
return TestGUI::test();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (p_test=="sound") {
|
||||
|
||||
return TestSound::test();
|
||||
}
|
||||
|
||||
if (p_test=="io") {
|
||||
|
||||
return TestIO::test();
|
||||
}
|
||||
|
||||
if (p_test=="particles") {
|
||||
|
||||
return TestParticles::test();
|
||||
}
|
||||
|
||||
if (p_test=="multimesh") {
|
||||
|
||||
return TestMultiMesh::test();
|
||||
}
|
||||
|
||||
if (p_test=="shaderlang") {
|
||||
|
||||
return TestShaderLang::test();
|
||||
}
|
||||
|
||||
if (p_test=="gd_tokenizer") {
|
||||
|
||||
return TestGDScript::test(TestGDScript::TEST_TOKENIZER);
|
||||
}
|
||||
|
||||
if (p_test=="gd_parser") {
|
||||
|
||||
return TestGDScript::test(TestGDScript::TEST_PARSER);
|
||||
}
|
||||
|
||||
if (p_test=="gd_compiler") {
|
||||
|
||||
return TestGDScript::test(TestGDScript::TEST_COMPILER);
|
||||
}
|
||||
|
||||
if (p_test=="image") {
|
||||
|
||||
return TestImage::test();
|
||||
}
|
||||
|
||||
if (p_test=="detailer") {
|
||||
|
||||
return TestMultiMesh::test();
|
||||
}
|
||||
|
||||
#ifdef PYTHON_ENABLED
|
||||
|
||||
if (p_test=="python") {
|
||||
|
||||
return TestPython::test();
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
const char ** tests_get_names() {
|
||||
|
||||
static const char* test_names[]={
|
||||
NULL
|
||||
};
|
||||
|
||||
return test_names;
|
||||
}
|
||||
|
||||
MainLoop* test_main(String p_test,const List<String>& p_args) {
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
41
bin/tests/test_main.h
Normal file
41
bin/tests/test_main.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*************************************************************************/
|
||||
/* test_main.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 TEST_MAIN_H
|
||||
#define TEST_MAIN_H
|
||||
|
||||
#include "ustring.h"
|
||||
#include "list.h"
|
||||
|
||||
const char ** tests_get_names();
|
||||
MainLoop* test_main(String p_test,const List<String>& p_args);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
300
bin/tests/test_math.cpp
Normal file
300
bin/tests/test_math.cpp
Normal file
@ -0,0 +1,300 @@
|
||||
/*************************************************************************/
|
||||
/* test_math.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "test_math.h"
|
||||
#include "ustring.h"
|
||||
#include "print_string.h"
|
||||
#include "transform.h"
|
||||
#include "matrix3.h"
|
||||
#include "math_funcs.h"
|
||||
#include "camera_matrix.h"
|
||||
#include "scene/main/node.h"
|
||||
#include "variant.h"
|
||||
#include "servers/visual/shader_language.h"
|
||||
#include "os/keyboard.h"
|
||||
#include "scene/resources/texture.h"
|
||||
#include "vmap.h"
|
||||
#include "os/os.h"
|
||||
namespace TestMath {
|
||||
|
||||
|
||||
void test_vec(Plane p_vec) {
|
||||
|
||||
|
||||
CameraMatrix cm;
|
||||
cm.set_perspective(45,1,0,100);
|
||||
Plane v0=cm.xform4(p_vec);
|
||||
|
||||
print_line("out: "+v0);
|
||||
v0.normal.z = (v0.d/100.0 *2.0-1.0) * v0.d;
|
||||
print_line("out_F: "+v0);
|
||||
|
||||
|
||||
/*v0: 0, 0, -0.1, 0.1
|
||||
v1: 0, 0, 0, 0.1
|
||||
fix: 0, 0, 0, 0.1
|
||||
v0: 0, 0, 1.302803, 1.5
|
||||
v1: 0, 0, 1.401401, 1.5
|
||||
fix: 0, 0, 1.401401, 1.5
|
||||
v0: 0, 0, 25.851850, 26
|
||||
v1: 0, 0, 25.925926, 26
|
||||
fix: 0, 0, 25.925924, 26
|
||||
v0: 0, 0, 49.899902, 50
|
||||
v1: 0, 0, 49.949947, 50
|
||||
fix: 0, 0, 49.949951, 50
|
||||
v0: 0, 0, 100, 100
|
||||
v1: 0, 0, 100, 100
|
||||
fix: 0, 0, 100, 100
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
MainLoop* test() {
|
||||
|
||||
{
|
||||
|
||||
// print_line("NUM: "+itos(237641278346127));
|
||||
print_line("NUM: "+itos(-128));
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
Vector3 v(1,2,3);
|
||||
v.normalize();
|
||||
float a=0.3;
|
||||
|
||||
//Quat q(v,a);
|
||||
Matrix3 m(v,a);
|
||||
|
||||
Vector3 v2(7,3,1);
|
||||
v2.normalize();
|
||||
float a2=0.8;
|
||||
|
||||
//Quat q(v,a);
|
||||
Matrix3 m2(v2,a2);
|
||||
|
||||
Quat q=m;
|
||||
Quat q2=m2;
|
||||
|
||||
Matrix3 m3 = m.inverse() * m2;
|
||||
Quat q3 = (q.inverse() * q2);//.normalized();
|
||||
|
||||
print_line(Quat(m3));
|
||||
print_line(q3);
|
||||
|
||||
print_line("before v: "+v+" a: "+rtos(a));
|
||||
q.get_axis_and_angle(v,a);
|
||||
print_line("after v: "+v+" a: "+rtos(a));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
String ret;
|
||||
|
||||
List<String> args;
|
||||
args.push_back("-l");
|
||||
Error err = OS::get_singleton()->execute("/bin/ls",args,true,NULL,&ret);
|
||||
print_line("error: "+itos(err));
|
||||
print_line(ret);
|
||||
|
||||
return NULL;
|
||||
Matrix3 m3;
|
||||
m3.rotate(Vector3(1,0,0),0.2);
|
||||
m3.rotate(Vector3(0,1,0),1.77);
|
||||
m3.rotate(Vector3(0,0,1),212);
|
||||
Matrix3 m32;
|
||||
m32.set_euler(m3.get_euler());
|
||||
print_line("ELEULEEEEEEEEEEEEEEEEEER: "+m3.get_euler()+" vs "+m32.get_euler());
|
||||
|
||||
|
||||
return NULL;
|
||||
|
||||
{
|
||||
|
||||
Dictionary d;
|
||||
d["momo"]=1;
|
||||
Dictionary b=d;
|
||||
b["44"]=4;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return NULL;
|
||||
print_line("inters: "+rtos(Geometry::segment_intersects_circle(Vector2(-5,0),Vector2(-2,0),Vector2(),1.0)));
|
||||
|
||||
|
||||
|
||||
print_line("cross: "+Vector3(1,2,3).cross(Vector3(4,5,7)));
|
||||
print_line("dot: "+rtos(Vector3(1,2,3).dot(Vector3(4,5,7))));
|
||||
print_line("abs: "+Vector3(-1,2,-3).abs());
|
||||
print_line("distance_to: "+rtos(Vector3(1,2,3).distance_to(Vector3(4,5,7))));
|
||||
print_line("distance_squared_to: "+rtos(Vector3(1,2,3).distance_squared_to(Vector3(4,5,7))));
|
||||
print_line("plus: "+(Vector3(1,2,3)+Vector3(Vector3(4,5,7))));
|
||||
print_line("minus: "+(Vector3(1,2,3)-Vector3(Vector3(4,5,7))));
|
||||
print_line("mul: "+(Vector3(1,2,3)*Vector3(Vector3(4,5,7))));
|
||||
print_line("div: "+(Vector3(1,2,3)/Vector3(Vector3(4,5,7))));
|
||||
print_line("mul scalar: "+(Vector3(1,2,3)*2));
|
||||
print_line("premul scalar: "+(2*Vector3(1,2,3)));
|
||||
print_line("div scalar: "+(Vector3(1,2,3)/3.0));
|
||||
print_line("length: "+rtos(Vector3(1,2,3).length()));
|
||||
print_line("length squared: "+rtos(Vector3(1,2,3).length_squared()));
|
||||
print_line("normalized: "+Vector3(1,2,3).normalized());
|
||||
print_line("inverse: "+Vector3(1,2,3).inverse());
|
||||
|
||||
{
|
||||
Vector3 v(4,5,7);
|
||||
v.normalize();
|
||||
print_line("normalize: "+v);
|
||||
}
|
||||
|
||||
{
|
||||
Vector3 v(4,5,7);
|
||||
v+=Vector3(1,2,3);
|
||||
print_line("+=: "+v);
|
||||
}
|
||||
|
||||
{
|
||||
Vector3 v(4,5,7);
|
||||
v-=Vector3(1,2,3);
|
||||
print_line("-=: "+v);
|
||||
}
|
||||
|
||||
{
|
||||
Vector3 v(4,5,7);
|
||||
v*=Vector3(1,2,3);
|
||||
print_line("*=: "+v);
|
||||
}
|
||||
|
||||
{
|
||||
Vector3 v(4,5,7);
|
||||
v/=Vector3(1,2,3);
|
||||
print_line("/=: "+v);
|
||||
}
|
||||
|
||||
{
|
||||
Vector3 v(4,5,7);
|
||||
v*=2.0;
|
||||
print_line("scalar *=: "+v);
|
||||
}
|
||||
|
||||
{
|
||||
Vector3 v(4,5,7);
|
||||
v/=2.0;
|
||||
print_line("scalar /=: "+v);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
print_line(String("C:\\momo\\.\\popo\\..\\gongo").simplify_path());
|
||||
print_line(String("res://../popo/..//gongo").simplify_path());
|
||||
print_line(String("res://..").simplify_path());
|
||||
|
||||
|
||||
DVector<uint8_t> a;
|
||||
DVector<uint8_t> b;
|
||||
|
||||
a.resize(20);
|
||||
b=a;
|
||||
b.resize(30);
|
||||
a=b;
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
String za = String::utf8("á");
|
||||
printf("unicode: %x\n",za[0]);
|
||||
CharString cs=za.utf8();
|
||||
for(int i=0;i<cs.size();i++) {
|
||||
uint32_t v = uint8_t(cs[i]);
|
||||
printf("%i - %x\n",i,v);
|
||||
}
|
||||
return NULL;
|
||||
|
||||
print_line(String("C:\\window\\system\\momo").path_to("C:\\window\\momonga"));
|
||||
print_line(String("res://momo/sampler").path_to("res://pindonga"));
|
||||
print_line(String("/margarito/terere").path_to("/margarito/pilates"));
|
||||
print_line(String("/algo").path_to("/algo"));
|
||||
print_line(String("c:").path_to("c:\\"));
|
||||
print_line(String("/").path_to("/"));
|
||||
|
||||
|
||||
print_line(itos(sizeof(Variant)));
|
||||
return NULL;
|
||||
|
||||
Vector<StringName> path;
|
||||
path.push_back("three");
|
||||
path.push_back("two");
|
||||
path.push_back("one");
|
||||
path.push_back("comeon");
|
||||
path.revert();
|
||||
|
||||
NodePath np(path,true);
|
||||
|
||||
print_line(np);
|
||||
|
||||
|
||||
return NULL;
|
||||
|
||||
bool a=2;
|
||||
|
||||
print_line(Variant(a));
|
||||
|
||||
|
||||
Matrix32 mat2_1;
|
||||
mat2_1.rotate(0.5);
|
||||
Matrix32 mat2_2;
|
||||
mat2_2.translate(Vector2(1,2));
|
||||
Matrix32 mat2_3 = mat2_1 * mat2_2;
|
||||
mat2_3.affine_invert();
|
||||
|
||||
print_line(mat2_3.elements[0]);
|
||||
print_line(mat2_3.elements[1]);
|
||||
print_line(mat2_3.elements[2]);
|
||||
|
||||
|
||||
|
||||
Transform mat3_1;
|
||||
mat3_1.basis.rotate(Vector3(0,0,1),0.5);
|
||||
Transform mat3_2;
|
||||
mat3_2.translate(Vector3(1,2,0));
|
||||
Transform mat3_3 = mat3_1 * mat3_2;
|
||||
mat3_3.affine_invert();
|
||||
|
||||
print_line(mat3_3.basis.get_axis(0));
|
||||
print_line(mat3_3.basis.get_axis(1));
|
||||
print_line(mat3_3.origin);
|
||||
|
||||
#endif
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
}
|
40
bin/tests/test_math.h
Normal file
40
bin/tests/test_math.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*************************************************************************/
|
||||
/* test_math.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 TEST_MATH_H
|
||||
#define TEST_MATH_H
|
||||
|
||||
#include "os/main_loop.h"
|
||||
|
||||
namespace TestMath {
|
||||
|
||||
MainLoop* test();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
499
bin/tests/test_misc.cpp
Normal file
499
bin/tests/test_misc.cpp
Normal file
@ -0,0 +1,499 @@
|
||||
/*************************************************************************/
|
||||
/* test_misc.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "test_misc.h"
|
||||
#include "servers/visual_server.h"
|
||||
#include "os/main_loop.h"
|
||||
#include "math_funcs.h"
|
||||
#include "print_string.h"
|
||||
|
||||
|
||||
namespace TestMisc {
|
||||
|
||||
struct ConvexTestResult
|
||||
{
|
||||
|
||||
Vector3 edgeA[2];
|
||||
Vector3 edgeB[2];
|
||||
bool valid;
|
||||
Vector3 contactA;
|
||||
Vector3 contactB;
|
||||
Vector3 contactNormal;
|
||||
float depth;
|
||||
|
||||
/*
|
||||
Vector3 contactA;
|
||||
Vector3 contactB;
|
||||
Vector3 contactNormal;
|
||||
Vector3 contactX;
|
||||
Vector3 contactY;
|
||||
Vector3 edgeA[2];
|
||||
Vector3 edgeB[2];
|
||||
float depth;
|
||||
bool valid;
|
||||
bool isEdgeEdge;
|
||||
bool needTransform;
|
||||
neBool ComputerEdgeContactPoint(ConvexTestResult & res);
|
||||
neBool ComputerEdgeContactPoint2(float & au, float & bu);
|
||||
void Reverse()
|
||||
{
|
||||
neSwap(contactA, contactB);
|
||||
contactNormal *= -1.0f;
|
||||
}*/
|
||||
bool ComputerEdgeContactPoint2(float & au, float & bu);
|
||||
};
|
||||
|
||||
|
||||
|
||||
bool ConvexTestResult::ComputerEdgeContactPoint2(float & au, float & bu)
|
||||
{
|
||||
float d1343, d4321, d1321, d4343, d2121;
|
||||
float numer, denom;
|
||||
|
||||
Vector3 p13;
|
||||
Vector3 p43;
|
||||
Vector3 p21;
|
||||
Vector3 diff;
|
||||
|
||||
p13 = (edgeA[0]) - (edgeB[0]);
|
||||
p43 = (edgeB[1]) - (edgeB[0]);
|
||||
|
||||
if ( p43.length_squared() < CMP_EPSILON2 )
|
||||
{
|
||||
valid = false;
|
||||
goto ComputerEdgeContactPoint2_Exit;
|
||||
}
|
||||
|
||||
p21 = (edgeA[1]) - (edgeA[0]);
|
||||
|
||||
if ( p21.length_squared()<CMP_EPSILON2 )
|
||||
{
|
||||
valid = false;
|
||||
goto ComputerEdgeContactPoint2_Exit;
|
||||
}
|
||||
|
||||
d1343 = p13.dot(p43);
|
||||
d4321 = p43.dot(p21);
|
||||
d1321 = p13.dot(p21);
|
||||
d4343 = p43.dot(p43);
|
||||
d2121 = p21.dot(p21);
|
||||
|
||||
denom = d2121 * d4343 - d4321 * d4321;
|
||||
|
||||
if (ABS(denom) < CMP_EPSILON)
|
||||
{
|
||||
valid = false;
|
||||
|
||||
goto ComputerEdgeContactPoint2_Exit;
|
||||
}
|
||||
|
||||
numer = d1343 * d4321 - d1321 * d4343;
|
||||
au = numer / denom;
|
||||
bu = (d1343 + d4321 * (au)) / d4343;
|
||||
|
||||
if (au < 0.0f || au >= 1.0f)
|
||||
{
|
||||
valid = false;
|
||||
}
|
||||
else if (bu < 0.0f || bu >= 1.0f)
|
||||
{
|
||||
valid = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
valid = true;
|
||||
}
|
||||
{
|
||||
Vector3 tmpv;
|
||||
|
||||
tmpv = p21 * au;
|
||||
contactA = (edgeA[0]) + tmpv;
|
||||
|
||||
tmpv = p43 * bu;
|
||||
contactB = (edgeB[0]) + tmpv;
|
||||
}
|
||||
|
||||
diff = contactA - contactB;
|
||||
|
||||
depth = Math::sqrt(diff.dot(diff));
|
||||
|
||||
return true;
|
||||
|
||||
ComputerEdgeContactPoint2_Exit:
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct neCollisionResult {
|
||||
|
||||
float depth;
|
||||
bool penetrate;
|
||||
Matrix3 collisionFrame;
|
||||
Vector3 contactA;
|
||||
Vector3 contactB;
|
||||
};
|
||||
|
||||
|
||||
struct TConvex {
|
||||
|
||||
float radius;
|
||||
float half_height;
|
||||
float CylinderRadius() const { return radius; }
|
||||
float CylinderHalfHeight() const { return half_height; }
|
||||
};
|
||||
|
||||
float GetDistanceFromLine2(Vector3 v, Vector3 & project, const Vector3 & pointA, const Vector3 & pointB)
|
||||
{
|
||||
Vector3 ba = pointB - pointA;
|
||||
|
||||
float len = ba.length();
|
||||
|
||||
if (len<CMP_EPSILON)
|
||||
ba=Vector3();
|
||||
else
|
||||
ba *= 1.0f / len;
|
||||
|
||||
Vector3 pa = v - pointA;
|
||||
|
||||
float k = pa.dot(ba);
|
||||
|
||||
project = pointA + ba * k;
|
||||
|
||||
Vector3 diff = v - project;
|
||||
|
||||
return diff.length();
|
||||
}
|
||||
|
||||
void TestCylinderVertEdge(neCollisionResult & result, Vector3 & edgeA1, Vector3 & edgeA2, Vector3 & vertB,
|
||||
TConvex & cA, TConvex & cB, Transform & transA, Transform & transB, bool flip)
|
||||
{
|
||||
Vector3 project;
|
||||
|
||||
float dist = GetDistanceFromLine2(vertB,project, edgeA1, edgeA2);
|
||||
|
||||
float depth = cA.CylinderRadius() + cB.CylinderRadius() - dist;
|
||||
|
||||
if (depth <= 0.0f)
|
||||
return;
|
||||
|
||||
if (depth <= result.depth)
|
||||
return;
|
||||
|
||||
result.penetrate = true;
|
||||
|
||||
result.depth = depth;
|
||||
|
||||
if (!flip)
|
||||
{
|
||||
result.collisionFrame.set_axis(2,(project - vertB).normalized());
|
||||
|
||||
result.contactA = project - result.collisionFrame.get_axis(2) * cA.CylinderRadius();
|
||||
|
||||
result.contactB = vertB + result.collisionFrame.get_axis(2) * cB.CylinderRadius();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
result.collisionFrame.set_axis(2,(vertB - project).normalized());
|
||||
|
||||
result.contactA = vertB - result.collisionFrame.get_axis(2) * cB.CylinderRadius();
|
||||
|
||||
result.contactB = project + result.collisionFrame.get_axis(2) * cA.CylinderRadius();
|
||||
}
|
||||
}
|
||||
|
||||
void TestCylinderVertVert(neCollisionResult & result, Vector3 & vertA, Vector3 & vertB,
|
||||
TConvex & cA, TConvex & cB, Transform & transA, Transform & transB)
|
||||
{
|
||||
Vector3 diff = vertA - vertB;
|
||||
|
||||
float dist = diff.length();
|
||||
|
||||
float depth = cA.CylinderRadius() + cB.CylinderRadius() - dist;
|
||||
|
||||
if (depth <= 0.0f)
|
||||
return;
|
||||
|
||||
if (depth <= result.depth)
|
||||
return;
|
||||
|
||||
result.penetrate = true;
|
||||
|
||||
result.depth = depth;
|
||||
|
||||
result.collisionFrame.set_axis(2, diff * (1.0f / dist));
|
||||
|
||||
result.contactA = vertA - result.collisionFrame.get_axis(2) * cA.CylinderRadius();
|
||||
|
||||
result.contactB = vertB + result.collisionFrame.get_axis(2) * cB.CylinderRadius();
|
||||
}
|
||||
|
||||
void Cylinder2CylinderTest(neCollisionResult & result, TConvex & cA, Transform & transA, TConvex & cB, Transform & transB)
|
||||
{
|
||||
result.penetrate = false;
|
||||
|
||||
Vector3 dir = transA.basis.get_axis(1).cross(transB.basis.get_axis(1));
|
||||
|
||||
float len = dir.length();
|
||||
|
||||
// bool isParallel = len<CMP_EPSILON;
|
||||
|
||||
// int doVertCheck = 0;
|
||||
|
||||
ConvexTestResult cr;
|
||||
|
||||
cr.edgeA[0] = transA.origin + transA.basis.get_axis(1) * cA.CylinderHalfHeight();
|
||||
cr.edgeA[1] = transA.origin - transA.basis.get_axis(1) * cA.CylinderHalfHeight();
|
||||
cr.edgeB[0] = transB.origin + transB.basis.get_axis(1) * cB.CylinderHalfHeight();
|
||||
cr.edgeB[1] = transB.origin - transB.basis.get_axis(1) * cB.CylinderHalfHeight();
|
||||
|
||||
// float dot = transA.basis.get_axis(1).dot(transB.basis.get_axis(1));
|
||||
|
||||
if (len>CMP_EPSILON)
|
||||
{
|
||||
float au, bu;
|
||||
|
||||
cr.ComputerEdgeContactPoint2(au, bu);
|
||||
|
||||
if (cr.valid)
|
||||
{
|
||||
float depth = cA.CylinderRadius() + cB.CylinderRadius() - cr.depth;
|
||||
|
||||
if (depth <= 0.0f)
|
||||
return;
|
||||
|
||||
result.depth = depth;
|
||||
|
||||
result.penetrate = true;
|
||||
|
||||
result.collisionFrame.set_axis(2, (cr.contactA - cr.contactB)*(1.0f / cr.depth));
|
||||
|
||||
result.contactA = cr.contactA - result.collisionFrame.get_axis(2) * cA.CylinderRadius();
|
||||
|
||||
result.contactB = cr.contactB + result.collisionFrame.get_axis(2) * cB.CylinderRadius();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
result.depth = -1.0e6f;
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
//project onto edge b
|
||||
|
||||
Vector3 diff = cr.edgeA[i] - cr.edgeB[1];
|
||||
|
||||
float dot = diff.dot(transB.basis.get_axis(1));
|
||||
|
||||
if (dot < 0.0f)
|
||||
{
|
||||
TestCylinderVertVert(result, cr.edgeA[i], cr.edgeB[1], cA, cB, transA, transB);
|
||||
}
|
||||
else if (dot > (2.0f * cB.CylinderHalfHeight()))
|
||||
{
|
||||
TestCylinderVertVert(result, cr.edgeA[i], cr.edgeB[0], cA, cB, transA, transB);
|
||||
}
|
||||
else
|
||||
{
|
||||
TestCylinderVertEdge(result, cr.edgeB[0], cr.edgeB[1], cr.edgeA[i], cB, cA, transB, transA, true);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
//project onto edge b
|
||||
|
||||
Vector3 diff = cr.edgeB[i] - cr.edgeA[1];
|
||||
|
||||
float dot = diff.dot(transA.basis.get_axis(1));
|
||||
|
||||
if (dot < 0.0f)
|
||||
{
|
||||
TestCylinderVertVert(result, cr.edgeB[i], cr.edgeA[1], cA, cB, transA, transB);
|
||||
}
|
||||
else if (dot > (2.0f * cB.CylinderHalfHeight()))
|
||||
{
|
||||
TestCylinderVertVert(result, cr.edgeB[i], cr.edgeA[0], cA, cB, transA, transB);
|
||||
}
|
||||
else
|
||||
{
|
||||
TestCylinderVertEdge(result, cr.edgeA[0], cr.edgeA[1], cr.edgeB[i], cA, cB, transA, transB, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class TestMainLoop : public MainLoop {
|
||||
|
||||
RID meshA;
|
||||
RID meshB;
|
||||
RID poly;
|
||||
RID instance;
|
||||
RID camera;
|
||||
RID viewport;
|
||||
RID boxA;
|
||||
RID boxB;
|
||||
RID scenario;
|
||||
|
||||
Transform rot_a;
|
||||
Transform rot_b;
|
||||
|
||||
bool quit;
|
||||
public:
|
||||
virtual void input_event(const InputEvent& p_event) {
|
||||
|
||||
if (p_event.type==InputEvent::MOUSE_MOTION && p_event.mouse_motion.button_mask&BUTTON_MASK_LEFT) {
|
||||
|
||||
rot_b.origin.y+=-p_event.mouse_motion.relative_y/100.0;
|
||||
rot_b.origin.x+=p_event.mouse_motion.relative_x/100.0;
|
||||
}
|
||||
if (p_event.type==InputEvent::MOUSE_MOTION && p_event.mouse_motion.button_mask&BUTTON_MASK_MIDDLE) {
|
||||
|
||||
//rot_b.origin.x+=-p_event.mouse_motion.relative_y/100.0;
|
||||
rot_b.origin.z+=p_event.mouse_motion.relative_x/100.0;
|
||||
}
|
||||
if (p_event.type==InputEvent::MOUSE_MOTION && p_event.mouse_motion.button_mask&BUTTON_MASK_RIGHT) {
|
||||
|
||||
float rot_x=-p_event.mouse_motion.relative_y/100.0;
|
||||
float rot_y=p_event.mouse_motion.relative_x/100.0;
|
||||
rot_b.basis = rot_b.basis * Matrix3(Vector3(1,0,0),rot_x) * Matrix3(Vector3(0,1,0),rot_y);
|
||||
}
|
||||
|
||||
}
|
||||
virtual void request_quit() {
|
||||
|
||||
quit=true;
|
||||
}
|
||||
virtual void init() {
|
||||
|
||||
VisualServer *vs=VisualServer::get_singleton();
|
||||
|
||||
camera = vs->camera_create();
|
||||
|
||||
viewport = vs->viewport_create();
|
||||
vs->viewport_attach_to_screen(viewport);
|
||||
vs->viewport_attach_camera( viewport, camera );
|
||||
vs->camera_set_transform(camera, Transform( Matrix3(), Vector3(0,0,3 ) ) );
|
||||
|
||||
/* CONVEX SHAPE */
|
||||
|
||||
DVector<Plane> cylinder_planes = Geometry::build_cylinder_planes(0.5,2,9,Vector3::AXIS_Y);
|
||||
RID cylinder_material = vs->fixed_material_create();
|
||||
vs->fixed_material_set_param( cylinder_material, VisualServer::FIXED_MATERIAL_PARAM_DIFFUSE, Color(0.8,0.2,0.9));
|
||||
vs->material_set_flag( cylinder_material, VisualServer::MATERIAL_FLAG_ONTOP,true);
|
||||
vs->material_set_flag( cylinder_material, VisualServer::MATERIAL_FLAG_WIREFRAME,true);
|
||||
vs->material_set_flag( cylinder_material, VisualServer::MATERIAL_FLAG_DOUBLE_SIDED,true);
|
||||
vs->material_set_flag( cylinder_material, VisualServer::MATERIAL_FLAG_UNSHADED,true);
|
||||
|
||||
RID cylinder_mesh = vs->mesh_create();
|
||||
Geometry::MeshData cylinder_data = Geometry::build_convex_mesh(cylinder_planes);
|
||||
vs->mesh_add_surface_from_mesh_data(cylinder_mesh,cylinder_data);
|
||||
vs->mesh_surface_set_material( cylinder_mesh, 0, cylinder_material );
|
||||
|
||||
meshA=vs->instance_create2(cylinder_mesh,scenario);
|
||||
meshB=vs->instance_create2(cylinder_mesh,scenario);
|
||||
boxA=vs->instance_create2(vs->get_test_cube(),scenario);
|
||||
boxB=vs->instance_create2(vs->get_test_cube(),scenario);
|
||||
|
||||
/*
|
||||
RID lightaux = vs->light_create( VisualServer::LIGHT_OMNI );
|
||||
vs->light_set_var( lightaux, VisualServer::LIGHT_VAR_RADIUS, 80 );
|
||||
vs->light_set_var( lightaux, VisualServer::LIGHT_VAR_ATTENUATION, 1 );
|
||||
vs->light_set_var( lightaux, VisualServer::LIGHT_VAR_ENERGY, 1.5 );
|
||||
light = vs->instance_create2( lightaux );
|
||||
*/
|
||||
RID lightaux = vs->light_create( VisualServer::LIGHT_DIRECTIONAL );
|
||||
vs->light_set_color( lightaux, VisualServer::LIGHT_COLOR_AMBIENT, Color(0.0,0.0,0.0) );
|
||||
//vs->light_set_shadow( lightaux, true );
|
||||
RID light = vs->instance_create2( lightaux,scenario );
|
||||
|
||||
//rot_a=Transform(Matrix3(Vector3(1,0,0),Math_PI/2.0),Vector3());
|
||||
rot_b=Transform(Matrix3(),Vector3(2,0,0));
|
||||
|
||||
//rot_x=0;
|
||||
//rot_y=0;
|
||||
quit=false;
|
||||
}
|
||||
virtual bool idle(float p_time) {
|
||||
|
||||
VisualServer *vs=VisualServer::get_singleton();
|
||||
|
||||
vs->instance_set_transform(meshA,rot_a);
|
||||
vs->instance_set_transform(meshB,rot_b);
|
||||
|
||||
|
||||
neCollisionResult res;
|
||||
TConvex a;
|
||||
a.radius=0.5;
|
||||
a.half_height=1;
|
||||
Cylinder2CylinderTest(res,a,rot_a,a,rot_b);
|
||||
if (res.penetrate) {
|
||||
|
||||
Matrix3 scale;
|
||||
scale.scale(Vector3(0.1,0.1,0.1));
|
||||
vs->instance_set_transform(boxA,Transform(scale,res.contactA));
|
||||
vs->instance_set_transform(boxB,Transform(scale,res.contactB));
|
||||
print_line("depth: "+rtos(res.depth));
|
||||
} else {
|
||||
|
||||
Matrix3 scale;
|
||||
scale.scale(Vector3());
|
||||
vs->instance_set_transform(boxA,Transform(scale,res.contactA));
|
||||
vs->instance_set_transform(boxB,Transform(scale,res.contactB));
|
||||
|
||||
}
|
||||
print_line("collided: "+itos(res.penetrate));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
virtual bool iteration(float p_time) {
|
||||
|
||||
|
||||
|
||||
return quit;
|
||||
}
|
||||
virtual void finish() {
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
MainLoop* test() {
|
||||
|
||||
return memnew( TestMainLoop );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
40
bin/tests/test_misc.h
Normal file
40
bin/tests/test_misc.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*************************************************************************/
|
||||
/* test_misc.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 TEST_MISC_H
|
||||
#define TEST_MISC_H
|
||||
|
||||
#include "os/main_loop.h"
|
||||
|
||||
namespace TestMisc {
|
||||
|
||||
MainLoop* test();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
121
bin/tests/test_particles.cpp
Normal file
121
bin/tests/test_particles.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
/*************************************************************************/
|
||||
/* test_particles.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "test_particles.h"
|
||||
#include "servers/visual_server.h"
|
||||
#include "os/main_loop.h"
|
||||
#include "math_funcs.h"
|
||||
#include "print_string.h"
|
||||
|
||||
namespace TestParticles {
|
||||
|
||||
|
||||
class TestMainLoop : public MainLoop {
|
||||
|
||||
RID particles;
|
||||
RID instance;
|
||||
RID camera;
|
||||
RID viewport;
|
||||
RID light;
|
||||
RID scenario;
|
||||
|
||||
struct InstanceInfo {
|
||||
|
||||
RID instance;
|
||||
Transform base;
|
||||
Vector3 rot_axis;
|
||||
};
|
||||
|
||||
List<InstanceInfo> instances;
|
||||
|
||||
float ofs;
|
||||
bool quit;
|
||||
public:
|
||||
virtual void input_event(const InputEvent& p_event) {
|
||||
|
||||
|
||||
}
|
||||
virtual void request_quit() {
|
||||
|
||||
quit=true;
|
||||
}
|
||||
virtual void init() {
|
||||
|
||||
VisualServer *vs=VisualServer::get_singleton();
|
||||
particles = vs->particles_create();
|
||||
vs->particles_set_amount(particles,1000);
|
||||
|
||||
instance = vs->instance_create2(particles,scenario);
|
||||
|
||||
|
||||
camera = vs->camera_create();
|
||||
|
||||
// vs->camera_set_perspective( camera, 60.0,0.1, 100.0 );
|
||||
viewport = vs->viewport_create();
|
||||
vs->viewport_attach_camera( viewport, camera );
|
||||
vs->camera_set_transform(camera, Transform( Matrix3(), Vector3(0,0,20 ) ) );
|
||||
/*
|
||||
RID lightaux = vs->light_create( VisualServer::LIGHT_OMNI );
|
||||
vs->light_set_var( lightaux, VisualServer::LIGHT_VAR_RADIUS, 80 );
|
||||
vs->light_set_var( lightaux, VisualServer::LIGHT_VAR_ATTENUATION, 1 );
|
||||
vs->light_set_var( lightaux, VisualServer::LIGHT_VAR_ENERGY, 1.5 );
|
||||
light = vs->instance_create2( lightaux );
|
||||
*/
|
||||
RID lightaux = vs->light_create( VisualServer::LIGHT_DIRECTIONAL );
|
||||
vs->light_set_color( lightaux, VisualServer::LIGHT_COLOR_AMBIENT, Color(0.0,0.0,0.0) );
|
||||
light = vs->instance_create2( lightaux, scenario );
|
||||
|
||||
ofs=0;
|
||||
quit=false;
|
||||
}
|
||||
virtual bool idle(float p_time) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
virtual bool iteration(float p_time) {
|
||||
|
||||
// VisualServer *vs=VisualServer::get_singleton();
|
||||
|
||||
ofs+=p_time;
|
||||
return quit;
|
||||
}
|
||||
virtual void finish() {
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
MainLoop* test() {
|
||||
|
||||
return memnew( TestMainLoop );
|
||||
|
||||
}
|
||||
|
||||
}
|
43
bin/tests/test_particles.h
Normal file
43
bin/tests/test_particles.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*************************************************************************/
|
||||
/* test_particles.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 TEST_PARTICLES_H
|
||||
#define TEST_PARTICLES_H
|
||||
|
||||
/**
|
||||
@author Juan Linietsky <reduzio@gmail.com>
|
||||
*/
|
||||
#include "os/main_loop.h"
|
||||
|
||||
namespace TestParticles {
|
||||
|
||||
MainLoop* test();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
662
bin/tests/test_physics.cpp
Normal file
662
bin/tests/test_physics.cpp
Normal file
@ -0,0 +1,662 @@
|
||||
/*************************************************************************/
|
||||
/* test_physics.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "test_physics.h"
|
||||
|
||||
|
||||
#include "servers/visual_server.h"
|
||||
#include "servers/physics_server.h"
|
||||
#include "os/main_loop.h"
|
||||
#include "math_funcs.h"
|
||||
#include "print_string.h"
|
||||
#include "map.h"
|
||||
#include "os/os.h"
|
||||
#include "quick_hull.h"
|
||||
|
||||
class TestPhysicsMainLoop : public MainLoop {
|
||||
|
||||
OBJ_TYPE( TestPhysicsMainLoop, MainLoop );
|
||||
|
||||
enum {
|
||||
LINK_COUNT = 20,
|
||||
};
|
||||
|
||||
RID test_cube;
|
||||
|
||||
RID plane;
|
||||
RID sphere;
|
||||
RID light;
|
||||
RID camera;
|
||||
RID mover;
|
||||
RID scenario;
|
||||
RID space;
|
||||
|
||||
RID character;
|
||||
|
||||
float ofs_x,ofs_y;
|
||||
|
||||
Point2 joy_direction;
|
||||
|
||||
List<RID> bodies;
|
||||
Map<PhysicsServer::ShapeType,RID> type_shape_map;
|
||||
Map<PhysicsServer::ShapeType,RID> type_mesh_map;
|
||||
|
||||
void body_changed_transform(Object *p_state, RID p_visual_instance) {
|
||||
|
||||
PhysicsDirectBodyState *state = (PhysicsDirectBodyState*)p_state;
|
||||
VisualServer *vs=VisualServer::get_singleton();
|
||||
Transform t=state->get_transform();
|
||||
//t.basis.scale( Vector3(1.0,0.5,0.2) );
|
||||
vs->instance_set_transform(p_visual_instance,t);
|
||||
}
|
||||
|
||||
bool quit;
|
||||
|
||||
protected:
|
||||
|
||||
static void _bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method("body_changed_transform",&TestPhysicsMainLoop::body_changed_transform);
|
||||
}
|
||||
|
||||
RID create_body(PhysicsServer::ShapeType p_shape, PhysicsServer::BodyMode p_body,const Transform p_location,bool p_active_default=true,const Transform&p_shape_xform=Transform()) {
|
||||
|
||||
VisualServer *vs=VisualServer::get_singleton();
|
||||
PhysicsServer * ps = PhysicsServer::get_singleton();
|
||||
|
||||
RID mesh_instance = vs->instance_create2(type_mesh_map[p_shape],scenario);
|
||||
RID body = ps->body_create(p_body,!p_active_default);
|
||||
ps->body_set_space(body,space);
|
||||
ps->body_set_param(body,PhysicsServer::BODY_PARAM_BOUNCE,0.5);
|
||||
//todo set space
|
||||
ps->body_add_shape(body,type_shape_map[p_shape]);
|
||||
ps->body_set_force_integration_callback(body,this,"body_changed_transform",mesh_instance);
|
||||
|
||||
ps->body_set_state( body, PhysicsServer::BODY_STATE_TRANSFORM,p_location);
|
||||
bodies.push_back(body);
|
||||
|
||||
if (p_body==PhysicsServer::BODY_MODE_STATIC) {
|
||||
|
||||
vs->instance_set_transform(mesh_instance,p_location);
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
RID create_static_plane(const Plane& p_plane) {
|
||||
|
||||
PhysicsServer * ps = PhysicsServer::get_singleton();
|
||||
|
||||
RID plane_shape = ps->shape_create(PhysicsServer::SHAPE_PLANE);;
|
||||
ps->shape_set_data( plane_shape, p_plane );
|
||||
|
||||
RID b = ps->body_create( PhysicsServer::BODY_MODE_STATIC );
|
||||
ps->body_set_space(b,space);
|
||||
//todo set space
|
||||
ps->body_add_shape(b, plane_shape);
|
||||
return b;
|
||||
|
||||
}
|
||||
|
||||
void configure_body(RID p_body,float p_mass, float p_friction, float p_bounce) {
|
||||
|
||||
PhysicsServer * ps = PhysicsServer::get_singleton();
|
||||
ps->body_set_param( p_body, PhysicsServer::BODY_PARAM_MASS, p_mass );
|
||||
ps->body_set_param( p_body, PhysicsServer::BODY_PARAM_FRICTION, p_friction );
|
||||
ps->body_set_param( p_body, PhysicsServer::BODY_PARAM_BOUNCE, p_bounce );
|
||||
|
||||
}
|
||||
|
||||
void init_shapes() {
|
||||
|
||||
VisualServer *vs=VisualServer::get_singleton();
|
||||
PhysicsServer * ps = PhysicsServer::get_singleton();
|
||||
|
||||
/* SPHERE SHAPE */
|
||||
RID sphere_mesh = vs->make_sphere_mesh(10,20,0.5);
|
||||
RID sphere_material = vs->fixed_material_create();
|
||||
//vs->material_set_flag( sphere_material, VisualServer::MATERIAL_FLAG_WIREFRAME, true );
|
||||
vs->fixed_material_set_param( sphere_material, VisualServer::FIXED_MATERIAL_PARAM_DIFFUSE, Color(0.7,0.8,3.0) );
|
||||
vs->mesh_surface_set_material( sphere_mesh, 0, sphere_material );
|
||||
type_mesh_map[PhysicsServer::SHAPE_SPHERE]=sphere_mesh;
|
||||
|
||||
RID sphere_shape=ps->shape_create(PhysicsServer::SHAPE_SPHERE);
|
||||
ps->shape_set_data( sphere_shape, 0.5 );
|
||||
type_shape_map[PhysicsServer::SHAPE_SPHERE]=sphere_shape;
|
||||
|
||||
/* BOX SHAPE */
|
||||
|
||||
DVector<Plane> box_planes = Geometry::build_box_planes(Vector3(0.5,0.5,0.5));
|
||||
RID box_material = vs->fixed_material_create();
|
||||
vs->fixed_material_set_param( box_material, VisualServer::FIXED_MATERIAL_PARAM_DIFFUSE, Color(1.0,0.2,0.2) );
|
||||
RID box_mesh = vs->mesh_create();
|
||||
Geometry::MeshData box_data = Geometry::build_convex_mesh(box_planes);
|
||||
vs->mesh_add_surface_from_mesh_data(box_mesh,box_data);
|
||||
vs->mesh_surface_set_material( box_mesh, 0, box_material );
|
||||
type_mesh_map[PhysicsServer::SHAPE_BOX]=box_mesh;
|
||||
|
||||
RID box_shape=ps->shape_create(PhysicsServer::SHAPE_BOX);
|
||||
ps->shape_set_data( box_shape, Vector3(0.5,0.5,0.5) );
|
||||
type_shape_map[PhysicsServer::SHAPE_BOX]=box_shape;
|
||||
|
||||
|
||||
/* CAPSULE SHAPE */
|
||||
|
||||
DVector<Plane> capsule_planes = Geometry::build_capsule_planes(0.5,0.7,12,Vector3::AXIS_Z);
|
||||
RID capsule_material = vs->fixed_material_create();
|
||||
vs->fixed_material_set_param( capsule_material, VisualServer::FIXED_MATERIAL_PARAM_DIFFUSE, Color(0.3,0.4,1.0) );
|
||||
|
||||
RID capsule_mesh = vs->mesh_create();
|
||||
Geometry::MeshData capsule_data = Geometry::build_convex_mesh(capsule_planes);
|
||||
vs->mesh_add_surface_from_mesh_data(capsule_mesh,capsule_data);
|
||||
vs->mesh_surface_set_material( capsule_mesh, 0, capsule_material );
|
||||
type_mesh_map[PhysicsServer::SHAPE_CAPSULE]=capsule_mesh;
|
||||
|
||||
RID capsule_shape=ps->shape_create(PhysicsServer::SHAPE_CAPSULE);
|
||||
Dictionary capsule_params;
|
||||
capsule_params["radius"]=0.5;
|
||||
capsule_params["height"]=1.4;
|
||||
ps->shape_set_data( capsule_shape, capsule_params );
|
||||
type_shape_map[PhysicsServer::SHAPE_CAPSULE]=capsule_shape;
|
||||
|
||||
/* CONVEX SHAPE */
|
||||
|
||||
DVector<Plane> convex_planes = Geometry::build_cylinder_planes(0.5,0.7,5,Vector3::AXIS_Z);
|
||||
RID convex_material = vs->fixed_material_create();
|
||||
vs->fixed_material_set_param( convex_material, VisualServer::FIXED_MATERIAL_PARAM_DIFFUSE, Color(0.8,0.2,0.9));
|
||||
|
||||
RID convex_mesh = vs->mesh_create();
|
||||
Geometry::MeshData convex_data = Geometry::build_convex_mesh(convex_planes);
|
||||
QuickHull::build(convex_data.vertices,convex_data);
|
||||
vs->mesh_add_surface_from_mesh_data(convex_mesh,convex_data);
|
||||
vs->mesh_surface_set_material( convex_mesh, 0, convex_material );
|
||||
type_mesh_map[PhysicsServer::SHAPE_CONVEX_POLYGON]=convex_mesh;
|
||||
|
||||
RID convex_shape=ps->shape_create(PhysicsServer::SHAPE_CONVEX_POLYGON);
|
||||
ps->shape_set_data( convex_shape, convex_data.vertices );
|
||||
type_shape_map[PhysicsServer::SHAPE_CONVEX_POLYGON]=convex_shape;
|
||||
|
||||
}
|
||||
|
||||
void make_trimesh(Vector<Vector3> p_faces,const Transform& p_xform=Transform()) {
|
||||
|
||||
VisualServer *vs=VisualServer::get_singleton();
|
||||
PhysicsServer * ps = PhysicsServer::get_singleton();
|
||||
RID trimesh_shape = ps->shape_create(PhysicsServer::SHAPE_CONCAVE_POLYGON);
|
||||
ps->shape_set_data(trimesh_shape, p_faces);
|
||||
p_faces=ps->shape_get_data(trimesh_shape); // optimized one
|
||||
Vector<Vector3> normals; // for drawing
|
||||
for (int i=0;i<p_faces.size()/3;i++) {
|
||||
|
||||
Plane p( p_faces[i*3+0],p_faces[i*3+1], p_faces[i*3+2] );
|
||||
normals.push_back(p.normal);
|
||||
normals.push_back(p.normal);
|
||||
normals.push_back(p.normal);
|
||||
}
|
||||
|
||||
RID trimesh_mesh = vs->mesh_create();
|
||||
Array d;
|
||||
d.resize(VS::ARRAY_MAX);
|
||||
d[VS::ARRAY_VERTEX]=p_faces;
|
||||
d[VS::ARRAY_NORMAL]=normals;
|
||||
vs->mesh_add_surface(trimesh_mesh, VS::PRIMITIVE_TRIANGLES, d );
|
||||
RID trimesh_mat = vs->fixed_material_create();
|
||||
vs->fixed_material_set_param( trimesh_mat, VisualServer::FIXED_MATERIAL_PARAM_DIFFUSE, Color(1.0,0.5,0.8));
|
||||
//vs->material_set_flag( trimesh_mat, VisualServer::MATERIAL_FLAG_UNSHADED,true);
|
||||
vs->mesh_surface_set_material( trimesh_mesh, 0, trimesh_mat );
|
||||
|
||||
RID triins = vs->instance_create2(trimesh_mesh,scenario);
|
||||
|
||||
|
||||
RID tribody = ps->body_create( PhysicsServer::BODY_MODE_STATIC);
|
||||
ps->body_set_space(tribody,space);
|
||||
//todo set space
|
||||
ps->body_add_shape(tribody, trimesh_shape);
|
||||
Transform tritrans = p_xform;
|
||||
ps->body_set_state( tribody, PhysicsServer::BODY_STATE_TRANSFORM, tritrans );
|
||||
vs->instance_set_transform( triins, tritrans );
|
||||
//RID trimesh_material = vs->fixed_material_create();
|
||||
//vs->material_generate( trimesh_material, Color(0.2,0.4,0.6) );
|
||||
//vs->mesh_surface_set_material( trimesh_mesh, 0, trimesh_material );
|
||||
|
||||
}
|
||||
|
||||
void make_grid(int p_width,int p_height,float p_cellsize,float p_cellheight,const Transform& p_xform=Transform()) {
|
||||
|
||||
Vector< Vector< float > > grid;
|
||||
|
||||
grid.resize(p_width);
|
||||
|
||||
for (int i=0;i<p_width;i++) {
|
||||
|
||||
grid[i].resize(p_height);
|
||||
|
||||
for (int j=0;j<p_height;j++) {
|
||||
|
||||
grid[i][j]=1.0+Math::random(-p_cellheight, p_cellheight );
|
||||
}
|
||||
}
|
||||
|
||||
Vector<Vector3> faces;
|
||||
|
||||
for (int i=1;i<p_width;i++) {
|
||||
|
||||
for (int j=1;j<p_height;j++) {
|
||||
|
||||
|
||||
#define MAKE_VERTEX(m_x,m_z)\
|
||||
faces.push_back( Vector3( (m_x-p_width/2)*p_cellsize, grid[m_x][m_z], (m_z-p_height/2)*p_cellsize ) )
|
||||
|
||||
MAKE_VERTEX(i,j-1);
|
||||
MAKE_VERTEX(i,j);
|
||||
MAKE_VERTEX(i-1,j);
|
||||
|
||||
MAKE_VERTEX(i-1,j-1);
|
||||
MAKE_VERTEX(i,j-1);
|
||||
MAKE_VERTEX(i-1,j);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
make_trimesh(faces,p_xform);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
virtual void input_event(const InputEvent& p_event) {
|
||||
|
||||
if (p_event.type==InputEvent::MOUSE_MOTION && p_event.mouse_motion.button_mask&4) {
|
||||
|
||||
ofs_y-=p_event.mouse_motion.relative_y/200.0;
|
||||
ofs_x+=p_event.mouse_motion.relative_x/200.0;
|
||||
|
||||
}
|
||||
|
||||
if (p_event.type==InputEvent::MOUSE_MOTION && p_event.mouse_motion.button_mask&1) {
|
||||
|
||||
float y=-p_event.mouse_motion.relative_y/20.0;
|
||||
float x=p_event.mouse_motion.relative_x/20.0;
|
||||
|
||||
if (mover.is_valid()) {
|
||||
|
||||
|
||||
PhysicsServer * ps = PhysicsServer::get_singleton();
|
||||
Transform t = ps->body_get_state(mover,PhysicsServer::BODY_STATE_TRANSFORM);
|
||||
t.origin+=Vector3(x,y,0);
|
||||
|
||||
ps->body_set_state(mover,PhysicsServer::BODY_STATE_TRANSFORM,t);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (p_event.type == InputEvent::JOYSTICK_MOTION) {
|
||||
|
||||
if (p_event.joy_motion.axis == 0) {
|
||||
|
||||
joy_direction.x = p_event.joy_motion.axis_value;
|
||||
};
|
||||
|
||||
if (p_event.joy_motion.axis == 1) {
|
||||
|
||||
joy_direction.y = p_event.joy_motion.axis_value;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
virtual void request_quit() {
|
||||
|
||||
quit=true;
|
||||
}
|
||||
virtual void init() {
|
||||
|
||||
ofs_x=ofs_y=0;
|
||||
init_shapes();
|
||||
|
||||
PhysicsServer *ps = PhysicsServer::get_singleton();
|
||||
space=ps->space_create();
|
||||
ps->space_set_active(space,true);
|
||||
|
||||
VisualServer *vs=VisualServer::get_singleton();
|
||||
|
||||
/* LIGHT */
|
||||
RID lightaux = vs->light_create( VisualServer::LIGHT_DIRECTIONAL );
|
||||
//vs->light_set_color( lightaux, VisualServer::LIGHT_COLOR_AMBIENT, Color(0.0,0.0,0.0) );
|
||||
scenario = vs->scenario_create();
|
||||
vs->light_set_shadow(lightaux,true);
|
||||
light = vs->instance_create2( lightaux,scenario );
|
||||
Transform t;
|
||||
t.rotate(Vector3(1.0,0,0),0.6);
|
||||
vs->instance_set_transform(light,t);
|
||||
|
||||
|
||||
|
||||
/* CAMERA */
|
||||
|
||||
camera = vs->camera_create();
|
||||
RID viewport = vs->viewport_create();
|
||||
vs->viewport_attach_camera( viewport, camera );
|
||||
vs->viewport_attach_to_screen(viewport);
|
||||
vs->viewport_set_scenario( viewport, scenario );
|
||||
|
||||
vs->camera_set_perspective(camera,60,0.1,40.0);
|
||||
vs->camera_set_transform(camera,Transform( Matrix3(), Vector3(0,9,12)));
|
||||
//vs->scenario_set_debug(scenario,VS::SCENARIO_DEBUG_WIREFRAME);
|
||||
|
||||
Transform gxf;
|
||||
gxf.basis.scale(Vector3(1.4,0.4,1.4));
|
||||
gxf.origin=Vector3(-2,1,-2);
|
||||
make_grid(5,5,2.5,1,gxf);
|
||||
// create_body(PhysicsServer::SHAPE_BOX,PhysicsServer::BODY_MODE_STATIC,gxf);
|
||||
//create_static_plane( Plane( Vector3(0,1,0), -2) );
|
||||
// test_joint();
|
||||
test_fall();
|
||||
//test_joint();
|
||||
|
||||
|
||||
/*
|
||||
Vector<Vector3> faces;
|
||||
faces.push_back( Vector3(10,0,-5) );
|
||||
faces.push_back( Vector3(0,0,10) );
|
||||
faces.push_back( Vector3(-10,-0.2,-5) );
|
||||
make_trimesh(faces);
|
||||
*/
|
||||
/* Make Trimesh */
|
||||
quit=false;
|
||||
return;
|
||||
|
||||
#if 0
|
||||
#define GRID_SIZE 5
|
||||
|
||||
float grid[GRID_SIZE][GRID_SIZE];
|
||||
|
||||
for (int i=0;i<GRID_SIZE;i++) {
|
||||
|
||||
for (int j=0;j<GRID_SIZE;j++) {
|
||||
|
||||
grid[j][i]=Math::random(0.0, 1.0 );
|
||||
}
|
||||
}
|
||||
|
||||
Vector<Vector3> faces;
|
||||
|
||||
for (int i=1;i<GRID_SIZE;i++) {
|
||||
|
||||
for (int j=1;j<GRID_SIZE;j++) {
|
||||
|
||||
|
||||
#define MAKE_VERTEX(m_x,m_z)\
|
||||
faces.push_back( Vector3( m_x-GRID_SIZE/2.0, grid[m_x][m_z], m_z-GRID_SIZE/2.0 )*3.0 )
|
||||
|
||||
MAKE_VERTEX(i,j-1);
|
||||
MAKE_VERTEX(i,j);
|
||||
MAKE_VERTEX(i-1,j);
|
||||
|
||||
MAKE_VERTEX(i-1,j-1);
|
||||
MAKE_VERTEX(i,j-1);
|
||||
MAKE_VERTEX(i-1,j);
|
||||
|
||||
}
|
||||
}
|
||||
/*
|
||||
faces.clear();
|
||||
faces.push_back( Vector3(0,0,-5) );
|
||||
faces.push_back( Vector3(1,0,-1) );
|
||||
faces.push_back( Vector3(-1,-0,-1) );
|
||||
*/
|
||||
|
||||
RID trimesh_shape = ps->shape_create();
|
||||
ps->shape_set_data(trimesh_shape, PhysicsServer::SHAPE_CONCAVE_POLYGON,faces);
|
||||
faces=ps->shape_get_shape(trimesh_shape, 0);
|
||||
Vector<Vector3> normals; // for drawing
|
||||
for (int i=0;i<faces.size()/3;i++) {
|
||||
|
||||
Plane p( faces[i*3+0],faces[i*3+1], faces[i*3+2] );
|
||||
normals.push_back(p.normal);
|
||||
normals.push_back(p.normal);
|
||||
normals.push_back(p.normal);
|
||||
}
|
||||
|
||||
RID trimesh_mesh = vs->mesh_create();
|
||||
vs->mesh_add_surface(trimesh_mesh, VS::PRIMITIVE_TRIANGLES, VS::ARRAY_FORMAT_VERTEX|VS::ARRAY_FORMAT_NORMAL, faces.size() );
|
||||
vs->mesh_surface_set_array(trimesh_mesh,0,VS::ARRAY_VERTEX, faces );
|
||||
vs->mesh_surface_set_array(trimesh_mesh,0,VS::ARRAY_NORMAL, normals );
|
||||
RID trimesh_mat = vs->fixed_material_create();
|
||||
vs->material_generate( trimesh_mat, Color(1.0,0.5,0.3) );
|
||||
vs->mesh_surface_set_material( trimesh_mesh, 0, trimesh_mat );
|
||||
|
||||
RID triins = vs->instance_create2(trimesh_mesh);
|
||||
|
||||
|
||||
|
||||
RID tribody = ps->body_create( PhysicsServer::BODY_MODE_STATIC, trimesh_shape);
|
||||
Transform tritrans = Transform( Matrix3(), Vector3(0,0,-2) );
|
||||
ps->body_set_state( tribody, PhysicsServer::BODY_STATE_TRANSFORM, tritrans );
|
||||
vs->instance_set_transform( triins, tritrans );
|
||||
RID trimesh_material = vs->fixed_material_create();
|
||||
vs->material_generate( trimesh_material, Color(0.2,0.4,0.6) );
|
||||
vs->mesh_surface_set_material( trimesh_mesh, 0, trimesh_material );
|
||||
#endif
|
||||
}
|
||||
virtual bool iteration(float p_time) {
|
||||
|
||||
if (mover) {
|
||||
static float joy_speed = 10;
|
||||
PhysicsServer * ps = PhysicsServer::get_singleton();
|
||||
Transform t = ps->body_get_state(mover,PhysicsServer::BODY_STATE_TRANSFORM);
|
||||
t.origin+=Vector3(joy_speed * joy_direction.x * p_time, -joy_speed * joy_direction.y * p_time,0);
|
||||
ps->body_set_state(mover,PhysicsServer::BODY_STATE_TRANSFORM,t);
|
||||
};
|
||||
|
||||
|
||||
Transform cameratr;
|
||||
cameratr.rotate(Vector3(0,1,0),ofs_x);
|
||||
cameratr.rotate(Vector3(1,0,0),-ofs_y);
|
||||
cameratr.translate(Vector3(0,2,8));
|
||||
VisualServer *vs=VisualServer::get_singleton();
|
||||
vs->camera_set_transform(camera,cameratr);
|
||||
|
||||
return quit;
|
||||
}
|
||||
virtual void finish() {
|
||||
|
||||
}
|
||||
|
||||
void test_joint() {
|
||||
#if 0
|
||||
PhysicsServer * ps = PhysicsServer::get_singleton();
|
||||
|
||||
mover = create_body(PhysicsServer::SHAPE_BOX,PhysicsServer::BODY_MODE_STATIC,Transform(Matrix3(),Vector3(0,0,-24)));
|
||||
RID b = create_body(PhysicsServer::SHAPE_CAPSULE,PhysicsServer::BODY_MODE_RIGID,Transform());
|
||||
|
||||
ps->joint_create_double_pin(b,Vector3(0,0,1.0),mover,Vector3(0,0,0));
|
||||
ps->body_add_collision_exception(mover,b);
|
||||
|
||||
|
||||
List<String> cmdline = OS::get_singleton()->get_cmdline_args();
|
||||
int link_count = LINK_COUNT;
|
||||
if (cmdline.size() > 0 && cmdline[cmdline.size()-1].to_int()) {
|
||||
link_count = cmdline[cmdline.size()-1].to_int();
|
||||
};
|
||||
|
||||
for(int i=0;i<link_count;i++) {
|
||||
|
||||
RID c = create_body(PhysicsServer::SHAPE_CAPSULE,PhysicsServer::BODY_MODE_RIGID,Transform());
|
||||
ps->joint_create_double_pin(b,Vector3(0,0,-0.7),c,Vector3(0,0,0.7));
|
||||
ps->body_add_collision_exception(c,b);
|
||||
b=c;
|
||||
}
|
||||
|
||||
|
||||
create_static_plane(Plane(Vector3(0,1,0),-8));
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_hinge() {
|
||||
#if 0
|
||||
PhysicsServer * ps = PhysicsServer::get_singleton();
|
||||
|
||||
|
||||
mover = create_body(PhysicsServer::SHAPE_BOX,PhysicsServer::BODY_MODE_STATIC,Transform(Matrix3(),Vector3(0,0,-24)));
|
||||
RID b = create_body(PhysicsServer::SHAPE_BOX,PhysicsServer::BODY_MODE_RIGID,Transform());
|
||||
|
||||
ps->joint_create_double_hinge(b,Transform(Matrix3(),Vector3(1,1,1.0)),mover,Transform(Matrix3(),Vector3(0,0,0)));
|
||||
ps->body_add_collision_exception(mover,b);
|
||||
|
||||
/*
|
||||
for(int i=0;i<20;i++) {
|
||||
|
||||
RID c = create_body(PhysicsServer::SHAPE_CAPSULE,PhysicsServer::BODY_MODE_RIGID,Transform());
|
||||
ps->joint_create_double_hinge(b,Transform(Matrix3(),Vector3(0,0,-0.7)),c,Transform(Matrix3(),Vector3(0,0,0.7)));
|
||||
ps->body_add_collision_exception(c,b);
|
||||
b=c;
|
||||
}
|
||||
|
||||
*/
|
||||
//create_static_plane(Plane(Vector3(0,1,0),-8));
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_character() {
|
||||
|
||||
VisualServer *vs=VisualServer::get_singleton();
|
||||
PhysicsServer * ps = PhysicsServer::get_singleton();
|
||||
|
||||
|
||||
DVector<Plane> capsule_planes = Geometry::build_capsule_planes(0.5,1,12,5,Vector3::AXIS_Y);
|
||||
RID capsule_material = vs->fixed_material_create();
|
||||
|
||||
vs->fixed_material_set_param( capsule_material, VisualServer::FIXED_MATERIAL_PARAM_DIFFUSE, Color(1,1,1) );
|
||||
|
||||
|
||||
RID capsule_mesh = vs->mesh_create();
|
||||
Geometry::MeshData capsule_data = Geometry::build_convex_mesh(capsule_planes);
|
||||
vs->mesh_add_surface_from_mesh_data(capsule_mesh,capsule_data);
|
||||
vs->mesh_surface_set_material( capsule_mesh, 0, capsule_material );
|
||||
type_mesh_map[PhysicsServer::SHAPE_CAPSULE]=capsule_mesh;
|
||||
|
||||
RID capsule_shape=ps->shape_create(PhysicsServer::SHAPE_CAPSULE);
|
||||
Dictionary capsule_params;
|
||||
capsule_params["radius"]=0.5;
|
||||
capsule_params["height"]=1;
|
||||
Transform shape_xform;
|
||||
shape_xform.rotate(Vector3(1,0,0),Math_PI/2.0);
|
||||
//shape_xform.origin=Vector3(1,1,1);
|
||||
ps->shape_set_data( capsule_shape, capsule_params);
|
||||
|
||||
|
||||
RID mesh_instance = vs->instance_create2(capsule_mesh,scenario);
|
||||
character = ps->body_create(PhysicsServer::BODY_MODE_CHARACTER);
|
||||
ps->body_set_space(character,space);
|
||||
//todo add space
|
||||
ps->body_add_shape(character,capsule_shape);
|
||||
|
||||
ps->body_set_force_integration_callback(character,this,"body_changed_transform",mesh_instance);
|
||||
|
||||
|
||||
ps->body_set_state( character, PhysicsServer::BODY_STATE_TRANSFORM,Transform(Matrix3(),Vector3(-2,5,-2)));
|
||||
bodies.push_back(character);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void test_fall() {
|
||||
|
||||
|
||||
for (int i=0;i<35;i++) {
|
||||
|
||||
static const PhysicsServer::ShapeType shape_idx[]={
|
||||
PhysicsServer::SHAPE_CAPSULE,
|
||||
PhysicsServer::SHAPE_BOX,
|
||||
PhysicsServer::SHAPE_SPHERE,
|
||||
PhysicsServer::SHAPE_CONVEX_POLYGON
|
||||
};
|
||||
|
||||
PhysicsServer::ShapeType type=shape_idx[i%4];
|
||||
//type=PhysicsServer::SHAPE_CONVEX_POLYGON;
|
||||
|
||||
Transform t;
|
||||
|
||||
t.origin=Vector3(0.0*i,3.5+1.1*i,0.7+0.0*i);
|
||||
//t.origin=Vector3(-0.7+0.0*i,0.5+4.1*i,0);
|
||||
t.basis.rotate(Vector3(0.2,-1,0),Math_PI/2*0.6);
|
||||
//t.basis.rotate(Vector3(0,-1,0),Math_PI/4*i);
|
||||
//t.basis.rotate(Vector3(0,-1,0),Math_PI/4*i);
|
||||
//t.basis.rotate(Vector3(-1,0,0),Math_PI/4*i);
|
||||
|
||||
|
||||
RID b = create_body(type,PhysicsServer::BODY_MODE_RIGID,t);
|
||||
//RID b = create_body(type,i==0?PhysicsServer::BODY_MODE_STATIC:PhysicsServer::BODY_MODE_RIGID,t);
|
||||
|
||||
}
|
||||
|
||||
create_static_plane( Plane( Vector3(0,1,0), -1) );
|
||||
|
||||
|
||||
/*
|
||||
create_static_plane( Plane( Vector3(1,0,0), -2) );
|
||||
create_static_plane( Plane( Vector3(-1,0,0), -2) );
|
||||
create_static_plane( Plane( Vector3(0,0,1), -2) );
|
||||
create_static_plane( Plane( Vector3(0,0,-1), -2) );
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
|
||||
void test_activate() {
|
||||
|
||||
create_body(PhysicsServer::SHAPE_BOX,PhysicsServer::BODY_MODE_RIGID,Transform(Matrix3(),Vector3(0,2,0)),true);
|
||||
//create_body(PhysicsServer::SHAPE_SPHERE,PhysicsServer::BODY_MODE_RIGID,Transform(Matrix3(),Vector3(0,6,0)),true);
|
||||
create_static_plane( Plane( Vector3(0,1,0), -1) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
virtual bool idle(float p_time) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
TestPhysicsMainLoop() {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
namespace TestPhysics {
|
||||
|
||||
MainLoop* test() {
|
||||
|
||||
return memnew( TestPhysicsMainLoop );
|
||||
|
||||
}
|
||||
|
||||
}
|
44
bin/tests/test_physics.h
Normal file
44
bin/tests/test_physics.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*************************************************************************/
|
||||
/* test_physics.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 TEST_PHYSICS_H
|
||||
#define TEST_PHYSICS_H
|
||||
|
||||
/**
|
||||
@author Juan Linietsky <reduzio@gmail.com>
|
||||
*/
|
||||
|
||||
#include "os/main_loop.h"
|
||||
|
||||
namespace TestPhysics {
|
||||
|
||||
MainLoop* test();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
466
bin/tests/test_physics_2d.cpp
Normal file
466
bin/tests/test_physics_2d.cpp
Normal file
File diff suppressed because one or more lines are too long
41
bin/tests/test_physics_2d.h
Normal file
41
bin/tests/test_physics_2d.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*************************************************************************/
|
||||
/* test_physics_2d.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 TEST_PHYSICS_2D_H
|
||||
#define TEST_PHYSICS_2D_H
|
||||
|
||||
|
||||
#include "os/main_loop.h"
|
||||
|
||||
namespace TestPhysics2D {
|
||||
|
||||
MainLoop* test();
|
||||
|
||||
}
|
||||
|
||||
#endif // TEST_PHYSICS_2D_H
|
56
bin/tests/test_python.cpp
Normal file
56
bin/tests/test_python.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
/*************************************************************************/
|
||||
/* test_python.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "test_python.h"
|
||||
|
||||
#ifdef PYTHON_ENABLED
|
||||
|
||||
#include "Python.h"
|
||||
#include "print_string.h"
|
||||
|
||||
namespace TestPython {
|
||||
|
||||
void test() {
|
||||
|
||||
print_line("testing python");
|
||||
PyRun_SimpleString("import engine\n");
|
||||
PyRun_SimpleString("def test(self):\n\tprint(\"noway\")\n");
|
||||
PyRun_SimpleString("a=engine.ObjectPtr()\n");
|
||||
PyRun_SimpleString("a.noway(22,'hello')\n");
|
||||
PyRun_SimpleString("a.normalize()\n");
|
||||
PyRun_SimpleString("class Moch(engine.ObjectPtr):\n\tdef mooch(self):\n\t\tprint('muchi')\n");
|
||||
PyRun_SimpleString("b=Moch();\n");
|
||||
PyRun_SimpleString("b.mooch();\n");
|
||||
PyRun_SimpleString("b.meis();\n");
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
43
bin/tests/test_python.h
Normal file
43
bin/tests/test_python.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*************************************************************************/
|
||||
/* test_python.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 TEST_PYTHON_H
|
||||
#define TEST_PYTHON_H
|
||||
|
||||
#ifdef PYTHON_ENABLED
|
||||
/**
|
||||
@author Juan Linietsky <reduzio@gmail.com>
|
||||
*/
|
||||
namespace TestPython {
|
||||
|
||||
void test();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
257
bin/tests/test_render.cpp
Normal file
257
bin/tests/test_render.cpp
Normal file
@ -0,0 +1,257 @@
|
||||
/*************************************************************************/
|
||||
/* test_render.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "test_render.h"
|
||||
#include "servers/visual_server.h"
|
||||
#include "os/main_loop.h"
|
||||
#include "math_funcs.h"
|
||||
#include "print_string.h"
|
||||
#include "os/os.h"
|
||||
#include "quick_hull.h"
|
||||
#define OBJECT_COUNT 50
|
||||
|
||||
namespace TestRender {
|
||||
|
||||
|
||||
class TestMainLoop : public MainLoop {
|
||||
|
||||
|
||||
RID test_cube;
|
||||
RID instance;
|
||||
RID camera;
|
||||
RID viewport;
|
||||
RID light;
|
||||
RID scenario;
|
||||
|
||||
struct InstanceInfo {
|
||||
|
||||
RID instance;
|
||||
Transform base;
|
||||
Vector3 rot_axis;
|
||||
};
|
||||
|
||||
List<InstanceInfo> instances;
|
||||
|
||||
float ofs;
|
||||
bool quit;
|
||||
public:
|
||||
virtual void input_event(const InputEvent& p_event) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
virtual void init() {
|
||||
|
||||
|
||||
print_line("INITIALIZING TEST RENDER");
|
||||
VisualServer *vs=VisualServer::get_singleton();
|
||||
test_cube = vs->get_test_cube();
|
||||
scenario = vs->scenario_create();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Vector<Vector3> vts;
|
||||
|
||||
/*
|
||||
DVector<Plane> sp = Geometry::build_sphere_planes(2,5,5);
|
||||
Geometry::MeshData md2 = Geometry::build_convex_mesh(sp);
|
||||
vts=md2.vertices;
|
||||
*/
|
||||
/*
|
||||
|
||||
static const int s = 20;
|
||||
for(int i=0;i<s;i++) {
|
||||
Matrix3 rot(Vector3(0,1,0),i*Math_PI/s);
|
||||
|
||||
for(int j=0;j<s;j++) {
|
||||
Vector3 v;
|
||||
v.x=Math::sin(j*Math_PI*2/s);
|
||||
v.y=Math::cos(j*Math_PI*2/s);
|
||||
|
||||
vts.push_back( rot.xform(v*2 ) );
|
||||
}
|
||||
}*/
|
||||
/*for(int i=0;i<100;i++) {
|
||||
|
||||
vts.push_back( Vector3(Math::randf()*2-1.0,Math::randf()*2-1.0,Math::randf()*2-1.0).normalized()*2);
|
||||
}*/
|
||||
/*
|
||||
vts.push_back(Vector3(0,0,1));
|
||||
vts.push_back(Vector3(0,0,-1));
|
||||
vts.push_back(Vector3(0,1,0));
|
||||
vts.push_back(Vector3(0,-1,0));
|
||||
vts.push_back(Vector3(1,0,0));
|
||||
vts.push_back(Vector3(-1,0,0));*/
|
||||
|
||||
vts.push_back(Vector3(1,1,1));
|
||||
vts.push_back(Vector3(1,-1,1));
|
||||
vts.push_back(Vector3(-1,1,1));
|
||||
vts.push_back(Vector3(-1,-1,1));
|
||||
vts.push_back(Vector3(1,1,-1));
|
||||
vts.push_back(Vector3(1,-1,-1));
|
||||
vts.push_back(Vector3(-1,1,-1));
|
||||
vts.push_back(Vector3(-1,-1,-1));
|
||||
|
||||
Geometry::MeshData md;
|
||||
Error err = QuickHull::build(vts,md);
|
||||
print_line("ERR: "+itos(err));
|
||||
test_cube = vs->mesh_create();
|
||||
vs->mesh_add_surface_from_mesh_data(test_cube,md);
|
||||
//vs->scenario_set_debug(scenario,VS::SCENARIO_DEBUG_WIREFRAME);
|
||||
|
||||
/*
|
||||
RID sm = vs->shader_create();
|
||||
//vs->shader_set_fragment_code(sm,"OUT_ALPHA=mod(TIME,1);");
|
||||
//vs->shader_set_vertex_code(sm,"OUT_VERTEX=IN_VERTEX*mod(TIME,1);");
|
||||
vs->shader_set_fragment_code(sm,"OUT_DIFFUSE=vec3(1,0,1);OUT_GLOW=abs(sin(TIME));");
|
||||
RID tcmat = vs->mesh_surface_get_material(test_cube,0);
|
||||
vs->material_set_shader(tcmat,sm);
|
||||
*/
|
||||
|
||||
|
||||
List<String> cmdline = OS::get_singleton()->get_cmdline_args();
|
||||
int object_count = OBJECT_COUNT;
|
||||
if (cmdline.size() > 0 && cmdline[cmdline.size()-1].to_int()) {
|
||||
object_count = cmdline[cmdline.size()-1].to_int();
|
||||
};
|
||||
|
||||
for (int i=0;i<object_count;i++) {
|
||||
|
||||
InstanceInfo ii;
|
||||
|
||||
|
||||
ii.instance = vs->instance_create2( test_cube, scenario );
|
||||
|
||||
|
||||
ii.base.translate( Math::random(-20,20), Math::random(-20,20),Math::random(-20,18) );
|
||||
ii.base.rotate( Vector3(0,1,0), Math::randf() * Math_PI );
|
||||
ii.base.rotate( Vector3(1,0,0), Math::randf() * Math_PI );
|
||||
vs->instance_set_transform( ii.instance, ii.base );
|
||||
|
||||
ii.rot_axis = Vector3( Math::random(-1,1), Math::random(-1,1), Math::random(-1,1) ).normalized();
|
||||
|
||||
instances.push_back(ii);
|
||||
|
||||
}
|
||||
|
||||
camera = vs->camera_create();
|
||||
|
||||
// vs->camera_set_perspective( camera, 60.0,0.1, 100.0 );
|
||||
|
||||
viewport = vs->viewport_create();
|
||||
vs->viewport_attach_to_screen(viewport);
|
||||
vs->viewport_attach_camera( viewport, camera );
|
||||
vs->viewport_set_scenario( viewport, scenario );
|
||||
vs->camera_set_transform(camera, Transform( Matrix3(), Vector3(0,3,30 ) ) );
|
||||
vs->camera_set_perspective( camera, 60, 0.1, 1000);
|
||||
|
||||
|
||||
/*
|
||||
RID lightaux = vs->light_create( VisualServer::LIGHT_OMNI );
|
||||
vs->light_set_var( lightaux, VisualServer::LIGHT_VAR_RADIUS, 80 );
|
||||
vs->light_set_var( lightaux, VisualServer::LIGHT_VAR_ATTENUATION, 1 );
|
||||
vs->light_set_var( lightaux, VisualServer::LIGHT_VAR_ENERGY, 1.5 );
|
||||
light = vs->instance_create( lightaux );
|
||||
*/
|
||||
RID lightaux;
|
||||
|
||||
//*
|
||||
lightaux = vs->light_create( VisualServer::LIGHT_DIRECTIONAL );
|
||||
vs->light_set_color( lightaux, VisualServer::LIGHT_COLOR_AMBIENT, Color(0.0,0.0,0.0) );
|
||||
vs->light_set_color( lightaux, VisualServer::LIGHT_COLOR_DIFFUSE, Color(1.0,1.0,1.0) );
|
||||
//vs->light_set_shadow( lightaux, true );
|
||||
light = vs->instance_create2( lightaux, scenario );
|
||||
Transform lla;
|
||||
//lla.set_look_at(Vector3(),Vector3(1,-1,1),Vector3(0,1,0));
|
||||
lla.set_look_at(Vector3(),Vector3(-0.000000,-0.836026,-0.548690),Vector3(0,1,0));
|
||||
|
||||
vs->instance_set_transform( light, lla );
|
||||
// */
|
||||
|
||||
//*
|
||||
lightaux = vs->light_create( VisualServer::LIGHT_OMNI );
|
||||
vs->light_set_color( lightaux, VisualServer::LIGHT_COLOR_AMBIENT, Color(0.0,0.0,1.0) );
|
||||
vs->light_set_color( lightaux, VisualServer::LIGHT_COLOR_DIFFUSE, Color(1.0,1.0,0.0) );
|
||||
vs->light_set_param( lightaux, VisualServer::LIGHT_PARAM_RADIUS, 4 );
|
||||
vs->light_set_param( lightaux, VisualServer::LIGHT_PARAM_ENERGY, 8 );
|
||||
//vs->light_set_shadow( lightaux, true );
|
||||
//light = vs->instance_create( lightaux );
|
||||
// */
|
||||
|
||||
ofs=0;
|
||||
quit=false;
|
||||
}
|
||||
virtual bool iteration(float p_time) {
|
||||
|
||||
VisualServer *vs=VisualServer::get_singleton();
|
||||
//Transform t;
|
||||
//t.rotate(Vector3(0, 1, 0), ofs);
|
||||
//t.translate(Vector3(0,0,20 ));
|
||||
//vs->camera_set_transform(camera, t);
|
||||
|
||||
ofs+=p_time*0.05;
|
||||
|
||||
//return quit;
|
||||
|
||||
for(List<InstanceInfo>::Element *E=instances.front();E;E=E->next()) {
|
||||
|
||||
Transform pre( Matrix3(E->get().rot_axis, ofs), Vector3() );
|
||||
vs->instance_set_transform( E->get().instance, pre * E->get().base );
|
||||
/*
|
||||
if( !E->next() ) {
|
||||
|
||||
vs->free( E->get().instance );
|
||||
instances.erase(E );
|
||||
}*/
|
||||
}
|
||||
|
||||
return quit;
|
||||
}
|
||||
|
||||
virtual bool idle(float p_time) {
|
||||
return quit;
|
||||
}
|
||||
|
||||
|
||||
virtual void finish() {
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
MainLoop* test() {
|
||||
|
||||
return memnew( TestMainLoop );
|
||||
|
||||
}
|
||||
|
||||
}
|
44
bin/tests/test_render.h
Normal file
44
bin/tests/test_render.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*************************************************************************/
|
||||
/* test_render.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 TEST_RENDER_H
|
||||
#define TEST_RENDER_H
|
||||
|
||||
/**
|
||||
@author Juan Linietsky <reduzio@gmail.com>
|
||||
*/
|
||||
|
||||
#include "os/main_loop.h"
|
||||
|
||||
namespace TestRender {
|
||||
|
||||
MainLoop* test();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
339
bin/tests/test_shader_lang.cpp
Normal file
339
bin/tests/test_shader_lang.cpp
Normal file
@ -0,0 +1,339 @@
|
||||
/*************************************************************************/
|
||||
/* test_shader_lang.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "test_shader_lang.h"
|
||||
|
||||
|
||||
#include "os/main_loop.h"
|
||||
#include "os/os.h"
|
||||
#include "os/file_access.h"
|
||||
|
||||
#include "scene/gui/control.h"
|
||||
#include "scene/gui/text_edit.h"
|
||||
#include "print_string.h"
|
||||
#include "servers/visual/shader_language.h"
|
||||
#include "drivers/gles2/shader_compiler_gles2.h"
|
||||
|
||||
|
||||
typedef ShaderLanguage SL;
|
||||
|
||||
namespace TestShaderLang {
|
||||
|
||||
|
||||
static String _mktab(int p_level) {
|
||||
|
||||
String tb;
|
||||
for(int i=0;i<p_level;i++) {
|
||||
tb+="\t";
|
||||
}
|
||||
|
||||
return tb;
|
||||
}
|
||||
|
||||
static String _typestr(SL::DataType p_type) {
|
||||
|
||||
switch(p_type) {
|
||||
|
||||
case SL::TYPE_VOID: return "void";
|
||||
case SL::TYPE_BOOL: return "bool";
|
||||
case SL::TYPE_FLOAT: return "float";
|
||||
case SL::TYPE_VEC2: return "vec2";
|
||||
case SL::TYPE_VEC3: return "vec3";
|
||||
case SL::TYPE_VEC4: return "vec4";
|
||||
case SL::TYPE_MAT3: return "mat3";
|
||||
case SL::TYPE_MAT4: return "mat4";
|
||||
case SL::TYPE_TEXTURE: return "texture";
|
||||
case SL::TYPE_CUBEMAP: return "cubemap";
|
||||
default: {}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
static String _opstr(SL::Operator p_op) {
|
||||
|
||||
switch(p_op) {
|
||||
case SL::OP_ASSIGN: return "=";
|
||||
case SL::OP_ADD: return "+";
|
||||
case SL::OP_SUB: return "-";
|
||||
case SL::OP_MUL: return "*";
|
||||
case SL::OP_DIV: return "/";
|
||||
case SL::OP_ASSIGN_ADD: return "+=";
|
||||
case SL::OP_ASSIGN_SUB: return "-=";
|
||||
case SL::OP_ASSIGN_MUL: return "*=";
|
||||
case SL::OP_ASSIGN_DIV: return "/=";
|
||||
case SL::OP_NEG: return "-";
|
||||
case SL::OP_NOT: return "!";
|
||||
case SL::OP_CMP_EQ: return "==";
|
||||
case SL::OP_CMP_NEQ: return "!=";
|
||||
case SL::OP_CMP_LEQ: return "<=";
|
||||
case SL::OP_CMP_GEQ: return ">=";
|
||||
case SL::OP_CMP_LESS: return "<";
|
||||
case SL::OP_CMP_GREATER: return ">";
|
||||
case SL::OP_CMP_OR: return "||";
|
||||
case SL::OP_CMP_AND: return "&&";
|
||||
default: return "";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
static String dump_node_code(SL::Node *p_node,int p_level) {
|
||||
|
||||
String code;
|
||||
|
||||
switch(p_node->type) {
|
||||
|
||||
case SL::Node::TYPE_PROGRAM: {
|
||||
|
||||
SL::ProgramNode *pnode=(SL::ProgramNode*)p_node;
|
||||
|
||||
for(Map<StringName,SL::Uniform>::Element *E=pnode->uniforms.front();E;E=E->next()) {
|
||||
|
||||
String ucode="uniform ";
|
||||
ucode+=_typestr(E->get().type)+"="+String(E->get().default_value)+"\n";
|
||||
code+=ucode;
|
||||
|
||||
}
|
||||
|
||||
for(int i=0;i<pnode->functions.size();i++) {
|
||||
|
||||
SL::FunctionNode *fnode=pnode->functions[i].function;
|
||||
|
||||
String header;
|
||||
header=_typestr(fnode->return_type)+" "+fnode->name+"(";
|
||||
for(int i=0;i<fnode->arguments.size();i++) {
|
||||
|
||||
if (i>0)
|
||||
header+=", ";
|
||||
header+=_typestr(fnode->arguments[i].type)+" "+fnode->arguments[i].name;
|
||||
}
|
||||
|
||||
header+=") {\n";
|
||||
code+=header;
|
||||
code+=dump_node_code(fnode->body,p_level+1);
|
||||
code+="}\n";
|
||||
}
|
||||
|
||||
code+=dump_node_code(pnode->body,p_level);
|
||||
} break;
|
||||
case SL::Node::TYPE_FUNCTION: {
|
||||
|
||||
} break;
|
||||
case SL::Node::TYPE_BLOCK: {
|
||||
SL::BlockNode *bnode=(SL::BlockNode*)p_node;
|
||||
|
||||
//variables
|
||||
for(Map<StringName,SL::DataType>::Element *E=bnode->variables.front();E;E=E->next()) {
|
||||
|
||||
code+=_mktab(p_level)+_typestr(E->value())+" "+E->key()+";\n";
|
||||
}
|
||||
|
||||
for(int i=0;i<bnode->statements.size();i++) {
|
||||
|
||||
code+=_mktab(p_level)+dump_node_code(bnode->statements[i],p_level)+";\n";
|
||||
}
|
||||
|
||||
|
||||
} break;
|
||||
case SL::Node::TYPE_VARIABLE: {
|
||||
SL::VariableNode *vnode=(SL::VariableNode*)p_node;
|
||||
code=vnode->name;
|
||||
|
||||
} break;
|
||||
case SL::Node::TYPE_CONSTANT: {
|
||||
SL::ConstantNode *cnode=(SL::ConstantNode*)p_node;
|
||||
switch(cnode->datatype) {
|
||||
|
||||
|
||||
case SL::TYPE_BOOL: code=cnode->value.operator bool()?"true":"false"; break;
|
||||
case SL::TYPE_FLOAT: code=cnode->value; break;
|
||||
case SL::TYPE_VEC2: { Vector2 v = cnode->value; code="vec2("+rtos(v.x)+", "+rtos(v.y)+")"; } break;
|
||||
case SL::TYPE_VEC3: { Vector3 v = cnode->value; code="vec3("+rtos(v.x)+", "+rtos(v.y)+", "+rtos(v.z)+")"; } break;
|
||||
case SL::TYPE_VEC4: { Plane v = cnode->value; code="vec4("+rtos(v.normal.x)+", "+rtos(v.normal.y)+", "+rtos(v.normal.z)+", "+rtos(v.d)+")"; } break;
|
||||
case SL::TYPE_MAT3: { Matrix3 x = cnode->value; code="mat3( vec3("+rtos(x.get_axis(0).x)+", "+rtos(x.get_axis(0).y)+", "+rtos(x.get_axis(0).z)+"), vec3("+rtos(x.get_axis(1).x)+", "+rtos(x.get_axis(1).y)+", "+rtos(x.get_axis(1).z)+"), vec3("+rtos(x.get_axis(2).x)+", "+rtos(x.get_axis(2).y)+", "+rtos(x.get_axis(2).z)+"))"; } break;
|
||||
case SL::TYPE_MAT4: { Transform x = cnode->value; code="mat4( vec3("+rtos(x.basis.get_axis(0).x)+", "+rtos(x.basis.get_axis(0).y)+", "+rtos(x.basis.get_axis(0).z)+"), vec3("+rtos(x.basis.get_axis(1).x)+", "+rtos(x.basis.get_axis(1).y)+", "+rtos(x.basis.get_axis(1).z)+"), vec3("+rtos(x.basis.get_axis(2).x)+", "+rtos(x.basis.get_axis(2).y)+", "+rtos(x.basis.get_axis(2).z)+"), vec3("+rtos(x.origin.x)+", "+rtos(x.origin.y)+", "+rtos(x.origin.z)+"))"; } break;
|
||||
default: code="<error: "+Variant::get_type_name(cnode->value.get_type())+" ("+itos(cnode->datatype)+">";
|
||||
}
|
||||
|
||||
} break;
|
||||
case SL::Node::TYPE_OPERATOR: {
|
||||
SL::OperatorNode *onode=(SL::OperatorNode*)p_node;
|
||||
|
||||
|
||||
switch(onode->op) {
|
||||
|
||||
case SL::OP_ASSIGN:
|
||||
case SL::OP_ASSIGN_ADD:
|
||||
case SL::OP_ASSIGN_SUB:
|
||||
case SL::OP_ASSIGN_MUL:
|
||||
case SL::OP_ASSIGN_DIV:
|
||||
code=dump_node_code(onode->arguments[0],p_level)+_opstr(onode->op)+dump_node_code(onode->arguments[1],p_level);
|
||||
break;
|
||||
|
||||
case SL::OP_ADD:
|
||||
case SL::OP_SUB:
|
||||
case SL::OP_MUL:
|
||||
case SL::OP_DIV:
|
||||
case SL::OP_CMP_EQ:
|
||||
case SL::OP_CMP_NEQ:
|
||||
case SL::OP_CMP_LEQ:
|
||||
case SL::OP_CMP_GEQ:
|
||||
case SL::OP_CMP_LESS:
|
||||
case SL::OP_CMP_GREATER:
|
||||
case SL::OP_CMP_OR:
|
||||
case SL::OP_CMP_AND:
|
||||
|
||||
code="("+dump_node_code(onode->arguments[0],p_level)+_opstr(onode->op)+dump_node_code(onode->arguments[1],p_level)+")";
|
||||
break;
|
||||
case SL::OP_NEG:
|
||||
case SL::OP_NOT:
|
||||
code=_opstr(onode->op)+dump_node_code(onode->arguments[0],p_level);
|
||||
break;
|
||||
case SL::OP_CALL:
|
||||
case SL::OP_CONSTRUCT:
|
||||
code=dump_node_code(onode->arguments[0],p_level)+"(";
|
||||
for(int i=1;i<onode->arguments.size();i++) {
|
||||
if (i>1)
|
||||
code+=", ";
|
||||
code+=dump_node_code(onode->arguments[i],p_level);
|
||||
}
|
||||
code+=")";
|
||||
break;
|
||||
default: {}
|
||||
}
|
||||
|
||||
} break;
|
||||
case SL::Node::TYPE_CONTROL_FLOW: {
|
||||
SL::ControlFlowNode *cfnode=(SL::ControlFlowNode*)p_node;
|
||||
if (cfnode->flow_op==SL::FLOW_OP_IF) {
|
||||
|
||||
code+="if ("+dump_node_code(cfnode->statements[0],p_level)+") {\n";
|
||||
code+=dump_node_code(cfnode->statements[1],p_level+1);
|
||||
if (cfnode->statements.size()==3) {
|
||||
|
||||
code+="} else {\n";
|
||||
code+=dump_node_code(cfnode->statements[2],p_level+1);
|
||||
}
|
||||
|
||||
code+="}\n";
|
||||
|
||||
} else if (cfnode->flow_op==SL::FLOW_OP_RETURN) {
|
||||
|
||||
if (cfnode->statements.size()) {
|
||||
code="return "+dump_node_code(cfnode->statements[0],p_level);
|
||||
} else {
|
||||
code="return";
|
||||
}
|
||||
}
|
||||
|
||||
} break;
|
||||
case SL::Node::TYPE_MEMBER: {
|
||||
SL::MemberNode *mnode=(SL::MemberNode*)p_node;
|
||||
code=dump_node_code(mnode->owner,p_level)+"."+mnode->name;
|
||||
|
||||
} break;
|
||||
}
|
||||
|
||||
return code;
|
||||
|
||||
}
|
||||
|
||||
static void recreate_code(void *p_str,SL::ProgramNode *p_program) {
|
||||
|
||||
print_line("recr");
|
||||
String *str=(String*)p_str;
|
||||
|
||||
*str=dump_node_code(p_program,0);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
MainLoop* test() {
|
||||
|
||||
List<String> cmdlargs = OS::get_singleton()->get_cmdline_args();
|
||||
|
||||
if (cmdlargs.empty()) {
|
||||
//try editor!
|
||||
return NULL;
|
||||
}
|
||||
|
||||
String test = cmdlargs.back()->get();
|
||||
|
||||
FileAccess *fa = FileAccess::open(test,FileAccess::READ);
|
||||
|
||||
if (!fa) {
|
||||
memdelete(fa);
|
||||
ERR_FAIL_V(NULL);
|
||||
}
|
||||
|
||||
String code;
|
||||
|
||||
while(true) {
|
||||
CharType c = fa->get_8();
|
||||
if (fa->eof_reached())
|
||||
break;
|
||||
code+=c;
|
||||
}
|
||||
|
||||
int errline;
|
||||
int errcol;
|
||||
String error;
|
||||
print_line(SL::lex_debug(code));
|
||||
Error err = SL::compile(code,ShaderLanguage::SHADER_MATERIAL_FRAGMENT,NULL,NULL,&error,&errline,&errcol);
|
||||
|
||||
if (err) {
|
||||
|
||||
print_line("Error: "+itos(errline)+":"+itos(errcol)+" "+error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
print_line("Compile OK! - pretty printing");
|
||||
|
||||
String rcode;
|
||||
err = SL::compile(code,ShaderLanguage::SHADER_MATERIAL_FRAGMENT,recreate_code,&rcode,&error,&errline,&errcol);
|
||||
|
||||
if (!err) {
|
||||
print_line(rcode);
|
||||
}
|
||||
|
||||
ShaderCompilerGLES2 comp;
|
||||
String codeline,globalsline;
|
||||
SL::VarInfo vi;
|
||||
vi.name="mongs";
|
||||
vi.type=SL::TYPE_VEC3;
|
||||
|
||||
|
||||
ShaderCompilerGLES2::Flags fl;
|
||||
comp.compile(code,ShaderLanguage::SHADER_MATERIAL_FRAGMENT,codeline,globalsline,fl);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
40
bin/tests/test_shader_lang.h
Normal file
40
bin/tests/test_shader_lang.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*************************************************************************/
|
||||
/* test_shader_lang.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 TEST_SHADER_LANG_H
|
||||
#define TEST_SHADER_LANG_H
|
||||
|
||||
#include "os/main_loop.h"
|
||||
|
||||
namespace TestShaderLang {
|
||||
|
||||
MainLoop* test();
|
||||
|
||||
}
|
||||
|
||||
#endif // TEST_SHADER_LANG_H
|
95
bin/tests/test_sound.cpp
Normal file
95
bin/tests/test_sound.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
/*************************************************************************/
|
||||
/* test_sound.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "test_sound.h"
|
||||
#include "servers/visual_server.h"
|
||||
#include "os/main_loop.h"
|
||||
#include "math_funcs.h"
|
||||
#include "scene/resources/sample.h"
|
||||
#include "io/resource_loader.h"
|
||||
#include "print_string.h"
|
||||
#include "servers/audio_server.h"
|
||||
#include "os/os.h"
|
||||
namespace TestSound {
|
||||
|
||||
|
||||
class TestMainLoop : public MainLoop {
|
||||
|
||||
bool quit;
|
||||
Ref<Sample> sample;
|
||||
|
||||
public:
|
||||
virtual void input_event(const InputEvent& p_event) {
|
||||
|
||||
|
||||
}
|
||||
virtual void request_quit() {
|
||||
|
||||
quit=true;
|
||||
}
|
||||
|
||||
virtual void init() {
|
||||
|
||||
List<String> cmdline = OS::get_singleton()->get_cmdline_args();
|
||||
quit=false;
|
||||
if (cmdline.size()) {
|
||||
|
||||
sample=ResourceLoader::load(cmdline.back()->get());
|
||||
ERR_FAIL_COND(sample.is_null());
|
||||
print_line("Sample loaded OK");
|
||||
}
|
||||
|
||||
RID voice = AudioServer::get_singleton()->voice_create();
|
||||
AudioServer::get_singleton()->voice_play( voice, sample->get_rid() );
|
||||
|
||||
|
||||
}
|
||||
|
||||
virtual bool idle(float p_time) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
virtual bool iteration(float p_time) {
|
||||
|
||||
return quit;
|
||||
}
|
||||
virtual void finish() {
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
MainLoop* test() {
|
||||
|
||||
return memnew( TestMainLoop );
|
||||
|
||||
}
|
||||
|
||||
}
|
40
bin/tests/test_sound.h
Normal file
40
bin/tests/test_sound.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*************************************************************************/
|
||||
/* test_sound.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 TEST_SOUND_H
|
||||
#define TEST_SOUND_H
|
||||
|
||||
#include "os/main_loop.h"
|
||||
|
||||
namespace TestSound {
|
||||
|
||||
MainLoop* test();
|
||||
|
||||
}
|
||||
|
||||
#endif // TEST_SOUND_H
|
546
bin/tests/test_string.cpp
Normal file
546
bin/tests/test_string.cpp
Normal file
@ -0,0 +1,546 @@
|
||||
/*************************************************************************/
|
||||
/* test_string.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "ustring.h"
|
||||
#include <wchar.h>
|
||||
//#include "math_funcs.h"
|
||||
#include <stdio.h>
|
||||
#include "os/os.h"
|
||||
#include "drivers/trex/regex.h"
|
||||
|
||||
#include "test_string.h"
|
||||
|
||||
namespace TestString {
|
||||
|
||||
bool test_1() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 1: Assign from cstr\n");
|
||||
|
||||
String s = "Hello";
|
||||
|
||||
OS::get_singleton()->print("\tExpected: Hello\n");
|
||||
OS::get_singleton()->print("\tResulted: %ls\n",s.c_str());
|
||||
|
||||
return (wcscmp(s.c_str(),L"Hello")==0);
|
||||
|
||||
}
|
||||
|
||||
bool test_2() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 2: Assign from string (operator=)\n");
|
||||
|
||||
String s = "Dolly";
|
||||
String t = s;
|
||||
|
||||
OS::get_singleton()->print("\tExpected: Dolly\n");
|
||||
OS::get_singleton()->print("\tResulted: %ls\n",t.c_str());
|
||||
|
||||
return (wcscmp(t.c_str(),L"Dolly")==0);
|
||||
|
||||
}
|
||||
|
||||
bool test_3() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 3: Assign from c-string (copycon)\n");
|
||||
|
||||
String s("Sheep");
|
||||
String t(s);
|
||||
|
||||
OS::get_singleton()->print("\tExpected: Sheep\n");
|
||||
OS::get_singleton()->print("\tResulted: %ls\n",t.c_str());
|
||||
|
||||
return (wcscmp(t.c_str(),L"Sheep")==0);
|
||||
|
||||
}
|
||||
|
||||
bool test_4() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 4: Assign from c-widechar (operator=)\n");
|
||||
|
||||
String s(L"Give me");
|
||||
|
||||
OS::get_singleton()->print("\tExpected: Give me\n");
|
||||
OS::get_singleton()->print("\tResulted: %ls\n",s.c_str());
|
||||
|
||||
return (wcscmp(s.c_str(),L"Give me")==0);
|
||||
|
||||
}
|
||||
|
||||
bool test_5() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 5: Assign from c-widechar (copycon)\n");
|
||||
|
||||
String s(L"Wool");
|
||||
|
||||
OS::get_singleton()->print("\tExpected: Wool\n");
|
||||
OS::get_singleton()->print("\tResulted: %ls\n",s.c_str());
|
||||
|
||||
return (wcscmp(s.c_str(),L"Wool")==0);
|
||||
|
||||
}
|
||||
|
||||
bool test_6() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 6: comparisons (equal)\n");
|
||||
|
||||
|
||||
String s="Test Compare";
|
||||
|
||||
OS::get_singleton()->print("\tComparing to \"Test Compare\"\n");
|
||||
|
||||
if (! ( s=="Test Compare" ) )
|
||||
return false;
|
||||
|
||||
if (! ( s==L"Test Compare" ) )
|
||||
return false;
|
||||
|
||||
if (! ( s==String("Test Compare") ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool test_7() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 7: comparisons (unequal)\n");
|
||||
|
||||
|
||||
String s="Test Compare";
|
||||
|
||||
OS::get_singleton()->print("\tComparing to \"Test Compare\"\n");
|
||||
|
||||
if (! ( s!="Peanut" ) )
|
||||
return false;
|
||||
|
||||
if (! ( s!=L"Coconut" ) )
|
||||
return false;
|
||||
|
||||
if (! ( s!=String("Butter") ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool test_8() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 8: comparisons (operator<)\n");
|
||||
|
||||
|
||||
String s="Bees";
|
||||
|
||||
OS::get_singleton()->print("\tComparing to \"Bees\"\n");
|
||||
|
||||
if ( ! (s < "Elephant") )
|
||||
return false;
|
||||
|
||||
if ( s < L"Amber" )
|
||||
return false;
|
||||
|
||||
if ( s < String("Beatrix") )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool test_9() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 9: Concatenation\n");
|
||||
|
||||
|
||||
String s;
|
||||
|
||||
s+="Have";
|
||||
s+=' ';
|
||||
s+='a';
|
||||
s+=String(" ");
|
||||
s = s + L"Nice";
|
||||
s = s + " ";
|
||||
s = s + String("Day");
|
||||
|
||||
OS::get_singleton()->print("\tComparing to \"Have a Nice Day\"\n");
|
||||
|
||||
return (s == "Have a Nice Day");
|
||||
|
||||
}
|
||||
|
||||
bool test_10() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 10: Misc funcs (size/length/empty/etc)\n");
|
||||
|
||||
if (! String("").empty())
|
||||
return false;
|
||||
|
||||
if (String("Mellon").size() != 7)
|
||||
return false;
|
||||
|
||||
if (String("Oranges").length() != 7)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool test_11() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 11: Operator[]\n");
|
||||
|
||||
String a="Kugar Sane";
|
||||
|
||||
a[0]='S';
|
||||
a[6]='C';
|
||||
|
||||
if (a != "Sugar Cane")
|
||||
return false;
|
||||
|
||||
if (a[1]!='u')
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool test_12() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 12: case functions\n");
|
||||
|
||||
|
||||
String a="MoMoNgA";
|
||||
|
||||
if (a.to_upper() != "MOMONGA")
|
||||
return false;
|
||||
|
||||
if (a.nocasecmp_to("momonga")!=0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool test_13() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 13: UTF8\n");
|
||||
|
||||
/* how can i embed UTF in here? */
|
||||
|
||||
static const CharType ustr[] = { 0x304A , 0x360F, 0x3088, 0x3046, 0 };
|
||||
// static const wchar_t ustr[] = { 'P', 0xCE, 'p',0xD3, 0 };
|
||||
String s=ustr;
|
||||
|
||||
OS::get_singleton()->print("\tUnicode: %ls\n",ustr);
|
||||
s.parse_utf8( s.utf8().get_data() );
|
||||
OS::get_singleton()->print("\tConvert/Parse UTF8: %ls\n",s.c_str());
|
||||
|
||||
return (s==ustr);
|
||||
|
||||
}
|
||||
|
||||
bool test_14() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 14: ASCII\n");
|
||||
|
||||
String s = L"Primero Leche";
|
||||
OS::get_singleton()->print("\tAscii: %s\n",s.ascii().get_data());
|
||||
|
||||
String t=s.ascii().get_data();
|
||||
return (s==t);
|
||||
|
||||
}
|
||||
|
||||
bool test_15() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 15: substr\n");
|
||||
|
||||
String s="Killer Baby";
|
||||
OS::get_singleton()->print("\tsubstr(3,4) of \"%ls\" is \"%ls\"\n",s.c_str(),s.substr(3,4).c_str());
|
||||
|
||||
return (s.substr(3,4)=="ler ");
|
||||
|
||||
}
|
||||
|
||||
bool test_16() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 16: find\n");
|
||||
|
||||
String s="Pretty Woman";
|
||||
OS::get_singleton()->print("\tString: %ls\n",s.c_str());
|
||||
OS::get_singleton()->print("\t\"tty\" is at %i pos.\n",s.find("tty"));
|
||||
OS::get_singleton()->print("\t\"Revenge of the Monster Truck\" is at %i pos.\n",s.find("Revenge of the Monster Truck"));
|
||||
|
||||
if (s.find("tty")!=3)
|
||||
return false;
|
||||
|
||||
if (s.find("Revenge of the Monster Truck")!=-1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool test_17() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 17: find no case\n");
|
||||
|
||||
String s="Pretty Whale";
|
||||
OS::get_singleton()->print("\tString: %ls\n",s.c_str());
|
||||
OS::get_singleton()->print("\t\"WHA\" is at %i pos.\n",s.findn("WHA"));
|
||||
OS::get_singleton()->print("\t\"Revenge of the Monster SawFish\" is at %i pos.\n",s.findn("Revenge of the Monster Truck"));
|
||||
|
||||
if (s.findn("WHA")!=7)
|
||||
return false;
|
||||
|
||||
if (s.findn("Revenge of the Monster SawFish")!=-1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool test_18() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 18: find no case\n");
|
||||
|
||||
String s="Pretty Whale";
|
||||
OS::get_singleton()->print("\tString: %ls\n",s.c_str());
|
||||
OS::get_singleton()->print("\t\"WHA\" is at %i pos.\n",s.findn("WHA"));
|
||||
OS::get_singleton()->print("\t\"Revenge of the Monster SawFish\" is at %i pos.\n",s.findn("Revenge of the Monster Truck"));
|
||||
|
||||
if (s.findn("WHA")!=7)
|
||||
return false;
|
||||
|
||||
if (s.findn("Revenge of the Monster SawFish")!=-1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool test_19() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 19: Search & replace\n");
|
||||
|
||||
String s="Happy Birthday, Anna!";
|
||||
OS::get_singleton()->print("\tString: %ls\n",s.c_str());
|
||||
|
||||
s=s.replace("Birthday","Halloween");
|
||||
OS::get_singleton()->print("\tReplaced Birthday/Halloween: %ls.\n",s.c_str());
|
||||
|
||||
return (s=="Happy Halloween, Anna!");
|
||||
|
||||
}
|
||||
|
||||
bool test_20() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 20: Insertion\n");
|
||||
|
||||
String s="Who is Frederic?";
|
||||
|
||||
OS::get_singleton()->print("\tString: %ls\n",s.c_str());
|
||||
s=s.insert( s.find("?")," Chopin" );
|
||||
OS::get_singleton()->print("\tInserted Chopin: %ls.\n",s.c_str());
|
||||
|
||||
return (s=="Who is Frederic Chopin?");
|
||||
|
||||
}
|
||||
|
||||
bool test_21() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 21: Number -> String\n");
|
||||
|
||||
OS::get_singleton()->print("\tPi is %f\n",33.141593);
|
||||
OS::get_singleton()->print("\tPi String is %ls\n",String::num(3.141593).c_str());
|
||||
|
||||
return String::num(3.141593)=="3.141593";
|
||||
|
||||
}
|
||||
|
||||
bool test_22() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 22: String -> Int\n");
|
||||
|
||||
static const char* nums[4]={ "1237461283", "- 22", "0", " - 1123412" };
|
||||
static const int num[4]={ 1237461283, -22, 0, -1123412 };
|
||||
|
||||
for (int i=0;i<4;i++) {
|
||||
OS::get_singleton()->print("\tString: \"%s\" as Int is %i\n",nums[i],String(nums[i]).to_int());
|
||||
|
||||
if (String(nums[i]).to_int()!=num[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool test_23() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 23: String -> Float\n");
|
||||
|
||||
static const char* nums[4]={ "-12348298412.2", "0.05", "2.0002", " -0.0001" };
|
||||
static const double num[4]={ -12348298412.2, 0.05, 2.0002, -0.0001 };
|
||||
|
||||
for (int i=0;i<4;i++) {
|
||||
OS::get_singleton()->print("\tString: \"%s\" as Float is %f\n",nums[i],String(nums[i]).to_double());
|
||||
|
||||
if ( ABS(String(nums[i]).to_double()-num[i])>0.00001)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool test_24() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 24: Slicing\n");
|
||||
|
||||
String s="Mars,Jupiter,Saturn,Uranus";
|
||||
|
||||
const char*slices[4]={"Mars","Jupiter","Saturn","Uranus"};
|
||||
|
||||
OS::get_singleton()->print("\tSlicing \"%ls\" by \"%s\"..\n",s.c_str(),",");
|
||||
|
||||
for (int i=0;i<s.get_slice_count(",");i++) {
|
||||
|
||||
OS::get_singleton()->print("\t\t%i- %ls\n",i+1,s.get_slice(",",i).c_str());
|
||||
|
||||
|
||||
if (s.get_slice(",",i)!=slices[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool test_25() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 25: Erasing\n");
|
||||
|
||||
String s="Josephine is such a cute girl!";
|
||||
|
||||
OS::get_singleton()->print("\tString: %ls\n",s.c_str());
|
||||
OS::get_singleton()->print("\tRemoving \"cute\"\n");
|
||||
|
||||
s.erase(s.find("cute "),String("cute ").length());
|
||||
OS::get_singleton()->print("\tResult: %ls\n",s.c_str());
|
||||
|
||||
|
||||
return (s=="Josephine is such a girl!");
|
||||
|
||||
}
|
||||
|
||||
bool test_26() {
|
||||
|
||||
OS::get_singleton()->print("\n\nTest 26: RegEx\n");
|
||||
RegEx regexp("(.*):(.*)");
|
||||
List<String> captures;
|
||||
|
||||
bool match = regexp.match("name:password", &captures);
|
||||
printf("\tmatch: %s\n", match?"true":"false");
|
||||
|
||||
printf("\t%i captures:\n", captures.size());
|
||||
List<String>::Element *I = captures.front();
|
||||
while (I) {
|
||||
|
||||
printf("%ls\n", I->get().c_str());
|
||||
|
||||
I = I->next();
|
||||
};
|
||||
return captures.size();
|
||||
};
|
||||
|
||||
typedef bool (*TestFunc)(void);
|
||||
|
||||
TestFunc test_funcs[] = {
|
||||
|
||||
test_1,
|
||||
test_2,
|
||||
test_3,
|
||||
test_4,
|
||||
test_5,
|
||||
test_6,
|
||||
test_7,
|
||||
test_8,
|
||||
test_9,
|
||||
test_10,
|
||||
test_11,
|
||||
test_12,
|
||||
test_13,
|
||||
test_14,
|
||||
test_15,
|
||||
test_16,
|
||||
test_17,
|
||||
test_18,
|
||||
test_19,
|
||||
test_20,
|
||||
test_21,
|
||||
test_22,
|
||||
test_23,
|
||||
test_24,
|
||||
test_25,
|
||||
test_26,
|
||||
0
|
||||
|
||||
};
|
||||
|
||||
MainLoop* test() {
|
||||
|
||||
/** A character length != wchar_t may be forced, so the tests wont work */
|
||||
|
||||
ERR_FAIL_COND_V( sizeof(CharType) != sizeof(wchar_t), NULL );
|
||||
|
||||
int count=0;
|
||||
int passed=0;
|
||||
|
||||
while(true) {
|
||||
if (!test_funcs[count])
|
||||
break;
|
||||
bool pass=test_funcs[count]();
|
||||
if (pass)
|
||||
passed++;
|
||||
OS::get_singleton()->print("\t%s\n",pass?"PASS":"FAILED");
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
OS::get_singleton()->print("\n\n\n");
|
||||
OS::get_singleton()->print("*************\n");
|
||||
OS::get_singleton()->print("***TOTALS!***\n");
|
||||
OS::get_singleton()->print("*************\n");
|
||||
|
||||
OS::get_singleton()->print("Passed %i of %i tests\n",count,passed);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
44
bin/tests/test_string.h
Normal file
44
bin/tests/test_string.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*************************************************************************/
|
||||
/* test_string.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 TEST_STRING_H
|
||||
#define TEST_STRING_H
|
||||
|
||||
#include "ustring.h"
|
||||
#include "os/main_loop.h"
|
||||
|
||||
namespace TestString {
|
||||
|
||||
MainLoop* test();
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
39
core/SCsub
Normal file
39
core/SCsub
Normal file
@ -0,0 +1,39 @@
|
||||
Import('env')
|
||||
|
||||
env.core_sources=[]
|
||||
|
||||
|
||||
gd_call=""
|
||||
gd_inc=""
|
||||
|
||||
for x in env.global_defaults:
|
||||
env.core_sources.append("#platform/"+x+"/globals/global_defaults.cpp")
|
||||
gd_inc+='#include "platform/'+x+'/globals/global_defaults.h"\n'
|
||||
gd_call+="\tregister_"+x+"_global_defaults();\n"
|
||||
|
||||
gd_cpp='#include "globals.h"\n'
|
||||
gd_cpp+=gd_inc
|
||||
gd_cpp+="void Globals::register_global_defaults() {\n"+gd_call+"\n}\n"
|
||||
|
||||
f = open("global_defaults.cpp","wb")
|
||||
f.write(gd_cpp)
|
||||
f.close()
|
||||
|
||||
|
||||
env.add_source_files(env.core_sources,"*.cpp")
|
||||
|
||||
Export('env')
|
||||
|
||||
import make_binders
|
||||
env.Command('method_bind.inc', 'make_binders.py', make_binders.run)
|
||||
|
||||
SConscript('os/SCsub');
|
||||
SConscript('math/SCsub');
|
||||
SConscript('io/SCsub');
|
||||
SConscript('bind/SCsub');
|
||||
|
||||
lib = env.Library("core",env.core_sources)
|
||||
|
||||
env.Prepend(LIBS=[lib])
|
||||
|
||||
|
198
core/allocators.h
Normal file
198
core/allocators.h
Normal file
@ -0,0 +1,198 @@
|
||||
/*************************************************************************/
|
||||
/* allocators.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 ALLOCATORS_H
|
||||
#define ALLOCATORS_H
|
||||
|
||||
#include "os/memory.h"
|
||||
template<int PREALLOC_COUNT=64, int MAX_HANDS=8>
|
||||
class BalloonAllocator {
|
||||
|
||||
enum {
|
||||
|
||||
USED_FLAG=(1<<30),
|
||||
USED_MASK=USED_FLAG-1
|
||||
};
|
||||
|
||||
struct Balloon {
|
||||
|
||||
Balloon *next;
|
||||
Balloon *prev;
|
||||
uint32_t hand;
|
||||
};
|
||||
|
||||
|
||||
struct Hand {
|
||||
|
||||
int used;
|
||||
int allocated;
|
||||
Balloon *first;
|
||||
Balloon *last;
|
||||
};
|
||||
|
||||
|
||||
Hand hands[MAX_HANDS];
|
||||
|
||||
|
||||
|
||||
public:
|
||||
|
||||
void* alloc(size_t p_size) {
|
||||
|
||||
size_t max=(1<<MAX_HANDS);
|
||||
ERR_FAIL_COND_V( p_size>max, NULL );
|
||||
|
||||
unsigned int hand=0;
|
||||
|
||||
while(p_size>(size_t)(1<<hand)) ++hand;
|
||||
|
||||
Hand &h=hands[hand];
|
||||
|
||||
if (h.used==h.allocated) {
|
||||
|
||||
for(int i=0;i<PREALLOC_COUNT;i++) {
|
||||
|
||||
Balloon *b = (Balloon*)memalloc(sizeof(Balloon)+(1<<hand));
|
||||
b->hand=hand;
|
||||
if (h.last) {
|
||||
|
||||
b->prev=h.last;
|
||||
h.last->next=b;
|
||||
h.last=b;
|
||||
} else {
|
||||
|
||||
b->prev=NULL;
|
||||
h.last=b;
|
||||
h.first=b;
|
||||
}
|
||||
}
|
||||
|
||||
h.last->next=NULL;
|
||||
h.allocated+=PREALLOC_COUNT;
|
||||
}
|
||||
|
||||
Balloon *pick=h.last;
|
||||
|
||||
ERR_FAIL_COND_V( (pick->hand&USED_FLAG), NULL );
|
||||
|
||||
// remove last
|
||||
h.last=h.last->prev;
|
||||
h.last->next=NULL;
|
||||
|
||||
pick->next=h.first;
|
||||
h.first->prev=pick;
|
||||
pick->prev=NULL;
|
||||
h.first=pick;
|
||||
h.used++;
|
||||
pick->hand|=USED_FLAG;
|
||||
|
||||
return (void*)(pick+1);
|
||||
}
|
||||
|
||||
void free(void* p_ptr) {
|
||||
|
||||
Balloon *b=(Balloon*)p_ptr;
|
||||
b-=1;
|
||||
|
||||
ERR_FAIL_COND(!(b->hand&USED_FLAG) );
|
||||
|
||||
b->hand=b->hand&USED_MASK; // not used
|
||||
int hand=b->hand;
|
||||
|
||||
Hand &h=hands[hand];
|
||||
|
||||
if (b==h.first)
|
||||
h.first=b->next;
|
||||
|
||||
if (b->prev)
|
||||
b->prev->next=b->next;
|
||||
if (b->next)
|
||||
b->next->prev=b->prev;
|
||||
|
||||
if (h.last!=b) {
|
||||
h.last->next=b;
|
||||
b->prev=h.last;
|
||||
b->next=NULL;
|
||||
h.last=b;
|
||||
}
|
||||
|
||||
h.used--;
|
||||
|
||||
if (h.used<=(h.allocated-(PREALLOC_COUNT*2))) { // this is done to ensure no alloc/free is done constantly
|
||||
|
||||
for(int i=0;i<PREALLOC_COUNT;i++) {
|
||||
ERR_CONTINUE( h.last->hand& USED_FLAG );
|
||||
|
||||
Balloon *new_last=h.last->prev;
|
||||
if (new_last)
|
||||
new_last->next=NULL;
|
||||
memfree( h.last );
|
||||
h.last=new_last;
|
||||
}
|
||||
h.allocated-=PREALLOC_COUNT;
|
||||
}
|
||||
}
|
||||
|
||||
BalloonAllocator() {
|
||||
|
||||
for(int i=0;i<MAX_HANDS;i++) {
|
||||
|
||||
hands[i].allocated=0;
|
||||
hands[i].used=0;
|
||||
hands[i].first=NULL;
|
||||
hands[i].last=NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void clear() {
|
||||
|
||||
for(int i=0;i<MAX_HANDS;i++) {
|
||||
|
||||
while(hands[i].first) {
|
||||
|
||||
Balloon *b=hands[i].first;
|
||||
hands[i].first=b->next;
|
||||
memfree(b);
|
||||
}
|
||||
|
||||
hands[i].allocated=0;
|
||||
hands[i].used=0;
|
||||
hands[i].first=NULL;
|
||||
hands[i].last=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
~BalloonAllocator() {
|
||||
|
||||
clear();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif // ALLOCATORS_H
|
241
core/array.cpp
Normal file
241
core/array.cpp
Normal file
@ -0,0 +1,241 @@
|
||||
/*************************************************************************/
|
||||
/* array.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "array.h"
|
||||
#include "vector.h"
|
||||
#include "hashfuncs.h"
|
||||
#include "variant.h"
|
||||
#include "object.h"
|
||||
|
||||
struct ArrayPrivate {
|
||||
|
||||
SafeRefCount refcount;
|
||||
Vector<Variant> array;
|
||||
bool shared;
|
||||
};
|
||||
|
||||
void Array::_ref(const Array& p_from) const {
|
||||
|
||||
ArrayPrivate *_fp = p_from._p;
|
||||
|
||||
ERR_FAIL_COND(!_fp); // should NOT happen.
|
||||
|
||||
if (_fp == _p)
|
||||
return; //wathever it is, nothing to do here move along
|
||||
|
||||
bool success = _fp->refcount.ref();
|
||||
|
||||
ERR_FAIL_COND(!success); //should really not happen either
|
||||
|
||||
_unref();
|
||||
|
||||
if (_fp->shared) {
|
||||
|
||||
_p = p_from._p;
|
||||
|
||||
} else {
|
||||
|
||||
_p = memnew( ArrayPrivate );
|
||||
_p->shared=false;
|
||||
_p->refcount.init();
|
||||
_p->array=_fp->array;
|
||||
|
||||
if (_fp->refcount.unref())
|
||||
memdelete(_fp);
|
||||
}
|
||||
}
|
||||
|
||||
void Array::_unref() const {
|
||||
|
||||
if (!_p)
|
||||
return;
|
||||
|
||||
if (_p->refcount.unref()) {
|
||||
memdelete(_p);
|
||||
}
|
||||
_p=NULL;
|
||||
}
|
||||
|
||||
|
||||
Variant& Array::operator[](int p_idx) {
|
||||
|
||||
return _p->array[p_idx];
|
||||
}
|
||||
|
||||
const Variant& Array::operator[](int p_idx) const {
|
||||
|
||||
return _p->array[p_idx];
|
||||
|
||||
}
|
||||
|
||||
int Array::size() const {
|
||||
|
||||
return _p->array.size();
|
||||
}
|
||||
bool Array::empty() const {
|
||||
|
||||
return _p->array.empty();
|
||||
}
|
||||
void Array::clear() {
|
||||
|
||||
_p->array.clear();
|
||||
}
|
||||
|
||||
bool Array::is_shared() const {
|
||||
|
||||
return _p->shared;
|
||||
}
|
||||
|
||||
bool Array::operator==(const Array& p_array) const {
|
||||
|
||||
return _p==p_array._p;
|
||||
}
|
||||
|
||||
uint32_t Array::hash() const {
|
||||
|
||||
uint32_t h=hash_djb2_one_32(0);
|
||||
|
||||
for (int i=0;i<_p->array.size();i++) {
|
||||
|
||||
h = hash_djb2_one_32( _p->array[i].hash(), h);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
void Array::operator=(const Array& p_array) {
|
||||
|
||||
_ref(p_array);
|
||||
}
|
||||
void Array::push_back(const Variant& p_value) {
|
||||
|
||||
_p->array.push_back(p_value);
|
||||
}
|
||||
|
||||
Error Array::resize(int p_new_size) {
|
||||
|
||||
return _p->array.resize(p_new_size);
|
||||
}
|
||||
|
||||
void Array::insert(int p_pos, const Variant& p_value) {
|
||||
|
||||
_p->array.insert(p_pos,p_value);
|
||||
}
|
||||
|
||||
void Array::erase(const Variant& p_value) {
|
||||
|
||||
_p->array.erase(p_value);
|
||||
}
|
||||
|
||||
int Array::find(const Variant& p_value) const {
|
||||
|
||||
return _p->array.find(p_value);
|
||||
}
|
||||
|
||||
void Array::remove(int p_pos) {
|
||||
|
||||
_p->array.remove(p_pos);
|
||||
}
|
||||
|
||||
|
||||
void Array::set(int p_idx,const Variant& p_value) {
|
||||
|
||||
operator[](p_idx)=p_value;
|
||||
}
|
||||
|
||||
const Variant& Array::get(int p_idx) const {
|
||||
|
||||
return operator[](p_idx);
|
||||
}
|
||||
|
||||
struct _ArrayVariantSort {
|
||||
|
||||
_FORCE_INLINE_ bool operator()(const Variant& p_l, const Variant& p_r) const {
|
||||
bool valid=false;
|
||||
Variant res;
|
||||
Variant::evaluate(Variant::OP_LESS,p_l,p_r,res,valid);
|
||||
if (!valid)
|
||||
res=false;
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
void Array::sort() {
|
||||
|
||||
_p->array.sort_custom<_ArrayVariantSort>();
|
||||
|
||||
}
|
||||
|
||||
struct _ArrayVariantSortCustom {
|
||||
|
||||
Object *obj;
|
||||
StringName func;
|
||||
|
||||
_FORCE_INLINE_ bool operator()(const Variant& p_l, const Variant& p_r) const {
|
||||
|
||||
const Variant*args[2]={&p_l,&p_r};
|
||||
Variant::CallError err;
|
||||
bool res = obj->call(func,args,2,err);
|
||||
if (err.error!=Variant::CallError::CALL_OK)
|
||||
res=false;
|
||||
return res;
|
||||
|
||||
}
|
||||
};
|
||||
void Array::sort_custom(Object *p_obj,const StringName& p_function){
|
||||
|
||||
ERR_FAIL_NULL(p_obj);
|
||||
|
||||
SortArray<Variant,_ArrayVariantSortCustom> avs;
|
||||
avs.compare.obj=p_obj;
|
||||
avs.compare.func=p_function;
|
||||
avs.sort(_p->array.ptr(),_p->array.size());
|
||||
|
||||
}
|
||||
|
||||
void Array::invert(){
|
||||
|
||||
_p->array.invert();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Array::Array(const Array& p_from) {
|
||||
|
||||
_p=NULL;
|
||||
_ref(p_from);
|
||||
|
||||
}
|
||||
Array::Array(bool p_shared) {
|
||||
|
||||
_p = memnew( ArrayPrivate );
|
||||
_p->refcount.init();
|
||||
_p->shared=p_shared;
|
||||
}
|
||||
Array::~Array() {
|
||||
|
||||
_unref();
|
||||
}
|
84
core/array.h
Normal file
84
core/array.h
Normal file
@ -0,0 +1,84 @@
|
||||
/*************************************************************************/
|
||||
/* array.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 ARRAY_H
|
||||
#define ARRAY_H
|
||||
|
||||
#include "typedefs.h"
|
||||
class Variant;
|
||||
class ArrayPrivate;
|
||||
class Object;
|
||||
class StringName;
|
||||
|
||||
class Array {
|
||||
|
||||
mutable ArrayPrivate *_p;
|
||||
void _ref(const Array& p_from) const;
|
||||
void _unref() const;
|
||||
|
||||
public:
|
||||
|
||||
Variant& operator[](int p_idx);
|
||||
const Variant& operator[](int p_idx) const;
|
||||
|
||||
void set(int p_idx,const Variant& p_value);
|
||||
const Variant& get(int p_idx) const;
|
||||
|
||||
int size() const;
|
||||
bool empty() const;
|
||||
void clear();
|
||||
|
||||
bool is_shared() const;
|
||||
|
||||
bool operator==(const Array& p_array) const;
|
||||
|
||||
uint32_t hash() const;
|
||||
void operator=(const Array& p_array);
|
||||
|
||||
void push_back(const Variant& p_value);
|
||||
_FORCE_INLINE_ void append(const Variant& p_value) { push_back(p_value); } //for python compatibility
|
||||
Error resize(int p_new_size);
|
||||
|
||||
void insert(int p_pos, const Variant& p_value);
|
||||
void remove(int p_pos);
|
||||
|
||||
void sort();
|
||||
void sort_custom(Object *p_obj,const StringName& p_function);
|
||||
void invert();
|
||||
|
||||
int find(const Variant& p_value) const;
|
||||
|
||||
void erase(const Variant& p_value);
|
||||
|
||||
Array(const Array& p_from);
|
||||
Array(bool p_shared=false);
|
||||
~Array();
|
||||
|
||||
};
|
||||
|
||||
#endif // ARRAY_H
|
35
core/balloon_allocator.h
Normal file
35
core/balloon_allocator.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*************************************************************************/
|
||||
/* balloon_allocator.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 BALLOON_ALLOCATOR_H
|
||||
#define BALLOON_ALLOCATOR_H
|
||||
|
||||
#include "os/memory.h"
|
||||
|
||||
#include "allocators.h"
|
||||
#endif // BALLOON_ALLOCATOR_H
|
7
core/bind/SCsub
Normal file
7
core/bind/SCsub
Normal file
@ -0,0 +1,7 @@
|
||||
Import('env')
|
||||
|
||||
env.add_source_files(env.core_sources,"*.cpp")
|
||||
|
||||
Export('env')
|
||||
|
||||
|
1436
core/bind/core_bind.cpp
Normal file
1436
core/bind/core_bind.cpp
Normal file
File diff suppressed because it is too large
Load Diff
417
core/bind/core_bind.h
Normal file
417
core/bind/core_bind.h
Normal file
@ -0,0 +1,417 @@
|
||||
#ifndef CORE_BIND_H
|
||||
#define CORE_BIND_H
|
||||
|
||||
#include "io/resource_loader.h"
|
||||
#include "io/resource_saver.h"
|
||||
#include "os/file_access.h"
|
||||
#include "os/dir_access.h"
|
||||
#include "os/thread.h"
|
||||
#include "os/semaphore.h"
|
||||
|
||||
|
||||
class _ResourceLoader : public Object {
|
||||
OBJ_TYPE(_ResourceLoader,Object);
|
||||
|
||||
protected:
|
||||
|
||||
static void _bind_methods();
|
||||
static _ResourceLoader *singleton;
|
||||
public:
|
||||
|
||||
|
||||
static _ResourceLoader *get_singleton() { return singleton; }
|
||||
Ref<ResourceInteractiveLoader> load_interactive(const String& p_path,const String& p_type_hint="");
|
||||
RES load(const String &p_path,const String& p_type_hint="");
|
||||
DVector<String> get_recognized_extensions_for_type(const String& p_type);
|
||||
void set_abort_on_missing_resources(bool p_abort);
|
||||
StringArray get_dependencies(const String& p_path);
|
||||
bool has(const String& p_path);
|
||||
|
||||
_ResourceLoader();
|
||||
};
|
||||
|
||||
class _ResourceSaver : public Object {
|
||||
OBJ_TYPE(_ResourceSaver,Object);
|
||||
|
||||
protected:
|
||||
|
||||
static void _bind_methods();
|
||||
static _ResourceSaver *singleton;
|
||||
public:
|
||||
|
||||
static _ResourceSaver *get_singleton() { return singleton; }
|
||||
|
||||
Error save(const String &p_path,const RES& p_resource, uint32_t p_flags);
|
||||
DVector<String> get_recognized_extensions(const RES& p_resource);
|
||||
|
||||
|
||||
_ResourceSaver();
|
||||
};
|
||||
|
||||
class MainLoop;
|
||||
|
||||
class _OS : public Object {
|
||||
OBJ_TYPE(_OS,Object);
|
||||
|
||||
protected:
|
||||
|
||||
static void _bind_methods();
|
||||
static _OS *singleton;
|
||||
public:
|
||||
|
||||
enum Weekday {
|
||||
DAY_SUNDAY,
|
||||
DAY_MONDAY,
|
||||
DAY_TUESDAY,
|
||||
DAY_WEDNESDAY,
|
||||
DAY_THURSDAY,
|
||||
DAY_FRIDAY,
|
||||
DAY_SATURDAY
|
||||
};
|
||||
|
||||
enum Month {
|
||||
MONTH_JANUARY,
|
||||
MONTH_FEBRUARY,
|
||||
MONTH_MARCH,
|
||||
MONTH_APRIL,
|
||||
MONTH_MAY,
|
||||
MONTH_JUNE,
|
||||
MONTH_JULY,
|
||||
MONTH_AUGUST,
|
||||
MONTH_SEPTEMBER,
|
||||
MONTH_OCTOBER,
|
||||
MONTH_NOVEMBER,
|
||||
MONTH_DECEMBER
|
||||
};
|
||||
|
||||
Point2 get_mouse_pos() const;
|
||||
void set_window_title(const String& p_title);
|
||||
int get_mouse_button_state() const;
|
||||
|
||||
|
||||
void set_clipboard(const String& p_text);
|
||||
String get_clipboard() const;
|
||||
|
||||
void set_video_mode(const Size2& p_size, bool p_fullscreen,bool p_resizeable,int p_screen=0);
|
||||
Size2 get_video_mode(int p_screen=0) const;
|
||||
bool is_video_mode_fullscreen(int p_screen=0) const;
|
||||
bool is_video_mode_resizable(int p_screen=0) const;
|
||||
Array get_fullscreen_mode_list(int p_screen=0) const;
|
||||
|
||||
void set_iterations_per_second(int p_ips);
|
||||
int get_iterations_per_second() const;
|
||||
|
||||
void set_low_processor_usage_mode(bool p_enabled);
|
||||
bool is_in_low_processor_usage_mode() const;
|
||||
|
||||
String get_executable_path() const;
|
||||
int execute(const String& p_path, const Vector<String> & p_arguments,bool p_blocking);
|
||||
Error kill(int p_pid);
|
||||
Error shell_open(String p_uri);
|
||||
|
||||
bool has_environment(const String& p_var) const;
|
||||
String get_environment(const String& p_var) const;
|
||||
|
||||
String get_name() const;
|
||||
Vector<String> get_cmdline_args();
|
||||
|
||||
String get_locale() const;
|
||||
String get_model_name() const;
|
||||
MainLoop *get_main_loop() const;
|
||||
|
||||
String get_custom_level() const;
|
||||
|
||||
float get_frames_per_second() const;
|
||||
|
||||
void dump_memory_to_file(const String& p_file);
|
||||
void dump_resources_to_file(const String& p_file);
|
||||
|
||||
void print_resources_in_use(bool p_short=false);
|
||||
void print_all_resources(const String& p_to_file);
|
||||
|
||||
bool has_touchscreen_ui_hint() const;
|
||||
|
||||
String get_unique_ID() const;
|
||||
|
||||
/*
|
||||
struct Date {
|
||||
|
||||
int year;
|
||||
Month month;
|
||||
int day;
|
||||
Weekday weekday;
|
||||
bool dst;
|
||||
};
|
||||
|
||||
struct Time {
|
||||
|
||||
int hour;
|
||||
int min;
|
||||
int sec;
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
void set_icon(const Image& p_icon);
|
||||
Dictionary get_date() const;
|
||||
Dictionary get_time() const;
|
||||
uint64_t get_unix_time() const;
|
||||
|
||||
int get_static_memory_usage() const;
|
||||
int get_static_memory_peak_usage() const;
|
||||
int get_dynamic_memory_usage() const;
|
||||
|
||||
void delay_usec(uint32_t p_usec) const;
|
||||
void delay_msec(uint32_t p_msec) const;
|
||||
uint32_t get_ticks_msec() const;
|
||||
|
||||
|
||||
bool can_draw() const;
|
||||
|
||||
int get_frames_drawn();
|
||||
|
||||
bool is_stdout_verbose() const;
|
||||
|
||||
int get_processor_count() const;
|
||||
|
||||
String get_data_dir() const;
|
||||
|
||||
static _OS *get_singleton() { return singleton; }
|
||||
|
||||
_OS();
|
||||
};
|
||||
|
||||
class _Geometry : public Object {
|
||||
|
||||
OBJ_TYPE(_Geometry, Object);
|
||||
|
||||
static _Geometry *singleton;
|
||||
protected:
|
||||
|
||||
static void _bind_methods();
|
||||
public:
|
||||
|
||||
static _Geometry *get_singleton();
|
||||
DVector<Plane> build_box_planes(const Vector3& p_extents);
|
||||
DVector<Plane> build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis=Vector3::AXIS_Z);
|
||||
DVector<Plane> build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis=Vector3::AXIS_Z);
|
||||
Variant segment_intersects_segment_2d(const Vector2& p_from_a,const Vector2& p_to_a,const Vector2& p_from_b,const Vector2& p_to_b);
|
||||
DVector<Vector2> get_closest_points_between_segments_2d( const Vector2& p1,const Vector2& q1, const Vector2& p2,const Vector2& q2);
|
||||
DVector<Vector3> get_closest_points_between_segments(const Vector3& p1,const Vector3& p2,const Vector3& q1,const Vector3& q2);
|
||||
Vector3 get_closest_point_to_segment(const Vector3& p_point, const Vector3& p_a,const Vector3& p_b);
|
||||
Variant ray_intersects_triangle( const Vector3& p_from, const Vector3& p_dir, const Vector3& p_v0,const Vector3& p_v1,const Vector3& p_v2);
|
||||
Variant segment_intersects_triangle( const Vector3& p_from, const Vector3& p_to, const Vector3& p_v0,const Vector3& p_v1,const Vector3& p_v2);
|
||||
DVector<Vector3> segment_intersects_sphere( const Vector3& p_from, const Vector3& p_to, const Vector3& p_sphere_pos,real_t p_sphere_radius);
|
||||
DVector<Vector3> segment_intersects_cylinder( const Vector3& p_from, const Vector3& p_to, float p_height,float p_radius);
|
||||
DVector<Vector3> segment_intersects_convex(const Vector3& p_from, const Vector3& p_to,const Vector<Plane>& p_planes);
|
||||
real_t segment_intersects_circle(const Vector2& p_from, const Vector2& p_to, const Vector2& p_circle_pos, real_t p_circle_radius);
|
||||
|
||||
Vector<int> triangulate_polygon(const Vector<Vector2>& p_polygon);
|
||||
|
||||
_Geometry();
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class _File : public Reference {
|
||||
|
||||
OBJ_TYPE(_File,Reference);
|
||||
FileAccess *f;
|
||||
bool eswap;
|
||||
protected:
|
||||
|
||||
static void _bind_methods();
|
||||
public:
|
||||
|
||||
enum ModeFlags {
|
||||
|
||||
READ=1,
|
||||
WRITE=2,
|
||||
READ_WRITE=3,
|
||||
};
|
||||
|
||||
Error open(const String& p_path, int p_mode_flags); ///< open a file
|
||||
void close(); ///< close a file
|
||||
bool is_open() const; ///< true when file is open
|
||||
|
||||
void seek(int64_t p_position); ///< seek to a given position
|
||||
void seek_end(int64_t p_position=0); ///< seek from the end of file
|
||||
int64_t get_pos() const; ///< get position in the file
|
||||
int64_t get_len() const; ///< get size of the file
|
||||
|
||||
bool eof_reached() const; ///< reading passed EOF
|
||||
|
||||
uint8_t get_8() const; ///< get a byte
|
||||
uint16_t get_16() const; ///< get 16 bits uint
|
||||
uint32_t get_32() const; ///< get 32 bits uint
|
||||
uint64_t get_64() const; ///< get 64 bits uint
|
||||
|
||||
float get_float() const;
|
||||
double get_double() const;
|
||||
real_t get_real() const;
|
||||
|
||||
Variant get_var() const;
|
||||
|
||||
DVector<uint8_t> get_buffer(int p_length) const; ///< get an array of bytes
|
||||
String get_line() const;
|
||||
String get_as_text() const;
|
||||
|
||||
/**< use this for files WRITTEN in _big_ endian machines (ie, amiga/mac)
|
||||
* It's not about the current CPU type but file formats.
|
||||
* this flags get reset to false (little endian) on each open
|
||||
*/
|
||||
|
||||
void set_endian_swap(bool p_swap);
|
||||
bool get_endian_swap();
|
||||
|
||||
Error get_error() const; ///< get last error
|
||||
|
||||
void store_8(uint8_t p_dest); ///< store a byte
|
||||
void store_16(uint16_t p_dest); ///< store 16 bits uint
|
||||
void store_32(uint32_t p_dest); ///< store 32 bits uint
|
||||
void store_64(uint64_t p_dest); ///< store 64 bits uint
|
||||
|
||||
void store_float(float p_dest);
|
||||
void store_double(double p_dest);
|
||||
void store_real(real_t p_real);
|
||||
|
||||
void store_string(const String& p_string);
|
||||
void store_line(const String& p_string);
|
||||
|
||||
Vector<String> get_csv_line() const;
|
||||
|
||||
|
||||
void store_buffer(const DVector<uint8_t>& p_buffer); ///< store an array of bytes
|
||||
|
||||
void store_var(const Variant& p_var);
|
||||
|
||||
bool file_exists(const String& p_name) const; ///< return true if a file exists
|
||||
|
||||
_File();
|
||||
virtual ~_File();
|
||||
|
||||
};
|
||||
|
||||
class _Directory : public Reference {
|
||||
|
||||
OBJ_TYPE(_Directory,Reference);
|
||||
DirAccess *d;
|
||||
protected:
|
||||
|
||||
static void _bind_methods();
|
||||
public:
|
||||
|
||||
Error open(const String& p_path);
|
||||
|
||||
bool list_dir_begin(); ///< This starts dir listing
|
||||
String get_next();
|
||||
bool current_is_dir() const;
|
||||
|
||||
void list_dir_end(); ///<
|
||||
|
||||
int get_drive_count();
|
||||
String get_drive(int p_drive);
|
||||
|
||||
Error change_dir(String p_dir); ///< can be relative or absolute, return false on success
|
||||
String get_current_dir(); ///< return current dir location
|
||||
|
||||
Error make_dir(String p_dir);
|
||||
Error make_dir_recursive(String p_dir);
|
||||
|
||||
bool file_exists(String p_file);
|
||||
|
||||
int get_space_left();
|
||||
|
||||
Error copy(String p_from,String p_to);
|
||||
Error rename(String p_from, String p_to);
|
||||
Error remove(String p_name);
|
||||
|
||||
|
||||
_Directory();
|
||||
virtual ~_Directory();
|
||||
|
||||
};
|
||||
|
||||
class _Marshalls : public Reference {
|
||||
|
||||
OBJ_TYPE(_Marshalls,Reference);
|
||||
|
||||
protected:
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
String variant_to_base64(const Variant& p_var);
|
||||
Variant base64_to_variant(const String& p_str);
|
||||
|
||||
_Marshalls() {};
|
||||
};
|
||||
|
||||
|
||||
class _Mutex : public Reference {
|
||||
|
||||
OBJ_TYPE(_Mutex,Reference);
|
||||
Mutex *mutex;
|
||||
|
||||
static void _bind_methods();
|
||||
public:
|
||||
|
||||
void lock();
|
||||
Error try_lock();
|
||||
void unlock();
|
||||
|
||||
_Mutex();
|
||||
~_Mutex();
|
||||
};
|
||||
|
||||
class _Semaphore : public Reference {
|
||||
|
||||
OBJ_TYPE(_Semaphore,Reference);
|
||||
Semaphore *semaphore;
|
||||
|
||||
static void _bind_methods();
|
||||
public:
|
||||
|
||||
Error wait();
|
||||
Error post();
|
||||
|
||||
_Semaphore();
|
||||
~_Semaphore();
|
||||
};
|
||||
|
||||
class _Thread : public Reference {
|
||||
|
||||
OBJ_TYPE(_Thread,Reference);
|
||||
|
||||
protected:
|
||||
|
||||
Variant ret;
|
||||
Variant userdata;
|
||||
volatile bool active;
|
||||
Object *target_instance;
|
||||
StringName target_method;
|
||||
Thread *thread;
|
||||
static void _bind_methods();
|
||||
static void _start_func(void *ud);
|
||||
public:
|
||||
|
||||
enum Priority {
|
||||
|
||||
PRIORITY_LOW,
|
||||
PRIORITY_NORMAL,
|
||||
PRIORITY_HIGH
|
||||
};
|
||||
|
||||
Error start(Object *p_instance,const StringName& p_method,const Variant& p_userdata=Variant(),int p_priority=PRIORITY_NORMAL);
|
||||
String get_id() const;
|
||||
bool is_active() const;
|
||||
Variant wait_to_finish();
|
||||
|
||||
_Thread();
|
||||
~_Thread();
|
||||
};
|
||||
|
||||
#endif // CORE_BIND_H
|
377
core/color.cpp
Normal file
377
core/color.cpp
Normal file
@ -0,0 +1,377 @@
|
||||
/*************************************************************************/
|
||||
/* color.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "color.h"
|
||||
#include "math_funcs.h"
|
||||
#include "print_string.h"
|
||||
|
||||
uint32_t Color::to_ARGB32() const {
|
||||
|
||||
uint32_t c=(uint8_t)(a*255);
|
||||
c<<=8;
|
||||
c|=(uint8_t)(r*255);
|
||||
c<<=8;
|
||||
c|=(uint8_t)(g*255);
|
||||
c<<=8;
|
||||
c|=(uint8_t)(b*255);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
uint32_t Color::to_32() const {
|
||||
|
||||
uint32_t c=(uint8_t)(a*255);
|
||||
c<<=8;
|
||||
c|=(uint8_t)(r*255);
|
||||
c<<=8;
|
||||
c|=(uint8_t)(g*255);
|
||||
c<<=8;
|
||||
c|=(uint8_t)(b*255);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
float Color::get_h() const {
|
||||
|
||||
float min = MIN( r, g );
|
||||
min = MIN( min, b );
|
||||
float max = MAX( r, g );
|
||||
max = MAX( max, b );
|
||||
|
||||
float delta = max - min;
|
||||
|
||||
if( delta == 0 )
|
||||
return 0;
|
||||
|
||||
float h;
|
||||
if( r == max )
|
||||
h = ( g - b ) / delta; // between yellow & magenta
|
||||
else if( g == max )
|
||||
h = 2 + ( b - r ) / delta; // between cyan & yellow
|
||||
else
|
||||
h = 4 + ( r - g ) / delta; // between magenta & cyan
|
||||
|
||||
h/=6.0;
|
||||
if (h<0)
|
||||
h+=1.0;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
float Color::get_s() const {
|
||||
|
||||
|
||||
float min = MIN( r, g );
|
||||
min = MIN( min, b );
|
||||
float max = MAX( r, g );
|
||||
max = MAX( max, b );
|
||||
|
||||
float delta = max - min;
|
||||
|
||||
return (max!=0) ? (delta / max) : 0;
|
||||
|
||||
}
|
||||
|
||||
float Color::get_v() const {
|
||||
|
||||
float max = MAX( r, g );
|
||||
max = MAX( max, b );
|
||||
return max;
|
||||
}
|
||||
|
||||
void Color::set_hsv(float p_h, float p_s, float p_v, float p_alpha) {
|
||||
|
||||
int i;
|
||||
float f, p, q, t;
|
||||
a=p_alpha;
|
||||
|
||||
if( p_s == 0 ) {
|
||||
// acp_hromatic (grey)
|
||||
r = g = b = p_v;
|
||||
return;
|
||||
}
|
||||
|
||||
p_h *=6.0;
|
||||
i = Math::floor( p_h );
|
||||
f = p_h - i;
|
||||
p = p_v * ( 1 - p_s );
|
||||
q = p_v * ( 1 - p_s * f );
|
||||
t = p_v * ( 1 - p_s * ( 1 - f ) );
|
||||
|
||||
switch( i ) {
|
||||
case 0:
|
||||
r = p_v;
|
||||
g = t;
|
||||
b = p;
|
||||
break;
|
||||
case 1:
|
||||
r = q;
|
||||
g = p_v;
|
||||
b = p;
|
||||
break;
|
||||
case 2:
|
||||
r = p;
|
||||
g = p_v;
|
||||
b = t;
|
||||
break;
|
||||
case 3:
|
||||
r = p;
|
||||
g = q;
|
||||
b = p_v;
|
||||
break;
|
||||
case 4:
|
||||
r = t;
|
||||
g = p;
|
||||
b = p_v;
|
||||
break;
|
||||
default: // cap_se 5:
|
||||
r = p_v;
|
||||
g = p;
|
||||
b = q;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Color::invert() {
|
||||
|
||||
r=1.0-r;
|
||||
g=1.0-g;
|
||||
g=1.0-b;
|
||||
}
|
||||
void Color::contrast() {
|
||||
|
||||
r=Math::fmod(r+0.5,1.0);
|
||||
g=Math::fmod(g+0.5,1.0);
|
||||
b=Math::fmod(b+0.5,1.0);
|
||||
}
|
||||
|
||||
Color Color::hex(uint32_t p_hex) {
|
||||
|
||||
float a = (p_hex&0xFF)/255.0;
|
||||
p_hex>>=8;
|
||||
float b = (p_hex&0xFF)/255.0;
|
||||
p_hex>>=8;
|
||||
float g = (p_hex&0xFF)/255.0;
|
||||
p_hex>>=8;
|
||||
float r = (p_hex&0xFF)/255.0;
|
||||
|
||||
return Color(r,g,b,a);
|
||||
}
|
||||
|
||||
static float _parse_col(const String& p_str, int p_ofs) {
|
||||
|
||||
int ig=0;
|
||||
|
||||
for(int i=0;i<2;i++) {
|
||||
|
||||
int c=p_str[i+p_ofs];
|
||||
int v=0;
|
||||
|
||||
if (c>='0' && c<='9') {
|
||||
v=c-'0';
|
||||
} else if (c>='a' && c<='f') {
|
||||
v=c-'a';
|
||||
v+=10;
|
||||
} else if (c>='A' && c<='F') {
|
||||
v=c-'A';
|
||||
v+=10;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (i==0)
|
||||
ig+=v*16;
|
||||
else
|
||||
ig+=v;
|
||||
|
||||
}
|
||||
|
||||
return ig;
|
||||
|
||||
}
|
||||
|
||||
Color Color::inverted() const {
|
||||
|
||||
Color c=*this;
|
||||
c.invert();
|
||||
return c;
|
||||
}
|
||||
|
||||
Color Color::contrasted() const {
|
||||
|
||||
Color c=*this;
|
||||
c.contrasted();
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
Color Color::html(const String& p_color) {
|
||||
|
||||
String color = p_color;
|
||||
if (color.length()==0)
|
||||
return Color();
|
||||
if (color[0]=='#')
|
||||
color=color.substr(1,color.length()-1);
|
||||
|
||||
bool alpha=false;
|
||||
|
||||
if (color.length()==8) {
|
||||
alpha=true;
|
||||
} else if (color.length()==6) {
|
||||
alpha=false;
|
||||
} else {
|
||||
ERR_EXPLAIN("Invalid Color Code: "+p_color);
|
||||
ERR_FAIL_V(Color());
|
||||
}
|
||||
|
||||
int a=255;
|
||||
if (alpha) {
|
||||
a=_parse_col(color,0);
|
||||
if (a<0) {
|
||||
ERR_EXPLAIN("Invalid Color Code: "+p_color);
|
||||
ERR_FAIL_V(Color());
|
||||
}
|
||||
}
|
||||
|
||||
int from=alpha?2:0;
|
||||
|
||||
int r=_parse_col(color,from+0);
|
||||
if (r<0) {
|
||||
ERR_EXPLAIN("Invalid Color Code: "+p_color);
|
||||
ERR_FAIL_V(Color());
|
||||
}
|
||||
int g=_parse_col(color,from+2);
|
||||
if (g<0) {
|
||||
ERR_EXPLAIN("Invalid Color Code: "+p_color);
|
||||
ERR_FAIL_V(Color());
|
||||
}
|
||||
int b=_parse_col(color,from+4);
|
||||
if (b<0) {
|
||||
ERR_EXPLAIN("Invalid Color Code: "+p_color);
|
||||
ERR_FAIL_V(Color());
|
||||
}
|
||||
|
||||
return Color(r/255.0,g/255.0,b/255.0,a/255.0);
|
||||
}
|
||||
|
||||
bool Color::html_is_valid(const String& p_color) {
|
||||
|
||||
String color = p_color;
|
||||
|
||||
if (color.length()==0)
|
||||
return false;
|
||||
if (color[0]=='#')
|
||||
color=color.substr(1,color.length()-1);
|
||||
|
||||
bool alpha=false;
|
||||
|
||||
if (color.length()==8) {
|
||||
alpha=true;
|
||||
} else if (color.length()==6) {
|
||||
alpha=false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
int a=255;
|
||||
if (alpha) {
|
||||
a=_parse_col(color,0);
|
||||
if (a<0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int from=alpha?2:0;
|
||||
|
||||
int r=_parse_col(color,from+0);
|
||||
if (r<0) {
|
||||
return false;
|
||||
}
|
||||
int g=_parse_col(color,from+2);
|
||||
if (g<0) {
|
||||
return false;
|
||||
}
|
||||
int b=_parse_col(color,from+4);
|
||||
if (b<0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
String _to_hex(float p_val) {
|
||||
|
||||
int v = p_val * 255;
|
||||
v = CLAMP(v,0,255);
|
||||
String ret;
|
||||
|
||||
for(int i=0;i<2;i++) {
|
||||
|
||||
CharType c[2]={0,0};
|
||||
int lv = v&0xF;
|
||||
if (lv<10)
|
||||
c[0]='0'+lv;
|
||||
else
|
||||
c[0]='a'+lv-10;
|
||||
|
||||
v>>=4;
|
||||
String cs=(const CharType*)c;
|
||||
ret = cs + ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
String Color::to_html(bool p_alpha) const {
|
||||
|
||||
String txt;
|
||||
txt+=_to_hex(r);
|
||||
txt+=_to_hex(g);
|
||||
txt+=_to_hex(b);
|
||||
if (p_alpha)
|
||||
txt=_to_hex(a)+txt;
|
||||
return txt;
|
||||
|
||||
}
|
||||
|
||||
|
||||
float Color::gray() const {
|
||||
|
||||
return (r+g+b)/3.0;
|
||||
}
|
||||
|
||||
Color::operator String() const {
|
||||
|
||||
return rtos(r)+", "+rtos(g)+", "+rtos(b)+", "+rtos(a);
|
||||
}
|
||||
|
||||
|
136
core/color.h
Normal file
136
core/color.h
Normal file
@ -0,0 +1,136 @@
|
||||
/*************************************************************************/
|
||||
/* color.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 COLOR_H
|
||||
#define COLOR_H
|
||||
|
||||
#include "ustring.h"
|
||||
/**
|
||||
@author Juan Linietsky <reduzio@gmail.com>
|
||||
*/
|
||||
struct Color {
|
||||
|
||||
union {
|
||||
|
||||
struct {
|
||||
float r;
|
||||
float g;
|
||||
float b;
|
||||
float a;
|
||||
};
|
||||
float components[4];
|
||||
};
|
||||
|
||||
bool operator==(const Color &p_color) const { return (r==p_color.r && g==p_color.g && b==p_color.b && a==p_color.a ); }
|
||||
bool operator!=(const Color &p_color) const { return (r!=p_color.r || g!=p_color.g || b!=p_color.b || a!=p_color.a ); }
|
||||
|
||||
uint32_t to_32() const;
|
||||
uint32_t to_ARGB32() const;
|
||||
float gray() const;
|
||||
float get_h() const;
|
||||
float get_s() const;
|
||||
float get_v() const;
|
||||
void set_hsv(float p_h, float p_s, float p_v, float p_alpha=1.0);
|
||||
|
||||
_FORCE_INLINE_ float& operator[](int idx) {
|
||||
return components[idx];
|
||||
}
|
||||
_FORCE_INLINE_ const float& operator[](int idx) const {
|
||||
return components[idx];
|
||||
}
|
||||
|
||||
void invert();
|
||||
void contrast();
|
||||
Color inverted() const;
|
||||
Color contrasted() const;
|
||||
|
||||
_FORCE_INLINE_ Color linear_interpolate(const Color& p_b, float p_t) const {
|
||||
|
||||
Color res=*this;
|
||||
|
||||
res.r+= (p_t * (p_b.r-r));
|
||||
res.g+= (p_t * (p_b.g-g));
|
||||
res.b+= (p_t * (p_b.b-b));
|
||||
res.a+= (p_t * (p_b.a-a));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Color blend(const Color& p_over) const {
|
||||
|
||||
|
||||
Color res;
|
||||
float sa = 1.0 - p_over.a;
|
||||
res.a = a*sa+p_over.a;
|
||||
if (res.a==0) {
|
||||
return Color(0,0,0,0);
|
||||
} else {
|
||||
res.r = (r*a*sa + p_over.r * p_over.a)/res.a;
|
||||
res.g = (g*a*sa + p_over.g * p_over.a)/res.a;
|
||||
res.b = (b*a*sa + p_over.b * p_over.a)/res.a;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static Color hex(uint32_t p_hex);
|
||||
static Color html(const String& p_color);
|
||||
static bool html_is_valid(const String& p_color);
|
||||
String to_html(bool p_alpha=true) const;
|
||||
|
||||
_FORCE_INLINE_ bool operator<(const Color& p_color) const; //used in set keys
|
||||
operator String() const;
|
||||
|
||||
/**
|
||||
* No construct parameters, r=0, g=0, b=0. a=255
|
||||
*/
|
||||
_FORCE_INLINE_ Color() {
|
||||
r=0; g=0; b=0; a=1.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB / RGBA construct parameters. Alpha is optional, but defaults to 1.0
|
||||
*/
|
||||
_FORCE_INLINE_ Color(float p_r,float p_g,float p_b,float p_a=1.0) { r=p_r; g=p_g; b=p_b; a=p_a; }
|
||||
};
|
||||
|
||||
bool Color::operator<(const Color& p_color) const {
|
||||
|
||||
if (r==p_color.r) {
|
||||
if (g==p_color.g) {
|
||||
if(b==p_color.b) {
|
||||
return (a<p_color.a);
|
||||
} else
|
||||
return (b<p_color.b);
|
||||
} else
|
||||
return g<p_color.g;
|
||||
} else
|
||||
return r<p_color.r;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
107
core/command_queue_mt.cpp
Normal file
107
core/command_queue_mt.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
/*************************************************************************/
|
||||
/* command_queue_mt.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "command_queue_mt.h"
|
||||
#include "os/os.h"
|
||||
|
||||
void CommandQueueMT::lock() {
|
||||
|
||||
if (mutex)
|
||||
mutex->lock();
|
||||
}
|
||||
|
||||
void CommandQueueMT::unlock() {
|
||||
|
||||
if (mutex)
|
||||
mutex->unlock();
|
||||
}
|
||||
|
||||
void CommandQueueMT::wait_for_flush() {
|
||||
|
||||
// wait one millisecond for a flush to happen
|
||||
OS::get_singleton()->delay_usec(1000);
|
||||
}
|
||||
|
||||
CommandQueueMT::SyncSemaphore* CommandQueueMT::_alloc_sync_sem() {
|
||||
|
||||
int idx=-1;
|
||||
|
||||
while(true) {
|
||||
|
||||
for(int i=0;i<SYNC_SEMAPHORES;i++) {
|
||||
|
||||
if (!sync_sems[i].in_use) {
|
||||
sync_sems[i].in_use=true;
|
||||
idx=i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (idx==-1) {
|
||||
wait_for_flush();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return &sync_sems[idx];
|
||||
}
|
||||
|
||||
|
||||
CommandQueueMT::CommandQueueMT(bool p_sync){
|
||||
|
||||
read_ptr=0;
|
||||
write_ptr=0;
|
||||
mutex = Mutex::create();
|
||||
|
||||
for(int i=0;i<SYNC_SEMAPHORES;i++) {
|
||||
|
||||
sync_sems[i].sem=Semaphore::create();
|
||||
sync_sems[i].in_use=false;
|
||||
|
||||
|
||||
}
|
||||
if (p_sync)
|
||||
sync = Semaphore::create();
|
||||
else
|
||||
sync=NULL;
|
||||
}
|
||||
|
||||
|
||||
CommandQueueMT::~CommandQueueMT() {
|
||||
|
||||
if (sync)
|
||||
memdelete(sync);
|
||||
memdelete(mutex);
|
||||
for(int i=0;i<SYNC_SEMAPHORES;i++) {
|
||||
|
||||
memdelete(sync_sems[i].sem);
|
||||
}
|
||||
}
|
||||
|
||||
|
999
core/command_queue_mt.h
Normal file
999
core/command_queue_mt.h
Normal file
@ -0,0 +1,999 @@
|
||||
/*************************************************************************/
|
||||
/* command_queue_mt.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 COMMAND_QUEUE_MT_H
|
||||
#define COMMAND_QUEUE_MT_H
|
||||
|
||||
#include "typedefs.h"
|
||||
#include "os/semaphore.h"
|
||||
#include "os/mutex.h"
|
||||
#include "os/memory.h"
|
||||
#include "simple_type.h"
|
||||
/**
|
||||
@author Juan Linietsky <reduzio@gmail.com>
|
||||
*/
|
||||
|
||||
class CommandQueueMT {
|
||||
|
||||
struct SyncSemaphore {
|
||||
|
||||
Semaphore *sem;
|
||||
bool in_use;
|
||||
};
|
||||
|
||||
struct CommandBase {
|
||||
|
||||
virtual void call()=0;
|
||||
virtual ~CommandBase() {};
|
||||
};
|
||||
|
||||
template<class T,class M>
|
||||
struct Command0 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
|
||||
virtual void call() { (instance->*method)(); }
|
||||
};
|
||||
|
||||
template<class T,class M,class P1>
|
||||
struct Command1 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
typename GetSimpleTypeT<P1>::type_t p1;
|
||||
|
||||
virtual void call() { (instance->*method)(p1); }
|
||||
};
|
||||
|
||||
template<class T,class M,class P1,class P2>
|
||||
struct Command2 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
typename GetSimpleTypeT<P1>::type_t p1;
|
||||
typename GetSimpleTypeT<P2>::type_t p2;
|
||||
|
||||
virtual void call() { (instance->*method)(p1,p2); }
|
||||
};
|
||||
|
||||
template<class T,class M,class P1,class P2,class P3>
|
||||
struct Command3 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
typename GetSimpleTypeT<P1>::type_t p1;
|
||||
typename GetSimpleTypeT<P2>::type_t p2;
|
||||
typename GetSimpleTypeT<P3>::type_t p3;
|
||||
|
||||
virtual void call() { (instance->*method)(p1,p2,p3); }
|
||||
};
|
||||
|
||||
template<class T,class M,class P1,class P2,class P3,class P4>
|
||||
struct Command4 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
typename GetSimpleTypeT<P1>::type_t p1;
|
||||
typename GetSimpleTypeT<P2>::type_t p2;
|
||||
typename GetSimpleTypeT<P3>::type_t p3;
|
||||
typename GetSimpleTypeT<P4>::type_t p4;
|
||||
|
||||
virtual void call() { (instance->*method)(p1,p2,p3,p4); }
|
||||
};
|
||||
|
||||
template<class T,class M,class P1,class P2,class P3,class P4,class P5>
|
||||
struct Command5 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
typename GetSimpleTypeT<P1>::type_t p1;
|
||||
typename GetSimpleTypeT<P2>::type_t p2;
|
||||
typename GetSimpleTypeT<P3>::type_t p3;
|
||||
typename GetSimpleTypeT<P4>::type_t p4;
|
||||
typename GetSimpleTypeT<P5>::type_t p5;
|
||||
|
||||
virtual void call() { (instance->*method)(p1,p2,p3,p4,p5); }
|
||||
};
|
||||
|
||||
template<class T,class M,class P1,class P2,class P3,class P4,class P5,class P6>
|
||||
struct Command6 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
typename GetSimpleTypeT<P1>::type_t p1;
|
||||
typename GetSimpleTypeT<P2>::type_t p2;
|
||||
typename GetSimpleTypeT<P3>::type_t p3;
|
||||
typename GetSimpleTypeT<P4>::type_t p4;
|
||||
typename GetSimpleTypeT<P5>::type_t p5;
|
||||
typename GetSimpleTypeT<P6>::type_t p6;
|
||||
|
||||
virtual void call() { (instance->*method)(p1,p2,p3,p4,p5,p6); }
|
||||
};
|
||||
|
||||
template<class T,class M,class P1,class P2,class P3,class P4,class P5,class P6,class P7>
|
||||
struct Command7 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
typename GetSimpleTypeT<P1>::type_t p1;
|
||||
typename GetSimpleTypeT<P2>::type_t p2;
|
||||
typename GetSimpleTypeT<P3>::type_t p3;
|
||||
typename GetSimpleTypeT<P4>::type_t p4;
|
||||
typename GetSimpleTypeT<P5>::type_t p5;
|
||||
typename GetSimpleTypeT<P6>::type_t p6;
|
||||
typename GetSimpleTypeT<P7>::type_t p7;
|
||||
|
||||
virtual void call() { (instance->*method)(p1,p2,p3,p4,p5,p6,p7); }
|
||||
};
|
||||
|
||||
/* comands that return */
|
||||
|
||||
template<class T,class M,class R>
|
||||
struct CommandRet0 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
R* ret;
|
||||
SyncSemaphore *sync;
|
||||
|
||||
virtual void call() { *ret = (instance->*method)(); sync->sem->post(); sync->in_use=false; ; }
|
||||
};
|
||||
|
||||
template<class T,class M,class P1,class R>
|
||||
struct CommandRet1 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
typename GetSimpleTypeT<P1>::type_t p1;
|
||||
R* ret;
|
||||
SyncSemaphore *sync;
|
||||
|
||||
virtual void call() { *ret = (instance->*method)(p1); sync->sem->post(); sync->in_use=false; ; }
|
||||
};
|
||||
|
||||
template<class T,class M,class P1,class P2,class R>
|
||||
struct CommandRet2 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
typename GetSimpleTypeT<P1>::type_t p1;
|
||||
typename GetSimpleTypeT<P2>::type_t p2;
|
||||
R* ret;
|
||||
SyncSemaphore *sync;
|
||||
|
||||
virtual void call() { *ret = (instance->*method)(p1,p2); sync->sem->post(); sync->in_use=false; ; }
|
||||
};
|
||||
|
||||
template<class T,class M,class P1,class P2,class P3,class R>
|
||||
struct CommandRet3 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
typename GetSimpleTypeT<P1>::type_t p1;
|
||||
typename GetSimpleTypeT<P2>::type_t p2;
|
||||
typename GetSimpleTypeT<P3>::type_t p3;
|
||||
R* ret;
|
||||
SyncSemaphore *sync;
|
||||
|
||||
virtual void call() { *ret = (instance->*method)(p1,p2,p3); sync->sem->post(); sync->in_use=false; ; }
|
||||
};
|
||||
|
||||
template<class T,class M,class P1,class P2,class P3,class P4,class R>
|
||||
struct CommandRet4 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
typename GetSimpleTypeT<P1>::type_t p1;
|
||||
typename GetSimpleTypeT<P2>::type_t p2;
|
||||
typename GetSimpleTypeT<P3>::type_t p3;
|
||||
typename GetSimpleTypeT<P4>::type_t p4;
|
||||
R* ret;
|
||||
SyncSemaphore *sync;
|
||||
|
||||
virtual void call() { *ret = (instance->*method)(p1,p2,p3,p4); sync->sem->post(); sync->in_use=false; ; }
|
||||
};
|
||||
|
||||
template<class T,class M,class P1,class P2,class P3,class P4,class P5,class R>
|
||||
struct CommandRet5 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
typename GetSimpleTypeT<P1>::type_t p1;
|
||||
typename GetSimpleTypeT<P2>::type_t p2;
|
||||
typename GetSimpleTypeT<P3>::type_t p3;
|
||||
typename GetSimpleTypeT<P4>::type_t p4;
|
||||
typename GetSimpleTypeT<P5>::type_t p5;
|
||||
R* ret;
|
||||
SyncSemaphore *sync;
|
||||
|
||||
virtual void call() { *ret = (instance->*method)(p1,p2,p3,p4,p5); sync->sem->post(); sync->in_use=false; ; }
|
||||
};
|
||||
|
||||
template<class T,class M,class P1,class P2,class P3,class P4,class P5,class P6,class R>
|
||||
struct CommandRet6 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
typename GetSimpleTypeT<P1>::type_t p1;
|
||||
typename GetSimpleTypeT<P2>::type_t p2;
|
||||
typename GetSimpleTypeT<P3>::type_t p3;
|
||||
typename GetSimpleTypeT<P4>::type_t p4;
|
||||
typename GetSimpleTypeT<P5>::type_t p5;
|
||||
typename GetSimpleTypeT<P6>::type_t p6;
|
||||
R* ret;
|
||||
SyncSemaphore *sync;
|
||||
|
||||
virtual void call() { *ret = (instance->*method)(p1,p2,p3,p4,p5,p6); sync->sem->post(); sync->in_use=false; ; }
|
||||
};
|
||||
|
||||
template<class T,class M,class P1,class P2,class P3,class P4,class P5,class P6,class P7,class R>
|
||||
struct CommandRet7 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
typename GetSimpleTypeT<P1>::type_t p1;
|
||||
typename GetSimpleTypeT<P2>::type_t p2;
|
||||
typename GetSimpleTypeT<P3>::type_t p3;
|
||||
typename GetSimpleTypeT<P4>::type_t p4;
|
||||
typename GetSimpleTypeT<P5>::type_t p5;
|
||||
typename GetSimpleTypeT<P6>::type_t p6;
|
||||
typename GetSimpleTypeT<P7>::type_t p7;
|
||||
R* ret;
|
||||
SyncSemaphore *sync;
|
||||
|
||||
virtual void call() { *ret = (instance->*method)(p1,p2,p3,p4,p5,p6,p7); sync->sem->post(); sync->in_use=false; ; }
|
||||
};
|
||||
|
||||
/** commands that don't return but sync */
|
||||
|
||||
/* comands that return */
|
||||
|
||||
template<class T,class M>
|
||||
struct CommandSync0 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
|
||||
SyncSemaphore *sync;
|
||||
|
||||
virtual void call() { (instance->*method)(); sync->sem->post(); sync->in_use=false; ; }
|
||||
};
|
||||
|
||||
template<class T,class M,class P1>
|
||||
struct CommandSync1 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
typename GetSimpleTypeT<P1>::type_t p1;
|
||||
|
||||
SyncSemaphore *sync;
|
||||
|
||||
virtual void call() { (instance->*method)(p1); sync->sem->post(); sync->in_use=false; ; }
|
||||
};
|
||||
|
||||
template<class T,class M,class P1,class P2>
|
||||
struct CommandSync2 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
typename GetSimpleTypeT<P1>::type_t p1;
|
||||
typename GetSimpleTypeT<P2>::type_t p2;
|
||||
|
||||
SyncSemaphore *sync;
|
||||
|
||||
virtual void call() { (instance->*method)(p1,p2); sync->sem->post(); sync->in_use=false; ; }
|
||||
};
|
||||
|
||||
template<class T,class M,class P1,class P2,class P3>
|
||||
struct CommandSync3 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
typename GetSimpleTypeT<P1>::type_t p1;
|
||||
typename GetSimpleTypeT<P2>::type_t p2;
|
||||
typename GetSimpleTypeT<P3>::type_t p3;
|
||||
|
||||
SyncSemaphore *sync;
|
||||
|
||||
virtual void call() { (instance->*method)(p1,p2,p3); sync->sem->post(); sync->in_use=false; ; }
|
||||
};
|
||||
|
||||
template<class T,class M,class P1,class P2,class P3,class P4>
|
||||
struct CommandSync4 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
typename GetSimpleTypeT<P1>::type_t p1;
|
||||
typename GetSimpleTypeT<P2>::type_t p2;
|
||||
typename GetSimpleTypeT<P3>::type_t p3;
|
||||
typename GetSimpleTypeT<P4>::type_t p4;
|
||||
|
||||
SyncSemaphore *sync;
|
||||
|
||||
virtual void call() { (instance->*method)(p1,p2,p3,p4); sync->sem->post(); sync->in_use=false; ; }
|
||||
};
|
||||
|
||||
template<class T,class M,class P1,class P2,class P3,class P4,class P5>
|
||||
struct CommandSync5 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
typename GetSimpleTypeT<P1>::type_t p1;
|
||||
typename GetSimpleTypeT<P2>::type_t p2;
|
||||
typename GetSimpleTypeT<P3>::type_t p3;
|
||||
typename GetSimpleTypeT<P4>::type_t p4;
|
||||
typename GetSimpleTypeT<P5>::type_t p5;
|
||||
|
||||
SyncSemaphore *sync;
|
||||
|
||||
virtual void call() { (instance->*method)(p1,p2,p3,p4,p5); sync->sem->post(); sync->in_use=false; ; }
|
||||
};
|
||||
|
||||
template<class T,class M,class P1,class P2,class P3,class P4,class P5,class P6>
|
||||
struct CommandSync6 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
typename GetSimpleTypeT<P1>::type_t p1;
|
||||
typename GetSimpleTypeT<P2>::type_t p2;
|
||||
typename GetSimpleTypeT<P3>::type_t p3;
|
||||
typename GetSimpleTypeT<P4>::type_t p4;
|
||||
typename GetSimpleTypeT<P5>::type_t p5;
|
||||
typename GetSimpleTypeT<P6>::type_t p6;
|
||||
|
||||
SyncSemaphore *sync;
|
||||
|
||||
virtual void call() { (instance->*method)(p1,p2,p3,p4,p5,p6); sync->sem->post(); sync->in_use=false; ; }
|
||||
};
|
||||
|
||||
template<class T,class M,class P1,class P2,class P3,class P4,class P5,class P6,class P7>
|
||||
struct CommandSync7 : public CommandBase {
|
||||
|
||||
T*instance;
|
||||
M method;
|
||||
typename GetSimpleTypeT<P1>::type_t p1;
|
||||
typename GetSimpleTypeT<P2>::type_t p2;
|
||||
typename GetSimpleTypeT<P3>::type_t p3;
|
||||
typename GetSimpleTypeT<P4>::type_t p4;
|
||||
typename GetSimpleTypeT<P5>::type_t p5;
|
||||
typename GetSimpleTypeT<P6>::type_t p6;
|
||||
typename GetSimpleTypeT<P7>::type_t p7;
|
||||
|
||||
SyncSemaphore *sync;
|
||||
|
||||
virtual void call() { (instance->*method)(p1,p2,p3,p4,p5,p6,p7); sync->sem->post(); sync->in_use=false; ; }
|
||||
};
|
||||
|
||||
/***** BASE *******/
|
||||
|
||||
enum {
|
||||
COMMAND_MEM_SIZE_KB=256,
|
||||
COMMAND_MEM_SIZE=COMMAND_MEM_SIZE_KB*1024,
|
||||
SYNC_SEMAPHORES=8
|
||||
};
|
||||
|
||||
|
||||
uint8_t command_mem[COMMAND_MEM_SIZE];
|
||||
uint32_t read_ptr;
|
||||
uint32_t write_ptr;
|
||||
SyncSemaphore sync_sems[SYNC_SEMAPHORES];
|
||||
Mutex *mutex;
|
||||
Semaphore *sync;
|
||||
|
||||
|
||||
template<class T>
|
||||
T* allocate() {
|
||||
|
||||
// alloc size is size+T+safeguard
|
||||
uint32_t alloc_size=sizeof(T)+sizeof(uint32_t);
|
||||
|
||||
tryagain:
|
||||
|
||||
if (write_ptr < read_ptr) {
|
||||
// behind read_ptr, check that there is room
|
||||
if ( (read_ptr-write_ptr) <= alloc_size )
|
||||
return NULL;
|
||||
} else if (write_ptr >= read_ptr) {
|
||||
// ahead of read_ptr, check that there is room
|
||||
|
||||
|
||||
if ( (COMMAND_MEM_SIZE-write_ptr) < alloc_size+4 ) {
|
||||
// no room at the end, wrap down;
|
||||
|
||||
if (read_ptr==0) // dont want write_ptr to become read_ptr
|
||||
return NULL;
|
||||
|
||||
// if this happens, it's a bug
|
||||
ERR_FAIL_COND_V( (COMMAND_MEM_SIZE-write_ptr) < sizeof(uint32_t), NULL );
|
||||
// zero means, wrap to begining
|
||||
|
||||
uint32_t * p = (uint32_t*)&command_mem[write_ptr];
|
||||
*p=0;
|
||||
write_ptr=0;
|
||||
goto tryagain;
|
||||
}
|
||||
}
|
||||
// allocate the size
|
||||
uint32_t * p = (uint32_t*)&command_mem[write_ptr];
|
||||
*p=sizeof(T);
|
||||
write_ptr+=sizeof(uint32_t);
|
||||
// allocate the command
|
||||
T* cmd = memnew_placement( &command_mem[write_ptr], T );
|
||||
write_ptr+=sizeof(T);
|
||||
return cmd;
|
||||
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T* allocate_and_lock() {
|
||||
|
||||
lock();
|
||||
T* ret;
|
||||
|
||||
while ( (ret=allocate<T>())==NULL ) {
|
||||
|
||||
unlock();
|
||||
// sleep a little until fetch happened and some room is made
|
||||
wait_for_flush();
|
||||
lock();
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool flush_one() {
|
||||
|
||||
tryagain:
|
||||
|
||||
// tried to read an empty queue
|
||||
if (read_ptr == write_ptr )
|
||||
return false;
|
||||
|
||||
uint32_t size = *(uint32_t*)( &command_mem[read_ptr] );
|
||||
|
||||
if (size==0) {
|
||||
//end of ringbuffer, wrap
|
||||
read_ptr=0;
|
||||
goto tryagain;
|
||||
}
|
||||
|
||||
read_ptr+=sizeof(uint32_t);
|
||||
|
||||
CommandBase *cmd = reinterpret_cast<CommandBase*>( &command_mem[read_ptr] );
|
||||
|
||||
cmd->call();
|
||||
cmd->~CommandBase();
|
||||
|
||||
read_ptr+=size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void lock();
|
||||
void unlock();
|
||||
void wait_for_flush();
|
||||
SyncSemaphore* _alloc_sync_sem();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/* NORMAL PUSH COMMANDS */
|
||||
|
||||
template<class T, class M>
|
||||
void push( T * p_instance, M p_method ) {
|
||||
|
||||
Command0<T,M> * cmd = allocate_and_lock< Command0<T,M> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
}
|
||||
|
||||
template<class T, class M, class P1>
|
||||
void push( T * p_instance, M p_method, P1 p1 ) {
|
||||
|
||||
Command1<T,M,P1> * cmd = allocate_and_lock< Command1<T,M,P1> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
cmd->p1=p1;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
}
|
||||
|
||||
template<class T, class M, class P1, class P2>
|
||||
void push( T * p_instance, M p_method, P1 p1, P2 p2 ) {
|
||||
|
||||
Command2<T,M,P1,P2> * cmd = allocate_and_lock< Command2<T,M,P1,P2> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
cmd->p1=p1;
|
||||
cmd->p2=p2;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
}
|
||||
|
||||
template<class T, class M, class P1, class P2, class P3>
|
||||
void push( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3 ) {
|
||||
|
||||
Command3<T,M,P1,P2,P3> * cmd = allocate_and_lock< Command3<T,M,P1,P2,P3> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
cmd->p1=p1;
|
||||
cmd->p2=p2;
|
||||
cmd->p3=p3;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
}
|
||||
|
||||
template<class T, class M, class P1, class P2, class P3, class P4>
|
||||
void push( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4 ) {
|
||||
|
||||
Command4<T,M,P1,P2,P3,P4> * cmd = allocate_and_lock< Command4<T,M,P1,P2,P3,P4> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
cmd->p1=p1;
|
||||
cmd->p2=p2;
|
||||
cmd->p3=p3;
|
||||
cmd->p4=p4;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
}
|
||||
|
||||
template<class T, class M, class P1, class P2, class P3, class P4, class P5>
|
||||
void push( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5 ) {
|
||||
|
||||
Command5<T,M,P1,P2,P3,P4,P5> * cmd = allocate_and_lock< Command5<T,M,P1,P2,P3,P4,P5> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
cmd->p1=p1;
|
||||
cmd->p2=p2;
|
||||
cmd->p3=p3;
|
||||
cmd->p4=p4;
|
||||
cmd->p5=p5;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
}
|
||||
|
||||
template<class T, class M, class P1, class P2, class P3, class P4, class P5, class P6>
|
||||
void push( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6 ) {
|
||||
|
||||
Command6<T,M,P1,P2,P3,P4,P5,P6> * cmd = allocate_and_lock< Command6<T,M,P1,P2,P3,P4,P5,P6> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
cmd->p1=p1;
|
||||
cmd->p2=p2;
|
||||
cmd->p3=p3;
|
||||
cmd->p4=p4;
|
||||
cmd->p5=p5;
|
||||
cmd->p6=p6;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
}
|
||||
|
||||
template<class T, class M, class P1, class P2, class P3, class P4, class P5, class P6, class P7>
|
||||
void push( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7 ) {
|
||||
|
||||
Command7<T,M,P1,P2,P3,P4,P5,P6,P7> * cmd = allocate_and_lock< Command7<T,M,P1,P2,P3,P4,P5,P6,P7> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
cmd->p1=p1;
|
||||
cmd->p2=p2;
|
||||
cmd->p3=p3;
|
||||
cmd->p4=p4;
|
||||
cmd->p5=p5;
|
||||
cmd->p6=p6;
|
||||
cmd->p7=p7;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
}
|
||||
/*** PUSH AND RET COMMANDS ***/
|
||||
|
||||
|
||||
template<class T, class M,class R>
|
||||
void push_and_ret( T * p_instance, M p_method, R* r_ret) {
|
||||
|
||||
CommandRet0<T,M,R> * cmd = allocate_and_lock< CommandRet0<T,M,R> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
cmd->ret=r_ret;
|
||||
SyncSemaphore *ss=_alloc_sync_sem();
|
||||
cmd->sync=ss;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
ss->sem->wait();
|
||||
}
|
||||
|
||||
template<class T, class M, class P1,class R>
|
||||
void push_and_ret( T * p_instance, M p_method, P1 p1, R* r_ret) {
|
||||
|
||||
CommandRet1<T,M,P1,R> * cmd = allocate_and_lock< CommandRet1<T,M,P1,R> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
cmd->p1=p1;
|
||||
cmd->ret=r_ret;
|
||||
SyncSemaphore *ss=_alloc_sync_sem();
|
||||
cmd->sync=ss;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
ss->sem->wait();
|
||||
}
|
||||
|
||||
template<class T, class M, class P1, class P2,class R>
|
||||
void push_and_ret( T * p_instance, M p_method, P1 p1, P2 p2, R* r_ret) {
|
||||
|
||||
CommandRet2<T,M,P1,P2,R> * cmd = allocate_and_lock< CommandRet2<T,M,P1,P2,R> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
cmd->p1=p1;
|
||||
cmd->p2=p2;
|
||||
cmd->ret=r_ret;
|
||||
SyncSemaphore *ss=_alloc_sync_sem();
|
||||
cmd->sync=ss;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
ss->sem->wait();
|
||||
}
|
||||
|
||||
template<class T, class M, class P1, class P2, class P3,class R>
|
||||
void push_and_ret( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, R* r_ret ) {
|
||||
|
||||
CommandRet3<T,M,P1,P2,P3,R> * cmd = allocate_and_lock< CommandRet3<T,M,P1,P2,P3,R> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
cmd->p1=p1;
|
||||
cmd->p2=p2;
|
||||
cmd->p3=p3;
|
||||
cmd->ret=r_ret;
|
||||
SyncSemaphore *ss=_alloc_sync_sem();
|
||||
cmd->sync=ss;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
ss->sem->wait();
|
||||
}
|
||||
|
||||
template<class T, class M, class P1, class P2, class P3, class P4,class R>
|
||||
void push_and_ret( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4, R* r_ret ) {
|
||||
|
||||
CommandRet4<T,M,P1,P2,P3,P4,R> * cmd = allocate_and_lock< CommandRet4<T,M,P1,P2,P3,P4,R> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
cmd->p1=p1;
|
||||
cmd->p2=p2;
|
||||
cmd->p3=p3;
|
||||
cmd->p4=p4;
|
||||
cmd->ret=r_ret;
|
||||
SyncSemaphore *ss=_alloc_sync_sem();
|
||||
cmd->sync=ss;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
ss->sem->wait();
|
||||
}
|
||||
|
||||
template<class T, class M, class P1, class P2, class P3, class P4, class P5,class R>
|
||||
void push_and_ret( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, R* r_ret ) {
|
||||
|
||||
CommandRet5<T,M,P1,P2,P3,P4,P5,R> * cmd = allocate_and_lock< CommandRet5<T,M,P1,P2,P3,P4,P5,R> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
cmd->p1=p1;
|
||||
cmd->p2=p2;
|
||||
cmd->p3=p3;
|
||||
cmd->p4=p4;
|
||||
cmd->p5=p5;
|
||||
cmd->ret=r_ret;
|
||||
SyncSemaphore *ss=_alloc_sync_sem();
|
||||
cmd->sync=ss;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
ss->sem->wait();
|
||||
}
|
||||
|
||||
template<class T, class M, class P1, class P2, class P3, class P4, class P5, class P6,class R>
|
||||
void push_and_ret( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, R* r_ret ) {
|
||||
|
||||
CommandRet6<T,M,P1,P2,P3,P4,P5,P6,R> * cmd = allocate_and_lock< CommandRet6<T,M,P1,P2,P3,P4,P5,P6,R> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
cmd->p1=p1;
|
||||
cmd->p2=p2;
|
||||
cmd->p3=p3;
|
||||
cmd->p4=p4;
|
||||
cmd->p5=p5;
|
||||
cmd->p6=p6;
|
||||
cmd->ret=r_ret;
|
||||
SyncSemaphore *ss=_alloc_sync_sem();
|
||||
cmd->sync=ss;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
ss->sem->wait();
|
||||
}
|
||||
|
||||
template<class T, class M, class P1, class P2, class P3, class P4, class P5, class P6,class P7,class R>
|
||||
void push_and_ret( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6,P7 p7, R* r_ret ) {
|
||||
|
||||
CommandRet7<T,M,P1,P2,P3,P4,P5,P6,P7,R> * cmd = allocate_and_lock< CommandRet7<T,M,P1,P2,P3,P4,P5,P6,P7,R> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
cmd->p1=p1;
|
||||
cmd->p2=p2;
|
||||
cmd->p3=p3;
|
||||
cmd->p4=p4;
|
||||
cmd->p5=p5;
|
||||
cmd->p6=p6;
|
||||
cmd->p7=p7;
|
||||
cmd->ret=r_ret;
|
||||
SyncSemaphore *ss=_alloc_sync_sem();
|
||||
cmd->sync=ss;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
ss->sem->wait();
|
||||
}
|
||||
|
||||
|
||||
template<class T, class M>
|
||||
void push_and_sync( T * p_instance, M p_method) {
|
||||
|
||||
CommandSync0<T,M> * cmd = allocate_and_lock< CommandSync0<T,M> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
|
||||
SyncSemaphore *ss=_alloc_sync_sem();
|
||||
cmd->sync=ss;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
ss->sem->wait();
|
||||
}
|
||||
|
||||
template<class T, class M, class P1>
|
||||
void push_and_sync( T * p_instance, M p_method, P1 p1) {
|
||||
|
||||
CommandSync1<T,M,P1> * cmd = allocate_and_lock< CommandSync1<T,M,P1> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
cmd->p1=p1;
|
||||
|
||||
SyncSemaphore *ss=_alloc_sync_sem();
|
||||
cmd->sync=ss;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
ss->sem->wait();
|
||||
}
|
||||
|
||||
template<class T, class M, class P1, class P2>
|
||||
void push_and_sync( T * p_instance, M p_method, P1 p1, P2 p2) {
|
||||
|
||||
CommandSync2<T,M,P1,P2> * cmd = allocate_and_lock< CommandSync2<T,M,P1,P2> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
cmd->p1=p1;
|
||||
cmd->p2=p2;
|
||||
|
||||
SyncSemaphore *ss=_alloc_sync_sem();
|
||||
cmd->sync=ss;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
ss->sem->wait();
|
||||
}
|
||||
|
||||
template<class T, class M, class P1, class P2, class P3>
|
||||
void push_and_sync( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3 ) {
|
||||
|
||||
CommandSync3<T,M,P1,P2,P3> * cmd = allocate_and_lock< CommandSync3<T,M,P1,P2,P3> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
cmd->p1=p1;
|
||||
cmd->p2=p2;
|
||||
cmd->p3=p3;
|
||||
|
||||
SyncSemaphore *ss=_alloc_sync_sem();
|
||||
cmd->sync=ss;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
ss->sem->wait();
|
||||
}
|
||||
|
||||
template<class T, class M, class P1, class P2, class P3, class P4>
|
||||
void push_and_sync( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4 ) {
|
||||
|
||||
CommandSync4<T,M,P1,P2,P3,P4> * cmd = allocate_and_lock< CommandSync4<T,M,P1,P2,P3,P4> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
cmd->p1=p1;
|
||||
cmd->p2=p2;
|
||||
cmd->p3=p3;
|
||||
cmd->p4=p4;
|
||||
|
||||
SyncSemaphore *ss=_alloc_sync_sem();
|
||||
cmd->sync=ss;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
ss->sem->wait();
|
||||
}
|
||||
|
||||
template<class T, class M, class P1, class P2, class P3, class P4, class P5>
|
||||
void push_and_sync( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5 ) {
|
||||
|
||||
CommandSync5<T,M,P1,P2,P3,P4,P5> * cmd = allocate_and_lock< CommandSync5<T,M,P1,P2,P3,P4,P5> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
cmd->p1=p1;
|
||||
cmd->p2=p2;
|
||||
cmd->p3=p3;
|
||||
cmd->p4=p4;
|
||||
cmd->p5=p5;
|
||||
|
||||
SyncSemaphore *ss=_alloc_sync_sem();
|
||||
cmd->sync=ss;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
ss->sem->wait();
|
||||
}
|
||||
|
||||
template<class T, class M, class P1, class P2, class P3, class P4, class P5, class P6>
|
||||
void push_and_sync( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6 ) {
|
||||
|
||||
CommandSync6<T,M,P1,P2,P3,P4,P5,P6> * cmd = allocate_and_lock< CommandSync6<T,M,P1,P2,P3,P4,P5,P6> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
cmd->p1=p1;
|
||||
cmd->p2=p2;
|
||||
cmd->p3=p3;
|
||||
cmd->p4=p4;
|
||||
cmd->p5=p5;
|
||||
cmd->p6=p6;
|
||||
|
||||
SyncSemaphore *ss=_alloc_sync_sem();
|
||||
cmd->sync=ss;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
ss->sem->wait();
|
||||
}
|
||||
|
||||
template<class T, class M, class P1, class P2, class P3, class P4, class P5, class P6,class P7>
|
||||
void push_and_sync( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6,P7 p7 ) {
|
||||
|
||||
CommandSync7<T,M,P1,P2,P3,P4,P5,P6,P7> * cmd = allocate_and_lock< CommandSync7<T,M,P1,P2,P3,P4,P5,P6,P7> >();
|
||||
|
||||
cmd->instance=p_instance;
|
||||
cmd->method=p_method;
|
||||
cmd->p1=p1;
|
||||
cmd->p2=p2;
|
||||
cmd->p3=p3;
|
||||
cmd->p4=p4;
|
||||
cmd->p5=p5;
|
||||
cmd->p6=p6;
|
||||
cmd->p7=p7;
|
||||
|
||||
SyncSemaphore *ss=_alloc_sync_sem();
|
||||
cmd->sync=ss;
|
||||
|
||||
unlock();
|
||||
|
||||
if (sync) sync->post();
|
||||
ss->sem->wait();
|
||||
}
|
||||
|
||||
void wait_and_flush_one() {
|
||||
ERR_FAIL_COND(!sync);
|
||||
sync->wait();
|
||||
lock();
|
||||
flush_one();
|
||||
unlock();
|
||||
}
|
||||
|
||||
void flush_all() {
|
||||
|
||||
ERR_FAIL_COND(sync);
|
||||
lock();
|
||||
while (true) {
|
||||
bool exit = !flush_one();
|
||||
if (exit)
|
||||
break;
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
CommandQueueMT(bool p_sync);
|
||||
~CommandQueueMT();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
534
core/compressed_translation.cpp
Normal file
534
core/compressed_translation.cpp
Normal file
@ -0,0 +1,534 @@
|
||||
/*************************************************************************/
|
||||
/* compressed_translation.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "compressed_translation.h"
|
||||
#include "pair.h"
|
||||
#include <string.h>
|
||||
|
||||
/////////// SMAZ /////////////
|
||||
|
||||
/*
|
||||
Copyright (c) 2006-2009, Salvatore Sanfilippo
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Smaz nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
/* Our compression codebook, used for compression */
|
||||
static const char *Smaz_cb[241] = {
|
||||
"\002s,\266", "\003had\232\002leW", "\003on \216", "", "\001yS",
|
||||
"\002ma\255\002li\227", "\003or \260", "", "\002ll\230\003s t\277",
|
||||
"\004fromg\002mel", "", "\003its\332", "\001z\333", "\003ingF", "\001>\336",
|
||||
"\001 \000\003 (\002nc\344", "\002nd=\003 on\312",
|
||||
"\002ne\213\003hat\276\003re q", "", "\002ngT\003herz\004have\306\003s o\225",
|
||||
"", "\003ionk\003s a\254\002ly\352", "\003hisL\003 inN\003 be\252", "",
|
||||
"\003 fo\325\003 of \003 ha\311", "", "\002of\005",
|
||||
"\003 co\241\002no\267\003 ma\370", "", "", "\003 cl\356\003enta\003 an7",
|
||||
"\002ns\300\001\"e", "\003n t\217\002ntP\003s, \205",
|
||||
"\002pe\320\003 we\351\002om\223", "\002on\037", "", "\002y G", "\003 wa\271",
|
||||
"\003 re\321\002or*", "", "\002=\"\251\002ot\337", "\003forD\002ou[",
|
||||
"\003 toR", "\003 th\r", "\003 it\366",
|
||||
"\003but\261\002ra\202\003 wi\363\002</\361", "\003 wh\237", "\002 4",
|
||||
"\003nd ?", "\002re!", "", "\003ng c", "",
|
||||
"\003ly \307\003ass\323\001a\004\002rir", "", "", "", "\002se_", "\003of \"",
|
||||
"\003div\364\002ros\003ere\240", "", "\002ta\310\001bZ\002si\324", "",
|
||||
"\003and\a\002rs\335", "\002rt\362", "\002teE", "\003ati\316", "\002so\263",
|
||||
"\002th\021", "\002tiJ\001c\034\003allp", "\003ate\345", "\002ss\246",
|
||||
"\002stM", "", "\002><\346", "\002to\024", "\003arew", "\001d\030",
|
||||
"\002tr\303", "", "\001\n1\003 a \222", "\003f tv\002veo", "\002un\340", "",
|
||||
"\003e o\242", "\002a \243\002wa\326\001e\002", "\002ur\226\003e a\274",
|
||||
"\002us\244\003\n\r\n\247", "\002ut\304\003e c\373", "\002we\221", "", "",
|
||||
"\002wh\302", "\001f,", "", "", "", "\003d t\206", "", "", "\003th \343",
|
||||
"\001g;", "", "", "\001\r9\003e s\265", "\003e t\234", "", "\003to Y",
|
||||
"\003e\r\n\236", "\002d \036\001h\022", "", "\001,Q", "\002 a\031", "\002 b^",
|
||||
"\002\r\n\025\002 cI", "\002 d\245", "\002 e\253", "\002 fh\001i\b\002e \v",
|
||||
"", "\002 hU\001-\314", "\002 i8", "", "", "\002 l\315", "\002 m{",
|
||||
"\002f :\002 n\354", "\002 o\035", "\002 p}\001.n\003\r\n\r\250", "",
|
||||
"\002 r\275", "\002 s>", "\002 t\016", "", "\002g \235\005which+\003whi\367",
|
||||
"\002 w5", "\001/\305", "\003as \214", "\003at \207", "", "\003who\331", "",
|
||||
"\001l\026\002h \212", "", "\002, $", "", "\004withV", "", "", "", "\001m-", "",
|
||||
"", "\002ac\357", "\002ad\350", "\003TheH", "", "", "\004this\233\001n\t",
|
||||
"", "\002. y", "", "\002alX\003e, \365", "\003tio\215\002be\\",
|
||||
"\002an\032\003ver\347", "", "\004that0\003tha\313\001o\006", "\003was2",
|
||||
"\002arO", "\002as.", "\002at'\003the\001\004they\200\005there\322\005theird",
|
||||
"\002ce\210", "\004were]", "", "\002ch\231\002l \264\001p<", "", "",
|
||||
"\003one\256", "", "\003he \023\002dej", "\003ter\270", "\002cou", "",
|
||||
"\002by\177\002di\201\002eax", "", "\002ec\327", "\002edB", "\002ee\353", "",
|
||||
"", "\001r\f\002n )", "", "", "", "\002el\262", "", "\003in i\002en3", "",
|
||||
"\002o `\001s\n", "", "\002er\033", "\003is t\002es6", "", "\002ge\371",
|
||||
"\004.com\375", "\002fo\334\003our\330", "\003ch \301\001t\003", "\002hab", "",
|
||||
"\003men\374", "", "\002he\020", "", "", "\001u&", "\002hif", "",
|
||||
"\003not\204\002ic\203", "\003ed @\002id\355", "", "", "\002ho\273",
|
||||
"\002r K\001vm", "", "", "", "\003t t\257\002il\360", "\002im\342",
|
||||
"\003en \317\002in\017", "\002io\220", "\002s \027\001wA", "", "\003er |",
|
||||
"\003es ~\002is%", "\002it/", "", "\002iv\272", "",
|
||||
"\002t #\ahttp://C\001x\372", "\002la\211", "\001<\341", "\003, a\224"
|
||||
};
|
||||
|
||||
/* Reverse compression codebook, used for decompression */
|
||||
static const char *Smaz_rcb[254] = {
|
||||
" ", "the", "e", "t", "a", "of", "o", "and", "i", "n", "s", "e ", "r", " th",
|
||||
" t", "in", "he", "th", "h", "he ", "to", "\r\n", "l", "s ", "d", " a", "an",
|
||||
"er", "c", " o", "d ", "on", " of", "re", "of ", "t ", ", ", "is", "u", "at",
|
||||
" ", "n ", "or", "which", "f", "m", "as", "it", "that", "\n", "was", "en",
|
||||
" ", " w", "es", " an", " i", "\r", "f ", "g", "p", "nd", " s", "nd ", "ed ",
|
||||
"w", "ed", "http://", "for", "te", "ing", "y ", "The", " c", "ti", "r ", "his",
|
||||
"st", " in", "ar", "nt", ",", " to", "y", "ng", " h", "with", "le", "al", "to ",
|
||||
"b", "ou", "be", "were", " b", "se", "o ", "ent", "ha", "ng ", "their", "\"",
|
||||
"hi", "from", " f", "in ", "de", "ion", "me", "v", ".", "ve", "all", "re ",
|
||||
"ri", "ro", "is ", "co", "f t", "are", "ea", ". ", "her", " m", "er ", " p",
|
||||
"es ", "by", "they", "di", "ra", "ic", "not", "s, ", "d t", "at ", "ce", "la",
|
||||
"h ", "ne", "as ", "tio", "on ", "n t", "io", "we", " a ", "om", ", a", "s o",
|
||||
"ur", "li", "ll", "ch", "had", "this", "e t", "g ", "e\r\n", " wh", "ere",
|
||||
" co", "e o", "a ", "us", " d", "ss", "\n\r\n", "\r\n\r", "=\"", " be", " e",
|
||||
"s a", "ma", "one", "t t", "or ", "but", "el", "so", "l ", "e s", "s,", "no",
|
||||
"ter", " wa", "iv", "ho", "e a", " r", "hat", "s t", "ns", "ch ", "wh", "tr",
|
||||
"ut", "/", "have", "ly ", "ta", " ha", " on", "tha", "-", " l", "ati", "en ",
|
||||
"pe", " re", "there", "ass", "si", " fo", "wa", "ec", "our", "who", "its", "z",
|
||||
"fo", "rs", ">", "ot", "un", "<", "im", "th ", "nc", "ate", "><", "ver", "ad",
|
||||
" we", "ly", "ee", " n", "id", " cl", "ac", "il", "</", "rt", " wi", "div",
|
||||
"e, ", " it", "whi", " ma", "ge", "x", "e c", "men", ".com"
|
||||
};
|
||||
|
||||
static int smaz_compress(const char *in, int inlen, char *out, int outlen) {
|
||||
unsigned int h1,h2,h3=0;
|
||||
int verblen = 0, _outlen = outlen;
|
||||
char verb[256], *_out = out;
|
||||
|
||||
while(inlen) {
|
||||
int j = 7, needed;
|
||||
char *flush = NULL;
|
||||
const char *slot;
|
||||
|
||||
h1 = h2 = in[0]<<3;
|
||||
if (inlen > 1) h2 += in[1];
|
||||
if (inlen > 2) h3 = h2^in[2];
|
||||
if (j > inlen) j = inlen;
|
||||
|
||||
/* Try to lookup substrings into the hash table, starting from the
|
||||
* longer to the shorter substrings */
|
||||
for (; j > 0; j--) {
|
||||
switch(j) {
|
||||
case 1: slot = Smaz_cb[h1%241]; break;
|
||||
case 2: slot = Smaz_cb[h2%241]; break;
|
||||
default: slot = Smaz_cb[h3%241]; break;
|
||||
}
|
||||
while(slot[0]) {
|
||||
if (slot[0] == j && memcmp(slot+1,in,j) == 0) {
|
||||
/* Match found in the hash table,
|
||||
* prepare a verbatim bytes flush if needed */
|
||||
if (verblen) {
|
||||
needed = (verblen == 1) ? 2 : 2+verblen;
|
||||
flush = out;
|
||||
out += needed;
|
||||
outlen -= needed;
|
||||
}
|
||||
/* Emit the byte */
|
||||
if (outlen <= 0) return _outlen+1;
|
||||
out[0] = slot[slot[0]+1];
|
||||
out++;
|
||||
outlen--;
|
||||
inlen -= j;
|
||||
in += j;
|
||||
goto out;
|
||||
} else {
|
||||
slot += slot[0]+2;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Match not found - add the byte to the verbatim buffer */
|
||||
verb[verblen] = in[0];
|
||||
verblen++;
|
||||
inlen--;
|
||||
in++;
|
||||
out:
|
||||
/* Prepare a flush if we reached the flush length limit, and there
|
||||
* is not already a pending flush operation. */
|
||||
if (!flush && (verblen == 256 || (verblen > 0 && inlen == 0))) {
|
||||
needed = (verblen == 1) ? 2 : 2+verblen;
|
||||
flush = out;
|
||||
out += needed;
|
||||
outlen -= needed;
|
||||
if (outlen < 0) return _outlen+1;
|
||||
}
|
||||
/* Perform a verbatim flush if needed */
|
||||
if (flush) {
|
||||
if (verblen == 1) {
|
||||
flush[0] = (signed char)254;
|
||||
flush[1] = verb[0];
|
||||
} else {
|
||||
flush[0] = (signed char)255;
|
||||
flush[1] = (signed char)(verblen-1);
|
||||
memcpy(flush+2,verb,verblen);
|
||||
}
|
||||
flush = NULL;
|
||||
verblen = 0;
|
||||
}
|
||||
}
|
||||
return out-_out;
|
||||
}
|
||||
|
||||
static int smaz_decompress(const char *in, int inlen, char *out, int outlen) {
|
||||
unsigned char *c = (unsigned char*) in;
|
||||
char *_out = out;
|
||||
int _outlen = outlen;
|
||||
|
||||
while(inlen) {
|
||||
if (*c == 254) {
|
||||
/* Verbatim byte */
|
||||
if (outlen < 1) return _outlen+1;
|
||||
*out = *(c+1);
|
||||
out++;
|
||||
outlen--;
|
||||
c += 2;
|
||||
inlen -= 2;
|
||||
} else if (*c == 255) {
|
||||
/* Verbatim string */
|
||||
int len = (*(c+1))+1;
|
||||
if (outlen < len) return _outlen+1;
|
||||
memcpy(out,c+2,len);
|
||||
out += len;
|
||||
outlen -= len;
|
||||
c += 2+len;
|
||||
inlen -= 2+len;
|
||||
} else {
|
||||
/* Codebook entry */
|
||||
const char *s = Smaz_rcb[*c];
|
||||
int len = strlen(s);
|
||||
|
||||
if (outlen < len) return _outlen+1;
|
||||
memcpy(out,s,len);
|
||||
out += len;
|
||||
outlen -= len;
|
||||
c++;
|
||||
inlen--;
|
||||
}
|
||||
}
|
||||
return out-_out;
|
||||
}
|
||||
|
||||
|
||||
/////////// END OF SMAZ /////////////
|
||||
|
||||
struct _PHashTranslationCmp {
|
||||
|
||||
int orig_len;
|
||||
CharString compressed;
|
||||
int offset;
|
||||
};
|
||||
|
||||
void PHashTranslation::generate(const Ref<Translation> &p_from) {
|
||||
#ifdef TOOLS_ENABLED
|
||||
List<StringName> keys;
|
||||
p_from->get_message_list(&keys);
|
||||
|
||||
int size=Math::larger_prime(keys.size());
|
||||
|
||||
|
||||
print_line("compressing keys: "+itos(keys.size()));
|
||||
Vector< Vector< Pair<int,CharString> > > buckets;
|
||||
Vector< Map< uint32_t, int > > table;
|
||||
Vector< uint32_t > hfunc_table;
|
||||
Vector< _PHashTranslationCmp > compressed;
|
||||
|
||||
table.resize(size);
|
||||
hfunc_table.resize(size);
|
||||
buckets.resize(size);
|
||||
compressed.resize(keys.size());
|
||||
|
||||
int idx=0;
|
||||
int total_compression_size=0;
|
||||
int total_string_size=0;
|
||||
|
||||
for(List<StringName>::Element *E=keys.front();E;E=E->next()) {
|
||||
|
||||
//hash string
|
||||
CharString cs = E->get().operator String().utf8();
|
||||
uint32_t h = hash(0,cs.get_data());
|
||||
Pair<int,CharString> p;
|
||||
p.first=idx;
|
||||
p.second=cs;
|
||||
buckets[h % size].push_back(p);
|
||||
|
||||
//compress string
|
||||
CharString src_s = p_from->get_message(E->get()).operator String().utf8();
|
||||
_PHashTranslationCmp ps;
|
||||
ps.orig_len=src_s.size();
|
||||
ps.offset=total_compression_size;
|
||||
|
||||
if (ps.orig_len!=0) {
|
||||
CharString dst_s;
|
||||
dst_s.resize(src_s.size());
|
||||
int ret = smaz_compress(src_s.get_data(),src_s.size(),&dst_s[0],src_s.size());
|
||||
if (ret>=src_s.size()) {
|
||||
//if compressed is larger than original, just use original
|
||||
ps.orig_len=src_s.size();
|
||||
ps.compressed=src_s;
|
||||
} else {
|
||||
dst_s.resize(ret);
|
||||
//ps.orig_len=;
|
||||
ps.compressed=dst_s;
|
||||
}
|
||||
} else {
|
||||
ps.orig_len=1;
|
||||
ps.compressed.resize(1);
|
||||
ps.compressed[0]=0;
|
||||
}
|
||||
|
||||
|
||||
compressed[idx]=ps;
|
||||
total_compression_size+=ps.compressed.size();
|
||||
total_string_size+=src_s.size();
|
||||
idx++;
|
||||
}
|
||||
|
||||
int bucket_table_size=0;
|
||||
print_line("total compressed string size: "+itos(total_compression_size)+" ("+itos(total_string_size)+" uncompressed).");
|
||||
|
||||
for(int i=0;i<size;i++) {
|
||||
|
||||
Vector< Pair<int,CharString> > &b = buckets[i];
|
||||
Map< uint32_t, int > &t=table[i];
|
||||
|
||||
if (b.size()==0)
|
||||
continue;
|
||||
|
||||
//print_line("bucket: "+itos(i)+" - elements: "+itos(b.size()));
|
||||
|
||||
int d = 1;
|
||||
int item =0;
|
||||
|
||||
while(item < b.size()) {
|
||||
|
||||
uint32_t slot = hash(d,b[item].second.get_data());
|
||||
if (t.has(slot)) {
|
||||
|
||||
item=0;
|
||||
d++;
|
||||
t.clear();
|
||||
} else {
|
||||
t[slot]=b[item].first;
|
||||
item++;
|
||||
}
|
||||
}
|
||||
|
||||
hfunc_table[i]=d;
|
||||
bucket_table_size+=2+b.size()*4;
|
||||
|
||||
}
|
||||
|
||||
|
||||
print_line("bucket table size: "+itos(bucket_table_size*4));
|
||||
print_line("hash table size: "+itos(size*4));
|
||||
|
||||
hash_table.resize(size);
|
||||
bucket_table.resize(bucket_table_size);
|
||||
|
||||
DVector<int>::Write htwb = hash_table.write();
|
||||
DVector<int>::Write btwb = bucket_table.write();
|
||||
|
||||
uint32_t *htw = (uint32_t*)&htwb[0];
|
||||
uint32_t *btw = (uint32_t*)&btwb[0];
|
||||
|
||||
int btindex=0;
|
||||
int collisions=0;
|
||||
|
||||
for(int i=0;i<size;i++) {
|
||||
|
||||
Map< uint32_t, int > &t=table[i];
|
||||
if (t.size()==0) {
|
||||
htw[i]=0xFFFFFFFF; //nothing
|
||||
continue;
|
||||
} else if (t.size()>1) {
|
||||
collisions+=t.size()-1;
|
||||
}
|
||||
|
||||
htw[i]=btindex;
|
||||
btw[btindex++]=t.size();
|
||||
btw[btindex++]=hfunc_table[i];
|
||||
|
||||
for( Map< uint32_t, int >::Element *E=t.front();E;E=E->next()) {
|
||||
|
||||
btw[btindex++]=E->key();
|
||||
btw[btindex++]=compressed[E->get()].offset;
|
||||
btw[btindex++]=compressed[E->get()].compressed.size();
|
||||
btw[btindex++]=compressed[E->get()].orig_len;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
print_line("total collisions: "+itos(collisions));
|
||||
|
||||
strings.resize(total_compression_size);
|
||||
DVector<uint8_t>::Write cw = strings.write();
|
||||
|
||||
for(int i=0;i<compressed.size();i++) {
|
||||
memcpy(&cw[compressed[i].offset],compressed[i].compressed.get_data(),compressed[i].compressed.size());
|
||||
}
|
||||
|
||||
|
||||
ERR_FAIL_COND(btindex!=bucket_table_size);
|
||||
set_locale(p_from->get_locale());
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
bool PHashTranslation::_set(const StringName& p_name, const Variant& p_value) {
|
||||
|
||||
String name = p_name.operator String();
|
||||
if (name=="hash_table") {
|
||||
hash_table=p_value;
|
||||
print_line("translation: loaded hash table of size: "+itos(hash_table.size()));
|
||||
} else if (name=="bucket_table") {
|
||||
bucket_table=p_value;
|
||||
print_line("translation: loaded bucket table of size: "+itos(bucket_table.size()));
|
||||
} else if (name=="strings") {
|
||||
strings=p_value;
|
||||
print_line("translation: loaded string table of size: "+itos(strings.size()));
|
||||
} else if (name=="load_from") {
|
||||
print_line("generating");
|
||||
generate(p_value);
|
||||
} else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool PHashTranslation::_get(const StringName& p_name,Variant &r_ret) const{
|
||||
|
||||
String name = p_name.operator String();
|
||||
if (name=="hash_table")
|
||||
r_ret=hash_table;
|
||||
else if (name=="bucket_table")
|
||||
r_ret=bucket_table;
|
||||
else if (name=="strings")
|
||||
r_ret=strings;
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
StringName PHashTranslation::get_message(const StringName& p_src_text) const {
|
||||
|
||||
int htsize = hash_table.size();
|
||||
|
||||
if (htsize==0)
|
||||
return StringName();
|
||||
|
||||
CharString str = p_src_text.operator String().utf8();
|
||||
uint32_t h = hash(0,str.get_data());
|
||||
|
||||
|
||||
DVector<int>::Read htr = hash_table.read();
|
||||
const uint32_t *htptr = (const uint32_t*)&htr[0];
|
||||
DVector<int>::Read btr = bucket_table.read();
|
||||
const uint32_t *btptr = (const uint32_t*)&btr[0];
|
||||
DVector<uint8_t>::Read sr = strings.read();
|
||||
const char *sptr= (const char*)&sr[0];
|
||||
|
||||
uint32_t p = htptr[ h % htsize];
|
||||
|
||||
//print_line("String: "+p_src_text.operator String());
|
||||
//print_line("Hash: "+itos(p));
|
||||
|
||||
if (p==0xFFFFFFFF) {
|
||||
// print_line("GETMSG: Nothing!");
|
||||
return StringName(); //nothing
|
||||
}
|
||||
|
||||
const Bucket &bucket = *(const Bucket*)&btptr[p];
|
||||
|
||||
h = hash(bucket.func,str.get_data());
|
||||
|
||||
int idx=-1;
|
||||
|
||||
for(int i=0;i<bucket.size;i++) {
|
||||
|
||||
if (bucket.elem[i].key==h) {
|
||||
|
||||
idx=i;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//print_line("bucket pos: "+itos(idx));
|
||||
if (idx==-1) {
|
||||
// print_line("GETMSG: Not in Bucket!");
|
||||
return StringName();
|
||||
}
|
||||
|
||||
if (bucket.elem[idx].comp_size == bucket.elem[idx].uncomp_size) {
|
||||
|
||||
String rstr;
|
||||
rstr.parse_utf8(&sptr[ bucket.elem[idx].str_offset ], bucket.elem[idx].uncomp_size );
|
||||
// print_line("Uncompressed, size: "+itos(bucket.elem[idx].comp_size));
|
||||
// print_line("Return: "+rstr);
|
||||
|
||||
return rstr;
|
||||
} else {
|
||||
|
||||
CharString uncomp;
|
||||
uncomp.resize( bucket.elem[idx].uncomp_size+1 );
|
||||
smaz_decompress(&sptr[ bucket.elem[idx].str_offset ], bucket.elem[idx].comp_size,uncomp.ptr(),bucket.elem[idx].uncomp_size );
|
||||
String rstr;
|
||||
rstr.parse_utf8(uncomp.get_data());
|
||||
// print_line("Compressed, size: "+itos(bucket.elem[idx].comp_size));
|
||||
// print_line("Return: "+rstr);
|
||||
return rstr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void PHashTranslation::_get_property_list( List<PropertyInfo> *p_list) const{
|
||||
|
||||
p_list->push_back( PropertyInfo(Variant::INT_ARRAY, "hash_table"));
|
||||
p_list->push_back( PropertyInfo(Variant::INT_ARRAY, "bucket_table"));
|
||||
p_list->push_back( PropertyInfo(Variant::RAW_ARRAY, "strings"));
|
||||
p_list->push_back( PropertyInfo(Variant::OBJECT, "load_from",PROPERTY_HINT_RESOURCE_TYPE,"Translation",PROPERTY_USAGE_EDITOR));
|
||||
|
||||
}
|
||||
void PHashTranslation::_bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("generate","from:Translation"),&PHashTranslation::generate);
|
||||
}
|
||||
|
||||
PHashTranslation::PHashTranslation()
|
||||
{
|
||||
}
|
93
core/compressed_translation.h
Normal file
93
core/compressed_translation.h
Normal file
@ -0,0 +1,93 @@
|
||||
/*************************************************************************/
|
||||
/* compressed_translation.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 COMPRESSED_TRANSLATION_H
|
||||
#define COMPRESSED_TRANSLATION_H
|
||||
|
||||
#include "translation.h"
|
||||
|
||||
class PHashTranslation : public Translation {
|
||||
|
||||
OBJ_TYPE(PHashTranslation,Translation);
|
||||
|
||||
|
||||
//this translation uses a sort of modified perfect hash algorithm
|
||||
//it requieres hashing strings twice and then does a binary search,
|
||||
//so it's slower, but at the same time it has an extreemly high chance
|
||||
//of catching untranslated strings
|
||||
|
||||
//load/store friendly types
|
||||
DVector<int> hash_table;
|
||||
DVector<int> bucket_table;
|
||||
DVector<uint8_t> strings;
|
||||
|
||||
|
||||
struct Bucket {
|
||||
|
||||
int size;
|
||||
uint32_t func;
|
||||
|
||||
struct Elem {
|
||||
|
||||
uint32_t key;
|
||||
uint32_t str_offset;
|
||||
uint32_t comp_size;
|
||||
uint32_t uncomp_size;
|
||||
};
|
||||
|
||||
Elem elem[1];
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ uint32_t hash( uint32_t d, const char *p_str ) const {
|
||||
|
||||
if (d==0)
|
||||
d=0x1000193;
|
||||
while(*p_str) {
|
||||
|
||||
d = (d * 0x1000193) ^ uint32_t(*p_str);
|
||||
p_str++;
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
protected:
|
||||
|
||||
bool _set(const StringName& p_name, const Variant& p_value);
|
||||
bool _get(const StringName& p_name,Variant &r_ret) const;
|
||||
void _get_property_list( List<PropertyInfo> *p_list) const;
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
|
||||
virtual StringName get_message(const StringName& p_src_text) const; //overridable for other implementations
|
||||
void generate(const Ref<Translation> &p_from);
|
||||
|
||||
PHashTranslation();
|
||||
};
|
||||
|
||||
#endif // COMPRESSED_TRANSLATION_H
|
47
core/core_string_names.cpp
Normal file
47
core/core_string_names.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
/*************************************************************************/
|
||||
/* core_string_names.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "core_string_names.h"
|
||||
|
||||
CoreStringNames* CoreStringNames::singleton=NULL;
|
||||
|
||||
CoreStringNames::CoreStringNames() {
|
||||
|
||||
_free=StaticCString::create("free");
|
||||
changed=StaticCString::create("changed");
|
||||
_meta=StaticCString::create("__meta__");
|
||||
_script=StaticCString::create("script/script");
|
||||
script_changed=StaticCString::create("script_changed");
|
||||
___pdcdata=StaticCString::create("___pdcdata");
|
||||
__getvar=StaticCString::create("__getvar");
|
||||
_iter_init=StaticCString::create("_iter_init");
|
||||
_iter_next=StaticCString::create("_iter_next");
|
||||
_iter_get=StaticCString::create("_iter_get");
|
||||
|
||||
|
||||
}
|
62
core/core_string_names.h
Normal file
62
core/core_string_names.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*************************************************************************/
|
||||
/* core_string_names.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 CORE_STRING_NAMES_H
|
||||
#define CORE_STRING_NAMES_H
|
||||
|
||||
#include "string_db.h"
|
||||
|
||||
class CoreStringNames {
|
||||
|
||||
friend void register_core_types();
|
||||
friend void unregister_core_types();
|
||||
|
||||
static CoreStringNames* singleton;
|
||||
|
||||
static void create() { singleton = memnew(CoreStringNames); }
|
||||
static void free() { memdelete( singleton); singleton=NULL; }
|
||||
|
||||
CoreStringNames();
|
||||
public:
|
||||
_FORCE_INLINE_ static CoreStringNames* get_singleton() { return singleton; }
|
||||
|
||||
|
||||
StringName _free;
|
||||
StringName changed;
|
||||
StringName _meta;
|
||||
StringName _script;
|
||||
StringName script_changed;
|
||||
StringName ___pdcdata;
|
||||
StringName __getvar;
|
||||
StringName _iter_init;
|
||||
StringName _iter_next;
|
||||
StringName _iter_get;
|
||||
|
||||
};
|
||||
|
||||
#endif // SCENE_STRING_NAMES_H
|
229
core/dictionary.cpp
Normal file
229
core/dictionary.cpp
Normal file
@ -0,0 +1,229 @@
|
||||
/*************************************************************************/
|
||||
/* dictionary.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "dictionary.h"
|
||||
#include "safe_refcount.h"
|
||||
#include "variant.h"
|
||||
#include "io/json.h"
|
||||
|
||||
struct _DictionaryVariantHash {
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash(const Variant &p_variant) { return p_variant.hash(); }
|
||||
};
|
||||
|
||||
|
||||
struct DictionaryPrivate {
|
||||
|
||||
SafeRefCount refcount;
|
||||
HashMap<Variant,Variant,_DictionaryVariantHash> variant_map;
|
||||
bool shared;
|
||||
|
||||
};
|
||||
|
||||
|
||||
void Dictionary::get_key_list( List<Variant> *p_keys) const {
|
||||
|
||||
_p->variant_map.get_key_list(p_keys);
|
||||
}
|
||||
|
||||
void Dictionary::_copy_on_write() const {
|
||||
|
||||
//make a copy of what we have
|
||||
if (_p->shared)
|
||||
return;
|
||||
|
||||
DictionaryPrivate *p = memnew(DictionaryPrivate);
|
||||
p->shared=_p->shared;
|
||||
p->variant_map=_p->variant_map;
|
||||
p->refcount.init();
|
||||
_unref();
|
||||
_p=p;
|
||||
}
|
||||
|
||||
Variant& Dictionary::operator[](const Variant& p_key) {
|
||||
|
||||
_copy_on_write();
|
||||
|
||||
return _p->variant_map[p_key];
|
||||
}
|
||||
|
||||
const Variant& Dictionary::operator[](const Variant& p_key) const {
|
||||
|
||||
return _p->variant_map[p_key];
|
||||
|
||||
}
|
||||
const Variant* Dictionary::getptr(const Variant& p_key) const {
|
||||
|
||||
return _p->variant_map.getptr(p_key);
|
||||
}
|
||||
Variant* Dictionary::getptr(const Variant& p_key) {
|
||||
|
||||
_copy_on_write();
|
||||
return _p->variant_map.getptr(p_key);
|
||||
}
|
||||
|
||||
Variant Dictionary::get_valid(const Variant& p_key) const {
|
||||
|
||||
const Variant *v = getptr(p_key);
|
||||
if (!v)
|
||||
return Variant();
|
||||
return *v;
|
||||
}
|
||||
|
||||
|
||||
int Dictionary::size() const {
|
||||
|
||||
return _p->variant_map.size();
|
||||
|
||||
}
|
||||
bool Dictionary::empty() const {
|
||||
|
||||
return !_p->variant_map.size();
|
||||
}
|
||||
|
||||
bool Dictionary::has(const Variant& p_key) const {
|
||||
|
||||
return _p->variant_map.has(p_key);
|
||||
}
|
||||
void Dictionary::erase(const Variant& p_key) {
|
||||
_copy_on_write();
|
||||
_p->variant_map.erase(p_key);
|
||||
}
|
||||
|
||||
bool Dictionary::operator==(const Dictionary& p_dictionary) const {
|
||||
|
||||
return _p==p_dictionary._p;
|
||||
}
|
||||
|
||||
void Dictionary::_ref(const Dictionary& p_from) const {
|
||||
|
||||
//make a copy first (thread safe)
|
||||
if (!p_from._p->refcount.ref())
|
||||
return; // couldn't copy
|
||||
|
||||
//if this is the same, unreference the other one
|
||||
if (p_from._p==_p) {
|
||||
_p->refcount.unref();
|
||||
return;
|
||||
}
|
||||
if (_p)
|
||||
_unref();
|
||||
_p=p_from._p;
|
||||
|
||||
}
|
||||
|
||||
void Dictionary::clear() {
|
||||
|
||||
_copy_on_write();
|
||||
_p->variant_map.clear();
|
||||
}
|
||||
|
||||
bool Dictionary::is_shared() const {
|
||||
|
||||
return _p->shared;
|
||||
}
|
||||
|
||||
|
||||
void Dictionary::_unref() const {
|
||||
|
||||
ERR_FAIL_COND(!_p);
|
||||
if (_p->refcount.unref()) {
|
||||
memdelete(_p);
|
||||
}
|
||||
_p=NULL;
|
||||
|
||||
}
|
||||
uint32_t Dictionary::hash() const {
|
||||
|
||||
return hash_djb2_one_64(make_uint64_t(_p));
|
||||
}
|
||||
|
||||
Array Dictionary::keys() const {
|
||||
|
||||
Array karr;
|
||||
karr.resize(size());
|
||||
const Variant *K=NULL;
|
||||
int idx=0;
|
||||
while((K=next(K))) {
|
||||
karr[idx++]=(*K);
|
||||
}
|
||||
return karr;
|
||||
|
||||
}
|
||||
|
||||
const Variant* Dictionary::next(const Variant* p_key) const {
|
||||
|
||||
return _p->variant_map.next(p_key);
|
||||
}
|
||||
|
||||
|
||||
Error Dictionary::parse_json(const String& p_json) {
|
||||
|
||||
String errstr;
|
||||
int errline=0;
|
||||
Error err = JSON::parse(p_json,*this,errstr,errline);
|
||||
if (err!=OK) {
|
||||
ERR_EXPLAIN("Error parsing JSON: "+errstr+" at line: "+itos(errline));
|
||||
ERR_FAIL_COND_V(err!=OK,err);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
String Dictionary::to_json() const {
|
||||
|
||||
return JSON::print(*this);
|
||||
}
|
||||
|
||||
|
||||
void Dictionary::operator=(const Dictionary& p_dictionary) {
|
||||
|
||||
_ref(p_dictionary);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Dictionary::Dictionary(const Dictionary& p_from) {
|
||||
_p=NULL;
|
||||
_ref(p_from);
|
||||
}
|
||||
|
||||
|
||||
Dictionary::Dictionary(bool p_shared) {
|
||||
|
||||
_p=memnew( DictionaryPrivate );
|
||||
_p->refcount.init();
|
||||
_p->shared=p_shared;
|
||||
|
||||
}
|
||||
Dictionary::~Dictionary() {
|
||||
|
||||
_unref();
|
||||
}
|
||||
|
||||
|
88
core/dictionary.h
Normal file
88
core/dictionary.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*************************************************************************/
|
||||
/* dictionary.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 DICTIONARY_H
|
||||
#define DICTIONARY_H
|
||||
|
||||
|
||||
#include "list.h"
|
||||
#include "array.h"
|
||||
#include "ustring.h"
|
||||
class Variant;
|
||||
|
||||
|
||||
struct DictionaryPrivate;
|
||||
|
||||
|
||||
class Dictionary {
|
||||
|
||||
mutable DictionaryPrivate *_p;
|
||||
|
||||
void _copy_on_write() const;
|
||||
void _ref(const Dictionary& p_from) const;
|
||||
void _unref() const;
|
||||
public:
|
||||
|
||||
void get_key_list( List<Variant> *p_keys) const;
|
||||
|
||||
Variant& operator[](const Variant& p_key);
|
||||
const Variant& operator[](const Variant& p_key) const;
|
||||
|
||||
const Variant* getptr(const Variant& p_key) const;
|
||||
Variant* getptr(const Variant& p_key);
|
||||
|
||||
Variant get_valid(const Variant& p_key) const;
|
||||
|
||||
int size() const;
|
||||
bool empty() const;
|
||||
void clear();
|
||||
|
||||
|
||||
Error parse_json(const String& p_json);
|
||||
String to_json() const;
|
||||
|
||||
bool is_shared() const;
|
||||
|
||||
bool has(const Variant& p_key) const;
|
||||
void erase(const Variant& p_key);
|
||||
|
||||
bool operator==(const Dictionary& p_dictionary) const;
|
||||
|
||||
uint32_t hash() const;
|
||||
void operator=(const Dictionary& p_dictionary);
|
||||
|
||||
const Variant* next(const Variant* p_key=NULL) const;
|
||||
|
||||
Array keys() const;
|
||||
|
||||
Dictionary(const Dictionary& p_from);
|
||||
Dictionary(bool p_shared=false);
|
||||
~Dictionary();
|
||||
};
|
||||
|
||||
#endif // DICTIONARY_H
|
32
core/dvector.cpp
Normal file
32
core/dvector.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
/*************************************************************************/
|
||||
/* dvector.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "dvector.h"
|
||||
|
||||
Mutex* dvector_lock=NULL;
|
||||
|
412
core/dvector.h
Normal file
412
core/dvector.h
Normal file
@ -0,0 +1,412 @@
|
||||
/*************************************************************************/
|
||||
/* dvector.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 DVECTOR_H
|
||||
#define DVECTOR_H
|
||||
|
||||
#include "os/memory.h"
|
||||
|
||||
|
||||
/**
|
||||
@author Juan Linietsky <reduzio@gmail.com>
|
||||
*/
|
||||
|
||||
|
||||
extern Mutex* dvector_lock;
|
||||
|
||||
template<class T>
|
||||
class DVector {
|
||||
|
||||
mutable MID mem;
|
||||
|
||||
|
||||
void copy_on_write() {
|
||||
|
||||
if (!mem.is_valid())
|
||||
return;
|
||||
|
||||
if (dvector_lock)
|
||||
dvector_lock->lock();
|
||||
|
||||
MID_Lock lock( mem );
|
||||
|
||||
|
||||
if ( *(int*)lock.data() == 1 ) {
|
||||
// one reference, means no refcount changes
|
||||
if (dvector_lock)
|
||||
dvector_lock->unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
MID new_mem= dynalloc( mem.get_size() );
|
||||
|
||||
if (!new_mem.is_valid()) {
|
||||
|
||||
if (dvector_lock)
|
||||
dvector_lock->unlock();
|
||||
ERR_FAIL_COND( new_mem.is_valid() ); // out of memory
|
||||
}
|
||||
|
||||
MID_Lock dst_lock( new_mem );
|
||||
|
||||
int *rc = (int*)dst_lock.data();
|
||||
|
||||
*rc=1;
|
||||
|
||||
T * dst = (T*)(rc + 1 );
|
||||
|
||||
T * src =(T*) ((int*)lock.data() + 1 );
|
||||
|
||||
int count = (mem.get_size() - sizeof(int)) / sizeof(T);
|
||||
|
||||
for (int i=0;i<count;i++) {
|
||||
|
||||
memnew_placement( &dst[i], T(src[i]) );
|
||||
}
|
||||
|
||||
(*(int*)lock.data())--;
|
||||
|
||||
// unlock all
|
||||
dst_lock=MID_Lock();
|
||||
lock=MID_Lock();
|
||||
|
||||
mem=new_mem;
|
||||
|
||||
if (dvector_lock)
|
||||
dvector_lock->unlock();
|
||||
|
||||
}
|
||||
|
||||
void reference( const DVector& p_dvector ) {
|
||||
|
||||
unreference();
|
||||
|
||||
if (dvector_lock)
|
||||
dvector_lock->lock();
|
||||
|
||||
if (!p_dvector.mem.is_valid()) {
|
||||
|
||||
if (dvector_lock)
|
||||
dvector_lock->unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
MID_Lock lock(p_dvector.mem);
|
||||
|
||||
int * rc = (int*)lock.data();
|
||||
(*rc)++;
|
||||
|
||||
lock = MID_Lock();
|
||||
mem=p_dvector.mem;
|
||||
|
||||
if (dvector_lock)
|
||||
dvector_lock->unlock();
|
||||
|
||||
}
|
||||
|
||||
|
||||
void unreference() {
|
||||
|
||||
if (dvector_lock)
|
||||
dvector_lock->lock();
|
||||
|
||||
if (!mem.is_valid()) {
|
||||
|
||||
if (dvector_lock)
|
||||
dvector_lock->unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
MID_Lock lock(mem);
|
||||
|
||||
int * rc = (int*)lock.data();
|
||||
(*rc)--;
|
||||
|
||||
if (*rc==0) {
|
||||
// no one else using it, destruct
|
||||
|
||||
T * t= (T*)(rc+1);
|
||||
int count = (mem.get_size() - sizeof(int)) / sizeof(T);
|
||||
|
||||
for (int i=0;i<count;i++) {
|
||||
|
||||
t[i].~T();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
lock = MID_Lock();
|
||||
|
||||
mem = MID ();
|
||||
|
||||
if (dvector_lock)
|
||||
dvector_lock->unlock();
|
||||
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
class Read {
|
||||
friend class DVector;
|
||||
MID_Lock lock;
|
||||
const T * mem;
|
||||
public:
|
||||
|
||||
_FORCE_INLINE_ const T& operator[](int p_index) const { return mem[p_index]; }
|
||||
_FORCE_INLINE_ const T *ptr() const { return mem; }
|
||||
|
||||
Read() { mem=NULL; }
|
||||
};
|
||||
|
||||
class Write {
|
||||
friend class DVector;
|
||||
MID_Lock lock;
|
||||
T * mem;
|
||||
public:
|
||||
|
||||
_FORCE_INLINE_ T& operator[](int p_index) { return mem[p_index]; }
|
||||
_FORCE_INLINE_ T *ptr() { return mem; }
|
||||
|
||||
Write() { mem=NULL; }
|
||||
};
|
||||
|
||||
|
||||
Read read() const {
|
||||
|
||||
Read r;
|
||||
if (mem.is_valid()) {
|
||||
r.lock = MID_Lock( mem );
|
||||
r.mem = (const T*)((int*)r.lock.data()+1);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
Write write() {
|
||||
|
||||
Write w;
|
||||
if (mem.is_valid()) {
|
||||
copy_on_write();
|
||||
w.lock = MID_Lock( mem );
|
||||
w.mem = (T*)((int*)w.lock.data()+1);
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
template<class MC>
|
||||
void fill_with(const MC& p_mc) {
|
||||
|
||||
|
||||
int c=p_mc.size();
|
||||
resize(c);
|
||||
Write w=write();
|
||||
int idx=0;
|
||||
for(const typename MC::Element *E=p_mc.front();E;E=E->next()) {
|
||||
|
||||
w[idx++]=E->get();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void remove(int p_index) {
|
||||
|
||||
int s = size();
|
||||
ERR_FAIL_INDEX(p_index, s);
|
||||
Write w = write();
|
||||
for (int i=p_index; i<s-1; i++) {
|
||||
|
||||
w[i]=w[i+1];
|
||||
};
|
||||
w = Write();
|
||||
resize(s-1);
|
||||
}
|
||||
|
||||
inline int size() const;
|
||||
T get(int p_index) const;
|
||||
void set(int p_index, const T& p_val);
|
||||
void push_back(const T& p_val);
|
||||
void append(const T& p_val) { push_back(p_val); }
|
||||
void append_array(const DVector<T>& p_arr) {
|
||||
int ds = p_arr.size();
|
||||
if (ds==0)
|
||||
return;
|
||||
int bs = size();
|
||||
resize( bs + ds);
|
||||
Write w = write();
|
||||
Read r = p_arr.read();
|
||||
for(int i=0;i<ds;i++)
|
||||
w[bs+i]=r[i];
|
||||
}
|
||||
|
||||
bool is_locked() const { return mem.is_locked(); }
|
||||
|
||||
inline const T operator[](int p_index) const;
|
||||
|
||||
Error resize(int p_size);
|
||||
|
||||
|
||||
void operator=(const DVector& p_dvector) { reference(p_dvector); }
|
||||
DVector() {}
|
||||
DVector(const DVector& p_dvector) { reference(p_dvector); }
|
||||
~DVector() { unreference(); }
|
||||
|
||||
};
|
||||
|
||||
template<class T>
|
||||
int DVector<T>::size() const {
|
||||
|
||||
return mem.is_valid() ? ((mem.get_size() - sizeof(int)) / sizeof(T) ) : 0;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T DVector<T>::get(int p_index) const {
|
||||
|
||||
return operator[](p_index);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void DVector<T>::set(int p_index, const T& p_val) {
|
||||
|
||||
if (p_index<0 || p_index>=size()) {
|
||||
ERR_FAIL_COND(p_index<0 || p_index>=size());
|
||||
}
|
||||
|
||||
Write w = write();
|
||||
w[p_index]=p_val;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void DVector<T>::push_back(const T& p_val) {
|
||||
|
||||
resize( size() + 1 );
|
||||
set( size() -1, p_val );
|
||||
}
|
||||
|
||||
template<class T>
|
||||
const T DVector<T>::operator[](int p_index) const {
|
||||
|
||||
if (p_index<0 || p_index>=size()) {
|
||||
T& aux=*((T*)0); //nullreturn
|
||||
ERR_FAIL_COND_V(p_index<0 || p_index>=size(),aux);
|
||||
}
|
||||
|
||||
Read r = read();
|
||||
|
||||
return r[p_index];
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
Error DVector<T>::resize(int p_size) {
|
||||
|
||||
if (dvector_lock)
|
||||
dvector_lock->lock();
|
||||
|
||||
bool same = p_size==size();
|
||||
|
||||
if (dvector_lock)
|
||||
dvector_lock->unlock();
|
||||
// no further locking is necesary because we are supposed to own the only copy of this (using copy on write)
|
||||
|
||||
if (same)
|
||||
return OK;
|
||||
|
||||
if (p_size == 0 ) {
|
||||
|
||||
unreference();
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
copy_on_write(); // make it unique
|
||||
|
||||
ERR_FAIL_COND_V( mem.is_locked(), ERR_LOCKED ); // if after copy on write, memory is locked, fail.
|
||||
|
||||
if (p_size > size() ) {
|
||||
|
||||
int oldsize=size();
|
||||
|
||||
MID_Lock lock;
|
||||
|
||||
if (oldsize==0) {
|
||||
|
||||
mem = dynalloc( p_size * sizeof(T) + sizeof(int) );
|
||||
lock=MID_Lock(mem);
|
||||
int *rc = ((int*)lock.data());
|
||||
*rc=1;
|
||||
|
||||
} else {
|
||||
|
||||
if (dynrealloc( mem, p_size * sizeof(T) + sizeof(int) )!=OK ) {
|
||||
|
||||
ERR_FAIL_V(ERR_OUT_OF_MEMORY); // out of memory
|
||||
}
|
||||
|
||||
lock=MID_Lock(mem);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
T *t = (T*)((int*)lock.data() + 1);
|
||||
|
||||
for (int i=oldsize;i<p_size;i++) {
|
||||
|
||||
memnew_placement(&t[i], T );
|
||||
}
|
||||
|
||||
lock = MID_Lock(); // clear
|
||||
} else {
|
||||
|
||||
int oldsize=size();
|
||||
|
||||
MID_Lock lock(mem);
|
||||
|
||||
|
||||
T *t = (T*)((int*)lock.data() + 1);
|
||||
|
||||
for (int i=p_size;i<oldsize;i++) {
|
||||
|
||||
t[i].~T();
|
||||
}
|
||||
|
||||
lock = MID_Lock(); // clear
|
||||
|
||||
if (dynrealloc( mem, p_size * sizeof(T) + sizeof(int) )!=OK ) {
|
||||
|
||||
ERR_FAIL_V(ERR_OUT_OF_MEMORY); // wtf error
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
95
core/error_list.h
Normal file
95
core/error_list.h
Normal file
@ -0,0 +1,95 @@
|
||||
/*************************************************************************/
|
||||
/* error_list.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 ERROR_LIST_H
|
||||
#define ERROR_LIST_H
|
||||
|
||||
/** Error List. Please never compare an error against FAILED
|
||||
* Either do result != OK , or !result. This way, Error fail
|
||||
* values can be more detailed in the future.
|
||||
*
|
||||
* This is a generic error list, mainly for organizing a language of returning errors.
|
||||
*/
|
||||
|
||||
enum Error {
|
||||
OK,
|
||||
FAILED, ///< Generic fail error
|
||||
ERR_UNAVAILABLE, ///< What is requested is unsupported/unavailable
|
||||
ERR_UNCONFIGURED, ///< The object being used hasnt been properly set up yet
|
||||
ERR_UNAUTHORIZED, ///< Missing credentials for requested resource
|
||||
ERR_PARAMETER_RANGE_ERROR, ///< Parameter given out of range (5)
|
||||
ERR_OUT_OF_MEMORY, ///< Out of memory
|
||||
ERR_FILE_NOT_FOUND,
|
||||
ERR_FILE_BAD_DRIVE,
|
||||
ERR_FILE_BAD_PATH,
|
||||
ERR_FILE_NO_PERMISSION, // (10)
|
||||
ERR_FILE_ALREADY_IN_USE,
|
||||
ERR_FILE_CANT_OPEN,
|
||||
ERR_FILE_CANT_WRITE,
|
||||
ERR_FILE_CANT_READ,
|
||||
ERR_FILE_UNRECOGNIZED, // (15)
|
||||
ERR_FILE_CORRUPT,
|
||||
ERR_FILE_EOF,
|
||||
ERR_CANT_OPEN, ///< Can't open a resource/socket/file
|
||||
ERR_CANT_CREATE,
|
||||
ERROR_QUERY_FAILED, // (20)
|
||||
ERR_ALREADY_IN_USE,
|
||||
ERR_LOCKED, ///< resource is locked
|
||||
ERR_TIMEOUT,
|
||||
ERR_CANT_CONNECT,
|
||||
ERR_CANT_RESOLVE, // (25)
|
||||
ERR_CONNECTION_ERROR,
|
||||
ERR_CANT_AQUIRE_RESOURCE,
|
||||
ERR_CANT_FORK,
|
||||
ERR_INVALID_DATA, ///< Data passed is invalid
|
||||
ERR_INVALID_PARAMETER, ///< Parameter passed is invalid (30)
|
||||
ERR_ALREADY_EXISTS, ///< When adding, item already exists
|
||||
ERR_DOES_NOT_EXIST, ///< When retrieving/erasing, it item does not exist
|
||||
ERR_DATABASE_CANT_READ, ///< database is full
|
||||
ERR_DATABASE_CANT_WRITE, ///< database is full
|
||||
ERR_COMPILATION_FAILED, // (35)
|
||||
ERR_METHOD_NOT_FOUND,
|
||||
ERR_LINK_FAILED,
|
||||
ERR_SCRIPT_FAILED,
|
||||
ERR_CYCLIC_LINK,
|
||||
ERR_INVALID_DECLARATION, // (40)
|
||||
ERR_DUPLICATE_SYMBOL,
|
||||
ERR_PARSE_ERROR,
|
||||
ERR_BUSY,
|
||||
ERR_SKIP,
|
||||
ERR_HELP, ///< user requested help!! (45)
|
||||
ERR_BUG, ///< a bug in the software certainly happened, due to a double check failing or unexpected behavior.
|
||||
ERR_PRINTER_ON_FIRE, /// the parallel port printer is engulfed in flames
|
||||
ERR_OMFG_THIS_IS_VERY_VERY_BAD, ///< shit happens, has never been used, though
|
||||
ERR_WTF = ERR_OMFG_THIS_IS_VERY_VERY_BAD ///< short version of the above
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
102
core/error_macros.cpp
Normal file
102
core/error_macros.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
/*************************************************************************/
|
||||
/* error_macros.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "error_macros.h"
|
||||
#include "os/os.h"
|
||||
|
||||
|
||||
bool _err_error_exists=false;
|
||||
|
||||
static ErrorHandlerList *error_handler_list=NULL;
|
||||
|
||||
void _err_set_last_error(const char* p_err) {
|
||||
|
||||
OS::get_singleton()->set_last_error(p_err);
|
||||
}
|
||||
|
||||
void _err_clear_last_error() {
|
||||
|
||||
OS::get_singleton()->clear_last_error();
|
||||
}
|
||||
|
||||
void add_error_handler(ErrorHandlerList *p_handler) {
|
||||
|
||||
_global_lock();
|
||||
p_handler->next=error_handler_list;
|
||||
error_handler_list=p_handler;
|
||||
_global_unlock();
|
||||
}
|
||||
|
||||
void remove_error_handler(ErrorHandlerList *p_handler) {
|
||||
|
||||
_global_lock();
|
||||
|
||||
ErrorHandlerList *prev = NULL;
|
||||
ErrorHandlerList *l = error_handler_list;
|
||||
|
||||
while(l) {
|
||||
|
||||
if (l==p_handler) {
|
||||
|
||||
if (prev)
|
||||
prev->next=l->next;
|
||||
else
|
||||
error_handler_list=l->next;
|
||||
break;
|
||||
}
|
||||
prev=l;
|
||||
l=l->next;
|
||||
|
||||
}
|
||||
|
||||
_global_unlock();
|
||||
|
||||
}
|
||||
|
||||
void _err_print_error(const char* p_function, const char* p_file,int p_line,const char *p_error,ErrorHandlerType p_type) {
|
||||
|
||||
|
||||
|
||||
OS::get_singleton()->print_error(p_function,p_file,p_line,p_error,_err_error_exists?OS::get_singleton()->get_last_error():"",(OS::ErrorType)p_type);
|
||||
|
||||
_global_lock();
|
||||
ErrorHandlerList *l = error_handler_list;
|
||||
while(l) {
|
||||
|
||||
l->errfunc(l->userdata,p_function,p_file,p_line,p_error,_err_error_exists?OS::get_singleton()->get_last_error():"",p_type);
|
||||
l=l->next;
|
||||
}
|
||||
|
||||
_global_unlock();
|
||||
|
||||
if (_err_error_exists) {
|
||||
OS::get_singleton()->clear_last_error();
|
||||
_err_error_exists=false;
|
||||
}
|
||||
|
||||
}
|
222
core/error_macros.h
Normal file
222
core/error_macros.h
Normal file
@ -0,0 +1,222 @@
|
||||
/*************************************************************************/
|
||||
/* error_macros.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 ERROR_MACROS_H
|
||||
#define ERROR_MACROS_H
|
||||
|
||||
|
||||
/**
|
||||
* Error macros. Unlike exceptions and asserts, these macros try to mantain consistency and stability
|
||||
* inside the code. It is recommended to always return processable data, so in case of an error, the
|
||||
* engine can stay working well.
|
||||
* In most cases, bugs and/or invalid data are not fatal and should never allow a perfectly running application
|
||||
* to fail or crash.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Pointer to the error macro priting function. Reassign to any function to have errors printed
|
||||
*/
|
||||
|
||||
/** Function used by the error macros */
|
||||
|
||||
// function, file, line, error, explanation
|
||||
|
||||
enum ErrorHandlerType {
|
||||
ERR_HANDLER_ERROR,
|
||||
ERR_HANDLER_WARNING,
|
||||
ERR_HANDLER_SCRIPT
|
||||
};
|
||||
|
||||
typedef void (*ErrorHandlerFunc)(void*,const char*,const char*,int p_line,const char *, const char *,ErrorHandlerType p_type);
|
||||
void _err_set_last_error(const char* p_err);
|
||||
void _err_clear_last_error();
|
||||
|
||||
struct ErrorHandlerList {
|
||||
|
||||
ErrorHandlerFunc errfunc;
|
||||
void *userdata;
|
||||
|
||||
ErrorHandlerList*next;
|
||||
|
||||
ErrorHandlerList() { errfunc=0; next=0; userdata=0; }
|
||||
};
|
||||
|
||||
void add_error_handler(ErrorHandlerList *p_handler);
|
||||
void remove_error_handler(ErrorHandlerList *p_handler);
|
||||
|
||||
void _err_print_error(const char* p_function,const char* p_file,int p_line,const char *p_error,ErrorHandlerType p_type=ERR_HANDLER_ERROR);
|
||||
|
||||
#ifndef _STR
|
||||
#define _STR(m_x) #m_x
|
||||
#define _MKSTR(m_x) _STR(m_x)
|
||||
#endif
|
||||
|
||||
#define _FNL __FILE__":"
|
||||
|
||||
/** An index has failed if m_index<0 or m_index >=m_size, the function exists */
|
||||
|
||||
extern bool _err_error_exists;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
/** Print a warning string.
|
||||
*/
|
||||
#define ERR_EXPLAINC(m_reason) {_err_set_last_error(m_reason); _err_error_exists=true;}
|
||||
#define ERR_EXPLAIN(m_string) {_err_set_last_error(String(m_string).utf8().get_data()); _err_error_exists=true;}
|
||||
|
||||
#else
|
||||
|
||||
#define ERR_EXPLAIN( m_text )
|
||||
#define ERR_EXPLAINC( m_text )
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
//#define FUNCTION_STR __PRETTY_FUNCTION__ - too annoying
|
||||
#define FUNCTION_STR __FUNCTION__
|
||||
#else
|
||||
#define FUNCTION_STR __FUNCTION__
|
||||
#endif
|
||||
|
||||
#define ERR_FAIL_INDEX(m_index,m_size) \
|
||||
do {if ((m_index)<0 || (m_index)>=(m_size)) { \
|
||||
_err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Index "_STR(m_index)" out of size ("_STR(m_size)")."); \
|
||||
return; \
|
||||
} else _err_error_exists=false; } while(0); \
|
||||
|
||||
/** An index has failed if m_index<0 or m_index >=m_size, the function exists.
|
||||
* This function returns an error value, if returning Error, please select the most
|
||||
* appropriate error condition from error_macros.h
|
||||
*/
|
||||
|
||||
#define ERR_FAIL_INDEX_V(m_index,m_size,m_retval) \
|
||||
do {if ((m_index)<0 || (m_index)>=(m_size)) { \
|
||||
_err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Index "_STR(m_index)" out of size ("_STR(m_size)")."); \
|
||||
return m_retval; \
|
||||
} else _err_error_exists=false;} while (0);
|
||||
|
||||
/** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert().
|
||||
* the function will exit.
|
||||
*/
|
||||
|
||||
#define ERR_FAIL_NULL(m_param) \
|
||||
{ if ( !m_param ) { \
|
||||
_err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Parameter ' "_STR(m_param)" ' is null."); \
|
||||
return; \
|
||||
}else _err_error_exists=false; } \
|
||||
|
||||
|
||||
#define ERR_FAIL_NULL_V(m_param,m_retval) \
|
||||
{ if ( !m_param ) { \
|
||||
_err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Parameter ' "_STR(m_param)" ' is null."); \
|
||||
return m_retval; \
|
||||
}else _err_error_exists=false; } \
|
||||
|
||||
/** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert().
|
||||
* the function will exit.
|
||||
*/
|
||||
|
||||
#define ERR_FAIL_COND(m_cond) \
|
||||
{ if ( m_cond ) { \
|
||||
_err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Condition ' "_STR(m_cond)" ' is true."); \
|
||||
return; \
|
||||
}else _err_error_exists=false; } \
|
||||
|
||||
/** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert().
|
||||
* the function will exit.
|
||||
* This function returns an error value, if returning Error, please select the most
|
||||
* appropriate error condition from error_macros.h
|
||||
*/
|
||||
|
||||
#define ERR_FAIL_COND_V(m_cond,m_retval) \
|
||||
{ if ( m_cond ) { \
|
||||
_err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Condition ' "_STR(m_cond)" ' is true. returned: "_STR(m_retval)); \
|
||||
return m_retval; \
|
||||
}else _err_error_exists=false; } \
|
||||
|
||||
/** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert().
|
||||
* the loop will skip to the next iteration.
|
||||
*/
|
||||
|
||||
#define ERR_CONTINUE(m_cond) \
|
||||
{ if ( m_cond ) { \
|
||||
_err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Condition ' "_STR(m_cond)" ' is true. Continuing..:"); \
|
||||
continue;\
|
||||
} else _err_error_exists=false;} \
|
||||
|
||||
/** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert().
|
||||
* the loop will break
|
||||
*/
|
||||
|
||||
#define ERR_BREAK(m_cond) \
|
||||
{ if ( m_cond ) { \
|
||||
_err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Condition ' "_STR(m_cond)" ' is true. Breaking..:"); \
|
||||
break;\
|
||||
} else _err_error_exists=false;} \
|
||||
|
||||
/** Print an error string and return
|
||||
*/
|
||||
|
||||
#define ERR_FAIL() \
|
||||
{ \
|
||||
_err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Method/Function Failed."); \
|
||||
_err_error_exists=false;\
|
||||
return;\
|
||||
} \
|
||||
|
||||
/** Print an error string and return with value
|
||||
*/
|
||||
|
||||
#define ERR_FAIL_V(m_value) \
|
||||
{ \
|
||||
_err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Method/Function Failed, returning: "__STR(m_value)); \
|
||||
_err_error_exists=false; \
|
||||
return m_value;\
|
||||
} \
|
||||
|
||||
/** Print an error string.
|
||||
*/
|
||||
|
||||
#define ERR_PRINT(m_string) \
|
||||
{ \
|
||||
_err_print_error(FUNCTION_STR,__FILE__,__LINE__,m_string); \
|
||||
_err_error_exists=false;\
|
||||
} \
|
||||
|
||||
|
||||
/** Print a warning string.
|
||||
*/
|
||||
|
||||
#define WARN_PRINT(m_string) \
|
||||
{ \
|
||||
_err_print_error(FUNCTION_STR,__FILE__,__LINE__,m_string,ERR_HANDLER_WARNING); \
|
||||
_err_error_exists=false;\
|
||||
} \
|
||||
|
||||
|
||||
|
||||
#endif
|
153
core/event_queue.cpp
Normal file
153
core/event_queue.cpp
Normal file
@ -0,0 +1,153 @@
|
||||
/*************************************************************************/
|
||||
/* event_queue.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "event_queue.h"
|
||||
|
||||
|
||||
Error EventQueue::push_call(uint32_t p_instance_ID, const StringName& p_method, VARIANT_ARG_DECLARE) {
|
||||
|
||||
uint8_t room_needed=sizeof(Event);
|
||||
int args=0;
|
||||
if (p_arg5.get_type()!=Variant::NIL)
|
||||
args=5;
|
||||
else if (p_arg4.get_type()!=Variant::NIL)
|
||||
args=4;
|
||||
else if (p_arg3.get_type()!=Variant::NIL)
|
||||
args=3;
|
||||
else if (p_arg2.get_type()!=Variant::NIL)
|
||||
args=2;
|
||||
else if (p_arg1.get_type()!=Variant::NIL)
|
||||
args=1;
|
||||
else
|
||||
args=0;
|
||||
|
||||
room_needed+=sizeof(Variant)*args;
|
||||
|
||||
ERR_FAIL_COND_V( (buffer_end+room_needed) >= buffer_size , ERR_OUT_OF_MEMORY );
|
||||
Event * ev = memnew_placement( &event_buffer[ buffer_end ], Event );
|
||||
ev->args=args;
|
||||
ev->instance_ID=p_instance_ID;
|
||||
ev->method=p_method;
|
||||
|
||||
buffer_end+=sizeof(Event);
|
||||
|
||||
if (args==1) {
|
||||
|
||||
Variant * v = memnew_placement( &event_buffer[ buffer_end ], Variant );
|
||||
buffer_end+=sizeof(Variant);
|
||||
*v=p_arg1;
|
||||
} else if (args==2) {
|
||||
|
||||
Variant * v = memnew_placement( &event_buffer[ buffer_end ], Variant );
|
||||
buffer_end+=sizeof(Variant);
|
||||
*v=p_arg2;
|
||||
} else if (args==3) {
|
||||
|
||||
Variant * v = memnew_placement( &event_buffer[ buffer_end ], Variant );
|
||||
buffer_end+=sizeof(Variant);
|
||||
*v=p_arg3;
|
||||
|
||||
} else if (args==4) {
|
||||
|
||||
Variant * v = memnew_placement( &event_buffer[ buffer_end ], Variant );
|
||||
buffer_end+=sizeof(Variant);
|
||||
*v=p_arg4;
|
||||
} else if (args==5) {
|
||||
|
||||
Variant * v = memnew_placement( &event_buffer[ buffer_end ], Variant );
|
||||
buffer_end+=sizeof(Variant);
|
||||
*v=p_arg5;
|
||||
}
|
||||
|
||||
if (buffer_max_used>buffer_end);
|
||||
buffer_max_used=buffer_end;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void EventQueue::flush_events() {
|
||||
|
||||
uint32_t read_pos=0;
|
||||
|
||||
while (read_pos < buffer_end ) {
|
||||
|
||||
Event *event = (Event*)&event_buffer[ read_pos ];
|
||||
Variant *args= (Variant*)(event+1);
|
||||
Object *obj = ObjectDB::get_instance(event->instance_ID);
|
||||
|
||||
if (obj) {
|
||||
// events don't expect a return value
|
||||
obj->call( event->method,
|
||||
(event->args>=1) ? args[0] : Variant(),
|
||||
(event->args>=2) ? args[1] : Variant(),
|
||||
(event->args>=3) ? args[2] : Variant(),
|
||||
(event->args>=4) ? args[3] : Variant(),
|
||||
(event->args>=5) ? args[4] : Variant() );
|
||||
}
|
||||
|
||||
if (event->args>=1) args[0].~Variant();
|
||||
if (event->args>=2) args[1].~Variant();
|
||||
if (event->args>=3) args[2].~Variant();
|
||||
if (event->args>=4) args[3].~Variant();
|
||||
if (event->args>=5) args[4].~Variant();
|
||||
event->~Event();
|
||||
|
||||
read_pos+=sizeof(Event)+sizeof(Variant)*event->args;
|
||||
}
|
||||
|
||||
buffer_end=0; // reset buffer
|
||||
}
|
||||
|
||||
EventQueue::EventQueue(uint32_t p_buffer_size) {
|
||||
|
||||
|
||||
buffer_end=0;
|
||||
buffer_max_used=0;
|
||||
buffer_size=p_buffer_size;
|
||||
event_buffer = memnew_arr( uint8_t, buffer_size );
|
||||
|
||||
}
|
||||
EventQueue::~EventQueue() {
|
||||
|
||||
uint32_t read_pos=0;
|
||||
|
||||
while (read_pos < buffer_end ) {
|
||||
|
||||
Event *event = (Event*)&event_buffer[ read_pos ];
|
||||
Variant *args= (Variant*)(event+1);
|
||||
for (int i=0;i<event->args;i++)
|
||||
args[i].~Variant();
|
||||
event->~Event();
|
||||
|
||||
read_pos+=sizeof(Event)+sizeof(Variant)*event->args;
|
||||
}
|
||||
|
||||
memdelete_arr(event_buffer);
|
||||
event_buffer=NULL;
|
||||
}
|
||||
|
66
core/event_queue.h
Normal file
66
core/event_queue.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*************************************************************************/
|
||||
/* event_queue.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 EVENT_QUEUE_H
|
||||
#define EVENT_QUEUE_H
|
||||
|
||||
#include "object.h"
|
||||
/**
|
||||
@author Juan Linietsky <reduzio@gmail.com>
|
||||
*/
|
||||
class EventQueue {
|
||||
|
||||
enum {
|
||||
|
||||
DEFAULT_EVENT_QUEUE_SIZE_KB=256
|
||||
};
|
||||
|
||||
struct Event {
|
||||
|
||||
uint32_t instance_ID;
|
||||
StringName method;
|
||||
int args;
|
||||
};
|
||||
|
||||
|
||||
uint8_t *event_buffer;
|
||||
uint32_t buffer_end;
|
||||
uint32_t buffer_max_used;
|
||||
uint32_t buffer_size;
|
||||
public:
|
||||
|
||||
|
||||
Error push_call(uint32_t p_instance_ID, const StringName& p_method, VARIANT_ARG_LIST);
|
||||
void flush_events();
|
||||
|
||||
EventQueue(uint32_t p_buffer_size=DEFAULT_EVENT_QUEUE_SIZE_KB*1024);
|
||||
~EventQueue();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
28
core/fpstr.cpp
Normal file
28
core/fpstr.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
/*************************************************************************/
|
||||
/* fpstr.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
28
core/fpstr.h
Normal file
28
core/fpstr.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*************************************************************************/
|
||||
/* fpstr.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
516
core/global_constants.cpp
Normal file
516
core/global_constants.cpp
Normal file
@ -0,0 +1,516 @@
|
||||
/*************************************************************************/
|
||||
/* global_constants.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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_constants.h"
|
||||
#include "variant.h"
|
||||
#include "os/keyboard.h"
|
||||
#include "object.h"
|
||||
|
||||
struct _GlobalConstant {
|
||||
|
||||
const char *name;
|
||||
int value;
|
||||
};
|
||||
|
||||
#define BIND_GLOBAL_CONSTANT(m_constant) {#m_constant,m_constant}
|
||||
|
||||
|
||||
static _GlobalConstant _global_constants[]={
|
||||
|
||||
//{ KEY_BACKSPACE, VK_BACK },// (0x08) // backspace
|
||||
|
||||
BIND_GLOBAL_CONSTANT( MARGIN_LEFT ),
|
||||
BIND_GLOBAL_CONSTANT( MARGIN_TOP ),
|
||||
BIND_GLOBAL_CONSTANT( MARGIN_RIGHT ),
|
||||
BIND_GLOBAL_CONSTANT( MARGIN_BOTTOM ),
|
||||
BIND_GLOBAL_CONSTANT( VERTICAL ),
|
||||
BIND_GLOBAL_CONSTANT( HORIZONTAL ),
|
||||
BIND_GLOBAL_CONSTANT( HALIGN_LEFT ),
|
||||
BIND_GLOBAL_CONSTANT( HALIGN_CENTER ),
|
||||
BIND_GLOBAL_CONSTANT( HALIGN_RIGHT ),
|
||||
BIND_GLOBAL_CONSTANT( VALIGN_TOP ),
|
||||
BIND_GLOBAL_CONSTANT( VALIGN_CENTER ),
|
||||
BIND_GLOBAL_CONSTANT( VALIGN_BOTTOM ),
|
||||
|
||||
// hueg list of keys
|
||||
BIND_GLOBAL_CONSTANT( SPKEY ),
|
||||
|
||||
BIND_GLOBAL_CONSTANT( KEY_ESCAPE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_TAB ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_BACKTAB ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_BACKSPACE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_RETURN ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_ENTER ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_INSERT ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_DELETE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_PAUSE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_PRINT ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_SYSREQ ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_CLEAR ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_HOME ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_END ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_LEFT ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_UP ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_RIGHT ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_DOWN ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_PAGEUP ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_PAGEDOWN ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_SHIFT ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_CONTROL ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_META ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_ALT ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_CAPSLOCK ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_NUMLOCK ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_SCROLLLOCK ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_F1 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_F2 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_F3 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_F4 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_F5 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_F6 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_F7 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_F8 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_F9 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_F10 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_F11 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_F12 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_F13 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_F14 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_F15 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_F16 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_KP_ENTER ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_KP_MULTIPLY ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_KP_DIVIDE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_KP_SUBSTRACT ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_KP_PERIOD ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_KP_ADD ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_KP_0 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_KP_1 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_KP_2 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_KP_3 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_KP_4 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_KP_5 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_KP_6 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_KP_7 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_KP_8 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_KP_9 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_SUPER_L ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_SUPER_R ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_MENU ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_HYPER_L ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_HYPER_R ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_HELP ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_DIRECTION_L ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_DIRECTION_R ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_BACK ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_FORWARD ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_STOP ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_REFRESH ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_VOLUMEDOWN ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_VOLUMEMUTE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_VOLUMEUP ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_BASSBOOST ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_BASSUP ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_BASSDOWN ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_TREBLEUP ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_TREBLEDOWN ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_MEDIAPLAY ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_MEDIASTOP ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_MEDIAPREVIOUS ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_MEDIANEXT ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_MEDIARECORD ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_HOMEPAGE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_FAVORITES ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_SEARCH ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_STANDBY ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_OPENURL ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_LAUNCHMAIL ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_LAUNCHMEDIA ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_LAUNCH0 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_LAUNCH1 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_LAUNCH2 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_LAUNCH3 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_LAUNCH4 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_LAUNCH5 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_LAUNCH6 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_LAUNCH7 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_LAUNCH8 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_LAUNCH9 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_LAUNCHA ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_LAUNCHB ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_LAUNCHC ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_LAUNCHD ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_LAUNCHE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_LAUNCHF ),
|
||||
|
||||
BIND_GLOBAL_CONSTANT( KEY_UNKNOWN ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_SPACE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_EXCLAM ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_QUOTEDBL ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_NUMBERSIGN ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_DOLLAR ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_PERCENT ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_AMPERSAND ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_APOSTROPHE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_PARENLEFT ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_PARENRIGHT ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_ASTERISK ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_PLUS ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_COMMA ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_MINUS ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_PERIOD ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_SLASH ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_0 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_1 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_2 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_3 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_4 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_5 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_6 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_7 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_8 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_9 ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_COLON ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_SEMICOLON ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_LESS ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_EQUAL ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_GREATER ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_QUESTION ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_AT ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_A ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_B ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_C ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_D ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_E ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_F ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_G ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_H ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_I ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_J ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_K ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_L ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_M ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_N ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_O ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_P ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_Q ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_R ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_S ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_T ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_U ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_V ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_W ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_X ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_Y ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_Z ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_BRACKETLEFT ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_BACKSLASH ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_BRACKETRIGHT ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_ASCIICIRCUM ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_UNDERSCORE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_QUOTELEFT ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_BRACELEFT ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_BAR ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_BRACERIGHT ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_ASCIITILDE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_NOBREAKSPACE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_EXCLAMDOWN ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_CENT ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_STERLING ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_CURRENCY ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_YEN ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_BROKENBAR ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_SECTION ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_DIAERESIS ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_COPYRIGHT ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_ORDFEMININE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_GUILLEMOTLEFT ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_NOTSIGN ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_HYPHEN ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_REGISTERED ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_MACRON ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_DEGREE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_PLUSMINUS ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_TWOSUPERIOR ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_THREESUPERIOR ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_ACUTE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_MU ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_PARAGRAPH ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_PERIODCENTERED ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_CEDILLA ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_ONESUPERIOR ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_MASCULINE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_GUILLEMOTRIGHT ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_ONEQUARTER ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_ONEHALF ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_THREEQUARTERS ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_QUESTIONDOWN ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_AGRAVE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_AACUTE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_ACIRCUMFLEX ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_ATILDE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_ADIAERESIS ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_ARING ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_AE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_CCEDILLA ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_EGRAVE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_EACUTE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_ECIRCUMFLEX ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_EDIAERESIS ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_IGRAVE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_IACUTE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_ICIRCUMFLEX ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_IDIAERESIS ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_ETH ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_NTILDE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_OGRAVE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_OACUTE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_OCIRCUMFLEX ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_OTILDE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_ODIAERESIS ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_MULTIPLY ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_OOBLIQUE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_UGRAVE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_UACUTE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_UCIRCUMFLEX ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_UDIAERESIS ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_YACUTE ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_THORN ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_SSHARP ),
|
||||
|
||||
BIND_GLOBAL_CONSTANT( KEY_DIVISION ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_YDIAERESIS ),
|
||||
|
||||
BIND_GLOBAL_CONSTANT( KEY_CODE_MASK ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_MODIFIER_MASK ),
|
||||
|
||||
BIND_GLOBAL_CONSTANT( KEY_MASK_SHIFT ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_MASK_ALT ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_MASK_META ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_MASK_CTRL ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_MASK_KPAD ),
|
||||
BIND_GLOBAL_CONSTANT( KEY_MASK_GROUP_SWITCH ),
|
||||
|
||||
// joysticks
|
||||
BIND_GLOBAL_CONSTANT( BUTTON_LEFT ),
|
||||
BIND_GLOBAL_CONSTANT( BUTTON_RIGHT ),
|
||||
BIND_GLOBAL_CONSTANT( BUTTON_MIDDLE ),
|
||||
BIND_GLOBAL_CONSTANT( BUTTON_WHEEL_UP ),
|
||||
BIND_GLOBAL_CONSTANT( BUTTON_WHEEL_DOWN ),
|
||||
BIND_GLOBAL_CONSTANT( BUTTON_MASK_LEFT ),
|
||||
BIND_GLOBAL_CONSTANT( BUTTON_MASK_RIGHT ),
|
||||
BIND_GLOBAL_CONSTANT( BUTTON_MASK_MIDDLE ),
|
||||
|
||||
BIND_GLOBAL_CONSTANT( JOY_BUTTON_0 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_BUTTON_1 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_BUTTON_2 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_BUTTON_3 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_BUTTON_4 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_BUTTON_5 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_BUTTON_6 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_BUTTON_7 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_BUTTON_8 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_BUTTON_9 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_BUTTON_10 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_BUTTON_11 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_BUTTON_12 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_BUTTON_13 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_BUTTON_14 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_BUTTON_15 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_BUTTON_MAX ),
|
||||
|
||||
BIND_GLOBAL_CONSTANT( JOY_SNES_A ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_SNES_B ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_SNES_X ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_SNES_Y ),
|
||||
|
||||
BIND_GLOBAL_CONSTANT( JOY_SONY_CIRCLE ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_SONY_X ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_SONY_SQUARE ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_SONY_TRIANGLE ),
|
||||
|
||||
BIND_GLOBAL_CONSTANT( JOY_SEGA_B ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_SEGA_A ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_SEGA_X ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_SEGA_Y ),
|
||||
|
||||
BIND_GLOBAL_CONSTANT( JOY_XBOX_B ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_XBOX_A ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_XBOX_X ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_XBOX_Y ),
|
||||
|
||||
BIND_GLOBAL_CONSTANT( JOY_DS_A ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_DS_B ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_DS_X ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_DS_Y ),
|
||||
|
||||
BIND_GLOBAL_CONSTANT( JOY_SELECT ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_START ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_DPAD_UP ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_DPAD_DOWN ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_DPAD_LEFT ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_DPAD_RIGHT ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_L ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_L2 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_L3 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_R ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_R2 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_R3 ),
|
||||
|
||||
BIND_GLOBAL_CONSTANT( JOY_AXIS_0 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_AXIS_1 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_AXIS_2 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_AXIS_3 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_AXIS_4 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_AXIS_5 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_AXIS_6 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_AXIS_7 ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_AXIS_MAX ),
|
||||
|
||||
BIND_GLOBAL_CONSTANT( JOY_ANALOG_0_X ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_ANALOG_0_Y ),
|
||||
|
||||
BIND_GLOBAL_CONSTANT( JOY_ANALOG_1_X ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_ANALOG_1_Y ),
|
||||
|
||||
BIND_GLOBAL_CONSTANT( JOY_ANALOG_2_X ),
|
||||
BIND_GLOBAL_CONSTANT( JOY_ANALOG_2_Y ),
|
||||
|
||||
|
||||
// error list
|
||||
|
||||
BIND_GLOBAL_CONSTANT( OK ),
|
||||
BIND_GLOBAL_CONSTANT( FAILED ), ///< Generic fail error
|
||||
BIND_GLOBAL_CONSTANT( ERR_UNAVAILABLE ), ///< What is requested is unsupported/unavailable
|
||||
BIND_GLOBAL_CONSTANT( ERR_UNCONFIGURED ), ///< The object being used hasnt been properly set up yet
|
||||
BIND_GLOBAL_CONSTANT( ERR_UNAUTHORIZED ), ///< Missing credentials for requested resource
|
||||
BIND_GLOBAL_CONSTANT( ERR_PARAMETER_RANGE_ERROR ), ///< Parameter given out of range
|
||||
BIND_GLOBAL_CONSTANT( ERR_OUT_OF_MEMORY ), ///< Out of memory
|
||||
BIND_GLOBAL_CONSTANT( ERR_FILE_NOT_FOUND ),
|
||||
BIND_GLOBAL_CONSTANT( ERR_FILE_BAD_DRIVE ),
|
||||
BIND_GLOBAL_CONSTANT( ERR_FILE_BAD_PATH ),
|
||||
BIND_GLOBAL_CONSTANT( ERR_FILE_NO_PERMISSION ),
|
||||
BIND_GLOBAL_CONSTANT( ERR_FILE_ALREADY_IN_USE ),
|
||||
BIND_GLOBAL_CONSTANT( ERR_FILE_CANT_OPEN ),
|
||||
BIND_GLOBAL_CONSTANT( ERR_FILE_CANT_WRITE ),
|
||||
BIND_GLOBAL_CONSTANT( ERR_FILE_CANT_READ ),
|
||||
BIND_GLOBAL_CONSTANT( ERR_FILE_UNRECOGNIZED ),
|
||||
BIND_GLOBAL_CONSTANT( ERR_FILE_CORRUPT ),
|
||||
BIND_GLOBAL_CONSTANT( ERR_FILE_EOF ),
|
||||
BIND_GLOBAL_CONSTANT( ERR_CANT_OPEN ), ///< Can't open a resource/socket/file
|
||||
BIND_GLOBAL_CONSTANT( ERR_CANT_CREATE ),
|
||||
BIND_GLOBAL_CONSTANT( ERROR_QUERY_FAILED ),
|
||||
BIND_GLOBAL_CONSTANT( ERR_ALREADY_IN_USE ),
|
||||
BIND_GLOBAL_CONSTANT( ERR_LOCKED ), ///< resource is locked
|
||||
BIND_GLOBAL_CONSTANT( ERR_TIMEOUT ),
|
||||
BIND_GLOBAL_CONSTANT( ERR_CANT_AQUIRE_RESOURCE ),
|
||||
BIND_GLOBAL_CONSTANT( ERR_INVALID_DATA ), ///< Data passed is invalid
|
||||
BIND_GLOBAL_CONSTANT( ERR_INVALID_PARAMETER ), ///< Parameter passed is invalid
|
||||
BIND_GLOBAL_CONSTANT( ERR_ALREADY_EXISTS ), ///< When adding ), item already exists
|
||||
BIND_GLOBAL_CONSTANT( ERR_DOES_NOT_EXIST ), ///< When retrieving/erasing ), it item does not exist
|
||||
BIND_GLOBAL_CONSTANT( ERR_DATABASE_CANT_READ ), ///< database is full
|
||||
BIND_GLOBAL_CONSTANT( ERR_DATABASE_CANT_WRITE ), ///< database is full
|
||||
BIND_GLOBAL_CONSTANT( ERR_COMPILATION_FAILED ),
|
||||
BIND_GLOBAL_CONSTANT( ERR_METHOD_NOT_FOUND ),
|
||||
BIND_GLOBAL_CONSTANT( ERR_LINK_FAILED ),
|
||||
BIND_GLOBAL_CONSTANT( ERR_SCRIPT_FAILED ),
|
||||
BIND_GLOBAL_CONSTANT( ERR_CYCLIC_LINK ),
|
||||
BIND_GLOBAL_CONSTANT( ERR_BUSY ),
|
||||
BIND_GLOBAL_CONSTANT( ERR_HELP ), ///< user requested help!!
|
||||
BIND_GLOBAL_CONSTANT( ERR_BUG ), ///< a bug in the software certainly happened ), due to a double check failing or unexpected behavior.
|
||||
BIND_GLOBAL_CONSTANT( ERR_WTF ),
|
||||
|
||||
BIND_GLOBAL_CONSTANT( PROPERTY_HINT_NONE ),
|
||||
BIND_GLOBAL_CONSTANT( PROPERTY_HINT_RANGE ),
|
||||
BIND_GLOBAL_CONSTANT( PROPERTY_HINT_EXP_RANGE ),
|
||||
BIND_GLOBAL_CONSTANT( PROPERTY_HINT_ENUM ),
|
||||
BIND_GLOBAL_CONSTANT( PROPERTY_HINT_LENGTH ),
|
||||
BIND_GLOBAL_CONSTANT( PROPERTY_HINT_FLAGS ),
|
||||
BIND_GLOBAL_CONSTANT( PROPERTY_HINT_FILE ),
|
||||
BIND_GLOBAL_CONSTANT( PROPERTY_HINT_DIR ),
|
||||
BIND_GLOBAL_CONSTANT( PROPERTY_HINT_RESOURCE_TYPE ),
|
||||
|
||||
BIND_GLOBAL_CONSTANT( PROPERTY_USAGE_STORAGE ),
|
||||
BIND_GLOBAL_CONSTANT( PROPERTY_USAGE_STORAGE ),
|
||||
BIND_GLOBAL_CONSTANT( PROPERTY_USAGE_EDITOR ),
|
||||
BIND_GLOBAL_CONSTANT( PROPERTY_USAGE_NETWORK ),
|
||||
BIND_GLOBAL_CONSTANT( PROPERTY_USAGE_DEFAULT ),
|
||||
{"TYPE_NIL",Variant::NIL},
|
||||
{"TYPE_BOOL",Variant::BOOL},
|
||||
{"TYPE_INT",Variant::INT},
|
||||
{"TYPE_REAL",Variant::REAL},
|
||||
{"TYPE_STRING",Variant::STRING},
|
||||
{"TYPE_VECTOR2",Variant::VECTOR2}, // 5
|
||||
{"TYPE_RECT2",Variant::RECT2},
|
||||
{"TYPE_VECTOR3",Variant::VECTOR3},
|
||||
{"TYPE_MATRIX32",Variant::MATRIX32},
|
||||
{"TYPE_PLANE",Variant::PLANE},
|
||||
{"TYPE_QUAT",Variant::QUAT}, // 10
|
||||
{"TYPE_AABB",Variant::_AABB}, //sorry naming convention fail :( not like it's used often
|
||||
{"TYPE_MATRIX3",Variant::MATRIX3},
|
||||
{"TYPE_TRANSFORM",Variant::TRANSFORM},
|
||||
{"TYPE_COLOR",Variant::COLOR},
|
||||
{"TYPE_IMAGE",Variant::IMAGE}, // 15
|
||||
{"TYPE_NODE_PATH",Variant::NODE_PATH},
|
||||
{"TYPE_RID",Variant::_RID},
|
||||
{"TYPE_OBJECT",Variant::OBJECT},
|
||||
{"TYPE_INPUT_EVENT",Variant::INPUT_EVENT},
|
||||
{"TYPE_DICTIONARY",Variant::DICTIONARY}, // 20
|
||||
{"TYPE_ARRAY",Variant::ARRAY},
|
||||
{"TYPE_RAW_ARRAY",Variant::RAW_ARRAY},
|
||||
{"TYPE_INT_ARRAY",Variant::INT_ARRAY},
|
||||
{"TYPE_REAL_ARRAY",Variant::REAL_ARRAY},
|
||||
{"TYPE_STRING_ARRAY",Variant::STRING_ARRAY}, // 25
|
||||
{"TYPE_VECTOR2_ARRAY",Variant::VECTOR2_ARRAY},
|
||||
{"TYPE_VECTOR3_ARRAY",Variant::VECTOR3_ARRAY},
|
||||
{"TYPE_COLOR_ARRAY",Variant::COLOR_ARRAY},
|
||||
{"TYPE_MAX",Variant::VARIANT_MAX},
|
||||
{NULL,0}
|
||||
|
||||
};
|
||||
|
||||
int GlobalConstants::get_global_constant_count() {
|
||||
|
||||
int i=0;
|
||||
while(_global_constants[i].name)
|
||||
i++;
|
||||
return i;
|
||||
|
||||
}
|
||||
|
||||
const char *GlobalConstants::get_global_constant_name(int p_idx) {
|
||||
|
||||
return _global_constants[p_idx].name;
|
||||
}
|
||||
|
||||
int GlobalConstants::get_global_constant_value(int p_idx) {
|
||||
|
||||
return _global_constants[p_idx].value;
|
||||
}
|
||||
|
||||
|
41
core/global_constants.h
Normal file
41
core/global_constants.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*************************************************************************/
|
||||
/* global_constants.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 GLOBAL_CONSTANTS_H
|
||||
#define GLOBAL_CONSTANTS_H
|
||||
|
||||
|
||||
class GlobalConstants {
|
||||
public:
|
||||
|
||||
static int get_global_constant_count();
|
||||
static const char *get_global_constant_name(int p_idx);
|
||||
static int get_global_constant_value(int p_idx);
|
||||
};
|
||||
|
||||
#endif // GLOBAL_CONSTANTS_H
|
1447
core/globals.cpp
Normal file
1447
core/globals.cpp
Normal file
File diff suppressed because it is too large
Load Diff
138
core/globals.h
Normal file
138
core/globals.h
Normal file
@ -0,0 +1,138 @@
|
||||
/*************************************************************************/
|
||||
/* globals.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 GLOBALS_H
|
||||
#define GLOBALS_H
|
||||
|
||||
#include "object.h"
|
||||
#include "set.h"
|
||||
#include "os/thread_safe.h"
|
||||
/**
|
||||
@author Juan Linietsky <reduzio@gmail.com>
|
||||
*/
|
||||
|
||||
|
||||
class Globals : public Object {
|
||||
|
||||
OBJ_TYPE( Globals, Object );
|
||||
_THREAD_SAFE_CLASS_
|
||||
|
||||
public:
|
||||
|
||||
typedef Map<String,Variant> CustomMap;
|
||||
|
||||
struct Singleton {
|
||||
StringName name;
|
||||
Object *ptr;
|
||||
Singleton(const StringName& p_name=StringName(), Object *p_ptr=NULL) { name=p_name; ptr=p_ptr; }
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
struct VariantContainer {
|
||||
int order;
|
||||
bool persist;
|
||||
Variant variant;
|
||||
bool hide_from_editor;
|
||||
bool overrided;
|
||||
VariantContainer(){ order=0; hide_from_editor=false; persist=false; overrided=false; }
|
||||
VariantContainer(const Variant& p_variant, int p_order, bool p_persist=false) { variant=p_variant; order=p_order; hide_from_editor=false; persist=p_persist; overrided=false; }
|
||||
};
|
||||
|
||||
int last_order;
|
||||
HashMap<String,VariantContainer> props;
|
||||
String resource_path;
|
||||
HashMap<String,PropertyInfo> custom_prop_info;
|
||||
bool disable_platform_override;
|
||||
|
||||
|
||||
bool _set(const StringName& p_name, const Variant& p_value);
|
||||
bool _get(const StringName& p_name,Variant &r_ret) const;
|
||||
void _get_property_list(List<PropertyInfo> *p_list) const;
|
||||
|
||||
static Globals *singleton;
|
||||
|
||||
Error _load_settings(const String p_path);
|
||||
Error _load_settings_binary(const String p_path);
|
||||
|
||||
Error _save_settings_text(const String& p_file,const Map<String,List<String> > &props,const CustomMap& p_custom=CustomMap());
|
||||
Error _save_settings_binary(const String& p_file,const Map<String,List<String> > &props,const CustomMap& p_custom=CustomMap());
|
||||
|
||||
List<Singleton> singletons;
|
||||
|
||||
|
||||
bool _load_resource_pack(const String& p_pack);
|
||||
|
||||
protected:
|
||||
|
||||
static void _bind_methods();
|
||||
public:
|
||||
|
||||
|
||||
bool has(String p_var) const;
|
||||
String localize_path(const String& p_path) const;
|
||||
String globalize_path(const String& p_path) const;
|
||||
|
||||
void set_persisting(const String& p_name, bool p_persist);
|
||||
bool is_persisting(const String& p_name) const;
|
||||
|
||||
String get_resource_path() const;
|
||||
|
||||
static Globals *get_singleton();
|
||||
|
||||
void clear(const String& p_name);
|
||||
int get_order(const String& p_name) const;
|
||||
void set_order(const String& p_name, int p_order);
|
||||
|
||||
Error setup(const String& p_path);
|
||||
|
||||
Error save_custom(const String& p_path="",const CustomMap& p_custom=CustomMap(),const Set<String>& p_ignore_masks=Set<String>());
|
||||
Error save();
|
||||
void set_custom_property_info(const String& p_prop,const PropertyInfo& p_info);
|
||||
|
||||
void add_singleton(const Singleton &p_singleton);
|
||||
void get_singletons(List<Singleton> *p_singletons);
|
||||
|
||||
bool has_singleton(const String& p_name) const;
|
||||
|
||||
Vector<String> get_optimizer_presets() const;
|
||||
|
||||
void set_disable_platform_override(bool p_disable);
|
||||
Object* get_singleton_object(const String& p_name) const;
|
||||
|
||||
void register_global_defaults();
|
||||
|
||||
Globals();
|
||||
~Globals();
|
||||
|
||||
};
|
||||
|
||||
//not a macro any longer
|
||||
Variant _GLOBAL_DEF( const String& p_var, const Variant& p_default);
|
||||
#define GLOBAL_DEF(m_var,m_value) _GLOBAL_DEF(m_var,m_value)
|
||||
#endif
|
630
core/hash_map.h
Normal file
630
core/hash_map.h
Normal file
@ -0,0 +1,630 @@
|
||||
/*************************************************************************/
|
||||
/* hash_map.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 HASH_MAP_H
|
||||
#define HASH_MAP_H
|
||||
|
||||
#include "hashfuncs.h"
|
||||
#include "error_macros.h"
|
||||
#include "ustring.h"
|
||||
#include "os/memory.h"
|
||||
#include "list.h"
|
||||
|
||||
|
||||
class HashMapHahserDefault {
|
||||
public:
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const char *p_cstr) { return hash_djb2(p_cstr); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const uint64_t p_int) {
|
||||
uint64_t v=p_int;
|
||||
v = (~v) + (v << 18); // v = (v << 18) - v - 1;
|
||||
v = v ^ (v >> 31);
|
||||
v = v * 21; // v = (v + (v << 2)) + (v << 4);
|
||||
v = v ^ (v >> 11);
|
||||
v = v + (v << 6);
|
||||
v = v ^ (v >> 22);
|
||||
return (int) v;
|
||||
}
|
||||
static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash(uint64_t(p_int)); }
|
||||
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash(const uint32_t p_int) { return p_int; }
|
||||
static _FORCE_INLINE_ uint32_t hash(const int32_t p_int) { return (uint32_t)p_int; }
|
||||
static _FORCE_INLINE_ uint32_t hash(const uint16_t p_int) { return p_int; }
|
||||
static _FORCE_INLINE_ uint32_t hash(const int16_t p_int) { return (uint32_t)p_int; }
|
||||
static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return p_int; }
|
||||
static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return (uint32_t)p_int; }
|
||||
static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return (uint32_t)p_wchar; }
|
||||
// static _FORCE_INLINE_ uint32_t hash(const void* p_ptr) { return uint32_t(uint64_t(p_ptr))*(0x9e3779b1L); }
|
||||
};
|
||||
|
||||
/**
|
||||
* @class HashMap
|
||||
* @author Juan Linietsky <reduzio@gmail.com>
|
||||
*
|
||||
* Implementation of a standard Hashing HashMap, for quick lookups of Data associated with a Key.
|
||||
* The implementation provides hashers for the default types, if you need a special kind of hasher, provide
|
||||
* your own.
|
||||
* @param TKey Key, search is based on it, needs to be hasheable. It is unique in this container.
|
||||
* @param TData Data, data associated with the key
|
||||
* @param Hasher Hasher object, needs to provide a valid static hash function for TKey
|
||||
* @param MIN_HASH_TABLE_POWER Miminum size of the hash table, as a power of two. You rarely need to change this parameter.
|
||||
* @param RELATIONSHIP Relationship at which the hash table is resized. if amount of elements is RELATIONSHIP
|
||||
* times bigger than the hash table, table is resized to solve this condition. if RELATIONSHIP is zero, table is always MIN_HASH_TABLE_POWER.
|
||||
*
|
||||
*/
|
||||
|
||||
template<class TKey, class TData, class Hasher=HashMapHahserDefault,uint8_t MIN_HASH_TABLE_POWER=3,uint8_t RELATIONSHIP=8>
|
||||
class HashMap {
|
||||
public:
|
||||
|
||||
struct Pair {
|
||||
|
||||
TKey key;
|
||||
TData data;
|
||||
|
||||
Pair() {}
|
||||
Pair(const TKey& p_key, const TData& p_data) { key=p_key; data=p_data; }
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
struct Entry {
|
||||
|
||||
uint32_t hash;
|
||||
Entry *next;
|
||||
Pair pair;
|
||||
|
||||
Entry() { next=0; }
|
||||
};
|
||||
|
||||
Entry **hash_table;
|
||||
uint8_t hash_table_power;
|
||||
uint32_t elements;
|
||||
|
||||
void make_hash_table() {
|
||||
|
||||
ERR_FAIL_COND( hash_table );
|
||||
|
||||
|
||||
hash_table = memnew_arr( Entry*, (1<<MIN_HASH_TABLE_POWER) );
|
||||
|
||||
hash_table_power = MIN_HASH_TABLE_POWER;
|
||||
elements=0;
|
||||
for (int i=0;i<(1<<MIN_HASH_TABLE_POWER);i++)
|
||||
hash_table[i]=0;
|
||||
}
|
||||
|
||||
void erase_hash_table() {
|
||||
|
||||
ERR_FAIL_COND(elements);
|
||||
|
||||
memdelete_arr( hash_table );
|
||||
hash_table=0;
|
||||
hash_table_power=0;
|
||||
elements=0;
|
||||
}
|
||||
|
||||
void check_hash_table() {
|
||||
|
||||
int new_hash_table_power=-1;
|
||||
|
||||
if ((int)elements > ( (1<<hash_table_power) * RELATIONSHIP ) ) {
|
||||
/* rehash up */
|
||||
new_hash_table_power=hash_table_power+1;
|
||||
|
||||
while( (int)elements > ( (1<<new_hash_table_power) * RELATIONSHIP ) ) {
|
||||
|
||||
new_hash_table_power++;
|
||||
}
|
||||
|
||||
} else if ( (hash_table_power>(int)MIN_HASH_TABLE_POWER) && ((int)elements < ( (1<<(hash_table_power-1)) * RELATIONSHIP ) ) ) {
|
||||
|
||||
/* rehash down */
|
||||
new_hash_table_power=hash_table_power-1;
|
||||
|
||||
while( (int)elements < ( (1<<(new_hash_table_power-1)) * RELATIONSHIP ) ) {
|
||||
|
||||
new_hash_table_power--;
|
||||
}
|
||||
|
||||
if (new_hash_table_power<(int)MIN_HASH_TABLE_POWER)
|
||||
new_hash_table_power=MIN_HASH_TABLE_POWER;
|
||||
}
|
||||
|
||||
|
||||
if (new_hash_table_power==-1)
|
||||
return;
|
||||
|
||||
Entry ** new_hash_table = memnew_arr( Entry*, (1<<new_hash_table_power) );
|
||||
if (!new_hash_table) {
|
||||
|
||||
ERR_PRINT("Out of Memory");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i=0;i<(1<<new_hash_table_power);i++) {
|
||||
|
||||
new_hash_table[i]=0;
|
||||
}
|
||||
|
||||
for (int i=0;i<(1<<hash_table_power);i++) {
|
||||
|
||||
while( hash_table[i] ) {
|
||||
|
||||
Entry *se=hash_table[i];
|
||||
hash_table[i]=se->next;
|
||||
int new_pos = se->hash & ((1<<new_hash_table_power)-1);
|
||||
se->next=new_hash_table[new_pos];
|
||||
new_hash_table[new_pos]=se;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (hash_table)
|
||||
memdelete_arr( hash_table );
|
||||
hash_table=new_hash_table;
|
||||
hash_table_power=new_hash_table_power;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* I want to have only one function.. */
|
||||
_FORCE_INLINE_ const Entry * get_entry( const TKey& p_key ) const {
|
||||
|
||||
uint32_t hash = Hasher::hash( p_key );
|
||||
uint32_t index = hash&((1<<hash_table_power)-1);
|
||||
|
||||
Entry *e = hash_table[index];
|
||||
|
||||
while (e) {
|
||||
|
||||
/* checking hash first avoids comparing key, which may take longer */
|
||||
if (e->hash == hash && e->pair.key == p_key ) {
|
||||
|
||||
/* the pair exists in this hashtable, so just update data */
|
||||
return e;
|
||||
}
|
||||
|
||||
e=e->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Entry * create_entry(const TKey& p_key) {
|
||||
|
||||
/* if entry doesn't exist, create it */
|
||||
Entry *e = memnew( Entry );
|
||||
ERR_FAIL_COND_V(!e,NULL); /* out of memory */
|
||||
uint32_t hash = Hasher::hash( p_key );
|
||||
uint32_t index = hash&((1<<hash_table_power)-1);
|
||||
e->next = hash_table[index];
|
||||
e->hash = hash;
|
||||
e->pair.key=p_key;
|
||||
|
||||
hash_table[index]=e;
|
||||
elements++;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
void copy_from(const HashMap& p_t) {
|
||||
|
||||
if (&p_t==this)
|
||||
return; /* much less bother with that */
|
||||
|
||||
clear();
|
||||
|
||||
if (!p_t.hash_table || p_t.hash_table_power==0)
|
||||
return; /* not copying from empty table */
|
||||
|
||||
hash_table = memnew_arr(Entry*,1<<p_t.hash_table_power);
|
||||
hash_table_power=p_t.hash_table_power;
|
||||
elements=p_t.elements;
|
||||
|
||||
for (int i=0;i<( 1<<p_t.hash_table_power );i++) {
|
||||
|
||||
hash_table[i]=NULL;
|
||||
/* elements will be in the reverse order, but it doesn't matter */
|
||||
|
||||
const Entry *e = p_t.hash_table[i];
|
||||
|
||||
while(e) {
|
||||
|
||||
Entry *le = memnew( Entry ); /* local entry */
|
||||
|
||||
*le=*e; /* copy data */
|
||||
|
||||
/* add to list and reassign pointers */
|
||||
le->next=hash_table[i];
|
||||
hash_table[i]=le;
|
||||
|
||||
e=e->next;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
public:
|
||||
|
||||
|
||||
void set( const TKey& p_key, const TData& p_data ) {
|
||||
|
||||
set( Pair( p_key, p_data ) );
|
||||
|
||||
}
|
||||
|
||||
void set( const Pair& p_pair ) {
|
||||
|
||||
if (!hash_table)
|
||||
make_hash_table(); // if no table, make one
|
||||
else
|
||||
check_hash_table(); // perform mantenience routine
|
||||
|
||||
/* As said, i want to have only one get_entry */
|
||||
Entry *e = const_cast<Entry*>( get_entry(p_pair.key) );
|
||||
|
||||
/* if we made it up to here, the pair doesn't exist, create and assign */
|
||||
|
||||
if (!e) {
|
||||
|
||||
e=create_entry(p_pair.key);
|
||||
if (!e)
|
||||
return;
|
||||
}
|
||||
|
||||
e->pair.data = p_pair.data;
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool has( const TKey& p_key ) const {
|
||||
|
||||
return getptr(p_key)!=NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a key from data, return a const reference.
|
||||
* WARNING: this doesn't check errors, use either getptr and check NULL, or check
|
||||
* first with has(key)
|
||||
*/
|
||||
|
||||
const TData& get( const TKey& p_key ) const {
|
||||
|
||||
const TData* res = getptr(p_key);
|
||||
ERR_FAIL_COND_V(!res,*res);
|
||||
return *res;
|
||||
}
|
||||
|
||||
TData& get( const TKey& p_key ) {
|
||||
|
||||
TData* res = getptr(p_key);
|
||||
ERR_FAIL_COND_V(!res,*res);
|
||||
return *res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as get, except it can return NULL when item was not found.
|
||||
* This is mainly used for speed purposes.
|
||||
*/
|
||||
|
||||
|
||||
_FORCE_INLINE_ TData* getptr( const TKey& p_key ) {
|
||||
|
||||
if (!hash_table)
|
||||
return NULL;
|
||||
|
||||
Entry *e=const_cast<Entry*>(get_entry(p_key ));
|
||||
|
||||
if (e)
|
||||
return &e->pair.data;
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ const TData* getptr( const TKey& p_key ) const {
|
||||
|
||||
if (!hash_table)
|
||||
return NULL;
|
||||
|
||||
const Entry *e=const_cast<Entry*>(get_entry(p_key ));
|
||||
|
||||
if (e)
|
||||
return &e->pair.data;
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as get, except it can return NULL when item was not found.
|
||||
* This version is custom, will take a hash and a custom key (that should support operator==()
|
||||
*/
|
||||
|
||||
template<class C>
|
||||
_FORCE_INLINE_ TData* custom_getptr( C p_custom_key,uint32_t p_custom_hash ) {
|
||||
|
||||
if (!hash_table)
|
||||
return NULL;
|
||||
|
||||
uint32_t hash = p_custom_hash;
|
||||
uint32_t index = hash&((1<<hash_table_power)-1);
|
||||
|
||||
Entry *e = hash_table[index];
|
||||
|
||||
while (e) {
|
||||
|
||||
/* checking hash first avoids comparing key, which may take longer */
|
||||
if (e->hash == hash && e->pair.key == p_custom_key ) {
|
||||
|
||||
/* the pair exists in this hashtable, so just update data */
|
||||
return &e->pair.data;
|
||||
}
|
||||
|
||||
e=e->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
_FORCE_INLINE_ const TData* custom_getptr( C p_custom_key,uint32_t p_custom_hash ) const {
|
||||
|
||||
if (!hash_table)
|
||||
return NULL;
|
||||
|
||||
uint32_t hash = p_custom_hash;
|
||||
uint32_t index = hash&((1<<hash_table_power)-1);
|
||||
|
||||
const Entry *e = hash_table[index];
|
||||
|
||||
while (e) {
|
||||
|
||||
/* checking hash first avoids comparing key, which may take longer */
|
||||
if (e->hash == hash && e->pair.key == p_custom_key ) {
|
||||
|
||||
/* the pair exists in this hashtable, so just update data */
|
||||
return &e->pair.data;
|
||||
}
|
||||
|
||||
e=e->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Erase an item, return true if erasing was succesful
|
||||
*/
|
||||
|
||||
bool erase( const TKey& p_key ) {
|
||||
|
||||
if (!hash_table)
|
||||
return false;
|
||||
|
||||
uint32_t hash = Hasher::hash( p_key );
|
||||
uint32_t index = hash&((1<<hash_table_power)-1);
|
||||
|
||||
|
||||
Entry *e = hash_table[index];
|
||||
Entry *p=NULL;
|
||||
while (e) {
|
||||
|
||||
/* checking hash first avoids comparing key, which may take longer */
|
||||
if (e->hash == hash && e->pair.key == p_key ) {
|
||||
|
||||
if (p) {
|
||||
|
||||
p->next=e->next;
|
||||
} else {
|
||||
//begin of list
|
||||
hash_table[index]=e->next;
|
||||
}
|
||||
|
||||
memdelete(e);
|
||||
elements--;
|
||||
|
||||
if (elements==0)
|
||||
erase_hash_table();
|
||||
else
|
||||
check_hash_table();
|
||||
return true;
|
||||
}
|
||||
|
||||
p=e;
|
||||
e=e->next;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
inline const TData& operator[](const TKey& p_key) const { //constref
|
||||
|
||||
return get(p_key);
|
||||
}
|
||||
inline TData& operator[](const TKey& p_key ) { //assignment
|
||||
|
||||
if (!hash_table)
|
||||
make_hash_table(); // if no table, make one
|
||||
else
|
||||
check_hash_table(); // perform mantenience routine
|
||||
|
||||
Entry *e = const_cast<Entry*>( get_entry(p_key) );
|
||||
|
||||
/* if we made it up to here, the pair doesn't exist, create */
|
||||
if (!e) {
|
||||
|
||||
e=create_entry(p_key);
|
||||
if (!e)
|
||||
return *(TData*)NULL; /* panic! */
|
||||
}
|
||||
|
||||
return e->pair.data;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next key to p_key, and the first key if p_key is null.
|
||||
* Returns a pointer to the next key if found, NULL otherwise.
|
||||
* Adding/Removing elements while iterating will, of course, have unexpected results, don't do it.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* const TKey *k=NULL;
|
||||
*
|
||||
* while( (k=table.next(k)) ) {
|
||||
*
|
||||
* print( *k );
|
||||
* }
|
||||
*
|
||||
*/
|
||||
const TKey* next(const TKey* p_key) const {
|
||||
|
||||
if (!hash_table) return NULL;
|
||||
|
||||
if (!p_key) { /* get the first key */
|
||||
|
||||
for (int i=0;i<(1<<hash_table_power);i++) {
|
||||
|
||||
if (hash_table[i]) {
|
||||
return &hash_table[i]->pair.key;
|
||||
}
|
||||
}
|
||||
|
||||
} else { /* get the next key */
|
||||
|
||||
const Entry *e = get_entry( *p_key );
|
||||
ERR_FAIL_COND_V( !e, NULL ); /* invalid key supplied */
|
||||
|
||||
if (e->next) {
|
||||
/* if there is a "next" in the list, return that */
|
||||
return &e->next->pair.key;
|
||||
} else {
|
||||
/* go to next entries */
|
||||
uint32_t index = e->hash&((1<<hash_table_power)-1);
|
||||
index++;
|
||||
for (int i=index;i<(1<<hash_table_power);i++) {
|
||||
|
||||
if (hash_table[i]) {
|
||||
return &hash_table[i]->pair.key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* nothing found, was at end */
|
||||
|
||||
}
|
||||
|
||||
|
||||
return NULL; /* nothing found */
|
||||
}
|
||||
|
||||
inline unsigned int size() const {
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
inline bool empty() const {
|
||||
|
||||
return elements==0;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
|
||||
/* clean up */
|
||||
if (hash_table) {
|
||||
for (int i=0;i<(1<<hash_table_power);i++) {
|
||||
|
||||
while (hash_table[i]) {
|
||||
|
||||
Entry *e=hash_table[i];
|
||||
hash_table[i]=e->next;
|
||||
memdelete( e );
|
||||
}
|
||||
}
|
||||
|
||||
memdelete_arr( hash_table );
|
||||
}
|
||||
|
||||
hash_table=0;
|
||||
hash_table_power=0;
|
||||
elements=0;
|
||||
}
|
||||
|
||||
|
||||
void operator=(const HashMap& p_table) {
|
||||
|
||||
copy_from(p_table);
|
||||
}
|
||||
|
||||
HashMap() {
|
||||
hash_table=NULL;
|
||||
elements=0;
|
||||
hash_table_power=0;
|
||||
}
|
||||
|
||||
void get_key_list(List<TKey> *p_keys) const {
|
||||
if (!hash_table)
|
||||
return;
|
||||
for(int i=0;i<(1<<hash_table_power);i++) {
|
||||
|
||||
Entry *e=hash_table[i];
|
||||
while(e) {
|
||||
p_keys->push_back(e->pair.key);
|
||||
e=e->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HashMap(const HashMap& p_table) {
|
||||
|
||||
hash_table=NULL;
|
||||
elements=0;
|
||||
hash_table_power=0;
|
||||
|
||||
copy_from(p_table);
|
||||
|
||||
}
|
||||
|
||||
~HashMap() {
|
||||
|
||||
clear();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
116
core/hashfuncs.h
Normal file
116
core/hashfuncs.h
Normal file
@ -0,0 +1,116 @@
|
||||
/*************************************************************************/
|
||||
/* hashfuncs.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 HASHFUNCS_H
|
||||
#define HASHFUNCS_H
|
||||
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
/**
|
||||
* Hashing functions
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* DJB2 Hash function
|
||||
* @param C String
|
||||
* @return 32-bits hashcode
|
||||
*/
|
||||
static inline uint32_t hash_djb2(const char *p_cstr) {
|
||||
|
||||
const unsigned char* chr=(const unsigned char*)p_cstr;
|
||||
uint32_t hash = 5381;
|
||||
uint32_t c;
|
||||
|
||||
while ((c = *chr++))
|
||||
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static inline uint32_t hash_djb2_buffer(uint8_t *p_buff, int p_len) {
|
||||
|
||||
uint32_t hash = 5381;
|
||||
|
||||
for(int i=0;i<p_len;i++)
|
||||
hash = ((hash << 5) + hash) + p_buff[i]; /* hash * 33 + c */
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static inline uint32_t hash_djb2_one_32(uint32_t p_in,uint32_t p_prev=5381) {
|
||||
|
||||
return ((p_prev<<5)+p_prev)+p_in;
|
||||
}
|
||||
|
||||
static inline uint32_t hash_djb2_one_float(float p_in,uint32_t p_prev=5381) {
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.f=p_in;
|
||||
|
||||
return ((p_prev<<5)+p_prev)+u.i;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static inline uint32_t make_uint32_t(T p_in) {
|
||||
|
||||
union {
|
||||
T t;
|
||||
uint32_t _u32;
|
||||
} _u;
|
||||
_u._u32=0;
|
||||
_u.t=p_in;
|
||||
return _u._u32;
|
||||
}
|
||||
|
||||
|
||||
static inline uint64_t hash_djb2_one_64(uint64_t p_in,uint64_t p_prev=5381) {
|
||||
|
||||
return ((p_prev<<5)+p_prev)+p_in;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
static inline uint64_t make_uint64_t(T p_in) {
|
||||
|
||||
union {
|
||||
T t;
|
||||
uint64_t _u64;
|
||||
} _u;
|
||||
_u._u64=0; // in case p_in is smaller
|
||||
|
||||
_u.t=p_in;
|
||||
return _u._u64;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
1737
core/image.cpp
Normal file
1737
core/image.cpp
Normal file
File diff suppressed because it is too large
Load Diff
336
core/image.h
Normal file
336
core/image.h
Normal file
@ -0,0 +1,336 @@
|
||||
/*************************************************************************/
|
||||
/* image.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "dvector.h"
|
||||
#include "color.h"
|
||||
#include "math_2d.h"
|
||||
/**
|
||||
* @author Juan Linietsky <reduzio@gmail.com>
|
||||
*
|
||||
* Image storage class. This is used to store an image in user memory, as well as
|
||||
* providing some basic methods for image manipulation.
|
||||
* Images can be loaded from a file, or registered into the Render object as textures.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
class Image {
|
||||
|
||||
enum {
|
||||
MAX_WIDTH=4096, // force a limit somehow
|
||||
MAX_HEIGHT=4096 // force a limit somehow
|
||||
};
|
||||
public:
|
||||
|
||||
enum Format {
|
||||
FORMAT_GRAYSCALE, ///< one byte per pixel, 0-255
|
||||
FORMAT_INTENSITY, ///< one byte per pixel, 0-255
|
||||
FORMAT_GRAYSCALE_ALPHA, ///< two bytes per pixel, 0-255. alpha 0-255
|
||||
FORMAT_RGB, ///< one byte R, one byte G, one byte B
|
||||
FORMAT_RGBA, ///< one byte R, one byte G, one byte B, one byte A
|
||||
FORMAT_INDEXED, ///< index byte 0-256, and after image end, 256*3 bytes of palette
|
||||
FORMAT_INDEXED_ALPHA, ///< index byte 0-256, and after image end, 256*4 bytes of palette (alpha)
|
||||
FORMAT_YUV_422,
|
||||
FORMAT_YUV_444,
|
||||
FORMAT_BC1, // DXT1
|
||||
FORMAT_BC2, // DXT3
|
||||
FORMAT_BC3, // DXT5
|
||||
FORMAT_BC4, // ATI1
|
||||
FORMAT_BC5, // ATI2
|
||||
FORMAT_PVRTC2,
|
||||
FORMAT_PVRTC2_ALPHA,
|
||||
FORMAT_PVRTC4,
|
||||
FORMAT_PVRTC4_ALPHA,
|
||||
FORMAT_ETC, // regular ETC, no transparency
|
||||
/*FORMAT_ETC2_R, for the future..
|
||||
FORMAT_ETC2_RG,
|
||||
FORMAT_ETC2_RGB,
|
||||
FORMAT_ETC2_RGBA1,
|
||||
FORMAT_ETC2_RGBA,*/
|
||||
FORMAT_CUSTOM,
|
||||
|
||||
FORMAT_MAX
|
||||
};
|
||||
|
||||
enum Interpolation {
|
||||
|
||||
INTERPOLATE_NEAREST,
|
||||
INTERPOLATE_BILINEAR,
|
||||
/* INTERPOLATE GAUSS */
|
||||
};
|
||||
|
||||
static Image (*_png_mem_loader_func)(const uint8_t* p_png);
|
||||
static void (*_image_compress_bc_func)(Image *);
|
||||
static void (*_image_compress_pvrtc2_func)(Image *);
|
||||
static void (*_image_compress_pvrtc4_func)(Image *);
|
||||
static void (*_image_compress_etc_func)(Image *);
|
||||
static void (*_image_decompress_pvrtc)(Image *);
|
||||
static void (*_image_decompress_bc)(Image *);
|
||||
static void (*_image_decompress_etc)(Image *);
|
||||
|
||||
static DVector<uint8_t> (*lossy_packer)(const Image& p_image,float p_quality);
|
||||
static Image (*lossy_unpacker)(const DVector<uint8_t>& p_buffer);
|
||||
static DVector<uint8_t> (*lossless_packer)(const Image& p_image);
|
||||
static Image (*lossless_unpacker)(const DVector<uint8_t>& p_buffer);
|
||||
private:
|
||||
|
||||
//internal byte based color
|
||||
struct BColor {
|
||||
union {
|
||||
uint8_t col[4];
|
||||
struct {
|
||||
uint8_t r,g,b,a;
|
||||
};
|
||||
};
|
||||
|
||||
bool operator==(const BColor& p_color) const { for(int i=0;i<4;i++) {if (col[i]!=p_color.col[i]) return false; } return true; }
|
||||
_FORCE_INLINE_ uint8_t gray() const { return (uint16_t(col[0])+uint16_t(col[1])+uint16_t(col[2]))/3; }
|
||||
_FORCE_INLINE_ BColor() {}
|
||||
BColor(uint8_t p_r,uint8_t p_g,uint8_t p_b,uint8_t p_a=255) { col[0]=p_r; col[1]=p_g; col[2]=p_b; col[3]=p_a; }
|
||||
};
|
||||
|
||||
//median cut classes
|
||||
|
||||
struct BColorPos {
|
||||
|
||||
uint32_t index;
|
||||
BColor color;
|
||||
struct SortR {
|
||||
|
||||
bool operator()(const BColorPos& ca, const BColorPos& cb) const { return ca.color.r < cb.color.r; }
|
||||
};
|
||||
|
||||
struct SortG {
|
||||
|
||||
bool operator()(const BColorPos& ca, const BColorPos& cb) const { return ca.color.g < cb.color.g; }
|
||||
};
|
||||
|
||||
struct SortB {
|
||||
|
||||
bool operator()(const BColorPos& ca, const BColorPos& cb) const { return ca.color.b < cb.color.b; }
|
||||
};
|
||||
|
||||
struct SortA {
|
||||
|
||||
bool operator()(const BColorPos& ca, const BColorPos& cb) const { return ca.color.a < cb.color.a; }
|
||||
};
|
||||
};
|
||||
|
||||
struct SPTree {
|
||||
|
||||
bool leaf;
|
||||
uint8_t split_plane;
|
||||
uint8_t split_value;
|
||||
union {
|
||||
int left;
|
||||
int color;
|
||||
};
|
||||
int right;
|
||||
SPTree() { leaf=true; left=-1; right=-1;}
|
||||
};
|
||||
|
||||
struct MCBlock {
|
||||
|
||||
BColorPos min_color,max_color;
|
||||
BColorPos *colors;
|
||||
int sp_idx;
|
||||
int color_count;
|
||||
int get_longest_axis_index() const;
|
||||
int get_longest_axis_length() const;
|
||||
bool operator<(const MCBlock& p_block) const;
|
||||
void shrink();
|
||||
MCBlock();
|
||||
MCBlock(BColorPos *p_colors,int p_color_count);
|
||||
};
|
||||
|
||||
Format format;
|
||||
DVector<uint8_t> data;
|
||||
int width,height,mipmaps;
|
||||
|
||||
|
||||
|
||||
_FORCE_INLINE_ BColor _get_pixel(int p_x,int p_y,const unsigned char *p_data,int p_data_size) const;
|
||||
_FORCE_INLINE_ BColor _get_pixelw(int p_x,int p_y,int p_width,const unsigned char *p_data,int p_data_size) const;
|
||||
_FORCE_INLINE_ void _put_pixelw(int p_x,int p_y, int p_width, const BColor& p_color, unsigned char *p_data);
|
||||
_FORCE_INLINE_ void _put_pixel(int p_x,int p_y, const BColor& p_color, unsigned char *p_data);
|
||||
_FORCE_INLINE_ void _get_mipmap_offset_and_size(int p_mipmap,int &r_offset, int &r_width, int &r_height) const; //get where the mipmap begins in data
|
||||
_FORCE_INLINE_ static void _get_format_min_data_size(Format p_format,int &r_w, int &r_h);
|
||||
|
||||
static int _get_dst_image_size(int p_width, int p_height, Format p_format,int &r_mipmaps,int p_mipmaps=-1);
|
||||
bool _can_modify(Format p_format) const;
|
||||
|
||||
|
||||
|
||||
public:
|
||||
|
||||
|
||||
|
||||
int get_width() const; ///< Get image width
|
||||
int get_height() const; ///< Get image height
|
||||
int get_mipmaps() const;
|
||||
|
||||
/**
|
||||
* Get a pixel from the image. for grayscale or indexed formats, use Color::gray to obtain the actual
|
||||
* value.
|
||||
*/
|
||||
Color get_pixel(int p_x,int p_y,int p_mipmap=0) const;
|
||||
/**
|
||||
* Set a pixel into the image. for grayscale or indexed formats, a suitable Color constructor.
|
||||
*/
|
||||
void put_pixel(int p_x,int p_y, const Color& p_color,int p_mipmap=0); /* alpha and index are averaged */
|
||||
|
||||
/**
|
||||
* Convert the image to another format, as close as it can be done.
|
||||
*/
|
||||
void convert( Format p_new_format );
|
||||
|
||||
/**
|
||||
* Get the current image format.
|
||||
*/
|
||||
Format get_format() const;
|
||||
|
||||
int get_mipmap_offset(int p_mipmap) const; //get where the mipmap begins in data
|
||||
void get_mipmap_offset_and_size(int p_mipmap,int &r_ofs, int &r_size) const; //get where the mipmap begins in data
|
||||
|
||||
/**
|
||||
* Resize the image, using the prefered interpolation method.
|
||||
* Indexed-Color images always use INTERPOLATE_NEAREST.
|
||||
*/
|
||||
|
||||
void resize_to_po2(bool p_square=false);
|
||||
void resize( int p_width, int p_height, Interpolation p_interpolation=INTERPOLATE_BILINEAR );
|
||||
Image resized( int p_width, int p_height, int p_interpolation=INTERPOLATE_BILINEAR );
|
||||
/**
|
||||
* Crop the image to a specific size, if larger, then the image is filled by black
|
||||
*/
|
||||
void crop( int p_width, int p_height );
|
||||
|
||||
|
||||
void flip_x();
|
||||
void flip_y();
|
||||
/**
|
||||
* Generate a mipmap to an image (creates an image 1/4 the size, with averaging of 4->1)
|
||||
*/
|
||||
Error generate_mipmaps(int p_amount=-1,bool p_keep_existing=false);
|
||||
|
||||
void clear_mipmaps();
|
||||
|
||||
|
||||
/**
|
||||
* Generate a normal map from a grayscale image
|
||||
*/
|
||||
|
||||
void make_normalmap(float p_height_scale=1.0);
|
||||
|
||||
/**
|
||||
* Create a new image of a given size and format. Current image will be lost
|
||||
*/
|
||||
void create(int p_width, int p_height, bool p_use_mipmaps, Format p_format);
|
||||
void create(int p_width, int p_height, int p_mipmaps, Format p_format, const DVector<uint8_t>& p_data);
|
||||
|
||||
void create( const char ** p_xpm );
|
||||
/**
|
||||
* returns true when the image is empty (0,0) in size
|
||||
*/
|
||||
bool empty() const;
|
||||
|
||||
DVector<uint8_t> get_data() const;
|
||||
|
||||
Error load(const String& p_path);
|
||||
|
||||
/**
|
||||
* create an empty image
|
||||
*/
|
||||
Image();
|
||||
/**
|
||||
* create an empty image of a specific size and format
|
||||
*/
|
||||
Image(int p_width, int p_height, bool p_use_mipmaps, Format p_format);
|
||||
/**
|
||||
* import an image of a specific size and format from a pointer
|
||||
*/
|
||||
Image(int p_width, int p_height, int p_mipmaps, Format p_format, const DVector<uint8_t>& p_data);
|
||||
|
||||
enum AlphaMode {
|
||||
ALPHA_NONE,
|
||||
ALPHA_BIT,
|
||||
ALPHA_BLEND
|
||||
};
|
||||
|
||||
AlphaMode detect_alpha() const;
|
||||
|
||||
void put_indexed_pixel(int p_x, int p_y, uint8_t p_idx,int p_mipmap=0);
|
||||
uint8_t get_indexed_pixel(int p_x, int p_y,int p_mipmap=0) const;
|
||||
void set_pallete(const DVector<uint8_t>& p_data);
|
||||
|
||||
|
||||
static int get_format_pixel_size(Format p_format);
|
||||
static int get_format_pixel_rshift(Format p_format);
|
||||
static int get_format_pallete_size(Format p_format);
|
||||
static int get_image_data_size(int p_width, int p_height, Format p_format,int p_mipmaps=0);
|
||||
static int get_image_required_mipmaps(int p_width, int p_height, Format p_format);
|
||||
|
||||
|
||||
|
||||
|
||||
bool operator==(const Image& p_image) const;
|
||||
|
||||
void quantize();
|
||||
|
||||
enum CompressMode {
|
||||
COMPRESS_BC,
|
||||
COMPRESS_PVRTC2,
|
||||
COMPRESS_PVRTC4,
|
||||
COMPRESS_ETC
|
||||
};
|
||||
|
||||
Error compress(CompressMode p_mode=COMPRESS_BC);
|
||||
Image compressed(int p_mode); /* from the Image::CompressMode enum */
|
||||
void decompress();
|
||||
|
||||
void fix_alpha_edges();
|
||||
|
||||
void blit_rect(const Image& p_src, const Rect2& p_src_rect,const Point2& p_dest);
|
||||
void brush_transfer(const Image& p_src, const Image& p_brush, const Point2& p_dest);
|
||||
Image brushed(const Image& p_src, const Image& p_brush, const Point2& p_dest) const;
|
||||
|
||||
Rect2 get_used_rect() const;
|
||||
Image get_rect(const Rect2& p_area) const;
|
||||
|
||||
static void set_compress_bc_func(void (*p_compress_func)(Image *));
|
||||
Image(const uint8_t* p_mem_png);
|
||||
Image(const char **p_xpm);
|
||||
~Image();
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
370
core/image_quantize.cpp
Normal file
370
core/image_quantize.cpp
Normal file
@ -0,0 +1,370 @@
|
||||
/*************************************************************************/
|
||||
/* image_quantize.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 <stdio.h>
|
||||
#include "print_string.h"
|
||||
#ifdef TOOLS_ENABLED
|
||||
#include "set.h"
|
||||
#include "sort.h"
|
||||
#include "os/os.h"
|
||||
|
||||
//#define QUANTIZE_SPEED_OVER_QUALITY
|
||||
|
||||
|
||||
Image::MCBlock::MCBlock() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
Image::MCBlock::MCBlock(BColorPos *p_colors,int p_color_count) {
|
||||
|
||||
colors=p_colors;
|
||||
color_count=p_color_count;
|
||||
min_color.color=BColor(255,255,255,255);
|
||||
max_color.color=BColor(0,0,0,0);
|
||||
shrink();
|
||||
}
|
||||
|
||||
int Image::MCBlock::get_longest_axis_index() const {
|
||||
|
||||
int max_dist=-1;
|
||||
int max_index=0;
|
||||
|
||||
for(int i=0;i<4;i++) {
|
||||
|
||||
int d = max_color.color.col[i]-min_color.color.col[i];
|
||||
//printf(" ai:%i - %i\n",i,d);
|
||||
if (d>max_dist) {
|
||||
max_index=i;
|
||||
max_dist=d;
|
||||
}
|
||||
}
|
||||
|
||||
return max_index;
|
||||
}
|
||||
int Image::MCBlock::get_longest_axis_length() const {
|
||||
|
||||
int max_dist=-1;
|
||||
int max_index=0;
|
||||
|
||||
for(int i=0;i<4;i++) {
|
||||
|
||||
int d = max_color.color.col[i]-min_color.color.col[i];
|
||||
if (d>max_dist) {
|
||||
max_index=i;
|
||||
max_dist=d;
|
||||
}
|
||||
}
|
||||
|
||||
return max_dist;
|
||||
}
|
||||
|
||||
bool Image::MCBlock::operator<(const MCBlock& p_block) const {
|
||||
|
||||
int alen = get_longest_axis_length();
|
||||
int blen = p_block.get_longest_axis_length();
|
||||
if (alen==blen) {
|
||||
|
||||
return colors < p_block.colors;
|
||||
} else
|
||||
return alen < blen;
|
||||
|
||||
}
|
||||
|
||||
void Image::MCBlock::shrink() {
|
||||
|
||||
min_color=colors[0];
|
||||
max_color=colors[0];
|
||||
|
||||
for(int i=1;i<color_count;i++) {
|
||||
|
||||
for(int j=0;j<4;j++) {
|
||||
|
||||
min_color.color.col[j]=MIN(min_color.color.col[j],colors[i].color.col[j]);
|
||||
max_color.color.col[j]=MAX(max_color.color.col[j],colors[i].color.col[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Image::quantize() {
|
||||
|
||||
Image::Format orig_format=format;
|
||||
|
||||
bool has_alpha = detect_alpha()!=ALPHA_NONE;
|
||||
|
||||
bool quantize_fast=OS::get_singleton()->has_environment("QUANTIZE_FAST");
|
||||
|
||||
convert(FORMAT_RGBA);
|
||||
|
||||
ERR_FAIL_COND( format!=FORMAT_RGBA );
|
||||
|
||||
DVector<uint8_t> indexed_data;
|
||||
|
||||
|
||||
{
|
||||
int color_count = data.size()/4;
|
||||
|
||||
ERR_FAIL_COND(color_count==0);
|
||||
|
||||
Set<MCBlock> block_queue;
|
||||
|
||||
DVector<BColorPos> data_colors;
|
||||
data_colors.resize(color_count);
|
||||
|
||||
DVector<BColorPos>::Write dcw=data_colors.write();
|
||||
|
||||
DVector<uint8_t>::Read dr = data.read();
|
||||
const BColor * drptr=(const BColor*)&dr[0];
|
||||
BColorPos *bcptr=&dcw[0];
|
||||
|
||||
|
||||
|
||||
{
|
||||
for(int i=0;i<color_count;i++) {
|
||||
|
||||
//uint32_t data_ofs=i<<2;
|
||||
bcptr[i].color=drptr[i];//BColor(drptr[data_ofs+0],drptr[data_ofs+1],drptr[data_ofs+2],drptr[data_ofs+3]);
|
||||
bcptr[i].index=i;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//printf("color count: %i\n",color_count);
|
||||
/*
|
||||
for(int i=0;i<color_count;i++) {
|
||||
|
||||
BColor bc = ((BColor*)&wb[0])[i];
|
||||
printf("%i - %i,%i,%i,%i\n",i,bc.r,bc.g,bc.b,bc.a);
|
||||
}*/
|
||||
|
||||
MCBlock initial_block((BColorPos*)&dcw[0],color_count);
|
||||
|
||||
block_queue.insert(initial_block);
|
||||
|
||||
while( block_queue.size() < 256 && block_queue.back()->get().color_count > 1 ) {
|
||||
|
||||
MCBlock longest = block_queue.back()->get();
|
||||
//printf("longest: %i (%i)\n",longest.get_longest_axis_index(),longest.get_longest_axis_length());
|
||||
|
||||
block_queue.erase(block_queue.back());
|
||||
|
||||
BColorPos *first = longest.colors;
|
||||
BColorPos *median = longest.colors + (longest.color_count+1)/2;
|
||||
BColorPos *end = longest.colors + longest.color_count;
|
||||
|
||||
#if 0
|
||||
int lai =longest.get_longest_axis_index();
|
||||
switch(lai) {
|
||||
#if 0
|
||||
case 0: { SortArray<BColorPos,BColorPos::SortR> sort; sort.sort(first,end-first); } break;
|
||||
case 1: { SortArray<BColorPos,BColorPos::SortG> sort; sort.sort(first,end-first); } break;
|
||||
case 2: { SortArray<BColorPos,BColorPos::SortB> sort; sort.sort(first,end-first); } break;
|
||||
case 3: { SortArray<BColorPos,BColorPos::SortA> sort; sort.sort(first,end-first); } break;
|
||||
#else
|
||||
case 0: { SortArray<BColorPos,BColorPos::SortR> sort; sort.nth_element(0,end-first,median-first,first); } break;
|
||||
case 1: { SortArray<BColorPos,BColorPos::SortG> sort; sort.nth_element(0,end-first,median-first,first); } break;
|
||||
case 2: { SortArray<BColorPos,BColorPos::SortB> sort; sort.nth_element(0,end-first,median-first,first); } break;
|
||||
case 3: { SortArray<BColorPos,BColorPos::SortA> sort; sort.nth_element(0,end-first,median-first,first); } break;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
//avoid same color from being split in 2
|
||||
//search forward and flip
|
||||
BColorPos *median_end=median;
|
||||
BColorPos *p=median_end+1;
|
||||
|
||||
while(p!=end) {
|
||||
if (median_end->color==p->color) {
|
||||
SWAP(*(median_end+1),*p);
|
||||
median_end++;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
//search backward and flip
|
||||
BColorPos *median_begin=median;
|
||||
p=median_begin-1;
|
||||
|
||||
while(p!=(first-1)) {
|
||||
if (median_begin->color==p->color) {
|
||||
SWAP(*(median_begin-1),*p);
|
||||
median_begin--;
|
||||
}
|
||||
p--;
|
||||
}
|
||||
|
||||
|
||||
if (first < median_begin) {
|
||||
median=median_begin;
|
||||
} else if (median_end < end-1) {
|
||||
median=median_end+1;
|
||||
} else {
|
||||
break; //shouldn't have arrived here, since it means all pixels are equal, but wathever
|
||||
}
|
||||
|
||||
MCBlock left(first,median-first);
|
||||
MCBlock right(median,end-median);
|
||||
|
||||
block_queue.insert(left);
|
||||
block_queue.insert(right);
|
||||
|
||||
#else
|
||||
switch(longest.get_longest_axis_index()) {
|
||||
case 0: { SortArray<BColorPos,BColorPos::SortR> sort; sort.nth_element(0,end-first,median-first,first); } break;
|
||||
case 1: { SortArray<BColorPos,BColorPos::SortG> sort; sort.nth_element(0,end-first,median-first,first); } break;
|
||||
case 2: { SortArray<BColorPos,BColorPos::SortB> sort; sort.nth_element(0,end-first,median-first,first); } break;
|
||||
case 3: { SortArray<BColorPos,BColorPos::SortA> sort; sort.nth_element(0,end-first,median-first,first); } break;
|
||||
|
||||
}
|
||||
|
||||
MCBlock left(first,median-first);
|
||||
MCBlock right(median,end-median);
|
||||
|
||||
block_queue.insert(left);
|
||||
block_queue.insert(right);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
while(block_queue.size() > 256) {
|
||||
|
||||
block_queue.erase(block_queue.front());// erase least significant
|
||||
}
|
||||
|
||||
int res_colors=0;
|
||||
|
||||
int comp_size = (has_alpha?4:3);
|
||||
indexed_data.resize(color_count + 256*comp_size);
|
||||
|
||||
DVector<uint8_t>::Write iw = indexed_data.write();
|
||||
uint8_t *iwptr=&iw[0];
|
||||
BColor pallete[256];
|
||||
|
||||
// print_line("applying quantization - res colors "+itos(block_queue.size()));
|
||||
|
||||
while(block_queue.size()) {
|
||||
|
||||
const MCBlock &b = block_queue.back()->get();
|
||||
|
||||
uint64_t sum[4]={0,0,0,0};
|
||||
|
||||
for(int i=0;i<b.color_count;i++) {
|
||||
|
||||
sum[0]+=b.colors[i].color.col[0];
|
||||
sum[1]+=b.colors[i].color.col[1];
|
||||
sum[2]+=b.colors[i].color.col[2];
|
||||
sum[3]+=b.colors[i].color.col[3];
|
||||
}
|
||||
|
||||
BColor c( sum[0]/b.color_count, sum[1]/b.color_count, sum[2]/b.color_count, sum[3]/b.color_count );
|
||||
|
||||
|
||||
|
||||
//printf(" %i: %i,%i,%i,%i out of %i\n",res_colors,c.r,c.g,c.b,c.a,b.color_count);
|
||||
|
||||
|
||||
|
||||
for(int i=0;i<comp_size;i++) {
|
||||
iwptr[ color_count + res_colors * comp_size + i ] = c.col[i];
|
||||
}
|
||||
|
||||
if (quantize_fast) {
|
||||
for(int i=0;i<b.color_count;i++) {
|
||||
iwptr[b.colors[i].index]=res_colors;
|
||||
}
|
||||
} else {
|
||||
|
||||
pallete[res_colors]=c;
|
||||
}
|
||||
|
||||
|
||||
res_colors++;
|
||||
|
||||
block_queue.erase(block_queue.back());
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (!quantize_fast) {
|
||||
|
||||
for(int i=0;i<color_count;i++) {
|
||||
|
||||
const BColor &c=drptr[i];
|
||||
uint8_t best_dist_idx=0;
|
||||
uint32_t dist=0xFFFFFFFF;
|
||||
|
||||
for(int j=0;j<res_colors;j++) {
|
||||
|
||||
const BColor &pc=pallete[j];
|
||||
uint32_t d = 0;
|
||||
{ int16_t v = (int16_t)c.r-(int16_t)pc.r; d+=v*v; }
|
||||
{ int16_t v = (int16_t)c.g-(int16_t)pc.g; d+=v*v; }
|
||||
{ int16_t v = (int16_t)c.b-(int16_t)pc.b; d+=v*v; }
|
||||
{ int16_t v = (int16_t)c.a-(int16_t)pc.a; d+=v*v; }
|
||||
|
||||
if (d<=dist) {
|
||||
best_dist_idx=j;
|
||||
dist=d;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
iwptr[ i ] = best_dist_idx;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//iw = DVector<uint8_t>::Write();
|
||||
//dr = DVector<uint8_t>::Read();
|
||||
//wb = DVector<uint8_t>::Write();
|
||||
}
|
||||
|
||||
print_line(itos(indexed_data.size()));
|
||||
data=indexed_data;
|
||||
format=has_alpha?FORMAT_INDEXED_ALPHA:FORMAT_INDEXED;
|
||||
|
||||
|
||||
} //do none
|
||||
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
void Image::quantize() {} //do none
|
||||
|
||||
|
||||
#endif
|
209
core/input_map.cpp
Normal file
209
core/input_map.cpp
Normal file
@ -0,0 +1,209 @@
|
||||
/*************************************************************************/
|
||||
/* input_map.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "input_map.h"
|
||||
#include "globals.h"
|
||||
|
||||
InputMap *InputMap::singleton=NULL;
|
||||
|
||||
void InputMap::add_action(const StringName& p_action) {
|
||||
|
||||
ERR_FAIL_COND( input_map.has(p_action) );
|
||||
input_map[p_action]=Action();
|
||||
static int last_id=1;
|
||||
input_map[p_action].id=last_id;
|
||||
input_id_map[last_id]=p_action;
|
||||
last_id++;
|
||||
|
||||
|
||||
}
|
||||
|
||||
void InputMap::erase_action(const StringName& p_action) {
|
||||
|
||||
ERR_FAIL_COND( !input_map.has(p_action) );
|
||||
input_id_map.erase(input_map[p_action].id);
|
||||
input_map.erase(p_action);
|
||||
|
||||
}
|
||||
|
||||
StringName InputMap::get_action_from_id(int p_id) const {
|
||||
|
||||
ERR_FAIL_COND_V(!input_id_map.has(p_id),StringName());
|
||||
return input_id_map[p_id];
|
||||
}
|
||||
|
||||
List<InputEvent>::Element *InputMap::_find_event(List<InputEvent> &p_list,const InputEvent& p_event) const {
|
||||
|
||||
for (List<InputEvent>::Element *E=p_list.front();E;E=E->next()) {
|
||||
|
||||
const InputEvent& e=E->get();
|
||||
if(e.type!=p_event.type)
|
||||
continue;
|
||||
if (e.type!=InputEvent::KEY && e.device!=p_event.device)
|
||||
continue;
|
||||
|
||||
bool same=false;
|
||||
|
||||
switch(p_event.type) {
|
||||
|
||||
case InputEvent::KEY: {
|
||||
|
||||
same=(e.key.scancode==p_event.key.scancode && e.key.mod == p_event.key.mod);
|
||||
|
||||
} break;
|
||||
case InputEvent::JOYSTICK_BUTTON: {
|
||||
|
||||
same=(e.joy_button.button_index==p_event.joy_button.button_index);
|
||||
|
||||
} break;
|
||||
case InputEvent::MOUSE_BUTTON: {
|
||||
|
||||
same=(e.mouse_button.button_index==p_event.mouse_button.button_index);
|
||||
|
||||
} break;
|
||||
case InputEvent::JOYSTICK_MOTION: {
|
||||
|
||||
same=(e.joy_motion.axis==p_event.joy_motion.axis);
|
||||
|
||||
} break;
|
||||
}
|
||||
|
||||
if (same)
|
||||
return E;
|
||||
}
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
bool InputMap::has_action(const StringName& p_action) const {
|
||||
|
||||
return input_map.has(p_action);
|
||||
}
|
||||
|
||||
void InputMap::action_add_event(const StringName& p_action,const InputEvent& p_event) {
|
||||
|
||||
ERR_FAIL_COND(p_event.type==InputEvent::ACTION);
|
||||
ERR_FAIL_COND( !input_map.has(p_action) );
|
||||
if (_find_event(input_map[p_action].inputs,p_event))
|
||||
return; //already gots
|
||||
|
||||
input_map[p_action].inputs.push_back(p_event);
|
||||
|
||||
}
|
||||
|
||||
|
||||
int InputMap::get_action_id(const StringName& p_action) const {
|
||||
|
||||
ERR_FAIL_COND_V(!input_map.has(p_action),-1);
|
||||
return input_map[p_action].id;
|
||||
}
|
||||
|
||||
bool InputMap::action_has_event(const StringName& p_action,const InputEvent& p_event) {
|
||||
|
||||
ERR_FAIL_COND_V( !input_map.has(p_action), false );
|
||||
return (_find_event(input_map[p_action].inputs,p_event)!=NULL);
|
||||
|
||||
}
|
||||
|
||||
void InputMap::action_erase_event(const StringName& p_action,const InputEvent& p_event) {
|
||||
|
||||
ERR_FAIL_COND( !input_map.has(p_action) );
|
||||
|
||||
List<InputEvent>::Element *E=_find_event(input_map[p_action].inputs,p_event);
|
||||
if (E)
|
||||
return; //already gots
|
||||
|
||||
input_map[p_action].inputs.erase(E);
|
||||
|
||||
}
|
||||
|
||||
const List<InputEvent> *InputMap::get_action_list(const StringName& p_action) {
|
||||
|
||||
const Map<StringName, Action>::Element *E=input_map.find(p_action);
|
||||
if (!E)
|
||||
return NULL;
|
||||
|
||||
return &E->get().inputs;
|
||||
}
|
||||
|
||||
bool InputMap::event_is_action(const InputEvent& p_event, const StringName& p_action) const {
|
||||
|
||||
|
||||
Map<StringName,Action >::Element *E=input_map.find(p_action);
|
||||
if(!E) {
|
||||
ERR_EXPLAIN("Request for unexisting InputMap action: "+String(p_action));
|
||||
ERR_FAIL_COND_V(!E,false);
|
||||
}
|
||||
|
||||
if (p_event.type==InputEvent::ACTION) {
|
||||
|
||||
return p_event.action.action==E->get().id;
|
||||
}
|
||||
|
||||
return _find_event(E->get().inputs,p_event)!=NULL;
|
||||
}
|
||||
|
||||
void InputMap::load_from_globals() {
|
||||
|
||||
input_map.clear();;
|
||||
|
||||
List<PropertyInfo> pinfo;
|
||||
Globals::get_singleton()->get_property_list(&pinfo);
|
||||
|
||||
for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
|
||||
const PropertyInfo &pi=E->get();
|
||||
|
||||
if (!pi.name.begins_with("input/"))
|
||||
continue;
|
||||
|
||||
String name = pi.name.substr(pi.name.find("/")+1,pi.name.length());
|
||||
|
||||
add_action(name);
|
||||
|
||||
Array va = Globals::get_singleton()->get(pi.name);;
|
||||
|
||||
for(int i=0;i<va.size();i++) {
|
||||
|
||||
InputEvent ie=va[i];
|
||||
if (ie.type==InputEvent::NONE)
|
||||
continue;
|
||||
action_add_event(name,ie);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
InputMap::InputMap() {
|
||||
|
||||
ERR_FAIL_COND(singleton);
|
||||
singleton=this;
|
||||
}
|
73
core/input_map.h
Normal file
73
core/input_map.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*************************************************************************/
|
||||
/* input_map.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 INPUT_MAP_H
|
||||
#define INPUT_MAP_H
|
||||
|
||||
|
||||
#include "object.h"
|
||||
|
||||
class InputMap : public Object {
|
||||
|
||||
OBJ_TYPE( InputMap, Object );
|
||||
static InputMap *singleton;
|
||||
|
||||
struct Action {
|
||||
int id;
|
||||
List<InputEvent> inputs;
|
||||
};
|
||||
mutable Map<StringName, Action> input_map;
|
||||
mutable Map<int,StringName> input_id_map;
|
||||
|
||||
List<InputEvent>::Element *_find_event(List<InputEvent> &p_list,const InputEvent& p_event) const;
|
||||
|
||||
public:
|
||||
|
||||
static _FORCE_INLINE_ InputMap *get_singleton() { return singleton; }
|
||||
|
||||
|
||||
bool has_action(const StringName& p_action) const;
|
||||
int get_action_id(const StringName& p_action) const;
|
||||
StringName get_action_from_id(int p_id) const;
|
||||
void add_action(const StringName& p_action);
|
||||
void erase_action(const StringName& p_action);
|
||||
|
||||
void action_add_event(const StringName& p_action,const InputEvent& p_event);
|
||||
bool action_has_event(const StringName& p_action,const InputEvent& p_event);
|
||||
void action_erase_event(const StringName& p_action,const InputEvent& p_event);
|
||||
|
||||
const List<InputEvent> *get_action_list(const StringName& p_action);
|
||||
bool event_is_action(const InputEvent& p_event, const StringName& p_action) const;
|
||||
|
||||
|
||||
void load_from_globals();
|
||||
|
||||
InputMap();
|
||||
};
|
||||
|
||||
#endif // INPUT_MAP_H
|
56
core/int_types.h
Normal file
56
core/int_types.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*************************************************************************/
|
||||
/* int_types.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
typedef signed __int8 int8_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef signed __int16 int16_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef signed __int32 int32_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
|
||||
#else
|
||||
|
||||
#ifdef NO_STDINT_H
|
||||
typedef unsigned char uint8_t;
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef signed short int16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef signed int int32_t;
|
||||
typedef long long int64_t;
|
||||
typedef unsigned long long int64_t;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#endif
|
9
core/io/SCsub
Normal file
9
core/io/SCsub
Normal file
@ -0,0 +1,9 @@
|
||||
Import('env')
|
||||
|
||||
env.add_source_files(env.core_sources,"*.cpp")
|
||||
env.add_source_files(env.core_sources,"*.c")
|
||||
#env.core_sources.append("io/fastlz.c")
|
||||
|
||||
Export('env')
|
||||
|
||||
|
110
core/io/base64.c
Normal file
110
core/io/base64.c
Normal file
@ -0,0 +1,110 @@
|
||||
#include <string.h>
|
||||
|
||||
char b64string[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
long base64_encode (to, from, len)
|
||||
char *to, *from;
|
||||
unsigned int len;
|
||||
{
|
||||
char *fromp = from;
|
||||
char *top = to;
|
||||
unsigned char cbyte;
|
||||
unsigned char obyte;
|
||||
char end[3];
|
||||
|
||||
for (; len >= 3; len -= 3) {
|
||||
cbyte = *fromp++;
|
||||
*top++ = b64string[(int)(cbyte >> 2)];
|
||||
obyte = (cbyte << 4) & 0x30; /* 0011 0000 */
|
||||
|
||||
cbyte = *fromp++;
|
||||
obyte |= (cbyte >> 4); /* 0000 1111 */
|
||||
*top++ = b64string[(int)obyte];
|
||||
obyte = (cbyte << 2) & 0x3C; /* 0011 1100 */
|
||||
|
||||
cbyte = *fromp++;
|
||||
obyte |= (cbyte >> 6); /* 0000 0011 */
|
||||
*top++ = b64string[(int)obyte];
|
||||
*top++ = b64string[(int)(cbyte & 0x3F)];/* 0011 1111 */
|
||||
}
|
||||
|
||||
if (len) {
|
||||
end[0] = *fromp++;
|
||||
if (--len) end[1] = *fromp++; else end[1] = 0;
|
||||
end[2] = 0;
|
||||
|
||||
cbyte = end[0];
|
||||
*top++ = b64string[(int)(cbyte >> 2)];
|
||||
obyte = (cbyte << 4) & 0x30; /* 0011 0000 */
|
||||
|
||||
cbyte = end[1];
|
||||
obyte |= (cbyte >> 4);
|
||||
*top++ = b64string[(int)obyte];
|
||||
obyte = (cbyte << 2) & 0x3C; /* 0011 1100 */
|
||||
|
||||
if (len) *top++ = b64string[(int)obyte];
|
||||
else *top++ = '=';
|
||||
*top++ = '=';
|
||||
}
|
||||
*top = 0;
|
||||
return top - to;
|
||||
}
|
||||
|
||||
/* badchar(): check if c is decent; puts either the */
|
||||
/* location of c or null into p. */
|
||||
#define badchar(c,p) (!(p = memchr(b64string, c, 64)))
|
||||
|
||||
long base64_decode (to, from, len)
|
||||
char *to, *from;
|
||||
unsigned int len;
|
||||
{
|
||||
char *fromp = from;
|
||||
char *top = to;
|
||||
char *p;
|
||||
unsigned char cbyte;
|
||||
unsigned char obyte;
|
||||
int padding = 0;
|
||||
|
||||
for (; len >= 4; len -= 4) {
|
||||
if ((cbyte = *fromp++) == '=') cbyte = 0;
|
||||
else {
|
||||
if (badchar(cbyte, p)) return -1;
|
||||
cbyte = (p - b64string);
|
||||
}
|
||||
obyte = cbyte << 2; /* 1111 1100 */
|
||||
|
||||
if ((cbyte = *fromp++) == '=') cbyte = 0;
|
||||
else {
|
||||
if (badchar(cbyte, p)) return -1;
|
||||
cbyte = p - b64string;
|
||||
}
|
||||
obyte |= cbyte >> 4; /* 0000 0011 */
|
||||
*top++ = obyte;
|
||||
|
||||
obyte = cbyte << 4; /* 1111 0000 */
|
||||
if ((cbyte = *fromp++) == '=') { cbyte = 0; padding++; }
|
||||
else {
|
||||
padding = 0;
|
||||
if (badchar (cbyte, p)) return -1;
|
||||
cbyte = p - b64string;
|
||||
}
|
||||
obyte |= cbyte >> 2; /* 0000 1111 */
|
||||
*top++ = obyte;
|
||||
|
||||
obyte = cbyte << 6; /* 1100 0000 */
|
||||
if ((cbyte = *fromp++) == '=') { cbyte = 0; padding++; }
|
||||
else {
|
||||
padding = 0;
|
||||
if (badchar (cbyte, p)) return -1;
|
||||
cbyte = p - b64string;
|
||||
}
|
||||
obyte |= cbyte; /* 0011 1111 */
|
||||
*top++ = obyte;
|
||||
}
|
||||
|
||||
*top = 0;
|
||||
if (len) return -1;
|
||||
return (top - to) - padding;
|
||||
}
|
||||
|
11
core/io/base64.h
Normal file
11
core/io/base64.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef BASE64_H
|
||||
#define BASE64_H
|
||||
|
||||
extern "C" {
|
||||
|
||||
uint32_t base64_encode (char* to, char* from, uint32_t len);
|
||||
uint32_t base64_decode (char* to, char* from, uint32_t len);
|
||||
|
||||
};
|
||||
|
||||
#endif /* BASE64_H */
|
91
core/io/compression.cpp
Normal file
91
core/io/compression.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
/*************************************************************************/
|
||||
/* compression.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "compression.h"
|
||||
|
||||
#include "fastlz.h"
|
||||
#include "os/copymem.h"
|
||||
|
||||
int Compression::compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size,Mode p_mode) {
|
||||
|
||||
switch(p_mode) {
|
||||
case MODE_FASTLZ: {
|
||||
|
||||
if (p_src_size<16) {
|
||||
uint8_t src[16];
|
||||
zeromem(&src[p_src_size],16-p_src_size);
|
||||
copymem(src,p_src,p_src_size);
|
||||
return fastlz_compress(src,16,p_dst);
|
||||
} else {
|
||||
return fastlz_compress(p_src,p_src_size,p_dst);
|
||||
}
|
||||
|
||||
} break;
|
||||
}
|
||||
|
||||
ERR_FAIL_V(-1);
|
||||
}
|
||||
|
||||
int Compression::get_max_compressed_buffer_size(int p_src_size,Mode p_mode){
|
||||
|
||||
switch(p_mode) {
|
||||
case MODE_FASTLZ: {
|
||||
|
||||
|
||||
int ss = p_src_size+p_src_size*6/100;
|
||||
if (ss<66)
|
||||
ss=66;
|
||||
return ss;
|
||||
|
||||
} break;
|
||||
}
|
||||
|
||||
ERR_FAIL_V(-1);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Compression::decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p_src, int p_src_size,Mode p_mode){
|
||||
|
||||
switch(p_mode) {
|
||||
case MODE_FASTLZ: {
|
||||
|
||||
if (p_dst_max_size<16) {
|
||||
uint8_t dst[16];
|
||||
fastlz_decompress(p_src,p_src_size,dst,16);
|
||||
copymem(p_dst,dst,p_dst_max_size);
|
||||
} else {
|
||||
fastlz_decompress(p_src,p_src_size,p_dst,p_dst_max_size);
|
||||
}
|
||||
return;
|
||||
} break;
|
||||
}
|
||||
|
||||
ERR_FAIL();
|
||||
}
|
53
core/io/compression.h
Normal file
53
core/io/compression.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*************************************************************************/
|
||||
/* compression.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 COMPRESSION_H
|
||||
#define COMPRESSION_H
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
class Compression
|
||||
{
|
||||
public:
|
||||
|
||||
enum Mode {
|
||||
MODE_FASTLZ,
|
||||
MODE_DEFLATE
|
||||
};
|
||||
|
||||
|
||||
static int compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size,Mode p_mode=MODE_FASTLZ);
|
||||
static int get_max_compressed_buffer_size(int p_src_size,Mode p_mode=MODE_FASTLZ);
|
||||
static void decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p_src, int p_src_size,Mode p_mode=MODE_FASTLZ);
|
||||
|
||||
Compression();
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // COMPRESSION_H
|
744
core/io/config_file.cpp
Normal file
744
core/io/config_file.cpp
Normal file
@ -0,0 +1,744 @@
|
||||
/*************************************************************************/
|
||||
/* config_file.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "config_file.h"
|
||||
#include "os/keyboard.h"
|
||||
#include "os/file_access.h"
|
||||
|
||||
StringArray ConfigFile::_get_sections() const {
|
||||
|
||||
List<String> s;
|
||||
get_sections(&s);
|
||||
StringArray arr;
|
||||
arr.resize(s.size());
|
||||
int idx=0;
|
||||
for(const List<String>::Element *E=s.front();E;E=E->next()) {
|
||||
|
||||
arr.set(idx++,E->get());
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
StringArray ConfigFile::_get_section_keys(const String& p_section) const{
|
||||
|
||||
List<String> s;
|
||||
get_section_keys(p_section,&s);
|
||||
StringArray arr;
|
||||
arr.resize(s.size());
|
||||
int idx=0;
|
||||
for(const List<String>::Element *E=s.front();E;E=E->next()) {
|
||||
|
||||
arr.set(idx++,E->get());
|
||||
}
|
||||
|
||||
return arr;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ConfigFile::set_value(const String& p_section, const String& p_key, const Variant& p_value){
|
||||
|
||||
if (p_value.get_type()==Variant::NIL) {
|
||||
//erase
|
||||
if (!values.has(p_section))
|
||||
return; // ?
|
||||
values[p_section].erase(p_key);
|
||||
if (values[p_section].empty()) {
|
||||
values.erase(p_section);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!values.has(p_section)) {
|
||||
values[p_section]=Map<String, Variant>();
|
||||
}
|
||||
|
||||
values[p_section][p_key]=p_value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Variant ConfigFile::get_value(const String& p_section, const String& p_key) const{
|
||||
|
||||
ERR_FAIL_COND_V(!values.has(p_section),Variant());
|
||||
ERR_FAIL_COND_V(!values[p_section].has(p_key),Variant());
|
||||
return values[p_section][p_key];
|
||||
|
||||
}
|
||||
|
||||
bool ConfigFile::has_section(const String& p_section) const {
|
||||
|
||||
return values.has(p_section);
|
||||
}
|
||||
bool ConfigFile::has_section_key(const String& p_section,const String& p_key) const {
|
||||
|
||||
if (!values.has(p_section))
|
||||
return false;
|
||||
return values[p_section].has(p_key);
|
||||
}
|
||||
|
||||
void ConfigFile::get_sections(List<String> *r_sections) const{
|
||||
|
||||
for(const Map< String, Map<String, Variant> >::Element *E=values.front();E;E=E->next()) {
|
||||
r_sections->push_back(E->key());
|
||||
}
|
||||
}
|
||||
void ConfigFile::get_section_keys(const String& p_section,List<String> *r_keys) const{
|
||||
|
||||
ERR_FAIL_COND(!values.has(p_section));
|
||||
|
||||
for(const Map<String, Variant> ::Element *E=values[p_section].front();E;E=E->next()) {
|
||||
r_keys->push_back(E->key());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static String _encode_variant(const Variant& p_variant) {
|
||||
|
||||
switch(p_variant.get_type()) {
|
||||
|
||||
case Variant::BOOL: {
|
||||
bool val = p_variant;
|
||||
return (val?"true":"false");
|
||||
} break;
|
||||
case Variant::INT: {
|
||||
int val = p_variant;
|
||||
return itos(val);
|
||||
} break;
|
||||
case Variant::REAL: {
|
||||
float val = p_variant;
|
||||
return rtos(val)+(val==int(val)?".0":"");
|
||||
} break;
|
||||
case Variant::STRING: {
|
||||
String val = p_variant;
|
||||
return "\""+val.xml_escape()+"\"";
|
||||
} break;
|
||||
case Variant::COLOR: {
|
||||
|
||||
Color val = p_variant;
|
||||
return "#"+val.to_html();
|
||||
} break;
|
||||
case Variant::STRING_ARRAY:
|
||||
case Variant::INT_ARRAY:
|
||||
case Variant::REAL_ARRAY:
|
||||
case Variant::ARRAY: {
|
||||
Array arr = p_variant;
|
||||
String str="[";
|
||||
for(int i=0;i<arr.size();i++) {
|
||||
|
||||
if (i>0)
|
||||
str+=", ";
|
||||
str+=_encode_variant(arr[i]);
|
||||
}
|
||||
str+="]";
|
||||
return str;
|
||||
} break;
|
||||
case Variant::DICTIONARY: {
|
||||
Dictionary d = p_variant;
|
||||
String str="{";
|
||||
List<Variant> keys;
|
||||
d.get_key_list(&keys);
|
||||
for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
|
||||
|
||||
if (E!=keys.front())
|
||||
str+=", ";
|
||||
str+=_encode_variant(E->get());
|
||||
str+=":";
|
||||
str+=_encode_variant(d[E->get()]);
|
||||
|
||||
}
|
||||
str+="}";
|
||||
return str;
|
||||
} break;
|
||||
case Variant::IMAGE: {
|
||||
String str="img(";
|
||||
|
||||
Image img=p_variant;
|
||||
if (!img.empty()) {
|
||||
|
||||
String format;
|
||||
switch(img.get_format()) {
|
||||
|
||||
case Image::FORMAT_GRAYSCALE: format="grayscale"; break;
|
||||
case Image::FORMAT_INTENSITY: format="intensity"; break;
|
||||
case Image::FORMAT_GRAYSCALE_ALPHA: format="grayscale_alpha"; break;
|
||||
case Image::FORMAT_RGB: format="rgb"; break;
|
||||
case Image::FORMAT_RGBA: format="rgba"; break;
|
||||
case Image::FORMAT_INDEXED : format="indexed"; break;
|
||||
case Image::FORMAT_INDEXED_ALPHA: format="indexed_alpha"; break;
|
||||
case Image::FORMAT_BC1: format="bc1"; break;
|
||||
case Image::FORMAT_BC2: format="bc2"; break;
|
||||
case Image::FORMAT_BC3: format="bc3"; break;
|
||||
case Image::FORMAT_BC4: format="bc4"; break;
|
||||
case Image::FORMAT_BC5: format="bc5"; break;
|
||||
case Image::FORMAT_CUSTOM: format="custom custom_size="+itos(img.get_data().size())+""; break;
|
||||
default: {}
|
||||
}
|
||||
|
||||
str+=format+", ";
|
||||
str+=itos(img.get_mipmaps())+", ";
|
||||
str+=itos(img.get_width())+", ";
|
||||
str+=itos(img.get_height())+", ";
|
||||
DVector<uint8_t> data = img.get_data();
|
||||
int ds=data.size();
|
||||
DVector<uint8_t>::Read r = data.read();
|
||||
for(int i=0;i<ds;i++) {
|
||||
uint8_t byte = r[i];
|
||||
const char hex[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
|
||||
char bstr[3]={ hex[byte>>4], hex[byte&0xF], 0};
|
||||
str+=bstr;
|
||||
}
|
||||
}
|
||||
str+=")";
|
||||
return str;
|
||||
} break;
|
||||
case Variant::INPUT_EVENT: {
|
||||
|
||||
InputEvent ev = p_variant;
|
||||
|
||||
switch(ev.type) {
|
||||
|
||||
case InputEvent::KEY: {
|
||||
|
||||
String mods;
|
||||
if (ev.key.mod.control)
|
||||
mods+="C";
|
||||
if (ev.key.mod.shift)
|
||||
mods+="S";
|
||||
if (ev.key.mod.alt)
|
||||
mods+="A";
|
||||
if (ev.key.mod.meta)
|
||||
mods+="M";
|
||||
if (mods!="")
|
||||
mods=", "+mods;
|
||||
|
||||
return "key("+keycode_get_string(ev.key.scancode)+mods+")";
|
||||
} break;
|
||||
case InputEvent::MOUSE_BUTTON: {
|
||||
|
||||
return "mbutton("+itos(ev.device)+", "+itos(ev.mouse_button.button_index)+")";
|
||||
} break;
|
||||
case InputEvent::JOYSTICK_BUTTON: {
|
||||
|
||||
return "jbutton("+itos(ev.device)+", "+itos(ev.joy_button.button_index)+")";
|
||||
} break;
|
||||
case InputEvent::JOYSTICK_MOTION: {
|
||||
|
||||
return "jaxis("+itos(ev.device)+", "+itos(ev.joy_motion.axis)+")";
|
||||
} break;
|
||||
default: {
|
||||
|
||||
return "nil";
|
||||
} break;
|
||||
|
||||
}
|
||||
} break;
|
||||
default: {}
|
||||
}
|
||||
|
||||
return "nil"; //don't know wha to do with this
|
||||
}
|
||||
|
||||
|
||||
Error ConfigFile::save(const String& p_path){
|
||||
|
||||
Error err;
|
||||
FileAccess *file = FileAccess::open(p_path,FileAccess::WRITE,&err);
|
||||
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
for(Map< String, Map<String, Variant> >::Element *E=values.front();E;E=E->next()) {
|
||||
|
||||
if (E!=values.front())
|
||||
file->store_string("\n");
|
||||
file->store_string("["+E->key()+"]\n\n");
|
||||
|
||||
for(Map<String, Variant>::Element *F=E->get().front();F;F=F->next()) {
|
||||
|
||||
file->store_string(F->key()+"="+_encode_variant(F->get())+"\n");
|
||||
}
|
||||
}
|
||||
|
||||
memdelete(file);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static Vector<String> _decode_params(const String& p_string) {
|
||||
|
||||
int begin=p_string.find("(");
|
||||
ERR_FAIL_COND_V(begin==-1,Vector<String>());
|
||||
begin++;
|
||||
int end=p_string.find(")");
|
||||
ERR_FAIL_COND_V(end<begin,Vector<String>());
|
||||
return p_string.substr(begin,end-begin).split(",");
|
||||
}
|
||||
|
||||
static String _get_chunk(const String& str,int &pos, int close_pos) {
|
||||
|
||||
|
||||
enum {
|
||||
MIN_COMMA,
|
||||
MIN_COLON,
|
||||
MIN_CLOSE,
|
||||
MIN_QUOTE,
|
||||
MIN_PARENTHESIS,
|
||||
MIN_CURLY_OPEN,
|
||||
MIN_OPEN
|
||||
};
|
||||
|
||||
int min_pos=close_pos;
|
||||
int min_what=MIN_CLOSE;
|
||||
|
||||
#define TEST_MIN(m_how,m_what) \
|
||||
{\
|
||||
int res = str.find(m_how,pos);\
|
||||
if (res!=-1 && res < min_pos) {\
|
||||
min_pos=res;\
|
||||
min_what=m_what;\
|
||||
}\
|
||||
}\
|
||||
|
||||
|
||||
TEST_MIN(",",MIN_COMMA);
|
||||
TEST_MIN("[",MIN_OPEN);
|
||||
TEST_MIN("{",MIN_CURLY_OPEN);
|
||||
TEST_MIN("(",MIN_PARENTHESIS);
|
||||
TEST_MIN("\"",MIN_QUOTE);
|
||||
|
||||
int end=min_pos;
|
||||
|
||||
|
||||
switch(min_what) {
|
||||
|
||||
case MIN_COMMA: {
|
||||
} break;
|
||||
case MIN_CLOSE: {
|
||||
//end because it's done
|
||||
} break;
|
||||
case MIN_QUOTE: {
|
||||
end=str.find("\"",min_pos+1)+1;
|
||||
ERR_FAIL_COND_V(end==-1,Variant());
|
||||
|
||||
} break;
|
||||
case MIN_PARENTHESIS: {
|
||||
|
||||
end=str.find(")",min_pos+1)+1;
|
||||
ERR_FAIL_COND_V(end==-1,Variant());
|
||||
|
||||
} break;
|
||||
case MIN_OPEN: {
|
||||
int level=1;
|
||||
while(end<close_pos) {
|
||||
|
||||
if (str[end]=='[')
|
||||
level++;
|
||||
if (str[end]==']') {
|
||||
level--;
|
||||
if (level==0)
|
||||
break;
|
||||
}
|
||||
end++;
|
||||
}
|
||||
ERR_FAIL_COND_V(level!=0,Variant());
|
||||
end++;
|
||||
} break;
|
||||
case MIN_CURLY_OPEN: {
|
||||
int level=1;
|
||||
while(end<close_pos) {
|
||||
|
||||
if (str[end]=='{')
|
||||
level++;
|
||||
if (str[end]=='}') {
|
||||
level--;
|
||||
if (level==0)
|
||||
break;
|
||||
}
|
||||
end++;
|
||||
}
|
||||
ERR_FAIL_COND_V(level!=0,Variant());
|
||||
end++;
|
||||
} break;
|
||||
|
||||
}
|
||||
|
||||
String ret = str.substr(pos,end-pos);
|
||||
|
||||
pos=end;
|
||||
while(pos<close_pos) {
|
||||
if (str[pos]!=',' && str[pos]!=' ' && str[pos]!=':')
|
||||
break;
|
||||
pos++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static Variant _decode_variant(const String& p_string) {
|
||||
|
||||
|
||||
String str = p_string.strip_edges();
|
||||
|
||||
if (str.nocasecmp_to("true")==0)
|
||||
return Variant(true);
|
||||
if (str.nocasecmp_to("false")==0)
|
||||
return Variant(false);
|
||||
if (str.nocasecmp_to("nil")==0)
|
||||
return Variant();
|
||||
if (str.is_valid_float()) {
|
||||
if (str.find(".")==-1)
|
||||
return str.to_int();
|
||||
else
|
||||
return str.to_double();
|
||||
|
||||
}
|
||||
if (str.begins_with("#")) { //string
|
||||
return Color::html(str);
|
||||
}
|
||||
if (str.begins_with("\"")) { //string
|
||||
int end = str.find_last("\"");
|
||||
ERR_FAIL_COND_V(end==0,Variant());
|
||||
return str.substr(1,end-1).xml_unescape();
|
||||
|
||||
}
|
||||
|
||||
if (str.begins_with("[")) { //array
|
||||
|
||||
int close_pos = str.find_last("]");
|
||||
ERR_FAIL_COND_V(close_pos==-1,Variant());
|
||||
Array array;
|
||||
|
||||
int pos=1;
|
||||
|
||||
while(pos<close_pos) {
|
||||
|
||||
String s = _get_chunk(str,pos,close_pos);
|
||||
array.push_back(_decode_variant(s));
|
||||
}
|
||||
return array;
|
||||
|
||||
}
|
||||
|
||||
if (str.begins_with("{")) { //array
|
||||
|
||||
int close_pos = str.find_last("}");
|
||||
ERR_FAIL_COND_V(close_pos==-1,Variant());
|
||||
Dictionary d;
|
||||
|
||||
int pos=1;
|
||||
|
||||
while(pos<close_pos) {
|
||||
|
||||
String key = _get_chunk(str,pos,close_pos);
|
||||
String data = _get_chunk(str,pos,close_pos);
|
||||
d[_decode_variant(key)]=_decode_variant(data);
|
||||
}
|
||||
return d;
|
||||
|
||||
}
|
||||
if (str.begins_with("key")) {
|
||||
Vector<String> params = _decode_params(p_string);
|
||||
ERR_FAIL_COND_V(params.size()!=1 && params.size()!=2,Variant());
|
||||
int scode=0;
|
||||
|
||||
if (params[0].is_numeric())
|
||||
scode=params[0].to_int();
|
||||
else
|
||||
scode=find_keycode(params[0]);
|
||||
|
||||
InputEvent ie;
|
||||
ie.type=InputEvent::KEY;
|
||||
ie.key.scancode=scode;
|
||||
|
||||
if (params.size()==2) {
|
||||
String mods=params[1];
|
||||
if (mods.findn("C")!=-1)
|
||||
ie.key.mod.control=true;
|
||||
if (mods.findn("A")!=-1)
|
||||
ie.key.mod.alt=true;
|
||||
if (mods.findn("S")!=-1)
|
||||
ie.key.mod.shift=true;
|
||||
if (mods.findn("M")!=-1)
|
||||
ie.key.mod.meta=true;
|
||||
}
|
||||
return ie;
|
||||
|
||||
}
|
||||
|
||||
if (str.begins_with("mbutton")) {
|
||||
Vector<String> params = _decode_params(p_string);
|
||||
ERR_FAIL_COND_V(params.size()!=2,Variant());
|
||||
|
||||
InputEvent ie;
|
||||
ie.type=InputEvent::MOUSE_BUTTON;
|
||||
ie.device=params[0].to_int();
|
||||
ie.mouse_button.button_index=params[1].to_int();
|
||||
|
||||
return ie;
|
||||
}
|
||||
|
||||
if (str.begins_with("jbutton")) {
|
||||
Vector<String> params = _decode_params(p_string);
|
||||
ERR_FAIL_COND_V(params.size()!=2,Variant());
|
||||
|
||||
InputEvent ie;
|
||||
ie.type=InputEvent::JOYSTICK_BUTTON;
|
||||
ie.device=params[0].to_int();
|
||||
ie.joy_button.button_index=params[1].to_int();
|
||||
|
||||
return ie;
|
||||
}
|
||||
|
||||
if (str.begins_with("jaxis")) {
|
||||
Vector<String> params = _decode_params(p_string);
|
||||
ERR_FAIL_COND_V(params.size()!=2,Variant());
|
||||
|
||||
InputEvent ie;
|
||||
ie.type=InputEvent::JOYSTICK_MOTION;
|
||||
ie.device=params[0].to_int();
|
||||
ie.joy_motion.axis=params[1].to_int();
|
||||
|
||||
return ie;
|
||||
}
|
||||
if (str.begins_with("img")) {
|
||||
Vector<String> params = _decode_params(p_string);
|
||||
if (params.size()==0) {
|
||||
return Image();
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V(params.size()!=5,Image());
|
||||
|
||||
String format=params[0].strip_edges();
|
||||
|
||||
Image::Format imgformat;
|
||||
|
||||
if (format=="grayscale") {
|
||||
imgformat=Image::FORMAT_GRAYSCALE;
|
||||
} else if (format=="intensity") {
|
||||
imgformat=Image::FORMAT_INTENSITY;
|
||||
} else if (format=="grayscale_alpha") {
|
||||
imgformat=Image::FORMAT_GRAYSCALE_ALPHA;
|
||||
} else if (format=="rgb") {
|
||||
imgformat=Image::FORMAT_RGB;
|
||||
} else if (format=="rgba") {
|
||||
imgformat=Image::FORMAT_RGBA;
|
||||
} else if (format=="indexed") {
|
||||
imgformat=Image::FORMAT_INDEXED;
|
||||
} else if (format=="indexed_alpha") {
|
||||
imgformat=Image::FORMAT_INDEXED_ALPHA;
|
||||
} else if (format=="bc1") {
|
||||
imgformat=Image::FORMAT_BC1;
|
||||
} else if (format=="bc2") {
|
||||
imgformat=Image::FORMAT_BC2;
|
||||
} else if (format=="bc3") {
|
||||
imgformat=Image::FORMAT_BC3;
|
||||
} else if (format=="bc4") {
|
||||
imgformat=Image::FORMAT_BC4;
|
||||
} else if (format=="bc5") {
|
||||
imgformat=Image::FORMAT_BC5;
|
||||
} else if (format=="custom") {
|
||||
imgformat=Image::FORMAT_CUSTOM;
|
||||
} else {
|
||||
|
||||
ERR_FAIL_V( Image() );
|
||||
}
|
||||
|
||||
int mipmaps=params[1].to_int();
|
||||
int w=params[2].to_int();
|
||||
int h=params[3].to_int();
|
||||
|
||||
if (w == 0 && w == 0) {
|
||||
//r_v = Image(w, h, imgformat);
|
||||
return Image();
|
||||
};
|
||||
|
||||
|
||||
String data=params[4];
|
||||
int datasize=data.length()/2;
|
||||
DVector<uint8_t> pixels;
|
||||
pixels.resize(datasize);
|
||||
DVector<uint8_t>::Write wb = pixels.write();
|
||||
const CharType *cptr=data.c_str();
|
||||
|
||||
int idx=0;
|
||||
uint8_t byte;
|
||||
while( idx<datasize*2) {
|
||||
|
||||
CharType c=*(cptr++);
|
||||
|
||||
ERR_FAIL_COND_V(c=='<',ERR_FILE_CORRUPT);
|
||||
|
||||
if ( (c>='0' && c<='9') || (c>='A' && c<='F') || (c>='a' && c<='f') ) {
|
||||
|
||||
if (idx&1) {
|
||||
|
||||
byte|=HEX2CHR(c);
|
||||
wb[idx>>1]=byte;
|
||||
} else {
|
||||
|
||||
byte=HEX2CHR(c)<<4;
|
||||
}
|
||||
|
||||
idx++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
wb = DVector<uint8_t>::Write();
|
||||
|
||||
return Image(w,h,mipmaps,imgformat,pixels);
|
||||
}
|
||||
|
||||
if (str.find(",")!=-1) { //vector2 or vector3
|
||||
Vector<float> farr = str.split_floats(",",true);
|
||||
if (farr.size()==2) {
|
||||
return Point2(farr[0],farr[1]);
|
||||
}
|
||||
if (farr.size()==3) {
|
||||
return Vector3(farr[0],farr[1],farr[2]);
|
||||
}
|
||||
ERR_FAIL_V(Variant());
|
||||
}
|
||||
|
||||
|
||||
return Variant();
|
||||
}
|
||||
|
||||
Error ConfigFile::load(const String& p_path) {
|
||||
|
||||
Error err;
|
||||
FileAccess *f= FileAccess::open(p_path,FileAccess::READ,&err);
|
||||
|
||||
if (err!=OK) {
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
String line;
|
||||
String section;
|
||||
String subpath;
|
||||
|
||||
int line_count = 0;
|
||||
|
||||
while(!f->eof_reached()) {
|
||||
|
||||
String line = f->get_line().strip_edges();
|
||||
line_count++;
|
||||
|
||||
if (line=="")
|
||||
continue;
|
||||
|
||||
// find comments
|
||||
|
||||
{
|
||||
|
||||
int pos=0;
|
||||
while (true) {
|
||||
int ret = line.find(";",pos);
|
||||
if (ret==-1)
|
||||
break;
|
||||
|
||||
int qc=0;
|
||||
for(int i=0;i<ret;i++) {
|
||||
|
||||
if (line[i]=='"')
|
||||
qc++;
|
||||
}
|
||||
|
||||
if ( !(qc&1) ) {
|
||||
//not inside string, real comment
|
||||
line=line.substr(0,ret);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
pos=ret+1;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (line.begins_with("[")) {
|
||||
|
||||
int end = line.find_last("]");
|
||||
ERR_CONTINUE(end!=line.length()-1);
|
||||
|
||||
section=line.substr(1,line.length()-2);
|
||||
|
||||
} else if (line.find("=")!=-1) {
|
||||
|
||||
|
||||
int eqpos = line.find("=");
|
||||
String var=line.substr(0,eqpos).strip_edges();
|
||||
String value=line.substr(eqpos+1,line.length()).strip_edges();
|
||||
|
||||
Variant val = _decode_variant(value);
|
||||
|
||||
set_value(section,var,val);
|
||||
|
||||
} else {
|
||||
|
||||
if (line.length() > 0) {
|
||||
ERR_PRINT(String("Syntax error on line "+itos(line_count)+" of file "+p_path).ascii().get_data());
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
memdelete(f);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ConfigFile::_bind_methods(){
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_value","section","key","value"),&ConfigFile::set_value);
|
||||
ObjectTypeDB::bind_method(_MD("get_value","section","key"),&ConfigFile::get_value);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("has_section","section"),&ConfigFile::has_section);
|
||||
ObjectTypeDB::bind_method(_MD("has_section_key","section","key"),&ConfigFile::has_section_key);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("get_sections"),&ConfigFile::_get_sections);
|
||||
ObjectTypeDB::bind_method(_MD("get_section_keys"),&ConfigFile::_get_section_keys);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("load:Error","path"),&ConfigFile::load);
|
||||
ObjectTypeDB::bind_method(_MD("save:Error","path"),&ConfigFile::save);
|
||||
|
||||
}
|
||||
|
||||
|
||||
ConfigFile::ConfigFile()
|
||||
{
|
||||
}
|
63
core/io/config_file.h
Normal file
63
core/io/config_file.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*************************************************************************/
|
||||
/* config_file.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 CONFIG_FILE_H
|
||||
#define CONFIG_FILE_H
|
||||
|
||||
#include "reference.h"
|
||||
|
||||
|
||||
class ConfigFile : public Reference {
|
||||
|
||||
OBJ_TYPE(ConfigFile,Reference);
|
||||
|
||||
Map< String, Map<String, Variant> > values;
|
||||
|
||||
StringArray _get_sections() const;
|
||||
StringArray _get_section_keys(const String& p_section) const;
|
||||
protected:
|
||||
|
||||
static void _bind_methods();
|
||||
public:
|
||||
|
||||
void set_value(const String& p_section, const String& p_key, const Variant& p_value);
|
||||
Variant get_value(const String& p_section, const String& p_key) const;
|
||||
|
||||
bool has_section(const String& p_section) const;
|
||||
bool has_section_key(const String& p_section,const String& p_key) const;
|
||||
|
||||
void get_sections(List<String> *r_sections) const;
|
||||
void get_section_keys(const String& p_section,List<String> *r_keys) const;
|
||||
|
||||
Error save(const String& p_path);
|
||||
Error load(const String& p_path);
|
||||
|
||||
ConfigFile();
|
||||
};
|
||||
|
||||
#endif // CONFIG_FILE_H
|
131
core/io/crypt.h
Normal file
131
core/io/crypt.h
Normal file
@ -0,0 +1,131 @@
|
||||
/* crypt.h -- base code for crypt/uncrypt ZIPfile
|
||||
|
||||
|
||||
Version 1.01e, February 12th, 2005
|
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant
|
||||
|
||||
This code is a modified version of crypting code in Infozip distribution
|
||||
|
||||
The encryption/decryption parts of this source code (as opposed to the
|
||||
non-echoing password parts) were originally written in Europe. The
|
||||
whole source package can be freely distributed, including from the USA.
|
||||
(Prior to January 2000, re-export from the US was a violation of US law.)
|
||||
|
||||
This encryption code is a direct transcription of the algorithm from
|
||||
Roger Schlafly, described by Phil Katz in the file appnote.txt. This
|
||||
file (appnote.txt) is distributed with the PKZIP program (even in the
|
||||
version without encryption capabilities).
|
||||
|
||||
If you don't need crypting in your application, just define symbols
|
||||
NOCRYPT and NOUNCRYPT.
|
||||
|
||||
This code support the "Traditional PKWARE Encryption".
|
||||
|
||||
The new AES encryption added on Zip format by Winzip (see the page
|
||||
http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong
|
||||
Encryption is not supported.
|
||||
*/
|
||||
|
||||
#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))
|
||||
|
||||
/***********************************************************************
|
||||
* Return the next byte in the pseudo-random sequence
|
||||
*/
|
||||
static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab)
|
||||
{
|
||||
unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an
|
||||
* unpredictable manner on 16-bit systems; not a problem
|
||||
* with any known compiler so far, though */
|
||||
|
||||
temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2;
|
||||
return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Update the encryption keys with the next byte of plain text
|
||||
*/
|
||||
static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c)
|
||||
{
|
||||
(*(pkeys+0)) = CRC32((*(pkeys+0)), c);
|
||||
(*(pkeys+1)) += (*(pkeys+0)) & 0xff;
|
||||
(*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1;
|
||||
{
|
||||
register int keyshift = (int)((*(pkeys+1)) >> 24);
|
||||
(*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* Initialize the encryption keys and the random header according to
|
||||
* the given password.
|
||||
*/
|
||||
static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab)
|
||||
{
|
||||
*(pkeys+0) = 305419896L;
|
||||
*(pkeys+1) = 591751049L;
|
||||
*(pkeys+2) = 878082192L;
|
||||
while (*passwd != '\0') {
|
||||
update_keys(pkeys,pcrc_32_tab,(int)*passwd);
|
||||
passwd++;
|
||||
}
|
||||
}
|
||||
|
||||
#define zdecode(pkeys,pcrc_32_tab,c) \
|
||||
(update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab)))
|
||||
|
||||
#define zencode(pkeys,pcrc_32_tab,c,t) \
|
||||
(t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c))
|
||||
|
||||
#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED
|
||||
|
||||
#define RAND_HEAD_LEN 12
|
||||
/* "last resort" source for second part of crypt seed pattern */
|
||||
# ifndef ZCR_SEED2
|
||||
# define ZCR_SEED2 3141592654UL /* use PI as default pattern */
|
||||
# endif
|
||||
|
||||
static int crypthead(const char* passwd, /* password string */
|
||||
unsigned char* buf, /* where to write header */
|
||||
int bufSize,
|
||||
unsigned long* pkeys,
|
||||
const unsigned long* pcrc_32_tab,
|
||||
unsigned long crcForCrypting)
|
||||
{
|
||||
int n; /* index in random header */
|
||||
int t; /* temporary */
|
||||
int c; /* random byte */
|
||||
unsigned char header[RAND_HEAD_LEN-2]; /* random header */
|
||||
static unsigned calls = 0; /* ensure different random header each time */
|
||||
|
||||
if (bufSize<RAND_HEAD_LEN)
|
||||
return 0;
|
||||
|
||||
/* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the
|
||||
* output of rand() to get less predictability, since rand() is
|
||||
* often poorly implemented.
|
||||
*/
|
||||
if (++calls == 1)
|
||||
{
|
||||
srand((unsigned)(time(NULL) ^ ZCR_SEED2));
|
||||
}
|
||||
init_keys(passwd, pkeys, pcrc_32_tab);
|
||||
for (n = 0; n < RAND_HEAD_LEN-2; n++)
|
||||
{
|
||||
c = (rand() >> 7) & 0xff;
|
||||
header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t);
|
||||
}
|
||||
/* Encrypt random header (last two bytes is high word of crc) */
|
||||
init_keys(passwd, pkeys, pcrc_32_tab);
|
||||
for (n = 0; n < RAND_HEAD_LEN-2; n++)
|
||||
{
|
||||
buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t);
|
||||
}
|
||||
buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t);
|
||||
buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t);
|
||||
return n;
|
||||
}
|
||||
|
||||
#endif
|
551
core/io/fastlz.c
Normal file
551
core/io/fastlz.c
Normal file
@ -0,0 +1,551 @@
|
||||
/*
|
||||
FastLZ - lightning-fast lossless compression library
|
||||
|
||||
Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
|
||||
Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
|
||||
Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#if !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR)
|
||||
|
||||
/*
|
||||
* Always check for bound when decompressing.
|
||||
* Generally it is best to leave it defined.
|
||||
*/
|
||||
#define FASTLZ_SAFE
|
||||
|
||||
/*
|
||||
* Give hints to the compiler for branch prediction optimization.
|
||||
*/
|
||||
#if defined(__GNUC__) && (__GNUC__ > 2)
|
||||
#define FASTLZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1))
|
||||
#define FASTLZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0))
|
||||
#else
|
||||
#define FASTLZ_EXPECT_CONDITIONAL(c) (c)
|
||||
#define FASTLZ_UNEXPECT_CONDITIONAL(c) (c)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Use inlined functions for supported systems.
|
||||
*/
|
||||
#if defined(__GNUC__) || defined(__DMC__) || defined(__POCC__) || defined(__WATCOMC__) || defined(__SUNPRO_C)
|
||||
#define FASTLZ_INLINE inline
|
||||
#elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__)
|
||||
#define FASTLZ_INLINE __inline
|
||||
#else
|
||||
#define FASTLZ_INLINE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Prevent accessing more than 8-bit at once, except on x86 architectures.
|
||||
*/
|
||||
#if !defined(FASTLZ_STRICT_ALIGN)
|
||||
#define FASTLZ_STRICT_ALIGN
|
||||
#if defined(__i386__) || defined(__386) /* GNU C, Sun Studio */
|
||||
#undef FASTLZ_STRICT_ALIGN
|
||||
#elif defined(__i486__) || defined(__i586__) || defined(__i686__) /* GNU C */
|
||||
#undef FASTLZ_STRICT_ALIGN
|
||||
#elif defined(_M_IX86) /* Intel, MSVC */
|
||||
#undef FASTLZ_STRICT_ALIGN
|
||||
#elif defined(__386)
|
||||
#undef FASTLZ_STRICT_ALIGN
|
||||
#elif defined(_X86_) /* MinGW */
|
||||
#undef FASTLZ_STRICT_ALIGN
|
||||
#elif defined(__I86__) /* Digital Mars */
|
||||
#undef FASTLZ_STRICT_ALIGN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* FIXME: use preprocessor magic to set this on different platforms!
|
||||
*/
|
||||
typedef unsigned char flzuint8;
|
||||
typedef unsigned short flzuint16;
|
||||
typedef unsigned int flzuint32;
|
||||
|
||||
/* prototypes */
|
||||
int fastlz_compress(const void* input, int length, void* output);
|
||||
int fastlz_compress_level(int level, const void* input, int length, void* output);
|
||||
int fastlz_decompress(const void* input, int length, void* output, int maxout);
|
||||
|
||||
#define MAX_COPY 32
|
||||
#define MAX_LEN 264 /* 256 + 8 */
|
||||
#define MAX_DISTANCE 8192
|
||||
|
||||
#if !defined(FASTLZ_STRICT_ALIGN)
|
||||
#define FASTLZ_READU16(p) *((const flzuint16*)(p))
|
||||
#else
|
||||
#define FASTLZ_READU16(p) ((p)[0] | (p)[1]<<8)
|
||||
#endif
|
||||
|
||||
#define HASH_LOG 13
|
||||
#define HASH_SIZE (1<< HASH_LOG)
|
||||
#define HASH_MASK (HASH_SIZE-1)
|
||||
#define HASH_FUNCTION(v,p) { v = FASTLZ_READU16(p); v ^= FASTLZ_READU16(p+1)^(v>>(16-HASH_LOG));v &= HASH_MASK; }
|
||||
|
||||
#undef FASTLZ_LEVEL
|
||||
#define FASTLZ_LEVEL 1
|
||||
|
||||
#undef FASTLZ_COMPRESSOR
|
||||
#undef FASTLZ_DECOMPRESSOR
|
||||
#define FASTLZ_COMPRESSOR fastlz1_compress
|
||||
#define FASTLZ_DECOMPRESSOR fastlz1_decompress
|
||||
static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output);
|
||||
static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout);
|
||||
#include "fastlz.c"
|
||||
|
||||
#undef FASTLZ_LEVEL
|
||||
#define FASTLZ_LEVEL 2
|
||||
|
||||
#undef MAX_DISTANCE
|
||||
#define MAX_DISTANCE 8191
|
||||
#define MAX_FARDISTANCE (65535+MAX_DISTANCE-1)
|
||||
|
||||
#undef FASTLZ_COMPRESSOR
|
||||
#undef FASTLZ_DECOMPRESSOR
|
||||
#define FASTLZ_COMPRESSOR fastlz2_compress
|
||||
#define FASTLZ_DECOMPRESSOR fastlz2_decompress
|
||||
static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output);
|
||||
static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout);
|
||||
#include "fastlz.c"
|
||||
|
||||
int fastlz_compress(const void* input, int length, void* output)
|
||||
{
|
||||
/* for short block, choose fastlz1 */
|
||||
if(length < 65536)
|
||||
return fastlz1_compress(input, length, output);
|
||||
|
||||
/* else... */
|
||||
return fastlz2_compress(input, length, output);
|
||||
}
|
||||
|
||||
int fastlz_decompress(const void* input, int length, void* output, int maxout)
|
||||
{
|
||||
/* magic identifier for compression level */
|
||||
int level = ((*(const flzuint8*)input) >> 5) + 1;
|
||||
|
||||
if(level == 1)
|
||||
return fastlz1_decompress(input, length, output, maxout);
|
||||
if(level == 2)
|
||||
return fastlz2_decompress(input, length, output, maxout);
|
||||
|
||||
/* unknown level, trigger error */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fastlz_compress_level(int level, const void* input, int length, void* output)
|
||||
{
|
||||
if(level == 1)
|
||||
return fastlz1_compress(input, length, output);
|
||||
if(level == 2)
|
||||
return fastlz2_compress(input, length, output);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */
|
||||
|
||||
static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output)
|
||||
{
|
||||
const flzuint8* ip = (const flzuint8*) input;
|
||||
const flzuint8* ip_bound = ip + length - 2;
|
||||
const flzuint8* ip_limit = ip + length - 12;
|
||||
flzuint8* op = (flzuint8*) output;
|
||||
|
||||
const flzuint8* htab[HASH_SIZE];
|
||||
const flzuint8** hslot;
|
||||
flzuint32 hval;
|
||||
|
||||
flzuint32 copy;
|
||||
|
||||
/* sanity check */
|
||||
if(FASTLZ_UNEXPECT_CONDITIONAL(length < 4))
|
||||
{
|
||||
if(length)
|
||||
{
|
||||
/* create literal copy only */
|
||||
*op++ = length-1;
|
||||
ip_bound++;
|
||||
while(ip <= ip_bound)
|
||||
*op++ = *ip++;
|
||||
return length+1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* initializes hash table */
|
||||
for (hslot = htab; hslot < htab + HASH_SIZE; hslot++)
|
||||
*hslot = ip;
|
||||
|
||||
/* we start with literal copy */
|
||||
copy = 2;
|
||||
*op++ = MAX_COPY-1;
|
||||
*op++ = *ip++;
|
||||
*op++ = *ip++;
|
||||
|
||||
/* main loop */
|
||||
while(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit))
|
||||
{
|
||||
const flzuint8* ref;
|
||||
flzuint32 distance;
|
||||
|
||||
/* minimum match length */
|
||||
flzuint32 len = 3;
|
||||
|
||||
/* comparison starting-point */
|
||||
const flzuint8* anchor = ip;
|
||||
|
||||
/* check for a run */
|
||||
#if FASTLZ_LEVEL==2
|
||||
if(ip[0] == ip[-1] && FASTLZ_READU16(ip-1)==FASTLZ_READU16(ip+1))
|
||||
{
|
||||
distance = 1;
|
||||
ip += 3;
|
||||
ref = anchor - 1 + 3;
|
||||
goto match;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* find potential match */
|
||||
HASH_FUNCTION(hval,ip);
|
||||
hslot = htab + hval;
|
||||
ref = htab[hval];
|
||||
|
||||
/* calculate distance to the match */
|
||||
distance = anchor - ref;
|
||||
|
||||
/* update hash table */
|
||||
*hslot = anchor;
|
||||
|
||||
/* is this a match? check the first 3 bytes */
|
||||
if(distance==0 ||
|
||||
#if FASTLZ_LEVEL==1
|
||||
(distance >= MAX_DISTANCE) ||
|
||||
#else
|
||||
(distance >= MAX_FARDISTANCE) ||
|
||||
#endif
|
||||
*ref++ != *ip++ || *ref++!=*ip++ || *ref++!=*ip++)
|
||||
goto literal;
|
||||
|
||||
#if FASTLZ_LEVEL==2
|
||||
/* far, needs at least 5-byte match */
|
||||
if(distance >= MAX_DISTANCE)
|
||||
{
|
||||
if(*ip++ != *ref++ || *ip++!= *ref++)
|
||||
goto literal;
|
||||
len += 2;
|
||||
}
|
||||
|
||||
match:
|
||||
#endif
|
||||
|
||||
/* last matched byte */
|
||||
ip = anchor + len;
|
||||
|
||||
/* distance is biased */
|
||||
distance--;
|
||||
|
||||
if(!distance)
|
||||
{
|
||||
/* zero distance means a run */
|
||||
flzuint8 x = ip[-1];
|
||||
while(ip < ip_bound)
|
||||
if(*ref++ != x) break; else ip++;
|
||||
}
|
||||
else
|
||||
for(;;)
|
||||
{
|
||||
/* safe because the outer check against ip limit */
|
||||
if(*ref++ != *ip++) break;
|
||||
if(*ref++ != *ip++) break;
|
||||
if(*ref++ != *ip++) break;
|
||||
if(*ref++ != *ip++) break;
|
||||
if(*ref++ != *ip++) break;
|
||||
if(*ref++ != *ip++) break;
|
||||
if(*ref++ != *ip++) break;
|
||||
if(*ref++ != *ip++) break;
|
||||
while(ip < ip_bound)
|
||||
if(*ref++ != *ip++) break;
|
||||
break;
|
||||
}
|
||||
|
||||
/* if we have copied something, adjust the copy count */
|
||||
if(copy)
|
||||
/* copy is biased, '0' means 1 byte copy */
|
||||
*(op-copy-1) = copy-1;
|
||||
else
|
||||
/* back, to overwrite the copy count */
|
||||
op--;
|
||||
|
||||
/* reset literal counter */
|
||||
copy = 0;
|
||||
|
||||
/* length is biased, '1' means a match of 3 bytes */
|
||||
ip -= 3;
|
||||
len = ip - anchor;
|
||||
|
||||
/* encode the match */
|
||||
#if FASTLZ_LEVEL==2
|
||||
if(distance < MAX_DISTANCE)
|
||||
{
|
||||
if(len < 7)
|
||||
{
|
||||
*op++ = (len << 5) + (distance >> 8);
|
||||
*op++ = (distance & 255);
|
||||
}
|
||||
else
|
||||
{
|
||||
*op++ = (7 << 5) + (distance >> 8);
|
||||
for(len-=7; len >= 255; len-= 255)
|
||||
*op++ = 255;
|
||||
*op++ = len;
|
||||
*op++ = (distance & 255);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* far away, but not yet in the another galaxy... */
|
||||
if(len < 7)
|
||||
{
|
||||
distance -= MAX_DISTANCE;
|
||||
*op++ = (len << 5) + 31;
|
||||
*op++ = 255;
|
||||
*op++ = distance >> 8;
|
||||
*op++ = distance & 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
distance -= MAX_DISTANCE;
|
||||
*op++ = (7 << 5) + 31;
|
||||
for(len-=7; len >= 255; len-= 255)
|
||||
*op++ = 255;
|
||||
*op++ = len;
|
||||
*op++ = 255;
|
||||
*op++ = distance >> 8;
|
||||
*op++ = distance & 255;
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
if(FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN-2))
|
||||
while(len > MAX_LEN-2)
|
||||
{
|
||||
*op++ = (7 << 5) + (distance >> 8);
|
||||
*op++ = MAX_LEN - 2 - 7 -2;
|
||||
*op++ = (distance & 255);
|
||||
len -= MAX_LEN-2;
|
||||
}
|
||||
|
||||
if(len < 7)
|
||||
{
|
||||
*op++ = (len << 5) + (distance >> 8);
|
||||
*op++ = (distance & 255);
|
||||
}
|
||||
else
|
||||
{
|
||||
*op++ = (7 << 5) + (distance >> 8);
|
||||
*op++ = len - 7;
|
||||
*op++ = (distance & 255);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* update the hash at match boundary */
|
||||
HASH_FUNCTION(hval,ip);
|
||||
htab[hval] = ip++;
|
||||
HASH_FUNCTION(hval,ip);
|
||||
htab[hval] = ip++;
|
||||
|
||||
/* assuming literal copy */
|
||||
*op++ = MAX_COPY-1;
|
||||
|
||||
continue;
|
||||
|
||||
literal:
|
||||
*op++ = *anchor++;
|
||||
ip = anchor;
|
||||
copy++;
|
||||
if(FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY))
|
||||
{
|
||||
copy = 0;
|
||||
*op++ = MAX_COPY-1;
|
||||
}
|
||||
}
|
||||
|
||||
/* left-over as literal copy */
|
||||
ip_bound++;
|
||||
while(ip <= ip_bound)
|
||||
{
|
||||
*op++ = *ip++;
|
||||
copy++;
|
||||
if(copy == MAX_COPY)
|
||||
{
|
||||
copy = 0;
|
||||
*op++ = MAX_COPY-1;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we have copied something, adjust the copy length */
|
||||
if(copy)
|
||||
*(op-copy-1) = copy-1;
|
||||
else
|
||||
op--;
|
||||
|
||||
#if FASTLZ_LEVEL==2
|
||||
/* marker for fastlz2 */
|
||||
*(flzuint8*)output |= (1 << 5);
|
||||
#endif
|
||||
|
||||
return op - (flzuint8*)output;
|
||||
}
|
||||
|
||||
static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout)
|
||||
{
|
||||
const flzuint8* ip = (const flzuint8*) input;
|
||||
const flzuint8* ip_limit = ip + length;
|
||||
flzuint8* op = (flzuint8*) output;
|
||||
flzuint8* op_limit = op + maxout;
|
||||
flzuint32 ctrl = (*ip++) & 31;
|
||||
int loop = 1;
|
||||
|
||||
do
|
||||
{
|
||||
const flzuint8* ref = op;
|
||||
flzuint32 len = ctrl >> 5;
|
||||
flzuint32 ofs = (ctrl & 31) << 8;
|
||||
|
||||
if(ctrl >= 32)
|
||||
{
|
||||
#if FASTLZ_LEVEL==2
|
||||
flzuint8 code;
|
||||
#endif
|
||||
len--;
|
||||
ref -= ofs;
|
||||
if (len == 7-1)
|
||||
#if FASTLZ_LEVEL==1
|
||||
len += *ip++;
|
||||
ref -= *ip++;
|
||||
#else
|
||||
do
|
||||
{
|
||||
code = *ip++;
|
||||
len += code;
|
||||
} while (code==255);
|
||||
code = *ip++;
|
||||
ref -= code;
|
||||
|
||||
/* match from 16-bit distance */
|
||||
if(FASTLZ_UNEXPECT_CONDITIONAL(code==255))
|
||||
if(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8)))
|
||||
{
|
||||
ofs = (*ip++) << 8;
|
||||
ofs += *ip++;
|
||||
ref = op - ofs - MAX_DISTANCE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FASTLZ_SAFE
|
||||
if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 > op_limit))
|
||||
return 0;
|
||||
|
||||
if (FASTLZ_UNEXPECT_CONDITIONAL(ref-1 < (flzuint8 *)output))
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
if(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit))
|
||||
ctrl = *ip++;
|
||||
else
|
||||
loop = 0;
|
||||
|
||||
if(ref == op)
|
||||
{
|
||||
/* optimize copy for a run */
|
||||
flzuint8 b = ref[-1];
|
||||
*op++ = b;
|
||||
*op++ = b;
|
||||
*op++ = b;
|
||||
for(; len; --len)
|
||||
*op++ = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if !defined(FASTLZ_STRICT_ALIGN)
|
||||
const flzuint16* p;
|
||||
flzuint16* q;
|
||||
#endif
|
||||
/* copy from reference */
|
||||
ref--;
|
||||
*op++ = *ref++;
|
||||
*op++ = *ref++;
|
||||
*op++ = *ref++;
|
||||
|
||||
#if !defined(FASTLZ_STRICT_ALIGN)
|
||||
/* copy a byte, so that now it's word aligned */
|
||||
if(len & 1)
|
||||
{
|
||||
*op++ = *ref++;
|
||||
len--;
|
||||
}
|
||||
|
||||
/* copy 16-bit at once */
|
||||
q = (flzuint16*) op;
|
||||
op += len;
|
||||
p = (const flzuint16*) ref;
|
||||
for(len>>=1; len > 4; len-=4)
|
||||
{
|
||||
*q++ = *p++;
|
||||
*q++ = *p++;
|
||||
*q++ = *p++;
|
||||
*q++ = *p++;
|
||||
}
|
||||
for(; len; --len)
|
||||
*q++ = *p++;
|
||||
#else
|
||||
for(; len; --len)
|
||||
*op++ = *ref++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ctrl++;
|
||||
#ifdef FASTLZ_SAFE
|
||||
if (FASTLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit))
|
||||
return 0;
|
||||
if (FASTLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit))
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
*op++ = *ip++;
|
||||
for(--ctrl; ctrl; ctrl--)
|
||||
*op++ = *ip++;
|
||||
|
||||
loop = FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit);
|
||||
if(loop)
|
||||
ctrl = *ip++;
|
||||
}
|
||||
}
|
||||
while(FASTLZ_EXPECT_CONDITIONAL(loop));
|
||||
|
||||
return op - (flzuint8*)output;
|
||||
}
|
||||
|
||||
#endif /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */
|
100
core/io/fastlz.h
Normal file
100
core/io/fastlz.h
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
FastLZ - lightning-fast lossless compression library
|
||||
|
||||
Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
|
||||
Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
|
||||
Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
|
||||
|
||||
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 FASTLZ_H
|
||||
#define FASTLZ_H
|
||||
|
||||
#define FASTLZ_VERSION 0x000100
|
||||
|
||||
#define FASTLZ_VERSION_MAJOR 0
|
||||
#define FASTLZ_VERSION_MINOR 0
|
||||
#define FASTLZ_VERSION_REVISION 0
|
||||
|
||||
#define FASTLZ_VERSION_STRING "0.1.0"
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Compress a block of data in the input buffer and returns the size of
|
||||
compressed block. The size of input buffer is specified by length. The
|
||||
minimum input buffer size is 16.
|
||||
|
||||
The output buffer must be at least 5% larger than the input buffer
|
||||
and can not be smaller than 66 bytes.
|
||||
|
||||
If the input is not compressible, the return value might be larger than
|
||||
length (input buffer size).
|
||||
|
||||
The input buffer and the output buffer can not overlap.
|
||||
*/
|
||||
|
||||
int fastlz_compress(const void* input, int length, void* output);
|
||||
|
||||
/**
|
||||
Decompress a block of compressed data and returns the size of the
|
||||
decompressed block. If error occurs, e.g. the compressed data is
|
||||
corrupted or the output buffer is not large enough, then 0 (zero)
|
||||
will be returned instead.
|
||||
|
||||
The input buffer and the output buffer can not overlap.
|
||||
|
||||
Decompression is memory safe and guaranteed not to write the output buffer
|
||||
more than what is specified in maxout.
|
||||
*/
|
||||
|
||||
int fastlz_decompress(const void* input, int length, void* output, int maxout);
|
||||
|
||||
/**
|
||||
Compress a block of data in the input buffer and returns the size of
|
||||
compressed block. The size of input buffer is specified by length. The
|
||||
minimum input buffer size is 16.
|
||||
|
||||
The output buffer must be at least 5% larger than the input buffer
|
||||
and can not be smaller than 66 bytes.
|
||||
|
||||
If the input is not compressible, the return value might be larger than
|
||||
length (input buffer size).
|
||||
|
||||
The input buffer and the output buffer can not overlap.
|
||||
|
||||
Compression level can be specified in parameter level. At the moment,
|
||||
only level 1 and level 2 are supported.
|
||||
Level 1 is the fastest compression and generally useful for short data.
|
||||
Level 2 is slightly slower but it gives better compression ratio.
|
||||
|
||||
Note that the compressed data, regardless of the level, can always be
|
||||
decompressed using the function fastlz_decompress above.
|
||||
*/
|
||||
|
||||
int fastlz_compress_level(int level, const void* input, int length, void* output);
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FASTLZ_H */
|
184
core/io/file_access_buffered.cpp
Normal file
184
core/io/file_access_buffered.cpp
Normal file
@ -0,0 +1,184 @@
|
||||
/*************************************************************************/
|
||||
/* file_access_buffered.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "file_access_buffered.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "error_macros.h"
|
||||
|
||||
Error FileAccessBuffered::set_error(Error p_error) const {
|
||||
|
||||
return (last_error = p_error);
|
||||
};
|
||||
|
||||
void FileAccessBuffered::set_cache_size(int p_size) {
|
||||
|
||||
cache_size = p_size;
|
||||
};
|
||||
|
||||
int FileAccessBuffered::get_cache_size() {
|
||||
|
||||
return cache_size;
|
||||
};
|
||||
|
||||
int FileAccessBuffered::cache_data_left() const {
|
||||
|
||||
if (file.offset >= file.size) {
|
||||
return 0;
|
||||
};
|
||||
|
||||
if (cache.offset == -1 || file.offset < cache.offset || file.offset >= cache.offset + cache.buffer.size()) {
|
||||
|
||||
return read_data_block(file.offset, cache_size);
|
||||
|
||||
} else {
|
||||
|
||||
return cache.buffer.size() - (file.offset - cache.offset);
|
||||
};
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
void FileAccessBuffered::seek(size_t p_position) {
|
||||
|
||||
file.offset = p_position;
|
||||
};
|
||||
|
||||
void FileAccessBuffered::seek_end(int64_t p_position) {
|
||||
|
||||
file.offset = file.size + p_position;
|
||||
};
|
||||
|
||||
size_t FileAccessBuffered::get_pos() const {
|
||||
|
||||
return file.offset;
|
||||
};
|
||||
|
||||
size_t FileAccessBuffered::get_len() const {
|
||||
|
||||
return file.size;
|
||||
};
|
||||
|
||||
bool FileAccessBuffered::eof_reached() const {
|
||||
|
||||
return file.offset > file.size;
|
||||
};
|
||||
|
||||
uint8_t FileAccessBuffered::get_8() const {
|
||||
|
||||
ERR_FAIL_COND_V(!file.open,0);
|
||||
|
||||
uint8_t byte = 0;
|
||||
if (cache_data_left() >= 1) {
|
||||
|
||||
byte = cache.buffer[file.offset - cache.offset];
|
||||
};
|
||||
|
||||
++file.offset;
|
||||
|
||||
return byte;
|
||||
};
|
||||
|
||||
int FileAccessBuffered::get_buffer(uint8_t *p_dest,int p_elements) const {
|
||||
|
||||
ERR_FAIL_COND_V(!file.open, -1);
|
||||
|
||||
if (p_elements > cache_size) {
|
||||
|
||||
int total_read = 0;
|
||||
|
||||
if (!(cache.offset == -1 || file.offset < cache.offset || file.offset >= cache.offset + cache.buffer.size())) {
|
||||
|
||||
int size = (cache.buffer.size() - (file.offset - cache.offset));
|
||||
size = size - (size % 4);
|
||||
//DVector<uint8_t>::Read read = cache.buffer.read();
|
||||
//memcpy(p_dest, read.ptr() + (file.offset - cache.offset), size);
|
||||
memcpy(p_dest, cache.buffer.ptr() + (file.offset - cache.offset), size);
|
||||
p_dest += size;
|
||||
p_elements -= size;
|
||||
file.offset += size;
|
||||
total_read += size;
|
||||
};
|
||||
|
||||
int err = read_data_block(file.offset, p_elements, p_dest);
|
||||
if (err >= 0) {
|
||||
total_read += err;
|
||||
file.offset += err;
|
||||
};
|
||||
|
||||
return total_read;
|
||||
};
|
||||
|
||||
|
||||
int to_read = p_elements;
|
||||
int total_read = 0;
|
||||
while (to_read > 0) {
|
||||
|
||||
int left = cache_data_left();
|
||||
if (left == 0) {
|
||||
if (to_read > 0) {
|
||||
file.offset += to_read;
|
||||
};
|
||||
return total_read;
|
||||
};
|
||||
if (left < 0) {
|
||||
return left;
|
||||
};
|
||||
|
||||
int r = MIN(left, to_read);
|
||||
//DVector<uint8_t>::Read read = cache.buffer.read();
|
||||
//memcpy(p_dest+total_read, &read.ptr()[file.offset - cache.offset], r);
|
||||
memcpy(p_dest+total_read, cache.buffer.ptr() + (file.offset - cache.offset), r);
|
||||
|
||||
file.offset += r;
|
||||
total_read += r;
|
||||
to_read -= r;
|
||||
};
|
||||
|
||||
return p_elements;
|
||||
};
|
||||
|
||||
bool FileAccessBuffered::is_open() const {
|
||||
|
||||
return file.open;
|
||||
};
|
||||
|
||||
Error FileAccessBuffered::get_error() const {
|
||||
|
||||
return last_error;
|
||||
};
|
||||
|
||||
FileAccessBuffered::FileAccessBuffered() {
|
||||
|
||||
cache_size = DEFAULT_CACHE_SIZE;
|
||||
};
|
||||
|
||||
FileAccessBuffered::~FileAccessBuffered(){
|
||||
|
||||
}
|
97
core/io/file_access_buffered.h
Normal file
97
core/io/file_access_buffered.h
Normal file
@ -0,0 +1,97 @@
|
||||
/*************************************************************************/
|
||||
/* file_access_buffered.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 FILE_ACCESS_BUFFERED_H
|
||||
#define FILE_ACCESS_BUFFERED_H
|
||||
|
||||
#include "os/file_access.h"
|
||||
|
||||
#include "dvector.h"
|
||||
#include "ustring.h"
|
||||
|
||||
class FileAccessBuffered : public FileAccess {
|
||||
|
||||
public:
|
||||
enum {
|
||||
DEFAULT_CACHE_SIZE = 128 * 1024,
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
int cache_size;
|
||||
|
||||
int cache_data_left() const;
|
||||
mutable Error last_error;
|
||||
|
||||
protected:
|
||||
|
||||
Error set_error(Error p_error) const;
|
||||
|
||||
mutable struct File {
|
||||
|
||||
bool open;
|
||||
int size;
|
||||
int offset;
|
||||
String name;
|
||||
int access_flags;
|
||||
} file;
|
||||
|
||||
mutable struct Cache {
|
||||
|
||||
Vector<uint8_t> buffer;
|
||||
int offset;
|
||||
} cache;
|
||||
|
||||
virtual int read_data_block(int p_offset, int p_size, uint8_t *p_dest = 0) const =0;
|
||||
|
||||
void set_cache_size(int p_size);
|
||||
int get_cache_size();
|
||||
|
||||
public:
|
||||
|
||||
virtual size_t get_pos() const; ///< get position in the file
|
||||
virtual size_t get_len() const; ///< get size of the file
|
||||
|
||||
virtual void seek(size_t p_position); ///< seek to a given position
|
||||
virtual void seek_end(int64_t p_position=0); ///< seek from the end of file
|
||||
|
||||
virtual bool eof_reached() const;
|
||||
|
||||
virtual uint8_t get_8() const;
|
||||
virtual int get_buffer(uint8_t *p_dst,int p_length) const; ///< get an array of bytes
|
||||
|
||||
virtual bool is_open() const;
|
||||
|
||||
virtual Error get_error() const;
|
||||
|
||||
FileAccessBuffered();
|
||||
virtual ~FileAccessBuffered();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
147
core/io/file_access_buffered_fa.h
Normal file
147
core/io/file_access_buffered_fa.h
Normal file
@ -0,0 +1,147 @@
|
||||
/*************************************************************************/
|
||||
/* file_access_buffered_fa.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 FILE_ACCESS_BUFFERED_FA_H
|
||||
#define FILE_ACCESS_BUFFERED_FA_H
|
||||
|
||||
#include "core/io/file_access_buffered.h"
|
||||
|
||||
template<class T>
|
||||
class FileAccessBufferedFA : public FileAccessBuffered {
|
||||
|
||||
T f;
|
||||
|
||||
int read_data_block(int p_offset, int p_size, uint8_t *p_dest = 0) const {
|
||||
|
||||
ERR_FAIL_COND_V( !f.is_open(), -1 );
|
||||
|
||||
((T*)&f)->seek(p_offset);
|
||||
|
||||
if (p_dest) {
|
||||
|
||||
f.get_buffer(p_dest, p_size);
|
||||
return p_size;
|
||||
|
||||
} else {
|
||||
|
||||
cache.offset = p_offset;
|
||||
cache.buffer.resize(p_size);
|
||||
|
||||
// on dvector
|
||||
//DVector<uint8_t>::Write write = cache.buffer.write();
|
||||
//f.get_buffer(write.ptr(), p_size);
|
||||
|
||||
// on vector
|
||||
f.get_buffer(cache.buffer.ptr(), p_size);
|
||||
|
||||
return p_size;
|
||||
};
|
||||
};
|
||||
|
||||
static FileAccess* create() {
|
||||
|
||||
return memnew( FileAccessBufferedFA<T>() );
|
||||
};
|
||||
|
||||
protected:
|
||||
virtual void _set_access_type(AccessType p_access) {
|
||||
f._set_access_type(p_access);
|
||||
FileAccessBuffered::_set_access_type(p_access);
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
|
||||
void store_8(uint8_t p_dest) {
|
||||
|
||||
f.store_8(p_dest);
|
||||
};
|
||||
|
||||
void store_buffer(const uint8_t *p_src,int p_length) {
|
||||
|
||||
f.store_buffer(p_src, p_length);
|
||||
};
|
||||
|
||||
bool file_exists(const String& p_name) {
|
||||
|
||||
return f.file_exists(p_name);
|
||||
};
|
||||
|
||||
Error _open(const String& p_path, int p_mode_flags) {
|
||||
|
||||
close();
|
||||
|
||||
Error ret = f._open(p_path, p_mode_flags);
|
||||
if (ret !=OK)
|
||||
return ret;
|
||||
//ERR_FAIL_COND_V( ret != OK, ret );
|
||||
|
||||
file.size = f.get_len();
|
||||
file.offset = 0;
|
||||
file.open = true;
|
||||
file.name = p_path;
|
||||
file.access_flags = p_mode_flags;
|
||||
|
||||
cache.buffer.resize(0);
|
||||
cache.offset = 0;
|
||||
|
||||
return set_error(OK);
|
||||
};
|
||||
|
||||
void close() {
|
||||
|
||||
f.close();
|
||||
|
||||
file.offset = 0;
|
||||
file.size = 0;
|
||||
file.open = false;
|
||||
file.name = "";
|
||||
|
||||
cache.buffer.resize(0);
|
||||
cache.offset = 0;
|
||||
set_error(OK);
|
||||
};
|
||||
|
||||
// static void make_default() {
|
||||
|
||||
//FileAccess::create_func = FileAccessBufferedFA<T>::create;
|
||||
// };
|
||||
|
||||
virtual uint64_t _get_modified_time(const String& p_file) {
|
||||
|
||||
return f._get_modified_time(p_file);
|
||||
}
|
||||
|
||||
FileAccessBufferedFA() {
|
||||
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
#endif // FILE_ACCESS_BUFFERED_FA_H
|
421
core/io/file_access_compressed.cpp
Normal file
421
core/io/file_access_compressed.cpp
Normal file
@ -0,0 +1,421 @@
|
||||
/*************************************************************************/
|
||||
/* file_access_compressed.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "file_access_compressed.h"
|
||||
#include "print_string.h"
|
||||
void FileAccessCompressed::configure(const String& p_magic, Compression::Mode p_mode, int p_block_size) {
|
||||
|
||||
magic=p_magic.ascii().get_data();
|
||||
if (magic.length()>4)
|
||||
magic=magic.substr(0,4);
|
||||
else {
|
||||
while(magic.length()<4)
|
||||
magic+=" ";
|
||||
}
|
||||
|
||||
cmode=p_mode;
|
||||
block_size=p_block_size;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#define WRITE_FIT(m_bytes) \
|
||||
{\
|
||||
if (write_pos+(m_bytes) > write_max) {\
|
||||
write_max=write_pos+(m_bytes);\
|
||||
}\
|
||||
if (write_max > write_buffer_size) {\
|
||||
write_buffer_size = nearest_power_of_2( write_max );\
|
||||
buffer.resize(write_buffer_size);\
|
||||
write_ptr=buffer.ptr();\
|
||||
}\
|
||||
}
|
||||
|
||||
|
||||
Error FileAccessCompressed::open_after_magic(FileAccess *p_base) {
|
||||
|
||||
|
||||
f=p_base;
|
||||
cmode=(Compression::Mode)f->get_32();
|
||||
block_size=f->get_32();
|
||||
read_total=f->get_32();
|
||||
int bc = (read_total/block_size)+1;
|
||||
int acc_ofs=f->get_pos()+bc*4;
|
||||
int max_bs=0;
|
||||
for(int i=0;i<bc;i++) {
|
||||
|
||||
ReadBlock rb;
|
||||
rb.offset=acc_ofs;
|
||||
rb.csize=f->get_32();
|
||||
acc_ofs+=rb.csize;
|
||||
max_bs=MAX(max_bs,rb.csize);
|
||||
read_blocks.push_back(rb);
|
||||
|
||||
|
||||
}
|
||||
|
||||
comp_buffer.resize(max_bs);
|
||||
buffer.resize(block_size);
|
||||
read_ptr=buffer.ptr();
|
||||
f->get_buffer(comp_buffer.ptr(),read_blocks[0].csize);
|
||||
at_end=false;
|
||||
read_eof=false;
|
||||
read_block_count=bc;
|
||||
read_block_size=read_blocks.size()==1?read_total:block_size;
|
||||
|
||||
Compression::decompress(buffer.ptr(),read_block_size,comp_buffer.ptr(),read_blocks[0].csize,cmode);
|
||||
read_block=0;
|
||||
read_pos=0;
|
||||
|
||||
return OK;
|
||||
|
||||
}
|
||||
|
||||
Error FileAccessCompressed::_open(const String& p_path, int p_mode_flags){
|
||||
|
||||
ERR_FAIL_COND_V(p_mode_flags==READ_WRITE,ERR_UNAVAILABLE);
|
||||
|
||||
if (f)
|
||||
close();
|
||||
|
||||
|
||||
Error err;
|
||||
f = FileAccess::open(p_path,p_mode_flags,&err);
|
||||
if (err!=OK) {
|
||||
//not openable
|
||||
|
||||
f=NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
if (p_mode_flags&WRITE) {
|
||||
|
||||
buffer.clear();
|
||||
writing=true;
|
||||
write_pos=0;
|
||||
write_buffer_size=256;
|
||||
buffer.resize(256);
|
||||
write_max=0;
|
||||
write_ptr=buffer.ptr();
|
||||
|
||||
|
||||
|
||||
//don't store anything else unless it's done saving!
|
||||
} else {
|
||||
|
||||
char rmagic[5];
|
||||
f->get_buffer((uint8_t*)rmagic,4);
|
||||
rmagic[4]=0;
|
||||
if (magic!=rmagic) {
|
||||
memdelete(f);
|
||||
f=NULL;
|
||||
return ERR_FILE_UNRECOGNIZED;
|
||||
}
|
||||
|
||||
open_after_magic(f);
|
||||
|
||||
}
|
||||
|
||||
return OK;
|
||||
|
||||
}
|
||||
void FileAccessCompressed::close(){
|
||||
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
|
||||
if (writing) {
|
||||
//save block table and all compressed blocks
|
||||
|
||||
CharString mgc = magic.utf8();
|
||||
f->store_buffer((const uint8_t*)mgc.get_data(),mgc.length()); //write header 4
|
||||
f->store_32(cmode); //write compression mode 4
|
||||
f->store_32(block_size); //write block size 4
|
||||
f->store_32(write_max); //max amount of data written 4
|
||||
int bc=(write_max/block_size)+1;
|
||||
|
||||
for(int i=0;i<bc;i++) {
|
||||
f->store_32(0); //compressed sizes, will update later
|
||||
}
|
||||
|
||||
|
||||
Vector<int> block_sizes;
|
||||
for(int i=0;i<bc;i++) {
|
||||
|
||||
int bl = i==(bc-1) ? write_max % block_size : block_size;
|
||||
uint8_t *bp = &write_ptr[i*block_size];
|
||||
|
||||
Vector<uint8_t> cblock;
|
||||
cblock.resize(Compression::get_max_compressed_buffer_size(bl,cmode));
|
||||
int s = Compression::compress(cblock.ptr(),bp,bl,cmode);
|
||||
|
||||
f->store_buffer(cblock.ptr(),s);
|
||||
block_sizes.push_back(s);
|
||||
}
|
||||
|
||||
f->seek(16); //ok write block sizes
|
||||
for(int i=0;i<bc;i++)
|
||||
f->store_32(block_sizes[i]);
|
||||
f->seek_end();
|
||||
f->store_buffer((const uint8_t*)mgc.get_data(),mgc.length()); //magic at the end too
|
||||
|
||||
buffer.clear();
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
comp_buffer.clear();
|
||||
buffer.clear();
|
||||
read_blocks.clear();
|
||||
}
|
||||
|
||||
memdelete(f);
|
||||
f=NULL;
|
||||
|
||||
}
|
||||
|
||||
bool FileAccessCompressed::is_open() const{
|
||||
|
||||
return f!=NULL;
|
||||
}
|
||||
|
||||
void FileAccessCompressed::seek(size_t p_position){
|
||||
|
||||
ERR_FAIL_COND(!f);
|
||||
if (writing) {
|
||||
|
||||
ERR_FAIL_COND(p_position>write_max);
|
||||
|
||||
write_pos=p_position;
|
||||
|
||||
} else {
|
||||
|
||||
ERR_FAIL_COND(p_position>read_total);
|
||||
if (p_position==read_total) {
|
||||
at_end=true;
|
||||
} else {
|
||||
|
||||
int block_idx = p_position/block_size;
|
||||
if (block_idx!=read_block) {
|
||||
|
||||
read_block=block_idx;
|
||||
f->seek(read_blocks[read_block].offset);
|
||||
f->get_buffer(comp_buffer.ptr(),read_blocks[read_block].csize);
|
||||
Compression::decompress(buffer.ptr(),read_blocks.size()==1?read_total:block_size,comp_buffer.ptr(),read_blocks[read_block].csize,cmode);
|
||||
read_block_size=read_block==read_block_count-1?read_total%block_size:block_size;
|
||||
}
|
||||
|
||||
read_pos=p_position%block_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FileAccessCompressed::seek_end(int64_t p_position){
|
||||
|
||||
ERR_FAIL_COND(!f);
|
||||
if (writing) {
|
||||
|
||||
seek(write_max+p_position);
|
||||
} else {
|
||||
|
||||
seek(read_total+p_position);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
size_t FileAccessCompressed::get_pos() const{
|
||||
|
||||
ERR_FAIL_COND_V(!f,0);
|
||||
if (writing) {
|
||||
|
||||
return write_pos;
|
||||
} else {
|
||||
|
||||
return read_block*block_size+read_pos;
|
||||
}
|
||||
|
||||
}
|
||||
size_t FileAccessCompressed::get_len() const{
|
||||
|
||||
ERR_FAIL_COND_V(!f,0);
|
||||
if (writing) {
|
||||
|
||||
return write_max;
|
||||
} else {
|
||||
return read_total;
|
||||
}
|
||||
}
|
||||
|
||||
bool FileAccessCompressed::eof_reached() const{
|
||||
|
||||
ERR_FAIL_COND_V(!f,false);
|
||||
if (writing) {
|
||||
return false;
|
||||
} else {
|
||||
return read_eof;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t FileAccessCompressed::get_8() const{
|
||||
|
||||
ERR_FAIL_COND_V(writing,0);
|
||||
ERR_FAIL_COND_V(!f,0);
|
||||
|
||||
if (at_end) {
|
||||
read_eof=true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t ret = read_ptr[read_pos];
|
||||
|
||||
read_pos++;
|
||||
if (read_pos>=read_block_size) {
|
||||
read_block++;
|
||||
|
||||
if (read_block<read_block_count) {
|
||||
//read another block of compressed data
|
||||
f->get_buffer(comp_buffer.ptr(),read_blocks[read_block].csize);
|
||||
Compression::decompress(buffer.ptr(),read_blocks.size()==1?read_total:block_size,comp_buffer.ptr(),read_blocks[read_block].csize,cmode);
|
||||
read_block_size=read_block==read_block_count-1?read_total%block_size:block_size;
|
||||
read_pos=0;
|
||||
|
||||
} else {
|
||||
read_block--;
|
||||
at_end=true;
|
||||
ret =0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
int FileAccessCompressed::get_buffer(uint8_t *p_dst, int p_length) const{
|
||||
|
||||
ERR_FAIL_COND_V(writing,0);
|
||||
ERR_FAIL_COND_V(!f,0);
|
||||
|
||||
if (at_end) {
|
||||
read_eof=true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
for(int i=0;i<p_length;i++) {
|
||||
|
||||
|
||||
p_dst[i]=read_ptr[read_pos];
|
||||
read_pos++;
|
||||
if (read_pos>=read_block_size) {
|
||||
read_block++;
|
||||
|
||||
if (read_block<read_block_count) {
|
||||
//read another block of compressed data
|
||||
f->get_buffer(comp_buffer.ptr(),read_blocks[read_block].csize);
|
||||
Compression::decompress(buffer.ptr(),read_blocks.size()==1?read_total:block_size,comp_buffer.ptr(),read_blocks[read_block].csize,cmode);
|
||||
read_block_size=read_block==read_block_count-1?read_total%block_size:block_size;
|
||||
read_pos=0;
|
||||
|
||||
} else {
|
||||
read_block--;
|
||||
at_end=true;
|
||||
if (i<p_length-1)
|
||||
read_eof=true;
|
||||
return i;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return p_length;
|
||||
|
||||
}
|
||||
|
||||
Error FileAccessCompressed::get_error() const{
|
||||
|
||||
return read_eof?ERR_FILE_EOF:OK;
|
||||
}
|
||||
|
||||
void FileAccessCompressed::store_8(uint8_t p_dest){
|
||||
|
||||
ERR_FAIL_COND(!f);
|
||||
ERR_FAIL_COND(!writing);
|
||||
|
||||
WRITE_FIT(1);
|
||||
write_ptr[write_pos++]=p_dest;
|
||||
|
||||
}
|
||||
|
||||
bool FileAccessCompressed::file_exists(const String& p_name){
|
||||
|
||||
FileAccess *fa = FileAccess::open(p_name,FileAccess::READ);
|
||||
if (!fa)
|
||||
return false;
|
||||
memdelete(fa);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t FileAccessCompressed::_get_modified_time(const String& p_file) {
|
||||
|
||||
if (f)
|
||||
return f->get_modified_time(p_file);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
FileAccessCompressed::FileAccessCompressed() {
|
||||
|
||||
f=NULL;
|
||||
magic="GCMP";
|
||||
block_size=4096;
|
||||
cmode=Compression::MODE_FASTLZ;
|
||||
writing=false;
|
||||
write_ptr=0;
|
||||
write_buffer_size=0;
|
||||
write_max=0;
|
||||
block_size=0;
|
||||
read_eof=false;
|
||||
at_end=false;
|
||||
read_total=0;
|
||||
read_ptr=NULL;
|
||||
read_block=0;
|
||||
read_block_count=0;
|
||||
read_block_size=0;
|
||||
read_pos=0;
|
||||
|
||||
}
|
||||
|
||||
FileAccessCompressed::~FileAccessCompressed(){
|
||||
|
||||
if (f)
|
||||
close();
|
||||
|
||||
}
|
101
core/io/file_access_compressed.h
Normal file
101
core/io/file_access_compressed.h
Normal file
@ -0,0 +1,101 @@
|
||||
/*************************************************************************/
|
||||
/* file_access_compressed.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 FILE_ACCESS_COMPRESSED_H
|
||||
#define FILE_ACCESS_COMPRESSED_H
|
||||
|
||||
#include "io/compression.h"
|
||||
#include "os/file_access.h"
|
||||
|
||||
class FileAccessCompressed : public FileAccess {
|
||||
|
||||
Compression::Mode cmode;
|
||||
bool writing;
|
||||
int write_pos;
|
||||
uint8_t*write_ptr;
|
||||
int write_buffer_size;
|
||||
int write_max;
|
||||
int block_size;
|
||||
mutable bool read_eof;
|
||||
mutable bool at_end;
|
||||
|
||||
struct ReadBlock {
|
||||
int csize;
|
||||
int offset;
|
||||
};
|
||||
|
||||
mutable Vector<uint8_t> comp_buffer;
|
||||
uint8_t *read_ptr;
|
||||
mutable int read_block;
|
||||
int read_block_count;
|
||||
mutable int read_block_size;
|
||||
mutable int read_pos;
|
||||
Vector<ReadBlock> read_blocks;
|
||||
int read_total;
|
||||
|
||||
|
||||
|
||||
|
||||
String magic;
|
||||
mutable Vector<uint8_t> buffer;
|
||||
FileAccess *f;
|
||||
public:
|
||||
|
||||
void configure(const String& p_magic, Compression::Mode p_mode=Compression::MODE_FASTLZ, int p_block_size=4096);
|
||||
|
||||
Error open_after_magic(FileAccess *p_base);
|
||||
|
||||
virtual Error _open(const String& p_path, int p_mode_flags); ///< open a file
|
||||
virtual void close(); ///< close a file
|
||||
virtual bool is_open() const; ///< true when file is open
|
||||
|
||||
virtual void seek(size_t p_position); ///< seek to a given position
|
||||
virtual void seek_end(int64_t p_position=0); ///< seek from the end of file
|
||||
virtual size_t get_pos() const; ///< get position in the file
|
||||
virtual size_t get_len() const; ///< get size of the file
|
||||
|
||||
virtual bool eof_reached() const; ///< reading passed EOF
|
||||
|
||||
virtual uint8_t get_8() const; ///< get a byte
|
||||
virtual int get_buffer(uint8_t *p_dst, int p_length) const;
|
||||
|
||||
virtual Error get_error() const; ///< get last error
|
||||
|
||||
virtual void store_8(uint8_t p_dest); ///< store a byte
|
||||
|
||||
virtual bool file_exists(const String& p_name); ///< return true if a file exists
|
||||
|
||||
virtual uint64_t _get_modified_time(const String& p_file);
|
||||
|
||||
|
||||
FileAccessCompressed();
|
||||
virtual ~FileAccessCompressed();
|
||||
|
||||
};
|
||||
|
||||
#endif // FILE_ACCESS_COMPRESSED_H
|
188
core/io/file_access_memory.cpp
Normal file
188
core/io/file_access_memory.cpp
Normal file
@ -0,0 +1,188 @@
|
||||
/*************************************************************************/
|
||||
/* file_access_memory.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "file_access_memory.h"
|
||||
|
||||
#include "os/dir_access.h"
|
||||
#include "os/copymem.h"
|
||||
#include "globals.h"
|
||||
#include "map.h"
|
||||
|
||||
static Map<String, Vector<uint8_t> >* files = NULL;
|
||||
|
||||
void FileAccessMemory::register_file(String p_name, Vector<uint8_t> p_data) {
|
||||
|
||||
if (!files) {
|
||||
files = memnew((Map<String, Vector<uint8_t> >));
|
||||
};
|
||||
|
||||
String name;
|
||||
if (Globals::get_singleton())
|
||||
name = Globals::get_singleton()->globalize_path(p_name);
|
||||
else
|
||||
name = p_name;
|
||||
name = DirAccess::normalize_path(name);
|
||||
|
||||
(*files)[name] = p_data;
|
||||
};
|
||||
|
||||
void FileAccessMemory::cleanup() {
|
||||
|
||||
if (!files)
|
||||
return;
|
||||
|
||||
memdelete(files);
|
||||
};
|
||||
|
||||
|
||||
FileAccess* FileAccessMemory::create() {
|
||||
|
||||
return memnew(FileAccessMemory);
|
||||
};
|
||||
|
||||
bool FileAccessMemory::file_exists(const String& p_name) {
|
||||
|
||||
String name = fix_path(p_name);
|
||||
name = DirAccess::normalize_path(name);
|
||||
|
||||
return files && (files->find(name) != NULL);
|
||||
};
|
||||
|
||||
|
||||
Error FileAccessMemory::_open(const String& p_path, int p_mode_flags) {
|
||||
|
||||
ERR_FAIL_COND_V(!files, ERR_FILE_NOT_FOUND);
|
||||
|
||||
String name = fix_path(p_path);
|
||||
name = DirAccess::normalize_path(name);
|
||||
|
||||
Map<String, Vector<uint8_t> >::Element* E = files->find(name);
|
||||
ERR_FAIL_COND_V(!E, ERR_FILE_NOT_FOUND);
|
||||
|
||||
data = &(E->get()[0]);
|
||||
length = E->get().size();
|
||||
pos = 0;
|
||||
|
||||
return OK;
|
||||
};
|
||||
|
||||
void FileAccessMemory::close() {
|
||||
|
||||
data = NULL;
|
||||
};
|
||||
|
||||
bool FileAccessMemory::is_open() const {
|
||||
|
||||
return data != NULL;
|
||||
};
|
||||
|
||||
void FileAccessMemory::seek(size_t p_position) {
|
||||
|
||||
ERR_FAIL_COND(!data);
|
||||
pos = p_position;
|
||||
};
|
||||
|
||||
void FileAccessMemory::seek_end(int64_t p_position) {
|
||||
|
||||
ERR_FAIL_COND(!data);
|
||||
pos = length + p_position;
|
||||
};
|
||||
|
||||
size_t FileAccessMemory::get_pos() const {
|
||||
|
||||
ERR_FAIL_COND_V(!data, 0);
|
||||
return pos;
|
||||
};
|
||||
|
||||
size_t FileAccessMemory::get_len() const {
|
||||
|
||||
ERR_FAIL_COND_V(!data, 0);
|
||||
return length;
|
||||
};
|
||||
|
||||
bool FileAccessMemory::eof_reached() const {
|
||||
|
||||
return pos >= length;
|
||||
};
|
||||
|
||||
uint8_t FileAccessMemory::get_8() const {
|
||||
|
||||
uint8_t ret;
|
||||
if (pos < length) {
|
||||
ret = data[pos];
|
||||
};
|
||||
++pos;
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
int FileAccessMemory::get_buffer(uint8_t *p_dst,int p_length) const {
|
||||
|
||||
ERR_FAIL_COND_V(!data, -1);
|
||||
|
||||
int left = length - pos;
|
||||
int read = MIN(p_length, left);
|
||||
|
||||
if (read < p_length) {
|
||||
WARN_PRINT("Reading less data than requested");
|
||||
};
|
||||
|
||||
copymem(p_dst, &data[pos], read);
|
||||
pos += p_length;
|
||||
|
||||
return read;
|
||||
};
|
||||
|
||||
Error FileAccessMemory::get_error() const {
|
||||
|
||||
return pos >= length ? ERR_FILE_EOF : OK;
|
||||
};
|
||||
|
||||
void FileAccessMemory::store_8(uint8_t p_byte) {
|
||||
|
||||
ERR_FAIL_COND(!data);
|
||||
ERR_FAIL_COND(pos >= length);
|
||||
data[pos++] = p_byte;
|
||||
};
|
||||
|
||||
void FileAccessMemory::store_buffer(const uint8_t *p_src,int p_length) {
|
||||
|
||||
int left = length - pos;
|
||||
int write = MIN(p_length, left);
|
||||
if (write < p_length) {
|
||||
WARN_PRINT("Writing less data than requested");
|
||||
};
|
||||
|
||||
copymem(&data[pos], p_src, write);
|
||||
pos += p_length;
|
||||
};
|
||||
|
||||
FileAccessMemory::FileAccessMemory() {
|
||||
|
||||
data = NULL;
|
||||
}
|
76
core/io/file_access_memory.h
Normal file
76
core/io/file_access_memory.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*************************************************************************/
|
||||
/* file_access_memory.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 FILE_ACCESS_MEMORY_H
|
||||
#define FILE_ACCESS_MEMORY_H
|
||||
|
||||
#include "os/file_access.h"
|
||||
|
||||
class FileAccessMemory : public FileAccess {
|
||||
|
||||
uint8_t* data;
|
||||
int length;
|
||||
mutable int pos;
|
||||
|
||||
static FileAccess* create();
|
||||
|
||||
public:
|
||||
|
||||
static void register_file(String p_name, Vector<uint8_t> p_data);
|
||||
static void cleanup();
|
||||
|
||||
virtual Error _open(const String& p_path, int p_mode_flags); ///< open a file
|
||||
virtual void close(); ///< close a file
|
||||
virtual bool is_open() const; ///< true when file is open
|
||||
|
||||
virtual void seek(size_t p_position); ///< seek to a given position
|
||||
virtual void seek_end(int64_t p_position); ///< seek from the end of file
|
||||
virtual size_t get_pos() const; ///< get position in the file
|
||||
virtual size_t get_len() const; ///< get size of the file
|
||||
|
||||
virtual bool eof_reached() const; ///< reading passed EOF
|
||||
|
||||
virtual uint8_t get_8() const; ///< get a byte
|
||||
|
||||
virtual int get_buffer(uint8_t *p_dst,int p_length) const; ///< get an array of bytes
|
||||
|
||||
virtual Error get_error() const; ///< get last error
|
||||
|
||||
virtual void store_8(uint8_t p_dest); ///< store a byte
|
||||
virtual void store_buffer(const uint8_t *p_src,int p_length); ///< store an array of bytes
|
||||
|
||||
virtual bool file_exists(const String& p_name); ///< return true if a file exists
|
||||
|
||||
virtual uint64_t _get_modified_time(const String& p_file) { return 0; }
|
||||
|
||||
|
||||
|
||||
FileAccessMemory();
|
||||
};
|
||||
|
||||
#endif // FILE_ACCESS_MEMORY_H
|
566
core/io/file_access_network.cpp
Normal file
566
core/io/file_access_network.cpp
Normal file
@ -0,0 +1,566 @@
|
||||
/*************************************************************************/
|
||||
/* file_access_network.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "file_access_network.h"
|
||||
#include "marshalls.h"
|
||||
#include "globals.h"
|
||||
#include "os/os.h"
|
||||
#include "io/ip.h"
|
||||
|
||||
|
||||
|
||||
#define DEBUG_PRINT(m_p) print_line(m_p)
|
||||
//#define DEBUG_TIME(m_what) printf("MS: %s - %lli\n",m_what,OS::get_singleton()->get_ticks_usec());
|
||||
//#define DEBUG_PRINT(m_p)
|
||||
#define DEBUG_TIME(m_what)
|
||||
|
||||
|
||||
void FileAccessNetworkClient::lock_mutex() {
|
||||
|
||||
mutex->lock();
|
||||
lockcount++;
|
||||
}
|
||||
|
||||
void FileAccessNetworkClient::unlock_mutex() {
|
||||
|
||||
lockcount--;
|
||||
mutex->unlock();
|
||||
|
||||
}
|
||||
|
||||
void FileAccessNetworkClient::put_32(int p_32) {
|
||||
|
||||
uint8_t buf[4];
|
||||
encode_uint32(p_32,buf);
|
||||
client->put_data(buf,4);
|
||||
DEBUG_PRINT("put32: "+itos(p_32));
|
||||
}
|
||||
|
||||
void FileAccessNetworkClient::put_64(int64_t p_64) {
|
||||
|
||||
uint8_t buf[8];
|
||||
encode_uint64(p_64,buf);
|
||||
client->put_data(buf,8);
|
||||
DEBUG_PRINT("put64: "+itos(p_64));
|
||||
|
||||
}
|
||||
|
||||
int FileAccessNetworkClient::get_32() {
|
||||
|
||||
uint8_t buf[4];
|
||||
client->get_data(buf,4);
|
||||
return decode_uint32(buf);
|
||||
|
||||
}
|
||||
|
||||
int64_t FileAccessNetworkClient::get_64() {
|
||||
|
||||
uint8_t buf[8];
|
||||
client->get_data(buf,8);
|
||||
return decode_uint64(buf);
|
||||
|
||||
}
|
||||
|
||||
void FileAccessNetworkClient::_thread_func() {
|
||||
|
||||
client->set_nodelay(true);
|
||||
while(!quit) {
|
||||
|
||||
DEBUG_PRINT("SEM WAIT - "+itos(sem->get()));
|
||||
Error err = sem->wait();
|
||||
DEBUG_TIME("sem_unlock");
|
||||
//DEBUG_PRINT("semwait returned "+itos(werr));
|
||||
DEBUG_PRINT("MUTEX LOCK "+itos(lockcount));
|
||||
DEBUG_PRINT("POPO");
|
||||
DEBUG_PRINT("PEPE");
|
||||
lock_mutex();
|
||||
DEBUG_PRINT("MUTEX PASS");
|
||||
|
||||
blockrequest_mutex->lock();
|
||||
while(block_requests.size()) {
|
||||
put_32(block_requests.front()->get().id);
|
||||
put_32(FileAccessNetwork::COMMAND_READ_BLOCK);
|
||||
put_64(block_requests.front()->get().offset);
|
||||
put_32(block_requests.front()->get().size);
|
||||
block_requests.pop_front();
|
||||
}
|
||||
blockrequest_mutex->unlock();
|
||||
|
||||
DEBUG_PRINT("THREAD ITER");
|
||||
|
||||
DEBUG_TIME("sem_read");
|
||||
int id = get_32();
|
||||
|
||||
int response = get_32();
|
||||
DEBUG_PRINT("GET RESPONSE: "+itos(response));
|
||||
|
||||
FileAccessNetwork *fa=NULL;
|
||||
|
||||
if (response!=FileAccessNetwork::RESPONSE_DATA) {
|
||||
ERR_FAIL_COND(!accesses.has(id));
|
||||
}
|
||||
|
||||
if (accesses.has(id))
|
||||
fa=accesses[id];
|
||||
|
||||
|
||||
switch(response) {
|
||||
|
||||
case FileAccessNetwork::RESPONSE_OPEN: {
|
||||
|
||||
|
||||
DEBUG_TIME("sem_open");
|
||||
int status = get_32();
|
||||
if (status!=OK) {
|
||||
fa->_respond(0,Error(status));
|
||||
} else {
|
||||
uint64_t len = get_64();
|
||||
fa->_respond(len,Error(status));
|
||||
}
|
||||
|
||||
fa->sem->post();
|
||||
|
||||
|
||||
} break;
|
||||
case FileAccessNetwork::RESPONSE_DATA: {
|
||||
|
||||
int64_t offset = get_64();
|
||||
uint32_t len = get_32();
|
||||
|
||||
Vector<uint8_t> block;
|
||||
block.resize(len);
|
||||
client->get_data(block.ptr(),len);
|
||||
|
||||
if (fa) //may have been queued
|
||||
fa->_set_block(offset,block);
|
||||
|
||||
} break;
|
||||
case FileAccessNetwork::RESPONSE_FILE_EXISTS: {
|
||||
|
||||
|
||||
int status = get_32();
|
||||
fa->exists_modtime=status!=0;
|
||||
fa->sem->post();
|
||||
|
||||
|
||||
|
||||
} break;
|
||||
case FileAccessNetwork::RESPONSE_GET_MODTIME: {
|
||||
|
||||
|
||||
uint64_t status = get_64();
|
||||
fa->exists_modtime=status;
|
||||
fa->sem->post();
|
||||
|
||||
} break;
|
||||
|
||||
}
|
||||
|
||||
|
||||
unlock_mutex();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FileAccessNetworkClient::_thread_func(void *s) {
|
||||
|
||||
FileAccessNetworkClient *self =(FileAccessNetworkClient*)s;
|
||||
|
||||
self->_thread_func();
|
||||
|
||||
}
|
||||
|
||||
Error FileAccessNetworkClient::connect(const String& p_host,int p_port,const String& p_password) {
|
||||
|
||||
IP_Address ip;
|
||||
|
||||
if (p_host.is_valid_ip_address()) {
|
||||
ip=p_host;
|
||||
} else {
|
||||
ip=IP::get_singleton()->resolve_hostname(p_host);
|
||||
}
|
||||
|
||||
DEBUG_PRINT("IP: "+String(ip)+" port "+itos(p_port));
|
||||
Error err = client->connect(ip,p_port);
|
||||
ERR_FAIL_COND_V(err,err);
|
||||
while(client->get_status()==StreamPeerTCP::STATUS_CONNECTING) {
|
||||
//DEBUG_PRINT("trying to connect....");
|
||||
OS::get_singleton()->delay_usec(1000);
|
||||
}
|
||||
|
||||
if (client->get_status()!=StreamPeerTCP::STATUS_CONNECTED) {
|
||||
return ERR_CANT_CONNECT;
|
||||
}
|
||||
|
||||
CharString cs = p_password.utf8();
|
||||
put_32(cs.length());
|
||||
client->put_data((const uint8_t*)cs.ptr(),cs.length());
|
||||
|
||||
int e = get_32();
|
||||
|
||||
if (e!=OK) {
|
||||
return ERR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
thread = Thread::create(_thread_func,this);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
FileAccessNetworkClient *FileAccessNetworkClient::singleton=NULL;
|
||||
|
||||
|
||||
FileAccessNetworkClient::FileAccessNetworkClient() {
|
||||
|
||||
thread=NULL;
|
||||
mutex = Mutex::create();
|
||||
blockrequest_mutex = Mutex::create();
|
||||
quit=false;
|
||||
singleton=this;
|
||||
last_id=0;
|
||||
client = Ref<StreamPeerTCP>( StreamPeerTCP::create() );
|
||||
sem=Semaphore::create();
|
||||
lockcount=0;
|
||||
}
|
||||
|
||||
FileAccessNetworkClient::~FileAccessNetworkClient() {
|
||||
|
||||
if (thread) {
|
||||
quit=true;
|
||||
sem->post();
|
||||
Thread::wait_to_finish(thread);
|
||||
}
|
||||
|
||||
memdelete(blockrequest_mutex);
|
||||
memdelete(mutex);
|
||||
memdelete(sem);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void FileAccessNetwork::_set_block(size_t p_offset,const Vector<uint8_t>& p_block) {
|
||||
|
||||
|
||||
int page = p_offset/page_size;
|
||||
ERR_FAIL_INDEX(page,pages.size());
|
||||
if (page<pages.size()-1) {
|
||||
ERR_FAIL_COND(p_block.size()!=page_size);
|
||||
} else {
|
||||
ERR_FAIL_COND( (p_block.size() != (total_size%page_size)));
|
||||
}
|
||||
|
||||
buffer_mutex->lock();
|
||||
pages[page].buffer=p_block;
|
||||
pages[page].queued=false;
|
||||
buffer_mutex->unlock();
|
||||
|
||||
if (waiting_on_page==page) {
|
||||
waiting_on_page=-1;
|
||||
page_sem->post();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FileAccessNetwork::_respond(size_t p_len,Error p_status) {
|
||||
|
||||
DEBUG_PRINT("GOT RESPONSE - len: "+itos(p_len)+" status: "+itos(p_status));
|
||||
response=p_status;
|
||||
if (response!=OK)
|
||||
return;
|
||||
opened=true;
|
||||
total_size=p_len;
|
||||
int pc = ((total_size-1)/page_size)+1;
|
||||
pages.resize(pc);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
Error FileAccessNetwork::_open(const String& p_path, int p_mode_flags) {
|
||||
|
||||
ERR_FAIL_COND_V(p_mode_flags!=READ,ERR_UNAVAILABLE);
|
||||
if (opened)
|
||||
close();
|
||||
FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
|
||||
DEBUG_PRINT("open: "+p_path);
|
||||
|
||||
DEBUG_TIME("open_begin");
|
||||
|
||||
nc->lock_mutex();
|
||||
nc->put_32(id);
|
||||
nc->accesses[id]=this;
|
||||
nc->put_32(COMMAND_OPEN_FILE);
|
||||
CharString cs =p_path.utf8();
|
||||
nc->put_32(cs.length());
|
||||
nc->client->put_data((const uint8_t*)cs.ptr(),cs.length());
|
||||
pos=0;
|
||||
eof_flag=false;
|
||||
last_page=-1;
|
||||
last_page_buff=NULL;
|
||||
|
||||
// buffers.clear();
|
||||
nc->unlock_mutex();
|
||||
DEBUG_PRINT("OPEN POST");
|
||||
DEBUG_TIME("open_post");
|
||||
nc->sem->post(); //awaiting answer
|
||||
DEBUG_PRINT("WAIT...");
|
||||
sem->wait();
|
||||
DEBUG_TIME("open_end");
|
||||
DEBUG_PRINT("WAIT ENDED...");
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
void FileAccessNetwork::close(){
|
||||
|
||||
if (!opened)
|
||||
return;
|
||||
|
||||
FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
|
||||
|
||||
DEBUG_PRINT("CLOSE");
|
||||
nc->lock_mutex();
|
||||
nc->put_32(id);
|
||||
nc->put_32(COMMAND_CLOSE);
|
||||
pages.clear();
|
||||
opened=false;
|
||||
nc->unlock_mutex();
|
||||
|
||||
|
||||
}
|
||||
bool FileAccessNetwork::is_open() const{
|
||||
|
||||
return opened;
|
||||
}
|
||||
|
||||
void FileAccessNetwork::seek(size_t p_position){
|
||||
|
||||
ERR_FAIL_COND(!opened);
|
||||
eof_flag=p_position>total_size;
|
||||
|
||||
if (p_position>=total_size) {
|
||||
p_position=total_size;
|
||||
}
|
||||
|
||||
pos=p_position;
|
||||
}
|
||||
|
||||
void FileAccessNetwork::seek_end(int64_t p_position){
|
||||
|
||||
seek(total_size+p_position);
|
||||
|
||||
}
|
||||
size_t FileAccessNetwork::get_pos() const{
|
||||
|
||||
ERR_FAIL_COND_V(!opened,0);
|
||||
return pos;
|
||||
}
|
||||
size_t FileAccessNetwork::get_len() const{
|
||||
|
||||
ERR_FAIL_COND_V(!opened,0);
|
||||
return total_size;
|
||||
}
|
||||
|
||||
bool FileAccessNetwork::eof_reached() const{
|
||||
|
||||
ERR_FAIL_COND_V(!opened,false);
|
||||
return eof_flag;
|
||||
}
|
||||
|
||||
uint8_t FileAccessNetwork::get_8() const{
|
||||
|
||||
uint8_t v;
|
||||
get_buffer(&v,1);
|
||||
return v;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void FileAccessNetwork::_queue_page(int p_page) const {
|
||||
|
||||
if (p_page>=pages.size())
|
||||
return;
|
||||
if (pages[p_page].buffer.empty() && !pages[p_page].queued) {
|
||||
|
||||
|
||||
FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
|
||||
|
||||
nc->blockrequest_mutex->lock();
|
||||
FileAccessNetworkClient::BlockRequest br;
|
||||
br.id=id;
|
||||
br.offset=size_t(p_page)*page_size;
|
||||
br.size=page_size;
|
||||
nc->block_requests.push_back(br);
|
||||
pages[p_page].queued=true;
|
||||
nc->blockrequest_mutex->unlock();
|
||||
DEBUG_PRINT("QUEUE PAGE POST");
|
||||
nc->sem->post();
|
||||
DEBUG_PRINT("queued "+itos(p_page));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int FileAccessNetwork::get_buffer(uint8_t *p_dst, int p_length) const{
|
||||
|
||||
//bool eof=false;
|
||||
if (pos+p_length>total_size) {
|
||||
eof_flag=true;
|
||||
}
|
||||
if (pos+p_length>=total_size) {
|
||||
p_length=total_size-pos;
|
||||
}
|
||||
|
||||
// FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
|
||||
|
||||
uint8_t *buff=last_page_buff;
|
||||
|
||||
for(int i=0;i<p_length;i++) {
|
||||
|
||||
int page=pos/page_size;
|
||||
|
||||
if (page!=last_page) {
|
||||
buffer_mutex->lock();
|
||||
if (pages[page].buffer.empty()) {
|
||||
//fuck
|
||||
|
||||
waiting_on_page=page;
|
||||
for(int j=0;j<read_ahead;j++) {
|
||||
|
||||
_queue_page(page+j);
|
||||
}
|
||||
buffer_mutex->unlock();
|
||||
DEBUG_PRINT("wait");
|
||||
page_sem->wait();
|
||||
DEBUG_PRINT("done");
|
||||
} else {
|
||||
|
||||
for(int j=0;j<read_ahead;j++) {
|
||||
|
||||
_queue_page(page+j);
|
||||
}
|
||||
buff=pages[page].buffer.ptr();
|
||||
//queue pages
|
||||
buffer_mutex->unlock();
|
||||
}
|
||||
|
||||
buff=pages[page].buffer.ptr();
|
||||
last_page_buff=buff;
|
||||
last_page=page;
|
||||
}
|
||||
|
||||
p_dst[i]=buff[pos-uint64_t(page)*page_size];
|
||||
pos++;
|
||||
}
|
||||
|
||||
return p_length;
|
||||
}
|
||||
|
||||
Error FileAccessNetwork::get_error() const{
|
||||
|
||||
return pos==total_size?ERR_FILE_EOF:OK;
|
||||
}
|
||||
|
||||
void FileAccessNetwork::store_8(uint8_t p_dest) {
|
||||
|
||||
ERR_FAIL();
|
||||
}
|
||||
|
||||
bool FileAccessNetwork::file_exists(const String& p_path){
|
||||
|
||||
FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
|
||||
nc->lock_mutex();
|
||||
nc->put_32(id);
|
||||
nc->put_32(COMMAND_FILE_EXISTS);
|
||||
CharString cs=p_path.utf8();
|
||||
nc->put_32(cs.length());
|
||||
nc->client->put_data((const uint8_t*)cs.ptr(),cs.length());
|
||||
nc->unlock_mutex();
|
||||
DEBUG_PRINT("FILE EXISTS POST");
|
||||
nc->sem->post();
|
||||
sem->wait();
|
||||
|
||||
return exists_modtime!=0;
|
||||
|
||||
}
|
||||
|
||||
uint64_t FileAccessNetwork::_get_modified_time(const String& p_file){
|
||||
|
||||
FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
|
||||
nc->lock_mutex();
|
||||
nc->put_32(id);
|
||||
nc->put_32(COMMAND_GET_MODTIME);
|
||||
CharString cs=p_file.utf8();
|
||||
nc->put_32(cs.length());
|
||||
nc->client->put_data((const uint8_t*)cs.ptr(),cs.length());
|
||||
nc->unlock_mutex();
|
||||
DEBUG_PRINT("MODTIME POST");
|
||||
nc->sem->post();
|
||||
sem->wait();
|
||||
|
||||
return exists_modtime;
|
||||
|
||||
}
|
||||
|
||||
FileAccessNetwork::FileAccessNetwork() {
|
||||
|
||||
eof_flag=false;
|
||||
opened=false;
|
||||
pos=0;
|
||||
sem=Semaphore::create();
|
||||
page_sem=Semaphore::create();
|
||||
buffer_mutex=Mutex::create();
|
||||
FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
|
||||
nc->lock_mutex();
|
||||
id=nc->last_id++;
|
||||
nc->accesses[id]=this;
|
||||
nc->unlock_mutex();
|
||||
page_size = GLOBAL_DEF("remote_fs/page_size",65536);
|
||||
read_ahead = GLOBAL_DEF("remote_fs/page_read_ahead",4);
|
||||
max_pages = GLOBAL_DEF("remote_fs/max_pages",20);
|
||||
last_activity_val=0;
|
||||
waiting_on_page=-1;
|
||||
last_page=-1;
|
||||
|
||||
|
||||
}
|
||||
|
||||
FileAccessNetwork::~FileAccessNetwork() {
|
||||
|
||||
close();
|
||||
memdelete(sem);
|
||||
memdelete(page_sem);
|
||||
memdelete(buffer_mutex);
|
||||
|
||||
FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
|
||||
nc->lock_mutex();
|
||||
id=nc->last_id++;
|
||||
nc->accesses.erase(id);
|
||||
nc->unlock_mutex();
|
||||
|
||||
}
|
169
core/io/file_access_network.h
Normal file
169
core/io/file_access_network.h
Normal file
@ -0,0 +1,169 @@
|
||||
/*************************************************************************/
|
||||
/* file_access_network.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 FILE_ACCESS_NETWORK_H
|
||||
#define FILE_ACCESS_NETWORK_H
|
||||
|
||||
#include "os/file_access.h"
|
||||
#include "os/semaphore.h"
|
||||
#include "os/thread.h"
|
||||
#include "io/stream_peer_tcp.h"
|
||||
|
||||
class FileAccessNetwork;
|
||||
|
||||
class FileAccessNetworkClient {
|
||||
|
||||
|
||||
struct BlockRequest {
|
||||
|
||||
int id;
|
||||
uint64_t offset;
|
||||
int size;
|
||||
};
|
||||
|
||||
int ml;
|
||||
|
||||
List<BlockRequest> block_requests;
|
||||
|
||||
Semaphore *sem;
|
||||
Thread *thread;
|
||||
bool quit;
|
||||
Mutex *mutex;
|
||||
Mutex *blockrequest_mutex;
|
||||
Map<int,FileAccessNetwork*> accesses;
|
||||
Ref<StreamPeerTCP> client;
|
||||
int last_id;
|
||||
|
||||
Vector<uint8_t> block;
|
||||
|
||||
void _thread_func();
|
||||
static void _thread_func(void *s);
|
||||
|
||||
void put_32(int p_32);
|
||||
void put_64(int64_t p_64);
|
||||
int get_32();
|
||||
int64_t get_64();
|
||||
int lockcount;
|
||||
void lock_mutex();
|
||||
void unlock_mutex();
|
||||
|
||||
friend class FileAccessNetwork;
|
||||
static FileAccessNetworkClient *singleton;
|
||||
|
||||
public:
|
||||
|
||||
static FileAccessNetworkClient *get_singleton() { return singleton; }
|
||||
|
||||
Error connect(const String& p_host,int p_port,const String& p_password="");
|
||||
|
||||
FileAccessNetworkClient();
|
||||
~FileAccessNetworkClient();
|
||||
|
||||
};
|
||||
|
||||
class FileAccessNetwork : public FileAccess {
|
||||
|
||||
Semaphore *sem;
|
||||
Semaphore *page_sem;
|
||||
Mutex *buffer_mutex;
|
||||
bool opened;
|
||||
size_t total_size;
|
||||
mutable size_t pos;
|
||||
int id;
|
||||
mutable bool eof_flag;
|
||||
mutable int last_page;
|
||||
mutable uint8_t *last_page_buff;
|
||||
|
||||
uint32_t page_size;
|
||||
int read_ahead;
|
||||
int max_pages;
|
||||
|
||||
mutable int waiting_on_page;
|
||||
mutable int last_activity_val;
|
||||
struct Page {
|
||||
int activity;
|
||||
bool queued;
|
||||
Vector<uint8_t> buffer;
|
||||
Page() { activity=0; queued=false; }
|
||||
};
|
||||
|
||||
mutable Vector< Page > pages;
|
||||
|
||||
mutable Error response;
|
||||
|
||||
uint64_t exists_modtime;
|
||||
friend class FileAccessNetworkClient;
|
||||
void _queue_page(int p_page) const;
|
||||
void _respond(size_t p_len,Error p_status);
|
||||
void _set_block(size_t p_offset,const Vector<uint8_t>& p_block);
|
||||
|
||||
public:
|
||||
|
||||
enum Command {
|
||||
COMMAND_OPEN_FILE,
|
||||
COMMAND_READ_BLOCK,
|
||||
COMMAND_CLOSE,
|
||||
COMMAND_FILE_EXISTS,
|
||||
COMMAND_GET_MODTIME,
|
||||
};
|
||||
|
||||
enum Response {
|
||||
RESPONSE_OPEN,
|
||||
RESPONSE_DATA,
|
||||
RESPONSE_FILE_EXISTS,
|
||||
RESPONSE_GET_MODTIME,
|
||||
};
|
||||
|
||||
|
||||
virtual Error _open(const String& p_path, int p_mode_flags); ///< open a file
|
||||
virtual void close(); ///< close a file
|
||||
virtual bool is_open() const; ///< true when file is open
|
||||
|
||||
virtual void seek(size_t p_position); ///< seek to a given position
|
||||
virtual void seek_end(int64_t p_position=0); ///< seek from the end of file
|
||||
virtual size_t get_pos() const; ///< get position in the file
|
||||
virtual size_t get_len() const; ///< get size of the file
|
||||
|
||||
virtual bool eof_reached() const; ///< reading passed EOF
|
||||
|
||||
virtual uint8_t get_8() const; ///< get a byte
|
||||
virtual int get_buffer(uint8_t *p_dst, int p_length) const;
|
||||
|
||||
virtual Error get_error() const; ///< get last error
|
||||
|
||||
virtual void store_8(uint8_t p_dest); ///< store a byte
|
||||
|
||||
virtual bool file_exists(const String& p_path); ///< return true if a file exists
|
||||
|
||||
virtual uint64_t _get_modified_time(const String& p_file);
|
||||
|
||||
FileAccessNetwork();
|
||||
~FileAccessNetwork();
|
||||
};
|
||||
|
||||
#endif // FILE_ACCESS_NETWORK_H
|
469
core/io/file_access_pack.cpp
Normal file
469
core/io/file_access_pack.cpp
Normal file
@ -0,0 +1,469 @@
|
||||
/*************************************************************************/
|
||||
/* file_access_pack.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "file_access_pack.h"
|
||||
#include "version.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
Error PackedData::add_pack(const String& p_path) {
|
||||
|
||||
for (int i=0; i<sources.size(); i++) {
|
||||
|
||||
if (sources[i]->try_open_pack(p_path)) {
|
||||
|
||||
return OK;
|
||||
};
|
||||
};
|
||||
|
||||
return ERR_FILE_UNRECOGNIZED;
|
||||
};
|
||||
|
||||
void PackedData::add_path(const String& pkg_path, const String& path, uint64_t ofs, uint64_t size, PackSource* p_src) {
|
||||
|
||||
bool exists = files.has(path);
|
||||
|
||||
PackedFile pf;
|
||||
pf.pack=pkg_path;
|
||||
pf.offset=ofs;
|
||||
pf.size=size;
|
||||
pf.src = p_src;
|
||||
|
||||
files[path]=pf;
|
||||
|
||||
if (!exists) {
|
||||
//search for dir
|
||||
String p = path.replace_first("res://","");
|
||||
PackedDir *cd=root;
|
||||
|
||||
if (p.find("/")!=-1) { //in a subdir
|
||||
|
||||
Vector<String> ds=p.get_base_dir().split("/");
|
||||
|
||||
for(int j=0;j<ds.size();j++) {
|
||||
|
||||
if (!cd->subdirs.has(ds[j])) {
|
||||
|
||||
PackedDir *pd = memnew( PackedDir );
|
||||
pd->name=ds[j];
|
||||
pd->parent=cd;
|
||||
cd->subdirs[pd->name]=pd;
|
||||
cd=pd;
|
||||
} else {
|
||||
cd=cd->subdirs[ds[j]];
|
||||
}
|
||||
}
|
||||
}
|
||||
cd->files.insert(path.get_file());
|
||||
}
|
||||
}
|
||||
|
||||
void PackedData::add_pack_source(PackSource *p_source) {
|
||||
|
||||
sources.push_back(p_source);
|
||||
};
|
||||
|
||||
PackedData *PackedData::singleton=NULL;
|
||||
|
||||
PackedData::PackedData() {
|
||||
|
||||
singleton=this;
|
||||
root=memnew(PackedDir);
|
||||
root->parent=NULL;
|
||||
disabled=false;
|
||||
|
||||
add_pack_source(memnew(PackedSourcePCK));
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
bool PackedSourcePCK::try_open_pack(const String& p_path) {
|
||||
|
||||
FileAccess *f = FileAccess::open(p_path,FileAccess::READ);
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
uint32_t magic= f->get_32();
|
||||
|
||||
if (magic != 0x4b435047) {
|
||||
//maybe at he end.... self contained exe
|
||||
f->seek_end();
|
||||
f->seek( f->get_pos() -4 );
|
||||
magic = f->get_32();
|
||||
if (magic != 0x4b435047) {
|
||||
|
||||
memdelete(f);
|
||||
return false;
|
||||
}
|
||||
f->seek( f->get_pos() -12 );
|
||||
|
||||
|
||||
uint64_t ds = f->get_64();
|
||||
f->seek( f->get_pos() -ds-8 );
|
||||
|
||||
magic = f->get_32();
|
||||
if (magic != 0x4b435047) {
|
||||
|
||||
memdelete(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint32_t ver_major = f->get_32();
|
||||
uint32_t ver_minor = f->get_32();
|
||||
uint32_t ver_rev = f->get_32();
|
||||
|
||||
ERR_EXPLAIN("Pack created with a newer version of the engine: "+itos(ver_major)+"."+itos(ver_minor)+"."+itos(ver_rev));
|
||||
ERR_FAIL_COND_V( ver_major > VERSION_MAJOR || (ver_major == VERSION_MAJOR && ver_minor > VERSION_MINOR), ERR_INVALID_DATA);
|
||||
|
||||
for(int i=0;i<16;i++) {
|
||||
//reserved
|
||||
f->get_32();
|
||||
}
|
||||
|
||||
int file_count = f->get_32();
|
||||
|
||||
for(int i=0;i<file_count;i++) {
|
||||
|
||||
uint32_t sl = f->get_32();
|
||||
CharString cs;
|
||||
cs.resize(sl+1);
|
||||
f->get_buffer((uint8_t*)cs.ptr(),sl);
|
||||
cs[sl]=0;
|
||||
|
||||
String path;
|
||||
path.parse_utf8(cs.ptr());
|
||||
|
||||
uint64_t ofs = f->get_64();
|
||||
uint64_t size = f->get_64();
|
||||
|
||||
PackedData::get_singleton()->add_path(p_path, path, ofs, size, this);
|
||||
};
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
FileAccess* PackedSourcePCK::get_file(const String &p_path, PackedData::PackedFile* p_file) {
|
||||
|
||||
return memnew( FileAccessPack(p_path, *p_file));
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
Error FileAccessPack::_open(const String& p_path, int p_mode_flags) {
|
||||
|
||||
ERR_FAIL_V(ERR_UNAVAILABLE);
|
||||
return ERR_UNAVAILABLE;
|
||||
}
|
||||
|
||||
void FileAccessPack::close() {
|
||||
|
||||
f->close();
|
||||
}
|
||||
|
||||
bool FileAccessPack::is_open() const{
|
||||
|
||||
return f->is_open();
|
||||
}
|
||||
|
||||
void FileAccessPack::seek(size_t p_position){
|
||||
|
||||
if (p_position>pf.size) {
|
||||
eof=true;
|
||||
} else {
|
||||
eof=false;
|
||||
}
|
||||
|
||||
f->seek(pf.offset+p_position);
|
||||
}
|
||||
void FileAccessPack::seek_end(int64_t p_position){
|
||||
|
||||
seek(pf.size+p_position);
|
||||
|
||||
}
|
||||
size_t FileAccessPack::get_pos() const {
|
||||
|
||||
return pos;
|
||||
}
|
||||
size_t FileAccessPack::get_len() const{
|
||||
|
||||
return pf.size;
|
||||
}
|
||||
|
||||
bool FileAccessPack::eof_reached() const{
|
||||
|
||||
return eof;
|
||||
}
|
||||
|
||||
uint8_t FileAccessPack::get_8() const {
|
||||
|
||||
if (pos>=pf.size) {
|
||||
eof=true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pos++;
|
||||
return f->get_8();
|
||||
}
|
||||
|
||||
|
||||
int FileAccessPack::get_buffer(uint8_t *p_dst,int p_length) const {
|
||||
|
||||
if (eof)
|
||||
return 0;
|
||||
|
||||
int64_t to_read=p_length;
|
||||
if (to_read+pos > pf.size) {
|
||||
eof=true;
|
||||
to_read=int64_t(pf.size)-int64_t(pos);
|
||||
}
|
||||
|
||||
pos+=p_length;
|
||||
|
||||
if (to_read<=0)
|
||||
return 0;
|
||||
f->get_buffer(p_dst,to_read);
|
||||
|
||||
return to_read;
|
||||
}
|
||||
|
||||
void FileAccessPack::set_endian_swap(bool p_swap) {
|
||||
FileAccess::set_endian_swap(p_swap);
|
||||
f->set_endian_swap(p_swap);
|
||||
}
|
||||
|
||||
Error FileAccessPack::get_error() const {
|
||||
|
||||
if (eof)
|
||||
return ERR_FILE_EOF;
|
||||
return OK;
|
||||
}
|
||||
|
||||
void FileAccessPack::store_8(uint8_t p_dest) {
|
||||
|
||||
ERR_FAIL();
|
||||
|
||||
}
|
||||
|
||||
void FileAccessPack::store_buffer(const uint8_t *p_src,int p_length) {
|
||||
|
||||
ERR_FAIL();
|
||||
|
||||
}
|
||||
|
||||
bool FileAccessPack::file_exists(const String& p_name) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
FileAccessPack::FileAccessPack(const String& p_path, const PackedData::PackedFile& p_file) {
|
||||
|
||||
pf=p_file;
|
||||
f=FileAccess::open(pf.pack,FileAccess::READ);
|
||||
if (!f) {
|
||||
ERR_EXPLAIN("Can't open pack-referenced file: "+String(pf.pack));
|
||||
ERR_FAIL_COND(!f);
|
||||
}
|
||||
f->seek(pf.offset);
|
||||
pos=0;
|
||||
eof=false;
|
||||
}
|
||||
|
||||
FileAccessPack::~FileAccessPack() {
|
||||
if (f)
|
||||
memdelete(f);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// DIR ACCESS
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
bool DirAccessPack::list_dir_begin() {
|
||||
|
||||
|
||||
list_dirs.clear();
|
||||
list_files.clear();
|
||||
|
||||
for (Map<String,PackedData::PackedDir*>::Element *E=current->subdirs.front();E;E=E->next()) {
|
||||
|
||||
list_dirs.push_back(E->key());
|
||||
}
|
||||
|
||||
for (Set<String>::Element *E=current->files.front();E;E=E->next()) {
|
||||
|
||||
list_files.push_back(E->get());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
String DirAccessPack::get_next(){
|
||||
|
||||
if (list_dirs.size()) {
|
||||
cdir=true;
|
||||
String d = list_dirs.front()->get();
|
||||
list_dirs.pop_front();
|
||||
return d;
|
||||
} else if (list_files.size()) {
|
||||
cdir=false;
|
||||
String f = list_files.front()->get();
|
||||
list_files.pop_front();
|
||||
return f;
|
||||
} else {
|
||||
return String();
|
||||
}
|
||||
}
|
||||
bool DirAccessPack::current_is_dir() const{
|
||||
|
||||
return cdir;
|
||||
}
|
||||
void DirAccessPack::list_dir_end() {
|
||||
|
||||
list_dirs.clear();
|
||||
list_files.clear();
|
||||
}
|
||||
|
||||
int DirAccessPack::get_drive_count() {
|
||||
|
||||
return 0;
|
||||
}
|
||||
String DirAccessPack::get_drive(int p_drive) {
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
Error DirAccessPack::change_dir(String p_dir) {
|
||||
|
||||
String nd = p_dir.replace("\\","/");
|
||||
bool absolute=false;
|
||||
if (nd.begins_with("res://")) {
|
||||
nd=nd.replace_first("res://","");
|
||||
absolute=true;
|
||||
}
|
||||
|
||||
nd=nd.simplify_path();
|
||||
|
||||
if (nd.begins_with("/")) {
|
||||
nd=nd.replace_first("/","") ;
|
||||
absolute=true;
|
||||
}
|
||||
|
||||
Vector<String> paths = nd.split("/");
|
||||
|
||||
PackedData::PackedDir *pd;
|
||||
|
||||
if (absolute)
|
||||
pd = PackedData::get_singleton()->root;
|
||||
else
|
||||
pd = current;
|
||||
|
||||
for(int i=0;i<paths.size();i++) {
|
||||
|
||||
String p = paths[i];
|
||||
if (p==".") {
|
||||
continue;
|
||||
} else if (p=="..") {
|
||||
if (pd->parent) {
|
||||
pd=pd->parent;
|
||||
}
|
||||
} else if (pd->subdirs.has(p)) {
|
||||
|
||||
pd=pd->subdirs[p];
|
||||
|
||||
} else {
|
||||
|
||||
return ERR_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
current=pd;
|
||||
|
||||
return OK;
|
||||
|
||||
|
||||
}
|
||||
|
||||
String DirAccessPack::get_current_dir() {
|
||||
|
||||
String p;
|
||||
PackedData::PackedDir *pd = current;
|
||||
while(pd->parent) {
|
||||
|
||||
if (pd!=current)
|
||||
p="/"+p;
|
||||
p=p+pd->name;
|
||||
}
|
||||
|
||||
return "res://"+p;
|
||||
|
||||
}
|
||||
|
||||
bool DirAccessPack::file_exists(String p_file){
|
||||
|
||||
return current->files.has(p_file);
|
||||
}
|
||||
|
||||
Error DirAccessPack::make_dir(String p_dir){
|
||||
|
||||
return ERR_UNAVAILABLE;
|
||||
}
|
||||
|
||||
Error DirAccessPack::rename(String p_from, String p_to){
|
||||
|
||||
return ERR_UNAVAILABLE;
|
||||
|
||||
}
|
||||
Error DirAccessPack::remove(String p_name){
|
||||
|
||||
return ERR_UNAVAILABLE;
|
||||
|
||||
}
|
||||
|
||||
size_t DirAccessPack::get_space_left(){
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DirAccessPack::DirAccessPack() {
|
||||
|
||||
current=PackedData::get_singleton()->root;
|
||||
cdir=false;
|
||||
}
|
||||
|
||||
DirAccessPack::~DirAccessPack() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
204
core/io/file_access_pack.h
Normal file
204
core/io/file_access_pack.h
Normal file
@ -0,0 +1,204 @@
|
||||
/*************************************************************************/
|
||||
/* file_access_pack.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 FILE_ACCESS_PACK_H
|
||||
#define FILE_ACCESS_PACK_H
|
||||
|
||||
#include "os/file_access.h"
|
||||
#include "os/dir_access.h"
|
||||
#include "map.h"
|
||||
#include "list.h"
|
||||
#include "print_string.h"
|
||||
|
||||
class PackSource;
|
||||
|
||||
class PackedData {
|
||||
friend class FileAccessPack;
|
||||
friend class DirAccessPack;
|
||||
friend class PackSource;
|
||||
|
||||
public:
|
||||
struct PackedFile {
|
||||
|
||||
String pack;
|
||||
uint64_t offset;
|
||||
uint64_t size;
|
||||
PackSource* src;
|
||||
};
|
||||
|
||||
private:
|
||||
struct PackedDir {
|
||||
PackedDir *parent;
|
||||
String name;
|
||||
Map<String,PackedDir*> subdirs;
|
||||
Set<String> files;
|
||||
};
|
||||
|
||||
|
||||
Map<String,PackedFile> files;
|
||||
Vector<PackSource*> sources;
|
||||
|
||||
PackedDir *root;
|
||||
//Map<String,PackedDir*> dirs;
|
||||
|
||||
static PackedData *singleton;
|
||||
bool disabled;
|
||||
|
||||
public:
|
||||
|
||||
void add_pack_source(PackSource* p_source);
|
||||
void add_path(const String& pkg_path, const String& path, uint64_t ofs, uint64_t size, PackSource* p_src); // for PackSource
|
||||
|
||||
void set_disabled(bool p_disabled) { disabled=p_disabled; }
|
||||
_FORCE_INLINE_ bool is_disabled() const { return disabled; }
|
||||
|
||||
static PackedData *get_singleton() { return singleton; }
|
||||
Error add_pack(const String& p_path);
|
||||
|
||||
_FORCE_INLINE_ FileAccess *try_open_path(const String& p_path);
|
||||
_FORCE_INLINE_ bool has_path(const String& p_path);
|
||||
|
||||
PackedData();
|
||||
};
|
||||
|
||||
class PackSource {
|
||||
|
||||
public:
|
||||
|
||||
virtual bool try_open_pack(const String& p_path)=0;
|
||||
virtual FileAccess* get_file(const String& p_path, PackedData::PackedFile* p_file)=0;
|
||||
};
|
||||
|
||||
class PackedSourcePCK : public PackSource {
|
||||
|
||||
public:
|
||||
|
||||
virtual bool try_open_pack(const String &p_path);
|
||||
virtual FileAccess* get_file(const String& p_path, PackedData::PackedFile* p_file);
|
||||
};
|
||||
|
||||
|
||||
class FileAccessPack : public FileAccess {
|
||||
|
||||
PackedData::PackedFile pf;
|
||||
|
||||
mutable size_t pos;
|
||||
mutable bool eof;
|
||||
|
||||
FileAccess *f;
|
||||
virtual Error _open(const String& p_path, int p_mode_flags);
|
||||
virtual uint64_t _get_modified_time(const String& p_file) { return 0; }
|
||||
|
||||
public:
|
||||
|
||||
|
||||
virtual void close();
|
||||
virtual bool is_open() const;
|
||||
|
||||
virtual void seek(size_t p_position);
|
||||
virtual void seek_end(int64_t p_position=0);
|
||||
virtual size_t get_pos() const;
|
||||
virtual size_t get_len() const;
|
||||
|
||||
virtual bool eof_reached() const;
|
||||
|
||||
virtual uint8_t get_8() const;
|
||||
|
||||
|
||||
virtual int get_buffer(uint8_t *p_dst,int p_length) const;
|
||||
|
||||
virtual void set_endian_swap(bool p_swap);
|
||||
|
||||
virtual Error get_error() const;
|
||||
|
||||
virtual void store_8(uint8_t p_dest);
|
||||
|
||||
virtual void store_buffer(const uint8_t *p_src,int p_length);
|
||||
|
||||
virtual bool file_exists(const String& p_name);
|
||||
|
||||
|
||||
FileAccessPack(const String& p_path, const PackedData::PackedFile& p_file);
|
||||
~FileAccessPack();
|
||||
};
|
||||
|
||||
|
||||
FileAccess *PackedData::try_open_path(const String& p_path) {
|
||||
|
||||
if (files.has(p_path)) {
|
||||
return files[p_path].src->get_file(p_path, &files[p_path]);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool PackedData::has_path(const String& p_path) {
|
||||
|
||||
return files.has(p_path);
|
||||
}
|
||||
|
||||
|
||||
class DirAccessPack : public DirAccess {
|
||||
|
||||
|
||||
PackedData::PackedDir *current;
|
||||
|
||||
List<String> list_dirs;
|
||||
List<String> list_files;
|
||||
bool cdir;
|
||||
|
||||
public:
|
||||
|
||||
virtual bool list_dir_begin();
|
||||
virtual String get_next();
|
||||
virtual bool current_is_dir() const;
|
||||
virtual void list_dir_end();
|
||||
|
||||
virtual int get_drive_count();
|
||||
virtual String get_drive(int p_drive);
|
||||
|
||||
virtual Error change_dir(String p_dir);
|
||||
virtual String get_current_dir();
|
||||
|
||||
|
||||
virtual bool file_exists(String p_file);
|
||||
|
||||
virtual Error make_dir(String p_dir);
|
||||
|
||||
virtual Error rename(String p_from, String p_to);
|
||||
virtual Error remove(String p_name);
|
||||
|
||||
size_t get_space_left();
|
||||
|
||||
DirAccessPack();
|
||||
~DirAccessPack();
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // FILE_ACCESS_PACK_H
|
367
core/io/file_access_zip.cpp
Normal file
367
core/io/file_access_zip.cpp
Normal file
@ -0,0 +1,367 @@
|
||||
/*************************************************************************/
|
||||
/* file_access_zip.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
#ifdef MINIZIP_ENABLED
|
||||
|
||||
#include "file_access_zip.h"
|
||||
|
||||
#include "core/os/file_access.h"
|
||||
|
||||
ZipArchive* ZipArchive::instance = NULL;
|
||||
|
||||
extern "C" {
|
||||
|
||||
static void* godot_open(void* data, const char* p_fname, int mode) {
|
||||
|
||||
if (mode & ZLIB_FILEFUNC_MODE_WRITE) {
|
||||
return NULL;
|
||||
};
|
||||
|
||||
FileAccess* f = (FileAccess*)data;
|
||||
f->open(p_fname, FileAccess::READ);
|
||||
|
||||
return f->is_open()?data:NULL;
|
||||
|
||||
};
|
||||
|
||||
static uLong godot_read(void* data, void* fdata, void* buf, uLong size) {
|
||||
|
||||
FileAccess* f = (FileAccess*)data;
|
||||
f->get_buffer((uint8_t*)buf, size);
|
||||
return size;
|
||||
};
|
||||
|
||||
static uLong godot_write(voidpf opaque, voidpf stream, const void* buf, uLong size) {
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
static long godot_tell (voidpf opaque, voidpf stream) {
|
||||
|
||||
FileAccess* f = (FileAccess*)opaque;
|
||||
return f->get_pos();
|
||||
};
|
||||
|
||||
static long godot_seek(voidpf opaque, voidpf stream, uLong offset, int origin) {
|
||||
|
||||
FileAccess* f = (FileAccess*)opaque;
|
||||
|
||||
int pos = offset;
|
||||
switch (origin) {
|
||||
|
||||
case ZLIB_FILEFUNC_SEEK_CUR:
|
||||
pos = f->get_pos() + offset;
|
||||
break;
|
||||
case ZLIB_FILEFUNC_SEEK_END:
|
||||
pos = f->get_len() + offset;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
f->seek(pos);
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
static int godot_close(voidpf opaque, voidpf stream) {
|
||||
|
||||
FileAccess* f = (FileAccess*)opaque;
|
||||
f->close();
|
||||
return 0;
|
||||
};
|
||||
|
||||
static int godot_testerror(voidpf opaque, voidpf stream) {
|
||||
|
||||
FileAccess* f = (FileAccess*)opaque;
|
||||
return f->get_error()!=OK?1:0;
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
void ZipArchive::close_handle(unzFile p_file) const {
|
||||
|
||||
ERR_FAIL_COND(!p_file);
|
||||
FileAccess* f = (FileAccess*)unzGetOpaque(p_file);
|
||||
unzCloseCurrentFile(p_file);
|
||||
unzClose(p_file);
|
||||
memdelete(f);
|
||||
};
|
||||
|
||||
unzFile ZipArchive::get_file_handle(String p_file) const {
|
||||
|
||||
ERR_FAIL_COND_V(!file_exists(p_file), NULL);
|
||||
File file = files[p_file];
|
||||
|
||||
FileAccess* f = FileAccess::open(packages[file.package].filename, FileAccess::READ);
|
||||
ERR_FAIL_COND_V(!f, NULL);
|
||||
|
||||
zlib_filefunc_def io;
|
||||
|
||||
io.opaque = f;
|
||||
io.zopen_file = godot_open;
|
||||
io.zread_file = godot_read;
|
||||
io.zwrite_file = godot_write;
|
||||
|
||||
io.ztell_file = godot_tell;
|
||||
io.zseek_file = godot_seek;
|
||||
io.zclose_file = godot_close;
|
||||
io.zerror_file = godot_testerror;
|
||||
|
||||
unzFile pkg = unzOpen2(packages[file.package].filename.utf8().get_data(), &io);
|
||||
ERR_FAIL_COND_V(!pkg, NULL);
|
||||
unzGoToFilePos(pkg, &file.file_pos);
|
||||
if (unzOpenCurrentFile(pkg) != UNZ_OK) {
|
||||
|
||||
unzClose(pkg);
|
||||
ERR_FAIL_V(NULL);
|
||||
};
|
||||
|
||||
return pkg;
|
||||
};
|
||||
|
||||
bool ZipArchive::try_open_pack(const String& p_name) {
|
||||
|
||||
printf("opening pack %ls, %i, %i\n", p_name.c_str(), p_name.extension().nocasecmp_to("zip"), p_name.extension().nocasecmp_to("pcz"));
|
||||
if (p_name.extension().nocasecmp_to("zip") != 0 && p_name.extension().nocasecmp_to("pcz") != 0)
|
||||
return false;
|
||||
|
||||
zlib_filefunc_def io;
|
||||
|
||||
FileAccess* f = FileAccess::open(p_name, FileAccess::READ);
|
||||
if (!f)
|
||||
return false;
|
||||
io.opaque = f;
|
||||
io.zopen_file = godot_open;
|
||||
io.zread_file = godot_read;
|
||||
io.zwrite_file = godot_write;
|
||||
|
||||
io.ztell_file = godot_tell;
|
||||
io.zseek_file = godot_seek;
|
||||
io.zclose_file = godot_close;
|
||||
io.zerror_file = godot_testerror;
|
||||
|
||||
unzFile zfile = unzOpen2(p_name.utf8().get_data(), &io);
|
||||
ERR_FAIL_COND_V(!zfile, false);
|
||||
|
||||
unz_global_info64 gi;
|
||||
int err = unzGetGlobalInfo64(zfile, &gi);
|
||||
ERR_FAIL_COND_V(err!=UNZ_OK, false);
|
||||
|
||||
Package pkg;
|
||||
pkg.filename = p_name;
|
||||
pkg.zfile = zfile;
|
||||
packages.push_back(pkg);
|
||||
int pkg_num = packages.size()-1;
|
||||
|
||||
for (unsigned int i=0;i<gi.number_entry;i++) {
|
||||
|
||||
char filename_inzip[256];
|
||||
|
||||
unz_file_info64 file_info;
|
||||
err = unzGetCurrentFileInfo64(zfile,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
|
||||
ERR_CONTINUE(err != UNZ_OK);
|
||||
|
||||
File f;
|
||||
f.package = pkg_num;
|
||||
unzGetFilePos(zfile, &f.file_pos);
|
||||
|
||||
String fname = String("res://") + filename_inzip;
|
||||
files[fname] = f;
|
||||
|
||||
PackedData::get_singleton()->add_path(p_name, fname, 0, 0, this);
|
||||
|
||||
if ((i+1)<gi.number_entry) {
|
||||
unzGoToNextFile(zfile);
|
||||
};
|
||||
};
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
bool ZipArchive::file_exists(String p_name) const {
|
||||
|
||||
return files.has(p_name);
|
||||
};
|
||||
|
||||
FileAccess* ZipArchive::get_file(const String& p_path, PackedData::PackedFile* p_file) {
|
||||
|
||||
return memnew(FileAccessZip(p_path, *p_file));
|
||||
};
|
||||
|
||||
|
||||
ZipArchive* ZipArchive::get_singleton() {
|
||||
|
||||
if (instance == NULL) {
|
||||
instance = memnew(ZipArchive);
|
||||
};
|
||||
|
||||
return instance;
|
||||
};
|
||||
|
||||
ZipArchive::ZipArchive() {
|
||||
|
||||
instance = this;
|
||||
//fa_create_func = FileAccess::get_create_func();
|
||||
};
|
||||
|
||||
ZipArchive::~ZipArchive() {
|
||||
|
||||
for (int i=0; i<packages.size(); i++) {
|
||||
|
||||
FileAccess* f = (FileAccess*)unzGetOpaque(packages[i].zfile);
|
||||
unzClose(packages[i].zfile);
|
||||
memdelete(f);
|
||||
};
|
||||
|
||||
packages.clear();
|
||||
};
|
||||
|
||||
|
||||
Error FileAccessZip::_open(const String& p_path, int p_mode_flags) {
|
||||
|
||||
close();
|
||||
|
||||
ERR_FAIL_COND_V(p_mode_flags & FileAccess::WRITE, FAILED);
|
||||
ZipArchive* arch = ZipArchive::get_singleton();
|
||||
ERR_FAIL_COND_V(!arch, FAILED);
|
||||
zfile = arch->get_file_handle(p_path);
|
||||
ERR_FAIL_COND_V(!zfile, FAILED);
|
||||
|
||||
int err = unzGetCurrentFileInfo64(zfile,&file_info,NULL,0,NULL,0,NULL,0);
|
||||
ERR_FAIL_COND_V(err != UNZ_OK, FAILED);
|
||||
|
||||
return OK;
|
||||
};
|
||||
|
||||
void FileAccessZip::close() {
|
||||
|
||||
if (!zfile)
|
||||
return;
|
||||
|
||||
ZipArchive* arch = ZipArchive::get_singleton();
|
||||
ERR_FAIL_COND(!arch);
|
||||
arch->close_handle(zfile);
|
||||
zfile = NULL;
|
||||
};
|
||||
|
||||
bool FileAccessZip::is_open() const {
|
||||
|
||||
return zfile != NULL;
|
||||
};
|
||||
|
||||
void FileAccessZip::seek(size_t p_position) {
|
||||
|
||||
ERR_FAIL_COND(!zfile);
|
||||
unzSeekCurrentFile(zfile, p_position);
|
||||
};
|
||||
|
||||
void FileAccessZip::seek_end(int64_t p_position) {
|
||||
|
||||
ERR_FAIL_COND(!zfile);
|
||||
unzSeekCurrentFile(zfile, get_len() + p_position);
|
||||
};
|
||||
|
||||
size_t FileAccessZip::get_pos() const {
|
||||
|
||||
ERR_FAIL_COND_V(!zfile, 0);
|
||||
return unztell(zfile);
|
||||
};
|
||||
|
||||
size_t FileAccessZip::get_len() const {
|
||||
|
||||
ERR_FAIL_COND_V(!zfile, 0);
|
||||
return file_info.uncompressed_size;
|
||||
};
|
||||
|
||||
bool FileAccessZip::eof_reached() const {
|
||||
|
||||
ERR_FAIL_COND_V(!zfile, true);
|
||||
|
||||
return at_eof;
|
||||
};
|
||||
|
||||
uint8_t FileAccessZip::get_8() const {
|
||||
|
||||
uint8_t ret = 0;
|
||||
get_buffer(&ret, 1);
|
||||
return ret;
|
||||
};
|
||||
|
||||
int FileAccessZip::get_buffer(uint8_t *p_dst,int p_length) const {
|
||||
|
||||
ERR_FAIL_COND_V(!zfile, -1);
|
||||
at_eof = unzeof(zfile);
|
||||
if (at_eof)
|
||||
return 0;
|
||||
int read = unzReadCurrentFile(zfile, p_dst, p_length);
|
||||
ERR_FAIL_COND_V(read < 0, read);
|
||||
if (read < p_length)
|
||||
at_eof = true;
|
||||
return read;
|
||||
};
|
||||
|
||||
Error FileAccessZip::get_error() const {
|
||||
|
||||
if (!zfile) {
|
||||
|
||||
return ERR_UNCONFIGURED;
|
||||
};
|
||||
if (eof_reached()) {
|
||||
return ERR_FILE_EOF;
|
||||
};
|
||||
|
||||
return OK;
|
||||
};
|
||||
|
||||
void FileAccessZip::store_8(uint8_t p_dest) {
|
||||
|
||||
ERR_FAIL();
|
||||
};
|
||||
|
||||
bool FileAccessZip::file_exists(const String& p_name) {
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
FileAccessZip::FileAccessZip(const String& p_path, const PackedData::PackedFile& p_file) {
|
||||
|
||||
zfile = NULL;
|
||||
_open(p_path, FileAccess::READ);
|
||||
};
|
||||
|
||||
FileAccessZip::~FileAccessZip() {
|
||||
|
||||
close();
|
||||
};
|
||||
|
||||
#endif
|
125
core/io/file_access_zip.h
Normal file
125
core/io/file_access_zip.h
Normal file
@ -0,0 +1,125 @@
|
||||
/*************************************************************************/
|
||||
/* file_access_zip.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
#ifdef MINIZIP_ENABLED
|
||||
|
||||
#ifndef FILE_ACCESS_Zip_H
|
||||
#define FILE_ACCESS_Zip_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "core/io/file_access_pack.h"
|
||||
#include "unzip.h"
|
||||
#include "map.h"
|
||||
|
||||
class ZipArchive : public PackSource {
|
||||
|
||||
public:
|
||||
|
||||
struct File {
|
||||
|
||||
int package;
|
||||
unz_file_pos file_pos;
|
||||
File() {
|
||||
|
||||
package = -1;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
|
||||
struct Package {
|
||||
String filename;
|
||||
unzFile zfile;
|
||||
};
|
||||
Vector<Package> packages;
|
||||
|
||||
Map<String,File> files;
|
||||
|
||||
static ZipArchive* instance;
|
||||
|
||||
FileAccess::CreateFunc fa_create_func;
|
||||
|
||||
public:
|
||||
|
||||
void close_handle(unzFile p_file) const;
|
||||
unzFile get_file_handle(String p_file) const;
|
||||
|
||||
Error add_package(String p_name);
|
||||
|
||||
bool file_exists(String p_name) const;
|
||||
|
||||
virtual bool try_open_pack(const String& p_path);
|
||||
FileAccess* get_file(const String& p_path, PackedData::PackedFile* p_file);
|
||||
|
||||
static ZipArchive* get_singleton();
|
||||
|
||||
ZipArchive();
|
||||
~ZipArchive();
|
||||
};
|
||||
|
||||
|
||||
class FileAccessZip : public FileAccess {
|
||||
|
||||
unzFile zfile;
|
||||
unz_file_info64 file_info;
|
||||
|
||||
mutable bool at_eof;
|
||||
|
||||
ZipArchive* archive;
|
||||
|
||||
public:
|
||||
|
||||
virtual Error _open(const String& p_path, int p_mode_flags); ///< open a file
|
||||
virtual void close(); ///< close a file
|
||||
virtual bool is_open() const; ///< true when file is open
|
||||
|
||||
virtual void seek(size_t p_position); ///< seek to a given position
|
||||
virtual void seek_end(int64_t p_position=0); ///< seek from the end of file
|
||||
virtual size_t get_pos() const; ///< get position in the file
|
||||
virtual size_t get_len() const; ///< get size of the file
|
||||
|
||||
virtual bool eof_reached() const; ///< reading passed EOF
|
||||
|
||||
virtual uint8_t get_8() const; ///< get a byte
|
||||
virtual int get_buffer(uint8_t *p_dst,int p_length) const;
|
||||
|
||||
virtual Error get_error() const; ///< get last error
|
||||
|
||||
virtual void store_8(uint8_t p_dest); ///< store a byte
|
||||
virtual bool file_exists(const String& p_name); ///< return true if a file exists
|
||||
|
||||
virtual uint64_t _get_modified_time(const String& p_file) { return 0; } // todo
|
||||
|
||||
FileAccessZip(const String& p_path, const PackedData::PackedFile& p_file);
|
||||
~FileAccessZip();
|
||||
};
|
||||
|
||||
#endif // FILE_ACCESS_ZIP_H
|
||||
|
||||
#endif
|
641
core/io/http_client.cpp
Normal file
641
core/io/http_client.cpp
Normal file
@ -0,0 +1,641 @@
|
||||
/*************************************************************************/
|
||||
/* http_client.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "http_client.h"
|
||||
|
||||
|
||||
Error HTTPClient::connect_url(const String& p_url) {
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error HTTPClient::connect(const String &p_host,int p_port){
|
||||
|
||||
close();
|
||||
conn_port=p_port;
|
||||
conn_host=p_host;
|
||||
|
||||
if (conn_host.begins_with("http://")) {
|
||||
|
||||
conn_host=conn_host.replace_first("http://","");
|
||||
} else if (conn_host.begins_with("https://")) {
|
||||
//use https
|
||||
conn_host=conn_host.replace_first("https://","");
|
||||
}
|
||||
|
||||
|
||||
connection=tcp_connection;
|
||||
if (conn_host.is_valid_ip_address()) {
|
||||
//is ip
|
||||
Error err = tcp_connection->connect(IP_Address(conn_host),p_port);
|
||||
if (err) {
|
||||
status=STATUS_CANT_CONNECT;
|
||||
return err;
|
||||
}
|
||||
|
||||
status=STATUS_CONNECTING;
|
||||
} else {
|
||||
//is hostname
|
||||
resolving=IP::get_singleton()->resolve_hostname_queue_item(conn_host);
|
||||
status=STATUS_RESOLVING;
|
||||
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
void HTTPClient::set_connection(const Ref<StreamPeer>& p_connection){
|
||||
|
||||
close();
|
||||
connection=p_connection;
|
||||
|
||||
}
|
||||
|
||||
|
||||
Error HTTPClient::request( Method p_method, const String& p_url, const Vector<String>& p_headers,const String& p_body) {
|
||||
|
||||
ERR_FAIL_INDEX_V(p_method,METHOD_MAX,ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(status!=STATUS_CONNECTED,ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(connection.is_null(),ERR_INVALID_DATA);
|
||||
|
||||
|
||||
static const char* _methods[METHOD_MAX]={
|
||||
"GET",
|
||||
"HEAD",
|
||||
"POST",
|
||||
"PUT",
|
||||
"DELETE",
|
||||
"OPTIONS",
|
||||
"TRACE",
|
||||
"CONNECT"};
|
||||
|
||||
String request=String(_methods[p_method])+" "+p_url+" HTTP/1.1\r\n";
|
||||
request+="Host: "+conn_host+":"+itos(conn_port)+"\r\n";
|
||||
for(int i=0;i<p_headers.size();i++) {
|
||||
request+=p_headers[i]+"\r\n";
|
||||
}
|
||||
request+="\r\n";
|
||||
request+=p_body;
|
||||
|
||||
CharString cs=request.utf8();
|
||||
Error err = connection->put_data((const uint8_t*)cs.ptr(),cs.length());
|
||||
if (err) {
|
||||
close();
|
||||
status=STATUS_CONNECTION_ERROR;
|
||||
return err;
|
||||
}
|
||||
|
||||
status=STATUS_REQUESTING;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error HTTPClient::send_body_text(const String& p_body){
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error HTTPClient::send_body_data(const ByteArray& p_body){
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool HTTPClient::has_response() const {
|
||||
|
||||
return response_headers.size()!=0;
|
||||
}
|
||||
|
||||
bool HTTPClient::is_response_chunked() const {
|
||||
|
||||
return chunked;
|
||||
}
|
||||
|
||||
int HTTPClient::get_response_code() const {
|
||||
|
||||
return response_num;
|
||||
}
|
||||
Error HTTPClient::get_response_headers(List<String> *r_response) {
|
||||
|
||||
if (!response_headers.size())
|
||||
return ERR_INVALID_PARAMETER;
|
||||
|
||||
for(int i=0;i<response_headers.size();i++) {
|
||||
|
||||
r_response->push_back(response_headers[i]);
|
||||
}
|
||||
|
||||
response_headers.clear();
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
void HTTPClient::close(){
|
||||
|
||||
if (tcp_connection->get_status()!=StreamPeerTCP::STATUS_NONE)
|
||||
tcp_connection->disconnect();
|
||||
|
||||
connection.unref();
|
||||
status=STATUS_DISCONNECTED;
|
||||
if (resolving!=IP::RESOLVER_INVALID_ID) {
|
||||
|
||||
IP::get_singleton()->erase_resolve_item(resolving);
|
||||
resolving=IP::RESOLVER_INVALID_ID;
|
||||
|
||||
}
|
||||
|
||||
response_headers.clear();
|
||||
response_str.clear();
|
||||
body_size=0;
|
||||
body_left=0;
|
||||
chunk_left=0;
|
||||
response_num=0;
|
||||
}
|
||||
|
||||
|
||||
Error HTTPClient::poll(){
|
||||
|
||||
switch(status) {
|
||||
|
||||
|
||||
case STATUS_RESOLVING: {
|
||||
ERR_FAIL_COND_V(resolving==IP::RESOLVER_INVALID_ID,ERR_BUG);
|
||||
|
||||
IP::ResolverStatus rstatus = IP::get_singleton()->get_resolve_item_status(resolving);
|
||||
switch(rstatus) {
|
||||
case IP::RESOLVER_STATUS_WAITING: return OK; //still resolving
|
||||
|
||||
case IP::RESOLVER_STATUS_DONE: {
|
||||
|
||||
IP_Address host = IP::get_singleton()->get_resolve_item_address(resolving);
|
||||
Error err = tcp_connection->connect(host,conn_port);
|
||||
IP::get_singleton()->erase_resolve_item(resolving);
|
||||
resolving=IP::RESOLVER_INVALID_ID;
|
||||
if (err) {
|
||||
status=STATUS_CANT_CONNECT;
|
||||
return err;
|
||||
}
|
||||
|
||||
status=STATUS_CONNECTING;
|
||||
} break;
|
||||
case IP::RESOLVER_STATUS_NONE:
|
||||
case IP::RESOLVER_STATUS_ERROR: {
|
||||
|
||||
IP::get_singleton()->erase_resolve_item(resolving);
|
||||
resolving=IP::RESOLVER_INVALID_ID;
|
||||
close();
|
||||
status=STATUS_CANT_RESOLVE;
|
||||
return ERR_CANT_RESOLVE;
|
||||
} break;
|
||||
|
||||
}
|
||||
} break;
|
||||
case STATUS_CONNECTING: {
|
||||
|
||||
StreamPeerTCP::Status s = tcp_connection->get_status();
|
||||
switch(s) {
|
||||
|
||||
case StreamPeerTCP::STATUS_CONNECTING: {
|
||||
return OK; //do none
|
||||
} break;
|
||||
case StreamPeerTCP::STATUS_CONNECTED: {
|
||||
status=STATUS_CONNECTED;
|
||||
return OK;
|
||||
} break;
|
||||
case StreamPeerTCP::STATUS_ERROR:
|
||||
case StreamPeerTCP::STATUS_NONE: {
|
||||
|
||||
close();
|
||||
status=STATUS_CANT_CONNECT;
|
||||
return ERR_CANT_CONNECT;
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
case STATUS_CONNECTED: {
|
||||
//request something please
|
||||
return OK;
|
||||
} break;
|
||||
case STATUS_REQUESTING: {
|
||||
|
||||
|
||||
while(true) {
|
||||
uint8_t byte;
|
||||
int rec=0;
|
||||
Error err = connection->get_partial_data(&byte,1,rec);
|
||||
if (err!=OK) {
|
||||
close();
|
||||
status=STATUS_CONNECTION_ERROR;
|
||||
return ERR_CONNECTION_ERROR;
|
||||
}
|
||||
|
||||
if (rec==0)
|
||||
return OK; //keep trying!
|
||||
|
||||
response_str.push_back(byte);
|
||||
int rs = response_str.size();
|
||||
if (
|
||||
(rs>=2 && response_str[rs-2]=='\n' && response_str[rs-1]=='\n') ||
|
||||
(rs>=4 && response_str[rs-4]=='\r' && response_str[rs-3]=='\n' && rs>=4 && response_str[rs-2]=='\r' && response_str[rs-1]=='\n')
|
||||
) {
|
||||
|
||||
|
||||
//end of response, parse.
|
||||
response_str.push_back(0);
|
||||
String response;
|
||||
response.parse_utf8((const char*)response_str.ptr());
|
||||
print_line("END OF RESPONSE? :\n"+response+"\n------");
|
||||
Vector<String> responses = response.split("\n");
|
||||
body_size=0;
|
||||
chunked=false;
|
||||
body_left=0;
|
||||
chunk_left=0;
|
||||
response_headers.clear();
|
||||
response_num = RESPONSE_OK;
|
||||
|
||||
for(int i=0;i<responses.size();i++) {
|
||||
|
||||
String s = responses[i].strip_edges();
|
||||
if (s.length()==0)
|
||||
continue;
|
||||
if (s.begins_with("Content-Length:")) {
|
||||
body_size = s.substr(s.find(":")+1,s.length()).strip_edges().to_int();
|
||||
body_left=body_size;
|
||||
}
|
||||
|
||||
if (s.begins_with("Transfer-Encoding:")) {
|
||||
String encoding = s.substr(s.find(":")+1,s.length()).strip_edges();
|
||||
print_line("TRANSFER ENCODING: "+encoding);
|
||||
if (encoding=="chunked") {
|
||||
chunked=true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (i==0 && responses[i].begins_with("HTTP")) {
|
||||
|
||||
String num = responses[i].get_slice(" ",1);
|
||||
response_num=num.to_int();
|
||||
} else {
|
||||
|
||||
response_headers.push_back(s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (body_size==0 && !chunked) {
|
||||
|
||||
status=STATUS_CONNECTED; //ask for something again?
|
||||
} else {
|
||||
status=STATUS_BODY;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
//wait for response
|
||||
return OK;
|
||||
} break;
|
||||
case STATUS_DISCONNECTED: {
|
||||
return ERR_UNCONFIGURED;
|
||||
} break;
|
||||
case STATUS_CONNECTION_ERROR: {
|
||||
return ERR_CONNECTION_ERROR;
|
||||
} break;
|
||||
case STATUS_CANT_CONNECT: {
|
||||
return ERR_CANT_CONNECT;
|
||||
} break;
|
||||
case STATUS_CANT_RESOLVE: {
|
||||
return ERR_CANT_RESOLVE;
|
||||
} break;
|
||||
}
|
||||
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
Dictionary HTTPClient::_get_response_headers_as_dictionary() {
|
||||
|
||||
List<String> rh;
|
||||
get_response_headers(&rh);
|
||||
Dictionary ret;
|
||||
for(const List<String>::Element *E=rh.front();E;E=E->next()) {
|
||||
String s = E->get();
|
||||
int sp = s.find(":");
|
||||
if (sp==-1)
|
||||
continue;
|
||||
String key = s.substr(0,sp).strip_edges();
|
||||
String value = s.substr(sp+1,s.length()).strip_edges();
|
||||
ret[key]=value;
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
StringArray HTTPClient::_get_response_headers() {
|
||||
|
||||
List<String> rh;
|
||||
get_response_headers(&rh);
|
||||
StringArray ret;
|
||||
ret.resize(rh.size());
|
||||
int idx=0;
|
||||
for(const List<String>::Element *E=rh.front();E;E=E->next()) {
|
||||
ret.set(idx++,E->get());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int HTTPClient::get_response_body_length() const {
|
||||
|
||||
return body_size;
|
||||
}
|
||||
|
||||
ByteArray HTTPClient::read_response_body_chunk() {
|
||||
|
||||
ERR_FAIL_COND_V( status !=STATUS_BODY, ByteArray() );
|
||||
|
||||
Error err=OK;
|
||||
|
||||
if (chunked) {
|
||||
|
||||
while(true) {
|
||||
|
||||
if (chunk_left==0) {
|
||||
//reading len
|
||||
uint8_t b;
|
||||
int rec=0;
|
||||
err = connection->get_partial_data(&b,1,rec);
|
||||
|
||||
if (rec==0)
|
||||
break;
|
||||
|
||||
chunk.push_back(b);
|
||||
|
||||
if (chunk.size()>32) {
|
||||
ERR_PRINT("HTTP Invalid chunk hex len");
|
||||
status=STATUS_CONNECTION_ERROR;
|
||||
return ByteArray();
|
||||
}
|
||||
|
||||
if (chunk.size()>2 && chunk[chunk.size()-2]=='\r' && chunk[chunk.size()-1]=='\n') {
|
||||
|
||||
int len=0;
|
||||
for(int i=0;i<chunk.size()-2;i++) {
|
||||
char c = chunk[i];
|
||||
int v=0;
|
||||
if (c>='0' && c<='9')
|
||||
v=c-'0';
|
||||
else if (c>='a' && c<='f')
|
||||
v=c-'a'+10;
|
||||
else if (c>='A' && c<='F')
|
||||
v=c-'A'+10;
|
||||
else {
|
||||
ERR_PRINT("HTTP Chunk len not in hex!!");
|
||||
status=STATUS_CONNECTION_ERROR;
|
||||
return ByteArray();
|
||||
}
|
||||
len<<=4;
|
||||
len|=v;
|
||||
if (len>(1<<24)) {
|
||||
ERR_PRINT("HTTP Chunk too big!! >16mb");
|
||||
status=STATUS_CONNECTION_ERROR;
|
||||
return ByteArray();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (len==0) {
|
||||
//end!
|
||||
status=STATUS_CONNECTED;
|
||||
chunk.clear();
|
||||
return ByteArray();
|
||||
}
|
||||
|
||||
chunk_left=len+2;
|
||||
chunk.resize(chunk_left);
|
||||
|
||||
}
|
||||
} else {
|
||||
|
||||
int rec=0;
|
||||
err = connection->get_partial_data(&chunk[chunk.size()-chunk_left],chunk_left,rec);
|
||||
if (rec==0) {
|
||||
break;
|
||||
}
|
||||
chunk_left-=rec;
|
||||
|
||||
if (chunk_left==0) {
|
||||
|
||||
if (chunk[chunk.size()-2]!='\r' || chunk[chunk.size()-1]!='\n') {
|
||||
ERR_PRINT("HTTP Invalid chunk terminator (not \\r\\n)");
|
||||
status=STATUS_CONNECTION_ERROR;
|
||||
return ByteArray();
|
||||
}
|
||||
|
||||
ByteArray ret;
|
||||
ret.resize(chunk.size()-2);
|
||||
{
|
||||
ByteArray::Write w = ret.write();
|
||||
copymem(w.ptr(),chunk.ptr(),chunk.size()-2);
|
||||
}
|
||||
chunk.clear();
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
ByteArray::Write r = tmp_read.write();
|
||||
int rec=0;
|
||||
err = connection->get_partial_data(r.ptr(),MIN(body_left,tmp_read.size()),rec);
|
||||
if (rec>0) {
|
||||
ByteArray ret;
|
||||
ret.resize(rec);
|
||||
ByteArray::Write w = ret.write();
|
||||
copymem(w.ptr(),r.ptr(),rec);
|
||||
body_left-=rec;
|
||||
if (body_left==0) {
|
||||
status=STATUS_CONNECTED;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (err!=OK) {
|
||||
close();
|
||||
if (err==ERR_FILE_EOF) {
|
||||
|
||||
status=STATUS_DISCONNECTED; //server disconnected
|
||||
} else {
|
||||
|
||||
status=STATUS_CONNECTION_ERROR;
|
||||
}
|
||||
} else if (body_left==0 && !chunked) {
|
||||
|
||||
status=STATUS_CONNECTED;
|
||||
}
|
||||
|
||||
return ByteArray();
|
||||
}
|
||||
|
||||
HTTPClient::Status HTTPClient::get_status() const {
|
||||
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void HTTPClient::_bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("connect:Error","host","port"),&HTTPClient::connect);
|
||||
ObjectTypeDB::bind_method(_MD("set_connection","connection:StreamPeer"),&HTTPClient::set_connection);
|
||||
ObjectTypeDB::bind_method(_MD("request","method","url","headers","body"),&HTTPClient::request,DEFVAL(String()));
|
||||
ObjectTypeDB::bind_method(_MD("send_body_text","body"),&HTTPClient::send_body_text);
|
||||
ObjectTypeDB::bind_method(_MD("send_body_data","body"),&HTTPClient::send_body_data);
|
||||
ObjectTypeDB::bind_method(_MD("close"),&HTTPClient::close);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("has_response"),&HTTPClient::has_response);
|
||||
ObjectTypeDB::bind_method(_MD("is_response_chunked"),&HTTPClient::is_response_chunked);
|
||||
ObjectTypeDB::bind_method(_MD("get_response_code"),&HTTPClient::get_response_code);
|
||||
ObjectTypeDB::bind_method(_MD("get_response_headers"),&HTTPClient::_get_response_headers);
|
||||
ObjectTypeDB::bind_method(_MD("get_response_headers_as_dictionary"),&HTTPClient::_get_response_headers_as_dictionary);
|
||||
ObjectTypeDB::bind_method(_MD("get_response_body_length"),&HTTPClient::get_response_body_length);
|
||||
ObjectTypeDB::bind_method(_MD("read_response_body_chunk"),&HTTPClient::read_response_body_chunk);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("get_status"),&HTTPClient::get_status);
|
||||
ObjectTypeDB::bind_method(_MD("poll:Error"),&HTTPClient::poll);
|
||||
|
||||
BIND_CONSTANT( METHOD_GET );
|
||||
BIND_CONSTANT( METHOD_HEAD );
|
||||
BIND_CONSTANT( METHOD_POST );
|
||||
BIND_CONSTANT( METHOD_PUT );
|
||||
BIND_CONSTANT( METHOD_DELETE );
|
||||
BIND_CONSTANT( METHOD_OPTIONS );
|
||||
BIND_CONSTANT( METHOD_TRACE );
|
||||
BIND_CONSTANT( METHOD_CONNECT );
|
||||
BIND_CONSTANT( METHOD_MAX );
|
||||
|
||||
BIND_CONSTANT( STATUS_DISCONNECTED );
|
||||
BIND_CONSTANT( STATUS_RESOLVING ); //resolving hostname (if passed a hostname)
|
||||
BIND_CONSTANT( STATUS_CANT_RESOLVE );
|
||||
BIND_CONSTANT( STATUS_CONNECTING ); //connecting to ip
|
||||
BIND_CONSTANT( STATUS_CANT_CONNECT );
|
||||
BIND_CONSTANT( STATUS_CONNECTED ); //connected ); requests only accepted here
|
||||
BIND_CONSTANT( STATUS_REQUESTING ); // request in progress
|
||||
BIND_CONSTANT( STATUS_BODY ); // request resulted in body ); which must be read
|
||||
BIND_CONSTANT( STATUS_CONNECTION_ERROR );
|
||||
|
||||
|
||||
BIND_CONSTANT( RESPONSE_CONTINUE );
|
||||
BIND_CONSTANT( RESPONSE_SWITCHING_PROTOCOLS );
|
||||
BIND_CONSTANT( RESPONSE_PROCESSING );
|
||||
|
||||
// 2xx successful
|
||||
BIND_CONSTANT( RESPONSE_OK );
|
||||
BIND_CONSTANT( RESPONSE_CREATED );
|
||||
BIND_CONSTANT( RESPONSE_ACCEPTED );
|
||||
BIND_CONSTANT( RESPONSE_NON_AUTHORITATIVE_INFORMATION );
|
||||
BIND_CONSTANT( RESPONSE_NO_CONTENT );
|
||||
BIND_CONSTANT( RESPONSE_RESET_CONTENT );
|
||||
BIND_CONSTANT( RESPONSE_PARTIAL_CONTENT );
|
||||
BIND_CONSTANT( RESPONSE_MULTI_STATUS );
|
||||
BIND_CONSTANT( RESPONSE_IM_USED );
|
||||
|
||||
// 3xx redirection
|
||||
BIND_CONSTANT( RESPONSE_MULTIPLE_CHOICES );
|
||||
BIND_CONSTANT( RESPONSE_MOVED_PERMANENTLY );
|
||||
BIND_CONSTANT( RESPONSE_FOUND );
|
||||
BIND_CONSTANT( RESPONSE_SEE_OTHER );
|
||||
BIND_CONSTANT( RESPONSE_NOT_MODIFIED );
|
||||
BIND_CONSTANT( RESPONSE_USE_PROXY );
|
||||
BIND_CONSTANT( RESPONSE_TEMPORARY_REDIRECT );
|
||||
|
||||
// 4xx client error
|
||||
BIND_CONSTANT( RESPONSE_BAD_REQUEST );
|
||||
BIND_CONSTANT( RESPONSE_UNAUTHORIZED );
|
||||
BIND_CONSTANT( RESPONSE_PAYMENT_REQUIRED );
|
||||
BIND_CONSTANT( RESPONSE_FORBIDDEN );
|
||||
BIND_CONSTANT( RESPONSE_NOT_FOUND );
|
||||
BIND_CONSTANT( RESPONSE_METHOD_NOT_ALLOWED );
|
||||
BIND_CONSTANT( RESPONSE_NOT_ACCEPTABLE );
|
||||
BIND_CONSTANT( RESPONSE_PROXY_AUTHENTICATION_REQUIRED );
|
||||
BIND_CONSTANT( RESPONSE_REQUEST_TIMEOUT );
|
||||
BIND_CONSTANT( RESPONSE_CONFLICT );
|
||||
BIND_CONSTANT( RESPONSE_GONE );
|
||||
BIND_CONSTANT( RESPONSE_LENGTH_REQUIRED );
|
||||
BIND_CONSTANT( RESPONSE_PRECONDITION_FAILED );
|
||||
BIND_CONSTANT( RESPONSE_REQUEST_ENTITY_TOO_LARGE );
|
||||
BIND_CONSTANT( RESPONSE_REQUEST_URI_TOO_LONG );
|
||||
BIND_CONSTANT( RESPONSE_UNSUPPORTED_MEDIA_TYPE );
|
||||
BIND_CONSTANT( RESPONSE_REQUESTED_RANGE_NOT_SATISFIABLE );
|
||||
BIND_CONSTANT( RESPONSE_EXPECTATION_FAILED );
|
||||
BIND_CONSTANT( RESPONSE_UNPROCESSABLE_ENTITY );
|
||||
BIND_CONSTANT( RESPONSE_LOCKED );
|
||||
BIND_CONSTANT( RESPONSE_FAILED_DEPENDENCY );
|
||||
BIND_CONSTANT( RESPONSE_UPGRADE_REQUIRED );
|
||||
|
||||
// 5xx server error
|
||||
BIND_CONSTANT( RESPONSE_INTERNAL_SERVER_ERROR );
|
||||
BIND_CONSTANT( RESPONSE_NOT_IMPLEMENTED );
|
||||
BIND_CONSTANT( RESPONSE_BAD_GATEWAY );
|
||||
BIND_CONSTANT( RESPONSE_SERVICE_UNAVAILABLE );
|
||||
BIND_CONSTANT( RESPONSE_GATEWAY_TIMEOUT );
|
||||
BIND_CONSTANT( RESPONSE_HTTP_VERSION_NOT_SUPPORTED );
|
||||
BIND_CONSTANT( RESPONSE_INSUFFICIENT_STORAGE );
|
||||
BIND_CONSTANT( RESPONSE_NOT_EXTENDED );
|
||||
|
||||
}
|
||||
|
||||
HTTPClient::HTTPClient(){
|
||||
|
||||
tcp_connection = StreamPeerTCP::create();
|
||||
resolving = IP::RESOLVER_INVALID_ID;
|
||||
status=STATUS_DISCONNECTED;
|
||||
conn_port=80;
|
||||
body_size=0;
|
||||
chunked=false;
|
||||
body_left=0;
|
||||
chunk_left=0;
|
||||
response_num=0;
|
||||
|
||||
tmp_read.resize(4096);
|
||||
}
|
||||
|
||||
HTTPClient::~HTTPClient(){
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user