d8223ffa75
That year should bring the long-awaited OpenGL ES 3.0 compatible renderer
with state-of-the-art rendering techniques tuned to work as low as middle
end handheld devices - without compromising with the possibilities given
for higher end desktop games of course. Great times ahead for the Godot
community and the gamers that will play our games!
(cherry picked from commit c7bc44d5ad
)
1122 lines
30 KiB
C++
1122 lines
30 KiB
C++
/*************************************************************************/
|
|
/* texture.cpp */
|
|
/*************************************************************************/
|
|
/* This file is part of: */
|
|
/* GODOT ENGINE */
|
|
/* http://www.godotengine.org */
|
|
/*************************************************************************/
|
|
/* Copyright (c) 2007-2017 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 "texture.h"
|
|
#include "io/image_loader.h"
|
|
#include "core/os/os.h"
|
|
|
|
|
|
|
|
Size2 Texture::get_size() const {
|
|
|
|
return Size2(get_width(),get_height());
|
|
}
|
|
|
|
|
|
void Texture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate, bool p_transpose) const {
|
|
|
|
VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,Rect2( p_pos, get_size()),get_rid(),false,p_modulate,p_transpose);
|
|
|
|
}
|
|
void Texture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate, bool p_transpose) const {
|
|
|
|
VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,p_rect,get_rid(),p_tile,p_modulate,p_transpose);
|
|
|
|
}
|
|
void Texture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate, bool p_transpose) const{
|
|
|
|
VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,p_rect,get_rid(),p_src_rect,p_modulate,p_transpose);
|
|
}
|
|
|
|
bool Texture::get_rect_region(const Rect2& p_rect, const Rect2& p_src_rect,Rect2& r_rect,Rect2& r_src_rect) const {
|
|
|
|
r_rect=p_rect;
|
|
r_src_rect=p_src_rect;
|
|
|
|
return true;
|
|
}
|
|
|
|
void Texture::_bind_methods() {
|
|
|
|
ObjectTypeDB::bind_method(_MD("get_width"),&Texture::get_width);
|
|
ObjectTypeDB::bind_method(_MD("get_height"),&Texture::get_height);
|
|
ObjectTypeDB::bind_method(_MD("get_size"),&Texture::get_size);
|
|
ObjectTypeDB::bind_method(_MD("get_rid"),&Texture::get_rid);
|
|
ObjectTypeDB::bind_method(_MD("has_alpha"),&Texture::has_alpha);
|
|
ObjectTypeDB::bind_method(_MD("set_flags","flags"),&Texture::set_flags);
|
|
ObjectTypeDB::bind_method(_MD("get_flags"),&Texture::get_flags);
|
|
ObjectTypeDB::bind_method(_MD("draw","canvas_item","pos","modulate","transpose"),&Texture::draw,DEFVAL(Color(1,1,1)),DEFVAL(false));
|
|
ObjectTypeDB::bind_method(_MD("draw_rect","canvas_item","rect","tile","modulate","transpose"),&Texture::draw_rect,DEFVAL(Color(1,1,1)),DEFVAL(false));
|
|
ObjectTypeDB::bind_method(_MD("draw_rect_region","canvas_item","rect","src_rect","modulate","transpose"),&Texture::draw_rect_region,DEFVAL(Color(1,1,1)),DEFVAL(false));
|
|
|
|
BIND_CONSTANT( FLAG_MIPMAPS );
|
|
BIND_CONSTANT( FLAG_REPEAT );
|
|
BIND_CONSTANT( FLAG_FILTER );
|
|
BIND_CONSTANT( FLAG_VIDEO_SURFACE );
|
|
BIND_CONSTANT( FLAGS_DEFAULT );
|
|
BIND_CONSTANT( FLAG_ANISOTROPIC_FILTER );
|
|
BIND_CONSTANT( FLAG_CONVERT_TO_LINEAR );
|
|
BIND_CONSTANT( FLAG_MIRRORED_REPEAT );
|
|
|
|
}
|
|
|
|
Texture::Texture() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
void ImageTexture::reload_from_file() {
|
|
|
|
String path=get_path();
|
|
if (!path.is_resource_file())
|
|
return;
|
|
|
|
uint32_t flags = get_flags();
|
|
Image img;
|
|
|
|
Error err = ImageLoader::load_image(path,&img);
|
|
ERR_FAIL_COND(err!=OK);
|
|
|
|
create_from_image(img,flags);
|
|
|
|
}
|
|
|
|
bool ImageTexture::_set(const StringName& p_name, const Variant& p_value) {
|
|
|
|
if (p_name=="image" && p_value.get_type()==Variant::IMAGE)
|
|
create_from_image( p_value,flags );
|
|
else if (p_name=="flags")
|
|
if (w*h==0)
|
|
flags=p_value;
|
|
else
|
|
set_flags(p_value);
|
|
else if (p_name=="size") {
|
|
Size2 s = p_value;
|
|
w=s.width;
|
|
h=s.height;
|
|
VisualServer::get_singleton()->texture_set_size_override(texture,w,h);
|
|
} else if (p_name=="storage") {
|
|
storage=Storage(p_value.operator int());
|
|
} else if (p_name=="lossy_quality") {
|
|
lossy_storage_quality=p_value;
|
|
} else if (p_name=="_data") {
|
|
_set_data(p_value);
|
|
} else
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool ImageTexture::_get(const StringName& p_name,Variant &r_ret) const {
|
|
|
|
|
|
if (p_name=="image_data") {
|
|
|
|
} else if (p_name=="image")
|
|
r_ret= get_data();
|
|
else if (p_name=="flags")
|
|
r_ret= flags;
|
|
else if (p_name=="size")
|
|
r_ret=Size2(w,h);
|
|
else if (p_name=="storage")
|
|
r_ret= storage;
|
|
else if (p_name=="lossy_quality")
|
|
r_ret= lossy_storage_quality;
|
|
else
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
void ImageTexture::_get_property_list( List<PropertyInfo> *p_list) const {
|
|
|
|
|
|
PropertyHint img_hint=PROPERTY_HINT_NONE;
|
|
if (storage==STORAGE_COMPRESS_LOSSY) {
|
|
img_hint=PROPERTY_HINT_IMAGE_COMPRESS_LOSSY;
|
|
} else if (storage==STORAGE_COMPRESS_LOSSLESS) {
|
|
img_hint=PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS;
|
|
}
|
|
|
|
|
|
|
|
p_list->push_back( PropertyInfo( Variant::INT, "flags", PROPERTY_HINT_FLAGS,"Mipmaps,Repeat,Filter,Anisotropic,sRGB,Mirrored Repeat") );
|
|
p_list->push_back( PropertyInfo( Variant::IMAGE, "image", img_hint,String::num(lossy_storage_quality)) );
|
|
p_list->push_back( PropertyInfo( Variant::VECTOR2, "size",PROPERTY_HINT_NONE, ""));
|
|
p_list->push_back( PropertyInfo( Variant::INT, "storage", PROPERTY_HINT_ENUM,"Uncompressed,Compress Lossy,Compress Lossless"));
|
|
p_list->push_back( PropertyInfo( Variant::REAL, "lossy_quality", PROPERTY_HINT_RANGE,"0.0,1.0,0.01" ));
|
|
}
|
|
|
|
void ImageTexture::_reload_hook(const RID& p_hook) {
|
|
|
|
String path=get_path();
|
|
if (!path.is_resource_file())
|
|
return;
|
|
|
|
Image img;
|
|
Error err = ImageLoader::load_image(path,&img);
|
|
|
|
ERR_FAIL_COND(err!=OK);
|
|
|
|
|
|
VisualServer::get_singleton()->texture_set_data(texture,img);
|
|
|
|
_change_notify();
|
|
}
|
|
|
|
void ImageTexture::create(int p_width, int p_height,Image::Format p_format,uint32_t p_flags) {
|
|
|
|
flags=p_flags;
|
|
VisualServer::get_singleton()->texture_allocate(texture,p_width, p_height, p_format, p_flags);
|
|
format=p_format;
|
|
w=p_width;
|
|
h=p_height;
|
|
|
|
}
|
|
void ImageTexture::create_from_image(const Image& p_image, uint32_t p_flags) {
|
|
|
|
flags=p_flags;
|
|
w=p_image.get_width();
|
|
h=p_image.get_height();
|
|
format=p_image.get_format();
|
|
|
|
VisualServer::get_singleton()->texture_allocate(texture,p_image.get_width(),p_image.get_height(), p_image.get_format(), p_flags);
|
|
VisualServer::get_singleton()->texture_set_data(texture,p_image);
|
|
_change_notify();
|
|
}
|
|
|
|
void ImageTexture::set_flags(uint32_t p_flags) {
|
|
|
|
|
|
|
|
/* uint32_t cube = flags & FLAG_CUBEMAP;
|
|
if (flags == p_flags&cube)
|
|
return;
|
|
|
|
flags=p_flags|cube; */
|
|
flags=p_flags;
|
|
VisualServer::get_singleton()->texture_set_flags(texture,p_flags);
|
|
|
|
}
|
|
|
|
uint32_t ImageTexture::get_flags() const {
|
|
|
|
return ImageTexture::flags;
|
|
}
|
|
|
|
Image::Format ImageTexture::get_format() const {
|
|
|
|
return format;
|
|
}
|
|
|
|
void ImageTexture::load(const String& p_path) {
|
|
|
|
Image img;
|
|
img.load(p_path);
|
|
create_from_image(img);
|
|
|
|
}
|
|
|
|
void ImageTexture::set_data(const Image& p_image) {
|
|
|
|
VisualServer::get_singleton()->texture_set_data(texture,p_image);
|
|
VisualServer::get_singleton()->texture_set_reload_hook(texture,0,StringName()); //hook is erased if data is changed
|
|
_change_notify();
|
|
}
|
|
|
|
void ImageTexture::_resource_path_changed() {
|
|
|
|
String path=get_path();
|
|
if (VS::get_singleton()->has_feature(VS::FEATURE_NEEDS_RELOAD_HOOK)) {
|
|
//this needs to be done much better, but probably will end up being deprecated as technology advances
|
|
if (path.is_resource_file() && ImageLoader::recognize(path.extension())) {
|
|
|
|
//hook is set only if path is hookable
|
|
VisualServer::get_singleton()->texture_set_reload_hook(texture,get_instance_ID(),"_reload_hook");
|
|
} else {
|
|
VisualServer::get_singleton()->texture_set_reload_hook(texture,0,StringName());
|
|
}
|
|
}
|
|
}
|
|
|
|
Image ImageTexture::get_data() const {
|
|
|
|
return VisualServer::get_singleton()->texture_get_data(texture);
|
|
}
|
|
|
|
int ImageTexture::get_width() const {
|
|
|
|
return w;
|
|
}
|
|
|
|
int ImageTexture::get_height() const {
|
|
|
|
return h;
|
|
}
|
|
|
|
|
|
RID ImageTexture::get_rid() const {
|
|
|
|
return texture;
|
|
}
|
|
|
|
void ImageTexture::fix_alpha_edges() {
|
|
|
|
if (format==Image::FORMAT_RGBA /*&& !(flags&FLAG_CUBEMAP)*/) {
|
|
|
|
Image img = get_data();
|
|
img.fix_alpha_edges();
|
|
set_data(img);
|
|
}
|
|
}
|
|
|
|
void ImageTexture::premultiply_alpha() {
|
|
|
|
if (format==Image::FORMAT_RGBA /*&& !(flags&FLAG_CUBEMAP)*/) {
|
|
|
|
Image img = get_data();
|
|
img.premultiply_alpha();
|
|
set_data(img);
|
|
}
|
|
}
|
|
|
|
void ImageTexture::normal_to_xy() {
|
|
|
|
Image img = get_data();
|
|
img.normalmap_to_xy();
|
|
create_from_image(img,flags);
|
|
}
|
|
|
|
void ImageTexture::shrink_x2_and_keep_size() {
|
|
|
|
Size2 sizeov=get_size();
|
|
Image img = get_data();
|
|
img.resize(img.get_width()/2,img.get_height()/2,Image::INTERPOLATE_BILINEAR);
|
|
create_from_image(img,flags);
|
|
set_size_override(sizeov);
|
|
|
|
}
|
|
|
|
bool ImageTexture::has_alpha() const {
|
|
|
|
return ( format==Image::FORMAT_GRAYSCALE_ALPHA || format==Image::FORMAT_INDEXED_ALPHA || format==Image::FORMAT_RGBA );
|
|
}
|
|
|
|
|
|
void ImageTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate, bool p_transpose) const {
|
|
|
|
if ((w|h)==0)
|
|
return;
|
|
VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,Rect2( p_pos, Size2(w,h)),texture,false,p_modulate,p_transpose);
|
|
|
|
}
|
|
void ImageTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate, bool p_transpose) const {
|
|
|
|
if ((w|h)==0)
|
|
return;
|
|
VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,p_rect,texture,p_tile,p_modulate,p_transpose);
|
|
|
|
}
|
|
void ImageTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate, bool p_transpose) const{
|
|
|
|
if ((w|h)==0)
|
|
return;
|
|
VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,p_rect,texture,p_src_rect,p_modulate,p_transpose);
|
|
}
|
|
|
|
void ImageTexture::set_size_override(const Size2& p_size) {
|
|
|
|
Size2 s=p_size;
|
|
if (s.x!=0)
|
|
w=s.x;
|
|
if (s.y!=0)
|
|
h=s.y;
|
|
VisualServer::get_singleton()->texture_set_size_override(texture,w,h);
|
|
}
|
|
|
|
void ImageTexture::set_path(const String& p_path,bool p_take_over) {
|
|
|
|
if (texture.is_valid()) {
|
|
VisualServer::get_singleton()->texture_set_path(texture,p_path);
|
|
}
|
|
|
|
Resource::set_path(p_path,p_take_over);
|
|
}
|
|
|
|
|
|
void ImageTexture::set_storage(Storage p_storage) {
|
|
|
|
storage=p_storage;
|
|
}
|
|
|
|
ImageTexture::Storage ImageTexture::get_storage() const {
|
|
|
|
return storage;
|
|
}
|
|
|
|
void ImageTexture::set_lossy_storage_quality(float p_lossy_storage_quality) {
|
|
|
|
lossy_storage_quality=p_lossy_storage_quality;
|
|
}
|
|
|
|
float ImageTexture::get_lossy_storage_quality() const {
|
|
|
|
return lossy_storage_quality;
|
|
}
|
|
|
|
void ImageTexture::_set_data(Dictionary p_data) {
|
|
|
|
Image img = p_data["image"];
|
|
uint32_t flags = p_data["flags"];
|
|
|
|
create_from_image(img, flags);
|
|
|
|
set_storage(Storage(p_data["storage"].operator int()));
|
|
set_lossy_storage_quality(p_data["lossy_quality"]);
|
|
|
|
set_size_override(p_data["size"]);
|
|
};
|
|
|
|
void ImageTexture::_bind_methods() {
|
|
|
|
ObjectTypeDB::bind_method(_MD("create","width","height","format","flags"),&ImageTexture::create,DEFVAL(FLAGS_DEFAULT));
|
|
ObjectTypeDB::bind_method(_MD("create_from_image","image","flags"),&ImageTexture::create_from_image,DEFVAL(FLAGS_DEFAULT));
|
|
ObjectTypeDB::bind_method(_MD("get_format"),&ImageTexture::get_format);
|
|
ObjectTypeDB::bind_method(_MD("load","path"),&ImageTexture::load);
|
|
ObjectTypeDB::bind_method(_MD("set_data","image"),&ImageTexture::set_data);
|
|
ObjectTypeDB::bind_method(_MD("get_data","cube_side"),&ImageTexture::get_data);
|
|
ObjectTypeDB::bind_method(_MD("set_storage","mode"),&ImageTexture::set_storage);
|
|
ObjectTypeDB::bind_method(_MD("get_storage"),&ImageTexture::get_storage);
|
|
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("normal_to_xy"),&ImageTexture::normal_to_xy);
|
|
ObjectTypeDB::bind_method(_MD("shrink_x2_and_keep_size"),&ImageTexture::shrink_x2_and_keep_size);
|
|
|
|
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::set_method_flags(get_type_static(),_SCS("normal_to_xy"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
|
|
ObjectTypeDB::set_method_flags(get_type_static(),_SCS("shrink_x2_and_keep_size"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
|
|
ObjectTypeDB::bind_method(_MD("_reload_hook","rid"),&ImageTexture::_reload_hook);
|
|
|
|
|
|
BIND_CONSTANT( STORAGE_RAW );
|
|
BIND_CONSTANT( STORAGE_COMPRESS_LOSSY );
|
|
BIND_CONSTANT( STORAGE_COMPRESS_LOSSLESS );
|
|
|
|
|
|
}
|
|
|
|
ImageTexture::ImageTexture() {
|
|
|
|
w=h=0;
|
|
flags=FLAGS_DEFAULT;
|
|
texture = VisualServer::get_singleton()->texture_create();
|
|
storage = STORAGE_RAW;
|
|
lossy_storage_quality=0.7;
|
|
|
|
|
|
}
|
|
|
|
|
|
ImageTexture::~ImageTexture() {
|
|
|
|
VisualServer::get_singleton()->free( texture );
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////
|
|
|
|
|
|
int AtlasTexture::get_width() const {
|
|
|
|
if (region.size.width==0) {
|
|
if (atlas.is_valid())
|
|
return atlas->get_width();
|
|
return 1;
|
|
} else {
|
|
return region.size.width+margin.size.width;
|
|
}
|
|
}
|
|
int AtlasTexture::get_height() const {
|
|
|
|
if (region.size.height==0) {
|
|
if (atlas.is_valid())
|
|
return atlas->get_height();
|
|
return 1;
|
|
} else {
|
|
return region.size.height+margin.size.height;
|
|
}
|
|
}
|
|
RID AtlasTexture::get_rid() const {
|
|
|
|
if (atlas.is_valid())
|
|
return atlas->get_rid();
|
|
|
|
return RID();
|
|
}
|
|
|
|
bool AtlasTexture::has_alpha() const {
|
|
|
|
if (atlas.is_valid())
|
|
return atlas->has_alpha();
|
|
|
|
return false;
|
|
}
|
|
|
|
void AtlasTexture::set_flags(uint32_t p_flags) {
|
|
|
|
if (atlas.is_valid())
|
|
atlas->set_flags(p_flags);
|
|
|
|
}
|
|
|
|
|
|
uint32_t AtlasTexture::get_flags() const{
|
|
|
|
if (atlas.is_valid())
|
|
return atlas->get_flags();
|
|
|
|
return 0;
|
|
}
|
|
|
|
void AtlasTexture::set_atlas(const Ref<Texture>& p_atlas){
|
|
|
|
if (atlas==p_atlas)
|
|
return;
|
|
atlas=p_atlas;
|
|
emit_changed();
|
|
emit_signal("atlas_changed");
|
|
}
|
|
Ref<Texture> AtlasTexture::get_atlas() const{
|
|
|
|
return atlas;
|
|
}
|
|
|
|
void AtlasTexture::set_region(const Rect2& p_region) {
|
|
|
|
region=p_region;
|
|
emit_changed();
|
|
|
|
}
|
|
|
|
Rect2 AtlasTexture::get_region() const {
|
|
|
|
return region;
|
|
}
|
|
|
|
void AtlasTexture::set_margin(const Rect2& p_margin) {
|
|
|
|
margin=p_margin;
|
|
emit_changed();
|
|
|
|
}
|
|
|
|
Rect2 AtlasTexture::get_margin() const {
|
|
|
|
return margin;
|
|
}
|
|
|
|
void AtlasTexture::_bind_methods() {
|
|
|
|
ObjectTypeDB::bind_method(_MD("set_atlas","atlas:Texture"),&AtlasTexture::set_atlas);
|
|
ObjectTypeDB::bind_method(_MD("get_atlas:Texture"),&AtlasTexture::get_atlas);
|
|
|
|
ObjectTypeDB::bind_method(_MD("set_region","region"),&AtlasTexture::set_region);
|
|
ObjectTypeDB::bind_method(_MD("get_region"),&AtlasTexture::get_region);
|
|
|
|
ObjectTypeDB::bind_method(_MD("set_margin","margin"),&AtlasTexture::set_margin);
|
|
ObjectTypeDB::bind_method(_MD("get_margin"),&AtlasTexture::get_margin);
|
|
|
|
ADD_SIGNAL(MethodInfo("atlas_changed"));
|
|
|
|
ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "atlas", PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_atlas"),_SCS("get_atlas") );
|
|
ADD_PROPERTY( PropertyInfo( Variant::RECT2, "region"), _SCS("set_region"),_SCS("get_region") );
|
|
ADD_PROPERTY( PropertyInfo( Variant::RECT2, "margin"), _SCS("set_margin"),_SCS("get_margin") );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AtlasTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate, bool p_transpose) const {
|
|
|
|
Rect2 rc=region;
|
|
|
|
if (!atlas.is_valid())
|
|
return;
|
|
|
|
if (rc.size.width==0) {
|
|
rc.size.width=atlas->get_width();
|
|
}
|
|
|
|
if (rc.size.height==0) {
|
|
rc.size.height=atlas->get_height();
|
|
}
|
|
|
|
VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,Rect2(p_pos+margin.pos,rc.size),atlas->get_rid(),rc,p_modulate,p_transpose);
|
|
}
|
|
|
|
void AtlasTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate, bool p_transpose) const {
|
|
|
|
Rect2 rc=region;
|
|
|
|
if (!atlas.is_valid())
|
|
return;
|
|
|
|
if (rc.size.width==0) {
|
|
rc.size.width=atlas->get_width();
|
|
}
|
|
|
|
if (rc.size.height==0) {
|
|
rc.size.height=atlas->get_height();
|
|
}
|
|
|
|
Vector2 scale = p_rect.size / (region.size+margin.size);
|
|
Rect2 dr( p_rect.pos+margin.pos*scale,rc.size*scale );
|
|
|
|
VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,dr,atlas->get_rid(),rc,p_modulate,p_transpose);
|
|
|
|
}
|
|
void AtlasTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate, bool p_transpose) const {
|
|
|
|
//this might not necesarily work well if using a rect, needs to be fixed properly
|
|
Rect2 rc=region;
|
|
|
|
if (!atlas.is_valid())
|
|
return;
|
|
|
|
Rect2 src=p_src_rect;
|
|
src.pos+=(rc.pos-margin.pos);
|
|
Rect2 src_c = rc.clip(src);
|
|
if (src_c.size==Size2())
|
|
return;
|
|
Vector2 ofs = (src_c.pos-src.pos);
|
|
|
|
Vector2 scale = p_rect.size / p_src_rect.size;
|
|
if(scale.x < 0)
|
|
{
|
|
float mx = (margin.size.width - margin.pos.x);
|
|
mx -= margin.pos.x;
|
|
ofs.x = -(ofs.x + mx);
|
|
}
|
|
if(scale.y < 0)
|
|
{
|
|
float my = margin.size.height - margin.pos.y;
|
|
my -= margin.pos.y;
|
|
ofs.y = -(ofs.y + my);
|
|
}
|
|
Rect2 dr( p_rect.pos+ofs*scale,src_c.size*scale );
|
|
|
|
VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,dr,atlas->get_rid(),src_c,p_modulate,p_transpose);
|
|
}
|
|
|
|
bool AtlasTexture::get_rect_region(const Rect2& p_rect, const Rect2& p_src_rect,Rect2& r_rect,Rect2& r_src_rect) const {
|
|
|
|
Rect2 rc=region;
|
|
|
|
if (!atlas.is_valid())
|
|
return false;
|
|
|
|
Rect2 src=p_src_rect;
|
|
src.pos+=(rc.pos-margin.pos);
|
|
Rect2 src_c = rc.clip(src);
|
|
if (src_c.size==Size2())
|
|
return false;
|
|
Vector2 ofs = (src_c.pos-src.pos);
|
|
|
|
Vector2 scale = p_rect.size / p_src_rect.size;
|
|
if(scale.x < 0)
|
|
{
|
|
float mx = (margin.size.width - margin.pos.x);
|
|
mx -= margin.pos.x;
|
|
ofs.x = -(ofs.x + mx);
|
|
}
|
|
if(scale.y < 0)
|
|
{
|
|
float my = margin.size.height - margin.pos.y;
|
|
my -= margin.pos.y;
|
|
ofs.y = -(ofs.y + my);
|
|
}
|
|
Rect2 dr( p_rect.pos+ofs*scale,src_c.size*scale );
|
|
|
|
|
|
|
|
r_rect=dr;
|
|
r_src_rect=src_c;
|
|
return true;
|
|
}
|
|
|
|
|
|
AtlasTexture::AtlasTexture() {
|
|
|
|
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////
|
|
|
|
|
|
int LargeTexture::get_width() const {
|
|
|
|
return size.width;
|
|
}
|
|
int LargeTexture::get_height() const {
|
|
|
|
return size.height;
|
|
}
|
|
RID LargeTexture::get_rid() const {
|
|
|
|
return RID();
|
|
}
|
|
|
|
bool LargeTexture::has_alpha() const {
|
|
|
|
for(int i=0;i<pieces.size();i++) {
|
|
if (pieces[i].texture->has_alpha())
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void LargeTexture::set_flags(uint32_t p_flags) {
|
|
|
|
for(int i=0;i<pieces.size();i++) {
|
|
pieces[i].texture->set_flags(p_flags);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
uint32_t LargeTexture::get_flags() const{
|
|
|
|
if (pieces.size())
|
|
return pieces[0].texture->get_flags();
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int LargeTexture::add_piece(const Point2& p_offset,const Ref<Texture>& p_texture) {
|
|
|
|
ERR_FAIL_COND_V(p_texture.is_null(), -1);
|
|
Piece p;
|
|
p.offset=p_offset;
|
|
p.texture=p_texture;
|
|
pieces.push_back(p);
|
|
|
|
return pieces.size() - 1;
|
|
}
|
|
|
|
void LargeTexture::set_piece_offset(int p_idx, const Point2& p_offset) {
|
|
|
|
ERR_FAIL_INDEX(p_idx, pieces.size());
|
|
pieces[p_idx].offset = p_offset;
|
|
};
|
|
|
|
void LargeTexture::set_piece_texture(int p_idx, const Ref<Texture>& p_texture) {
|
|
|
|
ERR_FAIL_INDEX(p_idx, pieces.size());
|
|
pieces[p_idx].texture = p_texture;
|
|
};
|
|
|
|
|
|
|
|
void LargeTexture::set_size(const Size2& p_size){
|
|
|
|
size=p_size;
|
|
}
|
|
void LargeTexture::clear(){
|
|
|
|
pieces.clear();
|
|
size=Size2i();
|
|
}
|
|
|
|
Array LargeTexture::_get_data() const {
|
|
|
|
Array arr;
|
|
for(int i=0;i<pieces.size();i++) {
|
|
arr.push_back(pieces[i].offset);
|
|
arr.push_back(pieces[i].texture);
|
|
}
|
|
arr.push_back(Size2(size));
|
|
return arr;
|
|
|
|
}
|
|
void LargeTexture::_set_data(const Array& p_array) {
|
|
|
|
ERR_FAIL_COND(p_array.size()<1);
|
|
ERR_FAIL_COND(!(p_array.size()&1));
|
|
clear();
|
|
for(int i=0;i<p_array.size()-1;i+=2) {
|
|
add_piece(p_array[i],p_array[i+1]);
|
|
}
|
|
size=Size2(p_array[p_array.size()-1]);
|
|
}
|
|
|
|
int LargeTexture::get_piece_count() const {
|
|
|
|
return pieces.size();
|
|
}
|
|
Vector2 LargeTexture::get_piece_offset(int p_idx) const{
|
|
|
|
ERR_FAIL_INDEX_V(p_idx,pieces.size(),Vector2());
|
|
return pieces[p_idx].offset;
|
|
}
|
|
Ref<Texture> LargeTexture::get_piece_texture(int p_idx) const{
|
|
|
|
ERR_FAIL_INDEX_V(p_idx,pieces.size(),Ref<Texture>());
|
|
return pieces[p_idx].texture;
|
|
|
|
}
|
|
|
|
|
|
void LargeTexture::_bind_methods() {
|
|
|
|
ObjectTypeDB::bind_method(_MD("add_piece","ofs","texture:Texture"),&LargeTexture::add_piece);
|
|
ObjectTypeDB::bind_method(_MD("set_piece_offset", "idx", "ofs"),&LargeTexture::set_piece_offset);
|
|
ObjectTypeDB::bind_method(_MD("set_piece_texture","idx", "texture:Texture"),&LargeTexture::set_piece_texture);
|
|
ObjectTypeDB::bind_method(_MD("set_size","size"),&LargeTexture::set_size);
|
|
ObjectTypeDB::bind_method(_MD("clear"),&LargeTexture::clear);
|
|
|
|
ObjectTypeDB::bind_method(_MD("get_piece_count"),&LargeTexture::get_piece_count);
|
|
ObjectTypeDB::bind_method(_MD("get_piece_offset","idx"),&LargeTexture::get_piece_offset);
|
|
ObjectTypeDB::bind_method(_MD("get_piece_texture:Texture","idx"),&LargeTexture::get_piece_texture);
|
|
|
|
ObjectTypeDB::bind_method(_MD("_set_data","data"),&LargeTexture::_set_data);
|
|
ObjectTypeDB::bind_method(_MD("_get_data"),&LargeTexture::_get_data);
|
|
|
|
ADD_PROPERTY( PropertyInfo( Variant::ARRAY, "_data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR), _SCS("_set_data"),_SCS("_get_data") );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LargeTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate, bool p_transpose) const {
|
|
|
|
for(int i=0;i<pieces.size();i++) {
|
|
|
|
// TODO
|
|
pieces[i].texture->draw(p_canvas_item,pieces[i].offset+p_pos,p_modulate,p_transpose);
|
|
}
|
|
}
|
|
|
|
void LargeTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate, bool p_transpose) const {
|
|
|
|
//tiling not supported for this
|
|
if (size.x==0 || size.y==0)
|
|
return;
|
|
|
|
Size2 scale = p_rect.size/size;
|
|
|
|
for(int i=0;i<pieces.size();i++) {
|
|
|
|
// TODO
|
|
pieces[i].texture->draw_rect(p_canvas_item,Rect2(pieces[i].offset*scale+p_rect.pos,pieces[i].texture->get_size()*scale),false,p_modulate,p_transpose);
|
|
}
|
|
}
|
|
void LargeTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate, bool p_transpose) const {
|
|
|
|
|
|
//tiling not supported for this
|
|
if (p_src_rect.size.x==0 || p_src_rect.size.y==0)
|
|
return;
|
|
|
|
Size2 scale = p_rect.size/p_src_rect.size;
|
|
|
|
for(int i=0;i<pieces.size();i++) {
|
|
|
|
// TODO
|
|
Rect2 rect( pieces[i].offset, pieces[i].texture->get_size());
|
|
if (!p_src_rect.intersects(rect))
|
|
continue;
|
|
Rect2 local = p_src_rect.clip(rect);
|
|
Rect2 target = local;
|
|
target.size*=scale;
|
|
target.pos=p_rect.pos+(p_src_rect.pos+rect.pos)*scale;
|
|
local.pos-=rect.pos;
|
|
pieces[i].texture->draw_rect_region(p_canvas_item,target,local,p_modulate,p_transpose);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
LargeTexture::LargeTexture() {
|
|
|
|
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void CubeMap::set_flags(uint32_t p_flags) {
|
|
|
|
flags=p_flags;
|
|
if (_is_valid())
|
|
VS::get_singleton()->texture_set_flags(cubemap,flags|VS::TEXTURE_FLAG_CUBEMAP);
|
|
}
|
|
|
|
uint32_t CubeMap::get_flags() const {
|
|
|
|
return flags;
|
|
}
|
|
|
|
void CubeMap::set_side(Side p_side,const Image& p_image) {
|
|
|
|
ERR_FAIL_COND(p_image.empty());
|
|
ERR_FAIL_INDEX(p_side,6);
|
|
if (!_is_valid()) {
|
|
format = p_image.get_format();
|
|
w=p_image.get_width();
|
|
h=p_image.get_height();
|
|
VS::get_singleton()->texture_allocate(cubemap,w,h,p_image.get_format(),flags|VS::TEXTURE_FLAG_CUBEMAP);
|
|
}
|
|
|
|
VS::get_singleton()->texture_set_data(cubemap,p_image,VS::CubeMapSide(p_side));
|
|
valid[p_side]=true;
|
|
}
|
|
|
|
Image CubeMap::get_side(Side p_side) const {
|
|
|
|
if (!valid[p_side])
|
|
return Image();
|
|
return VS::get_singleton()->texture_get_data(cubemap,VS::CubeMapSide(p_side));
|
|
|
|
}
|
|
|
|
Image::Format CubeMap::get_format() const {
|
|
|
|
return format;
|
|
}
|
|
int CubeMap::get_width() const {
|
|
|
|
return w;
|
|
}
|
|
int CubeMap::get_height() const {
|
|
|
|
return h;
|
|
}
|
|
|
|
RID CubeMap::get_rid() const {
|
|
|
|
return cubemap;
|
|
}
|
|
|
|
|
|
void CubeMap::set_storage(Storage p_storage) {
|
|
|
|
storage=p_storage;
|
|
}
|
|
|
|
CubeMap::Storage CubeMap::get_storage() const {
|
|
|
|
return storage;
|
|
}
|
|
|
|
void CubeMap::set_lossy_storage_quality(float p_lossy_storage_quality) {
|
|
|
|
lossy_storage_quality=p_lossy_storage_quality;
|
|
}
|
|
|
|
float CubeMap::get_lossy_storage_quality() const {
|
|
|
|
return lossy_storage_quality;
|
|
}
|
|
|
|
void CubeMap::set_path(const String& p_path,bool p_take_over) {
|
|
|
|
if (cubemap.is_valid()) {
|
|
VisualServer::get_singleton()->texture_set_path(cubemap,p_path);
|
|
}
|
|
|
|
Resource::set_path(p_path,p_take_over);
|
|
}
|
|
|
|
|
|
bool CubeMap::_set(const StringName& p_name, const Variant& p_value) {
|
|
|
|
if (p_name=="side/left") {
|
|
set_side(SIDE_LEFT,p_value);
|
|
} else if (p_name=="side/right") {
|
|
set_side(SIDE_RIGHT,p_value);
|
|
} else if (p_name=="side/bottom") {
|
|
set_side(SIDE_BOTTOM,p_value);
|
|
} else if (p_name=="side/top") {
|
|
set_side(SIDE_TOP,p_value);
|
|
} else if (p_name=="side/front") {
|
|
set_side(SIDE_FRONT,p_value);
|
|
} else if (p_name=="side/back") {
|
|
set_side(SIDE_BACK,p_value);
|
|
} else if (p_name=="flags") {
|
|
set_flags(p_value);
|
|
} else if (p_name=="storage") {
|
|
storage=Storage(p_value.operator int());
|
|
} else if (p_name=="lossy_quality") {
|
|
lossy_storage_quality=p_value;
|
|
} else
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool CubeMap::_get(const StringName& p_name,Variant &r_ret) const {
|
|
|
|
if (p_name=="side/left") {
|
|
r_ret=get_side(SIDE_LEFT);
|
|
} else if (p_name=="side/right") {
|
|
r_ret=get_side(SIDE_RIGHT);
|
|
} else if (p_name=="side/bottom") {
|
|
r_ret=get_side(SIDE_BOTTOM);
|
|
} else if (p_name=="side/top") {
|
|
r_ret=get_side(SIDE_TOP);
|
|
} else if (p_name=="side/front") {
|
|
r_ret=get_side(SIDE_FRONT);
|
|
} else if (p_name=="side/back") {
|
|
r_ret=get_side(SIDE_BACK);
|
|
} else if (p_name=="flags") {
|
|
r_ret= flags;
|
|
} else if (p_name=="storage") {
|
|
r_ret= storage;
|
|
} else if (p_name=="lossy_quality") {
|
|
r_ret= lossy_storage_quality;
|
|
} else
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
void CubeMap::_get_property_list( List<PropertyInfo> *p_list) const {
|
|
|
|
|
|
PropertyHint img_hint=PROPERTY_HINT_NONE;
|
|
if (storage==STORAGE_COMPRESS_LOSSY) {
|
|
img_hint=PROPERTY_HINT_IMAGE_COMPRESS_LOSSY;
|
|
} else if (storage==STORAGE_COMPRESS_LOSSLESS) {
|
|
img_hint=PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS;
|
|
}
|
|
|
|
|
|
p_list->push_back( PropertyInfo( Variant::INT, "flags", PROPERTY_HINT_FLAGS,"Mipmaps,Repeat,Filter" ) );
|
|
p_list->push_back( PropertyInfo( Variant::IMAGE, "side/left", img_hint,String::num(lossy_storage_quality)) );
|
|
p_list->push_back( PropertyInfo( Variant::IMAGE, "side/right", img_hint,String::num(lossy_storage_quality)) );
|
|
p_list->push_back( PropertyInfo( Variant::IMAGE, "side/bottom", img_hint,String::num(lossy_storage_quality)) );
|
|
p_list->push_back( PropertyInfo( Variant::IMAGE, "side/top", img_hint,String::num(lossy_storage_quality)) );
|
|
p_list->push_back( PropertyInfo( Variant::IMAGE, "side/front", img_hint,String::num(lossy_storage_quality)) );
|
|
p_list->push_back( PropertyInfo( Variant::IMAGE, "side/back", img_hint,String::num(lossy_storage_quality)) );
|
|
p_list->push_back( PropertyInfo( Variant::INT, "storage", PROPERTY_HINT_ENUM,"Uncompressed,Compress Lossy,Compress Lossless",PROPERTY_USAGE_EDITOR));
|
|
p_list->push_back( PropertyInfo( Variant::REAL, "lossy_quality", PROPERTY_HINT_RANGE,"0.0,1.0,0.01" ) );
|
|
}
|
|
|
|
void CubeMap::_bind_methods() {
|
|
|
|
ObjectTypeDB::bind_method(_MD("get_width"),&CubeMap::get_width);
|
|
ObjectTypeDB::bind_method(_MD("get_height"),&CubeMap::get_height);
|
|
ObjectTypeDB::bind_method(_MD("get_rid"),&CubeMap::get_rid);
|
|
ObjectTypeDB::bind_method(_MD("set_flags","flags"),&CubeMap::set_flags);
|
|
ObjectTypeDB::bind_method(_MD("get_flags"),&CubeMap::get_flags);
|
|
|
|
ObjectTypeDB::bind_method(_MD("set_side","side","image"),&CubeMap::set_side);
|
|
ObjectTypeDB::bind_method(_MD("get_side","side"),&CubeMap::get_side);
|
|
ObjectTypeDB::bind_method(_MD("set_storage","mode"),&CubeMap::set_storage);
|
|
ObjectTypeDB::bind_method(_MD("get_storage"),&CubeMap::get_storage);
|
|
ObjectTypeDB::bind_method(_MD("set_lossy_storage_quality","quality"),&CubeMap::set_lossy_storage_quality);
|
|
ObjectTypeDB::bind_method(_MD("get_lossy_storage_quality"),&CubeMap::get_lossy_storage_quality);
|
|
|
|
|
|
BIND_CONSTANT( STORAGE_RAW );
|
|
BIND_CONSTANT( STORAGE_COMPRESS_LOSSY );
|
|
BIND_CONSTANT( STORAGE_COMPRESS_LOSSLESS );
|
|
BIND_CONSTANT( SIDE_LEFT );
|
|
BIND_CONSTANT( SIDE_RIGHT );
|
|
BIND_CONSTANT( SIDE_BOTTOM );
|
|
BIND_CONSTANT( SIDE_TOP );
|
|
BIND_CONSTANT( SIDE_FRONT );
|
|
BIND_CONSTANT( SIDE_BACK );
|
|
BIND_CONSTANT( FLAG_MIPMAPS );
|
|
BIND_CONSTANT( FLAG_REPEAT );
|
|
BIND_CONSTANT( FLAG_FILTER );
|
|
BIND_CONSTANT( FLAGS_DEFAULT );
|
|
|
|
|
|
}
|
|
|
|
CubeMap::CubeMap() {
|
|
|
|
w=h=0;
|
|
flags=FLAGS_DEFAULT;
|
|
for(int i=0;i<6;i++)
|
|
valid[i]=false;
|
|
cubemap = VisualServer::get_singleton()->texture_create();
|
|
storage = STORAGE_RAW;
|
|
lossy_storage_quality=0.7;
|
|
|
|
|
|
}
|
|
|
|
|
|
CubeMap::~CubeMap() {
|
|
|
|
VisualServer::get_singleton()->free( cubemap );
|
|
}
|
|
|
|
|
|
|
|
|
|
/* BIND_CONSTANT( FLAG_CUBEMAP );
|
|
BIND_CONSTANT( CUBEMAP_LEFT );
|
|
BIND_CONSTANT( CUBEMAP_RIGHT );
|
|
BIND_CONSTANT( CUBEMAP_BOTTOM );
|
|
BIND_CONSTANT( CUBEMAP_TOP );
|
|
BIND_CONSTANT( CUBEMAP_FRONT );
|
|
BIND_CONSTANT( CUBEMAP_BACK );
|
|
*/
|