Making Godot Easier to Use..

-=-=-=-=-=-=-=-=-=-=-=-=-=-=

-Auto indenter in code editor, this makes it much easier to paste external code.
-Zoom in 2D viewport now uses the mouse pointer as reference.
-Obscure hack to see where code/line of GDScript in C++ backtrace.
-Fixed a bug where keys would get stuck on X11 if pressed simultaneously
-Added Api on IP singleton to request local IPs.
-Premultiplied alpha support when importing texture, editing PNGs and as a blend mode.
This commit is contained in:
Juan Linietsky 2014-05-24 01:35:47 -03:00
parent f9ff086235
commit 1cad087969
54 changed files with 928 additions and 106 deletions

View file

@ -98,6 +98,13 @@ void _ResourceSaver::_bind_methods() {
ObjectTypeDB::bind_method(_MD("save","path","resource:Resource"),&_ResourceSaver::save, DEFVAL(0));
ObjectTypeDB::bind_method(_MD("get_recognized_extensions","type"),&_ResourceSaver::get_recognized_extensions);
BIND_CONSTANT(FLAG_RELATIVE_PATHS);
BIND_CONSTANT(FLAG_BUNDLE_RESOURCES);
BIND_CONSTANT(FLAG_CHANGE_PATH);
BIND_CONSTANT(FLAG_OMIT_EDITOR_PROPERTIES);
BIND_CONSTANT(FLAG_SAVE_BIG_ENDIAN);
BIND_CONSTANT(FLAG_COMPRESS);
}
_ResourceSaver::_ResourceSaver() {

View file

@ -39,6 +39,16 @@ protected:
static _ResourceSaver *singleton;
public:
enum SaverFlags {
FLAG_RELATIVE_PATHS=1,
FLAG_BUNDLE_RESOURCES=2,
FLAG_CHANGE_PATH=4,
FLAG_OMIT_EDITOR_PROPERTIES=8,
FLAG_SAVE_BIG_ENDIAN=16,
FLAG_COMPRESS=32,
};
static _ResourceSaver *get_singleton() { return singleton; }
Error save(const String &p_path,const RES& p_resource, uint32_t p_flags);

View file

@ -1660,6 +1660,31 @@ void Image::set_compress_bc_func(void (*p_compress_func)(Image *)) {
}
void Image::premultiply_alpha() {
if (data.size()==0)
return;
if (format!=FORMAT_RGBA)
return; //not needed
DVector<uint8_t>::Write wp = data.write();
unsigned char *data_ptr=wp.ptr();
for(int i=0;i<height;i++) {
for(int j=0;j<width;j++) {
BColor bc = _get_pixel(j,i,data_ptr,0);
bc.r=(int(bc.r)*int(bc.a))>>8;
bc.g=(int(bc.g)*int(bc.a))>>8;
bc.b=(int(bc.b)*int(bc.a))>>8;
_put_pixel(j,i,bc,data_ptr);
}
}
}
void Image::fix_alpha_edges() {
if (data.size()==0)

View file

@ -320,6 +320,7 @@ public:
void decompress();
void fix_alpha_edges();
void premultiply_alpha();
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);

View file

@ -25,6 +25,7 @@ Error FileAccessEncrypted::open_and_parse(FileAccess *p_base,const Vector<uint8_
} else if (p_mode==MODE_READ) {
writing=false;
key=p_key;
uint32_t magic = p_base->get_32();
print_line("MAGIC: "+itos(magic));
@ -278,6 +279,10 @@ uint64_t FileAccessEncrypted::_get_modified_time(const String& p_file){
FileAccessEncrypted::FileAccessEncrypted() {
file=NULL;
pos=0;
eofed=false;
mode=MODE_MAX;
writing=false;
}

View file

@ -188,6 +188,18 @@ void IP::erase_resolve_item(ResolverID p_id) {
}
Array IP::_get_local_addresses() const {
Array addresses;
List<IP_Address> ip_addresses;
get_local_addresses(&ip_addresses);
for(List<IP_Address>::Element *E=ip_addresses.front();E;E=E->next()) {
addresses.push_back(E->get());
}
return addresses;
}
void IP::_bind_methods() {
ObjectTypeDB::bind_method(_MD("resolve_hostname","host"),&IP::resolve_hostname);
@ -195,6 +207,7 @@ void IP::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_resolve_item_status","id"),&IP::get_resolve_item_status);
ObjectTypeDB::bind_method(_MD("get_resolve_item_address","id"),&IP::get_resolve_item_address);
ObjectTypeDB::bind_method(_MD("erase_resolve_item","id"),&IP::erase_resolve_item);
ObjectTypeDB::bind_method(_MD("get_local_addresses"),&IP::_get_local_addresses);
BIND_CONSTANT( RESOLVER_STATUS_NONE );
BIND_CONSTANT( RESOLVER_STATUS_WAITING );

View file

@ -66,16 +66,19 @@ protected:
static void _bind_methods();
virtual IP_Address _resolve_hostname(const String& p_hostname)=0;
Array _get_local_addresses() const;
static IP* (*_create)();
public:
IP_Address resolve_hostname(const String& p_hostname);
// async resolver hostname
ResolverID resolve_hostname_queue_item(const String& p_hostname);
ResolverStatus get_resolve_item_status(ResolverID p_id) const;
IP_Address get_resolve_item_address(ResolverID p_id) const;
virtual void get_local_addresses(List<IP_Address> *r_addresses) const=0;
void erase_resolve_item(ResolverID p_id);
static IP* get_singleton();

View file

@ -100,7 +100,7 @@ FileAccess *FileAccess::open(const String& p_path, int p_mode_flags, Error *r_er
FileAccess *ret=NULL;
if (!(p_mode_flags&WRITE) && PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled()) {
ret = PackedData::get_singleton()->try_open_path(p_path);
if (ret) {
if (ret) {
if (r_error)
*r_error=OK;
return ret;

View file

@ -211,6 +211,8 @@ void InputDefault::parse_input_event(const InputEvent& p_event) {
if (p_event.key.scancode==0)
break;
// print_line(p_event);
if (p_event.key.pressed)
keys_pressed.insert(p_event.key.scancode);
else

View file

@ -37,7 +37,7 @@ void MainLoop::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_WM_FOCUS_OUT);
BIND_CONSTANT(NOTIFICATION_WM_QUIT_REQUEST);
BIND_CONSTANT(NOTIFICATION_WM_UNFOCUS_REQUEST);
BIND_CONSTANT(NOTIFICATION_OS_MEMORY_WARNING);
};

View file

@ -141,6 +141,7 @@ public:
virtual int find_function(const String& p_function,const String& p_code) const=0;
virtual String make_function(const String& p_class,const String& p_name,const StringArray& p_args) const=0;
virtual Error complete_keyword(const String& p_code, int p_line, const String& p_base_path, const String& p_keyword, List<String>* r_options) { return ERR_UNAVAILABLE; }
virtual void auto_indent_code(String& p_code,int p_from_line,int p_to_line) const=0;
/* DEBUGGER FUNCTIONS */

View file

@ -3,10 +3,10 @@
<ext_resource path="res://music.ogg" type="AudioStream"></ext_resource>
<ext_resource path="res://tileset.xml" type="TileSet"></ext_resource>
<ext_resource path="res://coin.xml" type="PackedScene"></ext_resource>
<ext_resource path="res://player.xml" type="PackedScene"></ext_resource>
<ext_resource path="res://moving_platform.xml" type="PackedScene"></ext_resource>
<ext_resource path="res://seesaw.xml" type="PackedScene"></ext_resource>
<ext_resource path="res://enemy.xml" type="PackedScene"></ext_resource>
<ext_resource path="res://moving_platform.xml" type="PackedScene"></ext_resource>
<ext_resource path="res://player.xml" type="PackedScene"></ext_resource>
<ext_resource path="res://parallax_bg.xml" type="PackedScene"></ext_resource>
<main_resource>
<dictionary name="_bundled" shared="false">
@ -160,9 +160,13 @@
<string> "pixel_snap" </string>
<bool> False </bool>
<string> "zoom" </string>
<real> 0.735092 </real>
<real> 0.54036 </real>
<string> "use_snap" </string>
<bool> False </bool>
<string> "ofs" </string>
<vector2> 55.9232, 767.661 </vector2>
<vector2> 418.81, 615.088 </vector2>
<string> "snap" </string>
<int> 10 </int>
</dictionary>
<string> "3D" </string>
<dictionary shared="false">

0
doc/make_doc.sh Executable file → Normal file
View file

View file

@ -6436,7 +6436,10 @@ void RasterizerGLES2::canvas_set_blend_mode(VS::MaterialBlendMode p_mode) {
case VS::MATERIAL_BLEND_MODE_MUL: {
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
} break;
case VS::MATERIAL_BLEND_MODE_PREMULT_ALPHA: {
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);
} break;
}

View file

@ -64,6 +64,9 @@ void main() {
highp float enc32 = dot( color,highp vec4(1.0 / (256.0 * 256.0 * 256.0),1.0 / (256.0 * 256.0),1.0 / 256.0,1) );
color = vec4(vec3(enc32),1.0);
#endif
// color.rgb*=color.a;
gl_FragColor = color;
}

View file

@ -30,12 +30,24 @@
#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED)
#ifdef WINDOWS_ENABLED
#define WINVER 0x0600
#include <ws2tcpip.h>
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#include <iphlpapi.h>
#else
#include <netdb.h>
#ifdef ANDROID_ENABLED
#include "platform/android/ifaddrs_android.h"
#else
#include <ifaddrs.h>
#endif
#include <arpa/inet.h>
#include <sys/socket.h>
#endif
IP_Address IP_Unix::_resolve_hostname(const String& p_hostname) {
@ -52,6 +64,93 @@ IP_Address IP_Unix::_resolve_hostname(const String& p_hostname) {
}
#if defined(WINDOWS_ENABLED)
void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
ULONG buf_size = 1024;
IP_ADAPTER_ADDRESSES* addrs;
while (true) {
addrs = (IP_ADAPTER_ADDRESSES*)memalloc(buf_size);
int err = GetAdaptersAddresses(AF_INET, GAA_FLAG_SKIP_ANYCAST |
GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER |
GAA_FLAG_SKIP_FRIENDLY_NAME,
NULL, addrs, &buf_size);
if (err == NO_ERROR) {
break;
};
memfree(addrs);
if (err == ERROR_BUFFER_OVERFLOW) {
continue; // will go back and alloc the right size
};
ERR_EXPLAIN("Call to GetAdaptersAddresses failed with error " + itos(err));
ERR_FAIL();
return;
};
IP_ADAPTER_ADDRESSES* adapter = addrs;
while (adapter != NULL) {
IP_ADAPTER_UNICAST_ADDRESS* address = adapter->FirstUnicastAddress;
while (address != NULL) {
char addr_chr[INET_ADDRSTRLEN];
SOCKADDR_IN* ipv4 = reinterpret_cast<SOCKADDR_IN*>(address->Address.lpSockaddr);
IP_Address ip;
ip.host= *((unsigned long*)&ipv4->sin_addr);
//inet_ntop(AF_INET, &ipv4->sin_addr, addr_chr, INET_ADDRSTRLEN);
r_addresses->push_back(ip);
address = address->Next;
};
adapter = adapter->Next;
};
memfree(addrs);
};
#else
void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
struct ifaddrs * ifAddrStruct=NULL;
struct ifaddrs * ifa=NULL;
getifaddrs(&ifAddrStruct);
for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa ->ifa_addr->sa_family==AF_INET) { // check it is IP4
// is a valid IP4 Address
IP_Address ip;
ip.host= *((unsigned long*)&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr);
r_addresses->push_back(ip);
}/* else if (ifa->ifa_addr->sa_family==AF_INET6) { // check it is IP6
// is a valid IP6 Address
tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
char addressBuffer[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
} */
}
if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct);
}
#endif
void IP_Unix::make_default() {
_create=_create_unix;

View file

@ -41,6 +41,8 @@ class IP_Unix : public IP {
static IP* _create_unix();
public:
virtual void get_local_addresses(List<IP_Address> *r_addresses) const;
static void make_default();
IP_Unix();
};

View file

@ -1263,6 +1263,16 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
gdfunc->name=func_name;
gdfunc->_script=p_script;
gdfunc->source=source;
#ifdef DEBUG_ENABLED
{
gdfunc->func_cname=(String(source)+" - "+String(func_name)).utf8();
gdfunc->_func_cname=gdfunc->func_cname.get_data();
}
#endif
if (p_func) {
gdfunc->_initial_line=p_func->line;
} else {

View file

@ -787,3 +787,67 @@ Error GDScriptLanguage::complete_keyword(const String& p_code, int p_line, const
return OK;
}
void GDScriptLanguage::auto_indent_code(String& p_code,int p_from_line,int p_to_line) const {
Vector<String> lines = p_code.split("\n");
List<int> indent_stack;
for(int i=0;i<lines.size();i++) {
String l = lines[i];
int tc=0;
for(int j=0;j<l.length();j++) {
if (l[j]==' ' || l[j]=='\t') {
tc++;
} else {
break;
}
}
String st = l.substr(tc,l.length()).strip_edges();
if (st=="" || st.begins_with("#"))
continue; //ignore!
int ilevel=0;
if (indent_stack.size()) {
ilevel=indent_stack.back()->get();
}
if (tc>ilevel) {
indent_stack.push_back(tc);
} else if (tc<ilevel) {
while(indent_stack.size() && indent_stack.back()->get()>tc) {
indent_stack.pop_back();
}
if (indent_stack.size() && indent_stack.back()->get()!=tc)
indent_stack.push_back(tc); //this is not right but gets the job done
}
if (i>=p_from_line) {
l="";
for(int j=0;j<indent_stack.size();j++)
l+="\t";
l+=st;
} else if (i>p_to_line) {
break;
}
//print_line(itos(indent_stack.size())+","+itos(tc)+": "+l);
lines[i]=l;
}
p_code="";
for(int i=0;i<lines.size();i++) {
if (i>0)
p_code+="\n";
p_code+=lines[i];
}
}

View file

@ -1221,6 +1221,15 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
return; //go back a level
}
if (pending_newline!=-1) {
NewLineNode *nl = alloc_node<NewLineNode>();
nl->line=pending_newline;
p_block->statements.push_back(nl);
pending_newline=-1;
}
switch(token) {
@ -1234,16 +1243,19 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
} break;
case GDTokenizer::TK_NEWLINE: {
if (!_parse_newline()) {
if (!error_set) {
p_block->end_line=tokenizer->get_token_line();
pending_newline=p_block->end_line;
}
return;
}
NewLineNode *nl = alloc_node<NewLineNode>();
nl->line=tokenizer->get_token_line();
p_block->statements.push_back(nl);
if (!_parse_newline()) {
if (!error_set) {
p_block->end_line=tokenizer->get_token_line();
}
return;
}
} break;
case GDTokenizer::TK_CF_PASS: {
if (tokenizer->get_token(1)!=GDTokenizer::TK_SEMICOLON && tokenizer->get_token(1)!=GDTokenizer::TK_NEWLINE ) {
@ -1782,6 +1794,7 @@ void GDParser::_parse_class(ClassNode *p_class) {
case GDTokenizer::TK_PR_FUNCTION: {
bool _static=false;
pending_newline=-1;
if (tokenizer->get_token(-1)==GDTokenizer::TK_PR_STATIC) {
@ -2490,6 +2503,7 @@ void GDParser::clear() {
tab_level.push_back(0);
error_line=0;
error_column=0;
pending_newline=-1;
parenthesis=0;
current_export.type=Variant::NIL;
error="";
@ -2501,6 +2515,7 @@ GDParser::GDParser() {
head=NULL;
list=NULL;
tokenizer=NULL;
pending_newline=-1;
clear();
}

View file

@ -362,6 +362,8 @@ private:
int error_line;
int error_column;
int pending_newline;
List<int> tab_level;
String base_path;

View file

@ -1159,6 +1159,9 @@ GDFunction::GDFunction() {
_stack_size=0;
_call_size=0;
name="<anonymous>";
#ifdef DEBUG_ENABLED
_func_cname=NULL;
#endif
}

View file

@ -118,10 +118,13 @@ friend class GDCompiler;
Vector<Variant> constants;
Vector<StringName> global_names;
Vector<int> default_arguments;
Vector<int> code;
#ifdef DEBUG_ENABLED
CharString func_cname;
const char*_func_cname;
#endif
List<StackDebug> stack_debug;
List<StackDebug> stack_debug;
_FORCE_INLINE_ Variant *_get_variant(int p_address,GDInstance *p_instance,GDScript *p_script,Variant &self,Variant *p_stack,String& r_error) const;
_FORCE_INLINE_ String _get_call_error(const Variant::CallError& p_err, const String& p_where,const Variant**argptrs) const;
@ -427,6 +430,7 @@ public:
virtual int find_function(const String& p_function,const String& p_code) const;
virtual String make_function(const String& p_class,const String& p_name,const StringArray& p_args) const;
virtual Error complete_keyword(const String& p_code, int p_line, const String& p_base_path,const String& p_keyword, List<String>* r_options);
virtual void auto_indent_code(String& p_code,int p_from_line,int p_to_line) const;
/* DEBUGGER FUNCTIONS */

View file

@ -13,6 +13,7 @@ android_files = [
'dir_access_jandroid.cpp',
'thread_jandroid.cpp',
'audio_driver_jandroid.cpp',
'ifaddrs_android.cpp',
'android_native_app_glue.c',
'java_glue.cpp'
]

View file

@ -0,0 +1,221 @@
/*
* libjingle
* Copyright 2012, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
#include "ifaddrs_android.h"
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/utsname.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <unistd.h>
#include <errno.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
struct netlinkrequest {
nlmsghdr header;
ifaddrmsg msg;
};
namespace {
const int kMaxReadSize = 4096;
};
static int set_ifname(struct ifaddrs* ifaddr, int interface) {
char buf[IFNAMSIZ] = {0};
char* name = if_indextoname(interface, buf);
if (name == NULL) {
return -1;
}
ifaddr->ifa_name = new char[strlen(name) + 1];
strncpy(ifaddr->ifa_name, name, strlen(name) + 1);
return 0;
}
static int set_flags(struct ifaddrs* ifaddr) {
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd == -1) {
return -1;
}
ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ - 1);
int rc = ioctl(fd, SIOCGIFFLAGS, &ifr);
close(fd);
if (rc == -1) {
return -1;
}
ifaddr->ifa_flags = ifr.ifr_flags;
return 0;
}
static int set_addresses(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* data,
size_t len) {
if (msg->ifa_family == AF_INET) {
sockaddr_in* sa = new sockaddr_in;
sa->sin_family = AF_INET;
memcpy(&sa->sin_addr, data, len);
ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
} else if (msg->ifa_family == AF_INET6) {
sockaddr_in6* sa = new sockaddr_in6;
sa->sin6_family = AF_INET6;
sa->sin6_scope_id = msg->ifa_index;
memcpy(&sa->sin6_addr, data, len);
ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
} else {
return -1;
}
return 0;
}
static int make_prefixes(struct ifaddrs* ifaddr, int family, int prefixlen) {
char* prefix = NULL;
if (family == AF_INET) {
sockaddr_in* mask = new sockaddr_in;
mask->sin_family = AF_INET;
memset(&mask->sin_addr, 0, sizeof(in_addr));
ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
if (prefixlen > 32) {
prefixlen = 32;
}
prefix = reinterpret_cast<char*>(&mask->sin_addr);
} else if (family == AF_INET6) {
sockaddr_in6* mask = new sockaddr_in6;
mask->sin6_family = AF_INET6;
memset(&mask->sin6_addr, 0, sizeof(in6_addr));
ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
if (prefixlen > 128) {
prefixlen = 128;
}
prefix = reinterpret_cast<char*>(&mask->sin6_addr);
} else {
return -1;
}
for (int i = 0; i < (prefixlen / 8); i++) {
*prefix++ = 0xFF;
}
char remainder = 0xff;
remainder <<= (8 - prefixlen % 8);
*prefix = remainder;
return 0;
}
static int populate_ifaddrs(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* bytes,
size_t len) {
if (set_ifname(ifaddr, msg->ifa_index) != 0) {
return -1;
}
if (set_flags(ifaddr) != 0) {
return -1;
}
if (set_addresses(ifaddr, msg, bytes, len) != 0) {
return -1;
}
if (make_prefixes(ifaddr, msg->ifa_family, msg->ifa_prefixlen) != 0) {
return -1;
}
return 0;
}
int getifaddrs(struct ifaddrs** result) {
int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (fd < 0) {
return -1;
}
netlinkrequest ifaddr_request;
memset(&ifaddr_request, 0, sizeof(ifaddr_request));
ifaddr_request.header.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
ifaddr_request.header.nlmsg_type = RTM_GETADDR;
ifaddr_request.header.nlmsg_len = NLMSG_LENGTH(sizeof(ifaddrmsg));
ssize_t count = send(fd, &ifaddr_request, ifaddr_request.header.nlmsg_len, 0);
if (static_cast<size_t>(count) != ifaddr_request.header.nlmsg_len) {
close(fd);
return -1;
}
struct ifaddrs* start = NULL;
struct ifaddrs* current = NULL;
char buf[kMaxReadSize];
ssize_t amount_read = recv(fd, &buf, kMaxReadSize, 0);
while (amount_read > 0) {
nlmsghdr* header = reinterpret_cast<nlmsghdr*>(&buf[0]);
size_t header_size = static_cast<size_t>(amount_read);
for ( ; NLMSG_OK(header, header_size);
header = NLMSG_NEXT(header, header_size)) {
switch (header->nlmsg_type) {
case NLMSG_DONE:
// Success. Return.
*result = start;
close(fd);
return 0;
case NLMSG_ERROR:
close(fd);
freeifaddrs(start);
return -1;
case RTM_NEWADDR: {
ifaddrmsg* address_msg =
reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(header));
rtattr* rta = IFA_RTA(address_msg);
ssize_t payload_len = IFA_PAYLOAD(header);
while (RTA_OK(rta, payload_len)) {
if (rta->rta_type == IFA_ADDRESS) {
int family = address_msg->ifa_family;
if (family == AF_INET || family == AF_INET6) {
ifaddrs* newest = new ifaddrs;
memset(newest, 0, sizeof(ifaddrs));
if (current) {
current->ifa_next = newest;
} else {
start = newest;
}
if (populate_ifaddrs(newest, address_msg, RTA_DATA(rta),
RTA_PAYLOAD(rta)) != 0) {
freeifaddrs(start);
*result = NULL;
return -1;
}
current = newest;
}
}
rta = RTA_NEXT(rta, payload_len);
}
break;
}
}
}
amount_read = recv(fd, &buf, kMaxReadSize, 0);
}
close(fd);
freeifaddrs(start);
return -1;
}
void freeifaddrs(struct ifaddrs* addrs) {
struct ifaddrs* last = NULL;
struct ifaddrs* cursor = addrs;
while (cursor) {
delete[] cursor->ifa_name;
delete cursor->ifa_addr;
delete cursor->ifa_netmask;
last = cursor;
cursor = cursor->ifa_next;
delete last;
}
}

View file

@ -0,0 +1,46 @@
/*
* libjingle
* Copyright 2013, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
#ifndef TALK_BASE_IFADDRS_ANDROID_H_
#define TALK_BASE_IFADDRS_ANDROID_H_
#include <stdio.h>
#include <sys/socket.h>
// Implementation of getifaddrs for Android.
// Fills out a list of ifaddr structs (see below) which contain information
// about every network interface available on the host.
// See 'man getifaddrs' on Linux or OS X (nb: it is not a POSIX function).
struct ifaddrs {
struct ifaddrs* ifa_next;
char* ifa_name;
unsigned int ifa_flags;
struct sockaddr* ifa_addr;
struct sockaddr* ifa_netmask;
// Real ifaddrs has broadcast, point to point and data members.
// We don't need them (yet?).
};
int getifaddrs(struct ifaddrs** result);
void freeifaddrs(struct ifaddrs* addrs);
#endif // TALK_BASE_IFADDRS_ANDROID_H_

View file

@ -65,6 +65,9 @@ import java.io.InputStream;
public class Godot extends Activity implements SensorEventListener
{
static final int MAX_SINGLETONS = 64;
static public class SingletonBase {
protected void registerClass(String p_name, String[] p_methods) {
@ -104,8 +107,21 @@ public class Godot extends Activity implements SensorEventListener
}
Godot.singletons[Godot.singleton_count++]=this;
}
protected void onMainActivityResult(int requestCode, int resultCode, Intent data) {
}
protected void onMainResume() {
}
public void registerMethods() {}
}
@ -133,6 +149,12 @@ public class Godot extends Activity implements SensorEventListener
//setTitle(title);
}
static SingletonBase singletons[] = new SingletonBase[MAX_SINGLETONS];
static int singleton_count=0;
public interface ResultCallback {
public void callback(int requestCode, int resultCode, Intent data);
};
@ -147,6 +169,11 @@ public class Godot extends Activity implements SensorEventListener
result_callback.callback(requestCode, resultCode, data);
result_callback = null;
};
for(int i=0;i<singleton_count;i++) {
singletons[i].onMainActivityResult(requestCode,resultCode,data);
}
};
public void onVideoInit(boolean use_gl2) {
@ -271,6 +298,12 @@ public class Godot extends Activity implements SensorEventListener
mView.onResume();
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
GodotLib.focusin();
for(int i=0;i<singleton_count;i++) {
singletons[i].onMainResume();
}
}
@Override public void onSensorChanged(SensorEvent event) {

View file

@ -1,7 +1,10 @@
package com.android.godot;
import org.json.JSONObject;
import android.app.Activity;
import android.util.Log;
public class GodotPaymentV3 extends Godot.SingletonBase {
@ -13,14 +16,17 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
private String accessToken;
private String purchaseValidationUrlPrefix;
private String transactionId;
public void purchase( String _sku) {
public void purchase( String _sku, String _transactionId) {
final String sku = _sku;
final String transactionId = _transactionId;
activity.getPaymentsManager().setBaseSingleton(this);
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
activity.getPaymentsManager().requestPurchase(sku);
activity.getPaymentsManager().requestPurchase(sku, transactionId);
}
});
};
@ -38,22 +44,31 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
public GodotPaymentV3(Activity p_activity) {
registerClass("GodotPayments", new String[] {"purchase", "setPurchaseCallbackId", "setPurchaseValidationUrlPrefix"});
registerClass("GodotPayments", new String[] {"purchase", "setPurchaseCallbackId", "setPurchaseValidationUrlPrefix", "setTransactionId", "getSignature"});
activity=(Godot) p_activity;
}
private String signature;
public String getSignature(){
return this.signature;
}
public void callbackSuccess(String ticket){
GodotLib.callobject(purchaseCallbackId, "purchase_success", new Object[]{ticket});
public void callbackSuccess(String ticket, String signature){
Log.d(this.getClass().getName(), "PRE-Send callback to purchase success");
GodotLib.calldeferred(purchaseCallbackId, "purchase_success", new Object[]{ticket, signature});
Log.d(this.getClass().getName(), "POST-Send callback to purchase success");
}
public void callbackFail(){
GodotLib.callobject(purchaseCallbackId, "purchase_fail", new Object[]{});
GodotLib.calldeferred(purchaseCallbackId, "purchase_fail", new Object[]{});
// GodotLib.callobject(purchaseCallbackId, "purchase_fail", new Object[]{});
}
public void callbackCancel(){
GodotLib.callobject(purchaseCallbackId, "purchase_cancel", new Object[]{});
GodotLib.calldeferred(purchaseCallbackId, "purchase_cancel", new Object[]{});
// GodotLib.callobject(purchaseCallbackId, "purchase_cancel", new Object[]{});
}
public int getPurchaseCallbackId() {
@ -84,4 +99,12 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
this.accessToken = accessToken;
}
public void setTransactionId(String transactionId){
this.transactionId = transactionId;
}
public String getTransactionId(){
return this.transactionId;
}
}

View file

@ -56,8 +56,7 @@ abstract public class ConsumeTask {
protected void onPostExecute(String param){
if(param == null){
success(new PaymentsCache(context).getConsumableValue("ticket", sku));
success( new PaymentsCache(context).getConsumableValue("ticket", sku) );
}else{
error(param);
}

View file

@ -34,7 +34,8 @@ abstract public class HandlePurchaseTask {
String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
Log.d("XXX", "Purchase data:" + purchaseData);
// String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
Log.d("XXX", "Purchase signature:" + dataSignature);
if (resultCode == Activity.RESULT_OK) {
@ -57,12 +58,13 @@ abstract public class HandlePurchaseTask {
error("Untrusted callback");
return;
}
Log.d("XXX", "Este es el product ID:" + productId);
pc.setConsumableValue("ticket_signautre", productId, dataSignature);
pc.setConsumableValue("ticket", productId, purchaseData);
pc.setConsumableFlag("block", productId, true);
pc.setConsumableValue("token", productId, purchaseToken);
success(productId);
success(productId, dataSignature);
return;
} catch (JSONException e) {
error(e.getMessage());
@ -72,7 +74,7 @@ abstract public class HandlePurchaseTask {
}
}
abstract protected void success(String ticket);
abstract protected void success(String ticket, String signature);
abstract protected void error(String message);
abstract protected void canceled();

View file

@ -2,6 +2,7 @@ package com.android.godot.payments;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
public class PaymentsCache {
@ -30,12 +31,14 @@ public class PaymentsCache {
SharedPreferences sharedPref = context.getSharedPreferences("consumables_" + set, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString(sku, value);
Log.d("XXX", "Setting asset: consumables_" + set + ":" + sku);
editor.commit();
}
public String getConsumableValue(String set, String sku){
SharedPreferences sharedPref = context.getSharedPreferences(
"consumables_" + set, Context.MODE_PRIVATE);
Log.d("XXX", "Getting asset: consumables_" + set + ":" + sku);
return sharedPref.getString(sku, null);
}

View file

@ -6,6 +6,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.util.Log;
import com.android.godot.Godot;
import com.android.godot.GodotPaymentV3;
@ -63,7 +64,7 @@ public class PaymentsManager {
}
};
public void requestPurchase(String sku){
public void requestPurchase(String sku, String transactionId){
new PurchaseTask(mService, Godot.getInstance()) {
@Override
@ -76,7 +77,7 @@ public class PaymentsManager {
protected void canceled() {
godotPaymentV3.callbackCancel();
}
}.purchase(sku);
}.purchase(sku, transactionId);
}
@ -84,13 +85,14 @@ public class PaymentsManager {
new HandlePurchaseTask(activity){
@Override
protected void success(final String sku) {
protected void success(final String sku, final String signature) {
new ConsumeTask(mService, activity) {
@Override
protected void success(String ticket) {
// godotPaymentV3.callbackSuccess("");
godotPaymentV3.callbackSuccess(ticket);
Log.d("XXX", "calling success:" + signature);
godotPaymentV3.callbackSuccess(ticket, signature);
}
@Override
@ -131,7 +133,7 @@ public class PaymentsManager {
@Override
protected void success(String ticket) {
godotPaymentV3.callbackSuccess(ticket);
godotPaymentV3.callbackSuccess(ticket, null);
}

View file

@ -31,7 +31,7 @@ abstract public class PurchaseTask {
private boolean isLooping = false;
public void purchase(final String sku){
public void purchase(final String sku, final String transactionId){
Log.d("XXX", "Starting purchase for: " + sku);
PaymentsCache pc = new PaymentsCache(context);
Boolean isBlocked = pc.getConsumableFlag("block", sku);
@ -40,7 +40,7 @@ abstract public class PurchaseTask {
// error("Awaiting payment confirmation");
// return;
// }
final String hash = Crypt.createRandomHash() + Crypt.createRandomHash();
final String hash = transactionId;
Bundle buyIntentBundle;
try {
@ -76,7 +76,7 @@ abstract public class PurchaseTask {
return;
}
isLooping=true;
PurchaseTask.this.purchase(sku);
PurchaseTask.this.purchase(sku, transactionId);
}

View file

@ -1,6 +1,6 @@
#!/bin/bash
jarsigner -digestalg SHA1 -sigalg MD5withRSA -verbose -keystore /home/luis/Downloads/carnavalguachin.keystore -storepass 12345678 "$1" momoselacome
jarsigner -digestalg SHA1 -sigalg MD5withRSA -verbose -keystore my-release-key.keystore "$1" reduz
echo ""
echo ""

View file

@ -21,7 +21,8 @@ def get_opts():
return [
('IPHONEPLATFORM', 'name of the iphone platform', 'iPhoneOS'),
('IPHONEPATH', 'the path to iphone toolchain', '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain'),
('IPHONESDK', 'path to the iphone SDK', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk/'),
('IOS_SDK_VERSION', 'The SDK version', 'iPhoneOS7.0'),
('IPHONESDK', 'path to the iphone SDK', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/${IOS_SDK_VERSION}.sdk/'),
('game_center', 'Support for game center', 'yes'),
('store_kit', 'Support for in-app store', 'yes'),
('ios_gles22_override', 'Force GLES2.0 on iOS', 'yes'),
@ -37,6 +38,7 @@ def get_flags():
('tools', 'yes'),
('nedmalloc', 'no'),
('webp', 'yes'),
('openssl','builtin'), #use builtin openssl
]
@ -81,7 +83,7 @@ def configure(env):
'-framework', 'AudioToolbox',
'-framework', 'SystemConfiguration',
'-framework', 'Security',
'-framework', 'AdSupport',
#'-framework', 'AdSupport',
'-framework', 'MediaPlayer',
])

View file

@ -50,6 +50,7 @@ static String keyboard_text;
static GLView* _instance = NULL;
static bool video_found_error = false;
static bool video_playing = false;
static float video_previous_volume = 0.0f;
void _show_keyboard(String p_existing) {
@ -91,24 +92,29 @@ bool _play_video(String p_path, float p_volume) {
[_instance addSubview:_instance.moviePlayerController.view];
[_instance.moviePlayerController play];
video_playing = true;
return true;
}
bool _is_video_playing() {
//NSInteger playback_state = _instance.moviePlayerController.playbackState;
if (video_found_error)
return false;
return (_instance.moviePlayerController.playbackState == MPMoviePlaybackStatePlaying);
return video_playing || _instance.moviePlayerController.playbackState == MPMoviePlaybackStatePlaying;
//if (video_found_error)
// return false;
//return (_instance.moviePlayerController.playbackState == MPMoviePlaybackStatePlaying);
}
void _pause_video() {
[_instance.moviePlayerController pause];
video_playing = false;
}
void _stop_video() {
[_instance.moviePlayerController stop];
[_instance.moviePlayerController.view removeFromSuperview];
[[MPMusicPlayerController applicationMusicPlayer] setVolume: video_previous_volume];
video_playing = false;
}
@implementation GLView
@ -549,6 +555,7 @@ static void clear_touches() {
[_instance.moviePlayerController.view removeFromSuperview];
[[MPMusicPlayerController applicationMusicPlayer] setVolume: video_previous_volume];
video_playing = false;
}
@end

View file

@ -117,7 +117,7 @@ def configure(env):
env.Append(CCFLAGS=['/DGLES2_ENABLED'])
env.Append(CCFLAGS=['/DGLES1_ENABLED'])
env.Append(CCFLAGS=['/DGLEW_ENABLED'])
env.Append(LIBS=['winmm','opengl32','dsound','kernel32','ole32','user32','gdi32','wsock32', 'shell32','advapi32'])
env.Append(LIBS=['winmm','opengl32','dsound','kernel32','ole32','user32','gdi32', 'IPHLPAPI', 'wsock32', 'shell32','advapi32'])
env.Append(LIBPATH=[os.getenv("WindowsSdkDir")+"/Lib"])
if (os.getenv("DXSDK_DIR")):
@ -196,7 +196,7 @@ def configure(env):
env.Append(CCFLAGS=['-DWINDOWS_ENABLED','-mwindows'])
env.Append(CPPFLAGS=['-DRTAUDIO_ENABLED'])
env.Append(CCFLAGS=['-DGLES2_ENABLED','-DGLES1_ENABLED','-DGLEW_ENABLED'])
env.Append(LIBS=['mingw32','opengl32', 'dsound', 'ole32', 'd3d9','winmm','gdi32','wsock32','kernel32'])
env.Append(LIBS=['mingw32','opengl32', 'dsound', 'ole32', 'd3d9','winmm','gdi32','iphlpapi','wsock32','kernel32'])
#'d3dx9d'
env.Append(CPPFLAGS=['-DMINGW_ENABLED'])
env.Append(LINKFLAGS=['-g'])

View file

@ -480,7 +480,7 @@ unsigned int OS_X11::get_mouse_button_state(unsigned int p_x11_state) {
return state;
}
void OS_X11::handle_key_event(XKeyEvent *p_event) {
void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
// X11 functions don't know what const is
@ -591,17 +591,9 @@ void OS_X11::handle_key_event(XKeyEvent *p_event) {
// To detect them, i use XPeekEvent and check that their
// difference in time is below a treshold.
bool echo=false;
if (xkeyevent->type == KeyPress) {
// saved the time of the last keyrelease to see
// if it's the same as this keypress.
if (xkeyevent->time==last_keyrelease_time)
echo=true;
} else {
if (xkeyevent->type != KeyPress) {
// make sure there are events pending,
// so this call won't block.
if (XPending(x11_display)>0) {
@ -615,17 +607,21 @@ void OS_X11::handle_key_event(XKeyEvent *p_event) {
// not very helpful today.
::Time tresh=ABS(peek_event.xkey.time-xkeyevent->time);
if (peek_event.type == KeyPress && tresh<5 )
echo=true;
if (peek_event.type == KeyPress && tresh<5 ) {
KeySym rk;
nbytes=XLookupString((XKeyEvent*)&peek_event, str, 256, &rk, NULL);
if (rk==keysym_keycode) {
XEvent event;
XNextEvent(x11_display, &event); //erase next event
handle_key_event( (XKeyEvent*)&event,true );
return; //ignore current, echo next
}
}
// use the time from peek_event so it always works
last_keyrelease_time=peek_event.xkey.time;
} else {
last_keyrelease_time=xkeyevent->time;
}
// save the time to check for echo when keypress happens
// save the time to check for echo when keypress happens
}
@ -643,7 +639,7 @@ void OS_X11::handle_key_event(XKeyEvent *p_event) {
event.key.scancode=keycode;
event.key.unicode=unicode;
event.key.echo=echo;
event.key.echo=p_echo;
if (event.key.scancode==KEY_BACKTAB) {
//make it consistent accross platforms.
@ -1017,7 +1013,7 @@ String OS_X11::get_name() {
Error OS_X11::shell_open(String p_uri) {
return ERR_UNAVAILABLE;
}

View file

@ -90,7 +90,7 @@ class OS_X11 : public OS_Unix {
MouseMode mouse_mode;
Point2i center;
void handle_key_event(XKeyEvent *p_event);
void handle_key_event(XKeyEvent *p_event,bool p_echo=false);
void process_xevents();
virtual void delete_main_loop();
IP_Unix *ip_unix;

View file

@ -447,7 +447,7 @@ float CanvasItem::get_self_opacity() const {
void CanvasItem::set_blend_mode(BlendMode p_blend_mode) {
ERR_FAIL_INDEX(p_blend_mode,4);
ERR_FAIL_INDEX(p_blend_mode,5);
blend_mode=p_blend_mode;
VisualServer::get_singleton()->canvas_item_set_blend_mode(canvas_item,VS::MaterialBlendMode(blend_mode));
@ -794,7 +794,7 @@ void CanvasItem::_bind_methods() {
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/behind_parent"), _SCS("set_draw_behind_parent"),_SCS("is_draw_behind_parent_enabled") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/on_top",PROPERTY_HINT_NONE,"",0), _SCS("_set_on_top"),_SCS("_is_on_top") ); //compatibility
ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"visibility/blend_mode",PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul"), _SCS("set_blend_mode"),_SCS("get_blend_mode") );
ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"visibility/blend_mode",PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul,PMAlpha"), _SCS("set_blend_mode"),_SCS("get_blend_mode") );
//exporting these two things doesn't really make much sense i think
//ADD_PROPERTY( PropertyInfo(Variant::BOOL,"transform/toplevel"), _SCS("set_as_toplevel"),_SCS("is_set_as_toplevel") );
//ADD_PROPERTY(PropertyInfo(Variant::BOOL,"transform/notify"),_SCS("set_transform_notify"),_SCS("is_transform_notify_enabled"));
@ -810,6 +810,7 @@ void CanvasItem::_bind_methods() {
BIND_CONSTANT( BLEND_MODE_ADD );
BIND_CONSTANT( BLEND_MODE_SUB );
BIND_CONSTANT( BLEND_MODE_MUL );
BIND_CONSTANT( BLEND_MODE_PREMULT_ALPHA );
BIND_CONSTANT( NOTIFICATION_DRAW);

View file

@ -49,7 +49,8 @@ public:
BLEND_MODE_MIX, //default
BLEND_MODE_ADD,
BLEND_MODE_SUB,
BLEND_MODE_MUL
BLEND_MODE_MUL,
BLEND_MODE_PREMULT_ALPHA
};
private:

View file

@ -158,7 +158,7 @@ void Material::_bind_methods() {
for(int i=0;i<HINT_MAX;i++)
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, String()+"hints/"+_hint_names[i] ),_SCS("set_hint"),_SCS("get_hint"),_hint_indices[i]);
ADD_PROPERTY( PropertyInfo( Variant::INT, "params/blend_mode",PROPERTY_HINT_ENUM,"Mix,Add,Sub" ), _SCS("set_blend_mode"),_SCS("get_blend_mode"));
ADD_PROPERTY( PropertyInfo( Variant::INT, "params/blend_mode",PROPERTY_HINT_ENUM,"Mix,Add,Sub,PMAlpha" ), _SCS("set_blend_mode"),_SCS("get_blend_mode"));
ADD_PROPERTY( PropertyInfo( Variant::REAL, "params/line_width",PROPERTY_HINT_RANGE,"0.1,32.0,0.1" ), _SCS("set_line_width"),_SCS("get_line_width"));
@ -189,6 +189,8 @@ void Material::_bind_methods() {
BIND_CONSTANT( BLEND_MODE_MIX );
BIND_CONSTANT( BLEND_MODE_ADD );
BIND_CONSTANT( BLEND_MODE_SUB );
BIND_CONSTANT( BLEND_MODE_MUL );
BIND_CONSTANT( BLEND_MODE_PREMULT_ALPHA );
}

View file

@ -75,6 +75,7 @@ public:
BLEND_MODE_MUL = VS::MATERIAL_BLEND_MODE_MUL,
BLEND_MODE_ADD = VS::MATERIAL_BLEND_MODE_ADD,
BLEND_MODE_SUB = VS::MATERIAL_BLEND_MODE_SUB,
BLEND_MODE_PREMULT_ALPHA = VS::MATERIAL_BLEND_MODE_PREMULT_ALPHA,
};

View file

@ -302,6 +302,16 @@ void ImageTexture::fix_alpha_edges() {
}
}
void ImageTexture::premultiply_alpha() {
if (format==Image::FORMAT_RGBA /*&& !(flags&FLAG_CUBEMAP)*/) {
Image img = get_data();
img.premultiply_alpha();
set_data(img);
}
}
bool ImageTexture::has_alpha() const {
return ( format==Image::FORMAT_GRAYSCALE_ALPHA || format==Image::FORMAT_INDEXED_ALPHA || format==Image::FORMAT_RGBA );
@ -386,8 +396,10 @@ void ImageTexture::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_lossy_storage_quality","quality"),&ImageTexture::set_lossy_storage_quality);
ObjectTypeDB::bind_method(_MD("get_lossy_storage_quality"),&ImageTexture::get_lossy_storage_quality);
ObjectTypeDB::bind_method(_MD("fix_alpha_edges"),&ImageTexture::fix_alpha_edges);
ObjectTypeDB::bind_method(_MD("premultiply_alpha"),&ImageTexture::premultiply_alpha);
ObjectTypeDB::bind_method(_MD("set_size_override","size"),&ImageTexture::set_size_override);
ObjectTypeDB::set_method_flags(get_type_static(),_SCS("fix_alpha_edges"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
ObjectTypeDB::set_method_flags(get_type_static(),_SCS("premultiply_alpha"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
ObjectTypeDB::bind_method(_MD("_reload_hook","rid"),&ImageTexture::_reload_hook);

View file

@ -143,6 +143,7 @@ public:
float get_lossy_storage_quality() const;
void fix_alpha_edges();
void premultiply_alpha();
void set_size_override(const Size2& p_size);

View file

@ -199,7 +199,8 @@ public:
MATERIAL_BLEND_MODE_MIX, //default
MATERIAL_BLEND_MODE_ADD,
MATERIAL_BLEND_MODE_SUB,
MATERIAL_BLEND_MODE_MUL
MATERIAL_BLEND_MODE_MUL,
MATERIAL_BLEND_MODE_PREMULT_ALPHA
};

View file

@ -44,6 +44,7 @@ static const char *flag_names[]={
"No MipMaps",
"Repeat",
"Filter (Magnifying)",
"Premultiply Alpha",
NULL
};
@ -55,6 +56,7 @@ static const char *flag_short_names[]={
"NoMipMap",
"Repeat",
"Filter",
"PMAlpha",
NULL
};
@ -919,6 +921,11 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
image.fix_alpha_edges();
}
if (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_PREMULT_ALPHA) {
image.premultiply_alpha();
}
if (shrink>1) {
@ -972,6 +979,11 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
image.fix_alpha_edges();
}
if (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_PREMULT_ALPHA) {
image.premultiply_alpha();
}
int orig_w=image.get_width();
int orig_h=image.get_height();

View file

@ -91,7 +91,8 @@ public:
IMAGE_FLAG_COMPRESS_EXTRA=8, // used for pvrtc2
IMAGE_FLAG_NO_MIPMAPS=16, //normal for 2D games
IMAGE_FLAG_REPEAT=32, //usually disabled in 2D
IMAGE_FLAG_FILTER=64 //almost always enabled
IMAGE_FLAG_FILTER=64, //almost always enabled
IMAGE_FLAG_PREMULT_ALPHA=128//almost always enabled
};
virtual String get_name() const;

View file

@ -134,6 +134,8 @@ public:
void _plot_light(const Vector3& p_plot_pos,const AABB& p_plot_aabb, Octant *p_octant, const AABB& p_aabb,const Color& p_light);
void _plot_light_point(const Vector3& p_plot_pos, Octant *p_octant, const AABB& p_aabb,const Color& p_light);
void _throw_ray(const Vector3& p_from, const Vector3& p_to,const Color& p_light,float *p_att_curve,float p_att_curve_len,int p_bounces);
@ -165,7 +167,7 @@ public:
}
BakedLightBaker() {
octree_depth=8;
octree_depth=6;
octree=NULL;
bvh=NULL;
leaf_list=NULL;
@ -408,7 +410,7 @@ void BakedLightBaker::_make_bvh() {
void BakedLightBaker::_octree_insert(const AABB& p_aabb,Octant *p_octant,Triangle* p_triangle, int p_depth) {
if (p_octant->leaf) {
#if 0
if (p_aabb.has_point(p_triangle->vertices[0]) && p_aabb.has_point(p_triangle->vertices[1]) &&p_aabb.has_point(p_triangle->vertices[2])) {
//face is completely enclosed, add area
p_octant->surface_area+=Face3(p_triangle->vertices[0],p_triangle->vertices[1],p_triangle->vertices[2]).get_area();
@ -433,12 +435,18 @@ void BakedLightBaker::_octree_insert(const AABB& p_aabb,Octant *p_octant,Triangl
p.d=-p_aabb.pos[i];
poly=Geometry::clip_polygon(poly,p);
}
//calculate area
for(int i=2;i<poly.size();i++) {
p_octant->surface_area+=Face3(poly[0],poly[i-1],poly[i]).get_area();
}
}
//calculate area
float clipped_area=0;
for(int i=2;i<poly.size();i++) {
clipped_area+=Face3(poly[0],poly[i-1],poly[i]).get_area();
}
print_line(itos(poly.size())+" Base: "+rtos(Face3(p_triangle->vertices[0],p_triangle->vertices[1],p_triangle->vertices[2]).get_area())+" clipped: "+rtos(clipped_area));
p_octant->surface_area+=clipped_area;
}
#endif
} else {
@ -500,7 +508,7 @@ void BakedLightBaker::_make_octree() {
octree_aabb=base;
cell_size=base.size.x;
for(int i=0;i<=octree_depth;i++)
for(int i=0;i<octree_depth;i++)
cell_size/=2.0;
octree = memnew( Octant );
@ -526,7 +534,7 @@ void BakedLightBaker::_plot_light(const Vector3& p_plot_pos,const AABB& p_plot_a
float d = p_plot_pos.distance_to(center);
if (d>r)
return; //oh crap! outside radius
float intensity = 1.0 - (d/r)*(d/r); //not gauss but..
float intensity = 1.0;// - (d/r)*(d/r); //not gauss but..
p_octant->light_accum[0]+=p_light.r*intensity;
p_octant->light_accum[1]+=p_light.g*intensity;
p_octant->light_accum[2]+=p_light.b*intensity;
@ -558,6 +566,42 @@ void BakedLightBaker::_plot_light(const Vector3& p_plot_pos,const AABB& p_plot_a
}
}
void BakedLightBaker::_plot_light_point(const Vector3& p_plot_pos, Octant *p_octant, const AABB& p_aabb,const Color& p_light) {
if (p_octant->leaf) {
p_octant->light_accum[0]+=p_light.r;
p_octant->light_accum[1]+=p_light.g;
p_octant->light_accum[2]+=p_light.b;
} else {
for(int i=0;i<8;i++) {
if (!p_octant->children[i])
continue;
AABB aabb=p_aabb;
aabb.size*=0.5;
if (i&1)
aabb.pos.x+=aabb.size.x;
if (i&2)
aabb.pos.y+=aabb.size.y;
if (i&4)
aabb.pos.z+=aabb.size.z;
if (!aabb.has_point(p_plot_pos))
continue;
_plot_light_point(p_plot_pos,p_octant->children[i],aabb,p_light);
}
}
}
void BakedLightBaker::_throw_ray(const Vector3& p_begin, const Vector3& p_end,const Color& p_light,float *p_att_curve,float p_att_curve_len,int p_bounces) {
@ -692,6 +736,7 @@ void BakedLightBaker::_throw_ray(const Vector3& p_begin, const Vector3& p_end,co
aabb.size=Vector3(2,2,2)*cell_size*plot_size;
_plot_light(r_point,aabb,octree,octree_aabb,p_light);
// _plot_light_point(r_point,octree,octree_aabb,p_light);
}
@ -772,9 +817,21 @@ void BakedLightBaker::bake(Node* p_node) {
void BakedLightEditor::_end_baking() {
if (!bake_thread)
return;
bake_thread_exit=true;
Thread::wait_to_finish(bake_thread);
bake_thread=NULL;
bake_thread_exit=false;
}
void BakedLightEditor::_node_removed(Node *p_node) {
if(p_node==node) {
_end_baking();
node=NULL;
p_node->remove_child(preview);
preview->set_mesh(Ref<Mesh>());
@ -784,6 +841,79 @@ void BakedLightEditor::_node_removed(Node *p_node) {
}
void BakedLightEditor::_bake_thread_func(void *arg) {
BakedLightEditor *ble = (BakedLightEditor*)arg;
while(!ble->bake_thread_exit) {
ble->baker->throw_rays(1000);
}
}
void BakedLightEditor::_notification(int p_option) {
if (p_option==NOTIFICATION_PROCESS) {
if (bake_thread) {
update_timeout-=get_process_delta_time();
if (update_timeout<0) {
float norm = baker->get_normalization();
float max_lum=0;
{
DVector<Color>::Write cw=colors.write();
BakedLightBaker::Octant *oct = baker->leaf_list;
int vert_idx=0;
while(oct) {
Color color;
color.r=oct->light_accum[0]/norm;
color.g=oct->light_accum[1]/norm;
color.b=oct->light_accum[2]/norm;
float lum = color.get_v();
//if (lum<0.05)
// color.a=0;
if (lum>max_lum)
max_lum=lum;
for (int i=0;i<36;i++) {
cw[vert_idx++]=color;
}
oct=oct->next_leaf;
}
}
Array a;
a.resize(Mesh::ARRAY_MAX);
a[Mesh::ARRAY_VERTEX]=vertices;
a[Mesh::ARRAY_COLOR]=colors;
while(mesh->get_surface_count())
mesh->surface_remove(0);
mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES,a);
mesh->surface_set_material(0,material);
update_timeout=1;
}
}
}
}
void BakedLightEditor::_menu_option(int p_option) {
@ -797,13 +927,9 @@ void BakedLightEditor::_menu_option(int p_option) {
preview->set_mesh(Ref<Mesh>());
baker->base_inv=node->get_global_transform().affine_inverse();
baker->bake(node);
baker->throw_rays(100000);
float norm = baker->get_normalization();
float max_lum=0;
print_line("CELLS: "+itos(baker->cell_count));
DVector<Color> colors;
DVector<Vector3> vertices;
print_line("cell size: "+rtos(baker->cell_size));
colors.resize(baker->cell_count*36);
vertices.resize(baker->cell_count*36);
@ -817,12 +943,6 @@ void BakedLightEditor::_menu_option(int p_option) {
while(oct) {
Color color;
color.r=oct->light_accum[0]/norm;
color.g=oct->light_accum[1]/norm;
color.b=oct->light_accum[2]/norm;
float lum = color.get_v();
if (lum>max_lum)
max_lum=lum;
for (int i=0;i<6;i++) {
@ -845,7 +965,7 @@ void BakedLightEditor::_menu_option(int p_option) {
}
for(int j=0;j<4;j++) {
face_points[j]*=baker->cell_size;
face_points[j]*=baker->cell_size*0.5;
face_points[j]+=Vector3(oct->offset[0],oct->offset[1],oct->offset[2]);
}
@ -873,25 +993,20 @@ void BakedLightEditor::_menu_option(int p_option) {
}
print_line("max lum: "+rtos(max_lum));
Array a;
a.resize(Mesh::ARRAY_MAX);
a[Mesh::ARRAY_VERTEX]=vertices;
a[Mesh::ARRAY_COLOR]=colors;
while(mesh->get_surface_count())
mesh->surface_remove(0);
mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES,a);
mesh->surface_set_material(0,material);
Ref<FixedMaterial> matcol = memnew( FixedMaterial );
matcol->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY,true);
matcol->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true);
matcol->set_flag(FixedMaterial::FLAG_UNSHADED,true);
matcol->set_flag(FixedMaterial::FLAG_DOUBLE_SIDED,true);
matcol->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1));
Ref<Mesh> m = memnew( Mesh );
m->add_surface(Mesh::PRIMITIVE_TRIANGLES,a);
m->surface_set_material(0,matcol);
preview->set_mesh(m);
bake_thread_exit=false;
update_timeout=0;
set_process(true);
bake_thread=Thread::create(_bake_thread_func,this);
preview->set_mesh(mesh);
} break;
@ -914,6 +1029,7 @@ void BakedLightEditor::edit(BakedLight *p_baked_light) {
}
node=p_baked_light;
_end_baking();
if (node)
node->add_child(preview);
@ -943,6 +1059,19 @@ BakedLightEditor::BakedLightEditor() {
node=NULL;
baker = memnew( BakedLightBaker );
preview = memnew( MeshInstance );
bake_thread=NULL;
update_timeout=0;
material = Ref<FixedMaterial> ( memnew( FixedMaterial ) );
material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY,true);
material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true);
material->set_flag(FixedMaterial::FLAG_UNSHADED,true);
material->set_flag(FixedMaterial::FLAG_DOUBLE_SIDED,true);
material->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1));
mesh = Ref<Mesh>( memnew( Mesh ));
}
BakedLightEditor::~BakedLightEditor() {

View file

@ -19,6 +19,15 @@ class BakedLightEditor : public Control {
OBJ_TYPE(BakedLightEditor, Control );
float update_timeout;
DVector<Color> colors;
DVector<Vector3> vertices;
Ref<Mesh> mesh;
Ref<FixedMaterial> material;
Thread *bake_thread;
bool bake_thread_exit;
MeshInstance *preview;
BakedLightBaker *baker;
AcceptDialog *err_dialog;
@ -32,12 +41,15 @@ class BakedLightEditor : public Control {
MENU_OPTION_CLEAR
};
static void _bake_thread_func(void *arg);
void _end_baking();
void _menu_option(int);
friend class BakedLightEditorPlugin;
protected:
void _node_removed(Node *p_node);
static void _bind_methods();
void _notification(int p_what);
public:
void edit(BakedLight *p_baked_light);

View file

@ -608,7 +608,14 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
if (b.button_index==BUTTON_WHEEL_DOWN) {
float prev_zoom=zoom;
zoom=zoom*0.95;
{
Point2 ofs(b.x,b.y);
ofs = ofs/prev_zoom - ofs/zoom;
h_scroll->set_val( h_scroll->get_val() + ofs.x );
v_scroll->set_val( v_scroll->get_val() + ofs.y );
}
_update_scroll(0);
viewport->update();
return;
@ -616,7 +623,15 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
if (b.button_index==BUTTON_WHEEL_UP) {
float prev_zoom=zoom;
zoom=zoom*(1.0/0.95);
{
Point2 ofs(b.x,b.y);
ofs = ofs/prev_zoom - ofs/zoom;
h_scroll->set_val( h_scroll->get_val() + ofs.x );
v_scroll->set_val( v_scroll->get_val() + ofs.y );
}
_update_scroll(0);
viewport->update();
return;

View file

@ -687,6 +687,26 @@ void ScriptEditor::_menu_option(int p_option) {
current->get_text_edit()->query_code_comple();
} break;
case EDIT_AUTO_INDENT: {
TextEdit *te = current->get_text_edit();
String text = te->get_text();
Ref<Script> scr = current->get_edited_script();
if (scr.is_null())
return;
int begin,end;
if (te->is_selection_active()) {
begin=te->get_selection_from_line();
end=te->get_selection_to_line();
} else {
begin=0;
end=te->get_line_count()-1;
}
scr->get_language()->auto_indent_code(text,begin,end);
te->set_text(text);
} break;
case SEARCH_FIND: {
@ -1321,6 +1341,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
edit_menu->get_popup()->add_item("Select All",EDIT_SELECT_ALL,KEY_MASK_CMD|KEY_A);
edit_menu->get_popup()->add_separator();
edit_menu->get_popup()->add_item("Complete Symbol",EDIT_COMPLETE,KEY_MASK_CMD|KEY_SPACE);
edit_menu->get_popup()->add_item("Auto Indent",EDIT_AUTO_INDENT,KEY_MASK_CMD|KEY_I);
edit_menu->get_popup()->connect("item_pressed", this,"_menu_option");

View file

@ -122,6 +122,7 @@ class ScriptEditor : public VBoxContainer {
EDIT_PASTE,
EDIT_SELECT_ALL,
EDIT_COMPLETE,
EDIT_AUTO_INDENT,
SEARCH_FIND,
SEARCH_FIND_NEXT,
SEARCH_REPLACE,

View file

@ -1566,6 +1566,7 @@ CustomPropertyEditor::CustomPropertyEditor() {
add_child(checks20[i]);
checks20[i]->hide();
checks20[i]->connect("pressed",this,"_action_pressed",make_binds(i));
checks20[i]->set_tooltip("Bit "+itos(i)+", val "+itos(1<<i)+".");
}
text_edit = memnew( TextEdit );